Package games.stendhal.client.sound.manager

Source Code of games.stendhal.client.sound.manager.SoundManager$SoundChannel

/* $Id: SoundManager.java,v 1.29 2010/11/27 16:35:09 martinfuchs Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.client.sound.manager;

import games.stendhal.client.sound.system.SignalProcessor;
import games.stendhal.client.sound.system.SoundSystem;
import games.stendhal.client.sound.system.Time;
import games.stendhal.client.sound.system.processors.DirectedSound;
import games.stendhal.client.sound.system.processors.Interruptor;
import games.stendhal.client.sound.system.processors.SoundLayers;
import games.stendhal.client.sound.system.processors.VolumeAdjustor;
import games.stendhal.common.math.Algebra;
import games.stendhal.common.resource.Resource;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import javax.sound.sampled.AudioFormat;

import org.apache.log4j.Logger;

/**
* Old implementation of the sound manager.
* @author silvio
*/
public final class SoundManager
{
    private final static Logger              logger                   = Logger.getLogger(SoundManager.class);
    private final static int                 OUTPUT_NUM_SAMPLES       = 256;
  private final static int                 SOUND_CHANNEL_LIMIT      = 0;
  private final static int                 USE_NUM_MIXER_LINES      = 0;
    private final static int                 DIMENSION                = 2;
    private final static float[]             HEARER_LOOKONG_DIRECTION = { 0.0f, 1.0f };
    private final static AudioFormat         AUDIO_FORMAT             = new AudioFormat(44100, 16, 2, true, false);
    private final static InfiniteAudibleArea INFINITE_AUDIBLE_AREA    = new InfiniteAudibleArea();
    public  final static Time                ZERO_DURATION            = new Time();

    public final static class Sound implements Cloneable
    {
        final AtomicReference<SoundFile>    file    = new AtomicReference<SoundFile>(null);
        final AtomicReference<SoundChannel> channel = new AtomicReference<SoundChannel>(null);
    Object                              object  = null;

    @Override
    public Sound clone()
    {
      Sound sound = new Sound();
      sound.file.set(file.get().clone());
      sound.object = object;
      return sound;
    }

    @SuppressWarnings("unchecked")
    public <T> T getAttachment(Class<T> clazz)
    {
      if(clazz.isInstance(object))
        return (T)object;

      return null;
    }

    public Object  getAttachment()           { return object;                                            }
        public boolean isActive()                { return channel.get() != null && channel.get().isActive(); }
    public void    setAttachment(Object obj) { object = obj;                                             }
    }
 
    private final class SoundChannel extends SignalProcessor
    {
        final float[]                      mSoundPosition = new float[DIMENSION];
        final AtomicBoolean                mAutoRepeat    = new AtomicBoolean(false);
        final AtomicBoolean                mIsActive      = new AtomicBoolean(false);
        final AtomicReference<AudibleArea> mAudibleArea   = new AtomicReference<AudibleArea>(INFINITE_AUDIBLE_AREA);
        final Interruptor                  mInterruptor   = new Interruptor();
        final DirectedSound                mDirectedSound = new DirectedSound();
        final VolumeAdjustor               mGlobalVolume  = new VolumeAdjustor();
        final SoundLayers.VolumeAdjustor   mLayerVolume;
        final SoundSystem.Output           mOutput;
        Sound                              mSound = null;

        SoundChannel()
        {
            mOutput      = mSoundSystem.openOutput(AUDIO_FORMAT);
            mLayerVolume = mSoundLayers.createVolumeAdjustor(0);

            SignalProcessor.createChain(mInterruptor, this, mLayerVolume, mGlobalVolume, mDirectedSound, mOutput);
        }

        boolean isActive      ()                            { return mIsActive.get();                      }
        void    setAutoRepeat (boolean repeat)              { mAutoRepeat.set(repeat);                     }
        void    setVolume     (float volume)                { mGlobalVolume.setVolume(volume);             }
        void    startFading   (float volume, Time duration) { mGlobalVolume.startFading(volume, duration); }
    void    startFading   (Time duration)               { mGlobalVolume.startFading(duration);         }
        void    setLayer      (int level)                   { mLayerVolume.setLayer(level);                }
        void    resumePlayback()                            { mInterruptor.play();                         }
    void    close         ()                            { mSoundSystem.closeOutput(mOutput);           }
    Sound   getSoundObject()                            { return mSound;                               }

    void setAudibleArea(AudibleArea area)
    {
      if(area == null)
        area = INFINITE_AUDIBLE_AREA;
     
      mAudibleArea.set(area);
    }

        synchronized void playSound(Sound newSound, float volume, Time time)
        {
            if(mSound != null)
            {
                mSound.file.get().disconnect();
                mSound.file.get().restart();
                mSound.channel.set(null);
                mLayerVolume.setIntensity(0.0f);
            }

            if(newSound != null)
            {
                if(time == null)
                    time = ZERO_DURATION;
               
                mInterruptor.play();
                mGlobalVolume.setVolume(0.0f);
                mGlobalVolume.startFading(volume, time);
                newSound.channel.set(this);
                newSound.file.get().connectTo(mInterruptor, true);
            }

            mSound = newSound;
      mIsActive.set(newSound != null);
        }

        void stopPlayback(Time time)
        {
      if(time == null)
        time = ZERO_DURATION;

            mAutoRepeat.set(false);
            mGlobalVolume.startFading(0.0f, time);
            mInterruptor.stop(time);
        }
       
        void update()
        {
            float intensity = mAudibleArea.get().getHearingIntensity(mHearerPosition);
            mAudibleArea.get().getClosestPoint(mSoundPosition, mHearerPosition);
            mDirectedSound.setPositions2D(mSoundPosition, mHearerPosition, HEARER_LOOKONG_DIRECTION, intensity);
            mLayerVolume.setIntensity(intensity);
        }

        @Override
        protected void finished()
        {
            if(mAutoRepeat.get())
            {
                mSound.file.get().restart();
            }
            else
            {
                playSound(null, 0, null);
                super.quit();
            }
        }
    }
   
    private final LinkedList<SoundChannel> mChannels       = new LinkedList<SoundChannel>();
    private final float[]                  mHearerPosition = new float[DIMENSION];
    private final SoundLayers              mSoundLayers    = new SoundLayers();
  private boolean                        mMute           = false;
  private SoundSystem                    mSoundSystem;

    protected SoundManager()
    {
        Algebra.mov_Vecf(mHearerPosition, 0.0f);

    mSoundSystem = new SoundSystem(null, AUDIO_FORMAT, new Time(15, Time.Unit.MILLI), USE_NUM_MIXER_LINES);
    mSoundSystem.setDaemon(true);
    mSoundSystem.start();
    }

  public Sound openSound(Resource resource, SoundFile.Type fileType)
    {
    return openSound(resource, fileType, OUTPUT_NUM_SAMPLES, true);
    }

  public synchronized Sound openSound(Resource resource, SoundFile.Type fileType, int numSamplesPerChunk, boolean enableStreaming)
    {
    Sound sound = null;

        try
        {
            SoundFile file = new SoundFile(resource, fileType, numSamplesPerChunk, enableStreaming);
            sound = new Sound();
            sound.file.set(file);
        }
        catch(IOException exception)
    {
      logger.warn(exception);
      return null;
    }

    return sound;
    }

    public synchronized void setHearerPosition(float[] position)
    {
        Algebra.mov_Vecf(mHearerPosition, position);
    }

    public synchronized void update()
    {
        for(SoundChannel channel: mChannels)
        {
            if(channel.isActive())
                channel.update();
        }
    }

  public synchronized void play(Sound sound, float volume, int layerLevel, AudibleArea area, boolean autoRepeat, Time fadeInDuration)
    {
        if(sound == null)
            return;

        if(sound.isActive())
        {
            SoundChannel channel = sound.channel.get();
            channel.setAutoRepeat(autoRepeat);
            channel.startFading(1.0f, fadeInDuration);
      channel.setVolume(volume);
            channel.setLayer(layerLevel);
            channel.setAudibleArea(area);
            channel.resumePlayback();
      channel.update();
        }
        else
        {
      if(!mMute)
      {
        SoundChannel channel = getInactiveChannel();
        channel.setAutoRepeat(autoRepeat);
        channel.setLayer(layerLevel);
        channel.setAudibleArea(area);
        channel.playSound(sound, volume, fadeInDuration);
        channel.update();

        closeInactiveChannels(SOUND_CHANNEL_LIMIT);
      }
        }
    }

    public synchronized void stop(Sound sound, Time fadeOutDuration)
    {
        if(sound != null && sound.isActive())
            sound.channel.get().stopPlayback(fadeOutDuration);
    }

    public synchronized void changeVolume(Sound sound, float volume)
    {
        if(sound != null && sound.isActive())
            sound.channel.get().setVolume(volume);
    }

    public synchronized void changeLayer(Sound sound, int layerLevel)
    {
        if(sound != null && sound.isActive())
            sound.channel.get().setLayer(layerLevel);
    }

    public synchronized void changeAudibleArea(Sound sound, AudibleArea area)
    {
        if(sound != null && sound.isActive())
            sound.channel.get().setAudibleArea(area);
    }

  public synchronized void mute(boolean turnOffSound, boolean useFading, Time delay)
  {
    if(turnOffSound && !mMute)
    {
      logger.info("turning off audio");
      mSoundSystem.suspend(delay);

      if(useFading)
      {
        for(SoundChannel channel: mChannels)
          if(channel.isActive())
            channel.startFading(0, delay);
      }
    }

    if(!turnOffSound && mMute)
    {
      logger.info("turning on audio");
      mSoundSystem.proceed(null);

      if(useFading)
      {
        for(SoundChannel channel: mChannels)
          if(channel.isActive())
            channel.startFading(delay);
      }
    }

    mMute = turnOffSound;
  }

  public synchronized Collection<Sound> getActiveSounds()
  {
    ArrayList<Sound> sounds = new ArrayList<Sound>(mChannels.size());

    for(SoundChannel channel: mChannels)
    {
      Sound sound = channel.getSoundObject();

      if(sound != null && sound.isActive())
        sounds.add(sound);
    }

    sounds.trimToSize();
    return sounds;
  }
 
    public synchronized void exit()
    {
    mSoundSystem.exit(null);

    try
    {
      mSoundSystem.join();
    }
    catch(InterruptedException exception)
    {
      logger.warn("joining sound system thread was interrupted: " + exception);
    }
    }

  private void closeInactiveChannels(int leaveNumChannelsOpen)
  {
    int                    numChannels = mChannels.size();
    Iterator<SoundChannel> iChannel    = mChannels.iterator();

    while(iChannel.hasNext())
    {
      if(mChannels.size() <= leaveNumChannelsOpen)
        break;
     
      SoundChannel currChannel = iChannel.next();

      if(!currChannel.isActive())
      {
        currChannel.close();
        iChannel.remove();
      }
    }

    numChannels -= mChannels.size();

    if(numChannels > 0)
      logger.debug("close " + numChannels + " inactive sound channels");
  }
 
    private SoundChannel getInactiveChannel()
    {
        SoundChannel foundChannel = null;

        for(SoundChannel channel: mChannels)
        {
            if(!channel.isActive())
      {
                foundChannel = channel;
        break;
      }
        }

        if(foundChannel == null)
    {
      foundChannel = new SoundChannel();
            mChannels.add(foundChannel);

      logger.debug("open new sound channel (number " + mChannels.size() + ")");
        }

        return foundChannel;
    }
}
TOP

Related Classes of games.stendhal.client.sound.manager.SoundManager$SoundChannel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.