/*
* 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.TargetDataLine;
import ddf.minim.AudioEffect;
import ddf.minim.AudioListener;
import ddf.minim.Minim;
import ddf.minim.MultiChannelBuffer;
import ddf.minim.spi.AudioStream;
// This is our AudioInput!
final class JSAudioInput extends Thread
implements AudioStream
{
private AudioListener listener;
private AudioEffect effect;
// line reading variables
private TargetDataLine line;
private FloatSampleBuffer buffer;
private int bufferSize;
private boolean finished;
private boolean mono;
private byte[] rawBytes;
JSAudioInput(TargetDataLine tdl, int bufferSize)
{
line = tdl;
this.bufferSize = bufferSize;
buffer = new FloatSampleBuffer(tdl.getFormat().getChannels(),
bufferSize,
tdl.getFormat().getSampleRate());
finished = false;
mono = ( buffer.getChannelCount() == 1 );
int byteBufferSize = buffer.getByteArrayBufferSize(line.getFormat());
Minim.debug("byteBufferSize is " + byteBufferSize);
rawBytes = new byte[byteBufferSize];
}
public void run()
{
line.start();
while ( !finished )
{
// read from the line
line.read(rawBytes, 0, rawBytes.length);
// convert to float samples
buffer.setSamplesFromBytes(rawBytes, 0, line.getFormat(),
0, buffer.getSampleCount());
// apply effects, if any, and broadcast the result
// to all listeners
if ( mono )
{
float[] samp = buffer.getChannel(0);
effect.process(samp);
listener.samples(samp);
}
else
{
float[] sampL = buffer.getChannel(0);
float[] sampR = buffer.getChannel(1);
effect.process(sampL, sampR);
listener.samples(sampL, sampR);
}
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
// we are done, clean up the line
line.flush();
line.stop();
line.close();
line = null;
}
public void open()
{
// start();
line.start();
}
public void close()
{
finished = true;
// we are done, clean up the line
line.flush();
line.stop();
line.close();
}
public int bufferSize()
{
return bufferSize;
}
public AudioFormat getFormat()
{
return line.getFormat();
}
public void setAudioEffect(AudioEffect effect)
{
this.effect = effect;
}
public void setAudioListener(AudioListener listener)
{
this.listener = listener;
}
public Control[] getControls()
{
return line.getControls();
}
public float[] read()
{
// TODO: this is sort of terrible, but will do for now. would be much better
// to dig the conversion stuff out of FloatSampleBuffer and do this more directly
int numSamples = 1;
// allocate enough bytes for one sample frame
byte[] bytes = new byte[ line.getFormat().getFrameSize() ];
line.read(bytes, 0, bytes.length);
buffer.setSamplesFromBytes(bytes, 0, line.getFormat(), 0, numSamples);
// allocate enough floats for the number of channels
float[] samples = new float[ buffer.getChannelCount() ];
for(int i = 0; i < samples.length; i++)
{
samples[i] = buffer.getChannel(i)[0];
}
return samples;
}
public int read(MultiChannelBuffer buffer)
{
// create our converter object
int numChannels = line.getFormat().getChannels();
int numSamples = buffer.getBufferSize();
float sampleRate = line.getFormat().getSampleRate();
FloatSampleBuffer convert = new FloatSampleBuffer( numChannels, numSamples, sampleRate );
// allocate enough bytes for the size of this buffer
byte[] bytes = new byte[ convert.getByteArrayBufferSize(line.getFormat()) ];
// read the bytes
line.read(bytes, 0, bytes.length);
// convert the bytes
convert.setSamplesFromBytes(bytes, 0, line.getFormat(), 0, numSamples);
// copy the converted floats into the MultiChannelBuffer
// make sure it has the correct number of channels first
buffer.setChannelCount(numChannels);
for(int i = 0; i < convert.getChannelCount(); i++)
{
buffer.setChannel(i, convert.getChannel(i));
}
return numSamples;
}
}