mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 00:27:26 -05:00
#39 WIP - rolls back embedding source events in buffers. The channel
calculator must be updated immediately any time the tuner's center frequency changes so that a channel can be allocated immediately. So, I changed source event handling to two parts where the channel calculator is immediately updated and the channelizer configuration is deferred so that it can happen on the buffer processor execution thread and we can avoid any sync() locking on the channelizer or polyphase channel sources.
This commit is contained in:
@@ -1,171 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 io.github.dsheirer.dsp.filter.channelizer;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter;
|
||||
import io.github.dsheirer.dsp.mixer.Oscillator;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import org.jtransforms.fft.FloatFFT_1D;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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 float[] mFilteredSamples;
|
||||
private FloatFFT_1D mFFT;
|
||||
|
||||
/**
|
||||
* Maximally Decimated Polyphase Filter Bank (MDPFB) channelizer that divides the input frequency band into
|
||||
* equal bandwidth channels.
|
||||
*
|
||||
* @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
|
||||
* 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 channelCount - number of channels to output.
|
||||
* @param channelSampleRate - channel sample rate (after decimation)
|
||||
*/
|
||||
public ComplexPolyphaseChannelizer(float[] coefficients, int channelCount, int channelSampleRate)
|
||||
{
|
||||
super(channelCount, channelSampleRate);
|
||||
|
||||
initFilters(coefficients);
|
||||
}
|
||||
|
||||
@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]);
|
||||
}
|
||||
}
|
||||
|
||||
protected void filter(float inphase, float quadrature)
|
||||
{
|
||||
int index = (getChannelCount() - mFilterPointer - 1) * 2;
|
||||
|
||||
mFilteredSamples[index] = mInphaseFilters[mFilterPointer].filter(inphase);
|
||||
mFilteredSamples[index + 1] = mQuadratureFilters[mFilterPointer].filter(quadrature);
|
||||
|
||||
if(mFilterPointer == 0)
|
||||
{
|
||||
calculate();
|
||||
mFilterPointer = getChannelCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFilterPointer--;
|
||||
}
|
||||
}
|
||||
|
||||
private void calculate()
|
||||
{
|
||||
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
|
||||
mFFT.complexForward(samples);
|
||||
|
||||
dispatch(samples);
|
||||
}
|
||||
|
||||
/**
|
||||
* Distributes the filter taps to each of the polyphase filters
|
||||
*
|
||||
* @param taps
|
||||
*/
|
||||
private void initFilters(float[] taps)
|
||||
{
|
||||
int tapCount = (int)Math.ceil((double)taps.length / (double)getChannelCount());
|
||||
|
||||
float[][] coefficients = new float[getChannelCount()][tapCount];
|
||||
|
||||
for(int tap = 0; tap < tapCount; tap++)
|
||||
{
|
||||
for(int filter = 0; filter < getChannelCount(); filter++)
|
||||
{
|
||||
int index = tap * getChannelCount() + filter;
|
||||
|
||||
if(index < taps.length)
|
||||
{
|
||||
coefficients[filter][tap] = taps[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInphaseFilters = new RealFIRFilter[getChannelCount()];
|
||||
mQuadratureFilters = new RealFIRFilter[getChannelCount()];
|
||||
|
||||
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[getChannelCount() * 2];
|
||||
mFFT = new FloatFFT_1D(getChannelCount());
|
||||
mFilterPointer = getChannelCount() -1;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
mLog.debug("Starting ...");
|
||||
|
||||
int symbolRate = 4800;
|
||||
int samplesPerSymbol = 2;
|
||||
int channels = 800;
|
||||
int channelBandwidth = 12500;
|
||||
int sampleRate = channels * channelBandwidth;
|
||||
|
||||
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 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, channelBandwidth);
|
||||
|
||||
Oscillator oscillator = new Oscillator(channelCenter, 2 * sampleRate);
|
||||
|
||||
for(int x = 0; x < 2000; x++)
|
||||
{
|
||||
channelizer.filter(oscillator.getComplex().inphase(), oscillator.getComplex().quadrature());
|
||||
oscillator.rotate();
|
||||
}
|
||||
|
||||
mLog.debug("Finished!");
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.IComplexBufferProvider;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
@@ -32,11 +33,13 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class PolyphaseChannelManager
|
||||
public class PolyphaseChannelManager implements ISourceEventProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelManager.class);
|
||||
private static final double MINIMUM_CHANNEL_BANDWIDTH = 12500.0;
|
||||
@@ -224,6 +227,40 @@ public class PolyphaseChannelManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process source events received from the source (ie tuner controller) for frequency and sample rate change
|
||||
* notifications.
|
||||
* @param sourceEvent to process
|
||||
* @throws SourceException
|
||||
*/
|
||||
@Override
|
||||
public void process(SourceEvent sourceEvent) throws SourceException
|
||||
{
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
//Update channel calculator immediately so that channels can be allocated
|
||||
mLog.debug("Updating channel calculator to frequency: " + sourceEvent.getValue());
|
||||
mChannelCalculator.setCenterFrequency(sourceEvent.getValue().longValue());
|
||||
|
||||
//Defer channelizer configuration changes to be handled on the buffer processor thread
|
||||
mBufferSourceEventMonitor.receive(sourceEvent);
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
//Update channel calculator immediately so that channels can be allocated
|
||||
mLog.debug("Updating channel calculator to sample rate: " + sourceEvent.getValue());
|
||||
mChannelCalculator.setSampleRate(sourceEvent.getValue().doubleValue());
|
||||
|
||||
//Defer channelizer configuration changes to be handled on the buffer processor thread
|
||||
mBufferSourceEventMonitor.receive(sourceEvent);
|
||||
break;
|
||||
default:
|
||||
mLog.info("Unrecognized source event: " + sourceEvent.toString());
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or updates the channelizer to process the incoming sample rate and updates any channel processors.
|
||||
*
|
||||
@@ -235,10 +272,9 @@ public class PolyphaseChannelManager
|
||||
*/
|
||||
private void updateChannelizerSampleRate(double sampleRate)
|
||||
{
|
||||
if(mPolyphaseChannelizer == null || Math.abs(mPolyphaseChannelizer.getSampleRate() - sampleRate) > 1.0)
|
||||
if(mPolyphaseChannelizer == null || Math.abs(mPolyphaseChannelizer.getSampleRate() - sampleRate) > 0.5)
|
||||
{
|
||||
mLog.debug("Creating or Updating Channelizer for sample rate " + sampleRate);
|
||||
mChannelCalculator.setSampleRate(sampleRate);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -271,21 +307,12 @@ public class PolyphaseChannelManager
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChannelizerCenterFrequency(long frequency)
|
||||
{
|
||||
mChannelCalculator.setCenterFrequency(frequency);
|
||||
|
||||
mLog.debug("Updating output processors - center frequency is now: " + frequency);
|
||||
|
||||
updateOutputProcessors(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates each of the output processors for any changes in the tuner's center frequency or sample rate, which
|
||||
* would cause the output processors to change the polyphase channelizer results channel(s) that the processor is
|
||||
* consuming
|
||||
*
|
||||
* @param sourceEvent that requires an update to the output processors
|
||||
* @param sourceEvent (optional-can be null) to broadcast to each output processor following the update
|
||||
*/
|
||||
private void updateOutputProcessors(SourceEvent sourceEvent)
|
||||
{
|
||||
@@ -293,13 +320,11 @@ public class PolyphaseChannelManager
|
||||
{
|
||||
updateOutputProcessor(channelSource);
|
||||
|
||||
//Notify the channel source that the frequency or sample rate has changed so that it can reset
|
||||
//any frequency correction value.
|
||||
//Send the non-null source event to each channel source
|
||||
if(sourceEvent != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//TODO: this notification event should go to the channelizer to be embedded in the channel buffer stream
|
||||
channelSource.process(sourceEvent);
|
||||
}
|
||||
catch(SourceException se)
|
||||
@@ -429,17 +454,44 @@ public class PolyphaseChannelManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the incoming buffer stream from the provider to detect frequency and sample rate change source events
|
||||
* and update the channelizer configuration as necessary.
|
||||
* Processes the incoming buffer stream from the provider and transfers the buffers to the polyphase channelizer.
|
||||
*
|
||||
* This monitor incorporates a queue for receiving source events that affect configuration of the channelizer so
|
||||
* that they can be processed on the buffer processor calling thread, avoiding unnecessary locks on the channelizer
|
||||
* and/or the channel sources and output processors.
|
||||
*/
|
||||
public class BufferSourceEventMonitor implements Listener<ComplexBuffer>
|
||||
{
|
||||
private Queue<SourceEvent> mQueuedSourceEvents = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/**
|
||||
* Queues the source event for deferred execution on the buffer processing thread.
|
||||
* @param event that affects configuration of the channelizer (frequency or sample rate change events)
|
||||
*/
|
||||
public void receive(SourceEvent event)
|
||||
{
|
||||
mQueuedSourceEvents.offer(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ComplexBuffer complexBuffer)
|
||||
{
|
||||
if(complexBuffer.hasSourceEvent())
|
||||
//Process any queued source events before processing the buffer
|
||||
SourceEvent queuedSourceEvent = mQueuedSourceEvents.poll();
|
||||
|
||||
while(queuedSourceEvent != null)
|
||||
{
|
||||
process(complexBuffer.getSourceEvent());
|
||||
switch(queuedSourceEvent.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
updateOutputProcessors(queuedSourceEvent);
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
updateChannelizerSampleRate(queuedSourceEvent.getValue().intValue());
|
||||
break;
|
||||
}
|
||||
|
||||
queuedSourceEvent = mQueuedSourceEvents.poll();
|
||||
}
|
||||
|
||||
if(mPolyphaseChannelizer != null)
|
||||
@@ -447,29 +499,5 @@ public class PolyphaseChannelManager
|
||||
mPolyphaseChannelizer.receive(complexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes frequency and sample rate change events that are embedded in the complex buffer stream from the
|
||||
* tuner or sample source
|
||||
*/
|
||||
public void process(SourceEvent sourceEvent)
|
||||
{
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
//Update the index calculator and each of the output processors to update each channel frequency
|
||||
mChannelCalculator.setCenterFrequency(sourceEvent.getValue().longValue());
|
||||
mLog.debug("Updating output processors - center frequency is now: " + sourceEvent.getValue().longValue());
|
||||
updateOutputProcessors(sourceEvent);
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
//Update the channelizer (and the output processors) for the new sample rate
|
||||
updateChannelizerSampleRate(sourceEvent.getValue().intValue());
|
||||
break;
|
||||
default:
|
||||
mLog.info("Received an unrecognized source event: " + sourceEvent.getEvent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,25 +15,9 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.sample;
|
||||
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
public class Buffer
|
||||
{
|
||||
private float[] mSamples;
|
||||
private SourceEvent mSourceEvent;
|
||||
|
||||
/**
|
||||
* Buffer containing float sample data and a source event that should be processed prior to processing the
|
||||
* sample data.
|
||||
*
|
||||
* @param samples data
|
||||
* @param sourceEvent indicating a change to the sample data that should be processed first
|
||||
*/
|
||||
public Buffer(float[] samples, SourceEvent sourceEvent)
|
||||
{
|
||||
mSamples = samples;
|
||||
mSourceEvent = sourceEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer containing float sample data
|
||||
@@ -52,32 +36,11 @@ public class Buffer
|
||||
return mSamples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional source event that should be processed before processing the included samples. Use the hasSourceEvent()
|
||||
* method to check for the existence of an event before accessing.
|
||||
*
|
||||
* @return optional source event or null
|
||||
*/
|
||||
public SourceEvent getSourceEvent()
|
||||
{
|
||||
return mSourceEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this buffer contains an optional source event that should be processed prior to processing the
|
||||
* included float samples array.
|
||||
*/
|
||||
public boolean hasSourceEvent()
|
||||
{
|
||||
return mSourceEvent != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup method to nullify all data and references
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
mSamples = null;
|
||||
mSourceEvent = null;
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,12 @@
|
||||
package io.github.dsheirer.sample.complex;
|
||||
|
||||
import io.github.dsheirer.sample.Buffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
public class ComplexBuffer extends Buffer
|
||||
{
|
||||
//Default timestamp - we use a static variable here so that there is only ever 1 instance in memory
|
||||
private static final long DEFAULT_TIMESTAMP = 0;
|
||||
|
||||
/**
|
||||
* Wrapper around float array containing interleaved I/Q samples and an optional source event that should be
|
||||
* processed prior to processing the sample data.
|
||||
*/
|
||||
public ComplexBuffer(float[] samples, SourceEvent sourceEvent)
|
||||
{
|
||||
super(samples, sourceEvent);
|
||||
}
|
||||
/**
|
||||
* Wrapper around float array containing interleaved I/Q samples
|
||||
*/
|
||||
|
||||
@@ -15,26 +15,10 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.sample.complex;
|
||||
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
public class TimestampedComplexBuffer extends ComplexBuffer
|
||||
{
|
||||
private long mTimestamp;
|
||||
|
||||
/**
|
||||
* Constructs a timestamped complex buffer using the specified time in milliseconds. Also includes a source event
|
||||
* that should be processed prior to processing the sample data.
|
||||
*
|
||||
* @param samples of data
|
||||
* @param sourceEvent - optional source event to embed with this buffer
|
||||
* @param timestamp relative to the first sample in the sample array
|
||||
*/
|
||||
public TimestampedComplexBuffer(float[] samples, SourceEvent sourceEvent, long timestamp)
|
||||
{
|
||||
super(samples, sourceEvent);
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a timestamped complex buffer using the specified time in milliseconds.
|
||||
*
|
||||
@@ -42,18 +26,9 @@ public class TimestampedComplexBuffer extends ComplexBuffer
|
||||
*/
|
||||
public TimestampedComplexBuffer(float[] samples, long timestamp)
|
||||
{
|
||||
this(samples, null, timestamp);
|
||||
}
|
||||
super(samples);
|
||||
|
||||
/**
|
||||
* Constructs a timestamped complex buffer using the current system time in milliseconds. Also includes a source
|
||||
* event that should be processed prior to processing the sample data.
|
||||
*
|
||||
* @param samples of data
|
||||
*/
|
||||
public TimestampedComplexBuffer(float[] samples, SourceEvent sourceEvent)
|
||||
{
|
||||
this(samples, sourceEvent, System.currentTimeMillis());
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +38,7 @@ public class TimestampedComplexBuffer extends ComplexBuffer
|
||||
*/
|
||||
public TimestampedComplexBuffer(float[] samples)
|
||||
{
|
||||
this(samples, null, System.currentTimeMillis());
|
||||
this(samples, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,21 +16,11 @@
|
||||
package io.github.dsheirer.sample.real;
|
||||
|
||||
import io.github.dsheirer.sample.Buffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RealBuffer extends Buffer
|
||||
{
|
||||
/**
|
||||
* Wrapper around float array containing real float samples and an optional source event that should be processed
|
||||
* prior to processing the sample array data.
|
||||
*/
|
||||
public RealBuffer(float[] samples, SourceEvent sourceEvent)
|
||||
{
|
||||
super(samples, sourceEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around float array containing real float samples
|
||||
*/
|
||||
@@ -46,6 +36,6 @@ public class RealBuffer extends Buffer
|
||||
{
|
||||
float[] copy = Arrays.copyOf(getSamples(), getSamples().length);
|
||||
|
||||
return new RealBuffer(copy, getSourceEvent());
|
||||
return new RealBuffer(copy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public class TunerSourceManager extends AbstractSourceManager
|
||||
mPolyphaseChannelManager = new PolyphaseChannelManager(tunerController);
|
||||
//Register to receive channel count change notifications for rebroadcasting
|
||||
mPolyphaseChannelManager.addSourceEventListener(this::process);
|
||||
mTunerController.addListener(mPolyphaseChannelManager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,7 +428,7 @@ public class TunerSourceManager extends AbstractSourceManager
|
||||
broadcast(sourceEvent);
|
||||
break;
|
||||
default:
|
||||
mLog.info("Received an unrecognized source event: " + sourceEvent);
|
||||
mLog.info("Unrecognized source event: " + sourceEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,10 @@ import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.TimestampedComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -42,7 +39,6 @@ public class SampleGenerator
|
||||
private long mInterval;
|
||||
private int mSamplesPerInterval;
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
private Queue<SourceEvent> mSourceEventQueue = new ConcurrentLinkedQueue();
|
||||
|
||||
/**
|
||||
* Generates complex sample buffers at the specified sample rate with a unity gain tone at the specified
|
||||
@@ -84,16 +80,6 @@ public class SampleGenerator
|
||||
this(sampleRate, frequency, interval, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues the source event for inclusion in the complex buffers generated by this sample generator. Source events
|
||||
* are queued FIFO and embedded one at a time in the subsequent buffers produced by this generator.
|
||||
* @param sourceEvent to queue
|
||||
*/
|
||||
public void queue(SourceEvent sourceEvent)
|
||||
{
|
||||
mSourceEventQueue.offer(sourceEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the number of complex samples generated per interval
|
||||
*/
|
||||
@@ -185,7 +171,7 @@ public class SampleGenerator
|
||||
if(mListener != null)
|
||||
{
|
||||
float[] samples = mOscillator.generate(mSamplesPerInterval);
|
||||
mListener.receive(new TimestampedComplexBuffer(samples, mSourceEventQueue.poll()));
|
||||
mListener.receive(new TimestampedComplexBuffer(samples));
|
||||
|
||||
if(mSweepUpdateInterval != 0)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,6 @@ package io.github.dsheirer.source.tuner.test;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
@@ -56,7 +55,7 @@ public class TestTunerController extends TunerController
|
||||
|
||||
try
|
||||
{
|
||||
mLog.debug("Setting frequency ...");
|
||||
mLog.debug("Setting frequency to:" + DEFAULT_CENTER_FREQUENCY);
|
||||
mFrequencyController.setFrequency(DEFAULT_CENTER_FREQUENCY);
|
||||
mLog.debug("Setting sample rate of freq controller to: " + DEFAULT_SAMPLE_RATE);
|
||||
mFrequencyController.setSampleRate(DEFAULT_SAMPLE_RATE);
|
||||
@@ -130,7 +129,6 @@ public class TestTunerController extends TunerController
|
||||
{
|
||||
long frequency = toneFrequency - mReferenceFrequency;
|
||||
mSampleGenerator.setFrequency(frequency);
|
||||
mSampleGenerator.queue(SourceEvent.frequencyChange(frequency));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,6 +155,5 @@ public class TestTunerController extends TunerController
|
||||
public void setSampleRate(int sampleRate) throws SourceException
|
||||
{
|
||||
mFrequencyController.setSampleRate(sampleRate);
|
||||
mSampleGenerator.queue(SourceEvent.sampleRateChange(sampleRate));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user