mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 09:37:36 -05:00
39 [WIP] cleans up the reusable buffers and creates both real and
complex variants.
This commit is contained in:
1
.idea/dictionaries/denny.xml
generated
1
.idea/dictionaries/denny.xml
generated
@@ -14,6 +14,7 @@
|
|||||||
<w>overflowable</w>
|
<w>overflowable</w>
|
||||||
<w>polyphase</w>
|
<w>polyphase</w>
|
||||||
<w>remez</w>
|
<w>remez</w>
|
||||||
|
<w>resampler</w>
|
||||||
<w>samplerate</w>
|
<w>samplerate</w>
|
||||||
<w>sdrtrunk</w>
|
<w>sdrtrunk</w>
|
||||||
<w>sheirer</w>
|
<w>sheirer</w>
|
||||||
|
|||||||
179
src/main/java/io/github/dsheirer/audio/AudioModule2.java
Normal file
179
src/main/java/io/github/dsheirer/audio/AudioModule2.java
Normal file
@@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
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<RealBuffer>
|
||||||
|
{
|
||||||
|
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<AudioPacket> mAudioPacketListener;
|
||||||
|
private Listener<ReusableBuffer> mResampledBufferListener;
|
||||||
|
private RealResampler mAudioResampler;
|
||||||
|
private Metadata mMetadata;
|
||||||
|
|
||||||
|
public AudioModule2(Metadata metadata)
|
||||||
|
{
|
||||||
|
mMetadata = metadata;
|
||||||
|
|
||||||
|
mResampledBufferListener = new Listener<ReusableBuffer>()
|
||||||
|
{
|
||||||
|
@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<RealBuffer> getFilteredRealBufferListener()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAudioPacketListener(Listener<AudioPacket> listener)
|
||||||
|
{
|
||||||
|
mAudioPacketListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAudioPacketListener()
|
||||||
|
{
|
||||||
|
mAudioPacketListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Listener<SourceEvent> getSourceEventListener()
|
||||||
|
{
|
||||||
|
return new Listener<SourceEvent>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void receive(SourceEvent sourceEvent)
|
||||||
|
{
|
||||||
|
if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_SAMPLE_RATE_CHANGE)
|
||||||
|
{
|
||||||
|
setSampleRate(sourceEvent.getValue().doubleValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Listener<SquelchState> getSquelchStateListener()
|
||||||
|
{
|
||||||
|
return mSquelchStateListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for squelch state listener
|
||||||
|
*/
|
||||||
|
public class SquelchStateListener implements Listener<SquelchState>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void receive(SquelchState state)
|
||||||
|
{
|
||||||
|
if(state == SquelchState.SQUELCH && mAudioPacketListener != null)
|
||||||
|
{
|
||||||
|
mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
|
||||||
|
}
|
||||||
|
|
||||||
|
mSquelchState = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ package io.github.dsheirer.dsp.filter.channelizer;
|
|||||||
|
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.ISourceEventListener;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ package io.github.dsheirer.dsp.filter.channelizer;
|
|||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
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.settings.SettingsManager;
|
||||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
@@ -258,7 +258,7 @@ public class ChannelizerViewer extends JFrame
|
|||||||
|
|
||||||
for(int x = 0; x < mChannelCount; x++)
|
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);
|
DiscreteChannelPanel channelPanel = new DiscreteChannelPanel(mSettingsManager, source, x);
|
||||||
channelPanel.setDFTSize(mChannelPanelDFTSize);
|
channelPanel.setDFTSize(mChannelPanelDFTSize);
|
||||||
|
|
||||||
@@ -327,8 +327,7 @@ public class ChannelizerViewer extends JFrame
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
mDFTProcessor.receive(reusableComplexBuffer);
|
||||||
reusableComplexBuffer.decrementUserCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -373,7 +372,8 @@ public class ChannelizerViewer extends JFrame
|
|||||||
mLog.debug("Samples:" + Arrays.toString(complexBuffer.getSamples()));
|
mLog.debug("Samples:" + Arrays.toString(complexBuffer.getSamples()));
|
||||||
}
|
}
|
||||||
|
|
||||||
mDFTProcessor.receive(complexBuffer.incrementUserCount());
|
complexBuffer.incrementUserCount();
|
||||||
|
mDFTProcessor.receive(complexBuffer);
|
||||||
complexBuffer.decrementUserCount();
|
complexBuffer.decrementUserCount();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -420,7 +420,8 @@ public class ChannelizerViewer extends JFrame
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
reusableComplexBuffer.incrementUserCount();
|
||||||
|
mDFTProcessor.receive(reusableComplexBuffer);
|
||||||
reusableComplexBuffer.decrementUserCount();
|
reusableComplexBuffer.decrementUserCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +477,8 @@ public class ChannelizerViewer extends JFrame
|
|||||||
mLog.debug("Samples:" + Arrays.toString(complexBuffer.getSamples()));
|
mLog.debug("Samples:" + Arrays.toString(complexBuffer.getSamples()));
|
||||||
}
|
}
|
||||||
|
|
||||||
mDFTProcessor.receive(complexBuffer.incrementUserCount());
|
complexBuffer.incrementUserCount();
|
||||||
|
mDFTProcessor.receive(complexBuffer);
|
||||||
complexBuffer.decrementUserCount();
|
complexBuffer.decrementUserCount();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -502,7 +504,8 @@ public class ChannelizerViewer extends JFrame
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
reusableComplexBuffer.incrementUserCount();
|
||||||
|
mDFTProcessor.receive(reusableComplexBuffer);
|
||||||
reusableComplexBuffer.decrementUserCount();
|
reusableComplexBuffer.decrementUserCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ package io.github.dsheirer.dsp.filter.channelizer;
|
|||||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||||
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
||||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
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.jtransforms.fft.FloatFFT_1D;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|||||||
@@ -28,15 +28,13 @@ import java.util.concurrent.ScheduledFuture;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class ScheduledBufferProcessor<E> implements Listener<E>
|
public class ContinuousBufferProcessor<E> implements Listener<E>
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(ScheduledBufferProcessor.class);
|
private final static Logger mLog = LoggerFactory.getLogger(ContinuousBufferProcessor.class);
|
||||||
|
|
||||||
private OverflowableTransferQueue<E> mQueue;
|
private OverflowableTransferQueue<E> mQueue;
|
||||||
private Listener<E> mListener;
|
private Listener<E> mListener;
|
||||||
private ScheduledFuture<?> mScheduledFuture;
|
private ScheduledFuture<?> mScheduledFuture;
|
||||||
private long mDistributionInterval;
|
|
||||||
private int mMaxBuffersPerInterval;
|
|
||||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,14 +50,10 @@ public class ScheduledBufferProcessor<E> implements Listener<E>
|
|||||||
*
|
*
|
||||||
* @param maximumSize of the internal queue (overflow happens when this is exceeded)
|
* @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 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<E> implements Listener<E>
|
|||||||
* notifications of overflow and reset state. Queue sizing parameters are specified in the constructor.
|
* notifications of overflow and reset state. Queue sizing parameters are specified in the constructor.
|
||||||
*
|
*
|
||||||
* @param queue implmentation of an overflowable transfer queue
|
* @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<E> queue, long distributionInterval, int maxBuffersPerInterval)
|
public ContinuousBufferProcessor(OverflowableTransferQueue<E> queue)
|
||||||
{
|
{
|
||||||
mQueue = queue;
|
mQueue = queue;
|
||||||
mDistributionInterval = distributionInterval;
|
|
||||||
mMaxBuffersPerInterval = maxBuffersPerInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,6 +104,7 @@ public class ScheduledBufferProcessor<E> implements Listener<E>
|
|||||||
@Override
|
@Override
|
||||||
public void receive(E e)
|
public void receive(E e)
|
||||||
{
|
{
|
||||||
|
// mLog.debug(" Queuing: " + e.toString());
|
||||||
mQueue.offer(e);
|
mQueue.offer(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +115,7 @@ public class ScheduledBufferProcessor<E> implements Listener<E>
|
|||||||
{
|
{
|
||||||
if(mRunning.compareAndSet(false, true))
|
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<E> implements Listener<E>
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mQueue.drainTo(mBuffers, mMaxBuffersPerInterval);
|
mQueue.drainTo(mBuffers, 10);
|
||||||
|
|
||||||
if(mListener != null)
|
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)
|
catch(Throwable throwable)
|
||||||
{
|
{
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.dsp.filter.channelizer;
|
package io.github.dsheirer.dsp.filter.channelizer;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.complex.reusable.OverflowableReusableBufferTransferQueue;
|
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||||
|
|
||||||
public class ScheduledReusableBufferProcessor extends ScheduledBufferProcessor<ReusableComplexBuffer>
|
public class ContinuousReusableBufferProcessor<T extends ReusableBuffer> extends ContinuousBufferProcessor<T>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Scheduled Reusable Buffer Processor combines an internal overflowable buffer with a scheduled runnable processing
|
* Scheduled Reusable Buffer Processor combines an internal overflowable buffer with a scheduled runnable processing
|
||||||
@@ -33,13 +33,9 @@ public class ScheduledReusableBufferProcessor extends ScheduledBufferProcessor<R
|
|||||||
*
|
*
|
||||||
* @param maximumSize of the internal queue (overflow happens when this is exceeded)
|
* @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 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
|
|
||||||
*/
|
*/
|
||||||
public ScheduledReusableBufferProcessor(int maximumSize, int resetThreshold, long distributionInterval, int maxBuffersPerInterval)
|
public ContinuousReusableBufferProcessor(int maximumSize, int resetThreshold)
|
||||||
{
|
{
|
||||||
super(new OverflowableReusableBufferTransferQueue(maximumSize, resetThreshold),
|
super(new OverflowableReusableBufferTransferQueue<T>(maximumSize, resetThreshold));
|
||||||
distributionInterval, maxBuffersPerInterval);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.dsp.filter.design.FilterDesignException;
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferProvider;
|
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
import io.github.dsheirer.source.SourceException;
|
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 static final int POLYPHASE_FILTER_TAPS_PER_CHANNEL = 17;
|
||||||
|
|
||||||
private Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
private Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
||||||
private IReusableComplexBufferProvider mReusableBufferProvider;
|
private IReusableBufferProvider<ReusableComplexBuffer> mReusableBufferProvider;
|
||||||
private List<PolyphaseChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
private List<PolyphaseChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
||||||
private ChannelCalculator mChannelCalculator;
|
private ChannelCalculator mChannelCalculator;
|
||||||
private ComplexPolyphaseChannelizerM2 mPolyphaseChannelizer;
|
private ComplexPolyphaseChannelizerM2 mPolyphaseChannelizer;
|
||||||
private ChannelSourceEventListener mChannelSourceEventListener = new ChannelSourceEventListener();
|
private ChannelSourceEventListener mChannelSourceEventListener = new ChannelSourceEventListener();
|
||||||
private BufferSourceEventMonitor mBufferSourceEventMonitor = new BufferSourceEventMonitor();
|
private BufferSourceEventMonitor mBufferSourceEventMonitor = new BufferSourceEventMonitor();
|
||||||
private ScheduledBufferProcessor mBufferProcessor;
|
private ContinuousBufferProcessor<ReusableComplexBuffer> mBufferProcessor;
|
||||||
private Map<Integer,float[]> mOutputProcessorFilters = new HashMap<>();
|
private Map<Integer,float[]> mOutputProcessorFilters = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +76,8 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
|||||||
* @param frequency of the provided complex buffer samples
|
* @param frequency of the provided complex buffer samples
|
||||||
* @param sampleRate 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<ReusableComplexBuffer> reusableBufferProvider,
|
||||||
|
long frequency, double sampleRate)
|
||||||
{
|
{
|
||||||
if(reusableBufferProvider == null)
|
if(reusableBufferProvider == null)
|
||||||
{
|
{
|
||||||
@@ -95,7 +96,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
|||||||
|
|
||||||
mChannelCalculator = new ChannelCalculator(sampleRate, channelCount, frequency, CHANNEL_OVERSAMPLING);
|
mChannelCalculator = new ChannelCalculator(sampleRate, channelCount, frequency, CHANNEL_OVERSAMPLING);
|
||||||
|
|
||||||
mBufferProcessor = new ScheduledBufferProcessor(500, 100, 50, 50);
|
mBufferProcessor = new ContinuousBufferProcessor(200, 50);
|
||||||
mBufferProcessor.setListener(mBufferSourceEventMonitor);
|
mBufferProcessor.setListener(mBufferSourceEventMonitor);
|
||||||
|
|
||||||
updateChannelizerSampleRate(sampleRate);
|
updateChannelizerSampleRate(sampleRate);
|
||||||
@@ -160,7 +161,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
|||||||
return channelSource;
|
return channelSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TunerChannelSource getSpecialChannel(int index)
|
public TunerChannelSource getTestChannel(int index)
|
||||||
{
|
{
|
||||||
PolyphaseChannelSource channelSource = null;
|
PolyphaseChannelSource channelSource = null;
|
||||||
|
|
||||||
@@ -181,6 +182,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
|||||||
}
|
}
|
||||||
catch(IllegalArgumentException iae)
|
catch(IllegalArgumentException iae)
|
||||||
{
|
{
|
||||||
|
mLog.error("Error", iae);
|
||||||
}
|
}
|
||||||
|
|
||||||
return channelSource;
|
return channelSource;
|
||||||
@@ -582,15 +584,19 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
|||||||
|
|
||||||
if(mPolyphaseChannelizer != null)
|
if(mPolyphaseChannelizer != null)
|
||||||
{
|
{
|
||||||
mPolyphaseChannelizer.receive(reusableComplexBuffer.incrementUserCount());
|
//User count management is handled by the channelizer
|
||||||
|
mPolyphaseChannelizer.receive(reusableComplexBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reusableComplexBuffer.decrementUserCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Throwable throwable)
|
catch(Throwable throwable)
|
||||||
{
|
{
|
||||||
mLog.error("Error", throwable);
|
mLog.error("Error", throwable);
|
||||||
|
reusableComplexBuffer.decrementUserCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
reusableComplexBuffer.decrementUserCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,8 +17,8 @@ package io.github.dsheirer.dsp.filter.channelizer;
|
|||||||
|
|
||||||
import io.github.dsheirer.dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor;
|
import io.github.dsheirer.dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferAssembler;
|
import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import io.github.dsheirer.dsp.mixer.IOscillator;
|
|||||||
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
import io.github.dsheirer.sample.SampleType;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||||
import io.github.dsheirer.sample.real.IOverflowListener;
|
import io.github.dsheirer.sample.real.IOverflowListener;
|
||||||
import io.github.dsheirer.settings.SettingsManager;
|
import io.github.dsheirer.settings.SettingsManager;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
@@ -177,8 +177,7 @@ public class SynthesizerViewer extends JFrame
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
mDFTProcessor.receive(reusableComplexBuffer);
|
||||||
reusableComplexBuffer.decrementUserCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,8 +211,7 @@ public class SynthesizerViewer extends JFrame
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
mDFTProcessor.receive(reusableComplexBuffer);
|
||||||
reusableComplexBuffer.decrementUserCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +275,7 @@ public class SynthesizerViewer extends JFrame
|
|||||||
private TwoChannelSynthesizerM2 mSynthesizer;
|
private TwoChannelSynthesizerM2 mSynthesizer;
|
||||||
private FS4DownConverter mFS4DownConverter = new FS4DownConverter();
|
private FS4DownConverter mFS4DownConverter = new FS4DownConverter();
|
||||||
private int mSamplesPerCycle = CHANNEL_SAMPLE_RATE / DATA_GENERATOR_FRAME_RATE;
|
private int mSamplesPerCycle = CHANNEL_SAMPLE_RATE / DATA_GENERATOR_FRAME_RATE;
|
||||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue();
|
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("SynthesizerViewer");
|
||||||
|
|
||||||
public DataGenerationManager()
|
public DataGenerationManager()
|
||||||
{
|
{
|
||||||
@@ -296,19 +294,22 @@ public class SynthesizerViewer extends JFrame
|
|||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
ReusableComplexBuffer channel1Buffer = mReusableBufferQueue.getBuffer(mSamplesPerCycle);
|
ReusableComplexBuffer channel1Buffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerCycle);
|
||||||
getChannel1ControlPanel().getOscillator().generateComplex(channel1Buffer);
|
getChannel1ControlPanel().getOscillator().generateComplex(channel1Buffer);
|
||||||
|
|
||||||
ReusableComplexBuffer channel2Buffer = mReusableBufferQueue.getBuffer(mSamplesPerCycle);
|
ReusableComplexBuffer channel2Buffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerCycle);
|
||||||
getChannel2ControlPanel().getOscillator().generateComplex(channel2Buffer);
|
getChannel2ControlPanel().getOscillator().generateComplex(channel2Buffer);
|
||||||
|
|
||||||
float[] synthesized = mSynthesizer.process(channel1Buffer.getSamples(), channel2Buffer.getSamples());
|
float[] synthesized = mSynthesizer.process(channel1Buffer.getSamples(), channel2Buffer.getSamples());
|
||||||
mFS4DownConverter.mixComplex(synthesized);
|
mFS4DownConverter.mixComplex(synthesized);
|
||||||
ReusableComplexBuffer synthesizedBuffer = mReusableBufferQueue.getBuffer(synthesized.length);
|
ReusableComplexBuffer synthesizedBuffer = mReusableComplexBufferQueue.getBuffer(synthesized.length);
|
||||||
|
|
||||||
getChannel1Panel().receive(channel1Buffer.incrementUserCount());
|
channel1Buffer.incrementUserCount();
|
||||||
getChannel2Panel().receive(channel2Buffer.incrementUserCount());
|
getChannel1Panel().receive(channel1Buffer);
|
||||||
getSpectrumPanel().receive(synthesizedBuffer.incrementUserCount());
|
channel2Buffer.incrementUserCount();
|
||||||
|
getChannel2Panel().receive(channel2Buffer);
|
||||||
|
synthesizedBuffer.incrementUserCount();
|
||||||
|
getSpectrumPanel().receive(synthesizedBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.IOscillator;
|
||||||
import io.github.dsheirer.dsp.mixer.Oscillator;
|
import io.github.dsheirer.dsp.mixer.Oscillator;
|
||||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
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.sample.real.IOverflowListener;
|
||||||
import io.github.dsheirer.source.Source;
|
import io.github.dsheirer.source.Source;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
package io.github.dsheirer.dsp.filter.channelizer.output;
|
package io.github.dsheirer.dsp.filter.channelizer.output;
|
||||||
|
|
||||||
import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelResultsBuffer;
|
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 io.github.dsheirer.source.Source;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
package io.github.dsheirer.dsp.filter.channelizer.output;
|
package io.github.dsheirer.dsp.filter.channelizer.output;
|
||||||
|
|
||||||
import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelResultsBuffer;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|||||||
@@ -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.PolyphaseChannelResultsBuffer;
|
||||||
import io.github.dsheirer.dsp.filter.channelizer.TwoChannelSynthesizerM2;
|
import io.github.dsheirer.dsp.filter.channelizer.TwoChannelSynthesizerM2;
|
||||||
import io.github.dsheirer.dsp.mixer.FS4DownConverter;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|||||||
@@ -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.FIRFilter;
|
||||||
import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
|
|
||||||
public class ComplexFIRFilter extends FIRFilter
|
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 mIFilter;
|
||||||
private RealFIRFilter mQFilter;
|
private RealFIRFilter mQFilter;
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ public class ComplexFIRFilter extends FIRFilter
|
|||||||
*/
|
*/
|
||||||
public ReusableComplexBuffer filter(ReusableComplexBuffer originalBuffer)
|
public ReusableComplexBuffer filter(ReusableComplexBuffer originalBuffer)
|
||||||
{
|
{
|
||||||
ReusableComplexBuffer filteredBuffer = mReusableBufferQueue.getBuffer(originalBuffer.getSamples().length);
|
ReusableComplexBuffer filteredBuffer = mReusableComplexBufferQueue.getBuffer(originalBuffer.getSamples().length);
|
||||||
filteredBuffer.setTimestamp(originalBuffer.getTimestamp());
|
filteredBuffer.setTimestamp(originalBuffer.getTimestamp());
|
||||||
|
|
||||||
float[] samples = originalBuffer.getSamples();
|
float[] samples = originalBuffer.getSamples();
|
||||||
@@ -107,6 +107,6 @@ public class ComplexFIRFilter extends FIRFilter
|
|||||||
{
|
{
|
||||||
mIFilter.dispose();
|
mIFilter.dispose();
|
||||||
mQFilter.dispose();
|
mQFilter.dispose();
|
||||||
mReusableBufferQueue.dispose();
|
mReusableComplexBufferQueue.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
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<SourceEvent> getSourceEventListener()
|
|
||||||
{
|
|
||||||
//TODO: we should get the channel sample rate and setup the resampler to output 8 kHz audio
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
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<RealBuffer>
|
||||||
|
{
|
||||||
|
protected static final Logger mLog = LoggerFactory.getLogger(RealResampler.class);
|
||||||
|
|
||||||
|
private Resampler mResampler;
|
||||||
|
private Listener<ReusableBuffer> 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<ReusableBuffer> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,11 +16,11 @@
|
|||||||
package io.github.dsheirer.dsp.gain;
|
package io.github.dsheirer.dsp.gain;
|
||||||
|
|
||||||
import io.github.dsheirer.buffer.FloatCircularBuffer;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.ComplexSampleListener;
|
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
|
public class ComplexFeedForwardGainControl implements ComplexSampleListener
|
||||||
{
|
{
|
||||||
@@ -29,7 +29,7 @@ public class ComplexFeedForwardGainControl implements ComplexSampleListener
|
|||||||
|
|
||||||
private ComplexSampleListener mListener;
|
private ComplexSampleListener mListener;
|
||||||
private FloatCircularBuffer mEnvelopeHistory;
|
private FloatCircularBuffer mEnvelopeHistory;
|
||||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("ComplexFeedForwardGainControl");
|
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexFeedForwardGainControl");
|
||||||
|
|
||||||
private float mMaxEnvelope = 0.0f;
|
private float mMaxEnvelope = 0.0f;
|
||||||
private float mGain = 1.0f;
|
private float mGain = 1.0f;
|
||||||
@@ -157,7 +157,7 @@ public class ComplexFeedForwardGainControl implements ComplexSampleListener
|
|||||||
{
|
{
|
||||||
float[] samples = buffer.getSamples();
|
float[] samples = buffer.getSamples();
|
||||||
|
|
||||||
ReusableComplexBuffer filteredBuffer = mReusableBufferQueue.getBuffer(samples.length);
|
ReusableComplexBuffer filteredBuffer = mReusableComplexBufferQueue.getBuffer(samples.length);
|
||||||
filteredBuffer.setTimestamp(buffer.getTimestamp());
|
filteredBuffer.setTimestamp(buffer.getTimestamp());
|
||||||
|
|
||||||
float[] filtered = filteredBuffer.getSamples();
|
float[] filtered = filteredBuffer.getSamples();
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.dsp.mixer;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ public abstract class AbstractOscillator implements IOscillator
|
|||||||
@Override
|
@Override
|
||||||
public void generateComplex(ReusableComplexBuffer reusableComplexBuffer)
|
public void generateComplex(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
int sampleCount = reusableComplexBuffer.getSampleLength();
|
int sampleCount = reusableComplexBuffer.getSampleCount();
|
||||||
|
|
||||||
if(mSampleBuffer == null || mSampleBuffer.capacity() != sampleCount * 2)
|
if(mSampleBuffer == null || mSampleBuffer.capacity() != sampleCount * 2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.dsp.mixer;
|
package io.github.dsheirer.dsp.mixer;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Oscillator interface.
|
* Oscillator interface.
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ package io.github.dsheirer.dsp.psk;
|
|||||||
|
|
||||||
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
|
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.ComplexSampleListener;
|
import io.github.dsheirer.sample.complex.ComplexSampleListener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
|
|
||||||
public abstract class PSKDemodulator<T> implements ComplexSampleListener
|
public abstract class PSKDemodulator<T> implements ComplexSampleListener
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ package io.github.dsheirer.instrument.gui.viewer;
|
|||||||
|
|
||||||
import io.github.dsheirer.instrument.gui.viewer.decoder.DecoderPane;
|
import io.github.dsheirer.instrument.gui.viewer.decoder.DecoderPane;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster;
|
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.source.IControllableFileSource;
|
import io.github.dsheirer.source.IControllableFileSource;
|
||||||
import io.github.dsheirer.source.IFrameLocationListener;
|
import io.github.dsheirer.source.IFrameLocationListener;
|
||||||
import io.github.dsheirer.source.wave.ComplexWaveSource;
|
import io.github.dsheirer.source.wave.ComplexWaveSource;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package io.github.dsheirer.instrument.gui.viewer.chart;
|
|||||||
import io.github.dsheirer.buffer.ComplexCircularBuffer;
|
import io.github.dsheirer.buffer.ComplexCircularBuffer;
|
||||||
import io.github.dsheirer.dsp.gain.ComplexGain;
|
import io.github.dsheirer.dsp.gain.ComplexGain;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package io.github.dsheirer.instrument.gui.viewer.chart;
|
|||||||
import io.github.dsheirer.buffer.ComplexCircularBuffer;
|
import io.github.dsheirer.buffer.ComplexCircularBuffer;
|
||||||
import io.github.dsheirer.dsp.gain.ComplexGain;
|
import io.github.dsheirer.dsp.gain.ComplexGain;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package io.github.dsheirer.instrument.gui.viewer.chart;
|
|||||||
import io.github.dsheirer.buffer.DoubleCircularBuffer;
|
import io.github.dsheirer.buffer.DoubleCircularBuffer;
|
||||||
import io.github.dsheirer.dsp.fm.FMDemodulator;
|
import io.github.dsheirer.dsp.fm.FMDemodulator;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.chart.LineChart;
|
import javafx.scene.chart.LineChart;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ package io.github.dsheirer.instrument.gui.viewer.decoder;
|
|||||||
|
|
||||||
import io.github.dsheirer.module.decode.DecoderType;
|
import io.github.dsheirer.module.decode.DecoderType;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster;
|
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import io.github.dsheirer.message.Message;
|
|||||||
import io.github.dsheirer.module.decode.DecoderType;
|
import io.github.dsheirer.module.decode.DecoderType;
|
||||||
import io.github.dsheirer.module.decode.p25.P25DecoderC4FMInstrumented;
|
import io.github.dsheirer.module.decode.p25.P25DecoderC4FMInstrumented;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.HBox;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import io.github.dsheirer.message.Message;
|
|||||||
import io.github.dsheirer.module.decode.DecoderType;
|
import io.github.dsheirer.module.decode.DecoderType;
|
||||||
import io.github.dsheirer.module.decode.p25.P25DecoderLSMInstrumented;
|
import io.github.dsheirer.module.decode.p25.P25DecoderLSMInstrumented;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.HBox;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder;
|
|||||||
import io.github.dsheirer.record.wave.RealBufferWaveRecorder;
|
import io.github.dsheirer.record.wave.RealBufferWaveRecorder;
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener;
|
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster;
|
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||||
import io.github.dsheirer.sample.real.IFilteredRealBufferListener;
|
import io.github.dsheirer.sample.real.IFilteredRealBufferListener;
|
||||||
import io.github.dsheirer.sample.real.IFilteredRealBufferProvider;
|
import io.github.dsheirer.sample.real.IFilteredRealBufferProvider;
|
||||||
import io.github.dsheirer.sample.real.IUnFilteredRealBufferListener;
|
import io.github.dsheirer.sample.real.IUnFilteredRealBufferListener;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package io.github.dsheirer.module.decode;
|
|||||||
|
|
||||||
import io.github.dsheirer.alias.AliasList;
|
import io.github.dsheirer.alias.AliasList;
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
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.metadata.Metadata;
|
||||||
import io.github.dsheirer.channel.state.AlwaysUnsquelchedDecoderState;
|
import io.github.dsheirer.channel.state.AlwaysUnsquelchedDecoderState;
|
||||||
import io.github.dsheirer.channel.traffic.TrafficChannelManager;
|
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 AlwaysUnsquelchedDecoderState(DecoderType.AM, channel.getName()));
|
||||||
modules.add(new AMDemodulatorModule());
|
modules.add(new AMDemodulatorModule());
|
||||||
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule2(metadata));
|
||||||
break;
|
break;
|
||||||
case NBFM:
|
case NBFM:
|
||||||
modules.add(new NBFMDecoder(decodeConfig));
|
modules.add(new NBFMDecoder(decodeConfig));
|
||||||
modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.NBFM, channel.getName()));
|
modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.NBFM, channel.getName()));
|
||||||
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
||||||
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule2(metadata));
|
||||||
break;
|
break;
|
||||||
case LTR_STANDARD:
|
case LTR_STANDARD:
|
||||||
MessageDirection direction = ((DecodeConfigLTRStandard) decodeConfig).getMessageDirection();
|
MessageDirection direction = ((DecodeConfigLTRStandard) decodeConfig).getMessageDirection();
|
||||||
@@ -199,14 +199,14 @@ public class DecoderFactory
|
|||||||
modules.add(new LTRStandardDecoderState(aliasList));
|
modules.add(new LTRStandardDecoderState(aliasList));
|
||||||
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
||||||
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule2(metadata));
|
||||||
break;
|
break;
|
||||||
case LTR_NET:
|
case LTR_NET:
|
||||||
modules.add(new LTRNetDecoder((DecodeConfigLTRNet) decodeConfig, aliasList));
|
modules.add(new LTRNetDecoder((DecodeConfigLTRNet) decodeConfig, aliasList));
|
||||||
modules.add(new LTRNetDecoderState(aliasList));
|
modules.add(new LTRNetDecoderState(aliasList));
|
||||||
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
||||||
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule2(metadata));
|
||||||
break;
|
break;
|
||||||
case MPT1327:
|
case MPT1327:
|
||||||
DecodeConfigMPT1327 mptConfig = (DecodeConfigMPT1327) decodeConfig;
|
DecodeConfigMPT1327 mptConfig = (DecodeConfigMPT1327) decodeConfig;
|
||||||
@@ -229,14 +229,14 @@ public class DecoderFactory
|
|||||||
|
|
||||||
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
||||||
modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
|
modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule2(metadata));
|
||||||
break;
|
break;
|
||||||
case PASSPORT:
|
case PASSPORT:
|
||||||
modules.add(new PassportDecoder(decodeConfig, aliasList));
|
modules.add(new PassportDecoder(decodeConfig, aliasList));
|
||||||
modules.add(new PassportDecoderState(aliasList));
|
modules.add(new PassportDecoderState(aliasList));
|
||||||
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
modules.add(new FMDemodulatorModule(NBFM_PASS_FREQUENCY, NBFM_STOP_FREQUENCY));
|
||||||
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule2(metadata));
|
||||||
break;
|
break;
|
||||||
case P25_PHASE1:
|
case P25_PHASE1:
|
||||||
DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1) decodeConfig;
|
DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1) decodeConfig;
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import io.github.dsheirer.alias.AliasList;
|
|||||||
import io.github.dsheirer.module.decode.Decoder;
|
import io.github.dsheirer.module.decode.Decoder;
|
||||||
import io.github.dsheirer.module.decode.DecoderType;
|
import io.github.dsheirer.module.decode.DecoderType;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener;
|
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
||||||
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.ISourceEventListener;
|
||||||
import io.github.dsheirer.source.ISourceEventProvider;
|
import io.github.dsheirer.source.ISourceEventProvider;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import io.github.dsheirer.dsp.gain.ComplexFeedForwardGainControl;
|
|||||||
import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulator;
|
import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulator;
|
||||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
||||||
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
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 io.github.dsheirer.source.SourceEvent;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulatorInstrumented;
|
|||||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
|
import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
|
||||||
import io.github.dsheirer.dsp.psk.SymbolDecisionData;
|
import io.github.dsheirer.dsp.psk.SymbolDecisionData;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
|
|
||||||
public class P25DecoderC4FMInstrumented extends P25DecoderC4FM
|
public class P25DecoderC4FMInstrumented extends P25DecoderC4FM
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import io.github.dsheirer.dsp.gain.ComplexFeedForwardGainControl;
|
|||||||
import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulator;
|
import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulator;
|
||||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
||||||
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
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 io.github.dsheirer.source.SourceEvent;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulatorInstrumented;
|
|||||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
|
import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
|
||||||
import io.github.dsheirer.dsp.psk.SymbolDecisionData;
|
import io.github.dsheirer.dsp.psk.SymbolDecisionData;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.Complex;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
|
||||||
|
|
||||||
public class P25DecoderLSMInstrumented extends P25DecoderLSM
|
public class P25DecoderLSMInstrumented extends P25DecoderLSM
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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.dsp.gain.AutomaticGainControl_RB;
|
||||||
import io.github.dsheirer.module.Module;
|
import io.github.dsheirer.module.Module;
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.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.IFilteredRealBufferProvider;
|
||||||
import io.github.dsheirer.sample.real.RealBuffer;
|
import io.github.dsheirer.sample.real.RealBuffer;
|
||||||
|
|
||||||
|
|||||||
@@ -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.dsp.fm.FMDemodulator_CB;
|
||||||
import io.github.dsheirer.module.Module;
|
import io.github.dsheirer.module.Module;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener;
|
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.real.IUnFilteredRealBufferProvider;
|
import io.github.dsheirer.sample.real.IUnFilteredRealBufferProvider;
|
||||||
import io.github.dsheirer.sample.real.RealBuffer;
|
import io.github.dsheirer.sample.real.RealBuffer;
|
||||||
import io.github.dsheirer.source.ISourceEventListener;
|
import io.github.dsheirer.source.ISourceEventListener;
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ package io.github.dsheirer.record.wave;
|
|||||||
import io.github.dsheirer.module.Module;
|
import io.github.dsheirer.module.Module;
|
||||||
import io.github.dsheirer.sample.ConversionUtils;
|
import io.github.dsheirer.sample.ConversionUtils;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableBufferDisposedListener;
|
import io.github.dsheirer.sample.buffer.IReusableBufferDisposedListener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferListener;
|
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
import io.github.dsheirer.util.TimeStamp;
|
import io.github.dsheirer.util.TimeStamp;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -207,14 +207,14 @@ public class ComplexBufferWaveRecorder extends Module implements IReusableComple
|
|||||||
{
|
{
|
||||||
public PoisonPill()
|
public PoisonPill()
|
||||||
{
|
{
|
||||||
super(new IReusableBufferDisposedListener()
|
super(new IReusableBufferDisposedListener<ReusableComplexBuffer>()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void disposed(ReusableComplexBuffer reusableComplexBuffer)
|
public void disposed(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
//no-op
|
//no-op
|
||||||
}
|
}
|
||||||
}, new float[2], System.currentTimeMillis());
|
}, new float[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.github.dsheirer.sample;
|
package io.github.dsheirer.sample;
|
||||||
|
|
||||||
|
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||||
import io.github.dsheirer.sample.real.RealBuffer;
|
import io.github.dsheirer.sample.real.RealBuffer;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -11,61 +12,71 @@ import java.nio.ShortBuffer;
|
|||||||
*/
|
*/
|
||||||
public class ConversionUtils
|
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
|
* 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();
|
ShortBuffer byteBuffer = buffer.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||||
|
|
||||||
float[] samples = new float[ buffer.limit() / 2 ];
|
float[] samples = new float[buffer.limit() / 2];
|
||||||
|
|
||||||
for( int x = 0; x < samples.length; x++ )
|
for(int x = 0; x < samples.length; x++)
|
||||||
{
|
{
|
||||||
samples[ x ] = (float)byteBuffer.get() / (float)Short.MAX_VALUE;
|
samples[x] = (float)byteBuffer.get() / (float)Short.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the float samples into a little-endian 16-bit sample byte buffer.
|
* Converts the float samples into a little-endian 16-bit sample byte buffer.
|
||||||
|
*
|
||||||
* @param samples - float array of sample data
|
* @param samples - float array of sample data
|
||||||
* @return - little-endian 16-bit sample byte buffer
|
* @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 );
|
ByteBuffer converted = ByteBuffer.allocate(samples.length * 2);
|
||||||
converted.order( ByteOrder.LITTLE_ENDIAN );
|
converted.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
for( float sample: samples )
|
for(float sample : samples)
|
||||||
{
|
{
|
||||||
converted.putShort( (short)( sample * Short.MAX_VALUE ) );
|
converted.putShort((short)(sample * Short.MAX_VALUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the float samples in a complex buffer to a little endian 16-bit
|
* Converts the float samples in a complex buffer to a little endian 16-bit
|
||||||
* buffer
|
* buffer
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer convertToSigned16BitSamples( Buffer buffer )
|
public static ByteBuffer convertToSigned16BitSamples(Buffer buffer)
|
||||||
{
|
{
|
||||||
return convertToSigned16BitSamples( buffer.getSamples() );
|
return convertToSigned16BitSamples(buffer.getSamples());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the float samples in a complex buffer to a little endian 16-bit
|
* Converts the float samples in a complex buffer to a little endian 16-bit
|
||||||
* buffer
|
* buffer
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer convertToSigned16BitSamples( RealBuffer buffer )
|
public static ByteBuffer convertToSigned16BitSamples(RealBuffer buffer)
|
||||||
{
|
{
|
||||||
return convertToSigned16BitSamples( buffer.getSamples() );
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.adapter;
|
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.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.adapter;
|
package io.github.dsheirer.sample.adapter;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
|
|
||||||
public interface IComplexSampleAdapter
|
public interface IComplexSampleAdapter
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.complex.reusable;
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -21,21 +21,22 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.LinkedTransferQueue;
|
import java.util.concurrent.LinkedTransferQueue;
|
||||||
|
|
||||||
public class ReusableBufferQueue implements IReusableBufferDisposedListener
|
public abstract class AbstractReusableBufferQueue<T extends ReusableBuffer> implements IReusableBufferDisposedListener<T>
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferQueue.class);
|
private final static Logger mLog = LoggerFactory.getLogger(AbstractReusableBufferQueue.class);
|
||||||
private Queue<ReusableComplexBuffer> mReusableBufferQueue = new LinkedTransferQueue<>();
|
|
||||||
|
private Queue<T> mReusableBufferQueue = new LinkedTransferQueue<>();
|
||||||
private int mBufferCount = 0;
|
private int mBufferCount = 0;
|
||||||
private String mDebugName;
|
private String mDebugName;
|
||||||
|
private int mBufferUserCounter;
|
||||||
|
|
||||||
public ReusableBufferQueue(String debugName)
|
public AbstractReusableBufferQueue(String debugName)
|
||||||
{
|
{
|
||||||
mDebugName = debugName;
|
mDebugName = debugName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReusableBufferQueue()
|
public AbstractReusableBufferQueue()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose()
|
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
|
* Implements buffer disposed listener interface. Disposed (ie user count = 0) buffers will automatically callback
|
||||||
* to this method to indicate when they are disposed.
|
* to this method to indicate when they are disposed.
|
||||||
*
|
*
|
||||||
* @param reusableComplexBuffer that has been disposed
|
* @param reusableBuffer that has been disposed
|
||||||
*/
|
*/
|
||||||
@Override
|
@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
|
* @param size of the samples that will be loaded into the buffer
|
||||||
* @return a reusable 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)
|
if(buffer == null)
|
||||||
{
|
{
|
||||||
buffer = new ReusableComplexBuffer(this, new float[size]);
|
buffer = createBuffer(size);
|
||||||
mBufferCount++;
|
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;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer of the specified size
|
||||||
|
*/
|
||||||
|
protected abstract T createBuffer(int size);
|
||||||
}
|
}
|
||||||
@@ -13,13 +13,13 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.complex.reusable;
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
public interface IReusableBufferDisposedListener
|
public interface IReusableBufferDisposedListener<T extends ReusableBuffer>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Notifies the listener that the timestamped buffer has been disposed and can now be reused.
|
* 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);
|
||||||
}
|
}
|
||||||
@@ -13,21 +13,21 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.complex.reusable;
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
|
|
||||||
public interface IReusableComplexBufferProvider
|
public interface IReusableBufferProvider<T extends ReusableBuffer>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Adds the listener to receive complex buffer samples
|
* Adds the listener to receive complex buffer samples
|
||||||
*/
|
*/
|
||||||
void addBufferListener(Listener<ReusableComplexBuffer> listener);
|
void addBufferListener(Listener<T> listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the listener from receiving complex buffer samples
|
* Removes the listener from receiving complex buffer samples
|
||||||
*/
|
*/
|
||||||
void removeBufferListener(Listener<ReusableComplexBuffer> listener);
|
void removeBufferListener(Listener<T> listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if there are any complex buffer listeners registered
|
* Indicates if there are any complex buffer listeners registered
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.complex.reusable;
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
|
|
||||||
public interface IReusableComplexBufferListener
|
public interface IReusableComplexBufferListener<T extends ReusableBuffer>
|
||||||
{
|
{
|
||||||
Listener<ReusableComplexBuffer> getReusableComplexBufferListener();
|
Listener<T> getReusableComplexBufferListener();
|
||||||
}
|
}
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.complex.reusable;
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
||||||
|
|
||||||
public class OverflowableReusableBufferTransferQueue extends OverflowableTransferQueue<ReusableComplexBuffer>
|
public class OverflowableReusableBufferTransferQueue<T extends ReusableBuffer> extends OverflowableTransferQueue<T>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Concurrent transfer queue that couples a higher-throughput linked transfer queue with an atomic integer for
|
* 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
|
* Overrides the overflow method to decrement the user count on any buffers that are being discarded when the queue
|
||||||
* is in an overflow state.
|
* is in an overflow state.
|
||||||
*
|
*
|
||||||
* @param reusableComplexBuffer that will be discarded
|
* @param t reusableBuffer that will be discarded
|
||||||
*/
|
*/
|
||||||
@Override
|
@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)
|
synchronized(mQueue)
|
||||||
{
|
{
|
||||||
ReusableComplexBuffer buffer = mQueue.poll();
|
T buffer = mQueue.poll();
|
||||||
|
|
||||||
while(buffer != null)
|
while(buffer != null)
|
||||||
{
|
{
|
||||||
@@ -13,19 +13,20 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
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 org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
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 long mTimestamp;
|
||||||
private AtomicInteger mUserCount = new AtomicInteger();
|
private AtomicInteger mUserCount = new AtomicInteger();
|
||||||
|
private String mDebugName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a reusable, timestamped complex buffer using the specified time in milliseconds.
|
* 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
|
* 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.
|
* 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 samples of data
|
||||||
* @param timestamp in millis for the buffer
|
* @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");
|
Validate.notNull(bufferDisposedListener, "Reusable Buffer Listener cannot be null");
|
||||||
mDisposalListener = disposalListener;
|
mBufferDisposedListener = bufferDisposedListener;
|
||||||
mTimestamp = timestamp;
|
mTimestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setDebugName(String debugName)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
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.
|
* This method is thread-safe.
|
||||||
*/
|
*/
|
||||||
public ReusableComplexBuffer decrementUserCount()
|
public void decrementUserCount()
|
||||||
{
|
{
|
||||||
int currentCount = mUserCount.decrementAndGet();
|
int currentCount = mUserCount.decrementAndGet();
|
||||||
|
|
||||||
if(currentCount == 0)
|
if(currentCount == 0)
|
||||||
{
|
{
|
||||||
mDisposalListener.disposed(this);
|
mBufferDisposedListener.disposed(this);
|
||||||
}
|
}
|
||||||
else if(currentCount < 0)
|
else if(currentCount < 0)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("User count is below zero. This indicates that this buffer's decrement" +
|
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");
|
" 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.
|
* This method is thread-safe.
|
||||||
*/
|
*/
|
||||||
public ReusableComplexBuffer incrementUserCount()
|
public void incrementUserCount()
|
||||||
{
|
{
|
||||||
mUserCount.incrementAndGet();
|
mUserCount.incrementAndGet();
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,9 +237,16 @@ public class ReusableComplexBuffer extends ComplexBuffer
|
|||||||
*
|
*
|
||||||
* @param additionalUserCount to add to the current user count
|
* @param additionalUserCount to add to the current user count
|
||||||
*/
|
*/
|
||||||
public ReusableComplexBuffer incrementUserCount(int additionalUserCount)
|
public void incrementUserCount(int additionalUserCount)
|
||||||
{
|
{
|
||||||
mUserCount.addAndGet(additionalUserCount);
|
mUserCount.addAndGet(additionalUserCount);
|
||||||
return this;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of users currently registered for this buffer
|
||||||
|
*/
|
||||||
|
public int getUserCount()
|
||||||
|
{
|
||||||
|
return mUserCount.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
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.dsp.filter.channelizer.SampleTimestampManager;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
@@ -27,7 +27,7 @@ import java.nio.FloatBuffer;
|
|||||||
*/
|
*/
|
||||||
public class ReusableBufferAssembler
|
public class ReusableBufferAssembler
|
||||||
{
|
{
|
||||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue();
|
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ReusableBufferAssembler");
|
||||||
private SampleTimestampManager mTimestampManager;
|
private SampleTimestampManager mTimestampManager;
|
||||||
private FloatBuffer mBuffer;
|
private FloatBuffer mBuffer;
|
||||||
private int mBufferSize;
|
private int mBufferSize;
|
||||||
@@ -115,7 +115,7 @@ public class ReusableBufferAssembler
|
|||||||
if(mListener != null && mBuffer.position() > 0)
|
if(mListener != null && mBuffer.position() > 0)
|
||||||
{
|
{
|
||||||
mBuffer.rewind();
|
mBuffer.rewind();
|
||||||
ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(mBufferSize);
|
ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mBufferSize);
|
||||||
reusableComplexBuffer.reloadFrom(mBuffer, mCurrentBufferTimestamp);
|
reusableComplexBuffer.reloadFrom(mBuffer, mCurrentBufferTimestamp);
|
||||||
reusableComplexBuffer.setUserCount(1);
|
reusableComplexBuffer.setUserCount(1);
|
||||||
mListener.receive(reusableComplexBuffer);
|
mListener.receive(reusableComplexBuffer);
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.sample.complex.reusable;
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
@@ -36,29 +36,10 @@ public class ReusableBufferBroadcaster extends Broadcaster<ReusableComplexBuffer
|
|||||||
@Override
|
@Override
|
||||||
public void broadcast(ReusableComplexBuffer reusableComplexBuffer)
|
public void broadcast(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
//There is a minuscule possibility that the listener list will change from the time that we get the size until
|
|
||||||
//the for/each iterator is created below, therefore we have to accurately track the user count. If a listener
|
|
||||||
//is added in the time between getting the list size and creating the iterator, that listener will NOT receive
|
|
||||||
//a copy of the buffer, but will instead get the next buffer. Likewise, if a listener is removed, we have to
|
|
||||||
//decrement the user count on the buffer after iterating the listener list.
|
|
||||||
int listenerCount = mListeners.size();
|
|
||||||
|
|
||||||
reusableComplexBuffer.incrementUserCount(listenerCount);
|
|
||||||
|
|
||||||
for(Listener<ReusableComplexBuffer> listener : mListeners)
|
for(Listener<ReusableComplexBuffer> listener : mListeners)
|
||||||
{
|
{
|
||||||
if(listenerCount > 0)
|
reusableComplexBuffer.incrementUserCount();
|
||||||
{
|
listener.receive(reusableComplexBuffer);
|
||||||
listener.receive(reusableComplexBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
listenerCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(listenerCount > 0)
|
|
||||||
{
|
|
||||||
reusableComplexBuffer.decrementUserCount();
|
|
||||||
listenerCount--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Decrement user counter for this broadcaster
|
//Decrement user counter for this broadcaster
|
||||||
@@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableBuffer>
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
package io.github.dsheirer.sample.buffer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class ReusableComplexBufferQueue extends AbstractReusableBufferQueue<ReusableComplexBuffer>
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ package io.github.dsheirer.source;
|
|||||||
|
|
||||||
import io.github.dsheirer.sample.Provider;
|
import io.github.dsheirer.sample.Provider;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
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<ReusableComplexBuffer>
|
public abstract class ComplexSource extends Source implements Provider<ReusableComplexBuffer>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ package io.github.dsheirer.source.mixer;
|
|||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.adapter.IComplexSampleAdapter;
|
import io.github.dsheirer.sample.adapter.IComplexSampleAdapter;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||||
import io.github.dsheirer.source.SourceException;
|
import io.github.dsheirer.source.SourceException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -42,7 +42,7 @@ public class ComplexMixer
|
|||||||
private int mBytesPerFrame = 0;
|
private int mBytesPerFrame = 0;
|
||||||
private IComplexSampleAdapter mSampleAdapter;
|
private IComplexSampleAdapter mSampleAdapter;
|
||||||
private Listener<ReusableComplexBuffer> mListener;
|
private Listener<ReusableComplexBuffer> 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
|
* 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 */
|
/* Dispatch samples to registered listeners */
|
||||||
if(mListener != null)
|
if(mListener != null)
|
||||||
{
|
{
|
||||||
ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(sampleCount);
|
ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(sampleCount);
|
||||||
|
|
||||||
//Convert samples and load into reusable buffer
|
//Convert samples and load into reusable buffer
|
||||||
mSampleAdapter.convertAndLoad(buffer, reusableComplexBuffer);
|
mSampleAdapter.convertAndLoad(buffer, reusableComplexBuffer);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
package io.github.dsheirer.source.tuner;
|
package io.github.dsheirer.source.tuner;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.IReusableComplexBufferProvider;
|
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster;
|
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||||
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.ISourceEventListener;
|
||||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
@@ -33,10 +33,10 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
|
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
|
||||||
IReusableComplexBufferProvider, Listener<ReusableComplexBuffer>
|
IReusableBufferProvider<ReusableComplexBuffer>, Listener<ReusableComplexBuffer>
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
|
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
|
||||||
protected ReusableBufferBroadcaster mSampleBroadcaster = new ReusableBufferBroadcaster();
|
protected ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster();
|
||||||
protected FrequencyController mFrequencyController;
|
protected FrequencyController mFrequencyController;
|
||||||
private int mMiddleUnusableHalfBandwidth;
|
private int mMiddleUnusableHalfBandwidth;
|
||||||
private double mUsableBandwidthPercentage;
|
private double mUsableBandwidthPercentage;
|
||||||
@@ -263,7 +263,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
|||||||
@Override
|
@Override
|
||||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||||
{
|
{
|
||||||
mSampleBroadcaster.addListener(listener);
|
mReusableBufferBroadcaster.addListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -272,7 +272,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
|||||||
@Override
|
@Override
|
||||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||||
{
|
{
|
||||||
mSampleBroadcaster.removeListener(listener);
|
mReusableBufferBroadcaster.removeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -281,7 +281,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
|||||||
@Override
|
@Override
|
||||||
public boolean hasBufferListeners()
|
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)
|
protected void broadcast(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mSampleBroadcaster.broadcast(reusableComplexBuffer.incrementUserCount());
|
mReusableBufferBroadcaster.broadcast(reusableComplexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
package io.github.dsheirer.source.tuner.channel;
|
package io.github.dsheirer.source.tuner.channel;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.ComplexSource;
|
||||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package io.github.dsheirer.source.tuner.fcd;
|
|||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.adapter.ComplexShortAdapter;
|
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.SourceException;
|
||||||
import io.github.dsheirer.source.mixer.ComplexMixer;
|
import io.github.dsheirer.source.mixer.ComplexMixer;
|
||||||
import io.github.dsheirer.source.tuner.MixerTunerDataLine;
|
import io.github.dsheirer.source.tuner.MixerTunerDataLine;
|
||||||
@@ -88,7 +88,7 @@ public abstract class FCDTunerController extends TunerController
|
|||||||
}
|
}
|
||||||
|
|
||||||
mComplexMixer = new ComplexMixer( mixerTDL.getTargetDataLine(), audioFormat, tunerName,
|
mComplexMixer = new ComplexMixer( mixerTDL.getTargetDataLine(), audioFormat, tunerName,
|
||||||
new ComplexShortAdapter(), mSampleBroadcaster);
|
new ComplexShortAdapter(), mReusableBufferBroadcaster);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ public abstract class ChannelSourceManager implements ISourceEventProcessor
|
|||||||
*/
|
*/
|
||||||
public abstract TunerChannelSource getSource(TunerChannel tunerChannel);
|
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
|
* Adds a listener to receive source events
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ public class TunerChannelSourceManager extends ChannelSourceManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TunerChannelSource getSpecialSource(int index)
|
public TunerChannelSource getTestingSource(int index)
|
||||||
{
|
{
|
||||||
//TODO: remove this debug method
|
//TODO: remove this debug method
|
||||||
return mPolyphaseChannelManager.getSpecialChannel(index);
|
return mPolyphaseChannelManager.getTestChannel(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
package io.github.dsheirer.source.tuner.rtl;
|
package io.github.dsheirer.source.tuner.rtl;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.SourceException;
|
||||||
import io.github.dsheirer.source.tuner.TunerManager;
|
import io.github.dsheirer.source.tuner.TunerManager;
|
||||||
import io.github.dsheirer.source.tuner.TunerType;
|
import io.github.dsheirer.source.tuner.TunerType;
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ package io.github.dsheirer.source.tuner.test;
|
|||||||
import io.github.dsheirer.dsp.mixer.IOscillator;
|
import io.github.dsheirer.dsp.mixer.IOscillator;
|
||||||
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferBroadcaster;
|
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -185,18 +185,19 @@ public class SampleGenerator
|
|||||||
public class Generator implements Runnable
|
public class Generator implements Runnable
|
||||||
{
|
{
|
||||||
private int mTriggerInterval = 0;
|
private int mTriggerInterval = 0;
|
||||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("** Sample Generator **");
|
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("SampleGenerator");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
if(mComplexBufferBroadcaster.hasListeners())
|
if(mComplexBufferBroadcaster.hasListeners())
|
||||||
{
|
{
|
||||||
ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(mSamplesPerInterval);
|
ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerInterval);
|
||||||
|
|
||||||
mOscillator.generateComplex(reusableComplexBuffer);
|
mOscillator.generateComplex(reusableComplexBuffer);
|
||||||
|
|
||||||
mComplexBufferBroadcaster.broadcast(reusableComplexBuffer.incrementUserCount());
|
reusableComplexBuffer.incrementUserCount();
|
||||||
|
mComplexBufferBroadcaster.broadcast(reusableComplexBuffer);
|
||||||
|
|
||||||
if(mSweepUpdateInterval != 0)
|
if(mSweepUpdateInterval != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
package io.github.dsheirer.source.tuner.test;
|
package io.github.dsheirer.source.tuner.test;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.SourceException;
|
||||||
import io.github.dsheirer.source.tuner.TunerController;
|
import io.github.dsheirer.source.tuner.TunerController;
|
||||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
package io.github.dsheirer.source.tuner.usb;
|
package io.github.dsheirer.source.tuner.usb;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
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.TunerManager;
|
||||||
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
@@ -394,9 +394,10 @@ public class USBTransferProcessor implements TransferCallback
|
|||||||
{
|
{
|
||||||
ByteBuffer nativeBuffer = transfer.buffer();
|
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();
|
transfer.buffer().rewind();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
package io.github.dsheirer.source.tuner.usb;
|
package io.github.dsheirer.source.tuner.usb;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
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;
|
import io.github.dsheirer.source.tuner.TunerController;
|
||||||
|
|
||||||
public abstract class USBTunerController extends TunerController
|
public abstract class USBTunerController extends TunerController
|
||||||
|
|||||||
@@ -15,15 +15,15 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.source.tuner.usb.converter;
|
package io.github.dsheirer.source.tuner.usb.converter;
|
||||||
|
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
public abstract class NativeBufferConverter
|
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
|
* 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);
|
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
|
//The reusable buffer will rewind the float buffer to the beginning
|
||||||
reusableComplexBuffer.reloadFrom(floatBuffer, System.currentTimeMillis());
|
reusableComplexBuffer.reloadFrom(floatBuffer, System.currentTimeMillis());
|
||||||
|
reusableComplexBuffer.incrementUserCount();
|
||||||
|
|
||||||
return reusableComplexBuffer;
|
return reusableComplexBuffer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ package io.github.dsheirer.source.wave;
|
|||||||
|
|
||||||
import io.github.dsheirer.sample.ConversionUtils;
|
import io.github.dsheirer.sample.ConversionUtils;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||||
import io.github.dsheirer.source.ComplexSource;
|
import io.github.dsheirer.source.ComplexSource;
|
||||||
import io.github.dsheirer.source.IControllableFileSource;
|
import io.github.dsheirer.source.IControllableFileSource;
|
||||||
import io.github.dsheirer.source.IFrameLocationListener;
|
import io.github.dsheirer.source.IFrameLocationListener;
|
||||||
@@ -45,7 +45,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
|||||||
private Listener<ReusableComplexBuffer> mListener;
|
private Listener<ReusableComplexBuffer> mListener;
|
||||||
private AudioInputStream mInputStream;
|
private AudioInputStream mInputStream;
|
||||||
private File mFile;
|
private File mFile;
|
||||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("Complex Wave Source");
|
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexWaveSource");
|
||||||
|
|
||||||
public ComplexWaveSource(File file) throws IOException
|
public ComplexWaveSource(File file) throws IOException
|
||||||
{
|
{
|
||||||
@@ -216,7 +216,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
|||||||
|
|
||||||
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
|
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
|
||||||
|
|
||||||
ReusableComplexBuffer reusableBuffer = mReusableBufferQueue.getBuffer(samples.length);
|
ReusableComplexBuffer reusableBuffer = mReusableComplexBufferQueue.getBuffer(samples.length);
|
||||||
reusableBuffer.reloadFrom(samples, System.currentTimeMillis());
|
reusableBuffer.reloadFrom(samples, System.currentTimeMillis());
|
||||||
reusableBuffer.incrementUserCount();
|
reusableBuffer.incrementUserCount();
|
||||||
mListener.receive(reusableBuffer);
|
mListener.receive(reusableBuffer);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
|
|||||||
import io.github.dsheirer.module.ProcessingChain;
|
import io.github.dsheirer.module.ProcessingChain;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
import io.github.dsheirer.sample.SampleType;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||||
import io.github.dsheirer.sample.real.RealBuffer;
|
import io.github.dsheirer.sample.real.RealBuffer;
|
||||||
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
|
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
|
||||||
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
||||||
@@ -69,37 +69,37 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
|
|||||||
private JLayeredPane mLayeredPane;
|
private JLayeredPane mLayeredPane;
|
||||||
private SpectrumPanel mSpectrumPanel;
|
private SpectrumPanel mSpectrumPanel;
|
||||||
private ChannelOverlayPanel mOverlayPanel;
|
private ChannelOverlayPanel mOverlayPanel;
|
||||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue();
|
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ChannelSpectrumPanel");
|
||||||
|
|
||||||
private Channel mCurrentChannel;
|
private Channel mCurrentChannel;
|
||||||
|
|
||||||
private int mSampleBufferSize = 2400;
|
private int mSampleBufferSize = 2400;
|
||||||
|
|
||||||
private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB(
|
private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB(
|
||||||
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true );
|
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true);
|
||||||
|
|
||||||
private AtomicBoolean mEnabled = new AtomicBoolean();
|
private AtomicBoolean mEnabled = new AtomicBoolean();
|
||||||
|
|
||||||
private SettingsManager mSettingsManager;
|
private SettingsManager mSettingsManager;
|
||||||
private ChannelProcessingManager mChannelProcessingManager;
|
private ChannelProcessingManager mChannelProcessingManager;
|
||||||
|
|
||||||
public ChannelSpectrumPanel( SettingsManager settingsManager,
|
public ChannelSpectrumPanel(SettingsManager settingsManager,
|
||||||
ChannelProcessingManager channelProcessingManager )
|
ChannelProcessingManager channelProcessingManager)
|
||||||
{
|
{
|
||||||
mSettingsManager = settingsManager;
|
mSettingsManager = settingsManager;
|
||||||
mChannelProcessingManager = channelProcessingManager;
|
mChannelProcessingManager = channelProcessingManager;
|
||||||
|
|
||||||
if( mSettingsManager != null )
|
if(mSettingsManager != null)
|
||||||
{
|
{
|
||||||
mSettingsManager.addListener( this );
|
mSettingsManager.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSpectrumPanel = new SpectrumPanel( mSettingsManager );
|
mSpectrumPanel = new SpectrumPanel(mSettingsManager);
|
||||||
mSpectrumPanel.setAveraging( 1 );
|
mSpectrumPanel.setAveraging(1);
|
||||||
|
|
||||||
mOverlayPanel = new ChannelOverlayPanel( mSettingsManager );
|
mOverlayPanel = new ChannelOverlayPanel(mSettingsManager);
|
||||||
mDFTProcessor.addConverter( mDFTConverter );
|
mDFTProcessor.addConverter(mDFTConverter);
|
||||||
mDFTConverter.addListener( mSpectrumPanel );
|
mDFTConverter.addListener(mSpectrumPanel);
|
||||||
|
|
||||||
/* Set the DFTProcessor to the decimated 24kHz sample rate */
|
/* Set the DFTProcessor to the decimated 24kHz sample rate */
|
||||||
mDFTProcessor.process(SourceEvent.sampleRateChange(24000.0));
|
mDFTProcessor.process(SourceEvent.sampleRateChange(24000.0));
|
||||||
@@ -109,395 +109,410 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
|
|||||||
|
|
||||||
public void dispose()
|
public void dispose()
|
||||||
{
|
{
|
||||||
setEnabled( false );
|
setEnabled(false);
|
||||||
|
|
||||||
mDFTProcessor.dispose();
|
mDFTProcessor.dispose();
|
||||||
|
|
||||||
if( mSettingsManager != null )
|
if(mSettingsManager != null)
|
||||||
{
|
{
|
||||||
mSettingsManager.removeListener( this );
|
mSettingsManager.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSettingsManager = null;
|
mSettingsManager = null;
|
||||||
mCurrentChannel = null;
|
mCurrentChannel = null;
|
||||||
mDFTProcessor = null;
|
mDFTProcessor = null;
|
||||||
mSpectrumPanel = null;
|
mSpectrumPanel = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrameRate( int framesPerSecond )
|
public void setFrameRate(int framesPerSecond)
|
||||||
{
|
{
|
||||||
mSampleBufferSize = (int)( 48000 / framesPerSecond );
|
mSampleBufferSize = (int)(48000 / framesPerSecond);
|
||||||
|
|
||||||
mDFTProcessor.setFrameRate( framesPerSecond );
|
mDFTProcessor.setFrameRate(framesPerSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initGui()
|
private void initGui()
|
||||||
{
|
{
|
||||||
setLayout( new MigLayout( "insets 0 0 0 0 ",
|
setLayout(new MigLayout("insets 0 0 0 0 ",
|
||||||
"[grow,fill]",
|
"[grow,fill]",
|
||||||
"[grow,fill]") );
|
"[grow,fill]"));
|
||||||
|
|
||||||
mLayeredPane = new JLayeredPane();
|
mLayeredPane = new JLayeredPane();
|
||||||
mLayeredPane.addComponentListener( new ResizeListener() );
|
mLayeredPane.addComponentListener(new ResizeListener());
|
||||||
|
|
||||||
MouseEventProcessor mouser = new MouseEventProcessor();
|
MouseEventProcessor mouser = new MouseEventProcessor();
|
||||||
|
|
||||||
mOverlayPanel.addMouseListener( mouser );
|
mOverlayPanel.addMouseListener(mouser);
|
||||||
mOverlayPanel.addMouseMotionListener( mouser );
|
mOverlayPanel.addMouseMotionListener(mouser);
|
||||||
|
|
||||||
mLayeredPane.add( mSpectrumPanel, new Integer( 0 ), 0 );
|
mLayeredPane.add(mSpectrumPanel, new Integer(0), 0);
|
||||||
mLayeredPane.add( mOverlayPanel, new Integer( 1 ), 0 );
|
mLayeredPane.add(mOverlayPanel, new Integer(1), 0);
|
||||||
|
|
||||||
add( mLayeredPane );
|
add(mLayeredPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled( boolean enabled )
|
public void setEnabled(boolean enabled)
|
||||||
{
|
{
|
||||||
if( enabled && mEnabled.compareAndSet( false, true ) )
|
if(enabled && mEnabled.compareAndSet(false, true))
|
||||||
{
|
{
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
else if( !enabled && mEnabled.compareAndSet( true, false ) )
|
else if(!enabled && mEnabled.compareAndSet(true, false))
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( "incomplete-switch" )
|
@SuppressWarnings("incomplete-switch")
|
||||||
public void channelChanged( ChannelEvent event )
|
public void channelChanged(ChannelEvent event)
|
||||||
{
|
{
|
||||||
switch( event.getEvent() )
|
switch(event.getEvent())
|
||||||
{
|
{
|
||||||
case NOTIFICATION_SELECTION_CHANGE:
|
case NOTIFICATION_SELECTION_CHANGE:
|
||||||
//ChannelSelectionManager ensures that only 1 channel can be
|
//ChannelSelectionManager ensures that only 1 channel can be
|
||||||
//selected and any previously selected channel will be first
|
//selected and any previously selected channel will be first
|
||||||
//deselected before we get a new selection event
|
//deselected before we get a new selection event
|
||||||
if( event.getChannel().isSelected() )
|
if(event.getChannel().isSelected())
|
||||||
{
|
{
|
||||||
if( mCurrentChannel != null )
|
if(mCurrentChannel != null)
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
mCurrentChannel = null;
|
mCurrentChannel = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentChannel = event.getChannel();
|
mCurrentChannel = event.getChannel();
|
||||||
|
|
||||||
if( mEnabled.get() )
|
if(mEnabled.get())
|
||||||
{
|
{
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
mCurrentChannel = null;
|
mCurrentChannel = null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NOTIFICATION_PROCESSING_STOP:
|
case NOTIFICATION_PROCESSING_STOP:
|
||||||
if( event.getChannel() == mCurrentChannel )
|
if(event.getChannel() == mCurrentChannel)
|
||||||
{
|
{
|
||||||
if( mEnabled.get() )
|
if(mEnabled.get())
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentChannel = null;
|
mCurrentChannel = null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start()
|
private void start()
|
||||||
{
|
|
||||||
if( mEnabled.get() && mCurrentChannel != null && mCurrentChannel.isProcessing() )
|
|
||||||
{
|
|
||||||
ProcessingChain processingChain = mChannelProcessingManager
|
|
||||||
.getProcessingChain( mCurrentChannel );
|
|
||||||
|
|
||||||
if( processingChain != null )
|
|
||||||
{
|
|
||||||
processingChain.addRealBufferListener( this );
|
|
||||||
|
|
||||||
mDFTProcessor.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stop()
|
|
||||||
{
|
|
||||||
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 )
|
if(mEnabled.get() && mCurrentChannel != null && mCurrentChannel.isProcessing())
|
||||||
{
|
{
|
||||||
mSpectrumPanel.settingChanged( setting );
|
ProcessingChain processingChain = mChannelProcessingManager
|
||||||
}
|
.getProcessingChain(mCurrentChannel);
|
||||||
if( mOverlayPanel != null )
|
|
||||||
{
|
if(processingChain != null)
|
||||||
mOverlayPanel.settingChanged( setting );
|
{
|
||||||
}
|
processingChain.addRealBufferListener(this);
|
||||||
|
|
||||||
|
mDFTProcessor.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void stop()
|
||||||
public void settingDeleted( Setting setting )
|
|
||||||
{
|
{
|
||||||
if( mSpectrumPanel != null )
|
if(mCurrentChannel != null && mCurrentChannel.isProcessing())
|
||||||
{
|
{
|
||||||
mSpectrumPanel.settingDeleted( setting );
|
ProcessingChain processingChain = mChannelProcessingManager
|
||||||
}
|
.getProcessingChain(mCurrentChannel);
|
||||||
|
|
||||||
if( mOverlayPanel != null )
|
if(processingChain != null)
|
||||||
{
|
{
|
||||||
mOverlayPanel.settingDeleted( setting );
|
processingChain.removeRealBufferListener(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDFTProcessor.stop();
|
||||||
|
|
||||||
|
mSpectrumPanel.clearSpectrum();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void receive( RealBuffer buffer )
|
public void settingChanged(Setting setting)
|
||||||
{
|
{
|
||||||
RealBuffer decimated = mDecimatingFilter.filter( buffer );
|
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
|
//Hack: we're placing real samples in a complex buffer that the DFT
|
||||||
//processor is expecting.
|
//processor is expecting.
|
||||||
ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(decimated.getSamples().length);
|
ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(decimated.getSamples().length);
|
||||||
reusableComplexBuffer.reloadFrom(decimated.getSamples(), System.currentTimeMillis());
|
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
|
* Monitors the sizing of the layered pane and resizes the spectrum and
|
||||||
* channel panels whenever the layered pane is resized
|
* channel panels whenever the layered pane is resized
|
||||||
*/
|
*/
|
||||||
public class ResizeListener implements ComponentListener
|
public class ResizeListener implements ComponentListener
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void componentResized( ComponentEvent e )
|
public void componentResized(ComponentEvent e)
|
||||||
{
|
{
|
||||||
Component c = e.getComponent();
|
Component c = e.getComponent();
|
||||||
|
|
||||||
mSpectrumPanel.setBounds( 0, 0, c.getWidth(), c.getHeight() );
|
mSpectrumPanel.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||||
mOverlayPanel.setBounds( 0, 0, c.getWidth(), c.getHeight() );
|
mOverlayPanel.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void componentHidden( ComponentEvent arg0 ) {}
|
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 )
|
|
||||||
{
|
{
|
||||||
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
|
@Override
|
||||||
public void mousePressed( MouseEvent e ) {}
|
public void componentMoved(ComponentEvent arg0)
|
||||||
@Override
|
{
|
||||||
public void mouseReleased( MouseEvent e ) {}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@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()
|
public int getAveraging()
|
||||||
{
|
{
|
||||||
return mSpectrumPanel.getAveraging();
|
return mSpectrumPanel.getAveraging();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAveraging( int averaging )
|
public void setAveraging(int averaging)
|
||||||
{
|
{
|
||||||
mSpectrumPanel.setAveraging( averaging );
|
mSpectrumPanel.setAveraging(averaging);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSampleSize( double sampleSize )
|
public void setSampleSize(double sampleSize)
|
||||||
{
|
{
|
||||||
mSpectrumPanel.setSampleSize( sampleSize );
|
mSpectrumPanel.setSampleSize(sampleSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSmoothing()
|
public int getSmoothing()
|
||||||
{
|
{
|
||||||
return mSpectrumPanel.getSmoothing();
|
return mSpectrumPanel.getSmoothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSmoothing( int smoothing )
|
public void setSmoothing(int smoothing)
|
||||||
{
|
{
|
||||||
mSpectrumPanel.setSmoothing( smoothing );
|
mSpectrumPanel.setSmoothing(smoothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SmoothingType getSmoothingType()
|
public SmoothingType getSmoothingType()
|
||||||
{
|
{
|
||||||
return mSpectrumPanel.getSmoothingType();
|
return mSpectrumPanel.getSmoothingType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSmoothingType( SmoothingType type )
|
public void setSmoothingType(SmoothingType type)
|
||||||
{
|
{
|
||||||
mSpectrumPanel.setSmoothingType( type );
|
mSpectrumPanel.setSmoothingType(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import io.github.dsheirer.dsp.filter.Window.WindowType;
|
|||||||
import io.github.dsheirer.properties.SystemProperties;
|
import io.github.dsheirer.properties.SystemProperties;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
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.sample.real.IOverflowListener;
|
||||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package io.github.dsheirer.spectrum;
|
|||||||
|
|
||||||
|
|
||||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -206,6 +206,13 @@ public class OverflowableBufferStream extends OverflowableTransferQueue<Reusable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void overflow(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
|
{
|
||||||
|
mLog.debug("*** Overflow - throwing away buffer: " + reusableComplexBuffer.name());
|
||||||
|
reusableComplexBuffer.decrementUserCount();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all elements from the queue and resets the internal counter to 0
|
* Clears all elements from the queue and resets the internal counter to 0
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import io.github.dsheirer.module.decode.DecoderType;
|
|||||||
import io.github.dsheirer.properties.SystemProperties;
|
import io.github.dsheirer.properties.SystemProperties;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
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.ColorSetting.ColorSettingName;
|
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
|
||||||
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
||||||
import io.github.dsheirer.settings.SettingsManager;
|
import io.github.dsheirer.settings.SettingsManager;
|
||||||
@@ -415,8 +415,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||||
{
|
{
|
||||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
mDFTProcessor.receive(reusableComplexBuffer);
|
||||||
reusableComplexBuffer.decrementUserCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user