Merge pull request #395 from DSheirer/393-raw-bitstream-recording

393 Recording raw decoded bitstream from supported decoder types
This commit is contained in:
Denny Sheirer
2018-08-11 08:09:22 -04:00
committed by GitHub
64 changed files with 938 additions and 425 deletions

View File

@@ -27,7 +27,7 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
* This class is designed to support 8 kHz sample rate demodulated audio.
*/
public class AudioModule extends Module implements IAudioPacketProvider, IReusableBufferListener,
ISquelchStateListener, Listener<ReusableBuffer>
ISquelchStateListener, Listener<ReusableFloatBuffer>
{
protected static final Logger mLog = LoggerFactory.getLogger(AudioModule.class);
private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("AudioModule");
@@ -139,11 +139,11 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
if(mAudioPacketListener != null && mSquelchState == SquelchState.UNSQUELCH)
{
ReusableBuffer highPassFiltered = mHighPassFilter.filter(reusableBuffer);
ReusableFloatBuffer highPassFiltered = mHighPassFilter.filter(reusableFloatBuffer);
ReusableAudioPacket audioPacket = mAudioPacketQueue.getBuffer(highPassFiltered.getSampleCount());
audioPacket.loadAudioFrom(highPassFiltered);
@@ -155,7 +155,7 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
}
else
{
reusableBuffer.decrementUserCount();
reusableFloatBuffer.decrementUserCount();
}
}

View File

@@ -33,6 +33,7 @@ import io.github.dsheirer.module.decode.event.MessageActivityModel;
import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.record.RecorderManager;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.binary.BinaryRecorder;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
import io.github.dsheirer.source.Source;
@@ -308,6 +309,25 @@ public class ChannelProcessingManager implements ChannelEventListener
{
processingChain.addModule(mRecorderManager.getBasebandRecorder(channel.toString()));
}
/* Add decoded bit stream recorder if the decoder supports bitstream output */
if(DecoderFactory.getBitstreamDecoders().contains(channel.getDecodeConfiguration().getDecoderType()))
{
if((recorders.contains(RecorderType.DEMODULATED_BIT_STREAM) &&
channel.getChannelType() == Channel.ChannelType.STANDARD))
{
processingChain.addModule(new BinaryRecorder(mRecorderManager.getRecordingBasePath(),
channel.toString()));
}
/* Add traffic channel decoded bit stream recorder */
if(recorders.contains(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM) &&
channel.getChannelType() == Channel.ChannelType.TRAFFIC)
{
processingChain.addModule(new BinaryRecorder(mRecorderManager.getRecordingBasePath(),
channel.toString()));
}
}
}
processingChain.setSource(source);

View File

@@ -21,7 +21,7 @@ import io.github.dsheirer.dsp.filter.resample.RealResampler;
import io.github.dsheirer.dsp.mixer.IOscillator;
import io.github.dsheirer.dsp.mixer.Oscillator;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
*
* Provides normal or inverted decoded output.
*/
public class AFSK1200Decoder implements Listener<ReusableBuffer>
public class AFSK1200Decoder implements Listener<ReusableFloatBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(AFSK1200Decoder.class);
@@ -110,7 +110,7 @@ public class AFSK1200Decoder implements Listener<ReusableBuffer>
* @param buffer containing 8.0 kHz unfiltered FM demodulated audio samples with sub-audible LTR signalling.
*/
@Override
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
mResampler.resample(buffer);
}
@@ -142,10 +142,10 @@ public class AFSK1200Decoder implements Listener<ReusableBuffer>
}
public class Decoder implements Listener<ReusableBuffer>
public class Decoder implements Listener<ReusableFloatBuffer>
{
@Override
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
//Calculate correlation values against each 1200/1800 reference signal
mCorrelationValuesMark = mCorrelatorMark.process(buffer);
@@ -212,17 +212,17 @@ public class AFSK1200Decoder implements Listener<ReusableBuffer>
* Processes each sample in the incoming sample buffer against a generated reference sample set for one symbol
* period to derive a correlation value that is in-turn averaged over one symbol period.
*
* @param reusableBuffer containing FM demodulated samples
* @param reusableFloatBuffer containing FM demodulated samples
* @return a reusable array of correlation values for each sample
*/
public float[] process(ReusableBuffer reusableBuffer)
public float[] process(ReusableFloatBuffer reusableFloatBuffer)
{
if(mCorrelationValues == null || mCorrelationValues.length != reusableBuffer.getSampleCount())
if(mCorrelationValues == null || mCorrelationValues.length != reusableFloatBuffer.getSampleCount())
{
mCorrelationValues = new float[reusableBuffer.getSampleCount()];
mCorrelationValues = new float[reusableFloatBuffer.getSampleCount()];
}
float[] samples = reusableBuffer.getSamples();
float[] samples = reusableFloatBuffer.getSamples();
int y;

View File

@@ -15,9 +15,9 @@
******************************************************************************/
package io.github.dsheirer.dsp.am;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
/**
* Performs AM demodulation on baseband I/Q samples to produce demodulated float output.
@@ -63,11 +63,11 @@ public class AMDemodulator
* @param complexBuffer to demodulate
* @return demodulated audio buffer.
*/
public ReusableBuffer demodulate(ReusableComplexBuffer complexBuffer)
public ReusableFloatBuffer demodulate(ReusableComplexBuffer complexBuffer)
{
ReusableBuffer reusableBuffer = mReusableBufferQueue.getBuffer(complexBuffer.getSampleCount());
ReusableFloatBuffer reusableFloatBuffer = mReusableBufferQueue.getBuffer(complexBuffer.getSampleCount());
float[] input = complexBuffer.getSamples();
float[] output = reusableBuffer.getSamples();
float[] output = reusableFloatBuffer.getSamples();
mOutputBufferPointer = 0;
for(int x= 0; x < complexBuffer.getSamples().length; x += 2)
@@ -77,6 +77,6 @@ public class AMDemodulator
complexBuffer.decrementUserCount();
return reusableBuffer;
return reusableFloatBuffer;
}
}

View File

@@ -136,6 +136,46 @@ public class ContinuousBufferProcessor<E> implements Listener<E>
}
}
/**
* Stops this buffer processor,stops queuing of incoming buffers and flushes the internal buffer queue
* contents to the listener.
*/
public void flushAndStop()
{
if(mRunning.compareAndSet(true, false))
{
if(mScheduledFuture != null)
{
mScheduledFuture.cancel(true);
mScheduledFuture = null;
}
process();
}
}
/**
* Distributes queued buffers to the listener
*/
private void process()
{
List<E> buffers = new ArrayList<>();
try
{
mQueue.drainTo(buffers);
if(mListener != null)
{
mListener.receive(buffers);
}
}
catch(Throwable throwable)
{
mLog.error("Error while dispatching buffers to listener", throwable);
}
}
/**
* Clears any buffers from the queue
*/
@@ -162,21 +202,7 @@ public class ContinuousBufferProcessor<E> implements Listener<E>
@Override
public void run()
{
List<E> buffers = new ArrayList<>();
try
{
mQueue.drainTo(buffers);
if(mListener != null)
{
mListener.receive(buffers);
}
}
catch(Throwable throwable)
{
mLog.error("Error while dispatching buffers to listeners", throwable);
}
process();
}
}
}

View File

@@ -15,10 +15,10 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.channelizer;
import io.github.dsheirer.sample.buffer.AbstractReusableBuffer;
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
public class ContinuousReusableBufferProcessor<T extends ReusableBuffer> extends ContinuousBufferProcessor<T>
public class ContinuousReusableBufferProcessor<T extends AbstractReusableBuffer> extends ContinuousBufferProcessor<T>
{
/**
* Scheduled Reusable Buffer Processor combines an internal overflowable buffer with a scheduled runnable processing

View File

@@ -23,8 +23,8 @@ import io.github.dsheirer.dsp.filter.Window.WindowType;
import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter2;
import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.sample.decimator.RealDecimator;
import io.github.dsheirer.sample.real.RealSampleListener;
import org.apache.commons.lang3.Validate;
@@ -124,7 +124,7 @@ public class RealPrimeCICDecimate
/**
* Adds a listener to receive the output of this CIC decimation filter
*/
public void setListener(Listener<ReusableBuffer> listener)
public void setListener(Listener<ReusableFloatBuffer> listener)
{
mOutput.setListener(listener);
}
@@ -173,7 +173,7 @@ public class RealPrimeCICDecimate
/**
* Primary input method for receiving real buffers.
*/
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
if(mFirstDecimatingStage != null)
{
@@ -353,7 +353,7 @@ public class RealPrimeCICDecimate
{
/* Decimated output buffers will contain 1024 samples */
private ReusableBufferAssembler mAssembler;
private Listener<ReusableBuffer> mReusableBufferListener;
private Listener<ReusableFloatBuffer> mReusableBufferListener;
private RealFIRFilter2 mCleanupFilter;
private HalfBandFilter mHalfBandFilter = new HalfBandFilter(
@@ -365,21 +365,21 @@ public class RealPrimeCICDecimate
attenuation, windowType), 0.4f);
mAssembler = new ReusableBufferAssembler(outputBufferSize);
mAssembler.setListener(new Listener<ReusableBuffer>()
mAssembler.setListener(new Listener<ReusableFloatBuffer>()
{
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
if(mReusableBufferListener != null)
{
ReusableBuffer cleanupFiltered = mCleanupFilter.filter(reusableBuffer);
ReusableBuffer halfBandFiltered = mHalfBandFilter.filter(cleanupFiltered);
ReusableFloatBuffer cleanupFiltered = mCleanupFilter.filter(reusableFloatBuffer);
ReusableFloatBuffer halfBandFiltered = mHalfBandFilter.filter(cleanupFiltered);
mReusableBufferListener.receive(halfBandFiltered);
}
else
{
reusableBuffer.decrementUserCount();
reusableFloatBuffer.decrementUserCount();
}
}
});
@@ -406,7 +406,7 @@ public class RealPrimeCICDecimate
/**
* Adds a listener to receive output samples
*/
public void setListener(Listener<ReusableBuffer> listener)
public void setListener(Listener<ReusableFloatBuffer> listener)
{
mReusableBufferListener = listener;
}

View File

@@ -15,8 +15,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.dc;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -77,11 +77,11 @@ public class BufferDCFilter
}
}
public ReusableBuffer filter(ReusableBuffer unfilteredBuffer)
public ReusableFloatBuffer filter(ReusableFloatBuffer unfilteredBuffer)
{
float[] unfilteredSamples = unfilteredBuffer.getSamples();
ReusableBuffer filteredBuffer = mReusableBufferQueue.getBuffer(unfilteredSamples.length);
ReusableFloatBuffer filteredBuffer = mReusableBufferQueue.getBuffer(unfilteredSamples.length);
float[] filteredSamples = filteredBuffer.getSamples();
float offset = getOffset(unfilteredSamples);

View File

@@ -15,8 +15,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.dc;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
/**
* DC removal filter for removing any DC offset that may be present when a signal is not aligned within the
@@ -77,9 +77,9 @@ public class DCRemovalFilter
* @param unfilteredBuffer containing samples to filter
* @return a new reusable buffer containing the filtered samples with the user count set to 1.
*/
public ReusableBuffer filter(ReusableBuffer unfilteredBuffer)
public ReusableFloatBuffer filter(ReusableFloatBuffer unfilteredBuffer)
{
ReusableBuffer filteredBuffer = mReusableBufferQueue.getBuffer(unfilteredBuffer.getSampleCount());
ReusableFloatBuffer filteredBuffer = mReusableBufferQueue.getBuffer(unfilteredBuffer.getSampleCount());
float[] unfilteredSamples = unfilteredBuffer.getSamples();
float[] filteredSamples = filteredBuffer.getSamples();

View File

@@ -15,8 +15,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.dc;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.sample.real.RealSampleListener;
public class IIRSinglePoleDCRemovalFilter implements RealSampleListener
@@ -67,9 +67,9 @@ public class IIRSinglePoleDCRemovalFilter implements RealSampleListener
* @param inputBuffer to filter
* @return filtered samples in a new (ie reused) output buffer
*/
public ReusableBuffer filter(ReusableBuffer inputBuffer)
public ReusableFloatBuffer filter(ReusableFloatBuffer inputBuffer)
{
ReusableBuffer outputBuffer = mReusableBufferQueue.getBuffer(inputBuffer.getSampleCount());
ReusableFloatBuffer outputBuffer = mReusableBufferQueue.getBuffer(inputBuffer.getSampleCount());
float[] inputSamples = inputBuffer.getSamples();
float[] outputSamples = outputBuffer.getSamples();

View File

@@ -16,8 +16,8 @@
package io.github.dsheirer.dsp.filter.fir.real;
import io.github.dsheirer.dsp.filter.fir.FIRFilter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
/**
* Finite Impulse Response (FIR) filter for filtering individual float samples or float sample arrays.
@@ -113,11 +113,11 @@ public class RealFIRFilter2 extends FIRFilter
* @param unfilteredBuffer containing a sample array to be filtered
* @return a new reusable buffer with the filtered samples.
*/
public ReusableBuffer filter(ReusableBuffer unfilteredBuffer)
public ReusableFloatBuffer filter(ReusableFloatBuffer unfilteredBuffer)
{
float[] unfilteredSamples = unfilteredBuffer.getSamples();
ReusableBuffer filteredBuffer = mReusableBufferQueue.getBuffer(unfilteredSamples.length);
ReusableFloatBuffer filteredBuffer = mReusableBufferQueue.getBuffer(unfilteredSamples.length);
float[] filteredSamples = filteredBuffer.getSamples();
for(int x = 0; x < unfilteredSamples.length; x++)

View File

@@ -17,8 +17,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.halfband.real;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import org.apache.commons.lang3.Validate;
public class HalfBandFilter
@@ -84,10 +84,10 @@ public class HalfBandFilter
mBufferPointer = mBufferPointer % mBufferSize;
}
public ReusableBuffer filter(ReusableBuffer input)
public ReusableFloatBuffer filter(ReusableFloatBuffer input)
{
float[] inputSamples = input.getSamples();
ReusableBuffer output = mReusableBufferQueue.getBuffer(inputSamples.length);
ReusableFloatBuffer output = mReusableBufferQueue.getBuffer(inputSamples.length);
float[] outputSamples = output.getSamples();
for(int x = 0; x < inputSamples.length; x++)

View File

@@ -18,8 +18,8 @@ package io.github.dsheirer.dsp.filter.resample;
import com.laszlosystems.libresample4j.Resampler;
import com.laszlosystems.libresample4j.SampleBuffers;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,7 +32,7 @@ public class RealResampler
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("RealResampler");
private Resampler mResampler;
private Listener<ReusableBuffer> mResampledListener;
private Listener<ReusableFloatBuffer> mResampledListener;
private BufferManager mBufferManager;
private double mResampleFactor;
@@ -50,11 +50,11 @@ public class RealResampler
/**
* Primary input method to the resampler
* @param reusableBuffer to resample
* @param reusableFloatBuffer to resample
*/
public void resample(ReusableBuffer reusableBuffer)
public void resample(ReusableFloatBuffer reusableFloatBuffer)
{
mBufferManager.load(reusableBuffer);
mBufferManager.load(reusableFloatBuffer);
mResampler.process(mResampleFactor, mBufferManager, false);
}
@@ -62,7 +62,7 @@ public class RealResampler
* Registers the listener to receive the resampled buffer output
* @param resampledBufferListener to receive buffers
*/
public void setListener(Listener<ReusableBuffer> resampledBufferListener)
public void setListener(Listener<ReusableFloatBuffer> resampledBufferListener)
{
mResampledListener = resampledBufferListener;
}
@@ -89,10 +89,10 @@ public class RealResampler
/**
* Queues the buffer sample for resampling
*/
public void load(ReusableBuffer reusableBuffer)
public void load(ReusableFloatBuffer reusableFloatBuffer)
{
mInputBuffer.put(reusableBuffer.getSamples());
reusableBuffer.decrementUserCount();
mInputBuffer.put(reusableFloatBuffer.getSamples());
reusableFloatBuffer.decrementUserCount();
}
@Override
@@ -128,7 +128,7 @@ public class RealResampler
while(mOutputBuffer.position() > mOutputBufferSize)
{
ReusableBuffer outputBuffer = mReusableBufferQueue.getBuffer(mOutputBufferSize);
ReusableFloatBuffer outputBuffer = mReusableBufferQueue.getBuffer(mOutputBufferSize);
mOutputBuffer.flip();
mOutputBuffer.get(outputBuffer.getSamples());

View File

@@ -17,9 +17,9 @@
******************************************************************************/
package io.github.dsheirer.dsp.fm;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.sample.complex.Complex;
/**
@@ -129,9 +129,9 @@ public class FMDemodulator
* @param basebandSampleBuffer containing samples to demodulate
* @return demodulated sample buffer.
*/
public ReusableBuffer demodulate(ReusableComplexBuffer basebandSampleBuffer)
public ReusableFloatBuffer demodulate(ReusableComplexBuffer basebandSampleBuffer)
{
ReusableBuffer demodulatedBuffer = mReusableBufferQueue.getBuffer(basebandSampleBuffer.getSampleCount());
ReusableFloatBuffer demodulatedBuffer = mReusableBufferQueue.getBuffer(basebandSampleBuffer.getSampleCount());
float[] basebandSamples = basebandSampleBuffer.getSamples();
float[] demodulatedSamples = demodulatedBuffer.getSamples();

View File

@@ -23,7 +23,7 @@ import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter2;
import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory;
* adjustment may not fully compensate for mis-tuned signals and may result in missed decodes of idle bursts. However,
* the DC filter will track a mis-tuned signal to baseband quickly upon a continuous transmission.
*/
public class LTRDecoder implements Listener<ReusableBuffer>, ISyncDetectListener, ISyncStateListener
public class LTRDecoder implements Listener<ReusableFloatBuffer>, ISyncDetectListener, ISyncStateListener
{
private final static Logger mLog = LoggerFactory.getLogger(LTRDecoder.class);
@@ -148,10 +148,10 @@ public class LTRDecoder implements Listener<ReusableBuffer>, ISyncDetectListener
* @param buffer containing 8.0 kHz unfiltered FM demodulated audio samples with sub-audible LTR signalling.
*/
@Override
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
ReusableBuffer dcFiltered = mDCFilter.filter(buffer);
ReusableBuffer lowPassFiltered = mLowPassFilter.filter(dcFiltered);
ReusableFloatBuffer dcFiltered = mDCFilter.filter(buffer);
ReusableFloatBuffer lowPassFiltered = mLowPassFilter.filter(dcFiltered);
for(float sample : lowPassFiltered.getSamples())
{

View File

@@ -2,8 +2,8 @@ package io.github.dsheirer.dsp.gain;
import io.github.dsheirer.buffer.DoubleCircularBuffer;
import io.github.dsheirer.buffer.RealCircularBuffer;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
/*******************************************************************************
* SDR Trunk
@@ -147,9 +147,9 @@ public class AutomaticGainControl
* @param input samples to process
* @return output samples with gain applied
*/
public ReusableBuffer process(ReusableBuffer input)
public ReusableFloatBuffer process(ReusableFloatBuffer input)
{
ReusableBuffer output = mReusableBufferQueue.getBuffer(input.getSampleCount());
ReusableFloatBuffer output = mReusableBufferQueue.getBuffer(input.getSampleCount());
float[] inputSamples = input.getSamples();
float[] outputSamples = output.getSamples();

View File

@@ -15,8 +15,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.mixer;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.sample.complex.Complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -182,11 +182,11 @@ public abstract class AbstractOscillator implements IOscillator
/**
* Generates enough real samples to fill the reusable buffer
* @param reusableBuffer to fill with real samples
* @param reusableFloatBuffer to fill with real samples
*/
@Override
public void generateReal(ReusableBuffer reusableBuffer)
public void generateReal(ReusableFloatBuffer reusableFloatBuffer)
{
reusableBuffer.reloadFrom(generateReal(reusableBuffer.getSampleCount()), System.currentTimeMillis());
reusableFloatBuffer.reloadFrom(generateReal(reusableFloatBuffer.getSampleCount()), System.currentTimeMillis());
}
}

View File

@@ -15,8 +15,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.mixer;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
/**
* Oscillator interface.
@@ -102,9 +102,9 @@ public interface IOscillator
* Generates real samples and fills the reusable buffer using the current system time in millis for
* the update timestamp.
*
* @param reusableBuffer to fill with complex samples
* @param reusableFloatBuffer to fill with complex samples
*/
void generateReal(ReusableBuffer reusableBuffer);
void generateReal(ReusableFloatBuffer reusableFloatBuffer);
/**
* Mixes (heterodynes) the complex sample array using the current settings of this oscillator.

View File

@@ -17,8 +17,8 @@ package io.github.dsheirer.gui.instrument;
import io.github.dsheirer.gui.instrument.decoder.AbstractDecoderPane;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.IControllableFileSource;
import io.github.dsheirer.source.IFrameLocationListener;
import io.github.dsheirer.source.wave.ComplexWaveSource;
@@ -177,7 +177,7 @@ public class PlaybackController extends HBox implements IFrameLocationListener
/**
* Adds listener to receive complex buffers from this playback
*/
public void addListener(Listener<ReusableBuffer> listener)
public void addListener(Listener<ReusableFloatBuffer> listener)
{
mReusableBufferBroadcaster.addListener(listener);
}
@@ -185,7 +185,7 @@ public class PlaybackController extends HBox implements IFrameLocationListener
/**
* Removes the listener from receiving complex buffers from this playback
*/
public void removeListener(Listener<ReusableBuffer> listener)
public void removeListener(Listener<ReusableFloatBuffer> listener)
{
mReusableBufferBroadcaster.removeListener(listener);
}

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.gui.instrument.chart;
import io.github.dsheirer.buffer.RealCircularBuffer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.LineChart;
@@ -27,7 +27,7 @@ import javafx.scene.layout.StackPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RealSampleLineChart extends LineChart implements Listener<ReusableBuffer>
public class RealSampleLineChart extends LineChart implements Listener<ReusableFloatBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(RealSampleLineChart.class);
private ObservableList<Data<Integer,Float>> mSamples = FXCollections.observableArrayList();
@@ -65,7 +65,7 @@ public class RealSampleLineChart extends LineChart implements Listener<ReusableB
}
@Override
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
for(float sample: buffer.getSamples())
{

View File

@@ -23,7 +23,7 @@ import io.github.dsheirer.gui.instrument.chart.RealSampleLineChart;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
@@ -52,7 +52,7 @@ public abstract class AbstractAFSK1200Pane extends RealDecoderPane
private void init()
{
//This is force-cast without type checking ....
addListener((Listener<ReusableBuffer>)getDecoder());
addListener((Listener<ReusableFloatBuffer>)getDecoder());
addListener(getSampleLineChart());

View File

@@ -17,10 +17,10 @@ package io.github.dsheirer.gui.instrument.decoder;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.scene.layout.VBox;
public abstract class AbstractDecoderPane<T extends ReusableBuffer> extends VBox implements Listener<T>
public abstract class AbstractDecoderPane<T extends ReusableFloatBuffer> extends VBox implements Listener<T>
{
abstract SampleType getSampleType();

View File

@@ -18,11 +18,11 @@ package io.github.dsheirer.gui.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.scene.text.Text;
public class RealDecoderPane extends AbstractDecoderPane<ReusableBuffer>
public class RealDecoderPane extends AbstractDecoderPane<ReusableFloatBuffer>
{
private ReusableBufferBroadcaster mBufferBroadcaster = new ReusableBufferBroadcaster();
private DecoderType mDecoderType;
@@ -47,17 +47,17 @@ public class RealDecoderPane extends AbstractDecoderPane<ReusableBuffer>
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
mBufferBroadcaster.broadcast(reusableBuffer);
mBufferBroadcaster.broadcast(reusableFloatBuffer);
}
public void addListener(Listener<ReusableBuffer> listener)
public void addListener(Listener<ReusableFloatBuffer> listener)
{
mBufferBroadcaster.addListener(listener);
}
public void removeListener(Listener<ReusableBuffer> listener)
public void removeListener(Listener<ReusableFloatBuffer> listener)
{
mBufferBroadcaster.removeListener(listener);
}

View File

@@ -49,11 +49,14 @@ import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
import io.github.dsheirer.sample.buffer.IReusableByteBufferListener;
import io.github.dsheirer.sample.buffer.IReusableByteBufferProvider;
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import io.github.dsheirer.sample.buffer.ReusableByteBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.ComplexSource;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.ISourceEventProvider;
@@ -93,8 +96,9 @@ public class ProcessingChain implements IChannelEventListener
private final static Logger mLog = LoggerFactory.getLogger(ProcessingChain.class);
private ReusableBufferBroadcaster<ReusableAudioPacket> mAudioPacketBroadcaster = new ReusableBufferBroadcaster<>();
private ReusableBufferBroadcaster<ReusableBuffer> mDemodulatedAudioBufferBroadcaster = new ReusableBufferBroadcaster();
private ReusableBufferBroadcaster<ReusableFloatBuffer> mDemodulatedAudioBufferBroadcaster = new ReusableBufferBroadcaster();
private ReusableBufferBroadcaster<ReusableComplexBuffer> mBasebandComplexBufferBroadcaster = new ReusableBufferBroadcaster();
private ReusableBufferBroadcaster<ReusableByteBuffer> mDemodulatedBitstreamBufferBroadcaster = new ReusableBufferBroadcaster();
private Broadcaster<AttributeChangeRequest> mAttributeChangeRequestBroadcaster = new Broadcaster<>();
private Broadcaster<CallEvent> mCallEventBroadcaster = new Broadcaster<>();
private Broadcaster<ChannelEvent> mChannelEventBroadcaster = new Broadcaster<>();
@@ -163,6 +167,7 @@ public class ProcessingChain implements IChannelEventListener
mCallEventBroadcaster.dispose();
mChannelEventBroadcaster.dispose();
mBasebandComplexBufferBroadcaster.dispose();
mDemodulatedBitstreamBufferBroadcaster.dispose();
mMessageBroadcaster.dispose();
mSquelchStateBroadcaster.dispose();
}
@@ -323,6 +328,11 @@ public class ProcessingChain implements IChannelEventListener
mDemodulatedAudioBufferBroadcaster.addListener(((IReusableBufferListener)module).getReusableBufferListener());
}
if(module instanceof IReusableByteBufferListener)
{
mDemodulatedBitstreamBufferBroadcaster.addListener(((IReusableByteBufferListener)module).getReusableByteBufferListener());
}
if(module instanceof IReusableComplexBufferListener)
{
mBasebandComplexBufferBroadcaster.addListener(((IReusableComplexBufferListener)module).getReusableComplexBufferListener());
@@ -385,6 +395,11 @@ public class ProcessingChain implements IChannelEventListener
mDemodulatedAudioBufferBroadcaster.removeListener(((IReusableBufferListener)module).getReusableBufferListener());
}
if(module instanceof IReusableByteBufferListener)
{
mDemodulatedBitstreamBufferBroadcaster.removeListener(((IReusableByteBufferListener) module).getReusableByteBufferListener());
}
if(module instanceof IReusableComplexBufferListener)
{
mBasebandComplexBufferBroadcaster.removeListener(((IReusableComplexBufferListener) module).getReusableComplexBufferListener());
@@ -452,6 +467,11 @@ public class ProcessingChain implements IChannelEventListener
((IMessageProvider) module).setMessageListener(mMessageBroadcaster);
}
if(module instanceof IReusableByteBufferProvider)
{
((IReusableByteBufferProvider)module).setBufferListener(mDemodulatedBitstreamBufferBroadcaster);
}
if(module instanceof IReusableBufferProvider)
{
((IReusableBufferProvider)module).setBufferListener(mDemodulatedAudioBufferBroadcaster);
@@ -484,6 +504,11 @@ public class ProcessingChain implements IChannelEventListener
((IAudioPacketProvider) module).setAudioPacketListener(null);
}
if(module instanceof IReusableByteBufferProvider)
{
((IReusableByteBufferProvider)module).removeBufferListener(mDemodulatedBitstreamBufferBroadcaster);
}
if(module instanceof ICallEventProvider)
{
((ICallEventProvider) module).removeCallEventListener(mCallEventBroadcaster);
@@ -549,7 +574,7 @@ public class ProcessingChain implements IChannelEventListener
//Broadcast the source sample rate so that each of the modules can self-configure
mSourceEventBroadcaster.broadcast(SourceEvent.sampleRateChange(mSource.getSampleRate(), "Processing Chain Startup"));
//Broadcast the source center frequencysample rate so that each of the modules can self-configure
//Broadcast the source center frequency / sample rate so that each of the modules can self-configure
mSourceEventBroadcaster.broadcast(SourceEvent.frequencyChange(mSource.getFrequency(), "Processing Chain Startup"));
//Setup the channel state to monitor source overflow conditions
@@ -790,7 +815,7 @@ public class ProcessingChain implements IChannelEventListener
/**
* Adds listener to receive demodulated audio buffers from an modules that produce demodulated audio.
*/
public void addDemodulatedAudioListener(Listener<ReusableBuffer> listener)
public void addDemodulatedAudioListener(Listener<ReusableFloatBuffer> listener)
{
mDemodulatedAudioBufferBroadcaster.addListener(listener);
}
@@ -798,7 +823,7 @@ public class ProcessingChain implements IChannelEventListener
/**
* Removes the listener from receiving demodulated audio buffers.
*/
public void removeDemodulatedAudioListener(Listener<ReusableBuffer> listener)
public void removeDemodulatedAudioListener(Listener<ReusableFloatBuffer> listener)
{
mDemodulatedAudioBufferBroadcaster.removeListener(listener);
}

View File

@@ -93,6 +93,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public class DecoderFactory
@@ -467,4 +468,17 @@ public class DecoderFactory
return null;
}
/**
* Decoder(s) that support bitstreams.
*
* @return set of decoders that support bitstreams.
*/
public static EnumSet<DecoderType> getBitstreamDecoders()
{
// return EnumSet.of(DecoderType.P25_PHASE1);
//None of the decoders currently support bitstream output.
return EnumSet.noneOf(DecoderType.class);
}
}

View File

@@ -19,7 +19,7 @@ import io.github.dsheirer.dsp.afsk.AFSK1200Decoder;
import io.github.dsheirer.module.decode.Decoder;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
/**
* Abstract class for Audio Frequency Shift Keying (AFSK) 1200-baud decoder based decoder modules.
@@ -28,7 +28,7 @@ import io.github.dsheirer.sample.buffer.ReusableBuffer;
*
* Sub-class implementations should invoke getDecoder().setListener() to receive decoded symbol stream.
*/
public abstract class AbstractAFSKDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableBuffer>
public abstract class AbstractAFSKDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableFloatBuffer>
{
private AFSK1200Decoder mAFSK1200Decoder;
@@ -48,13 +48,13 @@ public abstract class AbstractAFSKDecoder extends Decoder implements IReusableBu
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
mAFSK1200Decoder.receive(reusableBuffer);
mAFSK1200Decoder.receive(reusableFloatBuffer);
}
@Override
public Listener<ReusableBuffer> getReusableBufferListener()
public Listener<ReusableFloatBuffer> getReusableBufferListener()
{
return this;
}

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.module.decode.fleetsync2;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.gui.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.beans.property.SimpleIntegerProperty;
/**
@@ -44,9 +44,9 @@ public class Fleetsync2DecoderInstrumented extends Fleetsync2Decoder implements
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
super.receive(reusableBuffer);
super.receive(reusableFloatBuffer);
bufferCount.setValue(bufferCount.intValue() + 1);
}

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.module.decode.lj1200;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.gui.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.beans.property.SimpleIntegerProperty;
/**
@@ -44,9 +44,9 @@ public class LJ1200DecoderInstrumented extends LJ1200Decoder implements IInstrum
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
super.receive(reusableBuffer);
super.receive(reusableFloatBuffer);
bufferCount.setValue(bufferCount.intValue() + 1);
}

View File

@@ -24,9 +24,9 @@ import io.github.dsheirer.module.decode.Decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public class LTRNetDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableBuffer>
public class LTRNetDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableFloatBuffer>
{
public static final int LTR_NET_MESSAGE_LENGTH = 40;
protected LTRDecoder mLTRDecoder;
@@ -73,15 +73,15 @@ public class LTRNetDecoder extends Decoder implements IReusableBufferListener, L
}
@Override
public Listener<ReusableBuffer> getReusableBufferListener()
public Listener<ReusableFloatBuffer> getReusableBufferListener()
{
return mLTRDecoder;
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
mLTRDecoder.receive(reusableBuffer);
mLTRDecoder.receive(reusableFloatBuffer);
}
@Override

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.module.decode.ltrnet;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.dsp.fsk.LTRDecoderInstrumented;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.beans.property.SimpleIntegerProperty;
public class LTRNetDecoderInstrumented extends LTRNetDecoder
@@ -35,9 +35,9 @@ public class LTRNetDecoderInstrumented extends LTRNetDecoder
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
super.receive(reusableBuffer);
super.receive(reusableFloatBuffer);
bufferCount.setValue(bufferCount.intValue() + 1);
}

View File

@@ -24,9 +24,9 @@ import io.github.dsheirer.module.decode.Decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public class LTRStandardDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableBuffer>
public class LTRStandardDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableFloatBuffer>
{
public static final int LTR_STANDARD_MESSAGE_LENGTH = 40;
@@ -65,15 +65,15 @@ public class LTRStandardDecoder extends Decoder implements IReusableBufferListen
}
@Override
public Listener<ReusableBuffer> getReusableBufferListener()
public Listener<ReusableFloatBuffer> getReusableBufferListener()
{
return mLTRDecoder;
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
mLTRDecoder.receive(reusableBuffer);
mLTRDecoder.receive(reusableFloatBuffer);
}
@Override

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.module.decode.mdc1200;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.gui.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.beans.property.SimpleIntegerProperty;
/**
@@ -44,9 +44,9 @@ public class MDCDecoderInstrumented extends MDCDecoder implements IInstrumentedA
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
super.receive(reusableBuffer);
super.receive(reusableFloatBuffer);
bufferCount.setValue(bufferCount.intValue() + 1);
}

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.module.decode.mpt1327;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.gui.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.beans.property.SimpleIntegerProperty;
/**
@@ -44,9 +44,9 @@ public class MPT1327DecoderInstrumented extends MPT1327Decoder implements IInstr
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
super.receive(reusableBuffer);
super.receive(reusableFloatBuffer);
bufferCount.setValue(bufferCount.intValue() + 1);
}

View File

@@ -2,13 +2,13 @@ package io.github.dsheirer.module.decode.p25;
import io.github.dsheirer.dsp.gain.DirectGainControl;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.sample.real.RealSampleListener;
import io.github.dsheirer.sample.real.RealSampleProvider;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.SourceEvent;
public class C4FMSymbolFilter implements Listener<ReusableBuffer>, ISourceEventListener, RealSampleProvider
public class C4FMSymbolFilter implements Listener<ReusableFloatBuffer>, ISourceEventListener, RealSampleProvider
{
private static final float TAPS[][] =
{
@@ -215,7 +215,7 @@ public class C4FMSymbolFilter implements Listener<ReusableBuffer>, ISourceEventL
}
@Override
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
for(float sample : buffer.getSamples())
{

View File

@@ -24,9 +24,9 @@ import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public class PassportDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableBuffer>
public class PassportDecoder extends Decoder implements IReusableBufferListener, Listener<ReusableFloatBuffer>
{
public static final int PASSPORT_MESSAGE_LENGTH = 68;
@@ -52,15 +52,15 @@ public class PassportDecoder extends Decoder implements IReusableBufferListener,
}
@Override
public Listener<ReusableBuffer> getReusableBufferListener()
public Listener<ReusableFloatBuffer> getReusableBufferListener()
{
return mLTRDecoder;
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
mLTRDecoder.receive(reusableBuffer);
mLTRDecoder.receive(reusableFloatBuffer);
}
@Override

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.module.decode.tait;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.gui.instrument.chart.IInstrumentedAFSK1200Decoder;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import javafx.beans.property.SimpleIntegerProperty;
/**
@@ -44,9 +44,9 @@ public class Tait1200DecoderInstrumented extends Tait1200Decoder implements IIns
}
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
super.receive(reusableBuffer);
super.receive(reusableFloatBuffer);
bufferCount.setValue(bufferCount.intValue() + 1);
}

View File

@@ -29,8 +29,8 @@ import io.github.dsheirer.module.Module;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.SourceEvent;
import org.slf4j.Logger;
@@ -55,7 +55,7 @@ public class AMDemodulatorModule extends Module implements ISourceEventListener,
private double mChannelBandwidth;
private double mOutputSampleRate;
private RealResampler mResampler;
private Listener<ReusableBuffer> mResampledReusableBufferListener;
private Listener<ReusableFloatBuffer> mResampledReusableBufferListener;
private SourceEventProcessor mSourceEventProcessor = new SourceEventProcessor();
/**
@@ -109,7 +109,7 @@ public class AMDemodulatorModule extends Module implements ISourceEventListener,
public void receive(ReusableComplexBuffer basebandBuffer)
{
ReusableComplexBuffer filteredBuffer = mIQFilter.filter(basebandBuffer);
ReusableBuffer demodulated = mDemodulator.demodulate(filteredBuffer);
ReusableFloatBuffer demodulated = mDemodulator.demodulate(filteredBuffer);
mResampler.resample(demodulated);
}
@@ -117,12 +117,12 @@ public class AMDemodulatorModule extends Module implements ISourceEventListener,
* Processes resampled audio buffers produced by the resampler.
* @param resampledAudio buffer to process.
*/
private void processResampledAudio(ReusableBuffer resampledAudio)
private void processResampledAudio(ReusableFloatBuffer resampledAudio)
{
if(mResampledReusableBufferListener != null)
{
ReusableBuffer filteredAudio = mLowPassFilter.filter(resampledAudio);
ReusableBuffer gainApplied = mAGC.process(filteredAudio);
ReusableFloatBuffer filteredAudio = mLowPassFilter.filter(resampledAudio);
ReusableFloatBuffer gainApplied = mAGC.process(filteredAudio);
mResampledReusableBufferListener.receive(gainApplied);
}
else
@@ -172,7 +172,7 @@ public class AMDemodulatorModule extends Module implements ISourceEventListener,
}
@Override
public void setBufferListener(Listener<ReusableBuffer> listener)
public void setBufferListener(Listener<ReusableFloatBuffer> listener)
{
mResampledReusableBufferListener = listener;
}
@@ -253,10 +253,10 @@ public class AMDemodulatorModule extends Module implements ISourceEventListener,
mResampler = new RealResampler(sampleRate, mOutputSampleRate, 2000, 1000);
mResampler.setListener(new Listener<ReusableBuffer>()
mResampler.setListener(new Listener<ReusableFloatBuffer>()
{
@Override
public void receive(ReusableBuffer resampledAudioBuffer)
public void receive(ReusableFloatBuffer resampledAudioBuffer)
{
processResampledAudio(resampledAudioBuffer);
}

View File

@@ -26,8 +26,8 @@ import io.github.dsheirer.module.Module;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.SourceEvent;
import org.slf4j.Logger;
@@ -47,7 +47,7 @@ public class FMDemodulatorModule extends Module implements ISourceEventListener,
private FMDemodulator mDemodulator = new FMDemodulator();
private RealResampler mResampler;
private SourceEventProcessor mSourceEventProcessor = new SourceEventProcessor();
private Listener<ReusableBuffer> mResampledReusableBufferListener;
private Listener<ReusableFloatBuffer> mResampledReusableBufferListener;
private double mChannelBandwidth;
private double mOutputSampleRate;
@@ -106,7 +106,7 @@ public class FMDemodulatorModule extends Module implements ISourceEventListener,
}
@Override
public void setBufferListener(Listener<ReusableBuffer> listener)
public void setBufferListener(Listener<ReusableFloatBuffer> listener)
{
mResampledReusableBufferListener = listener;
}
@@ -128,7 +128,7 @@ public class FMDemodulatorModule extends Module implements ISourceEventListener,
}
ReusableComplexBuffer basebandFilteredBuffer = mIQFilter.filter(reusableComplexBuffer);
ReusableBuffer demodulatedBuffer = mDemodulator.demodulate(basebandFilteredBuffer);
ReusableFloatBuffer demodulatedBuffer = mDemodulator.demodulate(basebandFilteredBuffer);
if(mResampler != null)
{
@@ -204,18 +204,18 @@ public class FMDemodulatorModule extends Module implements ISourceEventListener,
mResampler = new RealResampler(sampleRate, mOutputSampleRate, 2000, 1000);
mResampler.setListener(new Listener<ReusableBuffer>()
mResampler.setListener(new Listener<ReusableFloatBuffer>()
{
@Override
public void receive(ReusableBuffer reusableBuffer)
public void receive(ReusableFloatBuffer reusableFloatBuffer)
{
if(mResampledReusableBufferListener != null)
{
mResampledReusableBufferListener.receive(reusableBuffer);
mResampledReusableBufferListener.receive(reusableFloatBuffer);
}
else
{
reusableBuffer.decrementUserCount();
reusableFloatBuffer.decrementUserCount();
}
}
});

View File

@@ -1,19 +1,17 @@
/*******************************************************************************
* 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/>
* sdr-trunk
* Copyright (C) 2014-2018 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.record;
@@ -22,7 +20,7 @@ import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.record.config.RecordConfiguration;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import javax.swing.JCheckBox;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
@@ -30,121 +28,168 @@ import java.util.List;
public class RecordConfigurationEditor extends Editor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mAudioRecorder;
private JCheckBox mBasebandRecorder;
private JCheckBox mTrafficBasebandRecorder;
private JCheckBox mBitstreamRecorder;
private JCheckBox mTrafficBitstreamRecorder;
public RecordConfigurationEditor()
{
init();
}
{
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "", "[][grow]" ) );
mAudioRecorder = new JCheckBox( "Audio" );
mAudioRecorder.setEnabled( false );
mAudioRecorder.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( mAudioRecorder );
setLayout(new MigLayout("fill,wrap 2", "", "[][][][grow]"));
mBasebandRecorder = new JCheckBox( "Baseband I/Q" );
mBasebandRecorder.setEnabled( false );
mBasebandRecorder.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( mBasebandRecorder );
mAudioRecorder = new JCheckBox("Audio");
mAudioRecorder.setEnabled(false);
mAudioRecorder.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mAudioRecorder, "wrap");
mTrafficBasebandRecorder = new JCheckBox( "Traffic Channel Baseband I/Q" );
mTrafficBasebandRecorder.setEnabled( false );
mTrafficBasebandRecorder.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( mTrafficBasebandRecorder );
mBasebandRecorder = new JCheckBox("Baseband I/Q");
mBasebandRecorder.setEnabled(false);
mBasebandRecorder.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mBasebandRecorder);
mTrafficBasebandRecorder = new JCheckBox("Traffic Channel Baseband I/Q");
mTrafficBasebandRecorder.setEnabled(false);
mTrafficBasebandRecorder.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mTrafficBasebandRecorder);
mBitstreamRecorder = new JCheckBox("Demodulated Bitstream");
mBitstreamRecorder.setEnabled(false);
mBitstreamRecorder.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mBitstreamRecorder);
mTrafficBitstreamRecorder = new JCheckBox("Traffic Channel Bitstream");
mTrafficBitstreamRecorder.setEnabled(false);
mTrafficBitstreamRecorder.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mTrafficBitstreamRecorder);
}
private void setControlsEnabled( boolean enabled )
private void setControlsEnabled(boolean enabled)
{
if( mAudioRecorder.isEnabled() != enabled )
{
mAudioRecorder.setEnabled( enabled );
}
if( mBasebandRecorder.isEnabled() != enabled )
{
mBasebandRecorder.setEnabled( enabled );
}
if( mTrafficBasebandRecorder.isEnabled() != enabled )
{
mTrafficBasebandRecorder.setEnabled( enabled );
}
if(mAudioRecorder.isEnabled() != enabled)
{
mAudioRecorder.setEnabled(enabled);
}
if(mBasebandRecorder.isEnabled() != enabled)
{
mBasebandRecorder.setEnabled(enabled);
}
if(mTrafficBasebandRecorder.isEnabled() != enabled)
{
mTrafficBasebandRecorder.setEnabled(enabled);
}
if(mBitstreamRecorder.isEnabled() != enabled)
{
mBitstreamRecorder.setEnabled(enabled);
}
if(mTrafficBitstreamRecorder.isEnabled() != enabled)
{
mTrafficBitstreamRecorder.setEnabled(enabled);
}
}
@Override
@Override
public void save()
{
if( hasItem() && isModified() )
{
RecordConfiguration config = getItem().getRecordConfiguration();
config.clearRecorders();
if( mAudioRecorder.isSelected() )
{
config.addRecorder( RecorderType.AUDIO );
}
if( mBasebandRecorder.isSelected() )
{
config.addRecorder( RecorderType.BASEBAND );
}
if( mTrafficBasebandRecorder.isSelected() )
{
config.addRecorder( RecorderType.TRAFFIC_BASEBAND );
}
}
setModified( false );
if(hasItem() && isModified())
{
RecordConfiguration config = getItem().getRecordConfiguration();
config.clearRecorders();
if(mAudioRecorder.isSelected())
{
config.addRecorder(RecorderType.AUDIO);
}
if(mBasebandRecorder.isSelected())
{
config.addRecorder(RecorderType.BASEBAND);
}
if(mTrafficBasebandRecorder.isSelected())
{
config.addRecorder(RecorderType.TRAFFIC_BASEBAND);
}
if(mBitstreamRecorder.isSelected())
{
config.addRecorder(RecorderType.DEMODULATED_BIT_STREAM);
}
if(mTrafficBitstreamRecorder.isSelected())
{
config.addRecorder(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM);
}
}
setModified(false);
}
@Override
public void setItem(Channel channel)
{
super.setItem(channel);
if(hasItem())
{
setControlsEnabled(true);
List<RecorderType> recorders = getItem().getRecordConfiguration().getRecorders();
mAudioRecorder.setSelected(recorders.contains(RecorderType.AUDIO));
mBasebandRecorder.setSelected(recorders.contains(RecorderType.BASEBAND));
mTrafficBasebandRecorder.setSelected(recorders.contains(RecorderType.TRAFFIC_BASEBAND));
mBitstreamRecorder.setSelected(recorders.contains(RecorderType.DEMODULATED_BIT_STREAM));
mTrafficBitstreamRecorder.setSelected(recorders.contains(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM));
}
else
{
setControlsEnabled(false);
}
}
@Override
public void setItem( Channel channel )
{
super.setItem( channel );
if( hasItem() )
{
setControlsEnabled( true );
List<RecorderType> recorders = getItem().getRecordConfiguration().getRecorders();
mAudioRecorder.setSelected( recorders.contains( RecorderType.AUDIO ) );
mBasebandRecorder.setSelected( recorders.contains( RecorderType.BASEBAND ) );
mTrafficBasebandRecorder.setSelected( recorders.contains( RecorderType.TRAFFIC_BASEBAND ) );
}
else
{
setControlsEnabled( false );
}
}
}

View File

@@ -1,60 +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 io.github.dsheirer.record;
import java.io.IOException;
public class Recorder
{
RecorderType mRecorderType;
public Recorder()
{
}
public String getFileName()
{
return "No Recording";
}
public void start() throws IOException
{
}
public void stop() throws IOException
{
}
public void pause()
{
}
public void resume()
{
}
public Recorder( RecorderType type )
{
mRecorderType = type;
}
public RecorderType getRecorderType()
{
return mRecorderType;
}
}

View File

@@ -1,7 +1,6 @@
/*
* *********************************************************************************************************************
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2017 Dennis Sheirer
* Copyright (C) 2014-2018 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
@@ -12,8 +11,8 @@
*
* 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.record;
import io.github.dsheirer.channel.metadata.Metadata;
@@ -29,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -228,13 +228,18 @@ public class RecorderManager implements Listener<ReusableAudioPacket>
return sb.toString();
}
public Path getRecordingBasePath()
{
return SystemProperties.getInstance().getApplicationFolder("recordings");
}
/**
* Constructs a baseband recorder for use in a processing chain.
*/
public ComplexBufferWaveRecorder getBasebandRecorder(String channelName)
{
StringBuilder sb = new StringBuilder();
sb.append(SystemProperties.getInstance().getApplicationFolder("recordings"));
sb.append(getRecordingBasePath());
sb.append(File.separator).append(channelName).append("_baseband");
return new ComplexBufferWaveRecorder(BASEBAND_SAMPLE_RATE, sb.toString());

View File

@@ -1,30 +1,59 @@
/*******************************************************************************
* 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/>
* sdr-trunk
* Copyright (C) 2014-2018 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.record;
import java.util.EnumSet;
/**
* Supported recorder types.
*/
public enum RecorderType
{
/**
* Audio - 8kHz PCM
*/
AUDIO( "Audio (.wav)"),
BASEBAND( "Baseband I/Q (.wav)"),
TRAFFIC_BASEBAND( "Traffic Channel Baseband I/Q (.wav)" );
/**
* Baseband, 16-bit complex inphase/quadrature samples at the channel sample rate.
*/
BASEBAND( "Baseband I/Q (.wav)"),
/**
* Demodulated bit stream at the baud rate of the decoder
*/
DEMODULATED_BIT_STREAM("Demodulated Bitstream (.bits)"),
/**
* Traffic channel baseband, 16-bit complex inphase/quadrature samples at the channel sample rate.
*/
TRAFFIC_BASEBAND( "Traffic Channel Baseband I/Q (.wav)" ),
/**
* Traffic channel demodulated bit stream at the baud rate of the decoder
*/
TRAFFIC_DEMODULATED_BIT_STREAM("Traffic Channel Demodulated Bitstream (.bits)");
private String mDisplayString;
/**
* Recorders available to all decoders
*/
public static final EnumSet<RecorderType> DEFAULT_RECORDER_TYPES = EnumSet.of(AUDIO, BASEBAND, TRAFFIC_BASEBAND);
RecorderType( String displayString )
{
mDisplayString = displayString;

View File

@@ -0,0 +1,199 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.record.binary;
import io.github.dsheirer.dsp.filter.channelizer.ContinuousReusableBufferProcessor;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableByteBufferListener;
import io.github.dsheirer.sample.buffer.ReusableByteBuffer;
import io.github.dsheirer.util.TimeStamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Binary recorder module for recording demodulated bit/byte streams
*
* Designed to record reusable byte buffers generated by a channel decoder.
*
* The contents of the file are the raw bytes as demodulated by the decoder with
* no header or timestamps, other than the timestamp included in the filename.
*/
public class BinaryRecorder extends Module implements IReusableByteBufferListener
{
private final static Logger mLog = LoggerFactory.getLogger(BinaryRecorder.class);
private ContinuousReusableBufferProcessor<ReusableByteBuffer> mBufferProcessor =
new ContinuousReusableBufferProcessor<>(500, 50);
private AtomicBoolean mRunning = new AtomicBoolean();
private Path mBaseRecordingPath;
private String mRecordingIdentifier;
private BinaryWriter mBinaryWriter = new BinaryWriter();
/**
* Constructs a binary recorder.
*
* @param baseRecordingPath where the recording should be created
* @param recordingIdentifier to include in the recording file name.
*/
public BinaryRecorder(Path baseRecordingPath, String recordingIdentifier)
{
mBaseRecordingPath = baseRecordingPath;
mRecordingIdentifier = recordingIdentifier;
mBufferProcessor.setListener(mBinaryWriter);
}
public void start()
{
if(mRunning.compareAndSet(false, true))
{
try
{
mBinaryWriter.start(getRecordingPath());
mBufferProcessor.start();
}
catch(IOException io)
{
mLog.error("Error starting binary baseband recorder", io);
}
}
}
public void stop()
{
if(mRunning.compareAndSet(true, false))
{
if(mBufferProcessor != null)
{
mBufferProcessor.flushAndStop();
mBufferProcessor.setListener(null);
try
{
mBinaryWriter.stop();
}
catch(IOException ioe)
{
mLog.error("Error stopping binary recorder", ioe);
}
}
}
}
/**
* Constructs a recording path/file name using the base path and a timestamped
* filename with the recording identifier.
*
* @return path to use for the recording file
*/
private Path getRecordingPath()
{
StringBuilder sb = new StringBuilder();
sb.append(TimeStamp.getTimeStamp("_"));
sb.append("_");
sb.append(mRecordingIdentifier);
sb.append(".bits");
return mBaseRecordingPath.resolve(sb.toString());
}
@Override
public Listener<ReusableByteBuffer> getReusableByteBufferListener()
{
return mBufferProcessor;
}
@Override
public void dispose()
{
stop();
}
@Override
public void reset()
{
}
/**
* Binary writer implementation for reusable byte buffers delivered from buffer processor
*/
public class BinaryWriter implements Listener<List<ReusableByteBuffer>>
{
private Path mCurrentPath;
private WritableByteChannel mWritableByteChannel;
public void start(Path path) throws IOException
{
mCurrentPath = path;
mWritableByteChannel = Files.newByteChannel(path,
EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE));
}
public void stop() throws IOException
{
if(mWritableByteChannel != null)
{
mWritableByteChannel.close();
}
mWritableByteChannel = null;
mCurrentPath = null;
}
@Override
public void receive(List<ReusableByteBuffer> reusableComplexBuffers)
{
for(ReusableByteBuffer buffer: reusableComplexBuffers)
{
if(mWritableByteChannel != null)
{
try
{
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer.getSamplesCopy());
mWritableByteChannel.write(byteBuffer);
}
catch(IOException ioe)
{
mLog.error("Error recording demodulated bits to file [" +
(mCurrentPath != null ? mCurrentPath.toString() : "no file") + "] - stopping recorder");
try
{
stop();
}
catch(IOException ioe2)
{
mLog.error("Error stopping recorder after write error", ioe2.getLocalizedMessage());
}
}
}
buffer.decrementUserCount();
}
}
}
}

View File

@@ -1,6 +1,6 @@
package io.github.dsheirer.sample;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -56,7 +56,7 @@ public class ConversionUtils
* Converts the float samples in a complex buffer to a little endian 16-bit
* buffer
*/
public static ByteBuffer convertToSigned16BitSamples(ReusableBuffer buffer)
public static ByteBuffer convertToSigned16BitSamples(ReusableFloatBuffer buffer)
{
return convertToSigned16BitSamples(buffer.getSamples());
}

View File

@@ -15,9 +15,9 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public abstract class AbstractSampleAdapter<T extends ReusableBuffer>
public abstract class AbstractSampleAdapter<T extends ReusableFloatBuffer>
{
public abstract T convert(byte[] sampleBytes);
}

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.mixer.MixerChannel;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
@@ -46,10 +46,10 @@ public class RealChannelShortAdapter extends RealSampleAdapter
}
@Override
public ReusableBuffer convert(byte[] samples)
public ReusableFloatBuffer convert(byte[] samples)
{
ReusableBuffer reusableBuffer = getBuffer(samples.length / 4);
float[] convertedSamples = reusableBuffer.getSamples();
ReusableFloatBuffer reusableFloatBuffer = getBuffer(samples.length / 4);
float[] convertedSamples = reusableFloatBuffer.getSamples();
mByteBuffer = ByteBuffer.wrap(samples);
@@ -76,7 +76,7 @@ public class RealChannelShortAdapter extends RealSampleAdapter
}
}
return reusableBuffer;
return reusableFloatBuffer;
}
/**

View File

@@ -15,10 +15,10 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public abstract class RealSampleAdapter extends AbstractSampleAdapter<ReusableBuffer>
public abstract class RealSampleAdapter extends AbstractSampleAdapter<ReusableFloatBuffer>
{
private ReusableBufferQueue mReusableBufferQueue;
@@ -32,7 +32,7 @@ public abstract class RealSampleAdapter extends AbstractSampleAdapter<ReusableBu
mReusableBufferQueue = new ReusableBufferQueue(debugName);
}
protected ReusableBuffer getBuffer(int size)
protected ReusableFloatBuffer getBuffer(int size)
{
return mReusableBufferQueue.getBuffer(size);
}

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -40,10 +40,10 @@ public class RealShortAdapter extends RealSampleAdapter
}
@Override
public ReusableBuffer convert(byte[] samples)
public ReusableFloatBuffer convert(byte[] samples)
{
ReusableBuffer reusableBuffer = getBuffer(samples.length / 2);
float[] convertedSamples = reusableBuffer.getSamples();
ReusableFloatBuffer reusableFloatBuffer = getBuffer(samples.length / 2);
float[] convertedSamples = reusableFloatBuffer.getSamples();
int pointer = 0;
@@ -58,7 +58,7 @@ public class RealShortAdapter extends RealSampleAdapter
pointer++;
}
return reusableBuffer;
return reusableFloatBuffer;
}
/**

View File

@@ -19,5 +19,5 @@ import io.github.dsheirer.sample.Listener;
public interface IReusableBufferListener
{
Listener<ReusableBuffer> getReusableBufferListener();
Listener<ReusableFloatBuffer> getReusableBufferListener();
}

View File

@@ -22,7 +22,7 @@ public interface IReusableBufferProvider
/**
* Adds the listener to receive complex buffer samples
*/
void setBufferListener(Listener<ReusableBuffer> listener);
void setBufferListener(Listener<ReusableFloatBuffer> listener);
/**
* Removes the listener from receiving complex buffer samples

View File

@@ -0,0 +1,23 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.sample.buffer;
import io.github.dsheirer.sample.Listener;
public interface IReusableByteBufferListener<ReusableByteBuffer>
{
Listener<ReusableByteBuffer> getReusableByteBufferListener();
}

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.sample.buffer;
import io.github.dsheirer.sample.Listener;
public interface IReusableByteBufferProvider
{
/**
* Adds the listener to receive complex buffer samples
*/
void setBufferListener(Listener<ReusableByteBuffer> listener);
/**
* Removes the listener from receiving complex buffer samples
*/
void removeBufferListener(Listener<ReusableByteBuffer> listener);
/**
* Indicates if there are any complex buffer listeners registered
*/
boolean hasBufferListeners();
}

View File

@@ -113,16 +113,16 @@ public class ReusableAudioPacket extends AbstractReusableBuffer
* Loads a copy of the float sample data from the reusable buffer into this audio packet, resizing the
* internal audio sample buffer as necessary.
*
* @param reusableBuffer to load audio sample data from
* @param reusableFloatBuffer to load audio sample data from
*/
public void loadAudioFrom(ReusableBuffer reusableBuffer)
public void loadAudioFrom(ReusableFloatBuffer reusableFloatBuffer)
{
if(reusableBuffer.getSamples().length != mAudioSamples.length)
if(reusableFloatBuffer.getSamples().length != mAudioSamples.length)
{
resize(reusableBuffer.getSamples().length);
resize(reusableFloatBuffer.getSamples().length);
}
System.arraycopy(reusableBuffer.getSamples(), 0, mAudioSamples, 0, reusableBuffer.getSamples().length);
System.arraycopy(reusableFloatBuffer.getSamples(), 0, mAudioSamples, 0, reusableFloatBuffer.getSamples().length);
}
/**

View File

@@ -19,16 +19,16 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.RealSampleListener;
/**
* Assembles single float samples into a ReusableBuffer containing an array of floats
* Assembles single float samples into a ReusableFloatBuffer containing an array of floats
*/
public class ReusableBufferAssembler implements RealSampleListener
{
private int mBufferSize;
private int mBufferPointer;
private ReusableBuffer mCurrentBuffer;
private ReusableFloatBuffer mCurrentBuffer;
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("Real");
private Listener<ReusableBuffer> mListener;
private Listener<ReusableFloatBuffer> mListener;
public ReusableBufferAssembler(int bufferSize)
{
@@ -73,7 +73,7 @@ public class ReusableBufferAssembler implements RealSampleListener
}
}
public void setListener(Listener<ReusableBuffer> listener)
public void setListener(Listener<ReusableFloatBuffer> listener)
{
mListener = listener;
}

View File

@@ -18,7 +18,7 @@ package io.github.dsheirer.sample.buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableBuffer>
public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableFloatBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferQueue.class);
@@ -35,13 +35,13 @@ public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableBuf
* @param size of the samples that will be loaded into the buffer
* @return a reusable buffer
*/
public ReusableBuffer getBuffer(int size)
public ReusableFloatBuffer getBuffer(int size)
{
ReusableBuffer buffer = getRecycledBuffer();
ReusableFloatBuffer buffer = getRecycledBuffer();
if(buffer == null)
{
buffer = new ReusableBuffer(this, new float[size]);
buffer = new ReusableFloatBuffer(this, new float[size]);
buffer.setDebugName("Owner:" + getDebugName());
incrementBufferCount();
}

View File

@@ -0,0 +1,97 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.sample.buffer;
import org.apache.commons.lang3.Validate;
public class ReusableByteBuffer extends AbstractReusableBuffer
{
private byte[] mSamples;
/**
* Creates a reusable, timestamped byte buffer using the specified time in milliseconds.
*
* NOTE: reusability of this buffer requires strict user count tracking. Each component that receives this
* buffer should not modify the buffer contents. Each component should also increment the user count before
* sending this buffer to another component and should decrement the user count when finished using this buffer.
*
* @param bufferDisposedListener to be notified when all consumers/users are finished using the buffer
* @param bytes of data
* @param timestamp in millis for the buffer
*/
ReusableByteBuffer(IReusableBufferDisposedListener bufferDisposedListener, byte[] bytes, long timestamp)
{
super(bufferDisposedListener, timestamp);
mSamples = bytes;
Validate.notNull(bufferDisposedListener, "Reusable Byte Buffer Listener cannot be null");
}
/**
* Constructs a timestamped byte buffer using the current system time in milliseconds.
*
* NOTE: reusability of this buffer requires strict user count tracking. Each component that receives this
* buffer should not modify the buffer contents. Each component should also increment the user count before
* sending this buffer to another component and should decrement the user count when finished using this buffer.
*
* @param bufferDisposedListener to be notified when all consumers are finished using the buffer
* @param bytes of data
*/
public ReusableByteBuffer(IReusableBufferDisposedListener bufferDisposedListener, byte[] bytes)
{
this(bufferDisposedListener, bytes, System.currentTimeMillis());
}
/**
* Samples for this buffer
*/
public byte[] getBytes()
{
return mSamples;
}
/**
* Creates a copy of the samples from this buffer
*/
public byte[] getSamplesCopy()
{
byte[] bytes = getBytes();
byte[] copy = new byte[bytes.length];
System.arraycopy(bytes, 0, copy, 0, bytes.length);
return copy;
}
/**
* Number of bytes contained in this buffer
*/
public int getSampleCount()
{
return getBytes().length;
}
/**
* Resizes the internal array to the size argument
*
* @param size for the internal array
*/
protected void resize(int size)
{
if(mSamples.length != size)
{
mSamples = new byte[size];
}
}
}

View File

@@ -0,0 +1,54 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.sample.buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReusableByteBufferQueue extends AbstractReusableBufferQueue<ReusableByteBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(ReusableByteBufferQueue.class);
public ReusableByteBufferQueue(String debugName)
{
super(debugName);
}
/**
* Returns a reusable buffer from an internal recycling queue, or creates a new buffer if there are currently no
* buffers available for reuse. The user count is set to one and must be managed throughout the lifecycle
* of the buffer.
*
* @param size of the samples that will be loaded into the buffer
* @return a reusable buffer
*/
public ReusableByteBuffer getBuffer(int size)
{
ReusableByteBuffer buffer = getRecycledBuffer();
if(buffer == null)
{
buffer = new ReusableByteBuffer(this, new byte[size]);
buffer.setDebugName("Owner:" + getDebugName());
incrementBufferCount();
}
buffer.resize(size);
buffer.incrementUserCount();
return buffer;
}
}

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.sample.buffer;
public class ReusableComplexBuffer extends ReusableBuffer
public class ReusableComplexBuffer extends ReusableFloatBuffer
{
/**
* Creates a reusable, timestamped complex buffer using the specified time in milliseconds.

View File

@@ -19,7 +19,7 @@ import org.apache.commons.lang3.Validate;
import java.nio.FloatBuffer;
public class ReusableBuffer extends AbstractReusableBuffer
public class ReusableFloatBuffer extends AbstractReusableBuffer
{
private float[] mSamples;
@@ -34,7 +34,7 @@ public class ReusableBuffer extends AbstractReusableBuffer
* @param samples of data
* @param timestamp in millis for the buffer
*/
ReusableBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples, long timestamp)
ReusableFloatBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples, long timestamp)
{
super(bufferDisposedListener, timestamp);
mSamples = samples;
@@ -79,7 +79,7 @@ public class ReusableBuffer extends AbstractReusableBuffer
* @param bufferDisposedListener to be notified when all consumers are finished using the buffer
* @param samples of data
*/
public ReusableBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples)
public ReusableFloatBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples)
{
this(bufferDisposedListener, samples, System.currentTimeMillis());
}

View File

@@ -2,10 +2,10 @@ package io.github.dsheirer.source;
import io.github.dsheirer.sample.Provider;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public abstract class RealSource extends Source implements Provider<ReusableBuffer>
public abstract class RealSource extends Source implements Provider<ReusableFloatBuffer>
{
@Override
public SampleType getSampleType()

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.source.mixer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.adapter.AbstractSampleAdapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.heartbeat.HeartbeatManager;
import io.github.dsheirer.util.ThreadPool;
@@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* the samples to an array of floats using the specified adapter. Dispatches float arrays to the registered
* buffer listener.
*/
public class MixerReader<T extends ReusableBuffer> implements Runnable
public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
{
private final static Logger mLog = LoggerFactory.getLogger(MixerReader.class);

View File

@@ -17,7 +17,7 @@ package io.github.dsheirer.source.mixer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.adapter.AbstractSampleAdapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.RealSource;
import io.github.dsheirer.source.SourceEvent;
@@ -101,7 +101,7 @@ public class RealMixerSource extends RealSource
/**
* Sets the listener to receive sample data in reusable buffers.
*/
public void setListener(Listener<ReusableBuffer> listener)
public void setListener(Listener<ReusableFloatBuffer> listener)
{
mMixerReader.setBufferListener(listener);
}
@@ -110,7 +110,7 @@ public class RealMixerSource extends RealSource
* Removes the listener from receiving sample data.
* @param listener
*/
public void removeListener(Listener<ReusableBuffer> listener)
public void removeListener(Listener<ReusableFloatBuffer> listener)
{
mMixerReader.removeBufferListener();
}

View File

@@ -19,8 +19,8 @@ package io.github.dsheirer.source.wave;
import io.github.dsheirer.sample.ConversionUtils;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.IControllableFileSource;
import io.github.dsheirer.source.IFrameLocationListener;
import io.github.dsheirer.source.RealSource;
@@ -45,7 +45,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
private int mBytesPerFrame;
private int mFrameCounter = 0;
private long mFrequency = 0;
private Listener<ReusableBuffer> mListener;
private Listener<ReusableFloatBuffer> mListener;
private AudioInputStream mInputStream;
private File mFile;
@@ -230,10 +230,10 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
ReusableBuffer reusableBuffer = mReusableBufferQueue.getBuffer(samples.length);
reusableBuffer.reloadFrom(samples, System.currentTimeMillis());
ReusableFloatBuffer reusableFloatBuffer = mReusableBufferQueue.getBuffer(samples.length);
reusableFloatBuffer.reloadFrom(samples, System.currentTimeMillis());
mListener.receive(reusableBuffer);
mListener.receive(reusableFloatBuffer);
}
}
}
@@ -242,7 +242,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
* Registers the listener to receive sample buffers as they are read from the wave file
*/
@Override
public void setListener(Listener<ReusableBuffer> listener)
public void setListener(Listener<ReusableFloatBuffer> listener)
{
mListener = listener;
}
@@ -251,7 +251,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
* Unregisters the listener from receiving sample buffers
*/
@Override
public void removeListener(Listener<ReusableBuffer> listener)
public void removeListener(Listener<ReusableFloatBuffer> listener)
{
mListener = null;
}

View File

@@ -26,9 +26,9 @@ import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
import io.github.dsheirer.settings.ColorSettingMenuItem;
import io.github.dsheirer.settings.Setting;
@@ -60,7 +60,7 @@ import java.awt.event.MouseMotionListener;
import java.util.concurrent.atomic.AtomicBoolean;
public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener,
Listener<ReusableBuffer>, SettingChangeListener, SpectralDisplayAdjuster
Listener<ReusableFloatBuffer>, SettingChangeListener, SpectralDisplayAdjuster
{
private static final long serialVersionUID = 1L;
@@ -267,9 +267,9 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
}
@Override
public void receive(ReusableBuffer buffer)
public void receive(ReusableFloatBuffer buffer)
{
ReusableBuffer decimated = mDecimatingFilter.filter(buffer);
ReusableFloatBuffer decimated = mDecimatingFilter.filter(buffer);
//Hack: we're placing real samples in a complex buffer that the DFT
//processor is expecting.