Files
sdrtrunk/src/record/wave/FloatWaveRecorder.java
dennis.sheirer e61c3a891c Memory/CPU performance improvement and Audio/Mixer source restructuring
Converted to use float primitives and to keep samples in buffer format until the sample rate is decimated to 48kHz.  
Added new non-recursive, CIC decimation filter -- untested

Updated sound card/mixer input source management.  Now testing for mono/stereo support for each card and limiting channel choices accordingly.  Separated the mixersource into a ComplexMixer and and SimplexMixerSource.  The ComplexMixer is used for sound card based tuners like the funcube.  The SimplexMixerSource is used for demodulated sound card inputs.

Interfaces for sample handling - standardized on using 'Complex' to indicate I/Q samples and 'Simplex' to indicate demodulated float samples.  The processing chain now accepts either a decimated (48k) list of complex samples from a tuner channel source, or a 48k simplex buffer (array of demodulated float samples).

Resolved issue with HackRF tuner not applying tuner configuration information.
2014-10-26 10:11:30 +00:00

178 lines
4.5 KiB
Java

/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* 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 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package record.wave;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue;
import javax.sound.sampled.AudioFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import record.Recorder;
import record.RecorderType;
import sample.simplex.SimplexSampleListener;
import util.waveaudio.WaveWriter;
import buffer.FloatSampleBufferAssembler;
/**
* Threaded WAVE audio recorder for recording mono float samples to a wave file
*/
public class FloatWaveRecorder extends Recorder implements SimplexSampleListener
{
private final static Logger mLog =
LoggerFactory.getLogger( FloatWaveRecorder.class );
private AudioFormat mAudioFormat;
private boolean mRunning = false;
private boolean mPaused = false;
private WaveWriter mWriter;
private String mFileName;
private BufferProcessor mBufferProcessor;
//Sample buffer queue ... constrained to 512 sample buffers (arbitrary size)
private LinkedBlockingQueue<ByteBuffer> mToWriteBufferQueue =
new LinkedBlockingQueue<ByteBuffer>( 512 );
private FloatSampleBufferAssembler mCurrentBuffer;
public FloatWaveRecorder( int sampleRate, String filename )
{
super( RecorderType.AUDIO );
mAudioFormat = new AudioFormat( sampleRate, //SampleRate
16, //Sample Size
1, //Channels
true, //Signed
false ); //Little Endian
mCurrentBuffer = new FloatSampleBufferAssembler( sampleRate );
mFileName = filename;
}
@Override
public String getFileName()
{
return mFileName + ".wav";
}
public void start() throws IOException
{
if( !mRunning )
{
mWriter = new WaveWriter( mFileName + ".wav", mAudioFormat );
mWriter.start();
mBufferProcessor = new BufferProcessor();
mBufferProcessor.start();
mRunning = true;
}
}
public void stop() throws IOException
{
if( mRunning )
{
mBufferProcessor = null;
mWriter.stop();
mWriter = null;
mRunning = false;
}
}
public void pause()
{
mPaused = true;
}
public void resume()
{
mPaused = false;
}
/**
* Assumes that the byte[] represents samples corresponding to the
* audio format object defined at construction
*/
public void receive( ByteBuffer buffer )
{
if( mRunning && !mPaused )
{
boolean success = mToWriteBufferQueue.offer( buffer );
if( !success )
{
mLog.error( "Wave recorder buffer overflow - throwing away " +
buffer.capacity() + " samples" );
}
}
}
@Override
public void receive( float sample )
{
mCurrentBuffer.put( sample );
if( !mCurrentBuffer.hasRemaining() )
{
//Dispatch the buffer to be written to disk
if( !mToWriteBufferQueue.offer( mCurrentBuffer.get() ) )
{
//We had an overflow ... log it
mLog.error( "FloatWaveRecorder: buffer overflow - throwing "
+ "away 1 second of sample data" );
}
mCurrentBuffer.reset();
}
}
public class BufferProcessor extends Thread
{
public void run()
{
while( true )
{
try
{
if( mWriter != null )
{
mWriter.write( mToWriteBufferQueue.take() );
}
}
catch ( IOException ioe )
{
mLog.error( "IOException while trying to write to the wave "
+ "writer", ioe );
}
catch ( InterruptedException e )
{
mLog.error( "Oops ... error while processing the buffer "
+ "queue for the wave recorder", e );
}
}
}
}
}