From 550aed79d43ce2347700c6e5dca455f0b10a44c6 Mon Sep 17 00:00:00 2001 From: "dennis.sheirer" Date: Sat, 27 Sep 2014 09:46:18 +0000 Subject: [PATCH] Changed FrequencyChangeListener interface to an event so that I could describe what event was causing the frequency change and to broadcast frequency and sample rate error values. R820T - added a couple more sample rate settings to the enum and modified the periodic sample rate info logger. --- src/controller/channel/ProcessingChain.java | 11 +- src/dsp/afc/AutomaticFrequencyControl.java | 32 ++- src/dsp/afc/FrequencyErrorListener.java | 10 - src/dsp/filter/FilterFactory.java | 10 +- src/gui/control/JFrequencyControl.java | 14 +- .../complex/ComplexSampleRateCounter.java | 114 ----------- src/source/recording/Recording.java | 24 ++- src/source/tuner/FrequencyChangeEvent.java | 34 ++++ src/source/tuner/FrequencyChangeListener.java | 13 +- src/source/tuner/FrequencyController.java | 31 ++- .../NumericallyControlledOscillator.java | 127 ------------ src/source/tuner/Tuner.java | 47 ++++- src/source/tuner/TunerChannelSource.java | 144 ++++++------- src/source/tuner/TunerController.java | 3 +- src/source/tuner/TunerNode.java | 34 +++- .../tuner/fcd/proV1/FCD1TunerController.java | 2 +- .../tuner/fcd/proV1/FCD1TunerEditorPanel.java | 26 ++- .../fcd/proplusV2/FCD2TunerController.java | 2 +- .../fcd/proplusV2/FCD2TunerEditorPanel.java | 27 ++- .../tuner/rtl/RTL2832TunerController.java | 192 +++++++++++++----- .../tuner/rtl/e4k/E4KTunerEditorPanel.java | 39 ++-- .../r820t/R820TTunerConfigurationPanel.java | 60 ++++++ .../rtl/r820t/R820TTunerEditorPanel.java | 39 ++-- src/spectrum/ChannelSpectrumPanel.java | 5 +- src/spectrum/DFTProcessor.java | 17 +- src/spectrum/OverlayPanel.java | 19 +- src/spectrum/SpectralDisplayPanel.java | 18 +- src/util/Oscillator.java | 6 + 28 files changed, 600 insertions(+), 500 deletions(-) delete mode 100644 src/dsp/afc/FrequencyErrorListener.java delete mode 100644 src/sample/complex/ComplexSampleRateCounter.java create mode 100644 src/source/tuner/FrequencyChangeEvent.java delete mode 100644 src/source/tuner/NumericallyControlledOscillator.java diff --git a/src/controller/channel/ProcessingChain.java b/src/controller/channel/ProcessingChain.java index 19b89017..b76bf591 100644 --- a/src/controller/channel/ProcessingChain.java +++ b/src/controller/channel/ProcessingChain.java @@ -46,6 +46,7 @@ import source.FloatSource; import source.Source; import source.SourceException; import source.config.SourceConfigMixer; +import source.tuner.FrequencyChangeListener; import source.tuner.Tuner; import source.tuner.TunerChannelSource; import alias.AliasList; @@ -61,7 +62,6 @@ import controller.state.ChannelState.State; import decode.Decoder; import decode.DecoderFactory; import dsp.afc.AutomaticFrequencyControl; -import dsp.afc.FrequencyErrorListener; import eventlog.EventLogType; import eventlog.EventLogger; @@ -403,16 +403,15 @@ public class ProcessingChain implements Listener mAFC = null; } - if( mSource instanceof FrequencyErrorListener && + if( mSource instanceof TunerChannelSource && mChannel.getDecodeConfiguration().isAFCEnabled() ) { - FrequencyErrorListener listener = - (FrequencyErrorListener)mSource; + TunerChannelSource tcs = (TunerChannelSource)mSource; - mAFC = new AutomaticFrequencyControl( listener ); + mAFC = new AutomaticFrequencyControl( tcs ); /* Register AFC to receive frequency change events */ - listener.addListener( mAFC ); + tcs.addListener( mAFC ); /* Add AFC as listener to the decoder */ mDecoder.addUnfilteredFloatListener( mAFC ); diff --git a/src/dsp/afc/AutomaticFrequencyControl.java b/src/dsp/afc/AutomaticFrequencyControl.java index 3dc211be..fa91b2a8 100644 --- a/src/dsp/afc/AutomaticFrequencyControl.java +++ b/src/dsp/afc/AutomaticFrequencyControl.java @@ -1,7 +1,9 @@ package dsp.afc; import sample.Listener; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; +import source.tuner.FrequencyChangeEvent.Attribute; import buffer.FloatAveragingBuffer; public class AutomaticFrequencyControl implements Listener, @@ -22,15 +24,14 @@ public class AutomaticFrequencyControl implements Listener, private int mSkipThreshold = 4; private int mErrorCorrection = 0; private long mCurrentFrequency; - private int mCurrentSampleRate; - private FrequencyErrorListener mListener; + private FrequencyChangeListener mListener; public enum Mode { NORMAL,FAST; } - public AutomaticFrequencyControl( FrequencyErrorListener listener ) + public AutomaticFrequencyControl( FrequencyChangeListener listener ) { mListener = listener; } @@ -57,7 +58,9 @@ public class AutomaticFrequencyControl implements Listener, { if( mListener != null ) { - mListener.setError( mErrorCorrection ); + mListener.frequencyChanged( + new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR, + mErrorCorrection ) ); } } @@ -156,14 +159,23 @@ public class AutomaticFrequencyControl implements Listener, } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - if( mCurrentFrequency != frequency || mCurrentSampleRate != bandwidth ) + switch( event.getAttribute() ) { - mCurrentFrequency = frequency; - mCurrentSampleRate = bandwidth; - - reset(); + case FREQUENCY: + int frequency = (int)event.getValue(); + + if( mCurrentFrequency != frequency ) + { + mCurrentFrequency = frequency; + + reset(); + } + case SAMPLE_RATE_ERROR: + break; + default: + break; } } } diff --git a/src/dsp/afc/FrequencyErrorListener.java b/src/dsp/afc/FrequencyErrorListener.java deleted file mode 100644 index b327bbee..00000000 --- a/src/dsp/afc/FrequencyErrorListener.java +++ /dev/null @@ -1,10 +0,0 @@ -package dsp.afc; - -import source.tuner.FrequencyChangeListener; - -public interface FrequencyErrorListener -{ - public void setError( int error ); - - public void addListener( FrequencyChangeListener listener ); -} diff --git a/src/dsp/filter/FilterFactory.java b/src/dsp/filter/FilterFactory.java index bbd3ec31..fd3099b6 100644 --- a/src/dsp/filter/FilterFactory.java +++ b/src/dsp/filter/FilterFactory.java @@ -406,7 +406,15 @@ public class FilterFactory int decimate = (int)( sampleRate / decimatedRate ); - filters[ 0 ] = new ComplexCICDecimate( decimate, 2, decimatedRate ); +// if( decimate < 25 ) +// { + filters[ 0 ] = new ComplexCICDecimate( decimate, 1, decimatedRate ); +// } +// else +// { +// filters[ 0 ] = new ComplexCICDecimate( decimate, 3, decimatedRate ); +// } + // int finalStopFrequency = decimatedRate - passFrequency; // diff --git a/src/gui/control/JFrequencyControl.java b/src/gui/control/JFrequencyControl.java index d70e25c8..50a6fc59 100644 --- a/src/gui/control/JFrequencyControl.java +++ b/src/gui/control/JFrequencyControl.java @@ -43,7 +43,9 @@ import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; +import source.tuner.FrequencyChangeEvent.Attribute; public class JFrequencyControl extends JPanel implements FrequencyChangeListener { @@ -132,9 +134,12 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener * rebroadcast this event, just set the control to indicate the new frequency. */ @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - setFrequency( frequency, false ); + if( event.getAttribute() == Attribute.FREQUENCY ) + { + setFrequency( (int)event.getValue(), false ); + } } /** @@ -174,9 +179,12 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener Iterator it = mListeners.iterator(); + FrequencyChangeEvent event = + new FrequencyChangeEvent( Attribute.FREQUENCY, mFrequency ); + while( it.hasNext() ) { - it.next().frequencyChanged( mFrequency, -1 ); + it.next().frequencyChanged( event ); } } diff --git a/src/sample/complex/ComplexSampleRateCounter.java b/src/sample/complex/ComplexSampleRateCounter.java deleted file mode 100644 index 81535894..00000000 --- a/src/sample/complex/ComplexSampleRateCounter.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * 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 - ******************************************************************************/ -package sample.complex; - -import gui.SDRTrunk; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sample.Listener; -import source.tuner.FrequencyChangeListener; -import buffer.FloatAveragingBuffer; - -public class ComplexSampleRateCounter implements Listener, - ComplexSampleListListener, - FrequencyChangeListener -{ - private final static Logger mLog = - LoggerFactory.getLogger( ComplexSampleRateCounter.class ); - - private int mCounter; - private int mAverageCounter; - private int mExpectedSampleRate; - private long mLastRun = 0; - private int mBufferSize = 100; - private FloatAveragingBuffer mAveragingBuffer; - - public ComplexSampleRateCounter( int expectedSampleRate, int bufferSize ) - { - mExpectedSampleRate = expectedSampleRate; - mBufferSize = bufferSize; - - mAveragingBuffer = new FloatAveragingBuffer( mBufferSize ); - - mLastRun = System.currentTimeMillis(); - - mLog.info( "Complex Sample Rate Counter started ...." ); - } - - @Override - public void receive( ComplexSample sample ) - { - mCounter++; - - if( mCounter >= mExpectedSampleRate ) - { - mCounter = 0; - - long now = System.currentTimeMillis(); - long elapsed = now - mLastRun; - mLastRun = now; - - float average = (float)mExpectedSampleRate * 1000.0f / (float)elapsed; - float runningAverage = mAveragingBuffer.get( average ); - - mAverageCounter++; - - mLog.info( "Complex Sample Rate Avg " + mAverageCounter + - " current [" + elapsed + " ms/" + average + - " hz] average [" + runningAverage + " hz] expected [" + - mExpectedSampleRate + " hz] over [" + - mBufferSize + "] buffer length" ); - } - } - - @Override - public void receive( List samples ) - { - mCounter += samples.size(); - - if( mCounter >= mExpectedSampleRate ) - { - mCounter -= mExpectedSampleRate; - - long now = System.currentTimeMillis(); - long elapsed = now - mLastRun; - mLastRun = now; - - float average = (float)mExpectedSampleRate * 1000.0f / (float)elapsed; - float runningAverage = mAveragingBuffer.get( average ); - - mAverageCounter++; - - mLog.info( "Complex Sample Rate Avg " + mAverageCounter + - " current [" + elapsed + " ms/" + average + - " hz] average [" + runningAverage + " hz] expected [" + - mExpectedSampleRate + " hz] over [" + - mBufferSize + "] buffer length" ); - } - } - - @Override - public void frequencyChanged( long frequency, int bandwidth ) - { - mExpectedSampleRate = bandwidth; - } -} diff --git a/src/source/recording/Recording.java b/src/source/recording/Recording.java index d19de698..501793dd 100644 --- a/src/source/recording/Recording.java +++ b/src/source/recording/Recording.java @@ -5,10 +5,12 @@ import java.util.ArrayList; import java.util.concurrent.RejectedExecutionException; import source.SourceException; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; import source.tuner.TunerChannel; import source.tuner.TunerChannelProvider; import source.tuner.TunerChannelSource; +import source.tuner.FrequencyChangeEvent.Attribute; import controller.ResourceManager; import controller.ThreadPoolManager; @@ -86,16 +88,22 @@ public class Recording implements Comparable, } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - mConfiguration.setCenterFrequency( frequency ); - mResourceManager.getSettingsManager().save(); - - mCenterFrequency = frequency; - - for( TunerChannelSource channel: mTunerChannels ) + if( event.getAttribute() == Attribute.FREQUENCY ) { - channel.frequencyChanged( frequency, bandwidth ); + int frequency = (int)event.getValue(); + + mConfiguration.setCenterFrequency( frequency ); + + mResourceManager.getSettingsManager().save(); + + mCenterFrequency = frequency; + + for( TunerChannelSource channel: mTunerChannels ) + { + channel.frequencyChanged( event ); + } } } diff --git a/src/source/tuner/FrequencyChangeEvent.java b/src/source/tuner/FrequencyChangeEvent.java new file mode 100644 index 00000000..b2dad23c --- /dev/null +++ b/src/source/tuner/FrequencyChangeEvent.java @@ -0,0 +1,34 @@ +package source.tuner; + +public class FrequencyChangeEvent +{ + public enum Attribute + { + SAMPLE_RATE_ERROR, + BANDWIDTH, + FREQUENCY, + FREQUENCY_ERROR, + SAMPLE_RATE; + } + + private Attribute mAttribute; + private long mValue; + + public FrequencyChangeEvent( Attribute attribute, long value ) + { + mAttribute = attribute; + mValue = value; + } + + public Attribute getAttribute() + { + return mAttribute; + } + + public long getValue() + { + return mValue; + } + + +} diff --git a/src/source/tuner/FrequencyChangeListener.java b/src/source/tuner/FrequencyChangeListener.java index ef8fea34..3aee68de 100644 --- a/src/source/tuner/FrequencyChangeListener.java +++ b/src/source/tuner/FrequencyChangeListener.java @@ -18,8 +18,8 @@ package source.tuner; /** - * Interface for broadcasting changes to frequency and/or bandwidth/sample rate - * to all registered listeners. + * Interface for broadcasting changes to frequency, bandwidth, sample rate, + * and actual sample rate values to all registered listeners. * * Note: broadcasted frequency should be the uncorrected, or displayable * frequency value. All frequency correction aspects should be handled within @@ -27,12 +27,5 @@ package source.tuner; */ public interface FrequencyChangeListener { - /** - * Broadcasts a change to the (uncorrected) frequency and/or bandwidth - * or sample rate. - * - * @param frequency - uncorrected frequency in hertz - * @param bandwidth - bandwidth in hertz - */ - public void frequencyChanged( long frequency, int bandwidth ); + public void frequencyChanged( FrequencyChangeEvent event ); } diff --git a/src/source/tuner/FrequencyController.java b/src/source/tuner/FrequencyController.java index cf80af6b..cfcb0150 100644 --- a/src/source/tuner/FrequencyController.java +++ b/src/source/tuner/FrequencyController.java @@ -20,6 +20,7 @@ package source.tuner; import java.util.ArrayList; import source.SourceException; +import source.tuner.FrequencyChangeEvent.Attribute; public class FrequencyController { @@ -29,7 +30,7 @@ public class FrequencyController private long mMinimumFrequency; private long mMaximumFrequency; private double mFrequencyCorrection = 0d; - private int mBandwidth = 0; + private int mSampleRate = 0; private ArrayList mListeners = new ArrayList(); @@ -50,17 +51,17 @@ public class FrequencyController */ public int getBandwidth() { - return mBandwidth; + return mSampleRate; } /** - * Set bandwidth/sample rate in hertz + * Set sample rate in hertz */ - public void setBandwidth( int bandwidth ) + public void setSampleRate( int sampleRate ) { - mBandwidth = bandwidth; + mSampleRate = sampleRate; - broadcastFrequencyChange(); + broadcastSampleRateChange(); } /** @@ -193,12 +194,28 @@ public class FrequencyController * bandwidth/sample rate value. */ protected void broadcastFrequencyChange() + { + broadcastFrequencyChangeEvent( + new FrequencyChangeEvent( Attribute.FREQUENCY, mFrequency ) ); + } + + /** + * Broadcasts a sample rate change + */ + protected void broadcastSampleRateChange() + { + broadcastFrequencyChangeEvent( + new FrequencyChangeEvent( Attribute.SAMPLE_RATE, mSampleRate ) ); + } + + public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event ) { for( FrequencyChangeListener listener: mListeners ) { - listener.frequencyChanged( mFrequency, mBandwidth ); + listener.frequencyChanged( event ); } } + public interface Tunable { diff --git a/src/source/tuner/NumericallyControlledOscillator.java b/src/source/tuner/NumericallyControlledOscillator.java deleted file mode 100644 index f49da924..00000000 --- a/src/source/tuner/NumericallyControlledOscillator.java +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* - * 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 - ******************************************************************************/ -package source.tuner; - -import sample.Listener; -import sample.complex.ComplexSample; -import sample.complex.ComplexSampleUtils; -import util.Oscillator; - -public class NumericallyControlledOscillator implements Listener, - FrequencyChangeListener -{ - private long mFrequency; - private int mSampleRate; - private Oscillator mSineWaveGenerator; - private Listener mListener; - /** - * Translates (shifts) frequency spectrum up or down, depending on the sign - * of the frequency argument, by mixing received complex samples with a - * generated sine wave of the frequency argument. Positive frequency shifts - * the received spectrum higher in frequency. Negative frequency shifts the - * received spectrum lower in frequency. In both cases, spectrum that is - * shifted outside of the sampling bandwidth will wrap around, due to the - * nature of quadrature sampling. - */ - public NumericallyControlledOscillator( long frequencyShift, int sampleRate ) - { - mFrequency = frequencyShift; - mSampleRate = sampleRate; - - int defaultMixingSignalGain = 10; - - mSineWaveGenerator = new Oscillator( mFrequency, mSampleRate ); - } - - /** - * Listener method for this class to receive samples from a Complex Sample - * Provider. This method multiplies the incoming sample by the generated - * mixing frequency to translate (ie shift +/-) the incoming signal, and - * then send the translated signal on to all registered listeners - */ - @Override - public void receive( ComplexSample sample ) - { - if( mListener != null ) - { - mListener.receive( ComplexSampleUtils.multiply( sample, - mSineWaveGenerator.nextComplex() ) ); - } - } - - @Override - public void frequencyChanged( long frequency, int bandwidth ) - { - if( frequency != mFrequency ) - { - setFrequency( frequency ); - } - - if( bandwidth != mSampleRate ) - { - setSampleRate( bandwidth ); - } - } - - /** - * Changes the frequency value and resets the sine wave generator, so that - * all subsequent samples will be output at the new translated frequency - * @param frequency - hertz - */ - public void setFrequency( long frequency ) - { - mFrequency = frequency; - mSineWaveGenerator.setFrequency( frequency ); - } - - /** - * Current frequency shift setting - * @return - frequency - hertz - */ - public long getFrequency() - { - return mFrequency; - } - - /** - * Changes the sample rate, so that all new input/output values will be - * translated at the new sample rate - * @param sampleRate - hertz - */ - public void setSampleRate( int sampleRate ) - { - mSampleRate = sampleRate; - mSineWaveGenerator.setSampleRate( sampleRate ); - } - - /** - * Add listener to receive frequency translated complex samples - */ - public void setListener( Listener listener ) - { - mListener = listener; - } - - /** - * Remove listener from receiving frequency translated complex samples. - */ - public void clearListener() - { - mListener = null; - } -} diff --git a/src/source/tuner/Tuner.java b/src/source/tuner/Tuner.java index f4df21ae..71d3afcb 100644 --- a/src/source/tuner/Tuner.java +++ b/src/source/tuner/Tuner.java @@ -24,6 +24,7 @@ import javax.swing.JPanel; import sample.Listener; import source.SourceException; +import source.tuner.FrequencyChangeEvent.Attribute; import controller.ResourceManager; import controller.ThreadPoolManager; @@ -172,11 +173,38 @@ public abstract class Tuner implements FrequencyChangeBroadcaster, /** * Broadcasts a frequency change event to all registered listeners */ - public void broadcastFrequencyChange( long frequency, int bandwidth ) + public void broadcastFrequencyChange( long frequency ) + { + broadcastFrequencyChangeEvent( + new FrequencyChangeEvent( Attribute.FREQUENCY, frequency ) ); + } + + /** + * Broadcasts a sample rate change event to all registered listeners + */ + public void broadcastSampleRateChange( int sampleRate ) + { + broadcastFrequencyChangeEvent( + new FrequencyChangeEvent( Attribute.SAMPLE_RATE, sampleRate ) ); + } + + /** + * Broadcasts actual sample rate change event to all registered listeners + */ + public void broadcastActualSampleRateChange( int actualSampleRate ) + { + broadcastFrequencyChangeEvent( + new FrequencyChangeEvent( Attribute.SAMPLE_RATE, actualSampleRate ) ); + } + + /** + * Broadcasts a frequency change event to all registered listeners + */ + public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event ) { for( FrequencyChangeListener listener: mFrequencyChangeListeners ) { - listener.frequencyChanged( frequency, bandwidth ); + listener.frequencyChanged( event ); } } @@ -184,8 +212,19 @@ public abstract class Tuner implements FrequencyChangeBroadcaster, * Frequency change listener method. We receive change events from the * controller and rebroadcast them to all registered listeners. */ - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - broadcastFrequencyChange( frequency, bandwidth ); + broadcastFrequencyChangeEvent( event ); } + +// /** +// * Broadcasts a frequency change event to all registered listeners +// */ +// public void broadcastBandwidthChange( int bandwidth ) +// { +// broadcastFrequencyChangeEvent( +// new FrequencyChangeEvent( Attribute.BANDWIDTH, bandwidth ) ); +// } +// + } diff --git a/src/source/tuner/TunerChannelSource.java b/src/source/tuner/TunerChannelSource.java index 2138c768..ac07d76c 100644 --- a/src/source/tuner/TunerChannelSource.java +++ b/src/source/tuner/TunerChannelSource.java @@ -29,17 +29,16 @@ import sample.complex.ComplexSample; import sample.complex.ComplexSampleAssembler; import source.ComplexSource; import source.SourceException; +import source.tuner.FrequencyChangeEvent.Attribute; import util.Oscillator; import controller.ThreadPoolManager; import controller.ThreadPoolManager.ThreadType; -import dsp.afc.FrequencyErrorListener; import dsp.filter.ComplexFilter; import dsp.filter.FilterFactory; import dsp.filter.Window.WindowType; public class TunerChannelSource extends ComplexSource implements FrequencyChangeListener, - FrequencyErrorListener, Listener { private static int sCHANNEL_RATE = 48000; @@ -64,32 +63,34 @@ public class TunerChannelSource extends ComplexSource public TunerChannelSource( ThreadPoolManager threadPoolManager, Tuner tuner, TunerChannel tunerChannel ) - throws RejectedExecutionException + throws RejectedExecutionException, SourceException { super( "Tuner Channel Source" ); mThreadPoolManager = threadPoolManager; - /* Schedule the decimation task to run 20 times a second */ - mTaskHandle = mThreadPoolManager.schedule( ThreadType.DECIMATION, - new DecimationProcessor(), 50, TimeUnit.MILLISECONDS ); mTuner = tuner; mTuner.addListener( (FrequencyChangeListener)this ); mTunerChannel = tunerChannel; + mTunerFrequency = mTuner.getFrequency(); + /* Setup the frequency translator to the current source frequency */ - try - { - frequencyChanged( mTuner.getFrequency(), mTuner.getSampleRate() ); - } - catch ( SourceException e ) - { - e.printStackTrace(); - } + long frequencyOffset = mTunerFrequency - mTunerChannel.getFrequency(); + + mSineWaveGenerator = new Oscillator( frequencyOffset, mTuner.getSampleRate() ); - /* Finally, register to receive samples from the tuner */ + /* Fire a sample rate change event to get the decimation chain setup */ + frequencyChanged( new FrequencyChangeEvent( + Attribute.SAMPLE_RATE, mTuner.getSampleRate() ) ); + + /* Schedule the decimation task to run 20 times a second */ + mTaskHandle = mThreadPoolManager.schedule( ThreadType.DECIMATION, + new DecimationProcessor(), 50, TimeUnit.MILLISECONDS ); + + /* Finally, register to receive samples from the tuner */ mTuner.addListener( (Listener)this ); } @@ -156,60 +157,73 @@ public class TunerChannelSource extends ComplexSource } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - /* Send change to Automatic Frequency Control */ + /* Send change to Automatic Frequency Control if it exists */ if( mFrequencyChangeListener != null ) { - mFrequencyChangeListener.frequencyChanged( frequency, bandwidth ); + mFrequencyChangeListener.frequencyChanged( event ); } - - long frequencyOffset = frequency - - mTunerChannel.getFrequency() - - mTunerFrequencyError; - if( mSineWaveGenerator == null ) + switch( event.getAttribute() ) { - mSineWaveGenerator = new Oscillator( frequencyOffset, bandwidth ); - } - else - { - mSineWaveGenerator.setFrequency( frequencyOffset ); - } - - /* Clear the buffer for the frequency to take immediate effect */ -// mBuffer.clear(); - - mTunerFrequency = frequency; - - /* Bandwidth/Sample rate change */ - if( bandwidth != mTunerSampleRate ) - { - /* Get the original decimation filter output listener */ -// Listener listener = null; - - /* Get new decimation filters */ - mDecimationFilters = FilterFactory - .getDecimationFilters( bandwidth, + case SAMPLE_RATE_ERROR: + break; + case SAMPLE_RATE: + int sampleRate = (int)event.getValue(); + + if( mTunerSampleRate != sampleRate ) + { + /* Set the oscillator to the new frequency */ + mSineWaveGenerator.setSampleRate( sampleRate ); + + /* Get new decimation filters */ + mDecimationFilters = FilterFactory + .getDecimationFilters( sampleRate, sCHANNEL_RATE, sCHANNEL_PASS_FREQUENCY, 48, //dB attenuation WindowType.HAMMING ); - - /* wire the filters together */ - if( mDecimationFilters.length > 1 ) - { - for( int x = 1; x < mDecimationFilters.length; x++ ) - { - mDecimationFilters[ x - 1 ].setListener( mDecimationFilters[ x ] ); - } - } - - /* re-add the original output listener */ - mDecimationFilters[ mDecimationFilters.length - 1 ] - .setListener( mBufferAssembler ); + + /* wire the filters together */ + if( mDecimationFilters.length > 1 ) + { + for( int x = 1; x < mDecimationFilters.length; x++ ) + { + mDecimationFilters[ x - 1 ] + .setListener( mDecimationFilters[ x ] ); + } + } + + /* re-add the original output listener */ + mDecimationFilters[ mDecimationFilters.length - 1 ] + .setListener( mBufferAssembler ); - mTunerSampleRate = bandwidth; + mTunerSampleRate = sampleRate; + } + break; + case FREQUENCY_ERROR: + mTunerFrequencyError = (int)event.getValue(); + + long frequencyErrorOffset = mTunerFrequency - + mTunerChannel.getFrequency() - + mTunerFrequencyError; + + mSineWaveGenerator.setFrequency( frequencyErrorOffset ); + break; + case FREQUENCY: + int frequency = (int)event.getValue(); + + /* If the frequency is updated, the AFC will also get reset, so + * we don't include the frequency error value here */ + long frequencyOffset = frequency - mTunerChannel.getFrequency(); + + mSineWaveGenerator.setFrequency( frequencyOffset ); + + mTunerFrequency = frequency; + break; + default: + break; } } @@ -264,20 +278,6 @@ public class TunerChannelSource extends ComplexSource } } - /** - * Automatic Frequency Control - */ - @Override - public void setError( int error ) - { - if( mTunerFrequencyError != error ) - { - mTunerFrequencyError = error; - frequencyChanged( mTunerFrequency, mTunerSampleRate ); - } - } - - @Override public void addListener( FrequencyChangeListener listener ) { mFrequencyChangeListener = listener; diff --git a/src/source/tuner/TunerController.java b/src/source/tuner/TunerController.java index f4e29025..71b51287 100644 --- a/src/source/tuner/TunerController.java +++ b/src/source/tuner/TunerController.java @@ -167,7 +167,8 @@ public abstract class TunerController implements Tunable updateLOFrequency(); - source = new TunerChannelSource( threadPoolManager, tuner, tunerChannel ); + source = new TunerChannelSource( threadPoolManager, + tuner, tunerChannel ); } return source; diff --git a/src/source/tuner/TunerNode.java b/src/source/tuner/TunerNode.java index e4f54dea..cbcf1b89 100644 --- a/src/source/tuner/TunerNode.java +++ b/src/source/tuner/TunerNode.java @@ -42,7 +42,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener private static DecimalFormat SAMPLE_RATE_FORMAT = new DecimalFormat( "0.000" ); private long mFrequency; - private int mBandwidth; + private int mSampleRate; public TunerNode( Tuner tuner ) { @@ -53,7 +53,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener try { mFrequency = tuner.getFrequency(); - mBandwidth = tuner.getSampleRate(); + mSampleRate = tuner.getSampleRate(); } catch ( SourceException e ) { @@ -82,7 +82,7 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener sb.append( " " ); sb.append( FREQUENCY_FORMAT.format( (double)mFrequency / 1E6d ) ); sb.append( " [" ); - sb.append( SAMPLE_RATE_FORMAT.format( (double)mBandwidth / 1E6d ) ); + sb.append( SAMPLE_RATE_FORMAT.format( (double)mSampleRate / 1E6d ) ); sb.append( "] MHz" ); return sb.toString(); @@ -122,11 +122,29 @@ public class TunerNode extends BaseNode implements FrequencyChangeListener } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - mFrequency = frequency; - mBandwidth = bandwidth; - - getModel().nodeChanged( TunerNode.this ); + switch( event.getAttribute() ) + { + case FREQUENCY: + int frequency = (int)event.getValue(); + + if( mFrequency != frequency ) + { + mFrequency = frequency; + getModel().nodeChanged( TunerNode.this ); + } + case SAMPLE_RATE: + int sampleRate = (int)event.getValue(); + + if( mSampleRate != sampleRate ) + { + mSampleRate = sampleRate; + getModel().nodeChanged( TunerNode.this ); + } + break; + default: + break; + } } } diff --git a/src/source/tuner/fcd/proV1/FCD1TunerController.java b/src/source/tuner/fcd/proV1/FCD1TunerController.java index 0f0f977a..11f267e7 100644 --- a/src/source/tuner/fcd/proV1/FCD1TunerController.java +++ b/src/source/tuner/fcd/proV1/FCD1TunerController.java @@ -60,7 +60,7 @@ public class FCD1TunerController extends FCDTunerController sMINIMUM_TUNABLE_FREQUENCY, sMAXIMUM_TUNABLE_FREQUENCY ); - mFrequencyController.setBandwidth( sSAMPLE_RATE ); + mFrequencyController.setSampleRate( sSAMPLE_RATE ); try { diff --git a/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java b/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java index e5dc6422..12c7b2c5 100644 --- a/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java +++ b/src/source/tuner/fcd/proV1/FCD1TunerEditorPanel.java @@ -30,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import source.SourceException; +import source.tuner.FrequencyChangeEvent; +import source.tuner.FrequencyChangeEvent.Attribute; import source.tuner.FrequencyChangeListener; import source.tuner.fcd.FCDTuner; import source.tuner.fcd.FCDTunerDetailsPanel; @@ -91,17 +93,19 @@ public class FCD1TunerEditorPanel extends JPanel implements FrequencyChangeListe } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - //Disregard the bandwidth value, which shouldn't be changing - try - { - mController.setFrequency( frequency ); - } - catch ( SourceException e ) - { - mLog.error( "FCTProController - error setting frequency [" + - frequency + "]", e ); - } + if( event.getAttribute() == Attribute.FREQUENCY ) + { + try + { + mController.setFrequency( event.getValue() ); + } + catch ( SourceException e ) + { + mLog.error( "FCTProController - error setting frequency [" + + event.getValue() + "]", e ); + } + } } } diff --git a/src/source/tuner/fcd/proplusV2/FCD2TunerController.java b/src/source/tuner/fcd/proplusV2/FCD2TunerController.java index 2fe5a07b..f6e27f42 100644 --- a/src/source/tuner/fcd/proplusV2/FCD2TunerController.java +++ b/src/source/tuner/fcd/proplusV2/FCD2TunerController.java @@ -53,7 +53,7 @@ public class FCD2TunerController extends FCDTunerController sMINIMUM_TUNABLE_FREQUENCY, sMAXIMUM_TUNABLE_FREQUENCY ); - mFrequencyController.setBandwidth( sSAMPLE_RATE ); + mFrequencyController.setSampleRate( sSAMPLE_RATE ); try { diff --git a/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java b/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java index 11ea9562..553f62c1 100644 --- a/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java +++ b/src/source/tuner/fcd/proplusV2/FCD2TunerEditorPanel.java @@ -30,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import source.SourceException; +import source.tuner.FrequencyChangeEvent; +import source.tuner.FrequencyChangeEvent.Attribute; import source.tuner.FrequencyChangeListener; import source.tuner.fcd.FCDTuner; import source.tuner.fcd.FCDTunerDetailsPanel; @@ -90,17 +92,20 @@ public class FCD2TunerEditorPanel extends JPanel implements FrequencyChangeListe } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - //Disregard the bandwidth, which shouldn't be changing - try - { - mController.setFrequency( frequency ); - } - catch ( SourceException e ) - { - mLog.error( "FCTProController - error setting frequency [" + - frequency + "]", e ); - } + if( event.getAttribute() == Attribute.FREQUENCY ) + { + //Disregard the bandwidth, which shouldn't be changing + try + { + mController.setFrequency( event.getValue() ); + } + catch ( SourceException e ) + { + mLog.error( "FCDProController - error setting frequency [" + + event.getValue() + "]", e ); + } + } } } diff --git a/src/source/tuner/rtl/RTL2832TunerController.java b/src/source/tuner/rtl/RTL2832TunerController.java index 4086f35b..5d090bb4 100644 --- a/src/source/tuner/rtl/RTL2832TunerController.java +++ b/src/source/tuner/rtl/RTL2832TunerController.java @@ -60,10 +60,13 @@ import org.usb4java.LibUsb; import sample.Listener; import source.SourceException; +import source.tuner.FrequencyChangeEvent; +import source.tuner.FrequencyChangeEvent.Attribute; import source.tuner.TunerController; import source.tuner.TunerType; import source.tuner.usb.USBTunerDevice; import util.TimeStamp; +import buffer.FloatAveragingBuffer; import controller.ResourceManager; public abstract class RTL2832TunerController extends TunerController @@ -85,7 +88,6 @@ public abstract class RTL2832TunerController extends TunerController (byte)( LibUsb.ENDPOINT_OUT | LibUsb.REQUEST_TYPE_VENDOR ); public final static byte sREQUEST_ZERO = (byte)0; - public final static int sUSB_IRP_DATA_SIZE = 65536; public final static int sUSB_IRP_POOL_SIZE = 10; public final static byte EEPROM_ADDRESS = (byte)0xA0; @@ -135,7 +137,9 @@ public abstract class RTL2832TunerController extends TunerController }; private static final DecimalFormat mDecimalFormatter = - new DecimalFormat( "###,###,###.#" ); + new DecimalFormat( "###,###,###.0" ); + private static final DecimalFormat mPercentFormatter = + new DecimalFormat( "###.00" ); private USBTunerDevice mUSBTunerDevice; protected UsbDevice mUSBDevice; @@ -163,6 +167,9 @@ public abstract class RTL2832TunerController extends TunerController private int mSampleRateAverageCount; protected int mOscillatorFrequency = 28800000; //28.8 MHz + private SampleRateMonitor mSampleRateMonitor; + public int mBufferSize = 16384; + /** * Abstract tuner controller device. Use the static getTunerClass() method * to determine the tuner type, and construct the corresponding child @@ -1163,7 +1170,17 @@ public abstract class RTL2832TunerController extends TunerController mSampleRate = sampleRate; - mFrequencyController.setBandwidth( sampleRate.getRate() ); + /** + * Adjust the size of the byte array buffers sent over the USB bus + */ + mBufferSize = mSampleRate.getBufferSize(); + + mFrequencyController.setSampleRate( sampleRate.getRate() ); + + if( mSampleRateMonitor != null ) + { + mSampleRateMonitor.setSampleRate( mSampleRate.getRate() ); + } } public void setSampleRateFrequencyCorrection( int ppm ) @@ -1392,34 +1409,37 @@ public abstract class RTL2832TunerController extends TunerController public enum SampleRate { /* Note: sample rates below 1.0MHz are subject to aliasing */ - RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz" ), - RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz" ), - RATE_0_912MHZ( 0x07E6, 0x0000, 912000, "0.912 MHz" ), - RATE_0_960MHZ( 0x077A, 0x0000, 960000, "0.960 MHz" ), - RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz" ), - RATE_1_440MHZ( 0x0500, 0x0000, 1440000, "1.440 MHz" ), - RATE_1_680MHZ( 0x044A, 0x0000, 1680000, "1.680 MHz" ), - RATE_1_824MHZ( 0x03F3, 0x0000, 1824000, "1.824 MHz" ), - RATE_2_016MHZ( 0x038F, 0x0000, 2016000, "2.016 MHz" ); - - /* Note: usb4java library buffer processing scheme doesn't seem capable - * of supporting these rates */ - //RATE_2_400MHZ( 0x0300, 0x0000, 2400000, "2.400 MHz" ), - //RATE_2_880MHZ( 0x0280, 0x0000, 2880000, "2.880 MHz" ), - //RATE_3_072MHZ( 0x0258, 0x0000, 3072000, "3.072 MHz" ), - //RATE_3_216MHZ( 0x023D, 0x0000, 3216000, "3.216 MHz" ); + RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz", 16384 ), + RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz", 16384 ), + RATE_0_912MHZ( 0x07E4, 0x0000, 912000, "0.912 MHz", 32768 ), + RATE_0_960MHZ( 0x0778, 0x0000, 960000, "0.960 MHz", 32768 ), + RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz", 65536 ), + RATE_1_440MHZ( 0x04FC, 0x0000, 1440000, "1.440 MHz", 65536 ), + RATE_1_680MHZ( 0x0448, 0x0000, 1680000, "1.680 MHz", 65536 ), + RATE_1_824MHZ( 0x03F0, 0x0000, 1824000, "1.824 MHz", 65536 ), + RATE_2_016MHZ( 0x038C, 0x0000, 2016000, "2.016 MHz", 131072 ), + RATE_2_208MHZ( 0x0340, 0x0000, 2208000, "2.208 MHz", 131072 ), + RATE_2_400MHZ( 0x02FC, 0x0000, 2400000, "2.400 MHz", 131072 ), + RATE_2_640MHZ( 0x02B4, 0x8000, 2640000, "2.640 MHz", 262144 ), + RATE_2_880MHZ( 0x027C, 0x0000, 2880000, "2.880 MHz", 262144 ); private int mRatioHigh; private int mRatioLow; private int mRate; private String mLabel; + private int mBufferSize; - private SampleRate( int ratioHigh, int ratioLow, int rate, String label ) + private SampleRate( int ratioHigh, + int ratioLow, + int rate, + String label, + int bufferSize ) { mRatioHigh = ratioHigh; mRatioLow = ratioLow; mRate = rate; mLabel = label; + mBufferSize = bufferSize; } public int getRatioHighBits() @@ -1447,6 +1467,11 @@ public abstract class RTL2832TunerController extends TunerController return mLabel; } + public int getBufferSize() + { + return mBufferSize; + } + /** * Returns the sample rate that is equal to the argument or the next * higher sample rate @@ -1545,7 +1570,7 @@ public abstract class RTL2832TunerController extends TunerController for( int x = 0; x < sUSB_IRP_POOL_SIZE; x++ ) { UsbIrp irp = mUSBPipe.createUsbIrp(); - irp.setData( new byte[ sUSB_IRP_DATA_SIZE ] ); + irp.setData( new byte[ mBufferSize ] ); irps.add( irp ); } @@ -1566,12 +1591,15 @@ public abstract class RTL2832TunerController extends TunerController if( mUSBPipe.isOpen() ) { mSampleDispatcherTask = mExecutor - .scheduleAtFixedRate( new BufferDispatcher(), - 0, 20, TimeUnit.MILLISECONDS ); + .scheduleAtFixedRate( new BufferDispatcher(), + 0, 20, TimeUnit.MILLISECONDS ); + + mSampleRateMonitor = + new SampleRateMonitor( mSampleRate.getRate() ); mSampleRateCounterTask = mExecutor - .scheduleAtFixedRate( new SampleRateMonitor(), - 60, 60, TimeUnit.SECONDS ); + .scheduleAtFixedRate( mSampleRateMonitor, + 10, 10, TimeUnit.SECONDS ); mUSBPipe.asyncSubmit( irps ); } @@ -1645,7 +1673,7 @@ public abstract class RTL2832TunerController extends TunerController { try { - mUSBPipe.asyncSubmit( new byte[ sUSB_IRP_DATA_SIZE ] ); + mUSBPipe.asyncSubmit( new byte[ mBufferSize ] ); } catch ( UsbNotActiveException | UsbNotOpenException | IllegalArgumentException | UsbDisconnectedException @@ -1707,37 +1735,103 @@ public abstract class RTL2832TunerController extends TunerController */ public class SampleRateMonitor implements Runnable { + private static final int BUFFER_SIZE = 5; + private int mTargetSampleRate; + private int mSampleRateMinimum; + private int mSampleRateMaximum; + private int mNewTargetSampleRate; + private FloatAveragingBuffer mRateErrorBuffer = + new FloatAveragingBuffer( BUFFER_SIZE ); + private AtomicBoolean mRateChanged = new AtomicBoolean(); + + public SampleRateMonitor( int sampleRate ) + { + setTargetRate( sampleRate ); + } + + public void setSampleRate( int sampleRate ) + { + mNewTargetSampleRate = sampleRate; + mRateChanged.set( true ); + } + + private void setTargetRate( int rate ) + { + mTargetSampleRate = rate; + mSampleRateMinimum = (int)( (float)mTargetSampleRate * 0.95f ); + mSampleRateMaximum = (int)( (float)mTargetSampleRate * 1.05f ); + + for( int x = 0; x < BUFFER_SIZE; x++ ) + { + mRateErrorBuffer.get( 0 ); + } + } + @Override public void run() { - int count = mSampleCounter.getAndSet( 0 ); - - double rate = (double)count / 120.0d; - - mSampleRateAverageSum += rate; - mSampleRateAverageCount++; - - double average = mSampleRateAverageSum / (double)mSampleRateAverageCount; - - StringBuilder sb = new StringBuilder(); - sb.append( TimeStamp.getTimeStamp( " " ) ); - sb.append( " RTL-2832 [" ); - if( mDescriptor != null ) + if( mRateChanged.compareAndSet( true, false ) ) { - sb.append( mDescriptor.getSerial() ); + setTargetRate( mNewTargetSampleRate ); + + /* Reset the sample counter */ + mSampleCounter.set( 0 ); + + mLog.info( "monitor reset for new sample rate [" + mTargetSampleRate + "]" ); + System.out.println( "monitor reset for new sample rate [" + mTargetSampleRate + "]" ); } else { - sb.append( "DESCRIPTOR IS NULL" ); + int count = mSampleCounter.getAndSet( 0 ); + + float current = (float)count / 20.0f; + + /** + * Only accept values +/- 5% of target rate + */ + float average; + + if( mSampleRateMinimum < current && current < mSampleRateMaximum ) + { + average = mRateErrorBuffer.get( (float)mTargetSampleRate - current ); + + /* broadcast an actual sample rate update */ + if( mFrequencyController != null ) + { + mFrequencyController.broadcastFrequencyChangeEvent( + new FrequencyChangeEvent( + Attribute.SAMPLE_RATE_ERROR, (int)average ) ); + } + } + else + { + average = mTargetSampleRate; + } + + StringBuilder sb = new StringBuilder(); + sb.append( TimeStamp.getTimeStamp( " " ) ); + sb.append( " RTL-2832 [" ); + if( mDescriptor != null ) + { + sb.append( mDescriptor.getSerial() ); + } + else + { + sb.append( "DESCRIPTOR IS NULL" ); + } + sb.append( "] sample rate current [" ); + sb.append( mDecimalFormatter.format( current ) ); + sb.append( " Hz " ); + sb.append( mPercentFormatter.format( 100.0f * ( current / (float)mTargetSampleRate ) ) ); + sb.append( "% ] average error [" ); + sb.append( average ); + sb.append( " Hz ] target " ); + sb.append( mTargetSampleRate ); + + System.out.println( sb.toString() ); + + mLog.info( sb.toString() ); } - sb.append( "] Sample Rate - current: " ); - sb.append( mDecimalFormatter.format( rate ) ); - sb.append( "\taverage: " ); - sb.append( mDecimalFormatter.format( average ) ); - sb.append( " count:" ); - sb.append( mSampleRateAverageCount ); - - mLog.info( sb.toString() ); } } diff --git a/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java b/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java index aaae46be..ed042e5f 100644 --- a/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java +++ b/src/source/tuner/rtl/e4k/E4KTunerEditorPanel.java @@ -31,7 +31,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import source.SourceException; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; +import source.tuner.FrequencyChangeEvent.Attribute; import source.tuner.rtl.RTL2832InfoPanel; import com.jidesoft.swing.JideTabbedPane; @@ -94,23 +96,28 @@ public class E4KTunerEditorPanel extends JPanel implements FrequencyChangeListen * apply end-user requested frequency changes against the tuner */ @Override - public void frequencyChanged( final long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - EventQueue.invokeLater( new Runnable() + if( event.getAttribute() == Attribute.FREQUENCY ) { - @Override - public void run() - { - try - { - mController.setFrequency( frequency ); - } - catch ( SourceException e ) - { - mLog.error( "E4KTunerController - error setting frequency [" + - frequency + "]", e ); - } - } - } ); + final int frequency = (int)event.getValue(); + + EventQueue.invokeLater( new Runnable() + { + @Override + public void run() + { + try + { + mController.setFrequency( frequency ); + } + catch ( SourceException e ) + { + mLog.error( "E4KTunerController - error setting frequency [" + + frequency + "]", e ); + } + } + } ); + } } } diff --git a/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java b/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java index 42567094..0fe7ce29 100644 --- a/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java +++ b/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java @@ -77,6 +77,7 @@ public class R820TTunerConfigurationPanel extends JPanel private JTextField mName; private JSpinner mFrequencyCorrection; + private JSpinner mSampleRateCorrection; private JComboBox mComboMasterGain; private JComboBox mComboMixerGain; private JComboBox mComboLNAGain; @@ -268,6 +269,65 @@ public class R820TTunerConfigurationPanel extends JPanel add( new JLabel( "Sample Rate:" ) ); add( mComboSampleRate, "growx,push" ); + /** + * Sample Rate Correction + */ + SpinnerModel sampleRateCorrectionModel = + new SpinnerNumberModel( 0, //initial value + -32768, //min + 32767, //max + 1 ); //step + + mSampleRateCorrection = new JSpinner( sampleRateCorrectionModel ); + + JSpinner.NumberEditor sampleRateCorrectionEditor = + (JSpinner.NumberEditor)mSampleRateCorrection.getEditor(); + + DecimalFormat sampleRateCorrectionFormat = + sampleRateCorrectionEditor.getFormat(); + + sampleRateCorrectionFormat.setMinimumFractionDigits( 0 ); + + sampleRateCorrectionEditor.getTextField() + .setHorizontalAlignment( SwingConstants.CENTER ); + + mSampleRateCorrection.addChangeListener( new ChangeListener() + { + @Override + public void stateChanged( ChangeEvent e ) + { + final int value = ((SpinnerNumberModel)mSampleRateCorrection + .getModel()).getNumber().intValue(); + + EventQueue.invokeLater( new Runnable() + { + @Override + public void run() + { + try + { + mController.setSampleRateFrequencyCorrection( value ); + } + catch ( SourceException | UsbException e1 ) + { + JOptionPane.showMessageDialog( + R820TTunerConfigurationPanel.this, + "E4K Tuner Controller - couldn't apply " + + "sample rate correction value: " + value + + e1.getLocalizedMessage() ); + + mLog.error( "E4K Tuner Controller - couldn't apply " + + "sample rate correction value: " + value + + e1.getLocalizedMessage() ); + } + } + } ); + } + } ); + + add( mSampleRateCorrection ); + add( new JLabel( "Sample Rate Correction (ppm)" ), "grow,push" ); + /** * Gain Controls */ diff --git a/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java b/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java index 5b6425e2..b4cc9bc7 100644 --- a/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java +++ b/src/source/tuner/rtl/r820t/R820TTunerEditorPanel.java @@ -31,7 +31,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import source.SourceException; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; +import source.tuner.FrequencyChangeEvent.Attribute; import source.tuner.rtl.RTL2832InfoPanel; import com.jidesoft.swing.JideTabbedPane; @@ -93,23 +95,28 @@ public class R820TTunerEditorPanel extends JPanel implements FrequencyChangeList * apply end-user requested frequency changes against the tuner */ @Override - public void frequencyChanged( final long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - EventQueue.invokeLater( new Runnable() + if( event.getAttribute() == Attribute.FREQUENCY ) { - @Override - public void run() - { - try - { - mController.setFrequency( frequency ); - } - catch ( SourceException e ) - { - mLog.error( "R820T Tuner Controller - error setting frequency [" + - frequency + "]", e ); - } - } - } ); + final int frequency = (int)event.getValue(); + + EventQueue.invokeLater( new Runnable() + { + @Override + public void run() + { + try + { + mController.setFrequency( frequency ); + } + catch ( SourceException e ) + { + mLog.error( "R820T Tuner Controller - error setting frequency [" + + frequency + "]", e ); + } + } + } ); + } } } diff --git a/src/spectrum/ChannelSpectrumPanel.java b/src/spectrum/ChannelSpectrumPanel.java index 1ef4a716..90229687 100644 --- a/src/spectrum/ChannelSpectrumPanel.java +++ b/src/spectrum/ChannelSpectrumPanel.java @@ -23,6 +23,8 @@ import settings.Setting; import settings.SettingChangeListener; import settings.SettingsManager; import source.Source.SampleType; +import source.tuner.FrequencyChangeEvent; +import source.tuner.FrequencyChangeEvent.Attribute; import spectrum.converter.DFTResultsConverter; import spectrum.converter.RealDecibelConverter; import spectrum.menu.AmplificationItem; @@ -86,7 +88,8 @@ public class ChannelSpectrumPanel extends JPanel mDecimatingSampleAssembler = new DecimatingSampleAssembler( mDFTProcessor ); /* Set the DFTProcessor to the decimated 24kHz sample rate */ - mDFTProcessor.frequencyChanged( 0, 24000 ); + mDFTProcessor.frequencyChanged( + new FrequencyChangeEvent( Attribute.SAMPLE_RATE, 24000 ) ); initGui(); } diff --git a/src/spectrum/DFTProcessor.java b/src/spectrum/DFTProcessor.java index bc68d882..4688ec28 100644 --- a/src/spectrum/DFTProcessor.java +++ b/src/spectrum/DFTProcessor.java @@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory; import sample.Listener; import source.Source; import source.Source.SampleType; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; import spectrum.converter.DFTResultsConverter; import dsp.filter.Window; @@ -443,11 +444,19 @@ public class DFTProcessor implements Listener, } @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - mSampleRate = bandwidth; - - calculateConsumptionRate(); + switch( event.getAttribute() ) + { + case SAMPLE_RATE_ERROR: + break; + case SAMPLE_RATE: + mSampleRate = (int)event.getValue(); + calculateConsumptionRate(); + break; + default: + break; + } } /** diff --git a/src/spectrum/OverlayPanel.java b/src/spectrum/OverlayPanel.java index 731c8507..9fb26388 100644 --- a/src/spectrum/OverlayPanel.java +++ b/src/spectrum/OverlayPanel.java @@ -36,6 +36,7 @@ import settings.ColorSetting; import settings.ColorSetting.ColorSettingName; import settings.Setting; import settings.SettingChangeListener; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; import source.tuner.TunerChannel; import controller.ResourceManager; @@ -523,10 +524,22 @@ public class OverlayPanel extends JPanel * Frequency change event handler */ @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - mBandwidth = bandwidth; - mFrequency = frequency; + switch( event.getAttribute() ) + { + case SAMPLE_RATE_ERROR: +// System.out.println( "OVerlay panel got a sample rate error update" ); + break; + case SAMPLE_RATE: + mBandwidth = (int)event.getValue(); + break; + case FREQUENCY: + mFrequency = (int)event.getValue(); + break; + default: + break; + } /** * Reset the visible channel configs list diff --git a/src/spectrum/SpectralDisplayPanel.java b/src/spectrum/SpectralDisplayPanel.java index 93e4c8d7..373253a5 100644 --- a/src/spectrum/SpectralDisplayPanel.java +++ b/src/spectrum/SpectralDisplayPanel.java @@ -55,9 +55,11 @@ import settings.SettingChangeListener; import settings.SettingsManager; import source.Source.SampleType; import source.SourceException; +import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeListener; import source.tuner.Tuner; import source.tuner.TunerSelectionListener; +import source.tuner.FrequencyChangeEvent.Attribute; import spectrum.converter.ComplexDecibelConverter; import spectrum.converter.DFTResultsConverter; import spectrum.menu.AmplificationItem; @@ -340,10 +342,10 @@ public class SpectralDisplayPanel extends JPanel * Receives frequency change events -- primarily from tuner components. */ @Override - public void frequencyChanged( long frequency, int bandwidth ) + public void frequencyChanged( FrequencyChangeEvent event ) { - mOverlayPanel.frequencyChanged( frequency, bandwidth ); - mDFTProcessor.frequencyChanged( frequency, bandwidth ); + mOverlayPanel.frequencyChanged( event ); + mDFTProcessor.frequencyChanged( event ); } /** @@ -381,11 +383,15 @@ public class SpectralDisplayPanel extends JPanel //Register the dft processor to receive samples from the tuner mTuner.addListener( (Listener)mDFTProcessor ); - //Fire a frequency change event so that everyone can init + //Fire frequency and sample rate change events so that everyone + //can init try { - frequencyChanged( mTuner.getFrequency(), - mTuner.getSampleRate() ); + frequencyChanged( new FrequencyChangeEvent( + Attribute.FREQUENCY, mTuner.getFrequency() ) ); + + frequencyChanged( new FrequencyChangeEvent( + Attribute.SAMPLE_RATE, mTuner.getSampleRate() ) ); } catch ( SourceException e ) { diff --git a/src/util/Oscillator.java b/src/util/Oscillator.java index 3ed02d84..302beda4 100644 --- a/src/util/Oscillator.java +++ b/src/util/Oscillator.java @@ -42,6 +42,11 @@ public class Oscillator update(); } + public ComplexSample getCurrentAngle() + { + return mCurrentAngle; + } + private void update() { float anglePerSample = @@ -64,6 +69,7 @@ public class Oscillator */ public void setSampleRate( int sampleRate ) { + System.out.println( "Oscillator - setting sampleRate to:" + sampleRate ); mSampleRate = (double)sampleRate; update(); }