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.
This commit is contained in:
dennis.sheirer
2014-10-26 10:11:30 +00:00
parent 0ad710fea2
commit e61c3a891c
71 changed files with 1754 additions and 619 deletions

View File

@@ -0,0 +1,85 @@
/*******************************************************************************
* 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 sample.adapter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import source.mixer.MixerChannel;
/**
* Converts 16-bit little endian byte data into an array of floats
*/
public class ChannelShortAdapter extends SampleAdapter
{
private ByteOrder mByteOrder = ByteOrder.LITTLE_ENDIAN;
private MixerChannel mMixerChannel;
public ChannelShortAdapter( MixerChannel channel )
{
/* Only use with LEFT/RIGHT channels */
assert( channel != MixerChannel.MONO );
mMixerChannel = channel;
}
@Override
public float[] convert( byte[] samples )
{
float[] processed = new float[ samples.length / 4 ];
int pointer = 0;
/* Wrap byte array in a byte buffer so we can process them as shorts */
ByteBuffer buffer = ByteBuffer.wrap( samples );
/* Set endian to correct byte ordering */
buffer.order( mByteOrder );
while( buffer.hasRemaining() )
{
if( mMixerChannel == MixerChannel.LEFT )
{
processed[ pointer ] = (float)buffer.getShort();
/* Throw away the right channel */
buffer.getShort();
}
else
{
/* Throw away the left channel */
buffer.getShort();
processed[ pointer ] = (float)buffer.getShort();
}
pointer++;
}
return processed;
}
/**
* Set byte interpretation to little or big endian. Defaults to LITTLE
* endian
*/
public void setByteOrder( ByteOrder order )
{
mByteOrder = order;
}
}

View File

@@ -15,10 +15,11 @@
* 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 sample;
package sample.adapter;
import java.util.List;
import sample.Listener;
import sample.complex.ComplexSample;
import source.mixer.MixerChannel;

View File

@@ -15,8 +15,9 @@
* 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 sample;
package sample.adapter;
import sample.Listener;
import sample.complex.ComplexSample;
public class FloatArrayToComplexAdapter implements Listener<Float[]>

View File

@@ -15,43 +15,13 @@
* 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 sample.complex;
package sample.adapter;
@Deprecated
public class RTLComplexSample extends ComplexSample
/*
* Adapter to convert byte data received from a data stream into float[]
* samples
*/
public abstract class SampleAdapter
{
private static final long serialVersionUID = 1L;
private static float[] mValues;
/**
* Creates a lookup table that converts the 8-bit valued range from 0 - 255
* into scaled float values of -128 to 0 to 127
*/
static
{
mValues = new float[ 256 ];
float scale = (float)( 1.0f / 127.0f );
for( int x = 0; x < 256; x++ )
{
mValues[ x ] = (float)( x - 128 ) * scale;
}
mValues[ 128 ] = 0.0000001f;
}
/**
* Constructs a complex sample from the sample format produced by the
* RTL-2832 chip, where the byte values run from 0 - 255, but represent
* the value -127 to 127
*
* @param left
* @param right
*/
public RTLComplexSample( byte left, byte right )
{
super( mValues[ left & 0xFF ], mValues[ right & 0xFF ] );
}
public abstract float[] convert( byte[] samples );
}

View File

@@ -0,0 +1,61 @@
/*******************************************************************************
* 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 sample.adapter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Converts 16-bit little endian byte data into an array of floats
*/
public class ShortAdapter extends SampleAdapter
{
private ByteOrder mByteOrder = ByteOrder.LITTLE_ENDIAN;
@Override
public float[] convert( byte[] samples )
{
float[] processed = new float[ samples.length / 2 ];
int pointer = 0;
/* Wrap byte array in a byte buffer so we can process them as shorts */
ByteBuffer buffer = ByteBuffer.wrap( samples );
/* Set endian to correct byte ordering */
buffer.order( mByteOrder );
while( buffer.hasRemaining() )
{
processed[ pointer ] = (float)buffer.getShort();
pointer++;
}
return processed;
}
/**
* Set byte interpretation to little or big endian. Defaults to LITTLE
* endian
*/
public void setByteOrder( ByteOrder order )
{
mByteOrder = order;
}
}

View File

@@ -0,0 +1,42 @@
package sample.complex;
import java.util.Arrays;
public class ComplexBuffer
{
private float[] mSamples;
/**
* Wrapper around float array containing interleaved I/Q samples
*/
public ComplexBuffer( float[] samples )
{
mSamples = samples;
}
/**
* Creates a deep copy of the buffer
*/
public ComplexBuffer copyOf()
{
float[] copy = Arrays.copyOf( mSamples, mSamples.length );
return new ComplexBuffer( copy );
}
/**
* Interleaved I/Q float sample array
*/
public float[] getSamples()
{
return mSamples;
}
/**
* Cleanup method to nullify all data and references
*/
public void dispose()
{
mSamples = null;
}
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* 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 sample.complex;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Broadcasts received float samples to multiple listeners
*/
public class ComplexSampleBroadcaster implements ComplexSampleListener
{
private CopyOnWriteArrayList<ComplexSampleListener> mListeners =
new CopyOnWriteArrayList<ComplexSampleListener>();
@Override
public void receive( float i, float q )
{
broadcast( i, q );
}
/**
* Clear listeners to prepare for garbage collection
*/
public void dispose()
{
mListeners.clear();
}
public boolean hasListeners()
{
return !mListeners.isEmpty();
}
public int getListenerCount()
{
return mListeners.size();
}
public void addListener( ComplexSampleListener listener )
{
mListeners.add( listener );
}
public void removeListener( ComplexSampleListener listener )
{
mListeners.remove( listener );
}
public void clear()
{
mListeners.clear();
}
public void broadcast( float i, float q )
{
for( ComplexSampleListener listener: mListeners )
{
listener.receive( i, q );
}
}
}

View File

@@ -0,0 +1,6 @@
package sample.complex;
public interface ComplexSampleListener
{
public void receive( float i, float q );
}

View File

@@ -0,0 +1,58 @@
package sample.decimator;
import sample.complex.ComplexSampleListener;
public class ComplexDecimator implements ComplexSampleListener
{
private ComplexSampleListener mListener;
private int mCounter = 0;
private int mDecimationRate;
/**
* Constructs a new Decimator object with the specified decimation rate.
*/
public ComplexDecimator( int rate )
{
mDecimationRate = rate;
}
public void dispose()
{
mListener = null;
}
/**
* Sets a new decimation rate. Rate can be changed after this object
* is constructed.
*/
public synchronized void setDecimationRate( int rate )
{
mDecimationRate = rate;
}
/**
* Receives samples allowing only 1 of every (rate) sample to go on
* to the registered listener
*/
@Override
public void receive( float i, float q )
{
mCounter++;
if( mCounter >= mDecimationRate )
{
mListener.receive( i, q );
mCounter = 0;
}
}
/**
* Sets the decimated output listener
*/
public void setListener( ComplexSampleListener listener )
{
mListener = listener;
}
}

View File

@@ -15,7 +15,9 @@
* 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 sample;
package sample.decimator;
import sample.Listener;
public class Decimator<T> implements Listener<T>

View File

@@ -0,0 +1,58 @@
package sample.decimator;
import sample.complex.ComplexSampleListener;
public class SimplexDecimator implements ComplexSampleListener
{
private ComplexSampleListener mListener;
private int mCounter = 0;
private int mDecimationRate;
/**
* Constructs a new Decimator object with the specified decimation rate.
*/
public SimplexDecimator( int rate )
{
mDecimationRate = rate;
}
public void dispose()
{
mListener = null;
}
/**
* Sets a new decimation rate. Rate can be changed after this object
* is constructed.
*/
public synchronized void setDecimationRate( int rate )
{
mDecimationRate = rate;
}
/**
* Receives samples allowing only 1 of every (rate) sample to go on
* to the registered listener
*/
@Override
public void receive( float i, float q )
{
mCounter++;
if( mCounter >= mDecimationRate )
{
mListener.receive( i, q );
mCounter = 0;
}
}
/**
* Sets the decimated output listener
*/
public void setListener( ComplexSampleListener listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,42 @@
package sample.simplex;
import java.util.Arrays;
public class SimplexBuffer
{
private float[] mSamples;
/**
* Wrapper around float array containing float samples
*/
public SimplexBuffer( float[] samples )
{
mSamples = samples;
}
/**
* Creates a deep copy of the buffer
*/
public SimplexBuffer copyOf()
{
float[] copy = Arrays.copyOf( mSamples, mSamples.length );
return new SimplexBuffer( copy );
}
/**
* Sample data
*/
public float[] getSamples()
{
return mSamples;
}
/**
* Cleanup method to nullify all data and references
*/
public void dispose()
{
mSamples = null;
}
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* 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 sample.simplex;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Broadcasts a received float sample to multiple listeners
*/
public class SimplexSampleBroadcaster implements SimplexSampleListener
{
private CopyOnWriteArrayList<SimplexSampleListener> mListeners =
new CopyOnWriteArrayList<SimplexSampleListener>();
@Override
public void receive( float sample )
{
broadcast( sample );
}
/**
* Clear listeners to prepare for garbage collection
*/
public void dispose()
{
mListeners.clear();
}
public boolean hasListeners()
{
return !mListeners.isEmpty();
}
public int getListenerCount()
{
return mListeners.size();
}
public void addListener( SimplexSampleListener listener )
{
mListeners.add( listener );
}
public void removeListener( SimplexSampleListener listener )
{
mListeners.remove( listener );
}
public void clear()
{
mListeners.clear();
}
public void broadcast( float sample )
{
for( SimplexSampleListener listener: mListeners )
{
listener.receive( sample );
}
}
}

View File

@@ -0,0 +1,6 @@
package sample.simplex;
public interface SimplexSampleListener
{
public void receive( float sample );
}

View File

@@ -0,0 +1,8 @@
package sample.simplex;
public interface SimplexSampleProvider
{
public void setListener( SimplexSampleListener listener );
public void removeListener( SimplexSampleListener listener );
}