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.