package micromod.output;
import micromod.output.converters.AudioFormatConverter;
import javax.sound.sampled.*;
/**
An OutputDevice for the Java1.3 audio system.
The one Java should have had 3 years ago ...
Because of the clunky way JavaSound drains it's buffer,
this class implements a workaround that alters the behaviour of
framesAvailable() to return more fine-grained values.
30 July 2003 (Jon Zeppieri): added getLine(), so we can
control volume on the line
*/
public class JavaSoundOutputDevice extends HasAvailableOutputDevice {
protected int samplingRate, bufferFrames, available;
protected long timeMillis, lastMillis;
protected SourceDataLine sourceDataLine;
/**
@param format An instance of micromod.output.AudioFormatConverter
@param samplingRate Try 44100
@param bufferTimeMillis The number of milliseconds of audio to buffer.
*/
public JavaSoundOutputDevice( AudioFormatConverter converter, int samplingRate, int bufferTimeMillis ) throws OutputDeviceException {
this.samplingRate = samplingRate;
int bitsPerSample = converter.getBytesPerFrame()/converter.getNumberOfChannels()*8;
initialise(converter);
AudioFormat outFormat = new AudioFormat( samplingRate, bitsPerSample,
converter.getNumberOfChannels(),
converter.isSigned(),
converter.isBigEndian() );
try {
DataLine.Info lineInfo = new DataLine.Info( SourceDataLine.class, outFormat );
sourceDataLine = (SourceDataLine)AudioSystem.getLine(lineInfo);
sourceDataLine.open( outFormat, (bufferTimeMillis*samplingRate/1000)*bytesPerFrame );
}
catch( LineUnavailableException e ) {
//e.printStackTrace();
throw new OutputDeviceException(" JavaSoundOutputDevice: Can't get a valid audio line!");
}
bufferFrames=sourceDataLine.getBufferSize()/bytesPerFrame;
System.out.println("\n JavaSound Realtime Output Device 0.8 initialised.");
}
// Added 30 July 2003 (Jon Zeppieri)
public SourceDataLine getLine()
{
return sourceDataLine;
}
public int framesAvailable() {
// A bit cleaner than the last version, eh?
timeMillis=System.currentTimeMillis();
available += (int)(timeMillis-lastMillis)*samplingRate/1000;
int realAvailable=super.framesAvailable();
if(available>realAvailable||realAvailable>=bufferFrames) available=realAvailable;
lastMillis=timeMillis;
return available;
}
public void write( byte[] buffer, int length ) {
sourceDataLine.write( buffer, 0, length );
available-=length/bytesPerFrame;
}
public int getSamplingRate() {
return samplingRate;
}
public void start() {
sourceDataLine.start();
available=super.framesAvailable();
lastMillis=System.currentTimeMillis();
}
public void pause() {
sourceDataLine.stop();
}
public void stop() {
sourceDataLine.drain();
// Assume hardware buffer is max. 50% JS buffersize (as it is on my linux system)
try{Thread.sleep(bufferFrames*500/samplingRate);}catch(InterruptedException ie){}
sourceDataLine.stop();
}
public void close() {
sourceDataLine.close();
}
protected int bytesAvailable() {
return sourceDataLine.available();
}
}