mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 09:07:27 -05:00
wip-channelizer
This commit is contained in:
@@ -36,18 +36,18 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.real.IOverflowListener;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.SourceEvent;
|
||||
import source.ISourceEventListener;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static source.tuner.frequency.FrequencyChangeEvent.Event.NOTIFICATION_FREQUENCY_CHANGE;
|
||||
import static source.SourceEvent.Event.NOTIFICATION_FREQUENCY_CHANGE;
|
||||
|
||||
public class ChannelState extends Module implements ICallEventProvider, IDecoderStateEventListener,
|
||||
IDecoderStateEventProvider, IFrequencyChangeListener, ISquelchStateProvider, IAttributeChangeRequestListener,
|
||||
IDecoderStateEventProvider, ISourceEventListener, ISquelchStateProvider, IAttributeChangeRequestListener,
|
||||
IOverflowListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelState.class);
|
||||
@@ -66,7 +66,7 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
private ChannelType mChannelType;
|
||||
private TrafficChannelManager mTrafficChannelEndListener;
|
||||
private CallEvent mTrafficChannelCallEvent;
|
||||
private FrequencyChangeListener mFrequencyChangeListener;
|
||||
private SourceChangeListener mSourceChangeListener;
|
||||
|
||||
private boolean mSquelchLocked = false;
|
||||
private boolean mSelected = false;
|
||||
@@ -196,14 +196,14 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
if(mFrequencyChangeListener == null)
|
||||
if(mSourceChangeListener == null)
|
||||
{
|
||||
mFrequencyChangeListener = new FrequencyChangeListener();
|
||||
mSourceChangeListener = new SourceChangeListener();
|
||||
}
|
||||
|
||||
return mFrequencyChangeListener;
|
||||
return mSourceChangeListener;
|
||||
}
|
||||
|
||||
private boolean isStandardChannel()
|
||||
@@ -552,14 +552,14 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
|
||||
/**
|
||||
* Listener to receive frequency change events and rebroadcast them to the decoder states
|
||||
*/
|
||||
public class FrequencyChangeListener implements Listener<FrequencyChangeEvent>
|
||||
public class SourceChangeListener implements Listener<SourceEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(FrequencyChangeEvent frequencyChangeEvent)
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
if(frequencyChangeEvent.getEvent() == NOTIFICATION_FREQUENCY_CHANGE)
|
||||
if(sourceEvent.getEvent() == NOTIFICATION_FREQUENCY_CHANGE)
|
||||
{
|
||||
long frequency = frequencyChangeEvent.getValue().longValue();
|
||||
long frequency = sourceEvent.getValue().longValue();
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, getState(), frequency));
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
******************************************************************************/
|
||||
package channel.traffic;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.id.priority.Priority;
|
||||
import channel.state.DecoderStateEvent;
|
||||
import channel.state.IDecoderStateEventListener;
|
||||
import controller.channel.Channel;
|
||||
@@ -27,7 +25,6 @@ import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelEvent;
|
||||
import controller.channel.ChannelEvent.Event;
|
||||
import controller.channel.ChannelModel;
|
||||
import controller.channel.ChannelProcessingManager;
|
||||
import controller.channel.TrafficChannelEvent;
|
||||
import module.Module;
|
||||
import module.decode.config.DecodeConfiguration;
|
||||
@@ -40,7 +37,6 @@ import record.config.RecordConfiguration;
|
||||
import sample.Listener;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -193,8 +189,8 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
|
||||
if(frequency > 0)
|
||||
{
|
||||
Channel channel = getChannel(callEvent.getChannel(), new TunerChannel(Type.TRAFFIC,
|
||||
frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth()));
|
||||
Channel channel = getChannel(callEvent.getChannel(), new TunerChannel(frequency,
|
||||
mDecodeConfiguration.getDecoderType().getChannelBandwidth()));
|
||||
|
||||
if(channel != null)
|
||||
{
|
||||
|
||||
@@ -34,9 +34,8 @@ import source.config.SourceConfigRecording;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.config.SourceConfiguration;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.SourceEvent;
|
||||
import source.SourceEvent.Event;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
@@ -46,7 +45,7 @@ import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
@XmlSeeAlso({Configuration.class})
|
||||
@XmlRootElement(name = "channel")
|
||||
public class Channel extends Configuration implements Listener<FrequencyChangeEvent>
|
||||
public class Channel extends Configuration implements Listener<SourceEvent>
|
||||
{
|
||||
// Standard channels are persisted and traffic channels are temporary
|
||||
public enum ChannelType
|
||||
@@ -418,15 +417,14 @@ public class Channel extends Configuration implements Listener<FrequencyChangeEv
|
||||
{
|
||||
SourceConfigTuner config = (SourceConfigTuner)mSourceConfiguration;
|
||||
|
||||
mTunerChannel = new TunerChannel(Type.LOCKED, config.getFrequency(),
|
||||
mTunerChannel = new TunerChannel(config.getFrequency(),
|
||||
mDecodeConfiguration.getDecoderType().getChannelBandwidth());
|
||||
}
|
||||
else if(mSourceConfiguration.getSourceType() == SourceType.RECORDING)
|
||||
{
|
||||
SourceConfigRecording config =
|
||||
(SourceConfigRecording)mSourceConfiguration;
|
||||
SourceConfigRecording config = (SourceConfigRecording)mSourceConfiguration;
|
||||
|
||||
mTunerChannel = new TunerChannel(Type.LOCKED, config.getFrequency(),
|
||||
mTunerChannel = new TunerChannel(config.getFrequency(),
|
||||
mDecodeConfiguration.getDecoderType().getChannelBandwidth());
|
||||
}
|
||||
}
|
||||
@@ -452,7 +450,7 @@ public class Channel extends Configuration implements Listener<FrequencyChangeEv
|
||||
* be used to visually show in the spectral display.
|
||||
*/
|
||||
@Override
|
||||
public void receive(FrequencyChangeEvent event)
|
||||
public void receive(SourceEvent event)
|
||||
{
|
||||
if(event.getEvent() == Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE)
|
||||
{
|
||||
|
||||
@@ -567,7 +567,7 @@ public class FilterFactory
|
||||
* For 40db attenuation, calculate the number of symbols based on the following formula:
|
||||
* Symbols = -44 * alpha + 33
|
||||
*
|
||||
* Polyphase Channelizer notes:
|
||||
* Polyphase TunerChannelizer notes:
|
||||
* -Set samples Per Symbol at 2 (or more) * number of channels
|
||||
* -Set symbolCount to sufficient size to produce required attenuation
|
||||
* -Set symbol rate in hertz
|
||||
@@ -725,7 +725,7 @@ public class FilterFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a windowed-sync (Nyquist) M/2 prototype FIR filter for use with a Polyphase Channelizer/Synthesizer.
|
||||
* Creates a windowed-sync (Nyquist) M/2 prototype FIR filter for use with a Polyphase TunerChannelizer/Synthesizer.
|
||||
* The filter is designed for x2 oversampling of each channel and the filter cutoff frequency is incrementally
|
||||
* adjusted to achieve a -6.02 dB attenuation at the channel band edge to enable perfect reconstruction of adjacent
|
||||
* channels.
|
||||
@@ -833,7 +833,7 @@ public class FilterFactory
|
||||
|
||||
if(logResults)
|
||||
{
|
||||
mLog.debug("Polyphase Channelizer Filter Design Summary");
|
||||
mLog.debug("Polyphase TunerChannelizer Filter Design Summary");
|
||||
mLog.debug("-------------------------------------------");
|
||||
mLog.debug("Channels: " + channels);
|
||||
mLog.debug("Taps Per Channel: " + tapsPerChannel);
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 dsp.filter.channelizer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ISourceEventListener;
|
||||
import source.SourceEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public abstract class AbstractComplexPolyphaseChannelizer implements Listener<ComplexBuffer>, ISourceEventListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(AbstractComplexPolyphaseChannelizer.class);
|
||||
|
||||
private Broadcaster<SourceEvent> mSourceChangeBroadcaster = new Broadcaster();
|
||||
private List<PolyphaseChannelSource> mChannels = new CopyOnWriteArrayList<>();
|
||||
private int mChannelCount;
|
||||
private int mChannelSampleRate;
|
||||
|
||||
/**
|
||||
* Complex sample polyphase channelizer
|
||||
*
|
||||
* @param channelCount
|
||||
*/
|
||||
public AbstractComplexPolyphaseChannelizer(int channelCount, int channelSampleRate)
|
||||
{
|
||||
mChannelCount = channelCount;
|
||||
mChannelSampleRate = channelSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of channels being processed by this channelizer.
|
||||
*/
|
||||
public int getChannelCount()
|
||||
{
|
||||
return mChannelCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output sample rate for each channel
|
||||
* @return sample rate in hertz
|
||||
*/
|
||||
public int getChannelSampleRate()
|
||||
{
|
||||
return mChannelSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the complex sample pair
|
||||
*
|
||||
* @param inphase sample
|
||||
* @param quadrature sample
|
||||
*/
|
||||
protected abstract void filter(float inphase, float quadrature);
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer complexBuffer)
|
||||
{
|
||||
float[] samples = complexBuffer.getSamples();
|
||||
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
filter(samples[x], samples[x + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the processed channel samples to any registered polyphase channel outputs.
|
||||
*
|
||||
* @param channels containing an array of I/Q samples per channel
|
||||
*/
|
||||
protected void dispatch(float[] channels)
|
||||
{
|
||||
for(PolyphaseChannelSource channel : mChannels)
|
||||
{
|
||||
channel.processChannels(channels);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the polyphase channel source to receive processed output channel samples
|
||||
*
|
||||
* @param polyphaseChannelSource
|
||||
*/
|
||||
public void addChannel(PolyphaseChannelSource polyphaseChannelSource)
|
||||
{
|
||||
mChannels.add(polyphaseChannelSource);
|
||||
mSourceChangeBroadcaster.addListener(polyphaseChannelSource.getSourceEventListener());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the polyphase channel source from receiving output channel samples.
|
||||
*
|
||||
* @param polyphaseChannelSource
|
||||
*/
|
||||
public void removeChannel(PolyphaseChannelSource polyphaseChannelSource)
|
||||
{
|
||||
mChannels.remove(polyphaseChannelSource);
|
||||
mSourceChangeBroadcaster.removeListener(polyphaseChannelSource.getSourceEventListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return mSourceChangeBroadcaster;
|
||||
}
|
||||
}
|
||||
135
src/dsp/filter/channelizer/Channelizer.java
Normal file
135
src/dsp/filter/channelizer/Channelizer.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 dsp.filter.channelizer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.Source;
|
||||
import source.SourceEvent;
|
||||
import source.tuner.Tuner;
|
||||
import source.tuner.TunerChannel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class Channelizer implements ISourceEventProcessor, Listener<SourceEvent>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(Channelizer.class);
|
||||
|
||||
private Tuner mTuner;
|
||||
private List<PolyphaseChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
* Provides access to Digital Drop Channel (DDC) sources from the tuner. Incorporates a polyphase channelizer
|
||||
* with downstream channel and upstream tuner management.
|
||||
*
|
||||
* @param tuner providing broadband sample buffers
|
||||
*/
|
||||
public Channelizer(Tuner tuner)
|
||||
{
|
||||
mTuner = tuner;
|
||||
mTuner.addSourceEventListener(this);
|
||||
}
|
||||
|
||||
public Source getChannel(TunerChannel tunerChannel)
|
||||
{
|
||||
//TODO: return a polyphase channel here
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts/adds the channel source to receive channelized sample buffers, registering with the tuner to receive
|
||||
* sample buffers when this is the first channel.
|
||||
*
|
||||
* @param channelSource to start
|
||||
*/
|
||||
private void startChannelSource(PolyphaseChannelSource channelSource)
|
||||
{
|
||||
if(mChannelSources.isEmpty())
|
||||
{
|
||||
//TODO: start the tuner
|
||||
}
|
||||
|
||||
mChannelSources.add(channelSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops/removes the channel source from receiving channelized sample buffers and deregisters from the tuner
|
||||
* if this is the last channel being sourced.
|
||||
*
|
||||
* @param channelSource to stop
|
||||
*/
|
||||
private void stopChannelSource(PolyphaseChannelSource channelSource)
|
||||
{
|
||||
mChannelSources.remove(channelSource);
|
||||
|
||||
if(mChannelSources.isEmpty())
|
||||
{
|
||||
//TODO: stop the tuner
|
||||
}
|
||||
|
||||
if(mTuner != null)
|
||||
{
|
||||
//TODO: change the tuner to accept a remove(TunerChannel) method
|
||||
// mTuner.remove(channel.getTunerChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(SourceEvent sourceEvent)
|
||||
{
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
case REQUEST_START_SAMPLE_STREAM:
|
||||
if(sourceEvent.hasSource() && sourceEvent.getSource() instanceof PolyphaseChannelSource)
|
||||
{
|
||||
startChannelSource((PolyphaseChannelSource)sourceEvent.getSource());
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.error("Request to stop sample stream for unrecognized source: " +
|
||||
(sourceEvent.hasSource() ? sourceEvent.getSource().getClass() : "null source"));
|
||||
}
|
||||
//TODO: add the channel and register for samples from the tuner
|
||||
break;
|
||||
case REQUEST_STOP_SAMPLE_STREAM:
|
||||
if(sourceEvent.hasSource() && sourceEvent.getSource() instanceof PolyphaseChannelSource)
|
||||
{
|
||||
stopChannelSource((PolyphaseChannelSource)sourceEvent.getSource());
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.error("Request to stop sample stream for unrecognized source: " +
|
||||
(sourceEvent.hasSource() ? sourceEvent.getSource().getClass() : "null source"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ package dsp.filter.channelizer;
|
||||
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window;
|
||||
import dsp.filter.correction.IQCorrectionFilter;
|
||||
import dsp.filter.design.FilterDesignException;
|
||||
import dsp.mixer.LowPhaseNoiseOscillator;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
@@ -31,7 +30,7 @@ import sample.SampleType;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import settings.SettingsManager;
|
||||
import source.tuner.configuration.TunerConfigurationModel;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.SourceEvent;
|
||||
import spectrum.DFTProcessor;
|
||||
import spectrum.DFTSize;
|
||||
import spectrum.SpectrumPanel;
|
||||
@@ -86,7 +85,7 @@ public class ChannelizerViewer extends JFrame
|
||||
|
||||
private void init()
|
||||
{
|
||||
setTitle("Channelizer Viewer");
|
||||
setTitle("TunerChannelizer Viewer");
|
||||
setSize(1000, 800);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill]"));
|
||||
@@ -212,7 +211,7 @@ public class ChannelizerViewer extends JFrame
|
||||
|
||||
public class ChannelArrayPanel extends JPanel implements Listener<ComplexBuffer>
|
||||
{
|
||||
private ComplexPolyphaseChannelizerM2 mPolyphaseChannelizer;
|
||||
private ComplexPolyphaseChannelizer mPolyphaseChannelizer;
|
||||
private ChannelDistributor mChannelDistributor;
|
||||
|
||||
public ChannelArrayPanel(float[] taps)
|
||||
@@ -223,7 +222,7 @@ public class ChannelizerViewer extends JFrame
|
||||
bufferSize++;
|
||||
}
|
||||
|
||||
mPolyphaseChannelizer = new ComplexPolyphaseChannelizerM2(taps, mChannelCount);
|
||||
mPolyphaseChannelizer = new ComplexPolyphaseChannelizer(taps, mChannelCount, CHANNEL_BANDWIDTH);
|
||||
mChannelDistributor = new ChannelDistributor(bufferSize, mChannelCount);
|
||||
mPolyphaseChannelizer.setChannelDistributor(mChannelDistributor);
|
||||
|
||||
@@ -272,8 +271,7 @@ public class ChannelizerViewer extends JFrame
|
||||
add(mSpectrumPanel);
|
||||
|
||||
mDFTProcessor.addConverter(mComplexDecibelConverter);
|
||||
mDFTProcessor.frequencyChanged(new FrequencyChangeEvent(
|
||||
FrequencyChangeEvent.Event.NOTIFICATION_SAMPLE_RATE_CHANGE, sampleRate));
|
||||
mDFTProcessor.process(SourceEvent.sampleRateChange(sampleRate));
|
||||
mComplexDecibelConverter.addListener(mSpectrumPanel);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,44 +25,40 @@ import dsp.mixer.Oscillator;
|
||||
import org.jtransforms.fft.FloatFFT_1D;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
public class ComplexPolyphaseChannelizer extends AbstractComplexPolyphaseChannelizer
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexPolyphaseChannelizer.class);
|
||||
|
||||
private RealFIRFilter[] mInphaseFilters;
|
||||
private RealFIRFilter[] mQuadratureFilters;
|
||||
private int mFilterPointer = 0;
|
||||
private int mChannelCount;
|
||||
private float[] mFilteredSamples;
|
||||
private FloatFFT_1D mFFT;
|
||||
private ChannelDistributor mChannelDistributor;
|
||||
|
||||
/**
|
||||
* Maximally Decimated Polyphase Filter Bank (MDPFB) channelizer that divides the input frequency band into
|
||||
* equal bandwidth channels.
|
||||
*
|
||||
* @param taps of a low-pass filter designed for the inbound sample rate with a cutoff frequency
|
||||
* @param coefficients of a prototype low-pass filter designed for the inbound sample rate with a cutoff frequency
|
||||
* equal to the channel bandwidth (sample rate / filters). If you need to synthesize (combine two or more
|
||||
* filte outputs) a new bandwidth signal from the outputs of this filter, then the filter should be designed
|
||||
* filter outputs) a new bandwidth signal from the outputs of this filter, then the filter should be designed
|
||||
* as a nyquist filter with -6 dB attenuation at the channel bandwidth cutoff frequency
|
||||
*
|
||||
* @param channels - number of channels to output.
|
||||
* @param channelCount - number of channels to output.
|
||||
* @param channelSampleRate - channel sample rate (after decimation)
|
||||
*/
|
||||
public ComplexPolyphaseChannelizer(float[] taps, int channels)
|
||||
public ComplexPolyphaseChannelizer(float[] coefficients, int channelCount, int channelSampleRate)
|
||||
{
|
||||
mChannelCount = channels;
|
||||
super(channelCount, channelSampleRate);
|
||||
|
||||
initFilters(taps);
|
||||
initFilters(coefficients);
|
||||
}
|
||||
|
||||
public void filter(float inphase, float quadrature)
|
||||
@Override
|
||||
protected void filter(float inphase, float quadrature)
|
||||
{
|
||||
int index = (mChannelCount - mFilterPointer - 1) * 2;
|
||||
int index = (getChannelCount() - mFilterPointer - 1) * 2;
|
||||
|
||||
mFilteredSamples[index] = mInphaseFilters[mFilterPointer].filter(inphase);
|
||||
mFilteredSamples[index + 1] = mQuadratureFilters[mFilterPointer].filter(quadrature);
|
||||
@@ -70,7 +66,7 @@ public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
if(mFilterPointer == 0)
|
||||
{
|
||||
calculate();
|
||||
mFilterPointer = mChannelCount - 1;
|
||||
mFilterPointer = getChannelCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -78,20 +74,9 @@ public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer complexBuffer)
|
||||
{
|
||||
float[] samples = complexBuffer.getSamples();
|
||||
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
filter(samples[x], samples[x + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculate()
|
||||
{
|
||||
float[] samples = new float[mChannelCount * 2];
|
||||
float[] samples = new float[getChannelCount() * 2];
|
||||
System.arraycopy(mFilteredSamples, 0, samples, 0, mFilteredSamples.length);
|
||||
|
||||
//FFT is executed in-place where the output overwrites the input
|
||||
@@ -100,24 +85,6 @@ public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
dispatch(samples);
|
||||
}
|
||||
|
||||
private void dispatch(float[] channels)
|
||||
{
|
||||
if(mChannelDistributor != null)
|
||||
{
|
||||
mChannelDistributor.receive(channels);
|
||||
}
|
||||
}
|
||||
|
||||
public void setChannelDistributor(ChannelDistributor channelDistributor)
|
||||
{
|
||||
mChannelDistributor = channelDistributor;
|
||||
}
|
||||
|
||||
private double magnitude(float real, float imaginary, int fftSize)
|
||||
{
|
||||
return Math.sqrt(Math.pow(real, 2.0) + Math.pow(imaginary, 2.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Distributes the filter taps to each of the polyphase filters
|
||||
*
|
||||
@@ -125,15 +92,15 @@ public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
*/
|
||||
private void initFilters(float[] taps)
|
||||
{
|
||||
int tapCount = (int)Math.ceil((double)taps.length / (double)mChannelCount);
|
||||
int tapCount = (int)Math.ceil((double)taps.length / (double)getChannelCount());
|
||||
|
||||
float[][] coefficients = new float[mChannelCount][tapCount];
|
||||
float[][] coefficients = new float[getChannelCount()][tapCount];
|
||||
|
||||
for(int tap = 0; tap < tapCount; tap++)
|
||||
{
|
||||
for(int filter = 0; filter < mChannelCount; filter++)
|
||||
for(int filter = 0; filter < getChannelCount(); filter++)
|
||||
{
|
||||
int index = tap * mChannelCount + filter;
|
||||
int index = tap * getChannelCount() + filter;
|
||||
|
||||
if(index < taps.length)
|
||||
{
|
||||
@@ -142,18 +109,18 @@ public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
}
|
||||
}
|
||||
|
||||
mInphaseFilters = new RealFIRFilter[mChannelCount];
|
||||
mQuadratureFilters = new RealFIRFilter[mChannelCount];
|
||||
mInphaseFilters = new RealFIRFilter[getChannelCount()];
|
||||
mQuadratureFilters = new RealFIRFilter[getChannelCount()];
|
||||
|
||||
for(int filter = 0; filter < mChannelCount; filter++)
|
||||
for(int filter = 0; filter < getChannelCount(); filter++)
|
||||
{
|
||||
mInphaseFilters[filter] = new RealFIRFilter(coefficients[filter], 1.0f);
|
||||
mQuadratureFilters[filter] = new RealFIRFilter(coefficients[filter], 1.0f);
|
||||
}
|
||||
|
||||
mFilteredSamples = new float[mChannelCount * 2];
|
||||
mFFT = new FloatFFT_1D(mChannelCount);
|
||||
mFilterPointer = mChannelCount -1;
|
||||
mFilteredSamples = new float[getChannelCount() * 2];
|
||||
mFFT = new FloatFFT_1D(getChannelCount());
|
||||
mFilterPointer = getChannelCount() -1;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
@@ -171,14 +138,14 @@ public class ComplexPolyphaseChannelizer implements Listener<ComplexBuffer>
|
||||
int channelCenter = (int)(12500 * 1.5);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\nPolyphase Channelizer\n");
|
||||
sb.append("\nPolyphase TunerChannelizer\n");
|
||||
sb.append("Sample Rate:" + sampleRate + " Channels:" + channels + " Channel Rate:" + channelBandwidth + "\n");
|
||||
sb.append("Tap Count:" + taps.length + "\n");
|
||||
sb.append("Channel:" + channelCenter);
|
||||
|
||||
mLog.debug(sb.toString());
|
||||
|
||||
ComplexPolyphaseChannelizer channelizer = new ComplexPolyphaseChannelizer(taps, 8);
|
||||
ComplexPolyphaseChannelizer channelizer = new ComplexPolyphaseChannelizer(taps, 8, channelBandwidth);
|
||||
|
||||
Oscillator oscillator = new Oscillator(channelCenter, 2 * sampleRate);
|
||||
|
||||
|
||||
@@ -25,21 +25,18 @@ import dsp.mixer.Oscillator;
|
||||
import org.jtransforms.fft.FloatFFT_1D;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChannelizer
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexPolyphaseChannelizerM2.class);
|
||||
|
||||
private ReverseFloatCircularBuffer[] mDataBuffers;
|
||||
private float[][] mFilterCoefficients;
|
||||
private int mFilterPointer = 0;
|
||||
private int mChannelCount;
|
||||
private FloatFFT_1D mFFT;
|
||||
private ChannelDistributor mChannelDistributor;
|
||||
|
||||
private DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0000");
|
||||
|
||||
@@ -51,23 +48,23 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
* equal to the channel bandwidth (sample rate / filters). If you need to synthesize (combine two or more
|
||||
* filte outputs) a new bandwidth signal from the outputs of this filter, then the filter should be designed
|
||||
* as a nyquist filter with -6 dB attenuation at the channel bandwidth cutoff frequency
|
||||
*
|
||||
* @param channels - number of filters/channels to output. Since this filter bank oversamples each filter
|
||||
* output, this number must be even (divisible by the oversample rate).
|
||||
* @param channelSampleRate for each decimated, oversampled channel
|
||||
*/
|
||||
public ComplexPolyphaseChannelizerM2(float[] taps, int channels)
|
||||
public ComplexPolyphaseChannelizerM2(float[] taps, int channels, int channelSampleRate)
|
||||
{
|
||||
super(channels, channelSampleRate);
|
||||
|
||||
if(channels % 2 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Channel count must be a multiple of 2");
|
||||
}
|
||||
|
||||
mChannelCount = channels;
|
||||
|
||||
initFilters(taps);
|
||||
}
|
||||
|
||||
public void filter(float inphase, float quadrature)
|
||||
protected void filter(float inphase, float quadrature)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -77,9 +74,9 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
if(mFilterPointer == 0)
|
||||
{
|
||||
calculate();
|
||||
mFilterPointer = mChannelCount * 2;
|
||||
mFilterPointer = getChannelCount() * 2;
|
||||
}
|
||||
else if(mFilterPointer == mChannelCount)
|
||||
else if(mFilterPointer == getChannelCount())
|
||||
{
|
||||
calculate();
|
||||
}
|
||||
@@ -92,20 +89,9 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer complexBuffer)
|
||||
{
|
||||
float[] samples = complexBuffer.getSamples();
|
||||
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
filter(samples[x], samples[x + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculate()
|
||||
{
|
||||
float[] samples = new float[mChannelCount * 2];
|
||||
float[] samples = new float[getChannelCount() * 2];
|
||||
|
||||
if(mFilterPointer == 0)
|
||||
{
|
||||
@@ -158,6 +144,7 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
|
||||
/**
|
||||
* Filters the samples contained in the buffer against the filter coefficients
|
||||
*
|
||||
* @param coefficients of the sub filter
|
||||
* @param buffer containing data samples
|
||||
* @return
|
||||
@@ -166,32 +153,14 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
{
|
||||
float accumulator = 0.0f;
|
||||
|
||||
for( int x = 0; x < coefficients.length; x++ )
|
||||
for(int x = 0; x < coefficients.length; x++)
|
||||
{
|
||||
accumulator += coefficients[ x ] * buffer.get(x);
|
||||
accumulator += coefficients[x] * buffer.get(x);
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
private void dispatch(float[] channels)
|
||||
{
|
||||
if(mChannelDistributor != null)
|
||||
{
|
||||
mChannelDistributor.receive(channels);
|
||||
}
|
||||
}
|
||||
|
||||
public void setChannelDistributor(ChannelDistributor channelDistributor)
|
||||
{
|
||||
mChannelDistributor = channelDistributor;
|
||||
}
|
||||
|
||||
private double magnitude(float real, float imaginary, int fftSize)
|
||||
{
|
||||
return Math.sqrt(Math.pow(real, 2.0) + Math.pow(imaginary, 2.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Distributes the filter taps to each of the polyphase filters
|
||||
*
|
||||
@@ -199,22 +168,22 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
*/
|
||||
private void initFilters(float[] taps)
|
||||
{
|
||||
int tapCount = (int)Math.ceil((double)taps.length / (double)mChannelCount);
|
||||
int tapCount = (int)Math.ceil((double)taps.length / (double)getChannelCount());
|
||||
|
||||
mDataBuffers = new ReverseFloatCircularBuffer[mChannelCount * 2];
|
||||
mDataBuffers = new ReverseFloatCircularBuffer[getChannelCount() * 2];
|
||||
|
||||
for(int x = 0; x < mChannelCount * 2; x++)
|
||||
for(int x = 0; x < getChannelCount() * 2; x++)
|
||||
{
|
||||
mDataBuffers[x] = new ReverseFloatCircularBuffer(tapCount);
|
||||
}
|
||||
|
||||
mFilterCoefficients = new float[mChannelCount][tapCount];
|
||||
mFilterCoefficients = new float[getChannelCount()][tapCount];
|
||||
|
||||
for(int tap = 0; tap < tapCount; tap++)
|
||||
{
|
||||
for(int filter = 0; filter < mChannelCount; filter++)
|
||||
for(int filter = 0; filter < getChannelCount(); filter++)
|
||||
{
|
||||
int index = tap * mChannelCount + filter;
|
||||
int index = tap * getChannelCount() + filter;
|
||||
|
||||
if(index < taps.length)
|
||||
{
|
||||
@@ -223,8 +192,8 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
}
|
||||
}
|
||||
|
||||
mFFT = new FloatFFT_1D(mChannelCount);
|
||||
mFilterPointer = mChannelCount - 1; //Start at M/2
|
||||
mFFT = new FloatFFT_1D(getChannelCount());
|
||||
mFilterPointer = getChannelCount() - 1; //Start at M/2
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
@@ -237,19 +206,19 @@ public class ComplexPolyphaseChannelizerM2 implements Listener<ComplexBuffer>
|
||||
int channelBandwidth = 12500;
|
||||
int sampleRate = channels * channelBandwidth;
|
||||
|
||||
float[] taps = FilterFactory.getLowPass( 10000000, 12500, 5600, Window.WindowType.BLACKMAN_HARRIS_7 );
|
||||
float[] taps = FilterFactory.getLowPass(10000000, 12500, 5600, Window.WindowType.BLACKMAN_HARRIS_7);
|
||||
|
||||
int channelCenter = (int)(12500 * 1.5);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\nPolyphase Channelizer\n");
|
||||
sb.append("\nPolyphase TunerChannelizer\n");
|
||||
sb.append("Sample Rate:" + sampleRate + " Channels:" + channels + " Channel Rate:" + channelBandwidth + "\n");
|
||||
sb.append("Tap Count:" + taps.length + "\n");
|
||||
sb.append("Channel:" + channelCenter);
|
||||
|
||||
mLog.debug(sb.toString());
|
||||
|
||||
ComplexPolyphaseChannelizerM2 channelizer = new ComplexPolyphaseChannelizerM2(taps, 8);
|
||||
ComplexPolyphaseChannelizerM2 channelizer = new ComplexPolyphaseChannelizerM2(taps, 8, channelBandwidth * 2);
|
||||
|
||||
Oscillator oscillator = new Oscillator(channelCenter, 2 * sampleRate);
|
||||
|
||||
|
||||
201
src/dsp/filter/channelizer/PolyphaseChannelSource.java
Normal file
201
src/dsp/filter/channelizer/PolyphaseChannelSource.java
Normal file
@@ -0,0 +1,201 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 dsp.filter.channelizer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.SourceException;
|
||||
import source.tuner.ComplexChannelSource;
|
||||
import source.tuner.TunerChannel;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class PolyphaseChannelSource extends ComplexChannelSource
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelSource.class);
|
||||
|
||||
private TunerChannel mTunerChannel;
|
||||
private long mTunerCenterFrequency;
|
||||
private int mUpstreamSampleRate;
|
||||
private int mChannelSampleRate;
|
||||
private int mChannelCount;
|
||||
private int mOutputFrequencyCorrection;
|
||||
|
||||
/**
|
||||
* Polyphase channelizer channel implementation. Adapts the channel array output samples from the polyphase
|
||||
* channelizer into a single channel, or a channel synthesized from two adjacent channels that is frequency
|
||||
* translated and decimated to a single channel.
|
||||
*
|
||||
* @param tunerChannel - requested output tuner channel frequency and bandwidth.
|
||||
*/
|
||||
public PolyphaseChannelSource(ISourceEventProcessor upstreamSourceEventProcessor, TunerChannel tunerChannel)
|
||||
{
|
||||
super(upstreamSourceEventProcessor);
|
||||
|
||||
mTunerChannel = tunerChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process source event notifications received from upstream source provider and source event requests
|
||||
* received from downstream consumers.
|
||||
*
|
||||
* @param sourceEvent containing a request or notification
|
||||
* @throws SourceException if there are any errors while processing the source event
|
||||
*/
|
||||
@Override
|
||||
public void process(SourceEvent sourceEvent) throws SourceException
|
||||
{
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
case NOTIFICATION_CHANNEL_SAMPLE_RATE_CHANGE:
|
||||
setChannelSampleRate(sourceEvent.getValue().intValue());
|
||||
break;
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mTunerCenterFrequency = sourceEvent.getValue().longValue();
|
||||
updateInputConfiguration();
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
setUpstreamSampleRate(sourceEvent.getValue().intValue());
|
||||
updateInputConfiguration();
|
||||
break;
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
setFrequencyCorrection(sourceEvent.getValue().intValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the array samples for each of the output channels from the polyphase channelizer.
|
||||
* @param channels
|
||||
*/
|
||||
public void processChannels(float[] channels)
|
||||
{
|
||||
|
||||
//TODO we have to dispatch full buffers on a separate thread so that we don't bog down the channelizer
|
||||
//TODO thread that is delivering the channel samples to us.
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates current processing configuration any time there is a change in tuner center frequency
|
||||
* or tuner sample rate.
|
||||
*/
|
||||
private void updateInputConfiguration()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Downstream sample rate
|
||||
*
|
||||
* @return sample rate in Hertz
|
||||
* @throws SourceException if this method is accessed before the channel count is established
|
||||
*/
|
||||
@Override
|
||||
public int getSampleRate() throws SourceException
|
||||
{
|
||||
if(mChannelSampleRate > 0)
|
||||
{
|
||||
return mChannelSampleRate;
|
||||
}
|
||||
|
||||
throw new SourceException("Channel sample rate has not been set.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the downstream channel sample rate. Since oversampling may occur in the upstream channelizer, we can't
|
||||
* rely on simply dividing the upstream sample rate by the number of channels. Thus, we required the upstream
|
||||
* channelizer to tell us the exact channel sample rate.
|
||||
*
|
||||
* @param channelSampleRate in hertz
|
||||
*/
|
||||
private void setChannelSampleRate(int channelSampleRate)
|
||||
{
|
||||
mChannelSampleRate = channelSampleRate;
|
||||
|
||||
//Translate the upstream channel sample rate event into a downstream sample rate change event
|
||||
broadcast(SourceEvent.sampleRateChange(mChannelSampleRate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input sample rate and broadcasts a source change event to the downstream listener
|
||||
* @param sampleRate from the upstream source
|
||||
*/
|
||||
private void setUpstreamSampleRate(int sampleRate)
|
||||
{
|
||||
mUpstreamSampleRate = sampleRate;
|
||||
|
||||
try
|
||||
{
|
||||
broadcast(SourceEvent.sampleRateChange(getSampleRate()));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Upstream sample rate changed - couldn't broadcast channel sample rate change event " +
|
||||
"to downstream channel", se);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the polyphase channel count.
|
||||
* @param channelCount number of channels being processed by the polyphase channelizer
|
||||
*/
|
||||
private void setChannelCount(int channelCount)
|
||||
{
|
||||
mChannelCount = channelCount;
|
||||
|
||||
try
|
||||
{
|
||||
broadcast(SourceEvent.sampleRateChange(getSampleRate()));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Polyphase channel count changed - couldn't broadcast channel sample rate change event " +
|
||||
"to downstream channel", se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrequency() throws SourceException
|
||||
{
|
||||
return mTunerChannel.getFrequency();
|
||||
}
|
||||
|
||||
private void setFrequencyCorrection(int correction)
|
||||
{
|
||||
//TODO:
|
||||
mLog.debug("Request for frequency correction: " + correction + " -- not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ public class FIRFilterSpecification
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Polyphase Channelizer filter specification builder that allows you to define the filter parameters and
|
||||
* Creates a Polyphase TunerChannelizer filter specification builder that allows you to define the filter parameters and
|
||||
* create a filter specification
|
||||
*/
|
||||
public static ChannelizerBuilder channelizerBuilder()
|
||||
|
||||
@@ -23,7 +23,7 @@ import dsp.filter.fir.FIRFilterSpecification;
|
||||
public class PolyphaseChannelizerDesigner extends FIRFilterSpecification
|
||||
{
|
||||
/**
|
||||
* Constructs a Polyphase Channelizer Remez filter specification.
|
||||
* Constructs a Polyphase TunerChannelizer Remez filter specification.
|
||||
*
|
||||
* Constructor is package private -- use the PolyphaseChannelizerFilterFactory to create a filter
|
||||
*
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.util.List;
|
||||
import sample.Listener;
|
||||
import sample.complex.Complex;
|
||||
import sample.complex.ComplexSampleListener;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.ISourceEventListener;
|
||||
import buffer.FloatAveragingBuffer;
|
||||
import dsp.filter.interpolator.RealInterpolator;
|
||||
import dsp.symbol.Dibit;
|
||||
@@ -73,7 +73,7 @@ public class LSMDemodulator implements Instrumentable, ComplexSampleListener
|
||||
|
||||
private CostasLoop mCostasLoop = new CostasLoop();
|
||||
|
||||
private IFrequencyChangeListener mFrequencyChangeListener;
|
||||
private ISourceEventListener mFrequencyChangeListener;
|
||||
|
||||
private EyeDiagramDataTap mEyeDiagramDataTap;
|
||||
|
||||
@@ -147,12 +147,12 @@ public class LSMDemodulator implements Instrumentable, ComplexSampleListener
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener( IFrequencyChangeListener listener )
|
||||
public void addListener( ISourceEventListener listener )
|
||||
{
|
||||
mFrequencyChangeListener = listener;
|
||||
}
|
||||
|
||||
public void removeListener( IFrequencyChangeListener listener )
|
||||
public void removeListener( ISourceEventListener listener )
|
||||
{
|
||||
mFrequencyChangeListener = null;
|
||||
}
|
||||
@@ -202,8 +202,8 @@ public class LSMDemodulator implements Instrumentable, ComplexSampleListener
|
||||
// if( correctionNeeded && mFrequencyChangeListener != null )
|
||||
// {
|
||||
// mLog.debug( "Issuing Frequency Correction: " + mFrequencyError );
|
||||
// mFrequencyChangeListener.frequencyChanged(
|
||||
// new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
|
||||
// mFrequencyChangeListener.process(
|
||||
// new SourceEvent( Attribute.FREQUENCY_ERROR,
|
||||
// mFrequencyError ) );
|
||||
// }
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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
|
||||
@@ -14,15 +14,21 @@
|
||||
*
|
||||
* 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 gui.control;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.InvalidFrequencyException;
|
||||
import source.SourceEvent;
|
||||
import source.SourceEvent.Event;
|
||||
import source.SourceException;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -35,26 +41,12 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import source.InvalidFrequencyException;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
|
||||
public class JFrequencyControl extends JPanel implements IFrequencyChangeProcessor
|
||||
public class JFrequencyControl extends JPanel implements ISourceEventProcessor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(JFrequencyControl.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(JFrequencyControl.class);
|
||||
|
||||
private List<IFrequencyChangeProcessor> mProcessors = new ArrayList<>();
|
||||
private List<ISourceEventProcessor> mProcessors = new ArrayList<>();
|
||||
|
||||
private Color mHighlightColor = Color.YELLOW;
|
||||
|
||||
@@ -62,7 +54,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
|
||||
private Cursor mBlankCursor;
|
||||
|
||||
private HashMap<Integer, Digit> mDigits = new HashMap<Integer, Digit>();
|
||||
private HashMap<Integer,Digit> mDigits = new HashMap<Integer,Digit>();
|
||||
|
||||
public JFrequencyControl()
|
||||
{
|
||||
@@ -81,7 +73,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
|
||||
Font font = new Font(Font.MONOSPACED, Font.BOLD, 30);
|
||||
|
||||
for (int x = 9; x >= 0; x--)
|
||||
for(int x = 9; x >= 0; x--)
|
||||
{
|
||||
Digit digit = null;
|
||||
|
||||
@@ -89,13 +81,13 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
{
|
||||
digit = new Digit(x);
|
||||
}
|
||||
catch (ParseException e)
|
||||
catch(ParseException e)
|
||||
{
|
||||
mLog.error("JFrequencyControl - parse exception "
|
||||
+ "constructing a digit - " + e);
|
||||
+ "constructing a digit - " + e);
|
||||
}
|
||||
|
||||
if (digit != null)
|
||||
if(digit != null)
|
||||
{
|
||||
mDigits.put(x, digit);
|
||||
|
||||
@@ -103,7 +95,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
|
||||
digit.setFont(font);
|
||||
|
||||
if (x == 6)
|
||||
if(x == 6)
|
||||
{
|
||||
JLabel period = new JLabel(".");
|
||||
|
||||
@@ -124,7 +116,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
Image cursorImage = Toolkit.getDefaultToolkit().createImage(imageByte);
|
||||
|
||||
mBlankCursor = Toolkit.getDefaultToolkit()
|
||||
.createCustomCursor(cursorImage, new Point(0, 0), "cursor");
|
||||
.createCustomCursor(cursorImage, new Point(0, 0), "cursor");
|
||||
|
||||
revalidate();
|
||||
}
|
||||
@@ -134,7 +126,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
{
|
||||
super.setEnabled(enabled);
|
||||
|
||||
for (Digit digit : mDigits.values())
|
||||
for(Digit digit : mDigits.values())
|
||||
{
|
||||
digit.setEnabled(enabled);
|
||||
}
|
||||
@@ -145,9 +137,9 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
* rebroadcast this event, just set the control to indicate the new frequency.
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event)
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
if (event.getEvent() == Event.NOTIFICATION_FREQUENCY_CHANGE)
|
||||
if(event.getEvent() == Event.NOTIFICATION_FREQUENCY_CHANGE)
|
||||
{
|
||||
setFrequency(event.getValue().longValue(), false);
|
||||
}
|
||||
@@ -161,7 +153,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
{
|
||||
mFrequency = frequency;
|
||||
|
||||
for (Digit digit : mDigits.values())
|
||||
for(Digit digit : mDigits.values())
|
||||
{
|
||||
digit.setFrequency(frequency, fireChangeEvent);
|
||||
}
|
||||
@@ -176,7 +168,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
{
|
||||
long frequency = 0;
|
||||
|
||||
for (Digit digit : mDigits.values())
|
||||
for(Digit digit : mDigits.values())
|
||||
{
|
||||
frequency += digit.getFrequency();
|
||||
}
|
||||
@@ -184,27 +176,26 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
private void fireFrequencyChanged() throws SourceException
|
||||
private void fireSourceChanged() throws SourceException
|
||||
{
|
||||
updateFrequency();
|
||||
|
||||
Iterator<IFrequencyChangeProcessor> it = mProcessors.iterator();
|
||||
Iterator<ISourceEventProcessor> it = mProcessors.iterator();
|
||||
|
||||
FrequencyChangeEvent event = new FrequencyChangeEvent(
|
||||
Event.REQUEST_FREQUENCY_CHANGE, mFrequency);
|
||||
SourceEvent event = SourceEvent.frequencyRequest(mFrequency);
|
||||
|
||||
while (it.hasNext())
|
||||
while(it.hasNext())
|
||||
{
|
||||
it.next().frequencyChanged(event);
|
||||
it.next().process(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(IFrequencyChangeProcessor processor)
|
||||
public void addListener(ISourceEventProcessor processor)
|
||||
{
|
||||
mProcessors.add(processor);
|
||||
}
|
||||
|
||||
public void removeListener(IFrequencyChangeProcessor processor)
|
||||
public void removeListener(ISourceEventProcessor processor)
|
||||
{
|
||||
mProcessors.remove(processor);
|
||||
}
|
||||
@@ -236,17 +227,17 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
public void setFrequency(long frequency, boolean fireChangeEvent)
|
||||
{
|
||||
//Strip the digits higher than this one
|
||||
long lower = frequency % (long) (Math.pow(10, mPower + 1));
|
||||
long lower = frequency % (long)(Math.pow(10, mPower + 1));
|
||||
|
||||
//Set the value to int value of dividing by 10 to this power
|
||||
long value = (long) (lower / (long) (Math.pow(10, mPower)));
|
||||
long value = (long)(lower / (long)(Math.pow(10, mPower)));
|
||||
|
||||
set(value, fireChangeEvent);
|
||||
}
|
||||
|
||||
public long getFrequency()
|
||||
{
|
||||
return mValue * (long) Math.pow(10, mPower);
|
||||
return mValue * (long)Math.pow(10, mPower);
|
||||
}
|
||||
|
||||
public void increment()
|
||||
@@ -256,7 +247,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
|
||||
public void increment(boolean fireChangeEvent)
|
||||
{
|
||||
if (isEnabled())
|
||||
if(isEnabled())
|
||||
{
|
||||
set(mValue + 1, fireChangeEvent);
|
||||
}
|
||||
@@ -269,7 +260,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
|
||||
public void decrement(boolean fireChangeEvent)
|
||||
{
|
||||
if (isEnabled())
|
||||
if(isEnabled())
|
||||
{
|
||||
set(mValue - 1, fireChangeEvent);
|
||||
}
|
||||
@@ -295,13 +286,13 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
mValue = amount;
|
||||
|
||||
|
||||
while (mValue < 0)
|
||||
while(mValue < 0)
|
||||
{
|
||||
mValue += 10;
|
||||
|
||||
Digit nextHigherDigit = mDigits.get(mPower + 1);
|
||||
|
||||
if (nextHigherDigit != null)
|
||||
if(nextHigherDigit != null)
|
||||
{
|
||||
nextHigherDigit.decrement(false);
|
||||
higherDigitDecremented = true;
|
||||
@@ -309,55 +300,55 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
|
||||
}
|
||||
|
||||
while (mValue > 9)
|
||||
while(mValue > 9)
|
||||
{
|
||||
mValue -= 10;
|
||||
|
||||
Digit nextHigherDigit = mDigits.get(mPower + 1);
|
||||
|
||||
if (nextHigherDigit != null)
|
||||
if(nextHigherDigit != null)
|
||||
{
|
||||
nextHigherDigit.increment(false);
|
||||
higherDigitIncremented = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fireChangeEvent)
|
||||
if(fireChangeEvent)
|
||||
{
|
||||
try
|
||||
{
|
||||
fireFrequencyChanged();
|
||||
fireSourceChanged();
|
||||
}
|
||||
catch (SourceException se)
|
||||
catch(SourceException se)
|
||||
{
|
||||
mValue = previous;
|
||||
|
||||
if (higherDigitIncremented)
|
||||
if(higherDigitIncremented)
|
||||
{
|
||||
Digit nextHigherDigit = mDigits.get(mPower + 1);
|
||||
|
||||
if (nextHigherDigit != null)
|
||||
if(nextHigherDigit != null)
|
||||
{
|
||||
nextHigherDigit.decrement(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (higherDigitDecremented)
|
||||
if(higherDigitDecremented)
|
||||
{
|
||||
Digit nextHigherDigit = mDigits.get(mPower + 1);
|
||||
|
||||
if (nextHigherDigit != null)
|
||||
if(nextHigherDigit != null)
|
||||
{
|
||||
nextHigherDigit.increment(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (se instanceof InvalidFrequencyException)
|
||||
if(se instanceof InvalidFrequencyException)
|
||||
{
|
||||
InvalidFrequencyException ife = (InvalidFrequencyException) se;
|
||||
InvalidFrequencyException ife = (InvalidFrequencyException)se;
|
||||
|
||||
JOptionPane.showMessageDialog(this, "Frequency [" + ife.getInvalidFrequency() +
|
||||
"] exceeds the frequency limit [" + ife.getValidFrequency() + "] for this tuner.");
|
||||
"] exceeds the frequency limit [" + ife.getValidFrequency() + "] for this tuner.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,15 +360,15 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
}
|
||||
|
||||
private class Listener implements KeyListener,
|
||||
MouseListener,
|
||||
MouseWheelListener
|
||||
MouseListener,
|
||||
MouseWheelListener
|
||||
{
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e)
|
||||
{
|
||||
int key = e.getKeyCode();
|
||||
|
||||
switch (key)
|
||||
switch(key)
|
||||
{
|
||||
case KeyEvent.VK_0:
|
||||
case KeyEvent.VK_NUMPAD0:
|
||||
@@ -464,7 +455,7 @@ public class JFrequencyControl extends JPanel implements IFrequencyChangeProcess
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
switch (e.getButton())
|
||||
switch(e.getButton())
|
||||
{
|
||||
case MouseEvent.BUTTON1:
|
||||
increment();
|
||||
|
||||
@@ -30,10 +30,8 @@ import channel.metadata.IAttributeChangeRequestProvider;
|
||||
import channel.state.ChannelState;
|
||||
import channel.state.DecoderState;
|
||||
import channel.state.DecoderStateEvent;
|
||||
import channel.state.DecoderStateEvent.Event;
|
||||
import channel.state.IDecoderStateEventListener;
|
||||
import channel.state.IDecoderStateEventProvider;
|
||||
import channel.state.State;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelEvent;
|
||||
import controller.channel.IChannelEventListener;
|
||||
@@ -63,11 +61,9 @@ import sample.real.RealBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.RealSource;
|
||||
import source.Source;
|
||||
import source.SourceException;
|
||||
import source.tuner.TunerChannelSource;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.tuner.frequency.IFrequencyChangeProvider;
|
||||
import source.ISourceEventListener;
|
||||
import source.ISourceEventProvider;
|
||||
import source.SourceEvent;
|
||||
import util.ThreadPool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -102,7 +98,7 @@ public class ProcessingChain implements IChannelEventListener
|
||||
private Broadcaster<ChannelEvent> mChannelEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<ComplexBuffer> mComplexBufferBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<DecoderStateEvent> mDecoderStateEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<FrequencyChangeEvent> mFrequencyChangeEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<SourceEvent> mFrequencyChangeEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<Message> mMessageBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<RealBuffer> mFilteredRealBufferBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<RealBuffer> mUnFilteredRealBufferBroadcaster = new Broadcaster<>();
|
||||
@@ -318,9 +314,9 @@ public class ProcessingChain implements IChannelEventListener
|
||||
mDecoderStateEventBroadcaster.addListener(((IDecoderStateEventListener) module).getDecoderStateListener());
|
||||
}
|
||||
|
||||
if(module instanceof IFrequencyChangeListener)
|
||||
if(module instanceof ISourceEventListener)
|
||||
{
|
||||
mFrequencyChangeEventBroadcaster.addListener(((IFrequencyChangeListener) module).getFrequencyChangeListener());
|
||||
mFrequencyChangeEventBroadcaster.addListener(((ISourceEventListener) module).getSourceEventListener());
|
||||
}
|
||||
|
||||
if(module instanceof IMessageListener)
|
||||
@@ -380,9 +376,9 @@ public class ProcessingChain implements IChannelEventListener
|
||||
mDecoderStateEventBroadcaster.removeListener(((IDecoderStateEventListener) module).getDecoderStateListener());
|
||||
}
|
||||
|
||||
if(module instanceof IFrequencyChangeListener)
|
||||
if(module instanceof ISourceEventListener)
|
||||
{
|
||||
mFrequencyChangeEventBroadcaster.removeListener(((IFrequencyChangeListener) module).getFrequencyChangeListener());
|
||||
mFrequencyChangeEventBroadcaster.removeListener(((ISourceEventListener) module).getSourceEventListener());
|
||||
}
|
||||
|
||||
if(module instanceof IMessageListener)
|
||||
@@ -437,9 +433,9 @@ public class ProcessingChain implements IChannelEventListener
|
||||
((IDecoderStateEventProvider) module).setDecoderStateListener(mDecoderStateEventBroadcaster);
|
||||
}
|
||||
|
||||
if(module instanceof IFrequencyChangeProvider)
|
||||
if(module instanceof IFilteredRealBufferProvider)
|
||||
{
|
||||
((IFrequencyChangeProvider) module).setFrequencyChangeListener(mFrequencyChangeEventBroadcaster);
|
||||
((IFilteredRealBufferProvider) module).setFilteredRealBufferListener(mFilteredRealBufferBroadcaster);
|
||||
}
|
||||
|
||||
if(module instanceof IMessageProvider)
|
||||
@@ -447,9 +443,9 @@ public class ProcessingChain implements IChannelEventListener
|
||||
((IMessageProvider) module).setMessageListener(mMessageBroadcaster);
|
||||
}
|
||||
|
||||
if(module instanceof IFilteredRealBufferProvider)
|
||||
if(module instanceof ISourceEventProvider)
|
||||
{
|
||||
((IFilteredRealBufferProvider) module).setFilteredRealBufferListener(mFilteredRealBufferBroadcaster);
|
||||
((ISourceEventProvider) module).setSourceEventListener(mFrequencyChangeEventBroadcaster);
|
||||
}
|
||||
|
||||
if(module instanceof ISquelchStateProvider)
|
||||
@@ -494,9 +490,9 @@ public class ProcessingChain implements IChannelEventListener
|
||||
((IDecoderStateEventProvider) module).setDecoderStateListener(null);
|
||||
}
|
||||
|
||||
if(module instanceof IFrequencyChangeProvider)
|
||||
if(module instanceof IFilteredRealBufferProvider)
|
||||
{
|
||||
((IFrequencyChangeProvider) module).setFrequencyChangeListener(null);
|
||||
((IFilteredRealBufferProvider) module).setFilteredRealBufferListener(null);
|
||||
}
|
||||
|
||||
if(module instanceof IMessageProvider)
|
||||
@@ -504,9 +500,9 @@ public class ProcessingChain implements IChannelEventListener
|
||||
((IMessageProvider) module).setMessageListener(null);
|
||||
}
|
||||
|
||||
if(module instanceof IFilteredRealBufferProvider)
|
||||
if(module instanceof ISourceEventProvider)
|
||||
{
|
||||
((IFilteredRealBufferProvider) module).setFilteredRealBufferListener(null);
|
||||
((ISourceEventProvider) module).setSourceEventListener(null);
|
||||
}
|
||||
|
||||
if(module instanceof ISquelchStateProvider)
|
||||
@@ -743,7 +739,7 @@ public class ProcessingChain implements IChannelEventListener
|
||||
* Adds the listener to receive frequency change events from the processing chain
|
||||
* @param listener to receive events
|
||||
*/
|
||||
public void addFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void addFrequencyChangeListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mFrequencyChangeEventBroadcaster.addListener(listener);
|
||||
}
|
||||
@@ -752,7 +748,7 @@ public class ProcessingChain implements IChannelEventListener
|
||||
* Removes the listener from receiving frequency change events
|
||||
* @param listener to remove
|
||||
*/
|
||||
public void removeFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void removeFrequencyChangeListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mFrequencyChangeEventBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
@@ -1,512 +1,508 @@
|
||||
package module.decode.p25;
|
||||
|
||||
import dsp.gain.DirectGainControl;
|
||||
import instrument.Instrumentable;
|
||||
import instrument.tap.Tap;
|
||||
import instrument.tap.TapGroup;
|
||||
import instrument.tap.stream.AdditiveFloatTap;
|
||||
import instrument.tap.stream.FloatTap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.real.RealBuffer;
|
||||
import sample.real.RealSampleListener;
|
||||
import sample.real.RealSampleProvider;
|
||||
import source.tuner.TunerChannelSource;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import dsp.gain.DirectGainControl;
|
||||
import source.ISourceEventListener;
|
||||
import source.SourceEvent;
|
||||
|
||||
public class C4FMSymbolFilter implements Listener<RealBuffer>, IFrequencyChangeListener, RealSampleProvider, Instrumentable
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class C4FMSymbolFilter implements Listener<RealBuffer>, ISourceEventListener, RealSampleProvider, Instrumentable
|
||||
{
|
||||
private static final float TAPS[][] =
|
||||
{
|
||||
{ 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f }, // 0/128
|
||||
{ -1.54700e-04f, 8.53777e-04f, -2.76968e-03f, 7.89295e-03f, 9.98534e-01f, -5.41054e-03f, 1.24642e-03f, -1.98993e-04f }, // 1/128
|
||||
{ -3.09412e-04f, 1.70888e-03f, -5.55134e-03f, 1.58840e-02f, 9.96891e-01f, -1.07209e-02f, 2.47942e-03f, -3.96391e-04f }, // 2/128
|
||||
{ -4.64053e-04f, 2.56486e-03f, -8.34364e-03f, 2.39714e-02f, 9.95074e-01f, -1.59305e-02f, 3.69852e-03f, -5.92100e-04f }, // 3/128
|
||||
{ -6.18544e-04f, 3.42130e-03f, -1.11453e-02f, 3.21531e-02f, 9.93082e-01f, -2.10389e-02f, 4.90322e-03f, -7.86031e-04f }, // 4/128
|
||||
{ -7.72802e-04f, 4.27773e-03f, -1.39548e-02f, 4.04274e-02f, 9.90917e-01f, -2.60456e-02f, 6.09305e-03f, -9.78093e-04f }, // 5/128
|
||||
{ -9.26747e-04f, 5.13372e-03f, -1.67710e-02f, 4.87921e-02f, 9.88580e-01f, -3.09503e-02f, 7.26755e-03f, -1.16820e-03f }, // 6/128
|
||||
{ -1.08030e-03f, 5.98883e-03f, -1.95925e-02f, 5.72454e-02f, 9.86071e-01f, -3.57525e-02f, 8.42626e-03f, -1.35627e-03f }, // 7/128
|
||||
{ -1.23337e-03f, 6.84261e-03f, -2.24178e-02f, 6.57852e-02f, 9.83392e-01f, -4.04519e-02f, 9.56876e-03f, -1.54221e-03f }, // 8/128
|
||||
{ -1.38589e-03f, 7.69462e-03f, -2.52457e-02f, 7.44095e-02f, 9.80543e-01f, -4.50483e-02f, 1.06946e-02f, -1.72594e-03f }, // 9/128
|
||||
{ -1.53777e-03f, 8.54441e-03f, -2.80746e-02f, 8.31162e-02f, 9.77526e-01f, -4.95412e-02f, 1.18034e-02f, -1.90738e-03f }, // 10/128
|
||||
{ -1.68894e-03f, 9.39154e-03f, -3.09033e-02f, 9.19033e-02f, 9.74342e-01f, -5.39305e-02f, 1.28947e-02f, -2.08645e-03f }, // 11/128
|
||||
{ -1.83931e-03f, 1.02356e-02f, -3.37303e-02f, 1.00769e-01f, 9.70992e-01f, -5.82159e-02f, 1.39681e-02f, -2.26307e-03f }, // 12/128
|
||||
{ -1.98880e-03f, 1.10760e-02f, -3.65541e-02f, 1.09710e-01f, 9.67477e-01f, -6.23972e-02f, 1.50233e-02f, -2.43718e-03f }, // 13/128
|
||||
{ -2.13733e-03f, 1.19125e-02f, -3.93735e-02f, 1.18725e-01f, 9.63798e-01f, -6.64743e-02f, 1.60599e-02f, -2.60868e-03f }, // 14/128
|
||||
{ -2.28483e-03f, 1.27445e-02f, -4.21869e-02f, 1.27812e-01f, 9.59958e-01f, -7.04471e-02f, 1.70776e-02f, -2.77751e-03f }, // 15/128
|
||||
{ -2.43121e-03f, 1.35716e-02f, -4.49929e-02f, 1.36968e-01f, 9.55956e-01f, -7.43154e-02f, 1.80759e-02f, -2.94361e-03f }, // 16/128
|
||||
{ -2.57640e-03f, 1.43934e-02f, -4.77900e-02f, 1.46192e-01f, 9.51795e-01f, -7.80792e-02f, 1.90545e-02f, -3.10689e-03f }, // 17/128
|
||||
{ -2.72032e-03f, 1.52095e-02f, -5.05770e-02f, 1.55480e-01f, 9.47477e-01f, -8.17385e-02f, 2.00132e-02f, -3.26730e-03f }, // 18/128
|
||||
{ -2.86289e-03f, 1.60193e-02f, -5.33522e-02f, 1.64831e-01f, 9.43001e-01f, -8.52933e-02f, 2.09516e-02f, -3.42477e-03f }, // 19/128
|
||||
{ -3.00403e-03f, 1.68225e-02f, -5.61142e-02f, 1.74242e-01f, 9.38371e-01f, -8.87435e-02f, 2.18695e-02f, -3.57923e-03f }, // 20/128
|
||||
{ -3.14367e-03f, 1.76185e-02f, -5.88617e-02f, 1.83711e-01f, 9.33586e-01f, -9.20893e-02f, 2.27664e-02f, -3.73062e-03f }, // 21/128
|
||||
{ -3.28174e-03f, 1.84071e-02f, -6.15931e-02f, 1.93236e-01f, 9.28650e-01f, -9.53307e-02f, 2.36423e-02f, -3.87888e-03f }, // 22/128
|
||||
{ -3.41815e-03f, 1.91877e-02f, -6.43069e-02f, 2.02814e-01f, 9.23564e-01f, -9.84679e-02f, 2.44967e-02f, -4.02397e-03f }, // 23/128
|
||||
{ -3.55283e-03f, 1.99599e-02f, -6.70018e-02f, 2.12443e-01f, 9.18329e-01f, -1.01501e-01f, 2.53295e-02f, -4.16581e-03f }, // 24/128
|
||||
{ -3.68570e-03f, 2.07233e-02f, -6.96762e-02f, 2.22120e-01f, 9.12947e-01f, -1.04430e-01f, 2.61404e-02f, -4.30435e-03f }, // 25/128
|
||||
{ -3.81671e-03f, 2.14774e-02f, -7.23286e-02f, 2.31843e-01f, 9.07420e-01f, -1.07256e-01f, 2.69293e-02f, -4.43955e-03f }, // 26/128
|
||||
{ -3.94576e-03f, 2.22218e-02f, -7.49577e-02f, 2.41609e-01f, 9.01749e-01f, -1.09978e-01f, 2.76957e-02f, -4.57135e-03f }, // 27/128
|
||||
{ -4.07279e-03f, 2.29562e-02f, -7.75620e-02f, 2.51417e-01f, 8.95936e-01f, -1.12597e-01f, 2.84397e-02f, -4.69970e-03f }, // 28/128
|
||||
{ -4.19774e-03f, 2.36801e-02f, -8.01399e-02f, 2.61263e-01f, 8.89984e-01f, -1.15113e-01f, 2.91609e-02f, -4.82456e-03f }, // 29/128
|
||||
{ -4.32052e-03f, 2.43930e-02f, -8.26900e-02f, 2.71144e-01f, 8.83893e-01f, -1.17526e-01f, 2.98593e-02f, -4.94589e-03f }, // 30/128
|
||||
{ -4.44107e-03f, 2.50946e-02f, -8.52109e-02f, 2.81060e-01f, 8.77666e-01f, -1.19837e-01f, 3.05345e-02f, -5.06363e-03f }, // 31/128
|
||||
{ -4.55932e-03f, 2.57844e-02f, -8.77011e-02f, 2.91006e-01f, 8.71305e-01f, -1.22047e-01f, 3.11866e-02f, -5.17776e-03f }, // 32/128
|
||||
{ -4.67520e-03f, 2.64621e-02f, -9.01591e-02f, 3.00980e-01f, 8.64812e-01f, -1.24154e-01f, 3.18153e-02f, -5.28823e-03f }, // 33/128
|
||||
{ -4.78866e-03f, 2.71272e-02f, -9.25834e-02f, 3.10980e-01f, 8.58189e-01f, -1.26161e-01f, 3.24205e-02f, -5.39500e-03f }, // 34/128
|
||||
{ -4.89961e-03f, 2.77794e-02f, -9.49727e-02f, 3.21004e-01f, 8.51437e-01f, -1.28068e-01f, 3.30021e-02f, -5.49804e-03f }, // 35/128
|
||||
{ -5.00800e-03f, 2.84182e-02f, -9.73254e-02f, 3.31048e-01f, 8.44559e-01f, -1.29874e-01f, 3.35600e-02f, -5.59731e-03f }, // 36/128
|
||||
{ -5.11376e-03f, 2.90433e-02f, -9.96402e-02f, 3.41109e-01f, 8.37557e-01f, -1.31581e-01f, 3.40940e-02f, -5.69280e-03f }, // 37/128
|
||||
{ -5.21683e-03f, 2.96543e-02f, -1.01915e-01f, 3.51186e-01f, 8.30432e-01f, -1.33189e-01f, 3.46042e-02f, -5.78446e-03f }, // 38/128
|
||||
{ -5.31716e-03f, 3.02507e-02f, -1.04150e-01f, 3.61276e-01f, 8.23188e-01f, -1.34699e-01f, 3.50903e-02f, -5.87227e-03f }, // 39/128
|
||||
{ -5.41467e-03f, 3.08323e-02f, -1.06342e-01f, 3.71376e-01f, 8.15826e-01f, -1.36111e-01f, 3.55525e-02f, -5.95620e-03f }, // 40/128
|
||||
{ -5.50931e-03f, 3.13987e-02f, -1.08490e-01f, 3.81484e-01f, 8.08348e-01f, -1.37426e-01f, 3.59905e-02f, -6.03624e-03f }, // 41/128
|
||||
{ -5.60103e-03f, 3.19495e-02f, -1.10593e-01f, 3.91596e-01f, 8.00757e-01f, -1.38644e-01f, 3.64044e-02f, -6.11236e-03f }, // 42/128
|
||||
{ -5.68976e-03f, 3.24843e-02f, -1.12650e-01f, 4.01710e-01f, 7.93055e-01f, -1.39767e-01f, 3.67941e-02f, -6.18454e-03f }, // 43/128
|
||||
{ -5.77544e-03f, 3.30027e-02f, -1.14659e-01f, 4.11823e-01f, 7.85244e-01f, -1.40794e-01f, 3.71596e-02f, -6.25277e-03f }, // 44/128
|
||||
{ -5.85804e-03f, 3.35046e-02f, -1.16618e-01f, 4.21934e-01f, 7.77327e-01f, -1.41727e-01f, 3.75010e-02f, -6.31703e-03f }, // 45/128
|
||||
{ -5.93749e-03f, 3.39894e-02f, -1.18526e-01f, 4.32038e-01f, 7.69305e-01f, -1.42566e-01f, 3.78182e-02f, -6.37730e-03f }, // 46/128
|
||||
{ -6.01374e-03f, 3.44568e-02f, -1.20382e-01f, 4.42134e-01f, 7.61181e-01f, -1.43313e-01f, 3.81111e-02f, -6.43358e-03f }, // 47/128
|
||||
{ -6.08674e-03f, 3.49066e-02f, -1.22185e-01f, 4.52218e-01f, 7.52958e-01f, -1.43968e-01f, 3.83800e-02f, -6.48585e-03f }, // 48/128
|
||||
{ -6.15644e-03f, 3.53384e-02f, -1.23933e-01f, 4.62289e-01f, 7.44637e-01f, -1.44531e-01f, 3.86247e-02f, -6.53412e-03f }, // 49/128
|
||||
{ -6.22280e-03f, 3.57519e-02f, -1.25624e-01f, 4.72342e-01f, 7.36222e-01f, -1.45004e-01f, 3.88454e-02f, -6.57836e-03f }, // 50/128
|
||||
{ -6.28577e-03f, 3.61468e-02f, -1.27258e-01f, 4.82377e-01f, 7.27714e-01f, -1.45387e-01f, 3.90420e-02f, -6.61859e-03f }, // 51/128
|
||||
{ -6.34530e-03f, 3.65227e-02f, -1.28832e-01f, 4.92389e-01f, 7.19116e-01f, -1.45682e-01f, 3.92147e-02f, -6.65479e-03f }, // 52/128
|
||||
{ -6.40135e-03f, 3.68795e-02f, -1.30347e-01f, 5.02377e-01f, 7.10431e-01f, -1.45889e-01f, 3.93636e-02f, -6.68698e-03f }, // 53/128
|
||||
{ -6.45388e-03f, 3.72167e-02f, -1.31800e-01f, 5.12337e-01f, 7.01661e-01f, -1.46009e-01f, 3.94886e-02f, -6.71514e-03f }, // 54/128
|
||||
{ -6.50285e-03f, 3.75341e-02f, -1.33190e-01f, 5.22267e-01f, 6.92808e-01f, -1.46043e-01f, 3.95900e-02f, -6.73929e-03f }, // 55/128
|
||||
{ -6.54823e-03f, 3.78315e-02f, -1.34515e-01f, 5.32164e-01f, 6.83875e-01f, -1.45993e-01f, 3.96678e-02f, -6.75943e-03f }, // 56/128
|
||||
{ -6.58996e-03f, 3.81085e-02f, -1.35775e-01f, 5.42025e-01f, 6.74865e-01f, -1.45859e-01f, 3.97222e-02f, -6.77557e-03f }, // 57/128
|
||||
{ -6.62802e-03f, 3.83650e-02f, -1.36969e-01f, 5.51849e-01f, 6.65779e-01f, -1.45641e-01f, 3.97532e-02f, -6.78771e-03f }, // 58/128
|
||||
{ -6.66238e-03f, 3.86006e-02f, -1.38094e-01f, 5.61631e-01f, 6.56621e-01f, -1.45343e-01f, 3.97610e-02f, -6.79588e-03f }, // 59/128
|
||||
{ -6.69300e-03f, 3.88151e-02f, -1.39150e-01f, 5.71370e-01f, 6.47394e-01f, -1.44963e-01f, 3.97458e-02f, -6.80007e-03f }, // 60/128
|
||||
{ -6.71985e-03f, 3.90083e-02f, -1.40136e-01f, 5.81063e-01f, 6.38099e-01f, -1.44503e-01f, 3.97077e-02f, -6.80032e-03f }, // 61/128
|
||||
{ -6.74291e-03f, 3.91800e-02f, -1.41050e-01f, 5.90706e-01f, 6.28739e-01f, -1.43965e-01f, 3.96469e-02f, -6.79662e-03f }, // 62/128
|
||||
{ -6.76214e-03f, 3.93299e-02f, -1.41891e-01f, 6.00298e-01f, 6.19318e-01f, -1.43350e-01f, 3.95635e-02f, -6.78902e-03f }, // 63/128
|
||||
{ -6.77751e-03f, 3.94578e-02f, -1.42658e-01f, 6.09836e-01f, 6.09836e-01f, -1.42658e-01f, 3.94578e-02f, -6.77751e-03f }, // 64/128
|
||||
{ -6.78902e-03f, 3.95635e-02f, -1.43350e-01f, 6.19318e-01f, 6.00298e-01f, -1.41891e-01f, 3.93299e-02f, -6.76214e-03f }, // 65/128
|
||||
{ -6.79662e-03f, 3.96469e-02f, -1.43965e-01f, 6.28739e-01f, 5.90706e-01f, -1.41050e-01f, 3.91800e-02f, -6.74291e-03f }, // 66/128
|
||||
{ -6.80032e-03f, 3.97077e-02f, -1.44503e-01f, 6.38099e-01f, 5.81063e-01f, -1.40136e-01f, 3.90083e-02f, -6.71985e-03f }, // 67/128
|
||||
{ -6.80007e-03f, 3.97458e-02f, -1.44963e-01f, 6.47394e-01f, 5.71370e-01f, -1.39150e-01f, 3.88151e-02f, -6.69300e-03f }, // 68/128
|
||||
{ -6.79588e-03f, 3.97610e-02f, -1.45343e-01f, 6.56621e-01f, 5.61631e-01f, -1.38094e-01f, 3.86006e-02f, -6.66238e-03f }, // 69/128
|
||||
{ -6.78771e-03f, 3.97532e-02f, -1.45641e-01f, 6.65779e-01f, 5.51849e-01f, -1.36969e-01f, 3.83650e-02f, -6.62802e-03f }, // 70/128
|
||||
{ -6.77557e-03f, 3.97222e-02f, -1.45859e-01f, 6.74865e-01f, 5.42025e-01f, -1.35775e-01f, 3.81085e-02f, -6.58996e-03f }, // 71/128
|
||||
{ -6.75943e-03f, 3.96678e-02f, -1.45993e-01f, 6.83875e-01f, 5.32164e-01f, -1.34515e-01f, 3.78315e-02f, -6.54823e-03f }, // 72/128
|
||||
{ -6.73929e-03f, 3.95900e-02f, -1.46043e-01f, 6.92808e-01f, 5.22267e-01f, -1.33190e-01f, 3.75341e-02f, -6.50285e-03f }, // 73/128
|
||||
{ -6.71514e-03f, 3.94886e-02f, -1.46009e-01f, 7.01661e-01f, 5.12337e-01f, -1.31800e-01f, 3.72167e-02f, -6.45388e-03f }, // 74/128
|
||||
{ -6.68698e-03f, 3.93636e-02f, -1.45889e-01f, 7.10431e-01f, 5.02377e-01f, -1.30347e-01f, 3.68795e-02f, -6.40135e-03f }, // 75/128
|
||||
{ -6.65479e-03f, 3.92147e-02f, -1.45682e-01f, 7.19116e-01f, 4.92389e-01f, -1.28832e-01f, 3.65227e-02f, -6.34530e-03f }, // 76/128
|
||||
{ -6.61859e-03f, 3.90420e-02f, -1.45387e-01f, 7.27714e-01f, 4.82377e-01f, -1.27258e-01f, 3.61468e-02f, -6.28577e-03f }, // 77/128
|
||||
{ -6.57836e-03f, 3.88454e-02f, -1.45004e-01f, 7.36222e-01f, 4.72342e-01f, -1.25624e-01f, 3.57519e-02f, -6.22280e-03f }, // 78/128
|
||||
{ -6.53412e-03f, 3.86247e-02f, -1.44531e-01f, 7.44637e-01f, 4.62289e-01f, -1.23933e-01f, 3.53384e-02f, -6.15644e-03f }, // 79/128
|
||||
{ -6.48585e-03f, 3.83800e-02f, -1.43968e-01f, 7.52958e-01f, 4.52218e-01f, -1.22185e-01f, 3.49066e-02f, -6.08674e-03f }, // 80/128
|
||||
{ -6.43358e-03f, 3.81111e-02f, -1.43313e-01f, 7.61181e-01f, 4.42134e-01f, -1.20382e-01f, 3.44568e-02f, -6.01374e-03f }, // 81/128
|
||||
{ -6.37730e-03f, 3.78182e-02f, -1.42566e-01f, 7.69305e-01f, 4.32038e-01f, -1.18526e-01f, 3.39894e-02f, -5.93749e-03f }, // 82/128
|
||||
{ -6.31703e-03f, 3.75010e-02f, -1.41727e-01f, 7.77327e-01f, 4.21934e-01f, -1.16618e-01f, 3.35046e-02f, -5.85804e-03f }, // 83/128
|
||||
{ -6.25277e-03f, 3.71596e-02f, -1.40794e-01f, 7.85244e-01f, 4.11823e-01f, -1.14659e-01f, 3.30027e-02f, -5.77544e-03f }, // 84/128
|
||||
{ -6.18454e-03f, 3.67941e-02f, -1.39767e-01f, 7.93055e-01f, 4.01710e-01f, -1.12650e-01f, 3.24843e-02f, -5.68976e-03f }, // 85/128
|
||||
{ -6.11236e-03f, 3.64044e-02f, -1.38644e-01f, 8.00757e-01f, 3.91596e-01f, -1.10593e-01f, 3.19495e-02f, -5.60103e-03f }, // 86/128
|
||||
{ -6.03624e-03f, 3.59905e-02f, -1.37426e-01f, 8.08348e-01f, 3.81484e-01f, -1.08490e-01f, 3.13987e-02f, -5.50931e-03f }, // 87/128
|
||||
{ -5.95620e-03f, 3.55525e-02f, -1.36111e-01f, 8.15826e-01f, 3.71376e-01f, -1.06342e-01f, 3.08323e-02f, -5.41467e-03f }, // 88/128
|
||||
{ -5.87227e-03f, 3.50903e-02f, -1.34699e-01f, 8.23188e-01f, 3.61276e-01f, -1.04150e-01f, 3.02507e-02f, -5.31716e-03f }, // 89/128
|
||||
{ -5.78446e-03f, 3.46042e-02f, -1.33189e-01f, 8.30432e-01f, 3.51186e-01f, -1.01915e-01f, 2.96543e-02f, -5.21683e-03f }, // 90/128
|
||||
{ -5.69280e-03f, 3.40940e-02f, -1.31581e-01f, 8.37557e-01f, 3.41109e-01f, -9.96402e-02f, 2.90433e-02f, -5.11376e-03f }, // 91/128
|
||||
{ -5.59731e-03f, 3.35600e-02f, -1.29874e-01f, 8.44559e-01f, 3.31048e-01f, -9.73254e-02f, 2.84182e-02f, -5.00800e-03f }, // 92/128
|
||||
{ -5.49804e-03f, 3.30021e-02f, -1.28068e-01f, 8.51437e-01f, 3.21004e-01f, -9.49727e-02f, 2.77794e-02f, -4.89961e-03f }, // 93/128
|
||||
{ -5.39500e-03f, 3.24205e-02f, -1.26161e-01f, 8.58189e-01f, 3.10980e-01f, -9.25834e-02f, 2.71272e-02f, -4.78866e-03f }, // 94/128
|
||||
{ -5.28823e-03f, 3.18153e-02f, -1.24154e-01f, 8.64812e-01f, 3.00980e-01f, -9.01591e-02f, 2.64621e-02f, -4.67520e-03f }, // 95/128
|
||||
{ -5.17776e-03f, 3.11866e-02f, -1.22047e-01f, 8.71305e-01f, 2.91006e-01f, -8.77011e-02f, 2.57844e-02f, -4.55932e-03f }, // 96/128
|
||||
{ -5.06363e-03f, 3.05345e-02f, -1.19837e-01f, 8.77666e-01f, 2.81060e-01f, -8.52109e-02f, 2.50946e-02f, -4.44107e-03f }, // 97/128
|
||||
{ -4.94589e-03f, 2.98593e-02f, -1.17526e-01f, 8.83893e-01f, 2.71144e-01f, -8.26900e-02f, 2.43930e-02f, -4.32052e-03f }, // 98/128
|
||||
{ -4.82456e-03f, 2.91609e-02f, -1.15113e-01f, 8.89984e-01f, 2.61263e-01f, -8.01399e-02f, 2.36801e-02f, -4.19774e-03f }, // 99/128
|
||||
{ -4.69970e-03f, 2.84397e-02f, -1.12597e-01f, 8.95936e-01f, 2.51417e-01f, -7.75620e-02f, 2.29562e-02f, -4.07279e-03f }, // 100/128
|
||||
{ -4.57135e-03f, 2.76957e-02f, -1.09978e-01f, 9.01749e-01f, 2.41609e-01f, -7.49577e-02f, 2.22218e-02f, -3.94576e-03f }, // 101/128
|
||||
{ -4.43955e-03f, 2.69293e-02f, -1.07256e-01f, 9.07420e-01f, 2.31843e-01f, -7.23286e-02f, 2.14774e-02f, -3.81671e-03f }, // 102/128
|
||||
{ -4.30435e-03f, 2.61404e-02f, -1.04430e-01f, 9.12947e-01f, 2.22120e-01f, -6.96762e-02f, 2.07233e-02f, -3.68570e-03f }, // 103/128
|
||||
{ -4.16581e-03f, 2.53295e-02f, -1.01501e-01f, 9.18329e-01f, 2.12443e-01f, -6.70018e-02f, 1.99599e-02f, -3.55283e-03f }, // 104/128
|
||||
{ -4.02397e-03f, 2.44967e-02f, -9.84679e-02f, 9.23564e-01f, 2.02814e-01f, -6.43069e-02f, 1.91877e-02f, -3.41815e-03f }, // 105/128
|
||||
{ -3.87888e-03f, 2.36423e-02f, -9.53307e-02f, 9.28650e-01f, 1.93236e-01f, -6.15931e-02f, 1.84071e-02f, -3.28174e-03f }, // 106/128
|
||||
{ -3.73062e-03f, 2.27664e-02f, -9.20893e-02f, 9.33586e-01f, 1.83711e-01f, -5.88617e-02f, 1.76185e-02f, -3.14367e-03f }, // 107/128
|
||||
{ -3.57923e-03f, 2.18695e-02f, -8.87435e-02f, 9.38371e-01f, 1.74242e-01f, -5.61142e-02f, 1.68225e-02f, -3.00403e-03f }, // 108/128
|
||||
{ -3.42477e-03f, 2.09516e-02f, -8.52933e-02f, 9.43001e-01f, 1.64831e-01f, -5.33522e-02f, 1.60193e-02f, -2.86289e-03f }, // 109/128
|
||||
{ -3.26730e-03f, 2.00132e-02f, -8.17385e-02f, 9.47477e-01f, 1.55480e-01f, -5.05770e-02f, 1.52095e-02f, -2.72032e-03f }, // 110/128
|
||||
{ -3.10689e-03f, 1.90545e-02f, -7.80792e-02f, 9.51795e-01f, 1.46192e-01f, -4.77900e-02f, 1.43934e-02f, -2.57640e-03f }, // 111/128
|
||||
{ -2.94361e-03f, 1.80759e-02f, -7.43154e-02f, 9.55956e-01f, 1.36968e-01f, -4.49929e-02f, 1.35716e-02f, -2.43121e-03f }, // 112/128
|
||||
{ -2.77751e-03f, 1.70776e-02f, -7.04471e-02f, 9.59958e-01f, 1.27812e-01f, -4.21869e-02f, 1.27445e-02f, -2.28483e-03f }, // 113/128
|
||||
{ -2.60868e-03f, 1.60599e-02f, -6.64743e-02f, 9.63798e-01f, 1.18725e-01f, -3.93735e-02f, 1.19125e-02f, -2.13733e-03f }, // 114/128
|
||||
{ -2.43718e-03f, 1.50233e-02f, -6.23972e-02f, 9.67477e-01f, 1.09710e-01f, -3.65541e-02f, 1.10760e-02f, -1.98880e-03f }, // 115/128
|
||||
{ -2.26307e-03f, 1.39681e-02f, -5.82159e-02f, 9.70992e-01f, 1.00769e-01f, -3.37303e-02f, 1.02356e-02f, -1.83931e-03f }, // 116/128
|
||||
{ -2.08645e-03f, 1.28947e-02f, -5.39305e-02f, 9.74342e-01f, 9.19033e-02f, -3.09033e-02f, 9.39154e-03f, -1.68894e-03f }, // 117/128
|
||||
{ -1.90738e-03f, 1.18034e-02f, -4.95412e-02f, 9.77526e-01f, 8.31162e-02f, -2.80746e-02f, 8.54441e-03f, -1.53777e-03f }, // 118/128
|
||||
{ -1.72594e-03f, 1.06946e-02f, -4.50483e-02f, 9.80543e-01f, 7.44095e-02f, -2.52457e-02f, 7.69462e-03f, -1.38589e-03f }, // 119/128
|
||||
{ -1.54221e-03f, 9.56876e-03f, -4.04519e-02f, 9.83392e-01f, 6.57852e-02f, -2.24178e-02f, 6.84261e-03f, -1.23337e-03f }, // 120/128
|
||||
{ -1.35627e-03f, 8.42626e-03f, -3.57525e-02f, 9.86071e-01f, 5.72454e-02f, -1.95925e-02f, 5.98883e-03f, -1.08030e-03f }, // 121/128
|
||||
{ -1.16820e-03f, 7.26755e-03f, -3.09503e-02f, 9.88580e-01f, 4.87921e-02f, -1.67710e-02f, 5.13372e-03f, -9.26747e-04f }, // 122/128
|
||||
{ -9.78093e-04f, 6.09305e-03f, -2.60456e-02f, 9.90917e-01f, 4.04274e-02f, -1.39548e-02f, 4.27773e-03f, -7.72802e-04f }, // 123/128
|
||||
{ -7.86031e-04f, 4.90322e-03f, -2.10389e-02f, 9.93082e-01f, 3.21531e-02f, -1.11453e-02f, 3.42130e-03f, -6.18544e-04f }, // 124/128
|
||||
{ -5.92100e-04f, 3.69852e-03f, -1.59305e-02f, 9.95074e-01f, 2.39714e-02f, -8.34364e-03f, 2.56486e-03f, -4.64053e-04f }, // 125/128
|
||||
{ -3.96391e-04f, 2.47942e-03f, -1.07209e-02f, 9.96891e-01f, 1.58840e-02f, -5.55134e-03f, 1.70888e-03f, -3.09412e-04f }, // 126/128
|
||||
{ -1.98993e-04f, 1.24642e-03f, -5.41054e-03f, 9.98534e-01f, 7.89295e-03f, -2.76968e-03f, 8.53777e-04f, -1.54700e-04f }, // 127/128
|
||||
{ 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f }, // 128/128
|
||||
};
|
||||
|
||||
private static final float TAPS[][] =
|
||||
{
|
||||
{0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f}, // 0/128
|
||||
{-1.54700e-04f, 8.53777e-04f, -2.76968e-03f, 7.89295e-03f, 9.98534e-01f, -5.41054e-03f, 1.24642e-03f, -1.98993e-04f}, // 1/128
|
||||
{-3.09412e-04f, 1.70888e-03f, -5.55134e-03f, 1.58840e-02f, 9.96891e-01f, -1.07209e-02f, 2.47942e-03f, -3.96391e-04f}, // 2/128
|
||||
{-4.64053e-04f, 2.56486e-03f, -8.34364e-03f, 2.39714e-02f, 9.95074e-01f, -1.59305e-02f, 3.69852e-03f, -5.92100e-04f}, // 3/128
|
||||
{-6.18544e-04f, 3.42130e-03f, -1.11453e-02f, 3.21531e-02f, 9.93082e-01f, -2.10389e-02f, 4.90322e-03f, -7.86031e-04f}, // 4/128
|
||||
{-7.72802e-04f, 4.27773e-03f, -1.39548e-02f, 4.04274e-02f, 9.90917e-01f, -2.60456e-02f, 6.09305e-03f, -9.78093e-04f}, // 5/128
|
||||
{-9.26747e-04f, 5.13372e-03f, -1.67710e-02f, 4.87921e-02f, 9.88580e-01f, -3.09503e-02f, 7.26755e-03f, -1.16820e-03f}, // 6/128
|
||||
{-1.08030e-03f, 5.98883e-03f, -1.95925e-02f, 5.72454e-02f, 9.86071e-01f, -3.57525e-02f, 8.42626e-03f, -1.35627e-03f}, // 7/128
|
||||
{-1.23337e-03f, 6.84261e-03f, -2.24178e-02f, 6.57852e-02f, 9.83392e-01f, -4.04519e-02f, 9.56876e-03f, -1.54221e-03f}, // 8/128
|
||||
{-1.38589e-03f, 7.69462e-03f, -2.52457e-02f, 7.44095e-02f, 9.80543e-01f, -4.50483e-02f, 1.06946e-02f, -1.72594e-03f}, // 9/128
|
||||
{-1.53777e-03f, 8.54441e-03f, -2.80746e-02f, 8.31162e-02f, 9.77526e-01f, -4.95412e-02f, 1.18034e-02f, -1.90738e-03f}, // 10/128
|
||||
{-1.68894e-03f, 9.39154e-03f, -3.09033e-02f, 9.19033e-02f, 9.74342e-01f, -5.39305e-02f, 1.28947e-02f, -2.08645e-03f}, // 11/128
|
||||
{-1.83931e-03f, 1.02356e-02f, -3.37303e-02f, 1.00769e-01f, 9.70992e-01f, -5.82159e-02f, 1.39681e-02f, -2.26307e-03f}, // 12/128
|
||||
{-1.98880e-03f, 1.10760e-02f, -3.65541e-02f, 1.09710e-01f, 9.67477e-01f, -6.23972e-02f, 1.50233e-02f, -2.43718e-03f}, // 13/128
|
||||
{-2.13733e-03f, 1.19125e-02f, -3.93735e-02f, 1.18725e-01f, 9.63798e-01f, -6.64743e-02f, 1.60599e-02f, -2.60868e-03f}, // 14/128
|
||||
{-2.28483e-03f, 1.27445e-02f, -4.21869e-02f, 1.27812e-01f, 9.59958e-01f, -7.04471e-02f, 1.70776e-02f, -2.77751e-03f}, // 15/128
|
||||
{-2.43121e-03f, 1.35716e-02f, -4.49929e-02f, 1.36968e-01f, 9.55956e-01f, -7.43154e-02f, 1.80759e-02f, -2.94361e-03f}, // 16/128
|
||||
{-2.57640e-03f, 1.43934e-02f, -4.77900e-02f, 1.46192e-01f, 9.51795e-01f, -7.80792e-02f, 1.90545e-02f, -3.10689e-03f}, // 17/128
|
||||
{-2.72032e-03f, 1.52095e-02f, -5.05770e-02f, 1.55480e-01f, 9.47477e-01f, -8.17385e-02f, 2.00132e-02f, -3.26730e-03f}, // 18/128
|
||||
{-2.86289e-03f, 1.60193e-02f, -5.33522e-02f, 1.64831e-01f, 9.43001e-01f, -8.52933e-02f, 2.09516e-02f, -3.42477e-03f}, // 19/128
|
||||
{-3.00403e-03f, 1.68225e-02f, -5.61142e-02f, 1.74242e-01f, 9.38371e-01f, -8.87435e-02f, 2.18695e-02f, -3.57923e-03f}, // 20/128
|
||||
{-3.14367e-03f, 1.76185e-02f, -5.88617e-02f, 1.83711e-01f, 9.33586e-01f, -9.20893e-02f, 2.27664e-02f, -3.73062e-03f}, // 21/128
|
||||
{-3.28174e-03f, 1.84071e-02f, -6.15931e-02f, 1.93236e-01f, 9.28650e-01f, -9.53307e-02f, 2.36423e-02f, -3.87888e-03f}, // 22/128
|
||||
{-3.41815e-03f, 1.91877e-02f, -6.43069e-02f, 2.02814e-01f, 9.23564e-01f, -9.84679e-02f, 2.44967e-02f, -4.02397e-03f}, // 23/128
|
||||
{-3.55283e-03f, 1.99599e-02f, -6.70018e-02f, 2.12443e-01f, 9.18329e-01f, -1.01501e-01f, 2.53295e-02f, -4.16581e-03f}, // 24/128
|
||||
{-3.68570e-03f, 2.07233e-02f, -6.96762e-02f, 2.22120e-01f, 9.12947e-01f, -1.04430e-01f, 2.61404e-02f, -4.30435e-03f}, // 25/128
|
||||
{-3.81671e-03f, 2.14774e-02f, -7.23286e-02f, 2.31843e-01f, 9.07420e-01f, -1.07256e-01f, 2.69293e-02f, -4.43955e-03f}, // 26/128
|
||||
{-3.94576e-03f, 2.22218e-02f, -7.49577e-02f, 2.41609e-01f, 9.01749e-01f, -1.09978e-01f, 2.76957e-02f, -4.57135e-03f}, // 27/128
|
||||
{-4.07279e-03f, 2.29562e-02f, -7.75620e-02f, 2.51417e-01f, 8.95936e-01f, -1.12597e-01f, 2.84397e-02f, -4.69970e-03f}, // 28/128
|
||||
{-4.19774e-03f, 2.36801e-02f, -8.01399e-02f, 2.61263e-01f, 8.89984e-01f, -1.15113e-01f, 2.91609e-02f, -4.82456e-03f}, // 29/128
|
||||
{-4.32052e-03f, 2.43930e-02f, -8.26900e-02f, 2.71144e-01f, 8.83893e-01f, -1.17526e-01f, 2.98593e-02f, -4.94589e-03f}, // 30/128
|
||||
{-4.44107e-03f, 2.50946e-02f, -8.52109e-02f, 2.81060e-01f, 8.77666e-01f, -1.19837e-01f, 3.05345e-02f, -5.06363e-03f}, // 31/128
|
||||
{-4.55932e-03f, 2.57844e-02f, -8.77011e-02f, 2.91006e-01f, 8.71305e-01f, -1.22047e-01f, 3.11866e-02f, -5.17776e-03f}, // 32/128
|
||||
{-4.67520e-03f, 2.64621e-02f, -9.01591e-02f, 3.00980e-01f, 8.64812e-01f, -1.24154e-01f, 3.18153e-02f, -5.28823e-03f}, // 33/128
|
||||
{-4.78866e-03f, 2.71272e-02f, -9.25834e-02f, 3.10980e-01f, 8.58189e-01f, -1.26161e-01f, 3.24205e-02f, -5.39500e-03f}, // 34/128
|
||||
{-4.89961e-03f, 2.77794e-02f, -9.49727e-02f, 3.21004e-01f, 8.51437e-01f, -1.28068e-01f, 3.30021e-02f, -5.49804e-03f}, // 35/128
|
||||
{-5.00800e-03f, 2.84182e-02f, -9.73254e-02f, 3.31048e-01f, 8.44559e-01f, -1.29874e-01f, 3.35600e-02f, -5.59731e-03f}, // 36/128
|
||||
{-5.11376e-03f, 2.90433e-02f, -9.96402e-02f, 3.41109e-01f, 8.37557e-01f, -1.31581e-01f, 3.40940e-02f, -5.69280e-03f}, // 37/128
|
||||
{-5.21683e-03f, 2.96543e-02f, -1.01915e-01f, 3.51186e-01f, 8.30432e-01f, -1.33189e-01f, 3.46042e-02f, -5.78446e-03f}, // 38/128
|
||||
{-5.31716e-03f, 3.02507e-02f, -1.04150e-01f, 3.61276e-01f, 8.23188e-01f, -1.34699e-01f, 3.50903e-02f, -5.87227e-03f}, // 39/128
|
||||
{-5.41467e-03f, 3.08323e-02f, -1.06342e-01f, 3.71376e-01f, 8.15826e-01f, -1.36111e-01f, 3.55525e-02f, -5.95620e-03f}, // 40/128
|
||||
{-5.50931e-03f, 3.13987e-02f, -1.08490e-01f, 3.81484e-01f, 8.08348e-01f, -1.37426e-01f, 3.59905e-02f, -6.03624e-03f}, // 41/128
|
||||
{-5.60103e-03f, 3.19495e-02f, -1.10593e-01f, 3.91596e-01f, 8.00757e-01f, -1.38644e-01f, 3.64044e-02f, -6.11236e-03f}, // 42/128
|
||||
{-5.68976e-03f, 3.24843e-02f, -1.12650e-01f, 4.01710e-01f, 7.93055e-01f, -1.39767e-01f, 3.67941e-02f, -6.18454e-03f}, // 43/128
|
||||
{-5.77544e-03f, 3.30027e-02f, -1.14659e-01f, 4.11823e-01f, 7.85244e-01f, -1.40794e-01f, 3.71596e-02f, -6.25277e-03f}, // 44/128
|
||||
{-5.85804e-03f, 3.35046e-02f, -1.16618e-01f, 4.21934e-01f, 7.77327e-01f, -1.41727e-01f, 3.75010e-02f, -6.31703e-03f}, // 45/128
|
||||
{-5.93749e-03f, 3.39894e-02f, -1.18526e-01f, 4.32038e-01f, 7.69305e-01f, -1.42566e-01f, 3.78182e-02f, -6.37730e-03f}, // 46/128
|
||||
{-6.01374e-03f, 3.44568e-02f, -1.20382e-01f, 4.42134e-01f, 7.61181e-01f, -1.43313e-01f, 3.81111e-02f, -6.43358e-03f}, // 47/128
|
||||
{-6.08674e-03f, 3.49066e-02f, -1.22185e-01f, 4.52218e-01f, 7.52958e-01f, -1.43968e-01f, 3.83800e-02f, -6.48585e-03f}, // 48/128
|
||||
{-6.15644e-03f, 3.53384e-02f, -1.23933e-01f, 4.62289e-01f, 7.44637e-01f, -1.44531e-01f, 3.86247e-02f, -6.53412e-03f}, // 49/128
|
||||
{-6.22280e-03f, 3.57519e-02f, -1.25624e-01f, 4.72342e-01f, 7.36222e-01f, -1.45004e-01f, 3.88454e-02f, -6.57836e-03f}, // 50/128
|
||||
{-6.28577e-03f, 3.61468e-02f, -1.27258e-01f, 4.82377e-01f, 7.27714e-01f, -1.45387e-01f, 3.90420e-02f, -6.61859e-03f}, // 51/128
|
||||
{-6.34530e-03f, 3.65227e-02f, -1.28832e-01f, 4.92389e-01f, 7.19116e-01f, -1.45682e-01f, 3.92147e-02f, -6.65479e-03f}, // 52/128
|
||||
{-6.40135e-03f, 3.68795e-02f, -1.30347e-01f, 5.02377e-01f, 7.10431e-01f, -1.45889e-01f, 3.93636e-02f, -6.68698e-03f}, // 53/128
|
||||
{-6.45388e-03f, 3.72167e-02f, -1.31800e-01f, 5.12337e-01f, 7.01661e-01f, -1.46009e-01f, 3.94886e-02f, -6.71514e-03f}, // 54/128
|
||||
{-6.50285e-03f, 3.75341e-02f, -1.33190e-01f, 5.22267e-01f, 6.92808e-01f, -1.46043e-01f, 3.95900e-02f, -6.73929e-03f}, // 55/128
|
||||
{-6.54823e-03f, 3.78315e-02f, -1.34515e-01f, 5.32164e-01f, 6.83875e-01f, -1.45993e-01f, 3.96678e-02f, -6.75943e-03f}, // 56/128
|
||||
{-6.58996e-03f, 3.81085e-02f, -1.35775e-01f, 5.42025e-01f, 6.74865e-01f, -1.45859e-01f, 3.97222e-02f, -6.77557e-03f}, // 57/128
|
||||
{-6.62802e-03f, 3.83650e-02f, -1.36969e-01f, 5.51849e-01f, 6.65779e-01f, -1.45641e-01f, 3.97532e-02f, -6.78771e-03f}, // 58/128
|
||||
{-6.66238e-03f, 3.86006e-02f, -1.38094e-01f, 5.61631e-01f, 6.56621e-01f, -1.45343e-01f, 3.97610e-02f, -6.79588e-03f}, // 59/128
|
||||
{-6.69300e-03f, 3.88151e-02f, -1.39150e-01f, 5.71370e-01f, 6.47394e-01f, -1.44963e-01f, 3.97458e-02f, -6.80007e-03f}, // 60/128
|
||||
{-6.71985e-03f, 3.90083e-02f, -1.40136e-01f, 5.81063e-01f, 6.38099e-01f, -1.44503e-01f, 3.97077e-02f, -6.80032e-03f}, // 61/128
|
||||
{-6.74291e-03f, 3.91800e-02f, -1.41050e-01f, 5.90706e-01f, 6.28739e-01f, -1.43965e-01f, 3.96469e-02f, -6.79662e-03f}, // 62/128
|
||||
{-6.76214e-03f, 3.93299e-02f, -1.41891e-01f, 6.00298e-01f, 6.19318e-01f, -1.43350e-01f, 3.95635e-02f, -6.78902e-03f}, // 63/128
|
||||
{-6.77751e-03f, 3.94578e-02f, -1.42658e-01f, 6.09836e-01f, 6.09836e-01f, -1.42658e-01f, 3.94578e-02f, -6.77751e-03f}, // 64/128
|
||||
{-6.78902e-03f, 3.95635e-02f, -1.43350e-01f, 6.19318e-01f, 6.00298e-01f, -1.41891e-01f, 3.93299e-02f, -6.76214e-03f}, // 65/128
|
||||
{-6.79662e-03f, 3.96469e-02f, -1.43965e-01f, 6.28739e-01f, 5.90706e-01f, -1.41050e-01f, 3.91800e-02f, -6.74291e-03f}, // 66/128
|
||||
{-6.80032e-03f, 3.97077e-02f, -1.44503e-01f, 6.38099e-01f, 5.81063e-01f, -1.40136e-01f, 3.90083e-02f, -6.71985e-03f}, // 67/128
|
||||
{-6.80007e-03f, 3.97458e-02f, -1.44963e-01f, 6.47394e-01f, 5.71370e-01f, -1.39150e-01f, 3.88151e-02f, -6.69300e-03f}, // 68/128
|
||||
{-6.79588e-03f, 3.97610e-02f, -1.45343e-01f, 6.56621e-01f, 5.61631e-01f, -1.38094e-01f, 3.86006e-02f, -6.66238e-03f}, // 69/128
|
||||
{-6.78771e-03f, 3.97532e-02f, -1.45641e-01f, 6.65779e-01f, 5.51849e-01f, -1.36969e-01f, 3.83650e-02f, -6.62802e-03f}, // 70/128
|
||||
{-6.77557e-03f, 3.97222e-02f, -1.45859e-01f, 6.74865e-01f, 5.42025e-01f, -1.35775e-01f, 3.81085e-02f, -6.58996e-03f}, // 71/128
|
||||
{-6.75943e-03f, 3.96678e-02f, -1.45993e-01f, 6.83875e-01f, 5.32164e-01f, -1.34515e-01f, 3.78315e-02f, -6.54823e-03f}, // 72/128
|
||||
{-6.73929e-03f, 3.95900e-02f, -1.46043e-01f, 6.92808e-01f, 5.22267e-01f, -1.33190e-01f, 3.75341e-02f, -6.50285e-03f}, // 73/128
|
||||
{-6.71514e-03f, 3.94886e-02f, -1.46009e-01f, 7.01661e-01f, 5.12337e-01f, -1.31800e-01f, 3.72167e-02f, -6.45388e-03f}, // 74/128
|
||||
{-6.68698e-03f, 3.93636e-02f, -1.45889e-01f, 7.10431e-01f, 5.02377e-01f, -1.30347e-01f, 3.68795e-02f, -6.40135e-03f}, // 75/128
|
||||
{-6.65479e-03f, 3.92147e-02f, -1.45682e-01f, 7.19116e-01f, 4.92389e-01f, -1.28832e-01f, 3.65227e-02f, -6.34530e-03f}, // 76/128
|
||||
{-6.61859e-03f, 3.90420e-02f, -1.45387e-01f, 7.27714e-01f, 4.82377e-01f, -1.27258e-01f, 3.61468e-02f, -6.28577e-03f}, // 77/128
|
||||
{-6.57836e-03f, 3.88454e-02f, -1.45004e-01f, 7.36222e-01f, 4.72342e-01f, -1.25624e-01f, 3.57519e-02f, -6.22280e-03f}, // 78/128
|
||||
{-6.53412e-03f, 3.86247e-02f, -1.44531e-01f, 7.44637e-01f, 4.62289e-01f, -1.23933e-01f, 3.53384e-02f, -6.15644e-03f}, // 79/128
|
||||
{-6.48585e-03f, 3.83800e-02f, -1.43968e-01f, 7.52958e-01f, 4.52218e-01f, -1.22185e-01f, 3.49066e-02f, -6.08674e-03f}, // 80/128
|
||||
{-6.43358e-03f, 3.81111e-02f, -1.43313e-01f, 7.61181e-01f, 4.42134e-01f, -1.20382e-01f, 3.44568e-02f, -6.01374e-03f}, // 81/128
|
||||
{-6.37730e-03f, 3.78182e-02f, -1.42566e-01f, 7.69305e-01f, 4.32038e-01f, -1.18526e-01f, 3.39894e-02f, -5.93749e-03f}, // 82/128
|
||||
{-6.31703e-03f, 3.75010e-02f, -1.41727e-01f, 7.77327e-01f, 4.21934e-01f, -1.16618e-01f, 3.35046e-02f, -5.85804e-03f}, // 83/128
|
||||
{-6.25277e-03f, 3.71596e-02f, -1.40794e-01f, 7.85244e-01f, 4.11823e-01f, -1.14659e-01f, 3.30027e-02f, -5.77544e-03f}, // 84/128
|
||||
{-6.18454e-03f, 3.67941e-02f, -1.39767e-01f, 7.93055e-01f, 4.01710e-01f, -1.12650e-01f, 3.24843e-02f, -5.68976e-03f}, // 85/128
|
||||
{-6.11236e-03f, 3.64044e-02f, -1.38644e-01f, 8.00757e-01f, 3.91596e-01f, -1.10593e-01f, 3.19495e-02f, -5.60103e-03f}, // 86/128
|
||||
{-6.03624e-03f, 3.59905e-02f, -1.37426e-01f, 8.08348e-01f, 3.81484e-01f, -1.08490e-01f, 3.13987e-02f, -5.50931e-03f}, // 87/128
|
||||
{-5.95620e-03f, 3.55525e-02f, -1.36111e-01f, 8.15826e-01f, 3.71376e-01f, -1.06342e-01f, 3.08323e-02f, -5.41467e-03f}, // 88/128
|
||||
{-5.87227e-03f, 3.50903e-02f, -1.34699e-01f, 8.23188e-01f, 3.61276e-01f, -1.04150e-01f, 3.02507e-02f, -5.31716e-03f}, // 89/128
|
||||
{-5.78446e-03f, 3.46042e-02f, -1.33189e-01f, 8.30432e-01f, 3.51186e-01f, -1.01915e-01f, 2.96543e-02f, -5.21683e-03f}, // 90/128
|
||||
{-5.69280e-03f, 3.40940e-02f, -1.31581e-01f, 8.37557e-01f, 3.41109e-01f, -9.96402e-02f, 2.90433e-02f, -5.11376e-03f}, // 91/128
|
||||
{-5.59731e-03f, 3.35600e-02f, -1.29874e-01f, 8.44559e-01f, 3.31048e-01f, -9.73254e-02f, 2.84182e-02f, -5.00800e-03f}, // 92/128
|
||||
{-5.49804e-03f, 3.30021e-02f, -1.28068e-01f, 8.51437e-01f, 3.21004e-01f, -9.49727e-02f, 2.77794e-02f, -4.89961e-03f}, // 93/128
|
||||
{-5.39500e-03f, 3.24205e-02f, -1.26161e-01f, 8.58189e-01f, 3.10980e-01f, -9.25834e-02f, 2.71272e-02f, -4.78866e-03f}, // 94/128
|
||||
{-5.28823e-03f, 3.18153e-02f, -1.24154e-01f, 8.64812e-01f, 3.00980e-01f, -9.01591e-02f, 2.64621e-02f, -4.67520e-03f}, // 95/128
|
||||
{-5.17776e-03f, 3.11866e-02f, -1.22047e-01f, 8.71305e-01f, 2.91006e-01f, -8.77011e-02f, 2.57844e-02f, -4.55932e-03f}, // 96/128
|
||||
{-5.06363e-03f, 3.05345e-02f, -1.19837e-01f, 8.77666e-01f, 2.81060e-01f, -8.52109e-02f, 2.50946e-02f, -4.44107e-03f}, // 97/128
|
||||
{-4.94589e-03f, 2.98593e-02f, -1.17526e-01f, 8.83893e-01f, 2.71144e-01f, -8.26900e-02f, 2.43930e-02f, -4.32052e-03f}, // 98/128
|
||||
{-4.82456e-03f, 2.91609e-02f, -1.15113e-01f, 8.89984e-01f, 2.61263e-01f, -8.01399e-02f, 2.36801e-02f, -4.19774e-03f}, // 99/128
|
||||
{-4.69970e-03f, 2.84397e-02f, -1.12597e-01f, 8.95936e-01f, 2.51417e-01f, -7.75620e-02f, 2.29562e-02f, -4.07279e-03f}, // 100/128
|
||||
{-4.57135e-03f, 2.76957e-02f, -1.09978e-01f, 9.01749e-01f, 2.41609e-01f, -7.49577e-02f, 2.22218e-02f, -3.94576e-03f}, // 101/128
|
||||
{-4.43955e-03f, 2.69293e-02f, -1.07256e-01f, 9.07420e-01f, 2.31843e-01f, -7.23286e-02f, 2.14774e-02f, -3.81671e-03f}, // 102/128
|
||||
{-4.30435e-03f, 2.61404e-02f, -1.04430e-01f, 9.12947e-01f, 2.22120e-01f, -6.96762e-02f, 2.07233e-02f, -3.68570e-03f}, // 103/128
|
||||
{-4.16581e-03f, 2.53295e-02f, -1.01501e-01f, 9.18329e-01f, 2.12443e-01f, -6.70018e-02f, 1.99599e-02f, -3.55283e-03f}, // 104/128
|
||||
{-4.02397e-03f, 2.44967e-02f, -9.84679e-02f, 9.23564e-01f, 2.02814e-01f, -6.43069e-02f, 1.91877e-02f, -3.41815e-03f}, // 105/128
|
||||
{-3.87888e-03f, 2.36423e-02f, -9.53307e-02f, 9.28650e-01f, 1.93236e-01f, -6.15931e-02f, 1.84071e-02f, -3.28174e-03f}, // 106/128
|
||||
{-3.73062e-03f, 2.27664e-02f, -9.20893e-02f, 9.33586e-01f, 1.83711e-01f, -5.88617e-02f, 1.76185e-02f, -3.14367e-03f}, // 107/128
|
||||
{-3.57923e-03f, 2.18695e-02f, -8.87435e-02f, 9.38371e-01f, 1.74242e-01f, -5.61142e-02f, 1.68225e-02f, -3.00403e-03f}, // 108/128
|
||||
{-3.42477e-03f, 2.09516e-02f, -8.52933e-02f, 9.43001e-01f, 1.64831e-01f, -5.33522e-02f, 1.60193e-02f, -2.86289e-03f}, // 109/128
|
||||
{-3.26730e-03f, 2.00132e-02f, -8.17385e-02f, 9.47477e-01f, 1.55480e-01f, -5.05770e-02f, 1.52095e-02f, -2.72032e-03f}, // 110/128
|
||||
{-3.10689e-03f, 1.90545e-02f, -7.80792e-02f, 9.51795e-01f, 1.46192e-01f, -4.77900e-02f, 1.43934e-02f, -2.57640e-03f}, // 111/128
|
||||
{-2.94361e-03f, 1.80759e-02f, -7.43154e-02f, 9.55956e-01f, 1.36968e-01f, -4.49929e-02f, 1.35716e-02f, -2.43121e-03f}, // 112/128
|
||||
{-2.77751e-03f, 1.70776e-02f, -7.04471e-02f, 9.59958e-01f, 1.27812e-01f, -4.21869e-02f, 1.27445e-02f, -2.28483e-03f}, // 113/128
|
||||
{-2.60868e-03f, 1.60599e-02f, -6.64743e-02f, 9.63798e-01f, 1.18725e-01f, -3.93735e-02f, 1.19125e-02f, -2.13733e-03f}, // 114/128
|
||||
{-2.43718e-03f, 1.50233e-02f, -6.23972e-02f, 9.67477e-01f, 1.09710e-01f, -3.65541e-02f, 1.10760e-02f, -1.98880e-03f}, // 115/128
|
||||
{-2.26307e-03f, 1.39681e-02f, -5.82159e-02f, 9.70992e-01f, 1.00769e-01f, -3.37303e-02f, 1.02356e-02f, -1.83931e-03f}, // 116/128
|
||||
{-2.08645e-03f, 1.28947e-02f, -5.39305e-02f, 9.74342e-01f, 9.19033e-02f, -3.09033e-02f, 9.39154e-03f, -1.68894e-03f}, // 117/128
|
||||
{-1.90738e-03f, 1.18034e-02f, -4.95412e-02f, 9.77526e-01f, 8.31162e-02f, -2.80746e-02f, 8.54441e-03f, -1.53777e-03f}, // 118/128
|
||||
{-1.72594e-03f, 1.06946e-02f, -4.50483e-02f, 9.80543e-01f, 7.44095e-02f, -2.52457e-02f, 7.69462e-03f, -1.38589e-03f}, // 119/128
|
||||
{-1.54221e-03f, 9.56876e-03f, -4.04519e-02f, 9.83392e-01f, 6.57852e-02f, -2.24178e-02f, 6.84261e-03f, -1.23337e-03f}, // 120/128
|
||||
{-1.35627e-03f, 8.42626e-03f, -3.57525e-02f, 9.86071e-01f, 5.72454e-02f, -1.95925e-02f, 5.98883e-03f, -1.08030e-03f}, // 121/128
|
||||
{-1.16820e-03f, 7.26755e-03f, -3.09503e-02f, 9.88580e-01f, 4.87921e-02f, -1.67710e-02f, 5.13372e-03f, -9.26747e-04f}, // 122/128
|
||||
{-9.78093e-04f, 6.09305e-03f, -2.60456e-02f, 9.90917e-01f, 4.04274e-02f, -1.39548e-02f, 4.27773e-03f, -7.72802e-04f}, // 123/128
|
||||
{-7.86031e-04f, 4.90322e-03f, -2.10389e-02f, 9.93082e-01f, 3.21531e-02f, -1.11453e-02f, 3.42130e-03f, -6.18544e-04f}, // 124/128
|
||||
{-5.92100e-04f, 3.69852e-03f, -1.59305e-02f, 9.95074e-01f, 2.39714e-02f, -8.34364e-03f, 2.56486e-03f, -4.64053e-04f}, // 125/128
|
||||
{-3.96391e-04f, 2.47942e-03f, -1.07209e-02f, 9.96891e-01f, 1.58840e-02f, -5.55134e-03f, 1.70888e-03f, -3.09412e-04f}, // 126/128
|
||||
{-1.98993e-04f, 1.24642e-03f, -5.41054e-03f, 9.98534e-01f, 7.89295e-03f, -2.76968e-03f, 8.53777e-04f, -1.54700e-04f}, // 127/128
|
||||
{0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f}, // 128/128
|
||||
};
|
||||
|
||||
/* Instrumentation Taps */
|
||||
private static final String INSTRUMENT_SYMBOL_SPREAD = "Tap Point: Symbol Spread (Goal=2.0)";
|
||||
private FloatTap mSymbolSpreadTap;
|
||||
private static final String INSTRUMENT_SYMBOL_SPREAD = "Tap Point: Symbol Spread (Goal=2.0)";
|
||||
private FloatTap mSymbolSpreadTap;
|
||||
private List<TapGroup> mAvailableTaps;
|
||||
|
||||
private static final int NUMBER_FILTER_TAPS = 8;
|
||||
private static final int NUMBER_FILTER_STEPS = 128;
|
||||
|
||||
private static final int SAMPLE_RATE = 48000;
|
||||
private static final int SYMBOL_RATE = 4800;
|
||||
|
||||
/* Tracking loop gain constant */
|
||||
private static final double K_SYMBOL_SPREAD = 0.0100;
|
||||
|
||||
/* Constraints on symbol spreading */
|
||||
private static final float SYMBOL_SPREAD_MAX = 2.4f; // upper range limit: +20%
|
||||
private static final float SYMBOL_SPREAD_MIN = 1.6f; // lower range limit: -20%
|
||||
private static final int NUMBER_FILTER_TAPS = 8;
|
||||
private static final int NUMBER_FILTER_STEPS = 128;
|
||||
|
||||
/* Symbol clock tracking loop gain */
|
||||
private static final double K_SYMBOL_TIMING = 0.025;
|
||||
|
||||
/* Coarse and fine frequency tracking constants */
|
||||
private static final double K_COARSE_FREQUENCY = 0.00125;
|
||||
private static final double K_FINE_FREQUENCY = 0.125;
|
||||
|
||||
/* Frequency correction broadcast threshold */
|
||||
private static final int SAMPLE_RATE = 48000;
|
||||
private static final int SYMBOL_RATE = 4800;
|
||||
|
||||
/* Tracking loop gain constant */
|
||||
private static final double K_SYMBOL_SPREAD = 0.0100;
|
||||
|
||||
/* Constraints on symbol spreading */
|
||||
private static final float SYMBOL_SPREAD_MAX = 2.4f; // upper range limit: +20%
|
||||
private static final float SYMBOL_SPREAD_MIN = 1.6f; // lower range limit: -20%
|
||||
|
||||
/* Symbol clock tracking loop gain */
|
||||
private static final double K_SYMBOL_TIMING = 0.025;
|
||||
|
||||
/* Coarse and fine frequency tracking constants */
|
||||
private static final double K_COARSE_FREQUENCY = 0.00125;
|
||||
private static final double K_FINE_FREQUENCY = 0.125;
|
||||
|
||||
/* Frequency correction broadcast threshold */
|
||||
// private static final double COARSE_FREQUENCY_DEADBAND = 1.66;
|
||||
private static final double COARSE_FREQUENCY_THRESHOLD = 1.20;
|
||||
|
||||
/* 2.0 symbol spread gives -3, -1, 1, 3 */
|
||||
private float mSymbolSpread = 2.0f;
|
||||
private float mSymbolClock = 0.0f;
|
||||
private float mSymbolTime = (float)SYMBOL_RATE / (float)SAMPLE_RATE;
|
||||
|
||||
private float mFineFrequencyCorrection = 0.0f;
|
||||
private float mCoarseFrequencyCorrection = 0.0f;
|
||||
private static final double COARSE_FREQUENCY_THRESHOLD = 1.20;
|
||||
|
||||
private float mHistory[] = new float[ NUMBER_FILTER_TAPS ];
|
||||
private int mHistoryLast = 0;
|
||||
|
||||
private RealSampleListener mListener;
|
||||
|
||||
private DirectGainControl mGainController = new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
|
||||
/* 2.0 symbol spread gives -3, -1, 1, 3 */
|
||||
private float mSymbolSpread = 2.0f;
|
||||
private float mSymbolClock = 0.0f;
|
||||
private float mSymbolTime = (float)SYMBOL_RATE / (float)SAMPLE_RATE;
|
||||
|
||||
private int mFrequencyAdjustmentRequested = 0;
|
||||
private int mFrequencyCorrection = 0;
|
||||
private int mFrequencyCorrectionMaximum = 3000;
|
||||
private boolean mResetFrequencyTracker = false;
|
||||
private FrequencyCorrectionProcessor mFrequencyCorrectionProcessor;
|
||||
private Listener<FrequencyChangeEvent> mFrequencyChangeListener;
|
||||
|
||||
/**
|
||||
* C4FM Symbol Filter
|
||||
*
|
||||
* Sample Gain values - the gain of incoming sample values will critically
|
||||
* impact the performance of this filter. Gain should be adjusted to
|
||||
* optimize the value of mSymbolSpread toward a value of 2.0. If the value
|
||||
* is less than 2.0, then increase gain. If the value is over 2.0, then
|
||||
* decrease gain.
|
||||
*
|
||||
* When preceded by the RealAutomaticGainFilter class, an optimal gain
|
||||
* setting for this filter is 15.4 and that yields a symbol spread that
|
||||
* is centered on 2.0, ranging 1.92 to 2.08.
|
||||
*/
|
||||
public C4FMSymbolFilter( int frequencyCorrectionMaximum )
|
||||
{
|
||||
mFrequencyCorrectionMaximum = frequencyCorrectionMaximum;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mGainController = null;
|
||||
private float mFineFrequencyCorrection = 0.0f;
|
||||
private float mCoarseFrequencyCorrection = 0.0f;
|
||||
|
||||
private float mHistory[] = new float[NUMBER_FILTER_TAPS];
|
||||
private int mHistoryLast = 0;
|
||||
|
||||
private RealSampleListener mListener;
|
||||
|
||||
private DirectGainControl mGainController = new DirectGainControl(15.0f, 0.1f, 35.0f, 0.3f);
|
||||
|
||||
private int mFrequencyAdjustmentRequested = 0;
|
||||
private int mFrequencyCorrection = 0;
|
||||
private int mFrequencyCorrectionMaximum = 3000;
|
||||
private boolean mResetFrequencyTracker = false;
|
||||
private FrequencyCorrectionProcessor mFrequencyCorrectionProcessor;
|
||||
private Listener<SourceEvent> mFrequencyChangeListener;
|
||||
|
||||
/**
|
||||
* C4FM Symbol Filter
|
||||
*
|
||||
* Sample Gain values - the gain of incoming sample values will critically
|
||||
* impact the performance of this filter. Gain should be adjusted to
|
||||
* optimize the value of mSymbolSpread toward a value of 2.0. If the value
|
||||
* is less than 2.0, then increase gain. If the value is over 2.0, then
|
||||
* decrease gain.
|
||||
*
|
||||
* When preceded by the RealAutomaticGainFilter class, an optimal gain
|
||||
* setting for this filter is 15.4 and that yields a symbol spread that
|
||||
* is centered on 2.0, ranging 1.92 to 2.08.
|
||||
*/
|
||||
public C4FMSymbolFilter(int frequencyCorrectionMaximum)
|
||||
{
|
||||
mFrequencyCorrectionMaximum = frequencyCorrectionMaximum;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mGainController = null;
|
||||
// mFrequencyCorrectionControl = null;
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( RealBuffer buffer )
|
||||
{
|
||||
for( float sample: buffer.getSamples() )
|
||||
{
|
||||
receive( sample );
|
||||
}
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(RealBuffer buffer)
|
||||
{
|
||||
for(float sample : buffer.getSamples())
|
||||
{
|
||||
receive(sample);
|
||||
}
|
||||
|
||||
/* If a frequency correction was requested during the processing of this
|
||||
* buffer, we'll apply the change and it will be reflected in the next
|
||||
* buffer, we'll apply the change and it will be reflected in the next
|
||||
* arriving buffer. Reset the lock on frequency correction and reset
|
||||
* the internal frequency correction tracker */
|
||||
if( mFrequencyAdjustmentRequested != 0 )
|
||||
{
|
||||
int correction = mFrequencyCorrection + mFrequencyAdjustmentRequested;
|
||||
|
||||
if( correction > mFrequencyCorrectionMaximum )
|
||||
{
|
||||
correction = mFrequencyCorrectionMaximum;
|
||||
}
|
||||
else if( correction < -mFrequencyCorrectionMaximum )
|
||||
{
|
||||
correction = -mFrequencyCorrectionMaximum;
|
||||
}
|
||||
if(mFrequencyAdjustmentRequested != 0)
|
||||
{
|
||||
int correction = mFrequencyCorrection + mFrequencyAdjustmentRequested;
|
||||
|
||||
broadcast( new FrequencyChangeEvent(Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
|
||||
if(correction > mFrequencyCorrectionMaximum)
|
||||
{
|
||||
correction = mFrequencyCorrectionMaximum;
|
||||
}
|
||||
else if(correction < -mFrequencyCorrectionMaximum)
|
||||
{
|
||||
correction = -mFrequencyCorrectionMaximum;
|
||||
}
|
||||
|
||||
mFrequencyAdjustmentRequested = 0;
|
||||
}
|
||||
}
|
||||
broadcast(SourceEvent.channelFrequencyCorrectionRequest(correction));
|
||||
|
||||
public void receive( float sample )
|
||||
mFrequencyAdjustmentRequested = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void receive(float sample)
|
||||
{
|
||||
sample = mGainController.correct( sample );
|
||||
|
||||
if( mResetFrequencyTracker )
|
||||
{
|
||||
mCoarseFrequencyCorrection = 0.0f;
|
||||
mFineFrequencyCorrection = 0.0f;
|
||||
|
||||
broadcast( new FrequencyChangeEvent(
|
||||
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, 0 ));
|
||||
|
||||
mResetFrequencyTracker = false;
|
||||
}
|
||||
|
||||
mSymbolClock += mSymbolTime;
|
||||
|
||||
mHistory[ mHistoryLast++ ] = sample;
|
||||
|
||||
mHistoryLast %= NUMBER_FILTER_TAPS;
|
||||
|
||||
if( mSymbolClock > 1.0f )
|
||||
{
|
||||
mSymbolClock -= 1.0f;
|
||||
|
||||
int imu = (int)Math.floor( 0.5 +
|
||||
( (float)NUMBER_FILTER_STEPS * ( mSymbolClock / mSymbolTime ) ) );
|
||||
|
||||
if( imu >= NUMBER_FILTER_STEPS )
|
||||
{
|
||||
imu = NUMBER_FILTER_STEPS - 1;
|
||||
}
|
||||
sample = mGainController.correct(sample);
|
||||
|
||||
int imu_p1 = imu + 1;
|
||||
if(mResetFrequencyTracker)
|
||||
{
|
||||
mCoarseFrequencyCorrection = 0.0f;
|
||||
mFineFrequencyCorrection = 0.0f;
|
||||
|
||||
int j = mHistoryLast;
|
||||
|
||||
double interp = 0.0;
|
||||
double interp_p1 = 0.0;
|
||||
|
||||
for( int i = 0; i < NUMBER_FILTER_TAPS; i++ )
|
||||
{
|
||||
interp += TAPS[ imu][ i ] * mHistory[ j ];
|
||||
interp_p1 += TAPS[ imu_p1 ][ i ] * mHistory[ j ];
|
||||
|
||||
j = ( j + 1 ) % NUMBER_FILTER_TAPS;
|
||||
}
|
||||
broadcast(SourceEvent.channelFrequencyCorrectionRequest(0l));
|
||||
|
||||
mResetFrequencyTracker = false;
|
||||
}
|
||||
|
||||
mSymbolClock += mSymbolTime;
|
||||
|
||||
mHistory[mHistoryLast++] = sample;
|
||||
|
||||
mHistoryLast %= NUMBER_FILTER_TAPS;
|
||||
|
||||
if(mSymbolClock > 1.0f)
|
||||
{
|
||||
mSymbolClock -= 1.0f;
|
||||
|
||||
int imu = (int)Math.floor(0.5 +
|
||||
((float)NUMBER_FILTER_STEPS * (mSymbolClock / mSymbolTime)));
|
||||
|
||||
if(imu >= NUMBER_FILTER_STEPS)
|
||||
{
|
||||
imu = NUMBER_FILTER_STEPS - 1;
|
||||
}
|
||||
|
||||
int imu_p1 = imu + 1;
|
||||
|
||||
int j = mHistoryLast;
|
||||
|
||||
double interp = 0.0;
|
||||
double interp_p1 = 0.0;
|
||||
|
||||
for(int i = 0; i < NUMBER_FILTER_TAPS; i++)
|
||||
{
|
||||
interp += TAPS[imu][i] * mHistory[j];
|
||||
interp_p1 += TAPS[imu_p1][i] * mHistory[j];
|
||||
|
||||
j = (j + 1) % NUMBER_FILTER_TAPS;
|
||||
}
|
||||
|
||||
/* Output symbol will be interpolated value corrected for symbol
|
||||
* spread and frequency offset */
|
||||
interp -= mFineFrequencyCorrection;
|
||||
interp_p1 -= mFineFrequencyCorrection;
|
||||
interp -= mFineFrequencyCorrection;
|
||||
interp_p1 -= mFineFrequencyCorrection;
|
||||
|
||||
/* Correct output for symbol deviation (spread) */
|
||||
float output = (float)( 2.0 * interp / mSymbolSpread );
|
||||
float output = (float)(2.0 * interp / mSymbolSpread);
|
||||
|
||||
/* Detect received symbol error: basically use a hard decision and
|
||||
* subtract off expected position nominal symbol level which will be
|
||||
* +/- 0.5 * symbol spread and +/- 1.5 symbol spread. Remember that
|
||||
* nominal symbol spread will be 2.0 */
|
||||
double symbolError;
|
||||
|
||||
if( interp < -mSymbolSpread )
|
||||
{
|
||||
double symbolError;
|
||||
|
||||
if(interp < -mSymbolSpread)
|
||||
{
|
||||
/* symbol is -3: Expected at -1.5 * symbol spread */
|
||||
symbolError = interp + ( 1.5 * mSymbolSpread );
|
||||
mSymbolSpread -= ( symbolError * 0.5 * K_SYMBOL_SPREAD );
|
||||
}
|
||||
else if( interp < 0.0 )
|
||||
{
|
||||
symbolError = interp + (1.5 * mSymbolSpread);
|
||||
mSymbolSpread -= (symbolError * 0.5 * K_SYMBOL_SPREAD);
|
||||
}
|
||||
else if(interp < 0.0)
|
||||
{
|
||||
/* symbol is -1: Expected at -0.5 * symbol_spread */
|
||||
symbolError = interp + (0.5 * mSymbolSpread );
|
||||
mSymbolSpread -= ( symbolError * K_SYMBOL_SPREAD );
|
||||
}
|
||||
else if( interp < mSymbolSpread )
|
||||
{
|
||||
symbolError = interp + (0.5 * mSymbolSpread);
|
||||
mSymbolSpread -= (symbolError * K_SYMBOL_SPREAD);
|
||||
}
|
||||
else if(interp < mSymbolSpread)
|
||||
{
|
||||
/* symbol is +1: Expected at +0.5 * symbol_spread */
|
||||
symbolError = interp - ( 0.5 * mSymbolSpread );
|
||||
mSymbolSpread += ( symbolError * K_SYMBOL_SPREAD );
|
||||
}
|
||||
else
|
||||
{
|
||||
symbolError = interp - (0.5 * mSymbolSpread);
|
||||
mSymbolSpread += (symbolError * K_SYMBOL_SPREAD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* symbol is +3: Expected at +1.5 * symbol_spread */
|
||||
symbolError = interp - ( 1.5 * mSymbolSpread );
|
||||
mSymbolSpread += ( symbolError * 0.5 * K_SYMBOL_SPREAD );
|
||||
}
|
||||
symbolError = interp - (1.5 * mSymbolSpread);
|
||||
mSymbolSpread += (symbolError * 0.5 * K_SYMBOL_SPREAD);
|
||||
}
|
||||
|
||||
/* Symbol clock tracking loop adjustment */
|
||||
if( interp_p1 < interp )
|
||||
{
|
||||
mSymbolClock += symbolError * K_SYMBOL_TIMING;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSymbolClock -= symbolError * K_SYMBOL_TIMING;
|
||||
}
|
||||
|
||||
if( mSymbolSpread < SYMBOL_SPREAD_MIN )
|
||||
{
|
||||
mGainController.increase();
|
||||
|
||||
mSymbolSpread = SYMBOL_SPREAD_MIN;
|
||||
}
|
||||
else if( mSymbolSpread > SYMBOL_SPREAD_MAX )
|
||||
{
|
||||
mGainController.decrease();
|
||||
if(interp_p1 < interp)
|
||||
{
|
||||
mSymbolClock += symbolError * K_SYMBOL_TIMING;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSymbolClock -= symbolError * K_SYMBOL_TIMING;
|
||||
}
|
||||
|
||||
mSymbolSpread = SYMBOL_SPREAD_MAX;
|
||||
}
|
||||
if(mSymbolSpread < SYMBOL_SPREAD_MIN)
|
||||
{
|
||||
mGainController.increase();
|
||||
|
||||
mCoarseFrequencyCorrection += ( ( mFineFrequencyCorrection -
|
||||
mCoarseFrequencyCorrection ) * K_COARSE_FREQUENCY );
|
||||
|
||||
mFineFrequencyCorrection += ( symbolError * K_FINE_FREQUENCY );
|
||||
mSymbolSpread = SYMBOL_SPREAD_MIN;
|
||||
}
|
||||
else if(mSymbolSpread > SYMBOL_SPREAD_MAX)
|
||||
{
|
||||
mGainController.decrease();
|
||||
|
||||
mSymbolSpread = SYMBOL_SPREAD_MAX;
|
||||
}
|
||||
|
||||
mCoarseFrequencyCorrection += ((mFineFrequencyCorrection -
|
||||
mCoarseFrequencyCorrection) * K_COARSE_FREQUENCY);
|
||||
|
||||
mFineFrequencyCorrection += (symbolError * K_FINE_FREQUENCY);
|
||||
|
||||
/* Queue a frequency adjustment (once per buffer) as needed */
|
||||
if( Math.abs( mCoarseFrequencyCorrection ) > COARSE_FREQUENCY_THRESHOLD )
|
||||
{
|
||||
mFrequencyAdjustmentRequested =
|
||||
500 * ( mCoarseFrequencyCorrection > 0 ? 1 : -1 );
|
||||
}
|
||||
|
||||
if( mSymbolSpreadTap != null )
|
||||
{
|
||||
mSymbolSpreadTap.receive( mSymbolSpread );
|
||||
}
|
||||
if(Math.abs(mCoarseFrequencyCorrection) > COARSE_FREQUENCY_THRESHOLD)
|
||||
{
|
||||
mFrequencyAdjustmentRequested =
|
||||
500 * (mCoarseFrequencyCorrection > 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
if(mSymbolSpreadTap != null)
|
||||
{
|
||||
mSymbolSpreadTap.receive(mSymbolSpread);
|
||||
}
|
||||
|
||||
/* dispatch the interpolated value to the listener */
|
||||
if( mListener != null )
|
||||
{
|
||||
mListener.receive( output );
|
||||
}
|
||||
}
|
||||
if(mListener != null)
|
||||
{
|
||||
mListener.receive(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener( RealSampleListener listener )
|
||||
@Override
|
||||
public void setListener(RealSampleListener listener)
|
||||
{
|
||||
mListener = listener;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( RealSampleListener listener )
|
||||
@Override
|
||||
public void removeListener(RealSampleListener listener)
|
||||
{
|
||||
mListener = null;
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
public List<TapGroup> getTapGroups()
|
||||
{
|
||||
if( mAvailableTaps == null )
|
||||
{
|
||||
mAvailableTaps = new ArrayList<>();
|
||||
if(mAvailableTaps == null)
|
||||
{
|
||||
mAvailableTaps = new ArrayList<>();
|
||||
|
||||
/*
|
||||
* Since the target is 2.0, we subtract 2.0 from the value so that
|
||||
* a good value is plotted right on the zero center line
|
||||
*/
|
||||
TapGroup group = new TapGroup( "C4FM Symbol Filter" );
|
||||
|
||||
group.add(
|
||||
new AdditiveFloatTap( INSTRUMENT_SYMBOL_SPREAD, 0, 0.1f, -2.0f ) );
|
||||
|
||||
mAvailableTaps.add( group );
|
||||
}
|
||||
|
||||
return mAvailableTaps;
|
||||
TapGroup group = new TapGroup("C4FM Symbol Filter");
|
||||
|
||||
group.add(
|
||||
new AdditiveFloatTap(INSTRUMENT_SYMBOL_SPREAD, 0, 0.1f, -2.0f));
|
||||
|
||||
mAvailableTaps.add(group);
|
||||
}
|
||||
|
||||
return mAvailableTaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTap( Tap tap )
|
||||
@Override
|
||||
public void registerTap(Tap tap)
|
||||
{
|
||||
if( tap.getName().contentEquals( INSTRUMENT_SYMBOL_SPREAD ) )
|
||||
{
|
||||
mSymbolSpreadTap = (FloatTap)tap;
|
||||
}
|
||||
if(tap.getName().contentEquals(INSTRUMENT_SYMBOL_SPREAD))
|
||||
{
|
||||
mSymbolSpreadTap = (FloatTap)tap;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTap( Tap tap )
|
||||
@Override
|
||||
public void unregisterTap(Tap tap)
|
||||
{
|
||||
if( tap.getName().contentEquals( INSTRUMENT_SYMBOL_SPREAD ) )
|
||||
{
|
||||
mSymbolSpreadTap = null;
|
||||
}
|
||||
if(tap.getName().contentEquals(INSTRUMENT_SYMBOL_SPREAD))
|
||||
{
|
||||
mSymbolSpreadTap = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a frequency change event to the registered listener
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void broadcast( FrequencyChangeEvent event )
|
||||
{
|
||||
if( mFrequencyChangeListener != null )
|
||||
{
|
||||
mFrequencyChangeListener.receive( event );
|
||||
}
|
||||
}
|
||||
public void broadcast(SourceEvent event)
|
||||
{
|
||||
if(mFrequencyChangeListener != null)
|
||||
{
|
||||
mFrequencyChangeListener.receive(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener for frequency change events.
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
|
||||
{
|
||||
mFrequencyChangeListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
if( mFrequencyCorrectionProcessor == null )
|
||||
{
|
||||
mFrequencyCorrectionProcessor = new FrequencyCorrectionProcessor();
|
||||
}
|
||||
|
||||
return mFrequencyCorrectionProcessor;
|
||||
}
|
||||
public void setFrequencyChangeListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mFrequencyChangeListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives notifications that the channel frequency correction has been
|
||||
* applied and updates internal tracking value.
|
||||
*/
|
||||
public class FrequencyCorrectionProcessor implements Listener<FrequencyChangeEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive( FrequencyChangeEvent event )
|
||||
{
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
mFrequencyCorrection = event.getValue().intValue();
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
if(mFrequencyCorrectionProcessor == null)
|
||||
{
|
||||
mFrequencyCorrectionProcessor = new FrequencyCorrectionProcessor();
|
||||
}
|
||||
|
||||
//Reset internal frequency tracking
|
||||
mCoarseFrequencyCorrection = 0.0f;
|
||||
mFineFrequencyCorrection = 0.0f;
|
||||
break;
|
||||
case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
mResetFrequencyTracker = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mFrequencyCorrectionProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives notifications that the channel frequency correction has been
|
||||
* applied and updates internal tracking value.
|
||||
*/
|
||||
public class FrequencyCorrectionProcessor implements Listener<SourceEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(SourceEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
mFrequencyCorrection = event.getValue().intValue();
|
||||
|
||||
//Reset internal frequency tracking
|
||||
mCoarseFrequencyCorrection = 0.0f;
|
||||
mFineFrequencyCorrection = 0.0f;
|
||||
break;
|
||||
case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
mResetFrequencyTracker = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import alias.AliasList;
|
||||
import instrument.Instrumentable;
|
||||
import module.decode.Decoder;
|
||||
import module.decode.DecoderType;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.tuner.frequency.IFrequencyChangeProvider;
|
||||
import source.ISourceEventListener;
|
||||
import source.ISourceEventProvider;
|
||||
|
||||
public abstract class P25Decoder extends Decoder implements IFrequencyChangeListener, IFrequencyChangeProvider, Instrumentable
|
||||
public abstract class P25Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider, Instrumentable
|
||||
{
|
||||
private P25MessageProcessor mMessageProcessor;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ package module.decode.p25;
|
||||
import instrument.tap.Tap;
|
||||
import instrument.tap.TapGroup;
|
||||
import instrument.tap.stream.DibitTap;
|
||||
import instrument.tap.stream.FloatBufferTap;
|
||||
import instrument.tap.stream.FloatTap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -35,12 +34,7 @@ import alias.AliasList;
|
||||
import sample.Listener;
|
||||
import sample.real.IFilteredRealBufferListener;
|
||||
import sample.real.RealBuffer;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.tuner.frequency.IFrequencyChangeProvider;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
|
||||
import source.SourceEvent;
|
||||
|
||||
public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferListener
|
||||
{
|
||||
@@ -222,7 +216,7 @@ public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener )
|
||||
{
|
||||
if( mSymbolFilter != null )
|
||||
{
|
||||
@@ -231,7 +225,7 @@ public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
if( mSymbolFilter != null )
|
||||
{
|
||||
@@ -240,11 +234,11 @@ public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
if( mSymbolFilter != null )
|
||||
{
|
||||
return mSymbolFilter.getFrequencyChangeListener();
|
||||
return mSymbolFilter.getSourceEventListener();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -42,7 +42,7 @@ import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
|
||||
import dsp.gain.ComplexFeedForwardGainControl;
|
||||
import dsp.psk.LSMDemodulator;
|
||||
import dsp.psk.QPSKPolarSlicer;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.SourceEvent;
|
||||
|
||||
public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
|
||||
{
|
||||
@@ -109,22 +109,22 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return new Listener<FrequencyChangeEvent>()
|
||||
return new Listener<SourceEvent>()
|
||||
{
|
||||
@Override
|
||||
public void receive(FrequencyChangeEvent frequencyChangeEvent)
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
//Ignored
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package sample;
|
||||
|
||||
public enum SampleType
|
||||
{
|
||||
COMPLEX, //Baseband
|
||||
REAL, //Demodulated
|
||||
COMPLEX_AND_REAL; //Baseband and Demodulated
|
||||
COMPLEX, // I/Q
|
||||
REAL; // Real
|
||||
}
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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;
|
||||
|
||||
import sample.Provider;
|
||||
@@ -6,8 +24,9 @@ import sample.complex.ComplexBuffer;
|
||||
|
||||
public abstract class ComplexSource extends Source implements Provider<ComplexBuffer>
|
||||
{
|
||||
public ComplexSource()
|
||||
{
|
||||
super( SampleType.COMPLEX );
|
||||
}
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return SampleType.COMPLEX;
|
||||
}
|
||||
}
|
||||
|
||||
35
src/source/ISourceEventListener.java
Normal file
35
src/source/ISourceEventListener.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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;
|
||||
|
||||
import sample.Listener;
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the device that implements the tuning of the frequency.
|
||||
*/
|
||||
public interface ISourceEventListener
|
||||
{
|
||||
Listener<SourceEvent> getSourceEventListener();
|
||||
}
|
||||
24
src/source/ISourceEventProcessor.java
Normal file
24
src/source/ISourceEventProcessor.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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;
|
||||
|
||||
public interface ISourceEventProcessor
|
||||
{
|
||||
void process(SourceEvent event) throws SourceException;
|
||||
}
|
||||
@@ -16,15 +16,15 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package source.tuner.frequency;
|
||||
package source;
|
||||
|
||||
import sample.Listener;
|
||||
|
||||
/**
|
||||
* Provider of Frequency Change Events
|
||||
* Provider of Source Change Events
|
||||
*/
|
||||
public interface IFrequencyChangeProvider
|
||||
public interface ISourceEventProvider
|
||||
{
|
||||
void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener );
|
||||
void removeFrequencyChangeListener();
|
||||
void setSourceEventListener(Listener<SourceEvent> listener );
|
||||
void removeSourceEventListener();
|
||||
}
|
||||
@@ -1,14 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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;
|
||||
|
||||
import sample.Provider;
|
||||
import sample.SampleType;
|
||||
import sample.real.RealBuffer;
|
||||
|
||||
|
||||
public abstract class RealSource extends Source implements Provider<RealBuffer>
|
||||
{
|
||||
public RealSource()
|
||||
{
|
||||
super( SampleType.REAL );
|
||||
}
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return SampleType.REAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,38 +20,38 @@ package source;
|
||||
import module.Module;
|
||||
import sample.SampleType;
|
||||
import sample.real.IOverflowListener;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.tuner.frequency.IFrequencyChangeProvider;
|
||||
|
||||
/**
|
||||
* Abstract class to define the minimum functionality of a sample data provider.
|
||||
*/
|
||||
public abstract class Source extends Module implements IFrequencyChangeListener, IFrequencyChangeProvider
|
||||
public abstract class Source extends Module implements ISourceEventListener, ISourceEventProvider
|
||||
{
|
||||
protected SampleType mSampleType;
|
||||
protected IOverflowListener mOverflowListener;
|
||||
|
||||
public Source( SampleType sampleType )
|
||||
{
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the type of samples provided by this source: real or complex
|
||||
*/
|
||||
public abstract SampleType getSampleType();
|
||||
|
||||
/**
|
||||
* Sample rate provided by this source
|
||||
*
|
||||
* @throws SourceException if there is an issue determining the sample rate for this source
|
||||
*/
|
||||
public abstract int getSampleRate() throws SourceException;
|
||||
|
||||
|
||||
/**
|
||||
* Center frequency for this source in Hertz
|
||||
*
|
||||
* @throws SourceException if there is an issue in determining the center frequency for this source
|
||||
*/
|
||||
public abstract long getFrequency() throws SourceException;
|
||||
|
||||
|
||||
/**
|
||||
* Process any cleanup actions to prepare for garbage collection of this source
|
||||
*/
|
||||
public abstract void dispose();
|
||||
|
||||
public SampleType getSampleType()
|
||||
{
|
||||
return mSampleType;
|
||||
}
|
||||
|
||||
public void setSampleType( SampleType sampleType )
|
||||
{
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive overflow state changes. Use null argument to clear the listener
|
||||
*/
|
||||
@@ -63,7 +63,7 @@ public abstract class Source extends Module implements IFrequencyChangeListener,
|
||||
/**
|
||||
* Broadcasts an overflow state
|
||||
*
|
||||
* @param overflow true if overlow, false if normal
|
||||
* @param overflow true if overflow, false if normal
|
||||
*/
|
||||
protected void broadcastOverflowState(boolean overflow)
|
||||
{
|
||||
|
||||
192
src/source/SourceEvent.java
Normal file
192
src/source/SourceEvent.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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;
|
||||
|
||||
public class SourceEvent
|
||||
{
|
||||
public enum Event
|
||||
{
|
||||
NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_CHANNEL_SAMPLE_RATE_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_POLYPHASE_CHANNEL_COUNT_CHANGE,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
|
||||
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
REQUEST_FREQUENCY_CHANGE,
|
||||
REQUEST_START_SAMPLE_STREAM,
|
||||
REQUEST_STOP_SAMPLE_STREAM;
|
||||
}
|
||||
|
||||
private Event mEvent;
|
||||
private Number mValue;
|
||||
private Source mSource;
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
private SourceEvent(Event event, Number value)
|
||||
{
|
||||
mEvent = event;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
private SourceEvent(Event event, Source source)
|
||||
{
|
||||
mEvent = event;
|
||||
mSource = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event description.
|
||||
*/
|
||||
public Event getEvent()
|
||||
{
|
||||
return mEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value associated with the event.
|
||||
*/
|
||||
public Number getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public boolean hasValue()
|
||||
{
|
||||
return mValue != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Source associated with the event
|
||||
*/
|
||||
public Source getSource()
|
||||
{
|
||||
return mSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this event contains an optional source
|
||||
*/
|
||||
public boolean hasSource()
|
||||
{
|
||||
return mSource != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frequency change event
|
||||
*
|
||||
* @param frequency in hertz
|
||||
*/
|
||||
public static SourceEvent frequencyChange(long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frequency correction change event
|
||||
*
|
||||
* @param frequencyCorrection in hertz
|
||||
*/
|
||||
public static SourceEvent frequencyCorrectionChange(long frequencyCorrection)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CORRECTION_CHANGE, frequencyCorrection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel frequency correction change event
|
||||
*
|
||||
* @param frequencyCorrection in hertz
|
||||
*/
|
||||
public static SourceEvent channelFrequencyCorrectionChange(long frequencyCorrection)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE, frequencyCorrection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new sample rate change event
|
||||
*
|
||||
* @param sampleRate in hertz
|
||||
*/
|
||||
public static SourceEvent sampleRateChange(int sampleRate)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE, sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel sample rate change event
|
||||
*
|
||||
* @param sampleRate in hertz
|
||||
*/
|
||||
public static SourceEvent channelSampleRateChange(int sampleRate)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_CHANNEL_SAMPLE_RATE_CHANGE, sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel count change event
|
||||
*
|
||||
* @param channelCount
|
||||
*/
|
||||
public static SourceEvent channelCountChange(int channelCount)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_POLYPHASE_CHANNEL_COUNT_CHANGE, channelCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frequency change request event
|
||||
*
|
||||
* @param frequency requested
|
||||
*/
|
||||
public static SourceEvent frequencyRequest(long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_FREQUENCY_CHANGE, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new channel frequency correction change request event
|
||||
*
|
||||
* @param frequency requested
|
||||
*/
|
||||
public static SourceEvent channelFrequencyCorrectionRequest(long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new start sample stream request event
|
||||
*/
|
||||
public static SourceEvent startSampleStream(Source source)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_START_SAMPLE_STREAM, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stop sample stream request event
|
||||
*/
|
||||
public static SourceEvent stopSampleStream(Source source)
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_STOP_SAMPLE_STREAM, source);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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.config;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.SourceType;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
public class SourceConfigRecording extends SourceConfiguration
|
||||
{
|
||||
private String mRecordingAlias;
|
||||
private long mFrequency;
|
||||
|
||||
public SourceConfigRecording()
|
||||
private String mRecordingAlias;
|
||||
private long mFrequency;
|
||||
|
||||
public SourceConfigRecording()
|
||||
{
|
||||
super( SourceType.RECORDING );
|
||||
super(SourceType.RECORDING);
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "recording_alias" )
|
||||
public String getRecordingAlias()
|
||||
{
|
||||
return mRecordingAlias;
|
||||
}
|
||||
|
||||
public void setRecordingAlias( String alias )
|
||||
{
|
||||
mRecordingAlias = alias;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "frequency" )
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency( long frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
@XmlAttribute(name = "recording_alias")
|
||||
public String getRecordingAlias()
|
||||
{
|
||||
return mRecordingAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecordingAlias(String alias)
|
||||
{
|
||||
mRecordingAlias = alias;
|
||||
}
|
||||
|
||||
@XmlAttribute(name = "frequency")
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return getRecordingAlias();
|
||||
return getRecordingAlias();
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
/* Create a tuner channel with a default bandwidth of 15 kHz */
|
||||
return new TunerChannel( Type.LOCKED, mFrequency, 15000 );
|
||||
}
|
||||
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
/* Create a tuner channel with a default bandwidth of 12.5 kHz */
|
||||
return new TunerChannel(mFrequency, 12500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,69 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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.config;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import source.SourceType;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class SourceConfigTuner extends SourceConfiguration
|
||||
{
|
||||
private static DecimalFormat sFORMAT = new DecimalFormat( "0.00000" );
|
||||
private static DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.00000");
|
||||
|
||||
private long mFrequency = 0;
|
||||
private int mBandwidth = 12500;
|
||||
|
||||
public SourceConfigTuner()
|
||||
private long mFrequency = 0;
|
||||
private int mBandwidth = 12500;
|
||||
|
||||
public SourceConfigTuner()
|
||||
{
|
||||
super( SourceType.TUNER );
|
||||
super(SourceType.TUNER);
|
||||
}
|
||||
|
||||
public SourceConfigTuner( TunerChannel tunerChannel )
|
||||
{
|
||||
this();
|
||||
|
||||
mFrequency = tunerChannel.getFrequency();
|
||||
mBandwidth = tunerChannel.getBandwidth();
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "frequency" )
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency( long frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceConfigTuner(TunerChannel tunerChannel)
|
||||
{
|
||||
this();
|
||||
|
||||
mFrequency = tunerChannel.getFrequency();
|
||||
mBandwidth = tunerChannel.getBandwidth();
|
||||
}
|
||||
|
||||
@XmlAttribute(name = "frequency")
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return sFORMAT.format( (double)mFrequency / 1000000.0d ) + " MHz";
|
||||
return FREQUENCY_FORMAT.format((double)mFrequency / 1000000.0d) + " MHz";
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return new TunerChannel(mFrequency, mBandwidth);
|
||||
}
|
||||
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return new TunerChannel( Type.LOCKED, mFrequency, mBandwidth );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import sample.real.RealBuffer;
|
||||
import source.RealSource;
|
||||
import source.SourceException;
|
||||
import dsp.gain.AutomaticGainControl;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.SourceEvent;
|
||||
|
||||
public class RealMixerSource extends RealSource
|
||||
{
|
||||
@@ -80,19 +80,19 @@ public class RealMixerSource extends RealSource
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
|
||||
@@ -9,12 +9,12 @@ import source.SourceException;
|
||||
import source.tuner.ITunerChannelProvider;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannelSource;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.SourceEvent.Event;
|
||||
import source.ISourceEventProcessor;
|
||||
|
||||
public class Recording implements Comparable<Recording>,
|
||||
IFrequencyChangeProcessor,
|
||||
ISourceEventProcessor,
|
||||
ITunerChannelProvider
|
||||
{
|
||||
private RecordingConfiguration mConfiguration;
|
||||
@@ -89,7 +89,7 @@ public class Recording implements Comparable<Recording>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException
|
||||
public void process(SourceEvent event ) throws SourceException
|
||||
{
|
||||
if( event.getEvent() == Event.NOTIFICATION_FREQUENCY_CHANGE )
|
||||
{
|
||||
@@ -103,7 +103,7 @@ public class Recording implements Comparable<Recording>,
|
||||
|
||||
for( TunerChannelSource channel: mTunerChannels )
|
||||
{
|
||||
channel.frequencyChanged( event );
|
||||
channel.process( event );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
169
src/source/tuner/ComplexChannelSource.java
Normal file
169
src/source/tuner/ComplexChannelSource.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.SourceException;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
/**
|
||||
* Complex source that provides a complex sample stream at the channel's required sample rate
|
||||
*/
|
||||
public abstract class ComplexChannelSource extends ComplexSource implements ISourceEventProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexChannelSource.class);
|
||||
private SourceEventProcessor mSourceEventProcessor = new SourceEventProcessor();
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
private Listener<ComplexBuffer> mComplexBufferListener;
|
||||
private ISourceEventProcessor mUpstreamSourceEventProcessor;
|
||||
|
||||
public ComplexChannelSource(ISourceEventProcessor upstreamSourceEventProcessor)
|
||||
{
|
||||
mUpstreamSourceEventProcessor = upstreamSourceEventProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source event listener to receive source events from this source
|
||||
*/
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mSourceEventListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the source event listener from receiving source events from this source
|
||||
*/
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mSourceEventListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the source event to the registered source event listener
|
||||
*/
|
||||
protected void broadcast(SourceEvent sourceEvent)
|
||||
{
|
||||
if(mSourceEventListener != null)
|
||||
{
|
||||
mSourceEventListener.receive(sourceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive complex sample buffers from this channel source
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the processed complex buffer to the downstream consumer.
|
||||
* @param complexBuffer containing complex samples
|
||||
*/
|
||||
protected void broadcast(ComplexBuffer complexBuffer)
|
||||
{
|
||||
if(mComplexBufferListener != null)
|
||||
{
|
||||
mComplexBufferListener.receive(complexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
//TODO: start a runnable to process downstream buffer dispatching
|
||||
|
||||
if(mUpstreamSourceEventProcessor != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mUpstreamSourceEventProcessor.process(SourceEvent.startSampleStream(ComplexChannelSource.this));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Error starting complex channel source");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(mUpstreamSourceEventProcessor != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mUpstreamSourceEventProcessor.process(SourceEvent.stopSampleStream(ComplexChannelSource.this));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Error starting complex channel source");
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: cancel a runnable to process downstream buffer dispatching
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Source Event processor interface for this source to receive source events
|
||||
*/
|
||||
@Override
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return mSourceEventProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter for implementing ISourceEventProcessor and dispatching source events to subclasses via the
|
||||
* ISourceEventProcessor.process() method.
|
||||
*/
|
||||
public class SourceEventProcessor implements Listener<SourceEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
try
|
||||
{
|
||||
process(sourceEvent);
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.error("Error processing source event", se);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,213 +1,239 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.SourceException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
|
||||
/**
|
||||
* Tuner - provides tuner channel sources, representing a channel frequency
|
||||
*/
|
||||
public abstract class Tuner implements ITunerChannelProvider
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( Tuner.class );
|
||||
|
||||
private String mName;
|
||||
private TunerController mTunerController;
|
||||
/**
|
||||
* Sample Listeners - these will typically be the DFT processor for spectral
|
||||
* display, or it will be one or more tuner channel sources
|
||||
*/
|
||||
protected List<Listener<ComplexBuffer>> mSampleListeners =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
protected List<Listener<TunerEvent>> mTunerChangeListeners =
|
||||
new ArrayList<>();
|
||||
|
||||
public Tuner( String name, TunerController tunerController )
|
||||
{
|
||||
mName = name;
|
||||
mTunerController = tunerController;
|
||||
private final static Logger mLog = LoggerFactory.getLogger(Tuner.class);
|
||||
|
||||
//Rebroadcast frequency and sample rate change events as tuner events
|
||||
mTunerController.addListener( new IFrequencyChangeProcessor()
|
||||
{
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event )
|
||||
{
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
broadcast( new TunerEvent( Tuner.this,
|
||||
source.tuner.TunerEvent.Event.FREQUENCY ));
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
broadcast( new TunerEvent( Tuner.this,
|
||||
source.tuner.TunerEvent.Event.SAMPLE_RATE ));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public TunerController getTunerController()
|
||||
{
|
||||
return mTunerController;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mSampleListeners.clear();
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier for this tuner, used to lookup a tuner configuration
|
||||
* from the settings manager.
|
||||
*
|
||||
* @return - unique identifier like a serial number, or a usb bus location
|
||||
* or ip address and port. Return some form of unique identification that
|
||||
* allows this tuner to be identified from among several of the same types
|
||||
* of tuners.
|
||||
*/
|
||||
public abstract String getUniqueID();
|
||||
private String mName;
|
||||
private TunerController mTunerController;
|
||||
/**
|
||||
* Sample Listeners - these will typically be the DFT processor for spectral
|
||||
* display, or it will be one or more tuner channel sources
|
||||
*/
|
||||
protected List<Listener<ComplexBuffer>> mSampleListeners = new CopyOnWriteArrayList<>();
|
||||
protected List<Listener<TunerEvent>> mTunerChangeListeners = new ArrayList<>();
|
||||
protected Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
||||
|
||||
/**
|
||||
* @return - tuner class enum entry
|
||||
*/
|
||||
public abstract TunerClass getTunerClass();
|
||||
|
||||
/**
|
||||
* @return - tuner type enum entry
|
||||
*/
|
||||
public abstract TunerType getTunerType();
|
||||
|
||||
/**
|
||||
* Name of this tuner object
|
||||
* @return - string name of this tuner object
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample size in bits
|
||||
*/
|
||||
public abstract double getSampleSize();
|
||||
|
||||
/**
|
||||
* Returns a tuner frequency channel source, tuned to the correct frequency
|
||||
*
|
||||
* Note: ensure the concrete implementation registers the returned
|
||||
* tuner channel source as a listener on the tuner, to receive frequency
|
||||
* change events.
|
||||
*
|
||||
* @param frequency - desired frequency
|
||||
*
|
||||
* @return - source for 48k sample rate
|
||||
*/
|
||||
public abstract TunerChannelSource getChannel( TunerChannel channel )
|
||||
throws RejectedExecutionException, SourceException;
|
||||
|
||||
/**
|
||||
* Releases the tuned channel resources
|
||||
*
|
||||
* Note: ensure the concrete implementation unregisters the tuner channel
|
||||
* source from the tuner as a frequency change listener
|
||||
*
|
||||
* @param channel - previously obtained tuner channel
|
||||
*/
|
||||
public abstract void releaseChannel( TunerChannelSource source );
|
||||
|
||||
/**
|
||||
* Registers the listener to receive complex float sample arrays
|
||||
*/
|
||||
public void addListener( Listener<ComplexBuffer> listener )
|
||||
public Tuner(String name, TunerController tunerController)
|
||||
{
|
||||
mSampleListeners.add( listener );
|
||||
mName = name;
|
||||
mTunerController = tunerController;
|
||||
|
||||
//Rebroadcast frequency and sample rate change events as tuner events
|
||||
mTunerController.addListener(new ISourceEventProcessor()
|
||||
{
|
||||
@Override
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
broadcast(new TunerEvent(Tuner.this,
|
||||
source.tuner.TunerEvent.Event.FREQUENCY));
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
broadcast(new TunerEvent(Tuner.this,
|
||||
source.tuner.TunerEvent.Event.SAMPLE_RATE));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeListener( Listener<ComplexBuffer> listener )
|
||||
public TunerController getTunerController()
|
||||
{
|
||||
mSampleListeners.remove( listener );
|
||||
return mTunerController;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mSampleListeners.clear();
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier for this tuner, used to lookup a tuner configuration
|
||||
* from the settings manager.
|
||||
*
|
||||
* @return - unique identifier like a serial number, or a usb bus location
|
||||
* or ip address and port. Return some form of unique identification that
|
||||
* allows this tuner to be identified from among several of the same types
|
||||
* of tuners.
|
||||
*/
|
||||
public abstract String getUniqueID();
|
||||
|
||||
/**
|
||||
* @return - tuner class enum entry
|
||||
*/
|
||||
public abstract TunerClass getTunerClass();
|
||||
|
||||
/**
|
||||
* @return - tuner type enum entry
|
||||
*/
|
||||
public abstract TunerType getTunerType();
|
||||
|
||||
/**
|
||||
* Name of this tuner object
|
||||
*
|
||||
* @return - string name of this tuner object
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample size in bits
|
||||
*/
|
||||
public abstract double getSampleSize();
|
||||
|
||||
/**
|
||||
* Returns a tuner frequency channel source, tuned to the correct frequency
|
||||
*
|
||||
* Note: ensure the concrete implementation registers the returned
|
||||
* tuner channel source as a listener on the tuner, to receive frequency
|
||||
* change events.
|
||||
*
|
||||
* @param channel - desired frequency and bandwidth
|
||||
* @return - source for 48k sample rate
|
||||
*/
|
||||
public abstract TunerChannelSource getChannel(TunerChannel channel)
|
||||
throws RejectedExecutionException, SourceException;
|
||||
|
||||
/**
|
||||
* Releases the tuned channel resources
|
||||
*
|
||||
* Note: ensure the concrete implementation unregisters the tuner channel
|
||||
* source from the tuner as a frequency change listener
|
||||
*
|
||||
* @param source - previously obtained tuner channel
|
||||
*/
|
||||
public abstract void releaseChannel(TunerChannelSource source);
|
||||
|
||||
/**
|
||||
* Registers the listener to receive complex float sample arrays
|
||||
*/
|
||||
public void addListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mSampleListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeListener(Listener<ComplexBuffer> listener)
|
||||
{
|
||||
mSampleListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the samples to all registered listeners
|
||||
*/
|
||||
public void broadcast( ComplexBuffer sampleBuffer )
|
||||
public void broadcast(ComplexBuffer sampleBuffer)
|
||||
{
|
||||
for( Listener<ComplexBuffer> listener: mSampleListeners )
|
||||
{
|
||||
listener.receive( sampleBuffer );
|
||||
}
|
||||
for(Listener<ComplexBuffer> listener : mSampleListeners)
|
||||
{
|
||||
listener.receive(sampleBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener
|
||||
*/
|
||||
public void addTunerChangeListener( Listener<TunerEvent> listener )
|
||||
/**
|
||||
* Registers the listener
|
||||
*/
|
||||
public void addTunerChangeListener(Listener<TunerEvent> listener)
|
||||
{
|
||||
mTunerChangeListeners.add( listener );
|
||||
mTunerChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeTunerChangeListener( Listener<TunerEvent> listener )
|
||||
/**
|
||||
* Removes the registered listener
|
||||
*/
|
||||
public void removeTunerChangeListener(Listener<TunerEvent> listener)
|
||||
{
|
||||
mTunerChangeListeners.remove( listener );
|
||||
mTunerChangeListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the tuner change event
|
||||
*/
|
||||
public void broadcast( TunerEvent event )
|
||||
public void broadcast(TunerEvent tunerEvent)
|
||||
{
|
||||
for( Listener<TunerEvent> listener: mTunerChangeListeners )
|
||||
{
|
||||
listener.receive( event );
|
||||
}
|
||||
for(Listener<TunerEvent> listener : mTunerChangeListeners)
|
||||
{
|
||||
listener.receive(tunerEvent);
|
||||
}
|
||||
|
||||
//Re-broadcast frequency and sample rate change events as source events
|
||||
switch(tunerEvent.getEvent())
|
||||
{
|
||||
case FREQUENCY:
|
||||
mSourceEventBroadcaster.broadcast(SourceEvent.frequencyChange(getTunerController().getFrequency()));
|
||||
break;
|
||||
case SAMPLE_RATE:
|
||||
mSourceEventBroadcaster.broadcast(SourceEvent.sampleRateChange(getTunerController().getSampleRate()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the listener to receive source events
|
||||
*/
|
||||
public void addSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mSourceEventBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving source events
|
||||
*/
|
||||
public void removeSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mSourceEventBroadcaster.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 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/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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;
|
||||
|
||||
public class TunerChannel implements Comparable<TunerChannel>
|
||||
{
|
||||
private Type mType;
|
||||
private long mFrequency;
|
||||
private int mBandwidth;
|
||||
|
||||
public TunerChannel( Type type, long frequency, int bandwidth )
|
||||
{
|
||||
mType = type;
|
||||
mFrequency = frequency;
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
public void setType( Type type )
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
private long mFrequency;
|
||||
private int mBandwidth;
|
||||
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency( long frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mBandwidth;
|
||||
}
|
||||
|
||||
public void setBandwidth( int bandwidth )
|
||||
{
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public long getMinFrequency()
|
||||
{
|
||||
return mFrequency - ( mBandwidth / 2 );
|
||||
}
|
||||
|
||||
public long getMaxFrequency()
|
||||
{
|
||||
return mFrequency + ( mBandwidth / 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this tuner channel overlaps the specified range
|
||||
*/
|
||||
public boolean overlaps( long minimum, long maximum )
|
||||
{
|
||||
long channelMin = getMinFrequency();
|
||||
long channelMax = getMaxFrequency();
|
||||
|
||||
return ( ( minimum <= channelMin && channelMin <= maximum ) ||
|
||||
( minimum <= channelMax && channelMax <= maximum ) ||
|
||||
( minimum <= channelMin && channelMax <= maximum ) ||
|
||||
( channelMin <= minimum && maximum <= channelMax ) );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "Channel: " );
|
||||
sb.append( getMinFrequency() );
|
||||
sb.append( "-" );
|
||||
sb.append( getMaxFrequency() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo( TunerChannel otherLock )
|
||||
public TunerChannel(long frequency, int bandwidth)
|
||||
{
|
||||
if( this.equals( otherLock ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if( mFrequency < otherLock.getFrequency() )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
mFrequency = frequency;
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mBandwidth;
|
||||
}
|
||||
|
||||
public void setBandwidth(int bandwidth)
|
||||
{
|
||||
mBandwidth = bandwidth;
|
||||
}
|
||||
|
||||
public long getMinFrequency()
|
||||
{
|
||||
return mFrequency - (mBandwidth / 2);
|
||||
}
|
||||
|
||||
public long getMaxFrequency()
|
||||
{
|
||||
return mFrequency + (mBandwidth / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this tuner channel overlaps the specified range
|
||||
*/
|
||||
public boolean overlaps(long minimum, long maximum)
|
||||
{
|
||||
long channelMin = getMinFrequency();
|
||||
long channelMax = getMaxFrequency();
|
||||
|
||||
return ((minimum <= channelMin && channelMin <= maximum) ||
|
||||
(minimum <= channelMax && channelMax <= maximum) ||
|
||||
(minimum <= channelMin && channelMax <= maximum) ||
|
||||
(channelMin <= minimum && maximum <= channelMax));
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("Channel: ");
|
||||
sb.append(getMinFrequency());
|
||||
sb.append("-");
|
||||
sb.append(getMaxFrequency());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TunerChannel otherLock)
|
||||
{
|
||||
return Long.compare(getFrequency(), otherLock.getFrequency());
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
LOCKED, //Use for decoding channels, so that they cannot be tuned out of range
|
||||
TRAFFIC, //Like locked, but for temporary allocated traffic channels
|
||||
TUNABLE; //Tunable -- can be tuned out of range
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,10 @@ import sample.complex.ComplexBuffer;
|
||||
import sample.real.IOverflowListener;
|
||||
import source.ComplexSource;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeListener;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import source.tuner.frequency.IFrequencyChangeProvider;
|
||||
import source.ISourceEventListener;
|
||||
import source.ISourceEventProvider;
|
||||
import source.SourceEvent;
|
||||
import source.ISourceEventProcessor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -46,7 +45,7 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class TunerChannelSource extends ComplexSource implements IFrequencyChangeProcessor, Listener<ComplexBuffer>
|
||||
public class TunerChannelSource extends ComplexSource implements ISourceEventProcessor, Listener<ComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class);
|
||||
|
||||
@@ -66,7 +65,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
private Oscillator mMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private Listener<ComplexBuffer> mListener;
|
||||
private IFrequencyChangeProcessor mFrequencyChangeProcessor;
|
||||
private ISourceEventProcessor mFrequencyChangeProcessor;
|
||||
private DownstreamProcessor mDownstreamFrequencyEventProcessor = new DownstreamProcessor();
|
||||
private ScheduledFuture<?> mTaskHandle;
|
||||
|
||||
@@ -100,7 +99,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
{
|
||||
mTuner = tuner;
|
||||
mTunerChannel = tunerChannel;
|
||||
mTuner.getTunerController().addListener((IFrequencyChangeProcessor) this);
|
||||
mTuner.getTunerController().addListener((ISourceEventProcessor) this);
|
||||
mTunerFrequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
mBuffer = new OverflowableTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD);
|
||||
@@ -111,8 +110,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
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()));
|
||||
process(SourceEvent.sampleRateChange(mTuner.getTunerController().getSampleRate()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,7 +200,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
updateMixerFrequencyOffset();
|
||||
|
||||
mDownstreamFrequencyEventProcessor.broadcast(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE, mChannelFrequencyCorrection));
|
||||
SourceEvent.channelFrequencyCorrectionChange(mChannelFrequencyCorrection));
|
||||
}
|
||||
|
||||
public Tuner getTuner()
|
||||
@@ -224,7 +222,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrequencyChangeListener(IFrequencyChangeProcessor processor)
|
||||
public void setFrequencyChangeListener(ISourceEventProcessor processor)
|
||||
{
|
||||
mFrequencyChangeProcessor = processor;
|
||||
}
|
||||
@@ -250,12 +248,12 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
* frequency correction events received from the channel consumer/listener
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event) throws SourceException
|
||||
public void process(SourceEvent event) throws SourceException
|
||||
{
|
||||
// Echo the event to the registered event listener
|
||||
if(mFrequencyChangeProcessor != null)
|
||||
{
|
||||
mFrequencyChangeProcessor.frequencyChanged(event);
|
||||
mFrequencyChangeProcessor.process(event);
|
||||
}
|
||||
|
||||
switch(event.getEvent())
|
||||
@@ -320,36 +318,36 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IFrequencyChangeProvider to enable this source to broadcast frequency change events to downstream
|
||||
* Implements ISourceEventProvider to enable this source to broadcast frequency change events to downstream
|
||||
* listeners.
|
||||
*
|
||||
* @param listener to receive downstream events
|
||||
*/
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mDownstreamFrequencyEventProcessor.setFrequencyChangeListener(listener);
|
||||
mDownstreamFrequencyEventProcessor.setSourceEventListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IFrequencyChangeProvider to remove the frequency change listener from receiving down-stream frequency
|
||||
* Implements ISourceEventProvider to remove the frequency change listener from receiving down-stream frequency
|
||||
* change events.
|
||||
*/
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mDownstreamFrequencyEventProcessor.removeFrequencyChangeListener();
|
||||
mDownstreamFrequencyEventProcessor.removeSourceEventListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IFrequencyChangeListener to receive frequency change events containing requests from downstream
|
||||
* Implements ISourceEventListener to receive frequency change events containing requests from downstream
|
||||
* listeners to change frequency values.
|
||||
* @return listener
|
||||
*/
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return mDownstreamFrequencyEventProcessor.getFrequencyChangeListener();
|
||||
return mDownstreamFrequencyEventProcessor.getSourceEventListener();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,17 +356,17 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
* notified of any frequency or sample rate change events and will also be able to request frequency correction
|
||||
* updates.
|
||||
*/
|
||||
public class DownstreamProcessor implements IFrequencyChangeListener, IFrequencyChangeProvider,
|
||||
Listener<FrequencyChangeEvent>
|
||||
public class DownstreamProcessor implements ISourceEventListener, ISourceEventProvider,
|
||||
Listener<SourceEvent>
|
||||
{
|
||||
//Listener to receive downstream events
|
||||
private Listener<FrequencyChangeEvent> mListener;
|
||||
private Listener<SourceEvent> mListener;
|
||||
|
||||
/**
|
||||
* Broadcasts the frequency change event to the downstream frequency change listener
|
||||
* @param event to broadcast
|
||||
*/
|
||||
public void broadcast(FrequencyChangeEvent event)
|
||||
public void broadcast(SourceEvent event)
|
||||
{
|
||||
if(mListener != null)
|
||||
{
|
||||
@@ -384,7 +382,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
try
|
||||
{
|
||||
long frequency = getFrequency();
|
||||
broadcast(new FrequencyChangeEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency));
|
||||
broadcast(SourceEvent.frequencyChange(frequency));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
@@ -400,7 +398,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
try
|
||||
{
|
||||
//Note: downstream sample rate is currently a fixed value -- it will change in the future
|
||||
broadcast(new FrequencyChangeEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE, getSampleRate()));
|
||||
broadcast(SourceEvent.sampleRateChange(getSampleRate()));
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
@@ -413,7 +411,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
* @param listener to receive events
|
||||
*/
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
@@ -422,7 +420,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
* Removes the downstream listener from receiving frequency change events.
|
||||
*/
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
@@ -431,7 +429,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
* Listener for receiving frequency change events from downstream components
|
||||
*/
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
@@ -441,7 +439,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
|
||||
* @param event to process
|
||||
*/
|
||||
@Override
|
||||
public void receive(FrequencyChangeEvent event)
|
||||
public void receive(SourceEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
|
||||
@@ -26,13 +26,13 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import source.SourceException;
|
||||
import source.tuner.configuration.TunerConfiguration;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.SourceEvent;
|
||||
import source.SourceEvent.Event;
|
||||
import source.tuner.frequency.FrequencyController;
|
||||
import source.tuner.frequency.FrequencyController.Tunable;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import source.ISourceEventProcessor;
|
||||
|
||||
public abstract class TunerController implements Tunable, IFrequencyChangeProcessor
|
||||
public abstract class TunerController implements Tunable, ISourceEventProcessor
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( TunerController.class );
|
||||
@@ -79,7 +79,7 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
* Responds to requests to set the frequency
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException
|
||||
public void process(SourceEvent event ) throws SourceException
|
||||
{
|
||||
if( event.getEvent() == Event.REQUEST_FREQUENCY_CHANGE )
|
||||
{
|
||||
@@ -381,7 +381,7 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
* Note: this is normally used by the Tuner. Any additional listeners can
|
||||
* be registered on the tuner.
|
||||
*/
|
||||
public void addListener( IFrequencyChangeProcessor processor )
|
||||
public void addListener( ISourceEventProcessor processor )
|
||||
{
|
||||
mFrequencyController.addListener( processor );
|
||||
}
|
||||
@@ -389,7 +389,7 @@ public abstract class TunerController implements Tunable, IFrequencyChangeProces
|
||||
/**
|
||||
* Removes the frequency change listener
|
||||
*/
|
||||
public void removeListener( IFrequencyChangeProcessor processor )
|
||||
public void removeListener( ISourceEventProcessor processor )
|
||||
{
|
||||
mFrequencyController.removeFrequencyChangeProcessor( processor );
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import gui.editor.Editor;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.config.SourceConfiguration;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.ISourceEventProcessor;
|
||||
import controller.channel.Channel;
|
||||
|
||||
public class TunerSourceEditor extends Editor<Channel>
|
||||
@@ -41,10 +41,10 @@ public class TunerSourceEditor extends Editor<Channel>
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[left]", "" ) );
|
||||
mFrequencyControl = new JFrequencyControl();
|
||||
mFrequencyControl.setEnabled( false );
|
||||
mFrequencyControl.addListener( new IFrequencyChangeProcessor()
|
||||
mFrequencyControl.addListener( new ISourceEventProcessor()
|
||||
{
|
||||
@Override
|
||||
public void frequencyChanged( FrequencyChangeEvent event )
|
||||
public void process(SourceEvent event )
|
||||
{
|
||||
setModified( true );
|
||||
}
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
package source.tuner.frequency;
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 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/>
|
||||
******************************************************************************/
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import module.Module;
|
||||
import sample.Listener;
|
||||
import sample.real.RealBuffer;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
|
||||
public class DCTrackingFrequencyControl extends Module
|
||||
implements Listener<RealBuffer>, IFrequencyChangeProvider
|
||||
{
|
||||
private static float COARSE_THRESHOLD = 0.1f;
|
||||
private static float LOOP_GAIN = 0.1f;
|
||||
private static float COARSE_GAIN = 1000.0f;
|
||||
private static float FINE_GAIN = 100.0f;
|
||||
private int mErrorCorrection = 0;
|
||||
private int mMaximumFrequencyCorrection = 0;
|
||||
private Listener<FrequencyChangeEvent> mListener;
|
||||
|
||||
/**
|
||||
* DC offset Automatic Frequency Control. Monitors DC bias present in an FM
|
||||
* demodulated audio stream and issues automatic frequency corrections to
|
||||
* maintain the DC bias close to zero.
|
||||
*
|
||||
* @param maximum - maximum allowable (+/-) frequency correction value.
|
||||
*/
|
||||
public DCTrackingFrequencyControl( int maximum )
|
||||
{
|
||||
mMaximumFrequencyCorrection = maximum;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( RealBuffer buffer )
|
||||
{
|
||||
double sum = 0.0d;
|
||||
|
||||
for( float sample: buffer.getSamples() )
|
||||
{
|
||||
sum += sample;
|
||||
}
|
||||
|
||||
float mean = (float)( sum / (double)buffer.getSamples().length );
|
||||
|
||||
float adjustment = 0.0f;
|
||||
|
||||
if( mean > COARSE_THRESHOLD || mean < - COARSE_THRESHOLD )
|
||||
{
|
||||
adjustment = mean * COARSE_GAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustment = mean * FINE_GAIN;
|
||||
}
|
||||
|
||||
setErrorCorrection( mErrorCorrection + (int)( (float)adjustment * LOOP_GAIN ) );
|
||||
}
|
||||
|
||||
private void setErrorCorrection( int correction )
|
||||
{
|
||||
if( mListener != null )
|
||||
{
|
||||
if( correction > mMaximumFrequencyCorrection )
|
||||
{
|
||||
correction = mMaximumFrequencyCorrection;
|
||||
}
|
||||
else if( correction < -mMaximumFrequencyCorrection )
|
||||
{
|
||||
correction = -mMaximumFrequencyCorrection;
|
||||
}
|
||||
|
||||
if( correction != mErrorCorrection )
|
||||
{
|
||||
mListener.receive( new FrequencyChangeEvent(
|
||||
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start( ScheduledExecutorService executor )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
setErrorCorrection( 0 );
|
||||
}
|
||||
}
|
||||
130
src/source/tuner/frequency/DCTrackingSourceControl.java
Normal file
130
src/source/tuner/frequency/DCTrackingSourceControl.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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.frequency;
|
||||
|
||||
import module.Module;
|
||||
import sample.Listener;
|
||||
import sample.real.RealBuffer;
|
||||
import source.ISourceEventProvider;
|
||||
import source.SourceEvent;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class DCTrackingSourceControl extends Module
|
||||
implements Listener<RealBuffer>, ISourceEventProvider
|
||||
{
|
||||
private static float COARSE_THRESHOLD = 0.1f;
|
||||
private static float LOOP_GAIN = 0.1f;
|
||||
private static float COARSE_GAIN = 1000.0f;
|
||||
private static float FINE_GAIN = 100.0f;
|
||||
private int mErrorCorrection = 0;
|
||||
private int mMaximumFrequencyCorrection = 0;
|
||||
private Listener<SourceEvent> mListener;
|
||||
|
||||
/**
|
||||
* DC offset Automatic Frequency Control. Monitors DC bias present in an FM
|
||||
* demodulated audio stream and issues automatic frequency corrections to
|
||||
* maintain the DC bias close to zero.
|
||||
*
|
||||
* @param maximum - maximum allowable (+/-) frequency correction value.
|
||||
*/
|
||||
public DCTrackingSourceControl(int maximum)
|
||||
{
|
||||
mMaximumFrequencyCorrection = maximum;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(RealBuffer buffer)
|
||||
{
|
||||
double sum = 0.0d;
|
||||
|
||||
for(float sample : buffer.getSamples())
|
||||
{
|
||||
sum += sample;
|
||||
}
|
||||
|
||||
float mean = (float)(sum / (double)buffer.getSamples().length);
|
||||
|
||||
float adjustment = 0.0f;
|
||||
|
||||
if(mean > COARSE_THRESHOLD || mean < -COARSE_THRESHOLD)
|
||||
{
|
||||
adjustment = mean * COARSE_GAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustment = mean * FINE_GAIN;
|
||||
}
|
||||
|
||||
setErrorCorrection(mErrorCorrection + (int)((float)adjustment * LOOP_GAIN));
|
||||
}
|
||||
|
||||
private void setErrorCorrection(int correction)
|
||||
{
|
||||
if(mListener != null)
|
||||
{
|
||||
if(correction > mMaximumFrequencyCorrection)
|
||||
{
|
||||
correction = mMaximumFrequencyCorrection;
|
||||
}
|
||||
else if(correction < -mMaximumFrequencyCorrection)
|
||||
{
|
||||
correction = -mMaximumFrequencyCorrection;
|
||||
}
|
||||
|
||||
if(correction != mErrorCorrection)
|
||||
{
|
||||
mListener.receive(SourceEvent.channelFrequencyCorrectionRequest(correction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
setErrorCorrection(0);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package source.tuner.frequency;
|
||||
|
||||
public class FrequencyChangeEvent
|
||||
{
|
||||
public enum Event
|
||||
{
|
||||
NOTIFICATION_FREQUENCY_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
|
||||
REQUEST_FREQUENCY_CHANGE,
|
||||
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE;
|
||||
}
|
||||
|
||||
private Event mEvent;
|
||||
private Number mValue;
|
||||
|
||||
public FrequencyChangeEvent( Event event, Number value )
|
||||
{
|
||||
mEvent = event;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public Event getEvent()
|
||||
{
|
||||
return mEvent;
|
||||
}
|
||||
|
||||
public Number getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package source.tuner.frequency;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import source.SourceException;
|
||||
import source.tuner.hackrf.HackRFTunerEditor;
|
||||
|
||||
public class FrequencyChangeProcessorWrapper
|
||||
implements IFrequencyChangeListener, Listener<FrequencyChangeEvent>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FrequencyChangeProcessorWrapper.class );
|
||||
|
||||
private IFrequencyChangeProcessor mProcessor;
|
||||
|
||||
/**
|
||||
* Provides IFrequencyChangeListener wrapper for an IFrequencyChangeProcessor
|
||||
*/
|
||||
public FrequencyChangeProcessorWrapper( IFrequencyChangeProcessor handler )
|
||||
{
|
||||
mProcessor = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( FrequencyChangeEvent event )
|
||||
{
|
||||
if( mProcessor != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessor.frequencyChanged( event );
|
||||
}
|
||||
catch( SourceException se )
|
||||
{
|
||||
mLog.error("Error sending frequency change event to embedded processor", se);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,257 +1,253 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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.frequency;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import source.ISourceEventProcessor;
|
||||
import source.InvalidFrequencyException;
|
||||
import source.Source;
|
||||
import source.SourceEvent;
|
||||
import source.SourceException;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class FrequencyController
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FrequencyController.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger(FrequencyController.class);
|
||||
|
||||
private Tunable mTunable;
|
||||
private long mFrequency = 101100000;
|
||||
private long mTunedFrequency = 101100000;
|
||||
private long mMinimumFrequency;
|
||||
private long mMaximumFrequency;
|
||||
private double mFrequencyCorrection = 0d;
|
||||
private int mSampleRate = 0;
|
||||
|
||||
private ArrayList<IFrequencyChangeProcessor> mProcessors = new ArrayList<>();
|
||||
|
||||
public FrequencyController( Tunable tunable,
|
||||
long minFrequency,
|
||||
long maxFrequency,
|
||||
double frequencyCorrection )
|
||||
{
|
||||
mTunable = tunable;
|
||||
mMinimumFrequency = minFrequency;
|
||||
mMaximumFrequency = maxFrequency;
|
||||
mFrequencyCorrection = frequencyCorrection;
|
||||
}
|
||||
private Tunable mTunable;
|
||||
private long mFrequency = 101100000;
|
||||
private long mTunedFrequency = 101100000;
|
||||
private long mMinimumFrequency;
|
||||
private long mMaximumFrequency;
|
||||
private double mFrequencyCorrection = 0d;
|
||||
private int mSampleRate = 0;
|
||||
|
||||
/**
|
||||
* Get bandwidth/sample rate in hertz
|
||||
*/
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
private ArrayList<ISourceEventProcessor> mProcessors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Set sample rate in hertz
|
||||
*/
|
||||
public void setSampleRate( int sampleRate ) throws SourceException
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
|
||||
broadcastSampleRateChange();
|
||||
}
|
||||
public FrequencyController(Tunable tunable, long minFrequency, long maxFrequency, double frequencyCorrection)
|
||||
{
|
||||
mTunable = tunable;
|
||||
mMinimumFrequency = minFrequency;
|
||||
mMaximumFrequency = maxFrequency;
|
||||
mFrequencyCorrection = frequencyCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get frequency in hertz
|
||||
*/
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
/**
|
||||
* Get bandwidth/sample rate in hertz
|
||||
*/
|
||||
public int getBandwidth()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency
|
||||
* @param frequency in hertz
|
||||
* @throws SourceException if tunable doesn't support tuning a corrected
|
||||
* version of the requested frequency
|
||||
*/
|
||||
public void setFrequency( long frequency ) throws SourceException
|
||||
{
|
||||
setFrequency( frequency, true );
|
||||
}
|
||||
/**
|
||||
* Set sample rate in hertz
|
||||
*/
|
||||
public void setSampleRate(int sampleRate) throws SourceException
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
|
||||
/**
|
||||
* Set frequency with optional broadcast of frequency change event. This
|
||||
* method supports changing the frequency correction value without
|
||||
* broadcasting a frequency change event.
|
||||
*/
|
||||
private void setFrequency( long frequency, boolean broadcastChange ) throws SourceException
|
||||
{
|
||||
long tunedFrequency = getTunedFrequency( frequency );
|
||||
|
||||
if( tunedFrequency < mMinimumFrequency )
|
||||
{
|
||||
throw new InvalidFrequencyException( "Requested frequency not valid", frequency, mMinimumFrequency );
|
||||
}
|
||||
broadcastSampleRateChange();
|
||||
}
|
||||
|
||||
if( tunedFrequency > mMaximumFrequency )
|
||||
{
|
||||
throw new InvalidFrequencyException( "Requested frequency not valid", frequency, mMaximumFrequency );
|
||||
}
|
||||
/**
|
||||
* Get frequency in hertz
|
||||
*/
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
mFrequency = frequency;
|
||||
/**
|
||||
* Set frequency
|
||||
*
|
||||
* @param frequency in hertz
|
||||
* @throws SourceException if tunable doesn't support tuning a corrected
|
||||
* version of the requested frequency
|
||||
*/
|
||||
public void setFrequency(long frequency) throws SourceException
|
||||
{
|
||||
setFrequency(frequency, true);
|
||||
}
|
||||
|
||||
mTunedFrequency = tunedFrequency;
|
||||
/**
|
||||
* Set frequency with optional broadcast of frequency change event. This
|
||||
* method supports changing the frequency correction value without
|
||||
* broadcasting a frequency change event.
|
||||
*/
|
||||
private void setFrequency(long frequency, boolean broadcastChange) throws SourceException
|
||||
{
|
||||
long tunedFrequency = getTunedFrequency(frequency);
|
||||
|
||||
if( mTunable != null )
|
||||
{
|
||||
mTunable.setTunedFrequency( mTunedFrequency );
|
||||
}
|
||||
if(tunedFrequency < mMinimumFrequency)
|
||||
{
|
||||
throw new InvalidFrequencyException("Requested frequency not valid", frequency, mMinimumFrequency);
|
||||
}
|
||||
|
||||
if(tunedFrequency > mMaximumFrequency)
|
||||
{
|
||||
throw new InvalidFrequencyException("Requested frequency not valid", frequency, mMaximumFrequency);
|
||||
}
|
||||
|
||||
mFrequency = frequency;
|
||||
|
||||
mTunedFrequency = tunedFrequency;
|
||||
|
||||
if(mTunable != null)
|
||||
{
|
||||
mTunable.setTunedFrequency(mTunedFrequency);
|
||||
}
|
||||
|
||||
/* Broadcast to all listeners that the frequency has changed */
|
||||
if( broadcastChange )
|
||||
{
|
||||
broadcastFrequencyChange();
|
||||
}
|
||||
}
|
||||
|
||||
public long getTunedFrequency()
|
||||
{
|
||||
return mTunedFrequency;
|
||||
}
|
||||
|
||||
public long getMinimumFrequency()
|
||||
{
|
||||
return mMinimumFrequency;
|
||||
}
|
||||
|
||||
public long getMaximumFrequency()
|
||||
{
|
||||
return mMaximumFrequency;
|
||||
}
|
||||
|
||||
if(broadcastChange)
|
||||
{
|
||||
broadcastFrequencyChange();
|
||||
}
|
||||
}
|
||||
|
||||
public long getTunedFrequency()
|
||||
{
|
||||
return mTunedFrequency;
|
||||
}
|
||||
|
||||
public long getMinimumFrequency()
|
||||
{
|
||||
return mMinimumFrequency;
|
||||
}
|
||||
|
||||
public long getMaximumFrequency()
|
||||
{
|
||||
return mMaximumFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the tuned frequency by adding frequency correction to the
|
||||
* corrected frequency.
|
||||
*
|
||||
* @param correctedFrequency
|
||||
*/
|
||||
private long getTunedFrequency( long correctedFrequency )
|
||||
private long getTunedFrequency(long correctedFrequency)
|
||||
{
|
||||
return (long)( (double)correctedFrequency /
|
||||
( 1.0 + ( mFrequencyCorrection / 1000000.0 ) ) );
|
||||
return (long)((double)correctedFrequency /
|
||||
(1.0 + (mFrequencyCorrection / 1000000.0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the corrected frequency by subtracting frequency correction
|
||||
* Calculate the corrected frequency by subtracting frequency correction
|
||||
* from the tuned frequency.
|
||||
*
|
||||
* @param tunedFrequency
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private long getCorrectedFrequency( long tunedFrequency )
|
||||
private long getCorrectedFrequency(long tunedFrequency)
|
||||
{
|
||||
return (long)( (double)tunedFrequency /
|
||||
( 1.0 - ( mFrequencyCorrection / 1000000.0 ) ) );
|
||||
return (long)((double)tunedFrequency /
|
||||
(1.0 - (mFrequencyCorrection / 1000000.0)));
|
||||
}
|
||||
|
||||
|
||||
public double getFrequencyCorrection()
|
||||
{
|
||||
return mFrequencyCorrection;
|
||||
return mFrequencyCorrection;
|
||||
}
|
||||
|
||||
public void setFrequencyCorrection( double correction ) throws SourceException
|
||||
|
||||
public void setFrequencyCorrection(double correction) throws SourceException
|
||||
{
|
||||
mFrequencyCorrection = correction;
|
||||
mFrequencyCorrection = correction;
|
||||
|
||||
if( mFrequency > 0 )
|
||||
{
|
||||
setFrequency( mFrequency, true );
|
||||
}
|
||||
if(mFrequency > 0)
|
||||
{
|
||||
setFrequency(mFrequency, true);
|
||||
}
|
||||
|
||||
broadcastFrequencyErrorChange();
|
||||
broadcastFrequencyCorrectionChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds listener to receive frequency change events
|
||||
*/
|
||||
//TODO: rename this to addFrequencyChangeProcessor()
|
||||
public void addListener( IFrequencyChangeProcessor processor )
|
||||
{
|
||||
if( !mProcessors.contains( processor ) )
|
||||
{
|
||||
mProcessors.add( processor );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes listener from receiving frequency change events
|
||||
*/
|
||||
public void removeFrequencyChangeProcessor( IFrequencyChangeProcessor processor )
|
||||
{
|
||||
mProcessors.remove( processor );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts a change/update to the current (uncorrected) frequency or the
|
||||
* Adds listener to receive frequency change events
|
||||
*/
|
||||
public void addListener(ISourceEventProcessor processor)
|
||||
{
|
||||
if(!mProcessors.contains(processor))
|
||||
{
|
||||
mProcessors.add(processor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes listener from receiving frequency change events
|
||||
*/
|
||||
public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
|
||||
{
|
||||
mProcessors.remove(processor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts a change/update to the current (uncorrected) frequency or the
|
||||
* bandwidth/sample rate value.
|
||||
*/
|
||||
protected void broadcastFrequencyChange() throws SourceException
|
||||
{
|
||||
broadcastFrequencyChangeEvent(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CHANGE, mFrequency ) );
|
||||
broadcast(SourceEvent.frequencyChange(mFrequency));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Broadcast a frequency error/correction value change
|
||||
*/
|
||||
protected void broadcastFrequencyErrorChange() throws SourceException
|
||||
protected void broadcastFrequencyCorrectionChange() throws SourceException
|
||||
{
|
||||
broadcastFrequencyChangeEvent(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_FREQUENCY_CORRECTION_CHANGE, mFrequencyCorrection ) );
|
||||
broadcast(SourceEvent.frequencyCorrectionChange((int)mFrequencyCorrection));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts a sample rate change
|
||||
*/
|
||||
protected void broadcastSampleRateChange() throws SourceException
|
||||
{
|
||||
broadcastFrequencyChangeEvent(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_SAMPLE_RATE_CHANGE, mSampleRate ) );
|
||||
broadcast(SourceEvent.sampleRateChange(mSampleRate));
|
||||
}
|
||||
|
||||
public void broadcastFrequencyChangeEvent( FrequencyChangeEvent event ) throws SourceException
|
||||
|
||||
public void broadcast(SourceEvent event) throws SourceException
|
||||
{
|
||||
for( IFrequencyChangeProcessor processor: mProcessors )
|
||||
{
|
||||
processor.frequencyChanged( event );
|
||||
}
|
||||
for(ISourceEventProcessor processor : mProcessors)
|
||||
{
|
||||
processor.process(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface Tunable
|
||||
{
|
||||
/**
|
||||
* Gets the tuned frequency of the device
|
||||
*/
|
||||
public long getTunedFrequency() throws SourceException;
|
||||
|
||||
/**
|
||||
* Sets the tuned frequency of the device
|
||||
*/
|
||||
public void setTunedFrequency( long frequency ) throws SourceException;
|
||||
|
||||
/**
|
||||
* Gets the current bandwidth setting of the device
|
||||
*/
|
||||
public int getCurrentSampleRate() throws SourceException;
|
||||
}
|
||||
public interface Tunable
|
||||
{
|
||||
/**
|
||||
* Gets the tuned frequency of the device
|
||||
*/
|
||||
public long getTunedFrequency() throws SourceException;
|
||||
|
||||
/**
|
||||
* Sets the tuned frequency of the device
|
||||
*/
|
||||
public void setTunedFrequency(long frequency) throws SourceException;
|
||||
|
||||
/**
|
||||
* Gets the current bandwidth setting of the device
|
||||
*/
|
||||
public int getCurrentSampleRate() throws SourceException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +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 <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package source.tuner.frequency;
|
||||
|
||||
import sample.Listener;
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the device that implements the tuning of the frequency.
|
||||
*/
|
||||
public interface IFrequencyChangeListener
|
||||
{
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener();
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package source.tuner.frequency;
|
||||
|
||||
import source.SourceException;
|
||||
|
||||
public interface IFrequencyChangeProcessor
|
||||
{
|
||||
public void frequencyChanged( FrequencyChangeEvent event ) throws SourceException;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import sample.complex.ComplexBuffer;
|
||||
import source.ComplexSource;
|
||||
import source.IControllableFileSource;
|
||||
import source.IFrameLocationListener;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.SourceEvent;
|
||||
|
||||
public class ComplexWaveSource extends ComplexSource implements IControllableFileSource
|
||||
{
|
||||
@@ -58,19 +58,19 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
|
||||
@@ -36,7 +36,7 @@ import sample.real.RealBuffer;
|
||||
import source.IControllableFileSource;
|
||||
import source.IFrameLocationListener;
|
||||
import source.RealSource;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.SourceEvent;
|
||||
|
||||
public class RealWaveSource extends RealSource
|
||||
implements IControllableFileSource, AutoCloseable
|
||||
@@ -58,19 +58,19 @@ public class RealWaveSource extends RealSource
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFrequencyChangeListener()
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
|
||||
public Listener<SourceEvent> getSourceEventListener()
|
||||
{
|
||||
//Not implemented
|
||||
return null;
|
||||
|
||||
@@ -26,8 +26,8 @@ import settings.ColorSettingMenuItem;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import settings.SettingsManager;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.SourceEvent;
|
||||
import source.SourceEvent.Event;
|
||||
import spectrum.converter.DFTResultsConverter;
|
||||
import spectrum.converter.RealDecibelConverter;
|
||||
import spectrum.menu.AveragingItem;
|
||||
@@ -90,8 +90,7 @@ public class ChannelSpectrumPanel extends JPanel
|
||||
mDFTConverter.addListener( mSpectrumPanel );
|
||||
|
||||
/* Set the DFTProcessor to the decimated 24kHz sample rate */
|
||||
mDFTProcessor.frequencyChanged(
|
||||
new FrequencyChangeEvent( Event.NOTIFICATION_SAMPLE_RATE_CHANGE, 24000 ) );
|
||||
mDFTProcessor.process(SourceEvent.sampleRateChange(24000));
|
||||
|
||||
initGui();
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import sample.Buffer;
|
||||
import sample.Listener;
|
||||
import sample.SampleType;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.ISourceEventProcessor;
|
||||
import spectrum.converter.DFTResultsConverter;
|
||||
import util.ThreadPool;
|
||||
|
||||
@@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* Processes both complex samples or float samples and dispatches a float array
|
||||
* of DFT results, using configurable fft size and output dispatch timelines.
|
||||
*/
|
||||
public class DFTProcessor implements Listener<ComplexBuffer>, IFrequencyChangeProcessor, IDFTWidthChangeProcessor
|
||||
public class DFTProcessor implements Listener<ComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(DFTProcessor.class);
|
||||
|
||||
@@ -452,7 +452,7 @@ public class DFTProcessor implements Listener<ComplexBuffer>, IFrequencyChangePr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event)
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
|
||||
@@ -31,8 +31,8 @@ import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import settings.SettingsManager;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.ISourceEventProcessor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -44,7 +44,7 @@ import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequencyChangeProcessor,
|
||||
public class OverlayPanel extends JPanel implements ChannelEventListener, ISourceEventProcessor,
|
||||
SettingChangeListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -635,7 +635,7 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ
|
||||
* Frequency change event handler
|
||||
*/
|
||||
@Override
|
||||
public void frequencyChanged(FrequencyChangeEvent event)
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
|
||||
@@ -36,10 +36,9 @@ import sample.complex.ComplexBuffer;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.ColorSettingMenuItem;
|
||||
import settings.SettingsManager;
|
||||
import source.ISourceEventProcessor;
|
||||
import source.SourceEvent;
|
||||
import source.tuner.Tuner;
|
||||
import source.tuner.frequency.FrequencyChangeEvent;
|
||||
import source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import spectrum.OverlayPanel.ChannelDisplay;
|
||||
import spectrum.converter.ComplexDecibelConverter;
|
||||
import spectrum.converter.DFTResultsConverter;
|
||||
@@ -65,7 +64,7 @@ import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuffer>, IFrequencyChangeProcessor, IDFTWidthChangeProcessor
|
||||
public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -223,7 +222,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
*
|
||||
* @param zoom level, 0 - 6.
|
||||
* @param frequency under the mouse to maintain while zooming
|
||||
* @param xAxisOffset where to maintain the frequency under the mouse
|
||||
* @param windowOffset where to maintain the frequency under the mouse
|
||||
*/
|
||||
public void setZoom(int zoom, long frequency, double windowOffset)
|
||||
{
|
||||
@@ -247,7 +246,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
//Calculate the bin offset into the newly sized zoom window that
|
||||
//would place the frequency in the same proportional window location
|
||||
//that it was in the previous zoom size
|
||||
double windowBinOffset = (double) getZoomWindowSizeInBins() * windowOffset;
|
||||
double windowBinOffset = (double)getZoomWindowSizeInBins() * windowOffset;
|
||||
|
||||
//Set the overall offset to place the reference frequency in the
|
||||
//same location in the newly zoomed window
|
||||
@@ -276,7 +275,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
offset = mDFTSize.getSize() - getZoomWindowSizeInBins();
|
||||
}
|
||||
|
||||
mDFTZoomWindowOffset = (int) offset;
|
||||
mDFTZoomWindowOffset = (int)offset;
|
||||
|
||||
mSpectrumPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
|
||||
mOverlayPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
|
||||
@@ -294,7 +293,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
|
||||
public int getZoomMultiplier()
|
||||
{
|
||||
return (int) Math.pow(2.0, mZoom);
|
||||
return (int)Math.pow(2.0, mZoom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,9 +309,9 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
|
||||
if(mOverlayPanel.containsFrequency(frequency))
|
||||
{
|
||||
offset = (double) mDFTSize.getSize() *
|
||||
((double) (frequency - mOverlayPanel.getMinFrequency()) /
|
||||
(double) mOverlayPanel.getBandwidth());
|
||||
offset = (double)mDFTSize.getSize() *
|
||||
((double)(frequency - mOverlayPanel.getMinFrequency()) /
|
||||
(double)mOverlayPanel.getBandwidth());
|
||||
}
|
||||
|
||||
return offset;
|
||||
@@ -361,11 +360,11 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
double totalHeight = mLayeredPanel.getPreferredSize().getHeight() +
|
||||
mWaterfallPanel.getPreferredSize().getHeight();
|
||||
|
||||
mLayeredPanel.setPreferredSize(new Dimension((int) mLayeredPanel
|
||||
.getPreferredSize().getWidth(), (int) (totalHeight / 2.0d)));
|
||||
mLayeredPanel.setPreferredSize(new Dimension((int)mLayeredPanel
|
||||
.getPreferredSize().getWidth(), (int)(totalHeight / 2.0d)));
|
||||
|
||||
mWaterfallPanel.setPreferredSize(new Dimension((int) mWaterfallPanel
|
||||
.getPreferredSize().getWidth(), (int) (totalHeight / 2.0d)));
|
||||
mWaterfallPanel.setPreferredSize(new Dimension((int)mWaterfallPanel
|
||||
.getPreferredSize().getWidth(), (int)(totalHeight / 2.0d)));
|
||||
|
||||
//Create the split pane to hold the layered pane and the waterfall
|
||||
JideSplitPane splitPane = new JideSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
@@ -385,17 +384,17 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
mDFTConverter = new ComplexDecibelConverter();
|
||||
mDFTProcessor.addConverter(mDFTConverter);
|
||||
|
||||
mDFTConverter.addListener((DFTResultsListener) mSpectrumPanel);
|
||||
mDFTConverter.addListener((DFTResultsListener) mWaterfallPanel);
|
||||
mDFTConverter.addListener((DFTResultsListener)mSpectrumPanel);
|
||||
mDFTConverter.addListener((DFTResultsListener)mWaterfallPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives frequency change events -- primarily from tuner components.
|
||||
*/
|
||||
public void frequencyChanged(FrequencyChangeEvent event)
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
mOverlayPanel.frequencyChanged(event);
|
||||
mDFTProcessor.frequencyChanged(event);
|
||||
mOverlayPanel.process(event);
|
||||
mDFTProcessor.process(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -425,19 +424,15 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
mTuner.getTunerController().addListener(this);
|
||||
|
||||
//Register the dft processor to receive samples from the tuner
|
||||
mTuner.addListener((Listener<ComplexBuffer>) mDFTProcessor);
|
||||
mTuner.addListener((Listener<ComplexBuffer>)mDFTProcessor);
|
||||
|
||||
mSpectrumPanel.setSampleSize(mTuner.getSampleSize());
|
||||
|
||||
//Fire frequency and sample rate change events so that the spectrum
|
||||
//and overlay panels can synchronize
|
||||
frequencyChanged(new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_FREQUENCY_CHANGE,
|
||||
mTuner.getTunerController().getFrequency()));
|
||||
process(SourceEvent.frequencyChange(mTuner.getTunerController().getFrequency()));
|
||||
|
||||
frequencyChanged(new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate()));
|
||||
process(SourceEvent.sampleRateChange(mTuner.getTunerController().getSampleRate()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +447,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
mTuner.getTunerController().removeListener(this);
|
||||
|
||||
//Deregister the dft processor from receiving samples
|
||||
mTuner.removeListener((Listener<ComplexBuffer>) mDFTProcessor);
|
||||
mTuner.removeListener((Listener<ComplexBuffer>)mDFTProcessor);
|
||||
mTuner = null;
|
||||
}
|
||||
}
|
||||
@@ -508,7 +503,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
|
||||
long frequency = mOverlayPanel.getFrequencyFromAxis(e.getX());
|
||||
|
||||
double windowOffset = (double) e.getX() / (double) getWidth();
|
||||
double windowOffset = (double)e.getX() / (double)getWidth();
|
||||
|
||||
setZoom(zoom, frequency, windowOffset);
|
||||
}
|
||||
@@ -526,9 +521,9 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
|
||||
int dragDistance = mDragStartX - event.getX();
|
||||
|
||||
double binDistance = (double) dragDistance / mPixelsPerBin;
|
||||
double binDistance = (double)dragDistance / mPixelsPerBin;
|
||||
|
||||
int offset = (int) (mDFTZoomWindowOffsetAtDragStart + binDistance);
|
||||
int offset = (int)(mDFTZoomWindowOffsetAtDragStart + binDistance);
|
||||
|
||||
if(offset < 0)
|
||||
{
|
||||
@@ -552,9 +547,9 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
|
||||
mDFTZoomWindowOffsetAtDragStart = mDFTZoomWindowOffset;
|
||||
|
||||
mPixelsPerBin = (double) getWidth() /
|
||||
((double) (mDFTSize.getSize()) /
|
||||
(double) getZoomMultiplier());
|
||||
mPixelsPerBin = (double)getWidth() /
|
||||
((double)(mDFTSize.getSize()) /
|
||||
(double)getZoomMultiplier());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -774,11 +769,11 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
}
|
||||
|
||||
/*
|
||||
* Zoom menu
|
||||
* Zoom menu
|
||||
*/
|
||||
JMenuItem zoomMenu = new JMenu("Zoom");
|
||||
|
||||
double windowOffset = (double) event.getX() / (double) getWidth();
|
||||
double windowOffset = (double)event.getX() / (double)getWidth();
|
||||
|
||||
zoomMenu.add(new ZoomItem(frequency, windowOffset));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user