From 60ffb18cd99b5e5dc692d7bd4bac239456e081ad Mon Sep 17 00:00:00 2001 From: Denny Date: Sun, 25 Mar 2018 09:13:03 -0400 Subject: [PATCH] 39 [WIP] cleans up the reusable buffers and creates both real and complex variants. --- .idea/dictionaries/denny.xml | 1 + .../github/dsheirer/audio/AudioModule2.java | 179 +++++ .../AbstractComplexPolyphaseChannelizer.java | 2 +- .../filter/channelizer/ChannelizerViewer.java | 19 +- .../ComplexPolyphaseChannelizerM2.java | 2 +- ...or.java => ContinuousBufferProcessor.java} | 40 +- ...=> ContinuousReusableBufferProcessor.java} | 14 +- .../channelizer/PolyphaseChannelManager.java | 26 +- .../channelizer/PolyphaseChannelSource.java | 4 +- .../filter/channelizer/SynthesizerViewer.java | 27 +- .../output/ChannelOutputProcessor.java | 2 +- .../IPolyphaseChannelOutputProcessor.java | 2 +- .../output/OneChannelOutputProcessor.java | 2 +- .../output/TwoChannelOutputProcessor.java | 2 +- .../filter/fir/complex/ComplexFIRFilter.java | 10 +- .../dsp/filter/resample/AudioResampler.java | 70 -- .../dsp/filter/resample/RealResampler.java | 166 ++++ .../gain/ComplexFeedForwardGainControl.java | 8 +- .../dsp/mixer/AbstractOscillator.java | 4 +- .../dsheirer/dsp/mixer/IOscillator.java | 2 +- .../dsheirer/dsp/psk/PSKDemodulator.java | 2 +- .../gui/viewer/PlaybackController.java | 4 +- .../viewer/chart/ComplexPhaseLineChart.java | 2 +- .../viewer/chart/ComplexSampleLineChart.java | 2 +- .../viewer/chart/FMDemodulatedLineChart.java | 2 +- .../gui/viewer/decoder/DecoderPane.java | 4 +- .../gui/viewer/decoder/P25Phase1C4FMPane.java | 2 +- .../gui/viewer/decoder/P25Phase1LSMPane.java | 2 +- .../dsheirer/module/ProcessingChain.java | 4 +- .../module/decode/DecoderFactory.java | 14 +- .../module/decode/p25/P25Decoder.java | 4 +- .../module/decode/p25/P25DecoderC4FM.java | 2 +- .../p25/P25DecoderC4FMInstrumented.java | 2 +- .../module/decode/p25/P25DecoderLSM.java | 2 +- .../decode/p25/P25DecoderLSMInstrumented.java | 2 +- .../demodulate/am/AMDemodulatorModule.java | 4 +- .../demodulate/fm/FMDemodulatorModule.java | 4 +- .../wave/ComplexBufferWaveRecorder.java | 10 +- .../dsheirer/sample/ConversionUtils.java | 87 +- .../sample/adapter/ComplexShortAdapter.java | 2 +- .../sample/adapter/IComplexSampleAdapter.java | 2 +- .../AbstractReusableBufferQueue.java} | 55 +- .../IReusableBufferDisposedListener.java | 8 +- .../IReusableBufferProvider.java} | 8 +- .../IReusableComplexBufferListener.java | 6 +- ...erflowableReusableBufferTransferQueue.java | 12 +- .../ReusableBuffer.java} | 92 ++- .../ReusableBufferAssembler.java | 6 +- .../ReusableBufferBroadcaster.java | 25 +- .../sample/buffer/ReusableBufferQueue.java | 39 + .../sample/buffer/ReusableComplexBuffer.java | 59 ++ .../buffer/ReusableComplexBufferQueue.java | 39 + .../github/dsheirer/source/ComplexSource.java | 2 +- .../dsheirer/source/mixer/ComplexMixer.java | 8 +- .../source/tuner/TunerController.java | 18 +- .../tuner/channel/TunerChannelSource.java | 2 +- .../source/tuner/fcd/FCDTunerController.java | 4 +- .../tuner/manager/ChannelSourceManager.java | 3 +- .../manager/TunerChannelSourceManager.java | 4 +- .../tuner/rtl/RTL2832TunerController.java | 2 +- .../source/tuner/test/SampleGenerator.java | 13 +- .../tuner/test/TestTunerController.java | 2 +- .../tuner/usb/USBTransferProcessor.java | 7 +- .../source/tuner/usb/USBTunerController.java | 2 +- .../usb/converter/NativeBufferConverter.java | 9 +- .../source/wave/ComplexWaveSource.java | 8 +- .../spectrum/ChannelSpectrumPanel.java | 749 +++++++++--------- .../dsheirer/spectrum/DFTProcessor.java | 2 +- .../spectrum/OverflowableBufferStream.java | 9 +- .../spectrum/SpectralDisplayPanel.java | 5 +- 70 files changed, 1211 insertions(+), 728 deletions(-) create mode 100644 src/main/java/io/github/dsheirer/audio/AudioModule2.java rename src/main/java/io/github/dsheirer/dsp/filter/channelizer/{ScheduledBufferProcessor.java => ContinuousBufferProcessor.java} (80%) rename src/main/java/io/github/dsheirer/dsp/filter/channelizer/{ScheduledReusableBufferProcessor.java => ContinuousReusableBufferProcessor.java} (71%) delete mode 100644 src/main/java/io/github/dsheirer/dsp/filter/resample/AudioResampler.java create mode 100644 src/main/java/io/github/dsheirer/dsp/filter/resample/RealResampler.java rename src/main/java/io/github/dsheirer/sample/{complex/reusable/ReusableBufferQueue.java => buffer/AbstractReusableBufferQueue.java} (50%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable => buffer}/IReusableBufferDisposedListener.java (81%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable/IReusableComplexBufferProvider.java => buffer/IReusableBufferProvider.java} (83%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable => buffer}/IReusableComplexBufferListener.java (84%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable => buffer}/OverflowableReusableBufferTransferQueue.java (85%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable/ReusableComplexBuffer.java => buffer/ReusableBuffer.java} (80%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable => buffer}/ReusableBufferAssembler.java (95%) rename src/main/java/io/github/dsheirer/sample/{complex/reusable => buffer}/ReusableBufferBroadcaster.java (66%) create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java create mode 100644 src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferQueue.java diff --git a/.idea/dictionaries/denny.xml b/.idea/dictionaries/denny.xml index a9674196..35e8bffe 100644 --- a/.idea/dictionaries/denny.xml +++ b/.idea/dictionaries/denny.xml @@ -14,6 +14,7 @@ overflowable polyphase remez + resampler samplerate sdrtrunk sheirer diff --git a/src/main/java/io/github/dsheirer/audio/AudioModule2.java b/src/main/java/io/github/dsheirer/audio/AudioModule2.java new file mode 100644 index 00000000..c2f498ac --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/AudioModule2.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * 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.audio; + +import io.github.dsheirer.audio.squelch.ISquelchStateListener; +import io.github.dsheirer.audio.squelch.SquelchState; +import io.github.dsheirer.channel.metadata.Metadata; +import io.github.dsheirer.dsp.filter.resample.RealResampler; +import io.github.dsheirer.module.Module; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableBuffer; +import io.github.dsheirer.sample.real.IFilteredRealBufferListener; +import io.github.dsheirer.sample.real.RealBuffer; +import io.github.dsheirer.source.ISourceEventListener; +import io.github.dsheirer.source.SourceEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides packaging of demodulated audio sample buffers into audio packets for + * broadcast to registered audio packet listeners. Includes audio packet + * metadata in constructed audio packets. + * + * Incorporates audio squelch state listener to control if audio packets are + * broadcast or ignored. + */ +public class AudioModule2 extends Module implements IAudioPacketProvider, IFilteredRealBufferListener, + ISquelchStateListener, ISourceEventListener, Listener +{ + protected static final Logger mLog = LoggerFactory.getLogger(AudioModule2.class); + private static final double OUTPUT_SAMPLE_RATE = 8000.0; + private SquelchStateListener mSquelchStateListener = new SquelchStateListener(); + private SquelchState mSquelchState = SquelchState.SQUELCH; + private Listener mAudioPacketListener; + private Listener mResampledBufferListener; + private RealResampler mAudioResampler; + private Metadata mMetadata; + + public AudioModule2(Metadata metadata) + { + mMetadata = metadata; + + mResampledBufferListener = new Listener() + { + @Override + public void receive(ReusableBuffer reusableBuffer) + { + if(mAudioPacketListener != null) + { + AudioPacket packet = new AudioPacket(reusableBuffer.getSamplesCopy(), mMetadata.copyOf()); + reusableBuffer.decrementUserCount(); + mAudioPacketListener.receive(packet); + } + } + }; + + setSampleRate(25000.0); + } + + /** + * Sets the incoming sample rate + */ + private void setSampleRate(double sampleRate) + { + mAudioResampler = new RealResampler(sampleRate, OUTPUT_SAMPLE_RATE); + mAudioResampler.setListener(mResampledBufferListener); + } + + @Override + public void dispose() + { + mSquelchStateListener = null; + mAudioPacketListener = null; + } + + @Override + public void reset() + { + } + + @Override + public void start() + { + /* No start operations provided */ + } + + @Override + public void stop() + { + /* Issue an end audio packet in case a recorder is still rolling */ + if(mAudioPacketListener != null) + { + mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf())); + } + } + + /** + * Processes demodulated audio samples into audio packets with current audio + * metadata and sends to the registered listener + */ + @Override + public void receive(RealBuffer buffer) + { + if(mAudioResampler != null && mSquelchState == SquelchState.UNSQUELCH) + { + mAudioResampler.receive(buffer); + } + } + + @Override + public Listener getFilteredRealBufferListener() + { + return this; + } + + @Override + public void setAudioPacketListener(Listener listener) + { + mAudioPacketListener = listener; + } + + @Override + public void removeAudioPacketListener() + { + mAudioPacketListener = null; + } + + @Override + public Listener getSourceEventListener() + { + return new Listener() + { + @Override + public void receive(SourceEvent sourceEvent) + { + if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_SAMPLE_RATE_CHANGE) + { + setSampleRate(sourceEvent.getValue().doubleValue()); + } + } + }; + } + + @Override + public Listener getSquelchStateListener() + { + return mSquelchStateListener; + } + + /** + * Wrapper for squelch state listener + */ + public class SquelchStateListener implements Listener + { + @Override + public void receive(SquelchState state) + { + if(state == SquelchState.SQUELCH && mAudioPacketListener != null) + { + mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf())); + } + + mSquelchState = state; + } + } +} diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java index cbffb3f7..7de9ead9 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java @@ -20,7 +20,7 @@ package io.github.dsheirer.dsp.filter.channelizer; import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.ISourceEventListener; import io.github.dsheirer.source.SourceEvent; import org.slf4j.Logger; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ChannelizerViewer.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ChannelizerViewer.java index 820ea2c0..c6d6c25f 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ChannelizerViewer.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ChannelizerViewer.java @@ -18,7 +18,7 @@ package io.github.dsheirer.dsp.filter.channelizer; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.SampleType; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.SourceEvent; @@ -258,7 +258,7 @@ public class ChannelizerViewer extends JFrame for(int x = 0; x < mChannelCount; x++) { - TunerChannelSource source = mTestTuner.getChannelSourceManager().getSpecialSource(x); + TunerChannelSource source = mTestTuner.getChannelSourceManager().getTestingSource(x); DiscreteChannelPanel channelPanel = new DiscreteChannelPanel(mSettingsManager, source, x); channelPanel.setDFTSize(mChannelPanelDFTSize); @@ -327,8 +327,7 @@ public class ChannelizerViewer extends JFrame @Override public void receive(ReusableComplexBuffer reusableComplexBuffer) { - mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount()); - reusableComplexBuffer.decrementUserCount(); + mDFTProcessor.receive(reusableComplexBuffer); } @Override @@ -373,7 +372,8 @@ public class ChannelizerViewer extends JFrame mLog.debug("Samples:" + Arrays.toString(complexBuffer.getSamples())); } - mDFTProcessor.receive(complexBuffer.incrementUserCount()); + complexBuffer.incrementUserCount(); + mDFTProcessor.receive(complexBuffer); complexBuffer.decrementUserCount(); } }); @@ -420,7 +420,8 @@ public class ChannelizerViewer extends JFrame @Override public void receive(ReusableComplexBuffer reusableComplexBuffer) { - mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount()); + reusableComplexBuffer.incrementUserCount(); + mDFTProcessor.receive(reusableComplexBuffer); reusableComplexBuffer.decrementUserCount(); } @@ -476,7 +477,8 @@ public class ChannelizerViewer extends JFrame mLog.debug("Samples:" + Arrays.toString(complexBuffer.getSamples())); } - mDFTProcessor.receive(complexBuffer.incrementUserCount()); + complexBuffer.incrementUserCount(); + mDFTProcessor.receive(complexBuffer); complexBuffer.decrementUserCount(); } }); @@ -502,7 +504,8 @@ public class ChannelizerViewer extends JFrame @Override public void receive(ReusableComplexBuffer reusableComplexBuffer) { - mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount()); + reusableComplexBuffer.incrementUserCount(); + mDFTProcessor.receive(reusableComplexBuffer); reusableComplexBuffer.decrementUserCount(); } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java index ddb01ae7..4ed168e1 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java @@ -21,7 +21,7 @@ package io.github.dsheirer.dsp.filter.channelizer; import io.github.dsheirer.dsp.filter.FilterFactory; import io.github.dsheirer.dsp.filter.Window.WindowType; import io.github.dsheirer.dsp.filter.design.FilterDesignException; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import org.jtransforms.fft.FloatFFT_1D; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ScheduledBufferProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java similarity index 80% rename from src/main/java/io/github/dsheirer/dsp/filter/channelizer/ScheduledBufferProcessor.java rename to src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java index 7c3ca3d7..8c6ec27c 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ScheduledBufferProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java @@ -28,15 +28,13 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -public class ScheduledBufferProcessor implements Listener +public class ContinuousBufferProcessor implements Listener { - private final static Logger mLog = LoggerFactory.getLogger(ScheduledBufferProcessor.class); + private final static Logger mLog = LoggerFactory.getLogger(ContinuousBufferProcessor.class); private OverflowableTransferQueue mQueue; private Listener mListener; private ScheduledFuture mScheduledFuture; - private long mDistributionInterval; - private int mMaxBuffersPerInterval; private AtomicBoolean mRunning = new AtomicBoolean(); /** @@ -52,14 +50,10 @@ public class ScheduledBufferProcessor implements Listener * * @param maximumSize of the internal queue (overflow happens when this is exceeded) * @param resetThreshold of the internal queue (overflow reset happens once queue size falls below this threshold - * @param distributionInterval in milliseconds specifying how often the internal scheduled thread pool buffer - * distributor should run - * @param maxBuffersPerInterval maximum number of buffers to pull from the internal queue during each distribution - * interval */ - public ScheduledBufferProcessor(int maximumSize, int resetThreshold, long distributionInterval, int maxBuffersPerInterval) + public ContinuousBufferProcessor(int maximumSize, int resetThreshold) { - this(new OverflowableTransferQueue<>(maximumSize, resetThreshold), distributionInterval, maxBuffersPerInterval); + this(new OverflowableTransferQueue<>(maximumSize, resetThreshold)); } /** @@ -74,16 +68,10 @@ public class ScheduledBufferProcessor implements Listener * notifications of overflow and reset state. Queue sizing parameters are specified in the constructor. * * @param queue implmentation of an overflowable transfer queue - * @param distributionInterval in milliseconds specifying how often the internal scheduled thread pool buffer - * distributor should run - * @param maxBuffersPerInterval maximum number of buffers to pull from the internal queue during each distribution - * interval */ - public ScheduledBufferProcessor(OverflowableTransferQueue queue, long distributionInterval, int maxBuffersPerInterval) + public ContinuousBufferProcessor(OverflowableTransferQueue queue) { mQueue = queue; - mDistributionInterval = distributionInterval; - mMaxBuffersPerInterval = maxBuffersPerInterval; } /** @@ -116,6 +104,7 @@ public class ScheduledBufferProcessor implements Listener @Override public void receive(E e) { +// mLog.debug(" Queuing: " + e.toString()); mQueue.offer(e); } @@ -126,7 +115,7 @@ public class ScheduledBufferProcessor implements Listener { if(mRunning.compareAndSet(false, true)) { - mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new Processor(), 0, mDistributionInterval, TimeUnit.MILLISECONDS); + mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new Processor(), 0, 5, TimeUnit.MILLISECONDS); } } @@ -175,17 +164,22 @@ public class ScheduledBufferProcessor implements Listener { try { - mQueue.drainTo(mBuffers, mMaxBuffersPerInterval); + mQueue.drainTo(mBuffers, 10); if(mListener != null) { - for(E buffer: mBuffers) + while(!mBuffers.isEmpty()) { - mListener.receive(buffer); + for(E buffer: mBuffers) + { +// mLog.debug("Dispatching: " + buffer.toString() + " Count:" + mBuffers.size()); + mListener.receive(buffer); + } + + mBuffers.clear(); + mQueue.drainTo(mBuffers, 10); } } - - mBuffers.clear(); } catch(Throwable throwable) { diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ScheduledReusableBufferProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousReusableBufferProcessor.java similarity index 71% rename from src/main/java/io/github/dsheirer/dsp/filter/channelizer/ScheduledReusableBufferProcessor.java rename to src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousReusableBufferProcessor.java index 24eb7843..0439fb11 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ScheduledReusableBufferProcessor.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.complex.reusable.OverflowableReusableBufferTransferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue; +import io.github.dsheirer.sample.buffer.ReusableBuffer; -public class ScheduledReusableBufferProcessor extends ScheduledBufferProcessor +public class ContinuousReusableBufferProcessor extends ContinuousBufferProcessor { /** * Scheduled Reusable Buffer Processor combines an internal overflowable buffer with a scheduled runnable processing @@ -33,13 +33,9 @@ public class ScheduledReusableBufferProcessor extends ScheduledBufferProcessor(maximumSize, resetThreshold)); } } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java index ee5ec599..d9118020 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java @@ -23,8 +23,8 @@ import io.github.dsheirer.dsp.filter.channelizer.output.TwoChannelOutputProcesso import io.github.dsheirer.dsp.filter.design.FilterDesignException; import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferProvider; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.IReusableBufferProvider; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.SourceException; @@ -52,13 +52,13 @@ public class PolyphaseChannelManager implements ISourceEventProcessor private static final int POLYPHASE_FILTER_TAPS_PER_CHANNEL = 17; private Broadcaster mSourceEventBroadcaster = new Broadcaster<>(); - private IReusableComplexBufferProvider mReusableBufferProvider; + private IReusableBufferProvider mReusableBufferProvider; private List mChannelSources = new CopyOnWriteArrayList<>(); private ChannelCalculator mChannelCalculator; private ComplexPolyphaseChannelizerM2 mPolyphaseChannelizer; private ChannelSourceEventListener mChannelSourceEventListener = new ChannelSourceEventListener(); private BufferSourceEventMonitor mBufferSourceEventMonitor = new BufferSourceEventMonitor(); - private ScheduledBufferProcessor mBufferProcessor; + private ContinuousBufferProcessor mBufferProcessor; private Map mOutputProcessorFilters = new HashMap<>(); /** @@ -76,7 +76,8 @@ public class PolyphaseChannelManager implements ISourceEventProcessor * @param frequency of the provided complex buffer samples * @param sampleRate of the provided complex buffer samples */ - public PolyphaseChannelManager(IReusableComplexBufferProvider reusableBufferProvider, long frequency, double sampleRate) + public PolyphaseChannelManager(IReusableBufferProvider reusableBufferProvider, + long frequency, double sampleRate) { if(reusableBufferProvider == null) { @@ -95,7 +96,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor mChannelCalculator = new ChannelCalculator(sampleRate, channelCount, frequency, CHANNEL_OVERSAMPLING); - mBufferProcessor = new ScheduledBufferProcessor(500, 100, 50, 50); + mBufferProcessor = new ContinuousBufferProcessor(200, 50); mBufferProcessor.setListener(mBufferSourceEventMonitor); updateChannelizerSampleRate(sampleRate); @@ -160,7 +161,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor return channelSource; } - public TunerChannelSource getSpecialChannel(int index) + public TunerChannelSource getTestChannel(int index) { PolyphaseChannelSource channelSource = null; @@ -181,6 +182,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor } catch(IllegalArgumentException iae) { + mLog.error("Error", iae); } return channelSource; @@ -582,15 +584,19 @@ public class PolyphaseChannelManager implements ISourceEventProcessor if(mPolyphaseChannelizer != null) { - mPolyphaseChannelizer.receive(reusableComplexBuffer.incrementUserCount()); + //User count management is handled by the channelizer + mPolyphaseChannelizer.receive(reusableComplexBuffer); + } + else + { + reusableComplexBuffer.decrementUserCount(); } } catch(Throwable throwable) { mLog.error("Error", throwable); + reusableComplexBuffer.decrementUserCount(); } - - reusableComplexBuffer.decrementUserCount(); } } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java index 0e62e6c7..b6a6a99f 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java @@ -17,8 +17,8 @@ package io.github.dsheirer.dsp.filter.channelizer; import io.github.dsheirer.dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferAssembler; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableBufferAssembler; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.tuner.channel.TunerChannel; import io.github.dsheirer.source.tuner.channel.TunerChannelSource; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/SynthesizerViewer.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/SynthesizerViewer.java index 75d48dea..ff8ae0d9 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/SynthesizerViewer.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/SynthesizerViewer.java @@ -23,8 +23,8 @@ import io.github.dsheirer.dsp.mixer.IOscillator; import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.SampleType; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.sample.real.IOverflowListener; import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.source.SourceEvent; @@ -177,8 +177,7 @@ public class SynthesizerViewer extends JFrame @Override public void receive(ReusableComplexBuffer reusableComplexBuffer) { - mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount()); - reusableComplexBuffer.decrementUserCount(); + mDFTProcessor.receive(reusableComplexBuffer); } } @@ -212,8 +211,7 @@ public class SynthesizerViewer extends JFrame @Override public void receive(ReusableComplexBuffer reusableComplexBuffer) { - mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount()); - reusableComplexBuffer.decrementUserCount(); + mDFTProcessor.receive(reusableComplexBuffer); } } @@ -277,7 +275,7 @@ public class SynthesizerViewer extends JFrame private TwoChannelSynthesizerM2 mSynthesizer; private FS4DownConverter mFS4DownConverter = new FS4DownConverter(); private int mSamplesPerCycle = CHANNEL_SAMPLE_RATE / DATA_GENERATOR_FRAME_RATE; - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue(); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("SynthesizerViewer"); public DataGenerationManager() { @@ -296,19 +294,22 @@ public class SynthesizerViewer extends JFrame @Override public void run() { - ReusableComplexBuffer channel1Buffer = mReusableBufferQueue.getBuffer(mSamplesPerCycle); + ReusableComplexBuffer channel1Buffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerCycle); getChannel1ControlPanel().getOscillator().generateComplex(channel1Buffer); - ReusableComplexBuffer channel2Buffer = mReusableBufferQueue.getBuffer(mSamplesPerCycle); + ReusableComplexBuffer channel2Buffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerCycle); getChannel2ControlPanel().getOscillator().generateComplex(channel2Buffer); float[] synthesized = mSynthesizer.process(channel1Buffer.getSamples(), channel2Buffer.getSamples()); mFS4DownConverter.mixComplex(synthesized); - ReusableComplexBuffer synthesizedBuffer = mReusableBufferQueue.getBuffer(synthesized.length); + ReusableComplexBuffer synthesizedBuffer = mReusableComplexBufferQueue.getBuffer(synthesized.length); - getChannel1Panel().receive(channel1Buffer.incrementUserCount()); - getChannel2Panel().receive(channel2Buffer.incrementUserCount()); - getSpectrumPanel().receive(synthesizedBuffer.incrementUserCount()); + channel1Buffer.incrementUserCount(); + getChannel1Panel().receive(channel1Buffer); + channel2Buffer.incrementUserCount(); + getChannel2Panel().receive(channel2Buffer); + synthesizedBuffer.incrementUserCount(); + getSpectrumPanel().receive(synthesizedBuffer); } } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java index 5f9f2954..60cfc9f7 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java @@ -22,7 +22,7 @@ import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelResultsBuffer; import io.github.dsheirer.dsp.mixer.IOscillator; import io.github.dsheirer.dsp.mixer.Oscillator; import io.github.dsheirer.sample.OverflowableTransferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferAssembler; +import io.github.dsheirer.sample.buffer.ReusableBufferAssembler; import io.github.dsheirer.sample.real.IOverflowListener; import io.github.dsheirer.source.Source; import org.slf4j.Logger; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java index 2dc2216a..3726866e 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java @@ -19,7 +19,7 @@ package io.github.dsheirer.dsp.filter.channelizer.output; import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelResultsBuffer; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferAssembler; +import io.github.dsheirer.sample.buffer.ReusableBufferAssembler; import io.github.dsheirer.source.Source; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java index b17970f9..1c5e534a 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java @@ -19,7 +19,7 @@ package io.github.dsheirer.dsp.filter.channelizer.output; import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelResultsBuffer; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferAssembler; +import io.github.dsheirer.sample.buffer.ReusableBufferAssembler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java index dcc637a5..d51096c2 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java @@ -18,7 +18,7 @@ package io.github.dsheirer.dsp.filter.channelizer.output; import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelResultsBuffer; import io.github.dsheirer.dsp.filter.channelizer.TwoChannelSynthesizerM2; import io.github.dsheirer.dsp.mixer.FS4DownConverter; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferAssembler; +import io.github.dsheirer.sample.buffer.ReusableBufferAssembler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java index 6c28556e..ece55ce4 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java @@ -17,13 +17,13 @@ package io.github.dsheirer.dsp.filter.fir.complex; import io.github.dsheirer.dsp.filter.fir.FIRFilter; import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; public class ComplexFIRFilter extends FIRFilter { - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("Complex FIR Filter"); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("Complex FIR Filter"); private RealFIRFilter mIFilter; private RealFIRFilter mQFilter; @@ -84,7 +84,7 @@ public class ComplexFIRFilter extends FIRFilter */ public ReusableComplexBuffer filter(ReusableComplexBuffer originalBuffer) { - ReusableComplexBuffer filteredBuffer = mReusableBufferQueue.getBuffer(originalBuffer.getSamples().length); + ReusableComplexBuffer filteredBuffer = mReusableComplexBufferQueue.getBuffer(originalBuffer.getSamples().length); filteredBuffer.setTimestamp(originalBuffer.getTimestamp()); float[] samples = originalBuffer.getSamples(); @@ -107,6 +107,6 @@ public class ComplexFIRFilter extends FIRFilter { mIFilter.dispose(); mQFilter.dispose(); - mReusableBufferQueue.dispose(); + mReusableComplexBufferQueue.dispose(); } } diff --git a/src/main/java/io/github/dsheirer/dsp/filter/resample/AudioResampler.java b/src/main/java/io/github/dsheirer/dsp/filter/resample/AudioResampler.java deleted file mode 100644 index c67401b9..00000000 --- a/src/main/java/io/github/dsheirer/dsp/filter/resample/AudioResampler.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * 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.dsp.filter.resample; - -import com.laszlosystems.libresample4j.Resampler; -import io.github.dsheirer.module.Module; -import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.source.ISourceEventListener; -import io.github.dsheirer.source.SourceEvent; - -public class AudioResampler extends Module implements ISourceEventListener -{ - private Resampler mResampler; - - public AudioResampler(double inputRate, double outputRate) - { - double resampleRate = outputRate / inputRate; - - mResampler = new Resampler(true, resampleRate, resampleRate); - } - - public float[] resample(float[] samples) - { - return null; - } - - @Override - public void reset() - { - - } - - @Override - public void start() - { - - } - - @Override - public void stop() - { - - } - - @Override - public void dispose() - { - - } - - @Override - public Listener getSourceEventListener() - { - //TODO: we should get the channel sample rate and setup the resampler to output 8 kHz audio - return null; - } -} 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 new file mode 100644 index 00000000..ece20c3d --- /dev/null +++ b/src/main/java/io/github/dsheirer/dsp/filter/resample/RealResampler.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * 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.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.real.RealBuffer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +public class RealResampler implements Listener +{ + protected static final Logger mLog = LoggerFactory.getLogger(RealResampler.class); + + private Resampler mResampler; + private Listener mResampledListener; + private BufferManager mBufferManager = new BufferManager(); + private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("RealResampler"); + private double mResampleFactor; + + /** + * Resampler for real sample buffers. + * @param inputRate + * @param outputRate + */ + public RealResampler(double inputRate, double outputRate) + { + mResampleFactor = outputRate / inputRate; + mResampler = new Resampler(true, mResampleFactor, mResampleFactor); + } + + /** + * Primary input method to the resampler + * @param realBuffer to resample + */ + @Override + public void receive(RealBuffer realBuffer) + { + mBufferManager.load(realBuffer); + mResampler.process(mResampleFactor, mBufferManager, false); + } + + /** + * Registers the listener to receive the resampled buffer output + * @param resampledBufferListener to receive buffers + */ + public void setListener(Listener resampledBufferListener) + { + mResampledListener = resampledBufferListener; + } + + /** + * Buffer manager for input and output buffers used during the resampling process. The manager will + * auto-resize the input and output buffers to meet the size of the incoming sample buffers. + */ + public class BufferManager implements SampleBuffers + { + private int mBufferLength = 1000; + private FloatBuffer mInputBuffer = ByteBuffer.allocate(mBufferLength).asFloatBuffer(); + private FloatBuffer mOutputBuffer = ByteBuffer.allocate(mBufferLength).asFloatBuffer(); + + public void resize(int bufferLength) + { + int floatBufferLength = bufferLength * 4; + + FloatBuffer inputBuffer = ByteBuffer.allocate(floatBufferLength).asFloatBuffer(); + inputBuffer.put(mInputBuffer); + mInputBuffer = inputBuffer; + + FloatBuffer outputBuffer = ByteBuffer.allocate(floatBufferLength).asFloatBuffer(); + outputBuffer.put(mOutputBuffer); + mOutputBuffer = outputBuffer; + + mBufferLength = bufferLength; + } + + /** + * Current length of the input and output buffers + */ + public int getBufferLength() + { + return mBufferLength; + } + + /** + * Queues the buffer sample for resampling + */ + public void load(RealBuffer realBuffer) + { + int remaining = mInputBuffer.remaining(); + + if(mInputBuffer.remaining() < realBuffer.getSamples().length) + { + resize(mInputBuffer.capacity() + (realBuffer.getSamples().length - mInputBuffer.remaining())); + } + + mInputBuffer.put(realBuffer.getSamples()); + } + + @Override + public int getInputBufferLength() + { + return mInputBuffer.position(); + } + + @Override + public int getOutputBufferLength() + { + return mOutputBuffer.remaining(); + } + + /** + * Provides input to the resampler + */ + @Override + public void produceInput(float[] samples, int offset, int length) + { + mInputBuffer.flip(); + mInputBuffer.get(samples, offset, length); + mInputBuffer.compact(); + } + + /** + * Receives output from the resampler and dispatches output buffers periodically. + */ + @Override + public void consumeOutput(float[] samples, int offset, int length) + { + mOutputBuffer.put(samples, offset, length); + + while(mOutputBuffer.position() > 200) + { + ReusableBuffer outputBuffer = mReusableBufferQueue.getBuffer(200); + + mOutputBuffer.flip(); + mOutputBuffer.get(outputBuffer.getSamples()); + mOutputBuffer.compact(); + + if(mResampledListener != null) + { + outputBuffer.incrementUserCount(); + mResampledListener.receive(outputBuffer); + } + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java b/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java index 13c54eda..3cb99948 100644 --- a/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java +++ b/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java @@ -16,11 +16,11 @@ package io.github.dsheirer.dsp.gain; import io.github.dsheirer.buffer.FloatCircularBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.sample.complex.Complex; import io.github.dsheirer.sample.complex.ComplexBuffer; import io.github.dsheirer.sample.complex.ComplexSampleListener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; public class ComplexFeedForwardGainControl implements ComplexSampleListener { @@ -29,7 +29,7 @@ public class ComplexFeedForwardGainControl implements ComplexSampleListener private ComplexSampleListener mListener; private FloatCircularBuffer mEnvelopeHistory; - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("ComplexFeedForwardGainControl"); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexFeedForwardGainControl"); private float mMaxEnvelope = 0.0f; private float mGain = 1.0f; @@ -157,7 +157,7 @@ public class ComplexFeedForwardGainControl implements ComplexSampleListener { float[] samples = buffer.getSamples(); - ReusableComplexBuffer filteredBuffer = mReusableBufferQueue.getBuffer(samples.length); + ReusableComplexBuffer filteredBuffer = mReusableComplexBufferQueue.getBuffer(samples.length); filteredBuffer.setTimestamp(buffer.getTimestamp()); float[] filtered = filteredBuffer.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 5be64115..3f7df3f8 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.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -160,7 +160,7 @@ public abstract class AbstractOscillator implements IOscillator @Override public void generateComplex(ReusableComplexBuffer reusableComplexBuffer) { - int sampleCount = reusableComplexBuffer.getSampleLength(); + int sampleCount = reusableComplexBuffer.getSampleCount(); if(mSampleBuffer == null || mSampleBuffer.capacity() != sampleCount * 2) { 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 1f843dda..18f522d5 100644 --- a/src/main/java/io/github/dsheirer/dsp/mixer/IOscillator.java +++ b/src/main/java/io/github/dsheirer/dsp/mixer/IOscillator.java @@ -15,7 +15,7 @@ ******************************************************************************/ package io.github.dsheirer.dsp.mixer; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; /** * Oscillator interface. diff --git a/src/main/java/io/github/dsheirer/dsp/psk/PSKDemodulator.java b/src/main/java/io/github/dsheirer/dsp/psk/PSKDemodulator.java index c187a408..aebc59e6 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/PSKDemodulator.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/PSKDemodulator.java @@ -17,9 +17,9 @@ package io.github.dsheirer.dsp.psk; import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; import io.github.dsheirer.sample.complex.ComplexSampleListener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; public abstract class PSKDemodulator implements ComplexSampleListener { diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/PlaybackController.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/PlaybackController.java index 6462901f..ee74737e 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/PlaybackController.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/PlaybackController.java @@ -17,8 +17,8 @@ package io.github.dsheirer.instrument.gui.viewer; import io.github.dsheirer.instrument.gui.viewer.decoder.DecoderPane; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.IControllableFileSource; import io.github.dsheirer.source.IFrameLocationListener; import io.github.dsheirer.source.wave.ComplexWaveSource; diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexPhaseLineChart.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexPhaseLineChart.java index 3d7694a2..000f3a50 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexPhaseLineChart.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexPhaseLineChart.java @@ -18,8 +18,8 @@ package io.github.dsheirer.instrument.gui.viewer.chart; import io.github.dsheirer.buffer.ComplexCircularBuffer; import io.github.dsheirer.dsp.gain.ComplexGain; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.value.ChangeListener; diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexSampleLineChart.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexSampleLineChart.java index bec81eef..d1b4b00c 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexSampleLineChart.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/ComplexSampleLineChart.java @@ -18,8 +18,8 @@ package io.github.dsheirer.instrument.gui.viewer.chart; import io.github.dsheirer.buffer.ComplexCircularBuffer; import io.github.dsheirer.dsp.gain.ComplexGain; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.value.ChangeListener; diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/FMDemodulatedLineChart.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/FMDemodulatedLineChart.java index c209a5db..334db601 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/FMDemodulatedLineChart.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/chart/FMDemodulatedLineChart.java @@ -18,8 +18,8 @@ package io.github.dsheirer.instrument.gui.viewer.chart; import io.github.dsheirer.buffer.DoubleCircularBuffer; import io.github.dsheirer.dsp.fm.FMDemodulator; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.chart.LineChart; diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/DecoderPane.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/DecoderPane.java index daaa092d..82d3ae86 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/DecoderPane.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/DecoderPane.java @@ -17,8 +17,8 @@ package io.github.dsheirer.instrument.gui.viewer.decoder; import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import javafx.scene.layout.VBox; import javafx.scene.text.Text; diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1C4FMPane.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1C4FMPane.java index 381e83be..56a3cff0 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1C4FMPane.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1C4FMPane.java @@ -24,7 +24,7 @@ import io.github.dsheirer.message.Message; import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.p25.P25DecoderC4FMInstrumented; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import org.slf4j.Logger; diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1LSMPane.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1LSMPane.java index b93fa58e..33b0f7e4 100644 --- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1LSMPane.java +++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1LSMPane.java @@ -24,7 +24,7 @@ import io.github.dsheirer.message.Message; import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.p25.P25DecoderLSMInstrumented; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import org.slf4j.Logger; diff --git a/src/main/java/io/github/dsheirer/module/ProcessingChain.java b/src/main/java/io/github/dsheirer/module/ProcessingChain.java index 060190ff..34b81cdb 100644 --- a/src/main/java/io/github/dsheirer/module/ProcessingChain.java +++ b/src/main/java/io/github/dsheirer/module/ProcessingChain.java @@ -49,8 +49,8 @@ import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder; import io.github.dsheirer.record.wave.RealBufferWaveRecorder; import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; import io.github.dsheirer.sample.real.IFilteredRealBufferListener; import io.github.dsheirer.sample.real.IFilteredRealBufferProvider; import io.github.dsheirer.sample.real.IUnFilteredRealBufferListener; 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 146e8f3a..c2020df7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java @@ -20,7 +20,7 @@ package io.github.dsheirer.module.decode; import io.github.dsheirer.alias.AliasList; import io.github.dsheirer.alias.AliasModel; -import io.github.dsheirer.audio.AudioModule; +import io.github.dsheirer.audio.AudioModule2; import io.github.dsheirer.channel.metadata.Metadata; import io.github.dsheirer.channel.state.AlwaysUnsquelchedDecoderState; import io.github.dsheirer.channel.traffic.TrafficChannelManager; @@ -184,14 +184,14 @@ public class DecoderFactory modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.AM, channel.getName())); modules.add(new AMDemodulatorModule()); modules.add(new DemodulatedAudioFilterModule(4000, 6000)); - modules.add(new AudioModule(metadata)); + modules.add(new AudioModule2(metadata)); break; case NBFM: modules.add(new NBFMDecoder(decodeConfig)); modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.NBFM, channel.getName())); modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY)); modules.add(new DemodulatedAudioFilterModule(4000, 6000)); - modules.add(new AudioModule(metadata)); + modules.add(new AudioModule2(metadata)); break; case LTR_STANDARD: MessageDirection direction = ((DecodeConfigLTRStandard) decodeConfig).getMessageDirection(); @@ -199,14 +199,14 @@ public class DecoderFactory modules.add(new LTRStandardDecoderState(aliasList)); modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY)); modules.add(new DemodulatedAudioFilterModule(4000, 6000)); - modules.add(new AudioModule(metadata)); + modules.add(new AudioModule2(metadata)); break; case LTR_NET: modules.add(new LTRNetDecoder((DecodeConfigLTRNet) decodeConfig, aliasList)); modules.add(new LTRNetDecoderState(aliasList)); modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY)); modules.add(new DemodulatedAudioFilterModule(4000, 6000)); - modules.add(new AudioModule(metadata)); + modules.add(new AudioModule2(metadata)); break; case MPT1327: DecodeConfigMPT1327 mptConfig = (DecodeConfigMPT1327) decodeConfig; @@ -229,14 +229,14 @@ public class DecoderFactory modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY)); modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f)); - modules.add(new AudioModule(metadata)); + modules.add(new AudioModule2(metadata)); break; case PASSPORT: modules.add(new PassportDecoder(decodeConfig, aliasList)); modules.add(new PassportDecoderState(aliasList)); modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY)); modules.add(new DemodulatedAudioFilterModule(4000, 6000)); - modules.add(new AudioModule(metadata)); + modules.add(new AudioModule2(metadata)); break; case P25_PHASE1: DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1) decodeConfig; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java index dfcf230b..f88348cf 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java @@ -19,8 +19,8 @@ import io.github.dsheirer.alias.AliasList; 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.complex.reusable.IReusableComplexBufferListener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.ISourceEventListener; import io.github.dsheirer.source.ISourceEventProvider; import io.github.dsheirer.source.SourceEvent; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java index f37f3aae..1155ec58 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java @@ -24,7 +24,7 @@ import io.github.dsheirer.dsp.gain.ComplexFeedForwardGainControl; import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulator; import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer; import io.github.dsheirer.dsp.psk.pll.CostasLoop; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java index 46762450..c69a44e6 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java @@ -20,8 +20,8 @@ import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulatorInstrumented; import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented; import io.github.dsheirer.dsp.psk.SymbolDecisionData; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; public class P25DecoderC4FMInstrumented extends P25DecoderC4FM { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java index 1fd4c683..d9dea665 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java @@ -23,7 +23,7 @@ import io.github.dsheirer.dsp.gain.ComplexFeedForwardGainControl; import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulator; import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer; import io.github.dsheirer.dsp.psk.pll.CostasLoop; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java index 41292d32..7997ae9f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java @@ -20,8 +20,8 @@ import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulatorInstrumented; import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented; import io.github.dsheirer.dsp.psk.SymbolDecisionData; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; public class P25DecoderLSMInstrumented extends P25DecoderLSM { 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 e55b51cb..f155c890 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 @@ -23,9 +23,9 @@ import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter_RB_RB; import io.github.dsheirer.dsp.gain.AutomaticGainControl_RB; import io.github.dsheirer.module.Module; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.ComplexBuffer; -import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; import io.github.dsheirer.sample.real.IFilteredRealBufferProvider; import io.github.dsheirer.sample.real.RealBuffer; 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 a976a3fa..b06864c8 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 @@ -23,8 +23,8 @@ import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter_CB_CB; import io.github.dsheirer.dsp.fm.FMDemodulator_CB; import io.github.dsheirer.module.Module; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.real.IUnFilteredRealBufferProvider; import io.github.dsheirer.sample.real.RealBuffer; import io.github.dsheirer.source.ISourceEventListener; diff --git a/src/main/java/io/github/dsheirer/record/wave/ComplexBufferWaveRecorder.java b/src/main/java/io/github/dsheirer/record/wave/ComplexBufferWaveRecorder.java index 12b519a3..ff68d8fb 100644 --- a/src/main/java/io/github/dsheirer/record/wave/ComplexBufferWaveRecorder.java +++ b/src/main/java/io/github/dsheirer/record/wave/ComplexBufferWaveRecorder.java @@ -18,9 +18,9 @@ package io.github.dsheirer.record.wave; import io.github.dsheirer.module.Module; import io.github.dsheirer.sample.ConversionUtils; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.IReusableBufferDisposedListener; -import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.IReusableBufferDisposedListener; +import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.TimeStamp; import org.slf4j.Logger; @@ -207,14 +207,14 @@ public class ComplexBufferWaveRecorder extends Module implements IReusableComple { public PoisonPill() { - super(new IReusableBufferDisposedListener() + super(new IReusableBufferDisposedListener() { @Override public void disposed(ReusableComplexBuffer reusableComplexBuffer) { //no-op } - }, new float[2], System.currentTimeMillis()); + }, new float[2]); } } } diff --git a/src/main/java/io/github/dsheirer/sample/ConversionUtils.java b/src/main/java/io/github/dsheirer/sample/ConversionUtils.java index 7ad5c27c..9cc988ff 100644 --- a/src/main/java/io/github/dsheirer/sample/ConversionUtils.java +++ b/src/main/java/io/github/dsheirer/sample/ConversionUtils.java @@ -1,5 +1,6 @@ package io.github.dsheirer.sample; +import io.github.dsheirer.sample.buffer.ReusableBuffer; import io.github.dsheirer.sample.real.RealBuffer; import java.nio.ByteBuffer; @@ -11,61 +12,71 @@ import java.nio.ShortBuffer; */ public class ConversionUtils { - public static float[] convertFromSigned16BitSamples( byte[] bytes ) + public static float[] convertFromSigned16BitSamples(byte[] bytes) { - return convertFromSigned16BitSamples( ByteBuffer.wrap( bytes ) ); + return convertFromSigned16BitSamples(ByteBuffer.wrap(bytes)); } /** * Converts the byte buffer containing 16-bit samples into a float array */ - public static float[] convertFromSigned16BitSamples( ByteBuffer buffer ) + public static float[] convertFromSigned16BitSamples(ByteBuffer buffer) { - ShortBuffer byteBuffer = buffer.order( ByteOrder.LITTLE_ENDIAN ).asShortBuffer(); - - float[] samples = new float[ buffer.limit() / 2 ]; - - for( int x = 0; x < samples.length; x++ ) - { - samples[ x ] = (float)byteBuffer.get() / (float)Short.MAX_VALUE; - } + ShortBuffer byteBuffer = buffer.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); - return samples; + float[] samples = new float[buffer.limit() / 2]; + + for(int x = 0; x < samples.length; x++) + { + samples[x] = (float)byteBuffer.get() / (float)Short.MAX_VALUE; + } + + return samples; } /** * Converts the float samples into a little-endian 16-bit sample byte buffer. + * * @param samples - float array of sample data * @return - little-endian 16-bit sample byte buffer */ - public static ByteBuffer convertToSigned16BitSamples( float[] samples ) + public static ByteBuffer convertToSigned16BitSamples(float[] samples) { - ByteBuffer converted = ByteBuffer.allocate( samples.length * 2 ); - converted.order( ByteOrder.LITTLE_ENDIAN ); + ByteBuffer converted = ByteBuffer.allocate(samples.length * 2); + converted.order(ByteOrder.LITTLE_ENDIAN); - for( float sample: samples ) - { - converted.putShort( (short)( sample * Short.MAX_VALUE ) ); - } - - return converted; + for(float sample : samples) + { + converted.putShort((short)(sample * Short.MAX_VALUE)); + } + + return converted; } - - /** - * Converts the float samples in a complex buffer to a little endian 16-bit - * buffer - */ - public static ByteBuffer convertToSigned16BitSamples( Buffer buffer ) - { - return convertToSigned16BitSamples( buffer.getSamples() ); - } - /** - * Converts the float samples in a complex buffer to a little endian 16-bit - * buffer - */ - public static ByteBuffer convertToSigned16BitSamples( RealBuffer buffer ) - { - return convertToSigned16BitSamples( buffer.getSamples() ); - } + /** + * Converts the float samples in a complex buffer to a little endian 16-bit + * buffer + */ + public static ByteBuffer convertToSigned16BitSamples(Buffer buffer) + { + return convertToSigned16BitSamples(buffer.getSamples()); + } + + /** + * Converts the float samples in a complex buffer to a little endian 16-bit + * buffer + */ + public static ByteBuffer convertToSigned16BitSamples(RealBuffer buffer) + { + return convertToSigned16BitSamples(buffer.getSamples()); + } + + /** + * Converts the float samples in a complex buffer to a little endian 16-bit + * buffer + */ + public static ByteBuffer convertToSigned16BitSamples(ReusableBuffer buffer) + { + return convertToSigned16BitSamples(buffer.getSamples()); + } } diff --git a/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java b/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java index 705a5448..6a3c80ac 100644 --- a/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java +++ b/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java @@ -15,7 +15,7 @@ ******************************************************************************/ package io.github.dsheirer.sample.adapter; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/src/main/java/io/github/dsheirer/sample/adapter/IComplexSampleAdapter.java b/src/main/java/io/github/dsheirer/sample/adapter/IComplexSampleAdapter.java index 471ee032..99d07eeb 100644 --- a/src/main/java/io/github/dsheirer/sample/adapter/IComplexSampleAdapter.java +++ b/src/main/java/io/github/dsheirer/sample/adapter/IComplexSampleAdapter.java @@ -15,7 +15,7 @@ ******************************************************************************/ package io.github.dsheirer.sample.adapter; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; public interface IComplexSampleAdapter { diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferQueue.java b/src/main/java/io/github/dsheirer/sample/buffer/AbstractReusableBufferQueue.java similarity index 50% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferQueue.java rename to src/main/java/io/github/dsheirer/sample/buffer/AbstractReusableBufferQueue.java index 89f7e81b..0959b060 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferQueue.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/AbstractReusableBufferQueue.java @@ -13,7 +13,7 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,21 +21,22 @@ import org.slf4j.LoggerFactory; import java.util.Queue; import java.util.concurrent.LinkedTransferQueue; -public class ReusableBufferQueue implements IReusableBufferDisposedListener +public abstract class AbstractReusableBufferQueue implements IReusableBufferDisposedListener { - private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferQueue.class); - private Queue mReusableBufferQueue = new LinkedTransferQueue<>(); + private final static Logger mLog = LoggerFactory.getLogger(AbstractReusableBufferQueue.class); + + private Queue mReusableBufferQueue = new LinkedTransferQueue<>(); private int mBufferCount = 0; private String mDebugName; + private int mBufferUserCounter; - public ReusableBufferQueue(String debugName) + public AbstractReusableBufferQueue(String debugName) { mDebugName = debugName; } - public ReusableBufferQueue() + public AbstractReusableBufferQueue() { - } public void dispose() @@ -47,12 +48,17 @@ public class ReusableBufferQueue implements IReusableBufferDisposedListener * Implements buffer disposed listener interface. Disposed (ie user count = 0) buffers will automatically callback * to this method to indicate when they are disposed. * - * @param reusableComplexBuffer that has been disposed + * @param reusableBuffer that has been disposed */ @Override - public void disposed(ReusableComplexBuffer reusableComplexBuffer) + public void disposed(T reusableBuffer) { - mReusableBufferQueue.offer(reusableComplexBuffer); + mReusableBufferQueue.offer(reusableBuffer); + +// if(mDebugName != null && mDebugName.contentEquals("NativeBufferConverter")) +// { +// mLog.debug("Reclaimed: " + reusableBuffer.name()); +// } } /** @@ -62,18 +68,37 @@ public class ReusableBufferQueue implements IReusableBufferDisposedListener * @param size of the samples that will be loaded into the buffer * @return a reusable buffer */ - public ReusableComplexBuffer getBuffer(int size) + public T getBuffer(int size) { - ReusableComplexBuffer buffer = mReusableBufferQueue.poll(); + T buffer = mReusableBufferQueue.poll(); - //Create a new buffer if we currently don't have any buffers to reuse if(buffer == null) { - buffer = new ReusableComplexBuffer(this, new float[size]); + buffer = createBuffer(size); mBufferCount++; - mLog.debug("Buffer Created - Count:" + mBufferCount + (mDebugName != null ? " [" + mDebugName + "]" : "")); + buffer.setDebugName("Owner:" + mDebugName + " Number:" + mBufferUserCounter++ + " NEW BUFFER"); + +// if(mDebugName != null && mDebugName.contentEquals("NativeBufferConverter")) +// { +// mLog.debug("Buffer Created - Count:" + mBufferCount + (mDebugName != null ? " [" + mDebugName + "]" : "")); +// } + } + else + { + String previous = buffer.name(); + buffer.setDebugName("Owner:" + mDebugName + " Number:" + mBufferUserCounter++); + +// if(mDebugName != null && mDebugName.contentEquals("NativeBufferConverter")) +// { +// mLog.debug("Buffer Reused: " + previous + " New Name:" + buffer.name()); +// } } return buffer; } + + /** + * Create a new buffer of the specified size + */ + protected abstract T createBuffer(int size); } diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableBufferDisposedListener.java b/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferDisposedListener.java similarity index 81% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableBufferDisposedListener.java rename to src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferDisposedListener.java index fd261e23..b3baaffb 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableBufferDisposedListener.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferDisposedListener.java @@ -13,13 +13,13 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; -public interface IReusableBufferDisposedListener +public interface IReusableBufferDisposedListener { /** * Notifies the listener that the timestamped buffer has been disposed and can now be reused. - * @param reusableComplexBuffer that has been disposed + * @param t reusableBuffer that has been disposed */ - void disposed(ReusableComplexBuffer reusableComplexBuffer); + void disposed(T t); } diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableComplexBufferProvider.java b/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java similarity index 83% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableComplexBufferProvider.java rename to src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java index 96ad66dd..afacda85 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableComplexBufferProvider.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/IReusableBufferProvider.java @@ -13,21 +13,21 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; import io.github.dsheirer.sample.Listener; -public interface IReusableComplexBufferProvider +public interface IReusableBufferProvider { /** * Adds the listener to receive complex buffer samples */ - void addBufferListener(Listener listener); + void addBufferListener(Listener listener); /** * Removes the listener from receiving complex buffer samples */ - void removeBufferListener(Listener listener); + void removeBufferListener(Listener listener); /** * Indicates if there are any complex buffer listeners registered diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableComplexBufferListener.java b/src/main/java/io/github/dsheirer/sample/buffer/IReusableComplexBufferListener.java similarity index 84% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableComplexBufferListener.java rename to src/main/java/io/github/dsheirer/sample/buffer/IReusableComplexBufferListener.java index 2f7a7306..47eada60 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/IReusableComplexBufferListener.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/IReusableComplexBufferListener.java @@ -13,11 +13,11 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; import io.github.dsheirer.sample.Listener; -public interface IReusableComplexBufferListener +public interface IReusableComplexBufferListener { - Listener getReusableComplexBufferListener(); + Listener getReusableComplexBufferListener(); } diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/OverflowableReusableBufferTransferQueue.java b/src/main/java/io/github/dsheirer/sample/buffer/OverflowableReusableBufferTransferQueue.java similarity index 85% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/OverflowableReusableBufferTransferQueue.java rename to src/main/java/io/github/dsheirer/sample/buffer/OverflowableReusableBufferTransferQueue.java index 05486981..914833bb 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/OverflowableReusableBufferTransferQueue.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/OverflowableReusableBufferTransferQueue.java @@ -13,11 +13,11 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; import io.github.dsheirer.sample.OverflowableTransferQueue; -public class OverflowableReusableBufferTransferQueue extends OverflowableTransferQueue +public class OverflowableReusableBufferTransferQueue extends OverflowableTransferQueue { /** * Concurrent transfer queue that couples a higher-throughput linked transfer queue with an atomic integer for @@ -38,12 +38,12 @@ public class OverflowableReusableBufferTransferQueue extends OverflowableTransfe * Overrides the overflow method to decrement the user count on any buffers that are being discarded when the queue * is in an overflow state. * - * @param reusableComplexBuffer that will be discarded + * @param t reusableBuffer that will be discarded */ @Override - protected void overflow(ReusableComplexBuffer reusableComplexBuffer) + protected void overflow(T t) { - reusableComplexBuffer.decrementUserCount(); + t.decrementUserCount(); } /** @@ -54,7 +54,7 @@ public class OverflowableReusableBufferTransferQueue extends OverflowableTransfe { synchronized(mQueue) { - ReusableComplexBuffer buffer = mQueue.poll(); + T buffer = mQueue.poll(); while(buffer != null) { diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableComplexBuffer.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBuffer.java similarity index 80% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableComplexBuffer.java rename to src/main/java/io/github/dsheirer/sample/buffer/ReusableBuffer.java index 151852af..d9434004 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableComplexBuffer.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBuffer.java @@ -13,19 +13,20 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; -import io.github.dsheirer.sample.complex.ComplexBuffer; import org.apache.commons.lang3.Validate; import java.nio.FloatBuffer; import java.util.concurrent.atomic.AtomicInteger; -public class ReusableComplexBuffer extends ComplexBuffer +public class ReusableBuffer { - private IReusableBufferDisposedListener mDisposalListener; + private float[] mSamples; + private IReusableBufferDisposedListener mBufferDisposedListener; private long mTimestamp; private AtomicInteger mUserCount = new AtomicInteger(); + private String mDebugName; /** * Creates a reusable, timestamped complex buffer using the specified time in milliseconds. @@ -34,32 +35,40 @@ public class ReusableComplexBuffer extends ComplexBuffer * 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 disposalListener to be notified when all consumers/users are finished using the buffer + * @param bufferDisposedListener to be notified when all consumers/users are finished using the buffer * @param samples of data * @param timestamp in millis for the buffer */ - public ReusableComplexBuffer(IReusableBufferDisposedListener disposalListener, float[] samples, long timestamp) + ReusableBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples, long timestamp) { - super(samples); + mSamples = samples; - Validate.notNull(disposalListener, "Timestamped Buffer Listener cannot be null"); - mDisposalListener = disposalListener; + Validate.notNull(bufferDisposedListener, "Reusable Buffer Listener cannot be null"); + mBufferDisposedListener = bufferDisposedListener; mTimestamp = timestamp; } - /** - * Constructs a timestamped complex 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 disposalListener to be notified when all consumers are finished using the buffer - * @param samples of data - */ - public ReusableComplexBuffer(IReusableBufferDisposedListener disposalListener, float[] samples) + public void setDebugName(String debugName) { - this(disposalListener, samples, System.currentTimeMillis()); + mDebugName = debugName; + } + + public String name() + { + return (mDebugName != null ? mDebugName : "(null)") + " User Count:" + getUserCount(); + } + + public String toString() + { + return name(); + } + + /** + * Samples for this buffer + */ + public float[] getSamples() + { + return mSamples; } /** @@ -74,11 +83,26 @@ public class ReusableComplexBuffer extends ComplexBuffer } /** - * Number of complex samples contained in this buffer + * Number of samples contained in this buffer */ - public int getSampleLength() + public int getSampleCount() { - return getSamples().length / 2; + return getSamples().length; + } + + /** + * Constructs a timestamped complex 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 samples of data + */ + public ReusableBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples) + { + this(bufferDisposedListener, samples, System.currentTimeMillis()); } /** @@ -173,21 +197,19 @@ public class ReusableComplexBuffer extends ComplexBuffer * * This method is thread-safe. */ - public ReusableComplexBuffer decrementUserCount() + public void decrementUserCount() { int currentCount = mUserCount.decrementAndGet(); if(currentCount == 0) { - mDisposalListener.disposed(this); + mBufferDisposedListener.disposed(this); } else if(currentCount < 0) { throw new IllegalStateException("User count is below zero. This indicates that this buffer's decrement" + " user count was invoked by more than the expected user count"); } - - return this; } /** @@ -199,10 +221,9 @@ public class ReusableComplexBuffer extends ComplexBuffer * * This method is thread-safe. */ - public ReusableComplexBuffer incrementUserCount() + public void incrementUserCount() { mUserCount.incrementAndGet(); - return this; } /** @@ -216,9 +237,16 @@ public class ReusableComplexBuffer extends ComplexBuffer * * @param additionalUserCount to add to the current user count */ - public ReusableComplexBuffer incrementUserCount(int additionalUserCount) + public void incrementUserCount(int additionalUserCount) { mUserCount.addAndGet(additionalUserCount); - return this; + } + + /** + * Number of users currently registered for this buffer + */ + public int getUserCount() + { + return mUserCount.get(); } } diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferAssembler.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java similarity index 95% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferAssembler.java rename to src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java index a58b62f3..d1f2847d 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferAssembler.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java @@ -13,7 +13,7 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; import io.github.dsheirer.dsp.filter.channelizer.SampleTimestampManager; import io.github.dsheirer.sample.Listener; @@ -27,7 +27,7 @@ import java.nio.FloatBuffer; */ public class ReusableBufferAssembler { - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue(); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ReusableBufferAssembler"); private SampleTimestampManager mTimestampManager; private FloatBuffer mBuffer; private int mBufferSize; @@ -115,7 +115,7 @@ public class ReusableBufferAssembler if(mListener != null && mBuffer.position() > 0) { mBuffer.rewind(); - ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(mBufferSize); + ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mBufferSize); reusableComplexBuffer.reloadFrom(mBuffer, mCurrentBufferTimestamp); reusableComplexBuffer.setUserCount(1); mListener.receive(reusableComplexBuffer); diff --git a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferBroadcaster.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferBroadcaster.java similarity index 66% rename from src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferBroadcaster.java rename to src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferBroadcaster.java index e2ac0f80..2df8493c 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/reusable/ReusableBufferBroadcaster.java +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferBroadcaster.java @@ -13,7 +13,7 @@ * If not, see * ******************************************************************************/ -package io.github.dsheirer.sample.complex.reusable; +package io.github.dsheirer.sample.buffer; import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; @@ -36,29 +36,10 @@ public class ReusableBufferBroadcaster extends Broadcaster listener : mListeners) { - if(listenerCount > 0) - { - listener.receive(reusableComplexBuffer); - } - - listenerCount--; - } - - while(listenerCount > 0) - { - reusableComplexBuffer.decrementUserCount(); - listenerCount--; + reusableComplexBuffer.incrementUserCount(); + listener.receive(reusableComplexBuffer); } //Decrement user counter for this broadcaster diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java new file mode 100644 index 00000000..85bb5efc --- /dev/null +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferQueue.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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 ReusableBufferQueue extends AbstractReusableBufferQueue +{ + private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferQueue.class); + + public ReusableBufferQueue(String debugName) + { + super(debugName); + } + + public ReusableBufferQueue() + { + } + + @Override + protected ReusableBuffer createBuffer(int size) + { + return new ReusableBuffer(this, new float[size]); + } +} diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java new file mode 100644 index 00000000..bc768d7c --- /dev/null +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBuffer.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * 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; + +public class ReusableComplexBuffer extends ReusableBuffer +{ + /** + * Creates a reusable, timestamped complex 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 disposalListener to be notified when all consumers/users are finished using the buffer + * @param samples of data + * @param timestamp in millis for the buffer + */ + ReusableComplexBuffer(IReusableBufferDisposedListener disposalListener, float[] samples, long timestamp) + { + super(disposalListener, samples, timestamp); + } + + /** + * Constructs a timestamped complex 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 disposalListener to be notified when all consumers are finished using the buffer + * @param samples of data + */ + protected ReusableComplexBuffer(IReusableBufferDisposedListener disposalListener, float[] samples) + { + this(disposalListener, samples, System.currentTimeMillis()); + } + + /** + * Number of complex samples contained in this buffer + */ + @Override + public int getSampleCount() + { + return getSamples().length / 2; + } +} diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferQueue.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferQueue.java new file mode 100644 index 00000000..0c52454e --- /dev/null +++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferQueue.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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 ReusableComplexBufferQueue extends AbstractReusableBufferQueue +{ + private final static Logger mLog = LoggerFactory.getLogger(ReusableComplexBufferQueue.class); + + public ReusableComplexBufferQueue(String debugName) + { + super(debugName); + } + + public ReusableComplexBufferQueue() + { + } + + @Override + protected ReusableComplexBuffer createBuffer(int size) + { + return new ReusableComplexBuffer(this, new float[size]); + } +} diff --git a/src/main/java/io/github/dsheirer/source/ComplexSource.java b/src/main/java/io/github/dsheirer/source/ComplexSource.java index a06be2dc..098641d5 100644 --- a/src/main/java/io/github/dsheirer/source/ComplexSource.java +++ b/src/main/java/io/github/dsheirer/source/ComplexSource.java @@ -17,7 +17,7 @@ package io.github.dsheirer.source; import io.github.dsheirer.sample.Provider; import io.github.dsheirer.sample.SampleType; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; public abstract class ComplexSource extends Source implements Provider { diff --git a/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java b/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java index fc117def..9d83fdac 100644 --- a/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java +++ b/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java @@ -17,8 +17,8 @@ package io.github.dsheirer.source.mixer; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.adapter.IComplexSampleAdapter; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.source.SourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +42,7 @@ public class ComplexMixer private int mBytesPerFrame = 0; private IComplexSampleAdapter mSampleAdapter; private Listener mListener; - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue(); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexMixer"); /** * Complex Mixer - constructs a reader on the mixer/sound card target data line using the specified audio @@ -173,7 +173,7 @@ public class ComplexMixer /* Dispatch samples to registered listeners */ if(mListener != null) { - ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(sampleCount); + ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(sampleCount); //Convert samples and load into reusable buffer mSampleAdapter.convertAndLoad(buffer, reusableComplexBuffer); diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java index ebd1c516..4d4b3377 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java @@ -18,9 +18,9 @@ package io.github.dsheirer.source.tuner; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferProvider; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.IReusableBufferProvider; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.ISourceEventListener; import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.SourceEvent; @@ -33,10 +33,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener, - IReusableComplexBufferProvider, Listener + IReusableBufferProvider, Listener { private final static Logger mLog = LoggerFactory.getLogger(TunerController.class); - protected ReusableBufferBroadcaster mSampleBroadcaster = new ReusableBufferBroadcaster(); + protected ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster(); protected FrequencyController mFrequencyController; private int mMiddleUnusableHalfBandwidth; private double mUsableBandwidthPercentage; @@ -263,7 +263,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor, @Override public void addBufferListener(Listener listener) { - mSampleBroadcaster.addListener(listener); + mReusableBufferBroadcaster.addListener(listener); } /** @@ -272,7 +272,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor, @Override public void removeBufferListener(Listener listener) { - mSampleBroadcaster.removeListener(listener); + mReusableBufferBroadcaster.removeListener(listener); } /** @@ -281,7 +281,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor, @Override public boolean hasBufferListeners() { - return mSampleBroadcaster.hasListeners(); + return mReusableBufferBroadcaster.hasListeners(); } /** @@ -289,7 +289,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor, */ protected void broadcast(ReusableComplexBuffer reusableComplexBuffer) { - mSampleBroadcaster.broadcast(reusableComplexBuffer.incrementUserCount()); + mReusableBufferBroadcaster.broadcast(reusableComplexBuffer); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java b/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java index b195afac..914458ab 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java +++ b/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java @@ -19,7 +19,7 @@ package io.github.dsheirer.source.tuner.channel; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.ComplexSource; import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.SourceEvent; diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/FCDTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/FCDTunerController.java index 9e77661e..002bcc63 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/FCDTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/FCDTunerController.java @@ -20,7 +20,7 @@ package io.github.dsheirer.source.tuner.fcd; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.adapter.ComplexShortAdapter; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.mixer.ComplexMixer; import io.github.dsheirer.source.tuner.MixerTunerDataLine; @@ -88,7 +88,7 @@ public abstract class FCDTunerController extends TunerController } mComplexMixer = new ComplexMixer( mixerTDL.getTargetDataLine(), audioFormat, tunerName, - new ComplexShortAdapter(), mSampleBroadcaster); + new ComplexShortAdapter(), mReusableBufferBroadcaster); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/ChannelSourceManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/ChannelSourceManager.java index 9280ac4b..1b113313 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/manager/ChannelSourceManager.java +++ b/src/main/java/io/github/dsheirer/source/tuner/manager/ChannelSourceManager.java @@ -54,7 +54,8 @@ public abstract class ChannelSourceManager implements ISourceEventProcessor */ public abstract TunerChannelSource getSource(TunerChannel tunerChannel); - public abstract TunerChannelSource getSpecialSource(int index); + //TODO: remove this testing method when finished with polyphase channel manager + public abstract TunerChannelSource getTestingSource(int index); /** * Adds a listener to receive source events diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/TunerChannelSourceManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/TunerChannelSourceManager.java index d3f2e7d8..0390fa40 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/manager/TunerChannelSourceManager.java +++ b/src/main/java/io/github/dsheirer/source/tuner/manager/TunerChannelSourceManager.java @@ -50,10 +50,10 @@ public class TunerChannelSourceManager extends ChannelSourceManager } @Override - public TunerChannelSource getSpecialSource(int index) + public TunerChannelSource getTestingSource(int index) { //TODO: remove this debug method - return mPolyphaseChannelManager.getSpecialChannel(index); + return mPolyphaseChannelManager.getTestChannel(index); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java index a6c8c138..95fe2445 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java @@ -22,7 +22,7 @@ package io.github.dsheirer.source.tuner.rtl; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.tuner.TunerManager; import io.github.dsheirer.source.tuner.TunerType; diff --git a/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java b/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java index 123fde8f..5c34cdb1 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java +++ b/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java @@ -18,9 +18,9 @@ package io.github.dsheirer.source.tuner.test; import io.github.dsheirer.dsp.mixer.IOscillator; import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.util.ThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -185,18 +185,19 @@ public class SampleGenerator public class Generator implements Runnable { private int mTriggerInterval = 0; - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("** Sample Generator **"); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("SampleGenerator"); @Override public void run() { if(mComplexBufferBroadcaster.hasListeners()) { - ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(mSamplesPerInterval); + ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerInterval); mOscillator.generateComplex(reusableComplexBuffer); - mComplexBufferBroadcaster.broadcast(reusableComplexBuffer.incrementUserCount()); + reusableComplexBuffer.incrementUserCount(); + mComplexBufferBroadcaster.broadcast(reusableComplexBuffer); if(mSweepUpdateInterval != 0) { diff --git a/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java index 0638232b..fc2489f2 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java @@ -19,7 +19,7 @@ package io.github.dsheirer.source.tuner.test; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.tuner.TunerController; import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; diff --git a/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java b/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java index 129f228e..55a09d1c 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java @@ -16,7 +16,7 @@ package io.github.dsheirer.source.tuner.usb; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.tuner.TunerManager; import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter; import io.github.dsheirer.util.ThreadPool; @@ -394,9 +394,10 @@ public class USBTransferProcessor implements TransferCallback { ByteBuffer nativeBuffer = transfer.buffer(); - ReusableComplexBuffer sampleBuffer = mNativeBufferConverter.convert(nativeBuffer, transfer.actualLength()); + ReusableComplexBuffer reusableComplexBuffer = + mNativeBufferConverter.convert(nativeBuffer, transfer.actualLength()); - mComplexBufferListener.receive(sampleBuffer); + mComplexBufferListener.receive(reusableComplexBuffer); } transfer.buffer().rewind(); diff --git a/src/main/java/io/github/dsheirer/source/tuner/usb/USBTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/usb/USBTunerController.java index db114e7d..185f901a 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/usb/USBTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/usb/USBTunerController.java @@ -19,7 +19,7 @@ package io.github.dsheirer.source.tuner.usb; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.tuner.TunerController; public abstract class USBTunerController extends TunerController diff --git a/src/main/java/io/github/dsheirer/source/tuner/usb/converter/NativeBufferConverter.java b/src/main/java/io/github/dsheirer/source/tuner/usb/converter/NativeBufferConverter.java index 9d9dfcbf..cbe86064 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/usb/converter/NativeBufferConverter.java +++ b/src/main/java/io/github/dsheirer/source/tuner/usb/converter/NativeBufferConverter.java @@ -15,15 +15,15 @@ ******************************************************************************/ package io.github.dsheirer.source.tuner.usb.converter; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import java.nio.ByteBuffer; import java.nio.FloatBuffer; public abstract class NativeBufferConverter { - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue(); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("NativeBufferConverter"); /** * Converts native byte buffers into complex float samples and produces reusable complex sample buffers. Tracks @@ -45,10 +45,11 @@ public abstract class NativeBufferConverter { FloatBuffer floatBuffer = convertSamples(byteBuffer, length); - ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(floatBuffer.capacity()); + ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(floatBuffer.capacity()); //The reusable buffer will rewind the float buffer to the beginning reusableComplexBuffer.reloadFrom(floatBuffer, System.currentTimeMillis()); + reusableComplexBuffer.incrementUserCount(); return reusableComplexBuffer; } diff --git a/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java b/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java index 256a53f3..219a5e1b 100644 --- a/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java +++ b/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java @@ -17,8 +17,8 @@ package io.github.dsheirer.source.wave; import io.github.dsheirer.sample.ConversionUtils; import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.source.ComplexSource; import io.github.dsheirer.source.IControllableFileSource; import io.github.dsheirer.source.IFrameLocationListener; @@ -45,7 +45,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil private Listener mListener; private AudioInputStream mInputStream; private File mFile; - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("Complex Wave Source"); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexWaveSource"); public ComplexWaveSource(File file) throws IOException { @@ -216,7 +216,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer); - ReusableComplexBuffer reusableBuffer = mReusableBufferQueue.getBuffer(samples.length); + ReusableComplexBuffer reusableBuffer = mReusableComplexBufferQueue.getBuffer(samples.length); reusableBuffer.reloadFrom(samples, System.currentTimeMillis()); reusableBuffer.incrementUserCount(); mListener.receive(reusableBuffer); diff --git a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java index 0431ff26..4cc781df 100644 --- a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java +++ b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java @@ -26,8 +26,8 @@ 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.complex.reusable.ReusableBufferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue; import io.github.dsheirer.sample.real.RealBuffer; import io.github.dsheirer.settings.ColorSetting.ColorSettingName; import io.github.dsheirer.settings.ColorSettingMenuItem; @@ -69,435 +69,450 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener private JLayeredPane mLayeredPane; private SpectrumPanel mSpectrumPanel; private ChannelOverlayPanel mOverlayPanel; - private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue(); + private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ChannelSpectrumPanel"); private Channel mCurrentChannel; private int mSampleBufferSize = 2400; - private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB( - Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true ); - + private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB( + Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true); + private AtomicBoolean mEnabled = new AtomicBoolean(); - + private SettingsManager mSettingsManager; private ChannelProcessingManager mChannelProcessingManager; - public ChannelSpectrumPanel( SettingsManager settingsManager, - ChannelProcessingManager channelProcessingManager ) + public ChannelSpectrumPanel(SettingsManager settingsManager, + ChannelProcessingManager channelProcessingManager) { - mSettingsManager = settingsManager; - mChannelProcessingManager = channelProcessingManager; - - if( mSettingsManager != null ) - { - mSettingsManager.addListener( this ); - } - - mSpectrumPanel = new SpectrumPanel( mSettingsManager ); - mSpectrumPanel.setAveraging( 1 ); + mSettingsManager = settingsManager; + mChannelProcessingManager = channelProcessingManager; - mOverlayPanel = new ChannelOverlayPanel( mSettingsManager ); - mDFTProcessor.addConverter( mDFTConverter ); - mDFTConverter.addListener( mSpectrumPanel ); + if(mSettingsManager != null) + { + mSettingsManager.addListener(this); + } + + mSpectrumPanel = new SpectrumPanel(mSettingsManager); + mSpectrumPanel.setAveraging(1); + + mOverlayPanel = new ChannelOverlayPanel(mSettingsManager); + mDFTProcessor.addConverter(mDFTConverter); + mDFTConverter.addListener(mSpectrumPanel); /* Set the DFTProcessor to the decimated 24kHz sample rate */ mDFTProcessor.process(SourceEvent.sampleRateChange(24000.0)); initGui(); } - + public void dispose() { - setEnabled( false ); - - mDFTProcessor.dispose(); + setEnabled(false); - if( mSettingsManager != null ) - { - mSettingsManager.removeListener( this ); - } - - mSettingsManager = null; - mCurrentChannel = null; - mDFTProcessor = null; - mSpectrumPanel = null; + mDFTProcessor.dispose(); + + if(mSettingsManager != null) + { + mSettingsManager.removeListener(this); + } + + mSettingsManager = null; + mCurrentChannel = null; + mDFTProcessor = null; + mSpectrumPanel = null; } - - public void setFrameRate( int framesPerSecond ) + + public void setFrameRate(int framesPerSecond) { - mSampleBufferSize = (int)( 48000 / framesPerSecond ); - - mDFTProcessor.setFrameRate( framesPerSecond ); + mSampleBufferSize = (int)(48000 / framesPerSecond); + + mDFTProcessor.setFrameRate(framesPerSecond); } - + private void initGui() { - setLayout( new MigLayout( "insets 0 0 0 0 ", - "[grow,fill]", - "[grow,fill]") ); - - mLayeredPane = new JLayeredPane(); - mLayeredPane.addComponentListener( new ResizeListener() ); - - MouseEventProcessor mouser = new MouseEventProcessor(); - - mOverlayPanel.addMouseListener( mouser ); - mOverlayPanel.addMouseMotionListener( mouser ); - - mLayeredPane.add( mSpectrumPanel, new Integer( 0 ), 0 ); - mLayeredPane.add( mOverlayPanel, new Integer( 1 ), 0 ); + setLayout(new MigLayout("insets 0 0 0 0 ", + "[grow,fill]", + "[grow,fill]")); - add( mLayeredPane ); + mLayeredPane = new JLayeredPane(); + mLayeredPane.addComponentListener(new ResizeListener()); + + MouseEventProcessor mouser = new MouseEventProcessor(); + + mOverlayPanel.addMouseListener(mouser); + mOverlayPanel.addMouseMotionListener(mouser); + + mLayeredPane.add(mSpectrumPanel, new Integer(0), 0); + mLayeredPane.add(mOverlayPanel, new Integer(1), 0); + + add(mLayeredPane); } - - public void setEnabled( boolean enabled ) + + public void setEnabled(boolean enabled) { - if( enabled && mEnabled.compareAndSet( false, true ) ) - { - start(); - } - else if( !enabled && mEnabled.compareAndSet( true, false ) ) - { - stop(); - } + if(enabled && mEnabled.compareAndSet(false, true)) + { + start(); + } + else if(!enabled && mEnabled.compareAndSet(true, false)) + { + stop(); + } } @Override - @SuppressWarnings( "incomplete-switch" ) - public void channelChanged( ChannelEvent event ) + @SuppressWarnings("incomplete-switch") + public void channelChanged(ChannelEvent event) { - switch( event.getEvent() ) - { - case NOTIFICATION_SELECTION_CHANGE: - //ChannelSelectionManager ensures that only 1 channel can be - //selected and any previously selected channel will be first - //deselected before we get a new selection event - if( event.getChannel().isSelected() ) - { - if( mCurrentChannel != null ) - { - stop(); - mCurrentChannel = null; - } - - mCurrentChannel = event.getChannel(); - - if( mEnabled.get() ) - { - start(); - } - } - else - { - stop(); - mCurrentChannel = null; - } - break; - case NOTIFICATION_PROCESSING_STOP: - if( event.getChannel() == mCurrentChannel ) - { - if( mEnabled.get() ) - { - stop(); - } + switch(event.getEvent()) + { + case NOTIFICATION_SELECTION_CHANGE: + //ChannelSelectionManager ensures that only 1 channel can be + //selected and any previously selected channel will be first + //deselected before we get a new selection event + if(event.getChannel().isSelected()) + { + if(mCurrentChannel != null) + { + stop(); + mCurrentChannel = null; + } - mCurrentChannel = null; - } - break; - } - } - - private void start() - { - if( mEnabled.get() && mCurrentChannel != null && mCurrentChannel.isProcessing() ) - { - ProcessingChain processingChain = mChannelProcessingManager - .getProcessingChain( mCurrentChannel ); + mCurrentChannel = event.getChannel(); - if( processingChain != null ) - { - processingChain.addRealBufferListener( this ); - - mDFTProcessor.start(); - } - } - } - - private void stop() - { - if( mCurrentChannel != null && mCurrentChannel.isProcessing() ) - { - ProcessingChain processingChain = mChannelProcessingManager - .getProcessingChain( mCurrentChannel ); + if(mEnabled.get()) + { + start(); + } + } + else + { + stop(); + mCurrentChannel = null; + } + break; + case NOTIFICATION_PROCESSING_STOP: + if(event.getChannel() == mCurrentChannel) + { + if(mEnabled.get()) + { + stop(); + } - if( processingChain != null ) - { - processingChain.removeRealBufferListener( this ); - } - } - - mDFTProcessor.stop(); - - mSpectrumPanel.clearSpectrum(); - } - - @Override - public void settingChanged( Setting setting ) - { - if( mSpectrumPanel != null ) - { - mSpectrumPanel.settingChanged( setting ); - } - if( mOverlayPanel != null ) - { - mOverlayPanel.settingChanged( setting ); - } + mCurrentChannel = null; + } + break; + } } - @Override - public void settingDeleted( Setting setting ) + private void start() { - if( mSpectrumPanel != null ) - { - mSpectrumPanel.settingDeleted( setting ); - } + if(mEnabled.get() && mCurrentChannel != null && mCurrentChannel.isProcessing()) + { + ProcessingChain processingChain = mChannelProcessingManager + .getProcessingChain(mCurrentChannel); - if( mOverlayPanel != null ) - { - mOverlayPanel.settingDeleted( setting ); - } + if(processingChain != null) + { + processingChain.addRealBufferListener(this); + + mDFTProcessor.start(); + } + } } - @Override - public void receive( RealBuffer buffer ) + private void stop() { - RealBuffer decimated = mDecimatingFilter.filter( buffer ); + if(mCurrentChannel != null && mCurrentChannel.isProcessing()) + { + ProcessingChain processingChain = mChannelProcessingManager + .getProcessingChain(mCurrentChannel); + + if(processingChain != null) + { + processingChain.removeRealBufferListener(this); + } + } + + mDFTProcessor.stop(); + + mSpectrumPanel.clearSpectrum(); + } + + @Override + public void settingChanged(Setting setting) + { + if(mSpectrumPanel != null) + { + mSpectrumPanel.settingChanged(setting); + } + if(mOverlayPanel != null) + { + mOverlayPanel.settingChanged(setting); + } + } + + @Override + public void settingDeleted(Setting setting) + { + if(mSpectrumPanel != null) + { + mSpectrumPanel.settingDeleted(setting); + } + + if(mOverlayPanel != null) + { + mOverlayPanel.settingDeleted(setting); + } + } + + @Override + public void receive(RealBuffer buffer) + { + RealBuffer decimated = mDecimatingFilter.filter(buffer); //Hack: we're placing real samples in a complex buffer that the DFT //processor is expecting. - ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(decimated.getSamples().length); + ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(decimated.getSamples().length); reusableComplexBuffer.reloadFrom(decimated.getSamples(), System.currentTimeMillis()); - mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount()); + reusableComplexBuffer.incrementUserCount(); + mDFTProcessor.receive(reusableComplexBuffer); } - /** - * Monitors the sizing of the layered pane and resizes the spectrum and - * channel panels whenever the layered pane is resized - */ - public class ResizeListener implements ComponentListener - { - @Override - public void componentResized( ComponentEvent e ) + /** + * Monitors the sizing of the layered pane and resizes the spectrum and + * channel panels whenever the layered pane is resized + */ + public class ResizeListener implements ComponentListener + { + @Override + public void componentResized(ComponentEvent e) { - Component c = e.getComponent(); - - mSpectrumPanel.setBounds( 0, 0, c.getWidth(), c.getHeight() ); - mOverlayPanel.setBounds( 0, 0, c.getWidth(), c.getHeight() ); + Component c = e.getComponent(); + + mSpectrumPanel.setBounds(0, 0, c.getWidth(), c.getHeight()); + mOverlayPanel.setBounds(0, 0, c.getWidth(), c.getHeight()); } - @Override - public void componentHidden( ComponentEvent arg0 ) {} - @Override - public void componentMoved( ComponentEvent arg0 ) {} - @Override - public void componentShown( ComponentEvent arg0 ) {} - } - - /** - * Mouse event handler for the channel panel. - */ - public class MouseEventProcessor implements MouseMotionListener, MouseListener - { - @Override - public void mouseMoved( MouseEvent event ) + @Override + public void componentHidden(ComponentEvent arg0) { - update( event ); - } - @Override - public void mouseDragged( MouseEvent event ) - { - update( event ); - } - - private void update( MouseEvent event ) - { - if( event.getComponent() == mOverlayPanel ) - { - mOverlayPanel.setCursorLocation( event.getPoint() ); - } - } - - @Override - public void mouseEntered( MouseEvent e ) - { - if( e.getComponent() == mOverlayPanel ) - { - mOverlayPanel.setCursorVisible( true ); - } - } - - @Override - public void mouseExited( MouseEvent e ) - { - mOverlayPanel.setCursorVisible( false ); - } - - /** - * Displays the context menu. - */ - @Override - public void mouseClicked( MouseEvent event ) - { - if( SwingUtilities.isRightMouseButton( event ) ) - { - JPopupMenu contextMenu = new JPopupMenu(); - - /** - * Color Menus - */ - JMenu colorMenu = new JMenu( "Color" ); - - colorMenu.add( new ColorSettingMenuItem( mSettingsManager, - ColorSettingName.SPECTRUM_CURSOR ) ); - - colorMenu.add( new ColorSettingMenuItem( mSettingsManager, - ColorSettingName.SPECTRUM_LINE ) ); - - colorMenu.add( new ColorSettingMenuItem( mSettingsManager, - ColorSettingName.SPECTRUM_BACKGROUND ) ); - - colorMenu.add( new ColorSettingMenuItem( mSettingsManager, - ColorSettingName.SPECTRUM_GRADIENT_BOTTOM ) ); - - colorMenu.add( new ColorSettingMenuItem( mSettingsManager, - ColorSettingName.SPECTRUM_GRADIENT_TOP ) ); - - contextMenu.add( colorMenu ); - - /** - * Display items: fft and frame rate - */ - JMenu displayMenu = new JMenu( "Display" ); - contextMenu.add( displayMenu ); - - /** - * Averaging menu - */ - JMenu averagingMenu = new JMenu( "Averaging" ); - averagingMenu.add( - new AveragingItem( ChannelSpectrumPanel.this, 2 ) ); - displayMenu.add( averagingMenu ); - - /** - * FFT width - */ - JMenu fftWidthMenu = new JMenu( "FFT Width" ); - displayMenu.add( fftWidthMenu ); - - for( DFTSize width: DFTSize.values() ) - { - fftWidthMenu.add( new DFTSizeItem( mDFTProcessor, width ) ); - } - - /** - * DFT Processor Frame Rate - */ - JMenu frameRateMenu = new JMenu( "Frame Rate" ); - displayMenu.add( frameRateMenu ); - - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 14 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 16 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 18 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 20 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 25 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 30 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 40 ) ); - frameRateMenu.add( new FrameRateItem( mDFTProcessor, 50 ) ); - - /** - * FFT Window Type - */ - JMenu fftWindowType = new JMenu( "Window Type" ); - displayMenu.add( fftWindowType ); - - for( WindowType type: WindowType.values() ) - { - fftWindowType.add( - new FFTWindowTypeItem( mDFTProcessor, type ) ); - } - - /** - * Smoothing menu - */ - JMenu smoothingMenu = new JMenu( "Smoothing" ); - - if( mSpectrumPanel.getSmoothingType() != SmoothingType.NONE ) - { - smoothingMenu.add( new SmoothingItem( ChannelSpectrumPanel.this, 5 ) ); - smoothingMenu.add( new JSeparator() ); - } - - smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.GAUSSIAN ) ); - smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.TRIANGLE ) ); - smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.RECTANGLE ) ); - smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.NONE ) ); - - displayMenu.add( smoothingMenu ); - - if( contextMenu != null ) - { - contextMenu.show( mOverlayPanel, - event.getX(), - event.getY() ); - } - } } - @Override - public void mousePressed( MouseEvent e ) {} - @Override - public void mouseReleased( MouseEvent e ) {} - } + @Override + public void componentMoved(ComponentEvent arg0) + { + } - @Override + @Override + public void componentShown(ComponentEvent arg0) + { + } + } + + /** + * Mouse event handler for the channel panel. + */ + public class MouseEventProcessor implements MouseMotionListener, MouseListener + { + @Override + public void mouseMoved(MouseEvent event) + { + update(event); + } + + @Override + public void mouseDragged(MouseEvent event) + { + update(event); + } + + private void update(MouseEvent event) + { + if(event.getComponent() == mOverlayPanel) + { + mOverlayPanel.setCursorLocation(event.getPoint()); + } + } + + @Override + public void mouseEntered(MouseEvent e) + { + if(e.getComponent() == mOverlayPanel) + { + mOverlayPanel.setCursorVisible(true); + } + } + + @Override + public void mouseExited(MouseEvent e) + { + mOverlayPanel.setCursorVisible(false); + } + + /** + * Displays the context menu. + */ + @Override + public void mouseClicked(MouseEvent event) + { + if(SwingUtilities.isRightMouseButton(event)) + { + JPopupMenu contextMenu = new JPopupMenu(); + + /** + * Color Menus + */ + JMenu colorMenu = new JMenu("Color"); + + colorMenu.add(new ColorSettingMenuItem(mSettingsManager, + ColorSettingName.SPECTRUM_CURSOR)); + + colorMenu.add(new ColorSettingMenuItem(mSettingsManager, + ColorSettingName.SPECTRUM_LINE)); + + colorMenu.add(new ColorSettingMenuItem(mSettingsManager, + ColorSettingName.SPECTRUM_BACKGROUND)); + + colorMenu.add(new ColorSettingMenuItem(mSettingsManager, + ColorSettingName.SPECTRUM_GRADIENT_BOTTOM)); + + colorMenu.add(new ColorSettingMenuItem(mSettingsManager, + ColorSettingName.SPECTRUM_GRADIENT_TOP)); + + contextMenu.add(colorMenu); + + /** + * Display items: fft and frame rate + */ + JMenu displayMenu = new JMenu("Display"); + contextMenu.add(displayMenu); + + /** + * Averaging menu + */ + JMenu averagingMenu = new JMenu("Averaging"); + averagingMenu.add( + new AveragingItem(ChannelSpectrumPanel.this, 2)); + displayMenu.add(averagingMenu); + + /** + * FFT width + */ + JMenu fftWidthMenu = new JMenu("FFT Width"); + displayMenu.add(fftWidthMenu); + + for(DFTSize width : DFTSize.values()) + { + fftWidthMenu.add(new DFTSizeItem(mDFTProcessor, width)); + } + + /** + * DFT Processor Frame Rate + */ + JMenu frameRateMenu = new JMenu("Frame Rate"); + displayMenu.add(frameRateMenu); + + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 14)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 16)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 18)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 20)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 25)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 30)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 40)); + frameRateMenu.add(new FrameRateItem(mDFTProcessor, 50)); + + /** + * FFT Window Type + */ + JMenu fftWindowType = new JMenu("Window Type"); + displayMenu.add(fftWindowType); + + for(WindowType type : WindowType.values()) + { + fftWindowType.add( + new FFTWindowTypeItem(mDFTProcessor, type)); + } + + /** + * Smoothing menu + */ + JMenu smoothingMenu = new JMenu("Smoothing"); + + if(mSpectrumPanel.getSmoothingType() != SmoothingType.NONE) + { + smoothingMenu.add(new SmoothingItem(ChannelSpectrumPanel.this, 5)); + smoothingMenu.add(new JSeparator()); + } + + smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.GAUSSIAN)); + smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.TRIANGLE)); + smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.RECTANGLE)); + smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.NONE)); + + displayMenu.add(smoothingMenu); + + if(contextMenu != null) + { + contextMenu.show(mOverlayPanel, + event.getX(), + event.getY()); + } + } + } + + @Override + public void mousePressed(MouseEvent e) + { + } + + @Override + public void mouseReleased(MouseEvent e) + { + } + } + + @Override public int getAveraging() { - return mSpectrumPanel.getAveraging(); + return mSpectrumPanel.getAveraging(); } - @Override - public void setAveraging( int averaging ) + @Override + public void setAveraging(int averaging) { - mSpectrumPanel.setAveraging( averaging ); + mSpectrumPanel.setAveraging(averaging); } - public void setSampleSize( double sampleSize ) - { - mSpectrumPanel.setSampleSize( sampleSize ); - } + public void setSampleSize(double sampleSize) + { + mSpectrumPanel.setSampleSize(sampleSize); + } - @Override - public int getSmoothing() - { - return mSpectrumPanel.getSmoothing(); - } + @Override + public int getSmoothing() + { + return mSpectrumPanel.getSmoothing(); + } - @Override - public void setSmoothing( int smoothing ) - { - mSpectrumPanel.setSmoothing( smoothing ); - } + @Override + public void setSmoothing(int smoothing) + { + mSpectrumPanel.setSmoothing(smoothing); + } - @Override - public SmoothingType getSmoothingType() - { - return mSpectrumPanel.getSmoothingType(); - } + @Override + public SmoothingType getSmoothingType() + { + return mSpectrumPanel.getSmoothingType(); + } - @Override - public void setSmoothingType( SmoothingType type ) - { - mSpectrumPanel.setSmoothingType( type ); - } + @Override + public void setSmoothingType(SmoothingType type) + { + mSpectrumPanel.setSmoothingType(type); + } } diff --git a/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java b/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java index 172a278f..4a281381 100644 --- a/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java +++ b/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java @@ -20,7 +20,7 @@ import io.github.dsheirer.dsp.filter.Window.WindowType; import io.github.dsheirer.properties.SystemProperties; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.SampleType; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.real.IOverflowListener; import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.SourceEvent; diff --git a/src/main/java/io/github/dsheirer/spectrum/OverflowableBufferStream.java b/src/main/java/io/github/dsheirer/spectrum/OverflowableBufferStream.java index 1525d8e4..af6077d2 100644 --- a/src/main/java/io/github/dsheirer/spectrum/OverflowableBufferStream.java +++ b/src/main/java/io/github/dsheirer/spectrum/OverflowableBufferStream.java @@ -17,7 +17,7 @@ package io.github.dsheirer.spectrum; import io.github.dsheirer.sample.OverflowableTransferQueue; -import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -206,6 +206,13 @@ public class OverflowableBufferStream extends OverflowableTransferQueue