/*
* Copyright (c) 2007 by Damien Di Fede <ddf@compartmental.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package ddf.minim.javasound;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.Control;
import javax.sound.sampled.SourceDataLine;
import ddf.minim.AudioEffect;
import ddf.minim.AudioListener;
import ddf.minim.AudioSignal;
import ddf.minim.Minim;
import ddf.minim.MultiChannelBuffer;
import ddf.minim.spi.AudioOut;
import ddf.minim.spi.AudioStream;
final class JSAudioOutput extends Thread implements AudioOut
{
private AudioListener listener;
private AudioStream stream;
private AudioSignal signal;
private AudioEffect effect;
private SourceDataLine line;
private AudioFormat format;
private FloatSampleBuffer buffer;
private MultiChannelBuffer mcBuffer;
private int bufferSize;
private boolean finished;
private byte[] outBytes;
JSAudioOutput(SourceDataLine sdl, int bufferSize)
{
super();
this.bufferSize = bufferSize;
format = sdl.getFormat();
buffer = new FloatSampleBuffer(format.getChannels(), bufferSize, format.getSampleRate());
mcBuffer = new MultiChannelBuffer(bufferSize, format.getChannels());
outBytes = new byte[buffer.getByteArrayBufferSize(format)];
finished = false;
line = sdl;
}
public void run()
{
line.start();
while (!finished)
{
buffer.makeSilence();
if ( signal != null )
{
readSignal();
}
else if ( stream != null )
{
readStream();
}
if (line.getFormat().getChannels() == Minim.MONO)
{
effect.process(buffer.getChannel(0));
listener.samples(buffer.getChannel(0));
}
else
{
effect.process(buffer.getChannel(0), buffer.getChannel(1));
listener.samples(buffer.getChannel(0), buffer.getChannel(1));
}
buffer.convertToByteArray(outBytes, 0, format);
if ( line.available() == line.getBufferSize() )
{
Minim.debug("Likely buffer underrun in AudioOutput.");
}
line.write(outBytes, 0, outBytes.length);
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
}
}
line.drain();
line.stop();
line.close();
line = null;
}
// TODO: ditch readSignal eventually
private void readSignal()
{
if (line.getFormat().getChannels() == Minim.MONO)
{
//long start = System.nanoTime();
signal.generate(buffer.getChannel(0));
//long end = System.nanoTime();
//long elap = (end - start) / 1000;
//System.out.println("Generated a buffer in " + elap + " microseconds.");
}
else
{
signal.generate(buffer.getChannel(0), buffer.getChannel(1));
}
}
private void readStream()
{
stream.read(mcBuffer);
for(int i = 0; i < mcBuffer.getChannelCount(); i++)
{
System.arraycopy(mcBuffer.getChannel(i), 0, buffer.getChannel(i), 0, buffer.getSampleCount());
}
}
public void open()
{
start();
}
public void close()
{
finished = true;
}
public int bufferSize()
{
return bufferSize;
}
public AudioFormat getFormat()
{
return format;
}
public void setAudioEffect(AudioEffect effect)
{
this.effect = effect;
}
public void setAudioSignal(AudioSignal signal)
{
this.signal = signal;
}
public void setAudioListener(AudioListener listener)
{
this.listener = listener;
}
public Control[] getControls()
{
return line.getControls();
}
public void setAudioStream(AudioStream stream)
{
this.stream = stream;
}
}