mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#108 [WIP] Created new ThreadPool class with a static ScheduledThreadExecutor that is now shared by all components. Removed ThreadPoolManager from all classes. Consolidating into 1 pool seems to have reduced CPU usage by ~15-20%. Overall memory usage is also reduced.
This commit is contained in:
@@ -1,22 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 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 source.tuner;
|
||||
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import dsp.mixer.Oscillator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Buffer;
|
||||
import sample.Listener;
|
||||
import sample.complex.Complex;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
@@ -26,371 +42,351 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.Buffer;
|
||||
import sample.Listener;
|
||||
import sample.complex.Complex;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import dsp.mixer.Oscillator;
|
||||
|
||||
public class TunerChannelSource extends ComplexSource
|
||||
implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
|
||||
implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( TunerChannelSource.class );
|
||||
|
||||
private static int CHANNEL_RATE = 48000;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
|
||||
private LinkedTransferQueue<ComplexBuffer> mBuffer =
|
||||
new LinkedTransferQueue<ComplexBuffer>();
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(TunerChannelSource.class);
|
||||
|
||||
private long mTunerFrequency = 0;
|
||||
private int mTunerSampleRate;
|
||||
private int mChannelFrequencyCorrection = 0;
|
||||
|
||||
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private boolean mExpended = false;
|
||||
|
||||
/**
|
||||
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
|
||||
* tuner down to a 48 kHz IQ channel rate.
|
||||
*
|
||||
* Note: this class can only be used once (started and stopped) and a new
|
||||
* tuner channel source must be requested from the tuner once this object
|
||||
* has been stopped. This is because channels are managed dynamically and
|
||||
* center tuned frequency may have changed since this source was obtained
|
||||
* and thus the tuner might no longer be able to source this channel once it
|
||||
* has been stopped.
|
||||
*
|
||||
* @param tuner to obtain wideband IQ samples from
|
||||
* @param tunerChannel specifying the center frequency for the DDC
|
||||
* @throws RejectedExecutionException if the thread pool manager cannot
|
||||
* accept the decimation processing task
|
||||
* @throws SourceException if the tuner has an issue providing IQ samples
|
||||
*/
|
||||
public TunerChannelSource( Tuner tuner, TunerChannel tunerChannel )
|
||||
throws RejectedExecutionException, SourceException
|
||||
private static int CHANNEL_RATE = 48000;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
|
||||
private LinkedTransferQueue<ComplexBuffer> mBuffer =
|
||||
new LinkedTransferQueue<ComplexBuffer>();
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
|
||||
private long mTunerFrequency = 0;
|
||||
private int mTunerSampleRate;
|
||||
private int mChannelFrequencyCorrection = 0;
|
||||
|
||||
private DecimationProcessor mDecimationProcessor = new DecimationProcessor();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private boolean mExpended = false;
|
||||
|
||||
/**
|
||||
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
|
||||
* tuner down to a 48 kHz IQ channel rate.
|
||||
*
|
||||
* Note: this class can only be used once (started and stopped) and a new
|
||||
* tuner channel source must be requested from the tuner once this object
|
||||
* has been stopped. This is because channels are managed dynamically and
|
||||
* center tuned frequency may have changed since this source was obtained
|
||||
* and thus the tuner might no longer be able to source this channel once it
|
||||
* has been stopped.
|
||||
*
|
||||
* @param tuner to obtain wideband IQ samples from
|
||||
* @param tunerChannel specifying the center frequency for the DDC
|
||||
* @throws RejectedExecutionException if the thread pool manager cannot
|
||||
* accept the decimation processing task
|
||||
* @throws SourceException if the tuner has an issue providing IQ samples
|
||||
*/
|
||||
public TunerChannelSource(Tuner tuner, TunerChannel tunerChannel)
|
||||
throws RejectedExecutionException, SourceException
|
||||
{
|
||||
mTuner = tuner;
|
||||
mTuner.getTunerController().addListener( (IFrequencyChangeProcessor)this );
|
||||
|
||||
mTunerChannel = tunerChannel;
|
||||
mTuner = tuner;
|
||||
mTuner.getTunerController().addListener((IFrequencyChangeProcessor) this);
|
||||
|
||||
mTunerChannel = tunerChannel;
|
||||
|
||||
mTunerFrequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
mTunerFrequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
/* Setup the frequency translator to the current source frequency */
|
||||
long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
|
||||
|
||||
mMixer = new Oscillator( frequencyOffset,
|
||||
mTuner.getTunerController().getSampleRate() );
|
||||
long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency();
|
||||
|
||||
mMixer = new Oscillator(frequencyOffset,
|
||||
mTuner.getTunerController().getSampleRate());
|
||||
|
||||
/* Fire a sample rate change event to setup the decimation chain */
|
||||
frequencyChanged( new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate() ) );
|
||||
frequencyChanged(new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate()));
|
||||
}
|
||||
|
||||
|
||||
public void start( ScheduledExecutorService executor )
|
||||
{
|
||||
if( mExpended )
|
||||
{
|
||||
throw new IllegalStateException( "Attempt to re-start an expended "
|
||||
+ "tuner channel source. TunerChannelSource objects can only "
|
||||
+ "be used once. " );
|
||||
}
|
||||
|
||||
if( mRunning.compareAndSet( false, true ))
|
||||
{
|
||||
|
||||
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
if(mExpended)
|
||||
{
|
||||
throw new IllegalStateException("Attempt to re-start an expended "
|
||||
+ "tuner channel source. TunerChannelSource objects can only "
|
||||
+ "be used once. ");
|
||||
}
|
||||
|
||||
if(mRunning.compareAndSet(false, true))
|
||||
{
|
||||
/* Schedule the decimation task to run every 10 ms (100 iterations/second) */
|
||||
mTaskHandle = executor.scheduleAtFixedRate( mDecimationProcessor,
|
||||
0, 10, TimeUnit.MILLISECONDS );
|
||||
mTaskHandle = executor.scheduleAtFixedRate(mDecimationProcessor,
|
||||
0, 10, TimeUnit.MILLISECONDS);
|
||||
|
||||
/* Finally, register to receive samples from the tuner */
|
||||
mTuner.addListener( (Listener<ComplexBuffer>)this );
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn( "Attempt to start() and already running tuner channel source was ignored" );
|
||||
}
|
||||
}
|
||||
mTuner.addListener((Listener<ComplexBuffer>) this);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Attempt to start() and already running tuner channel source was ignored");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if( mRunning.compareAndSet( true, false ))
|
||||
{
|
||||
mTuner.releaseChannel( this );
|
||||
mDecimationProcessor.shutdown();
|
||||
|
||||
if( mTaskHandle != null )
|
||||
{
|
||||
mTaskHandle.cancel( true );
|
||||
mTaskHandle = null;
|
||||
}
|
||||
|
||||
mBuffer.clear();
|
||||
|
||||
mExpended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn( "Attempt to stop() and already stopped tuner channel source was ignored" );
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(mRunning.compareAndSet(true, false))
|
||||
{
|
||||
mTuner.releaseChannel(this);
|
||||
mDecimationProcessor.shutdown();
|
||||
|
||||
if(mTaskHandle != null)
|
||||
{
|
||||
mTaskHandle.cancel(true);
|
||||
mTaskHandle = null;
|
||||
}
|
||||
|
||||
mBuffer.clear();
|
||||
|
||||
mExpended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Attempt to stop() and already stopped tuner channel source was ignored");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
if( !mRunning.get() )
|
||||
{
|
||||
if(!mRunning.get())
|
||||
{
|
||||
/* Tell the tuner to release/unregister our resources */
|
||||
mTuner.getTunerController().removeListener( this );
|
||||
mTuner = null;
|
||||
mTunerChannel = null;
|
||||
mBuffer = null;
|
||||
mFrequencyChangeProcessor = null;
|
||||
mListener = null;
|
||||
mMixer = null;
|
||||
mDecimationFilter.dispose();
|
||||
mDecimationFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
{
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( ComplexBuffer buffer )
|
||||
{
|
||||
if( mRunning.get() )
|
||||
{
|
||||
mBuffer.add( buffer );
|
||||
}
|
||||
mTuner.getTunerController().removeListener(this);
|
||||
// mTuner = null;
|
||||
// mTunerChannel = null;
|
||||
// mBuffer = null;
|
||||
// mFrequencyChangeProcessor = null;
|
||||
// mListener = null;
|
||||
// mMixer = null;
|
||||
// mDecimationFilter.dispose();
|
||||
// mDecimationFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrequencyChangeListener( IFrequencyChangeProcessor processor )
|
||||
public Tuner getTuner()
|
||||
{
|
||||
mFrequencyChangeProcessor = processor;
|
||||
return mTuner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer buffer)
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
mBuffer.add(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrequencyChangeListener(IFrequencyChangeProcessor processor)
|
||||
{
|
||||
mFrequencyChangeProcessor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
/* Save a pointer to the listener so that if we have to change the
|
||||
* decimation filter, we can re-add the listener */
|
||||
mListener = listener;
|
||||
|
||||
mDecimationFilter.setListener( listener );
|
||||
}
|
||||
mListener = listener;
|
||||
|
||||
@Override
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for frequency change events received from the tuner and channel
|
||||
* frequency correction events received from the channel consumer/listener
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException
|
||||
{
|
||||
// Echo the event to the registered event listener
|
||||
if( mFrequencyChangeProcessor != null )
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged( event );
|
||||
}
|
||||
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mTunerFrequency = event.getValue().longValue();
|
||||
updateMixerFrequencyOffset();
|
||||
break;
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
mChannelFrequencyCorrection = event.getValue().intValue();
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
if( mFrequencyChangeProcessor != null )
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(
|
||||
new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
mChannelFrequencyCorrection ) );
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
int sampleRate = event.getValue().intValue();
|
||||
|
||||
if( mTunerSampleRate != sampleRate )
|
||||
{
|
||||
mMixer.setSampleRate( sampleRate );
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory
|
||||
.getDecimationFilter( sampleRate,
|
||||
CHANNEL_RATE,
|
||||
1, //Order
|
||||
CHANNEL_PASS_FREQUENCY,
|
||||
60, //dB attenuation
|
||||
WindowType.HAMMING );
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilter.setListener( mListener );
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mDecimationFilter.setListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency -
|
||||
mTunerChannel.getFrequency() -
|
||||
mChannelFrequencyCorrection;
|
||||
@Override
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
mMixer.setFrequency( offset );
|
||||
}
|
||||
/**
|
||||
* Handler for frequency change events received from the tuner and channel
|
||||
* frequency correction events received from the channel consumer/listener
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event) throws SourceException
|
||||
{
|
||||
// Echo the event to the registered event listener
|
||||
if(mFrequencyChangeProcessor != null)
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(event);
|
||||
}
|
||||
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mTunerFrequency = event.getValue().longValue();
|
||||
updateMixerFrequencyOffset();
|
||||
break;
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
mChannelFrequencyCorrection = event.getValue().intValue();
|
||||
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
if(mFrequencyChangeProcessor != null)
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(
|
||||
new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
mChannelFrequencyCorrection));
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
int sampleRate = event.getValue().intValue();
|
||||
|
||||
if(mTunerSampleRate != sampleRate)
|
||||
{
|
||||
mMixer.setSampleRate(sampleRate);
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory
|
||||
.getDecimationFilter(sampleRate,
|
||||
CHANNEL_RATE,
|
||||
1, //Order
|
||||
CHANNEL_PASS_FREQUENCY,
|
||||
60, //dB attenuation
|
||||
WindowType.HAMMING);
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilter.setListener(mListener);
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency -
|
||||
mTunerChannel.getFrequency() -
|
||||
mChannelFrequencyCorrection;
|
||||
|
||||
mMixer.setFrequency(offset);
|
||||
}
|
||||
|
||||
public int getSampleRate() throws SourceException
|
||||
{
|
||||
return CHANNEL_RATE;
|
||||
return CHANNEL_RATE;
|
||||
}
|
||||
|
||||
public long getFrequency() throws SourceException
|
||||
{
|
||||
return mTunerChannel.getFrequency();
|
||||
return mTunerChannel.getFrequency();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decimates an inbound buffer of I/Q samples from the source down to the
|
||||
* standard 48000 channel sample rate
|
||||
*/
|
||||
public class DecimationProcessor implements Runnable
|
||||
{
|
||||
private boolean mProcessing = true;
|
||||
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
|
||||
public class DecimationProcessor implements Runnable
|
||||
{
|
||||
private boolean mProcessing = true;
|
||||
private List<ComplexBuffer> mSampleBuffers = new ArrayList<ComplexBuffer>();
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
mProcessing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
mProcessing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
/* General exception handler so that any errors won't kill the
|
||||
* decimation thread and cause the input buffers to fill up and
|
||||
* run the program out of memory */
|
||||
try
|
||||
{
|
||||
if( mProcessing )
|
||||
{
|
||||
{
|
||||
// long start = System.currentTimeMillis();
|
||||
|
||||
mBuffer.drainTo( mSampleBuffers, 8 );
|
||||
|
||||
for( Buffer buffer: mSampleBuffers )
|
||||
{
|
||||
try
|
||||
{
|
||||
if(mProcessing)
|
||||
{
|
||||
{
|
||||
mBuffer.drainTo(mSampleBuffers, 8);
|
||||
|
||||
for(Buffer buffer : mSampleBuffers)
|
||||
{
|
||||
/* Check to see if we've been shutdown */
|
||||
if( !mProcessing )
|
||||
{
|
||||
mBuffer.clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
float[] samples = buffer.getSamples();
|
||||
if(!mProcessing)
|
||||
{
|
||||
mBuffer.clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
float[] samples = buffer.getSamples();
|
||||
|
||||
/* We make a copy of the buffer so that we don't affect
|
||||
* anyone else that is using the same buffer, like other
|
||||
* channels or the spectral display */
|
||||
float[] translated = new float[ samples.length ];
|
||||
float[] translated = new float[samples.length];
|
||||
|
||||
/* Perform frequency translation */
|
||||
for( int x = 0; x < samples.length; x += 2 )
|
||||
{
|
||||
mMixer.rotate();
|
||||
|
||||
translated[ x ] = Complex.multiplyInphase(
|
||||
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
mMixer.rotate();
|
||||
|
||||
translated[ x + 1 ] = Complex.multiplyQuadrature(
|
||||
samples[ x ], samples[ x + 1 ], mMixer.inphase(), mMixer.quadrature() );
|
||||
}
|
||||
|
||||
if( mProcessing && mDecimationFilter != null )
|
||||
{
|
||||
mDecimationFilter.receive( new ComplexBuffer( translated ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mLog.debug( "Processed [" + mSampleBuffers.size() + "] in " + ( System.currentTimeMillis() - start ) );
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
translated[x] = Complex.multiplyInphase(
|
||||
samples[x], samples[x + 1], mMixer.inphase(), mMixer.quadrature());
|
||||
|
||||
translated[x + 1] = Complex.multiplyQuadrature(
|
||||
samples[x], samples[x + 1], mMixer.inphase(), mMixer.quadrature());
|
||||
}
|
||||
|
||||
if(mProcessing)
|
||||
{
|
||||
final ComplexPrimeCICDecimate filter = mDecimationFilter;
|
||||
filter.receive(new ComplexBuffer(translated));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
/* Only log the stack trace if we're still processing */
|
||||
if( mProcessing )
|
||||
{
|
||||
mLog.error( "Error encountered during decimation process", e );
|
||||
}
|
||||
}
|
||||
if(mProcessing)
|
||||
{
|
||||
mLog.error("Error encountered during decimation process", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if we've been shutdown */
|
||||
if( !mProcessing )
|
||||
{
|
||||
mBuffer.clear();
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
if(!mProcessing)
|
||||
{
|
||||
mBuffer.clear();
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user