From 5f8f2ec33096b8e06e8b42c62345ef201d64fb9e Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 11 Aug 2018 08:02:58 -0400 Subject: [PATCH] Resolves #393 - Adds support for recording demodulated (raw) bitstream buffers. None of the decoders currently support this yet, but the P25 will be updated to provide bitstream output for recording. Renames the ReusableBuffer class to ReusableFloatBuffer for consistency. --- .../io/github/dsheirer/audio/AudioModule.java | 10 +- .../channel/ChannelProcessingManager.java | 20 ++ .../dsheirer/dsp/afsk/AFSK1200Decoder.java | 20 +- .../github/dsheirer/dsp/am/AMDemodulator.java | 10 +- .../ContinuousBufferProcessor.java | 56 +++- .../ContinuousReusableBufferProcessor.java | 4 +- .../dsp/filter/cic/RealPrimeCICDecimate.java | 20 +- .../dsp/filter/dc/BufferDCFilter.java | 6 +- .../dsp/filter/dc/DCRemovalFilter.java | 6 +- .../dc/IIRSinglePoleDCRemovalFilter.java | 6 +- .../dsp/filter/fir/real/RealFIRFilter2.java | 6 +- .../filter/halfband/real/HalfBandFilter.java | 6 +- .../dsp/filter/resample/RealResampler.java | 20 +- .../github/dsheirer/dsp/fm/FMDemodulator.java | 6 +- .../github/dsheirer/dsp/fsk/LTRDecoder.java | 10 +- .../dsp/gain/AutomaticGainControl.java | 6 +- .../dsp/mixer/AbstractOscillator.java | 8 +- .../dsheirer/dsp/mixer/IOscillator.java | 6 +- .../gui/instrument/PlaybackController.java | 6 +- .../instrument/chart/RealSampleLineChart.java | 6 +- .../decoder/AbstractAFSK1200Pane.java | 4 +- .../decoder/AbstractDecoderPane.java | 4 +- .../instrument/decoder/RealDecoderPane.java | 12 +- .../dsheirer/module/ProcessingChain.java | 35 ++- .../module/decode/DecoderFactory.java | 14 + .../decode/afsk/AbstractAFSKDecoder.java | 10 +- .../Fleetsync2DecoderInstrumented.java | 6 +- .../lj1200/LJ1200DecoderInstrumented.java | 6 +- .../module/decode/ltrnet/LTRNetDecoder.java | 10 +- .../ltrnet/LTRNetDecoderInstrumented.java | 6 +- .../ltrstandard/LTRStandardDecoder.java | 10 +- .../mdc1200/MDCDecoderInstrumented.java | 6 +- .../mpt1327/MPT1327DecoderInstrumented.java | 6 +- .../module/decode/p25/C4FMSymbolFilter.java | 6 +- .../decode/passport/PassportDecoder.java | 10 +- .../tait/Tait1200DecoderInstrumented.java | 6 +- .../demodulate/am/AMDemodulatorModule.java | 18 +- .../demodulate/fm/FMDemodulatorModule.java | 16 +- .../record/RecordConfigurationEditor.java | 258 +++++++++++------- .../io/github/dsheirer/record/Recorder.java | 60 ---- .../dsheirer/record/RecorderManager.java | 18 ++ .../github/dsheirer/record/RecorderType.java | 67 +++-- .../record/binary/BinaryRecorder.java | 199 ++++++++++++++ .../dsheirer/sample/ConversionUtils.java | 4 +- .../sample/adapter/AbstractSampleAdapter.java | 4 +- .../adapter/RealChannelShortAdapter.java | 10 +- .../sample/adapter/RealSampleAdapter.java | 6 +- .../sample/adapter/RealShortAdapter.java | 10 +- .../buffer/IReusableBufferListener.java | 2 +- .../buffer/IReusableBufferProvider.java | 2 +- .../buffer/IReusableByteBufferListener.java | 23 ++ .../buffer/IReusableByteBufferProvider.java | 36 +++ .../sample/buffer/ReusableAudioPacket.java | 10 +- .../buffer/ReusableBufferAssembler.java | 8 +- .../sample/buffer/ReusableBufferQueue.java | 8 +- .../sample/buffer/ReusableByteBuffer.java | 97 +++++++ .../buffer/ReusableByteBufferQueue.java | 54 ++++ .../sample/buffer/ReusableComplexBuffer.java | 2 +- ...leBuffer.java => ReusableFloatBuffer.java} | 6 +- .../io/github/dsheirer/source/RealSource.java | 4 +- .../dsheirer/source/mixer/MixerReader.java | 4 +- .../source/mixer/RealMixerSource.java | 6 +- .../dsheirer/source/wave/RealWaveSource.java | 14 +- .../spectrum/ChannelSpectrumPanel.java | 8 +- 64 files changed, 936 insertions(+), 407 deletions(-) delete mode 100644 src/main/java/io/github/dsheirer/record/Recorder.java create mode 100644 src/main/java/io/github/dsheirer/record/binary/BinaryRecorder.java create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferListener.java create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferProvider.java create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/ReusableByteBuffer.java create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/ReusableByteBufferQueue.java rename src/main/java/io/github/dsheirer/sample/buffer/{ReusableBuffer.java => ReusableFloatBuffer.java} (94%) diff --git a/src/main/java/io/github/dsheirer/audio/AudioModule.java b/src/main/java/io/github/dsheirer/audio/AudioModule.java index b11f8cb0..5e60c0ca 100644 --- a/src/main/java/io/github/dsheirer/audio/AudioModule.java +++ b/src/main/java/io/github/dsheirer/audio/AudioModule.java @@ -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 + ISquelchStateListener, Listener { 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(); } } diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java index 7ef918d3..dac3da29 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java @@ -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); diff --git a/src/main/java/io/github/dsheirer/dsp/afsk/AFSK1200Decoder.java b/src/main/java/io/github/dsheirer/dsp/afsk/AFSK1200Decoder.java index fb673981..1602986a 100644 --- a/src/main/java/io/github/dsheirer/dsp/afsk/AFSK1200Decoder.java +++ b/src/main/java/io/github/dsheirer/dsp/afsk/AFSK1200Decoder.java @@ -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 +public class AFSK1200Decoder implements Listener { private final static Logger mLog = LoggerFactory.getLogger(AFSK1200Decoder.class); @@ -110,7 +110,7 @@ public class AFSK1200Decoder implements Listener * @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 } - public class Decoder implements Listener + public class Decoder implements Listener { @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 * 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; diff --git a/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator.java b/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator.java index 0ca45fb3..bec59588 100644 --- a/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator.java +++ b/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator.java @@ -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; } } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java index 0ee7e268..75835c57 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java @@ -136,6 +136,46 @@ public class ContinuousBufferProcessor implements Listener } } + /** + * 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 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 implements Listener @Override public void run() { - List 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(); } } } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousReusableBufferProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousReusableBufferProcessor.java index 0439fb11..57f9f2fb 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousReusableBufferProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousReusableBufferProcessor.java @@ -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 extends ContinuousBufferProcessor +public class ContinuousReusableBufferProcessor extends ContinuousBufferProcessor { /** * Scheduled Reusable Buffer Processor combines an internal overflowable buffer with a scheduled runnable processing diff --git a/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java b/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java index 87b444b7..07c5c8ee 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java @@ -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 listener) + public void setListener(Listener 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 mReusableBufferListener; + private Listener 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() + mAssembler.setListener(new Listener() { @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 listener) + public void setListener(Listener listener) { mReusableBufferListener = listener; } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/dc/BufferDCFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/dc/BufferDCFilter.java index d9f2d25c..8d8c997a 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/dc/BufferDCFilter.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/dc/BufferDCFilter.java @@ -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); diff --git a/src/main/java/io/github/dsheirer/dsp/filter/dc/DCRemovalFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/dc/DCRemovalFilter.java index 4f7f2be4..8a54141f 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/dc/DCRemovalFilter.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/dc/DCRemovalFilter.java @@ -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(); diff --git a/src/main/java/io/github/dsheirer/dsp/filter/dc/IIRSinglePoleDCRemovalFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/dc/IIRSinglePoleDCRemovalFilter.java index d11d8035..b980b02f 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/dc/IIRSinglePoleDCRemovalFilter.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/dc/IIRSinglePoleDCRemovalFilter.java @@ -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(); diff --git a/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter2.java b/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter2.java index 67f5a7e3..75e209b0 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter2.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter2.java @@ -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++) diff --git a/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java index da71b64c..0f52b780 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java @@ -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++) diff --git a/src/main/java/io/github/dsheirer/dsp/filter/resample/RealResampler.java b/src/main/java/io/github/dsheirer/dsp/filter/resample/RealResampler.java index 3565b094..949ebea7 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/resample/RealResampler.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/resample/RealResampler.java @@ -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 mResampledListener; + private Listener 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 resampledBufferListener) + public void setListener(Listener 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()); diff --git a/src/main/java/io/github/dsheirer/dsp/fm/FMDemodulator.java b/src/main/java/io/github/dsheirer/dsp/fm/FMDemodulator.java index 642f5d87..2dd550ea 100644 --- a/src/main/java/io/github/dsheirer/dsp/fm/FMDemodulator.java +++ b/src/main/java/io/github/dsheirer/dsp/fm/FMDemodulator.java @@ -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(); diff --git a/src/main/java/io/github/dsheirer/dsp/fsk/LTRDecoder.java b/src/main/java/io/github/dsheirer/dsp/fsk/LTRDecoder.java index cde125aa..cda51b67 100644 --- a/src/main/java/io/github/dsheirer/dsp/fsk/LTRDecoder.java +++ b/src/main/java/io/github/dsheirer/dsp/fsk/LTRDecoder.java @@ -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, ISyncDetectListener, ISyncStateListener +public class LTRDecoder implements Listener, ISyncDetectListener, ISyncStateListener { private final static Logger mLog = LoggerFactory.getLogger(LTRDecoder.class); @@ -148,10 +148,10 @@ public class LTRDecoder implements Listener, 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()) { diff --git a/src/main/java/io/github/dsheirer/dsp/gain/AutomaticGainControl.java b/src/main/java/io/github/dsheirer/dsp/gain/AutomaticGainControl.java index 63ef04e6..a8533d97 100644 --- a/src/main/java/io/github/dsheirer/dsp/gain/AutomaticGainControl.java +++ b/src/main/java/io/github/dsheirer/dsp/gain/AutomaticGainControl.java @@ -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(); diff --git a/src/main/java/io/github/dsheirer/dsp/mixer/AbstractOscillator.java b/src/main/java/io/github/dsheirer/dsp/mixer/AbstractOscillator.java index fa012fe4..144ff1a4 100644 --- a/src/main/java/io/github/dsheirer/dsp/mixer/AbstractOscillator.java +++ b/src/main/java/io/github/dsheirer/dsp/mixer/AbstractOscillator.java @@ -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()); } } diff --git a/src/main/java/io/github/dsheirer/dsp/mixer/IOscillator.java b/src/main/java/io/github/dsheirer/dsp/mixer/IOscillator.java index 2d0b4930..5546bff7 100644 --- a/src/main/java/io/github/dsheirer/dsp/mixer/IOscillator.java +++ b/src/main/java/io/github/dsheirer/dsp/mixer/IOscillator.java @@ -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. diff --git a/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java b/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java index a679fafc..a12f75c7 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java @@ -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 listener) + public void addListener(Listener 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 listener) + public void removeListener(Listener listener) { mReusableBufferBroadcaster.removeListener(listener); } diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java index a914bc2a..708518f3 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java @@ -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 +public class RealSampleLineChart extends LineChart implements Listener { private final static Logger mLog = LoggerFactory.getLogger(RealSampleLineChart.class); private ObservableList> mSamples = FXCollections.observableArrayList(); @@ -65,7 +65,7 @@ public class RealSampleLineChart extends LineChart implements Listener)getDecoder()); + addListener((Listener)getDecoder()); addListener(getSampleLineChart()); diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java index 64324438..5c324989 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java @@ -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 extends VBox implements Listener +public abstract class AbstractDecoderPane extends VBox implements Listener { abstract SampleType getSampleType(); diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java index afc05786..1b2f15f1 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java @@ -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 +public class RealDecoderPane extends AbstractDecoderPane { private ReusableBufferBroadcaster mBufferBroadcaster = new ReusableBufferBroadcaster(); private DecoderType mDecoderType; @@ -47,17 +47,17 @@ public class RealDecoderPane extends AbstractDecoderPane } @Override - public void receive(ReusableBuffer reusableBuffer) + public void receive(ReusableFloatBuffer reusableFloatBuffer) { - mBufferBroadcaster.broadcast(reusableBuffer); + mBufferBroadcaster.broadcast(reusableFloatBuffer); } - public void addListener(Listener listener) + public void addListener(Listener listener) { mBufferBroadcaster.addListener(listener); } - public void removeListener(Listener listener) + public void removeListener(Listener listener) { mBufferBroadcaster.removeListener(listener); } diff --git a/src/main/java/io/github/dsheirer/module/ProcessingChain.java b/src/main/java/io/github/dsheirer/module/ProcessingChain.java index c517a9b7..8b4cd8aa 100644 --- a/src/main/java/io/github/dsheirer/module/ProcessingChain.java +++ b/src/main/java/io/github/dsheirer/module/ProcessingChain.java @@ -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 mAudioPacketBroadcaster = new ReusableBufferBroadcaster<>(); - private ReusableBufferBroadcaster mDemodulatedAudioBufferBroadcaster = new ReusableBufferBroadcaster(); + private ReusableBufferBroadcaster mDemodulatedAudioBufferBroadcaster = new ReusableBufferBroadcaster(); private ReusableBufferBroadcaster mBasebandComplexBufferBroadcaster = new ReusableBufferBroadcaster(); + private ReusableBufferBroadcaster mDemodulatedBitstreamBufferBroadcaster = new ReusableBufferBroadcaster(); private Broadcaster mAttributeChangeRequestBroadcaster = new Broadcaster<>(); private Broadcaster mCallEventBroadcaster = new Broadcaster<>(); private Broadcaster 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 listener) + public void addDemodulatedAudioListener(Listener 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 listener) + public void removeDemodulatedAudioListener(Listener listener) { mDemodulatedAudioBufferBroadcaster.removeListener(listener); } diff --git a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java index d12e489d..0218aed5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java @@ -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 getBitstreamDecoders() + { +// return EnumSet.of(DecoderType.P25_PHASE1); + + //None of the decoders currently support bitstream output. + return EnumSet.noneOf(DecoderType.class); + } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/module/decode/afsk/AbstractAFSKDecoder.java b/src/main/java/io/github/dsheirer/module/decode/afsk/AbstractAFSKDecoder.java index 466642e9..ffa4f6e1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/afsk/AbstractAFSKDecoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/afsk/AbstractAFSKDecoder.java @@ -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 +public abstract class AbstractAFSKDecoder extends Decoder implements IReusableBufferListener, Listener { 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 getReusableBufferListener() + public Listener getReusableBufferListener() { return this; } diff --git a/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderInstrumented.java index 481c2f26..894d22c7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderInstrumented.java @@ -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); } diff --git a/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderInstrumented.java index b86661ee..735dd2d7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderInstrumented.java @@ -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); } diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoder.java b/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoder.java index b1d35001..8d749bb5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoder.java @@ -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 +public class LTRNetDecoder extends Decoder implements IReusableBufferListener, Listener { 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 getReusableBufferListener() + public Listener getReusableBufferListener() { return mLTRDecoder; } @Override - public void receive(ReusableBuffer reusableBuffer) + public void receive(ReusableFloatBuffer reusableFloatBuffer) { - mLTRDecoder.receive(reusableBuffer); + mLTRDecoder.receive(reusableFloatBuffer); } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderInstrumented.java index b8970362..ea0e279b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderInstrumented.java @@ -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); } diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoder.java b/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoder.java index 89043350..212cf5c7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoder.java @@ -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 +public class LTRStandardDecoder extends Decoder implements IReusableBufferListener, Listener { public static final int LTR_STANDARD_MESSAGE_LENGTH = 40; @@ -65,15 +65,15 @@ public class LTRStandardDecoder extends Decoder implements IReusableBufferListen } @Override - public Listener getReusableBufferListener() + public Listener getReusableBufferListener() { return mLTRDecoder; } @Override - public void receive(ReusableBuffer reusableBuffer) + public void receive(ReusableFloatBuffer reusableFloatBuffer) { - mLTRDecoder.receive(reusableBuffer); + mLTRDecoder.receive(reusableFloatBuffer); } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderInstrumented.java index a3b90632..526c5c3f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderInstrumented.java @@ -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); } diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderInstrumented.java index 8ef42fce..eb6d31ac 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderInstrumented.java @@ -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); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java index 7d5d4462..3ad8e86b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java @@ -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, ISourceEventListener, RealSampleProvider +public class C4FMSymbolFilter implements Listener, ISourceEventListener, RealSampleProvider { private static final float TAPS[][] = { @@ -215,7 +215,7 @@ public class C4FMSymbolFilter implements Listener, ISourceEventL } @Override - public void receive(ReusableBuffer buffer) + public void receive(ReusableFloatBuffer buffer) { for(float sample : buffer.getSamples()) { diff --git a/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoder.java b/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoder.java index cc30e36b..ab94e76a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoder.java @@ -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 +public class PassportDecoder extends Decoder implements IReusableBufferListener, Listener { public static final int PASSPORT_MESSAGE_LENGTH = 68; @@ -52,15 +52,15 @@ public class PassportDecoder extends Decoder implements IReusableBufferListener, } @Override - public Listener getReusableBufferListener() + public Listener getReusableBufferListener() { return mLTRDecoder; } @Override - public void receive(ReusableBuffer reusableBuffer) + public void receive(ReusableFloatBuffer reusableFloatBuffer) { - mLTRDecoder.receive(reusableBuffer); + mLTRDecoder.receive(reusableFloatBuffer); } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderInstrumented.java index b4f7eab4..66f3100b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderInstrumented.java @@ -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); } diff --git a/src/main/java/io/github/dsheirer/module/demodulate/am/AMDemodulatorModule.java b/src/main/java/io/github/dsheirer/module/demodulate/am/AMDemodulatorModule.java index e216fd11..1eda7cb2 100644 --- a/src/main/java/io/github/dsheirer/module/demodulate/am/AMDemodulatorModule.java +++ b/src/main/java/io/github/dsheirer/module/demodulate/am/AMDemodulatorModule.java @@ -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 mResampledReusableBufferListener; + private Listener 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 listener) + public void setBufferListener(Listener 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() + mResampler.setListener(new Listener() { @Override - public void receive(ReusableBuffer resampledAudioBuffer) + public void receive(ReusableFloatBuffer resampledAudioBuffer) { processResampledAudio(resampledAudioBuffer); } diff --git a/src/main/java/io/github/dsheirer/module/demodulate/fm/FMDemodulatorModule.java b/src/main/java/io/github/dsheirer/module/demodulate/fm/FMDemodulatorModule.java index 7dfc7a6e..4fa81782 100644 --- a/src/main/java/io/github/dsheirer/module/demodulate/fm/FMDemodulatorModule.java +++ b/src/main/java/io/github/dsheirer/module/demodulate/fm/FMDemodulatorModule.java @@ -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 mResampledReusableBufferListener; + private Listener mResampledReusableBufferListener; private double mChannelBandwidth; private double mOutputSampleRate; @@ -106,7 +106,7 @@ public class FMDemodulatorModule extends Module implements ISourceEventListener, } @Override - public void setBufferListener(Listener listener) + public void setBufferListener(Listener 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() + mResampler.setListener(new Listener() { @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(); } } }); diff --git a/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java b/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java index 1dab9ba3..220cc33e 100644 --- a/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java @@ -1,17 +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 ******************************************************************************/ @@ -22,7 +22,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 +30,169 @@ import java.util.List; public class RecordConfigurationEditor extends Editor { 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 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 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 ); - } - } } diff --git a/src/main/java/io/github/dsheirer/record/Recorder.java b/src/main/java/io/github/dsheirer/record/Recorder.java deleted file mode 100644 index b91663ff..00000000 --- a/src/main/java/io/github/dsheirer/record/Recorder.java +++ /dev/null @@ -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 - ******************************************************************************/ -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; - } -} diff --git a/src/main/java/io/github/dsheirer/record/RecorderManager.java b/src/main/java/io/github/dsheirer/record/RecorderManager.java index d6351867..2070c050 100644 --- a/src/main/java/io/github/dsheirer/record/RecorderManager.java +++ b/src/main/java/io/github/dsheirer/record/RecorderManager.java @@ -29,6 +29,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,6 +229,11 @@ public class RecorderManager implements Listener return sb.toString(); } + public Path getRecordingBasePath() + { + return SystemProperties.getInstance().getApplicationFolder("recordings"); + } + /** * Constructs a baseband recorder for use in a processing chain. */ @@ -240,6 +246,18 @@ public class RecorderManager implements Listener return new ComplexBufferWaveRecorder(BASEBAND_SAMPLE_RATE, sb.toString()); } + /** + * Constructs a baseband recorder for use in a processing chain. + */ + public ComplexBufferWaveRecorder getBitstreamRecorder(String channelName) + { + StringBuilder sb = new StringBuilder(); + sb.append(SystemProperties.getInstance().getApplicationFolder("recordings")); + sb.append(File.separator).append(channelName).append("_bitstream"); + + return new ComplexBufferWaveRecorder(BASEBAND_SAMPLE_RATE, sb.toString()); + } + /** * Processes queued audio packets and distributes to each of the audio recorders. Removes any idle recorders * that have not been updated according to an idle threshold period diff --git a/src/main/java/io/github/dsheirer/record/RecorderType.java b/src/main/java/io/github/dsheirer/record/RecorderType.java index fe294126..1921cad4 100644 --- a/src/main/java/io/github/dsheirer/record/RecorderType.java +++ b/src/main/java/io/github/dsheirer/record/RecorderType.java @@ -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 + * 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 + * ******************************************************************************/ 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 DEFAULT_RECORDER_TYPES = EnumSet.of(AUDIO, BASEBAND, TRAFFIC_BASEBAND); + RecorderType( String displayString ) { mDisplayString = displayString; diff --git a/src/main/java/io/github/dsheirer/record/binary/BinaryRecorder.java b/src/main/java/io/github/dsheirer/record/binary/BinaryRecorder.java new file mode 100644 index 00000000..a1f000a7 --- /dev/null +++ b/src/main/java/io/github/dsheirer/record/binary/BinaryRecorder.java @@ -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 + * + ******************************************************************************/ +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 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 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> + { + 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 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(); + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/sample/ConversionUtils.java b/src/main/java/io/github/dsheirer/sample/ConversionUtils.java index 57b08bd8..5a48ed61 100644 --- a/src/main/java/io/github/dsheirer/sample/ConversionUtils.java +++ b/src/main/java/io/github/dsheirer/sample/ConversionUtils.java @@ -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()); } diff --git a/src/main/java/io/github/dsheirer/sample/adapter/AbstractSampleAdapter.java b/src/main/java/io/github/dsheirer/sample/adapter/AbstractSampleAdapter.java index b2db661c..9bc4bfe6 100644 --- a/src/main/java/io/github/dsheirer/sample/adapter/AbstractSampleAdapter.java +++ b/src/main/java/io/github/dsheirer/sample/adapter/AbstractSampleAdapter.java @@ -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 +public abstract class AbstractSampleAdapter { public abstract T convert(byte[] sampleBytes); } diff --git a/src/main/java/io/github/dsheirer/sample/adapter/RealChannelShortAdapter.java b/src/main/java/io/github/dsheirer/sample/adapter/RealChannelShortAdapter.java index b7f685fc..522fd879 100644 --- a/src/main/java/io/github/dsheirer/sample/adapter/RealChannelShortAdapter.java +++ b/src/main/java/io/github/dsheirer/sample/adapter/RealChannelShortAdapter.java @@ -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; } /** diff --git a/src/main/java/io/github/dsheirer/sample/adapter/RealSampleAdapter.java b/src/main/java/io/github/dsheirer/sample/adapter/RealSampleAdapter.java index afbe0c7f..70d05bcd 100644 --- a/src/main/java/io/github/dsheirer/sample/adapter/RealSampleAdapter.java +++ b/src/main/java/io/github/dsheirer/sample/adapter/RealSampleAdapter.java @@ -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 +public abstract class RealSampleAdapter extends AbstractSampleAdapter { private ReusableBufferQueue mReusableBufferQueue; @@ -32,7 +32,7 @@ public abstract class RealSampleAdapter extends AbstractSampleAdapter getReusableBufferListener(); + Listener getReusableBufferListener(); } diff --git a/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java b/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java index f2333731..41795f92 100644 --- a/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java @@ -22,7 +22,7 @@ public interface IReusableBufferProvider /** * Adds the listener to receive complex buffer samples */ - void setBufferListener(Listener listener); + void setBufferListener(Listener listener); /** * Removes the listener from receiving complex buffer samples diff --git a/src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferListener.java b/src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferListener.java new file mode 100644 index 00000000..2aba9f9a --- /dev/null +++ b/src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferListener.java @@ -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 + * + ******************************************************************************/ +package io.github.dsheirer.sample.buffer; + +import io.github.dsheirer.sample.Listener; + +public interface IReusableByteBufferListener +{ + Listener getReusableByteBufferListener(); +} diff --git a/src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferProvider.java b/src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferProvider.java new file mode 100644 index 00000000..e84db05c --- /dev/null +++ b/src/main/java/io/github/dsheirer/sample/buffer/IReusableByteBufferProvider.java @@ -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 + * + ******************************************************************************/ +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 listener); + + /** + * Removes the listener from receiving complex buffer samples + */ + void removeBufferListener(Listener listener); + + /** + * Indicates if there are any complex buffer listeners registered + */ + boolean hasBufferListeners(); +} diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableAudioPacket.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableAudioPacket.java index ec878c86..c64e6f98 100644 --- a/src/main/java/io/github/dsheirer/sample/buffer/ReusableAudioPacket.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableAudioPacket.java @@ -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); } /** diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java index fd1bdd14..59fda806 100644 --- a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java @@ -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 mListener; + private Listener mListener; public ReusableBufferAssembler(int bufferSize) { @@ -73,7 +73,7 @@ public class ReusableBufferAssembler implements RealSampleListener } } - public void setListener(Listener listener) + public void setListener(Listener listener) { mListener = listener; } diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java index 4c00f2e1..229b9387 100644 --- a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java @@ -18,7 +18,7 @@ package io.github.dsheirer.sample.buffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ReusableBufferQueue extends AbstractReusableBufferQueue +public class ReusableBufferQueue extends AbstractReusableBufferQueue { private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferQueue.class); @@ -35,13 +35,13 @@ public class ReusableBufferQueue extends AbstractReusableBufferQueue + * + ******************************************************************************/ +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]; + } + } +} diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableByteBufferQueue.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableByteBufferQueue.java new file mode 100644 index 00000000..b322097e --- /dev/null +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableByteBufferQueue.java @@ -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 + * + ******************************************************************************/ +package io.github.dsheirer.sample.buffer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReusableByteBufferQueue extends AbstractReusableBufferQueue +{ + 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; + } +} diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java index bc768d7c..80455474 100644 --- a/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java @@ -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. diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBuffer.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableFloatBuffer.java similarity index 94% rename from src/main/java/io/github/dsheirer/sample/buffer/ReusableBuffer.java rename to src/main/java/io/github/dsheirer/sample/buffer/ReusableFloatBuffer.java index d8d15f6d..ba66b323 100644 --- a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBuffer.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableFloatBuffer.java @@ -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()); } diff --git a/src/main/java/io/github/dsheirer/source/RealSource.java b/src/main/java/io/github/dsheirer/source/RealSource.java index 1b61efcd..a84ad915 100644 --- a/src/main/java/io/github/dsheirer/source/RealSource.java +++ b/src/main/java/io/github/dsheirer/source/RealSource.java @@ -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 +public abstract class RealSource extends Source implements Provider { @Override public SampleType getSampleType() diff --git a/src/main/java/io/github/dsheirer/source/mixer/MixerReader.java b/src/main/java/io/github/dsheirer/source/mixer/MixerReader.java index 87315c22..c36af769 100644 --- a/src/main/java/io/github/dsheirer/source/mixer/MixerReader.java +++ b/src/main/java/io/github/dsheirer/source/mixer/MixerReader.java @@ -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 implements Runnable +public class MixerReader implements Runnable { private final static Logger mLog = LoggerFactory.getLogger(MixerReader.class); diff --git a/src/main/java/io/github/dsheirer/source/mixer/RealMixerSource.java b/src/main/java/io/github/dsheirer/source/mixer/RealMixerSource.java index 5cb6a7fb..35682ebe 100644 --- a/src/main/java/io/github/dsheirer/source/mixer/RealMixerSource.java +++ b/src/main/java/io/github/dsheirer/source/mixer/RealMixerSource.java @@ -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 listener) + public void setListener(Listener 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 listener) + public void removeListener(Listener listener) { mMixerReader.removeBufferListener(); } diff --git a/src/main/java/io/github/dsheirer/source/wave/RealWaveSource.java b/src/main/java/io/github/dsheirer/source/wave/RealWaveSource.java index 1aec2279..e7f2c134 100644 --- a/src/main/java/io/github/dsheirer/source/wave/RealWaveSource.java +++ b/src/main/java/io/github/dsheirer/source/wave/RealWaveSource.java @@ -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 mListener; + private Listener 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 listener) + public void setListener(Listener 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 listener) + public void removeListener(Listener listener) { mListener = null; } diff --git a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java index 57ecdf4b..9314bf98 100644 --- a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java +++ b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java @@ -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, SettingChangeListener, SpectralDisplayAdjuster + Listener, 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.