package client.audio;
import common.Constants;
import java.io.*;
import java.util.logging.*;
import javax.sound.sampled.*;
/**
* A handy sound-clip wrapper
* @author dvanhumb
*/
public class SoundEffect implements LineListener, Constants {
public static Logger logger = Logger.getLogger(CLIENT_LOGGER_NAME);
protected float volume;
protected File soundFile;
protected Clip soundClip;
protected Object lock = new Object();
protected volatile boolean playing;
protected FloatControl volumeControl;
protected FloatControl gainControl;
public SoundEffect(File fileName) throws IOException, UnsupportedAudioFileException, LineUnavailableException
{
soundFile = fileName;
AudioInputStream in = AudioSystem.getAudioInputStream(soundFile);
soundClip = AudioSystem.getClip();
soundClip.open(in);
soundClip.addLineListener(this);
volume = 1.0f;
playing = false;
if (soundClip.isControlSupported(FloatControl.Type.VOLUME))
volumeControl = (FloatControl)soundClip.getControl(FloatControl.Type.VOLUME);
else
{
volumeControl = null;
}
if (soundClip.isControlSupported(FloatControl.Type.MASTER_GAIN))
gainControl = (FloatControl)soundClip.getControl(FloatControl.Type.MASTER_GAIN);
else
{
logger.warning("No gain control available!");
gainControl = null;
}
}
/**
* Start playing the sound, even if it's playing already
*/
public void play()
{
playing = true;
soundClip.setFramePosition(0);
soundClip.start();
}
/**
* Start playing the sound if it's not playing already
*/
public void playIfNot()
{
if (!playing)
play();
}
/**
* Stop the sound playing
*/
public void stop()
{
soundClip.stop();
playing = false;
}
/**
* Loop until we tell it to stop
*/
public void loop()
{
playing = true;
soundClip.loop(Clip.LOOP_CONTINUOUSLY);
}
/**
* Loop for a certain number of times
* @param numTimes The number of times to loop
*/
public void loop(int numTimes)
{
playing = true;
soundClip.loop(numTimes);
}
/**
* Returns true if this sound effect is currently being played
* @return Whether the sound is being played or not
*/
public boolean isPlaying()
{
return playing;
}
/**
* Called when the sound clip this class wraps changes state
*/
public void update(LineEvent event)
{
if (event.getType().equals(LineEvent.Type.STOP))
{
logger.info("A sound effect stopped.");
playing = false;
lock.notifyAll();
}
else if (event.getType().equals(LineEvent.Type.START))
{
logger.info("A sound effect started playing.");
}
else if (event.getType().equals(LineEvent.Type.OPEN))
{
logger.info("A sound effect was loaded.");
}
}
// I don't think this is a good idea in what is essentially an event-driven system -Daryl
// public void waitUntilDone()
// {
// synchronized (lock)
// {
// while (playing)
// {
// try { lock.wait(10); }
// catch (InterruptedException er) { }
// }
// }
// }
/**
* Get the current volume in the range of 0.0 to 1.0
* @return The current volume
*/
public float getVolume()
{
return volume;
}
/**
* Set the current volume level
* @param v The desired volume level between 0.0 and 1.0
* Note that if it might not actually change the volume level if the audio clip has no volume or gain controls avaiable
*/
public void setVolume(float v)
{
logger.info(String.format("client.audio.SoundEffect.setVolume(): Settings a volume of %.1f on audio clip %s.", v, soundFile.getName()));
volume = v;
if (volumeControl != null)
volumeControl.setValue(volume);
else if (gainControl != null)
{
float vol = -10*(1 - v);
vol = Math.min(6, vol);
gainControl.setValue(vol);
}
}
}