mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Updates complex decimation filters to use either scalar or vector optimal implementation. (#1148)
Updates HackRF native byte buffers with automatic DC removal. Creates new half-band channel source to replace the cic-based channel source in the heterodyne channelizer. Resolves issue in RTL native buffer processing. Creates a CACHED thread pool and reduces the number of threads for the SCHEDULED thread pool to 2. Changes each of the channel source implementations to use a dedicated thread (Dispatcher class) instead of the scheduled thread pool, to reduce the amount of buffered/retained samples objects in memory. Lots of other small changes and tweaks. Removes last of Reusable buffer code. Updates DFTProcessor to use a single thread scheduled executor. Updates Polyphase channelizer to use threads instead of an executor. Removes a number of unused classes. Commenting out window calibration. Scalar is faster in both implementations. Adds vector and scalar implementations for windows. Repackages window and window type classes. WIP adds vector implementations for Airspy non-interleaved buffer iterator and calibration plugins for both interleaved and non-interleaved buffer iterators. WIP adds vector implementations for Airspy interleaved buffer iterator. Work on developing scalar and vector implementations of airspy sample conversion and airspy native buffer processing. Introduces new INativeBuffer framework where tuner raw samples are retained in their native (compressed) format until when they're needed and they are converted on-demand into smaller complex sample buffers to aid garbage collection. Removes all usage of ReusableComplexBuffers and ReusableChannelREsultsBuffers. Updates polyphase channelizer to be more efficient in output channel processing. Updates ViterbiDecoder to change Map usage to array for memory efficiency. Updates channel processors to used scalar implementation for gain and mixer, until the polyphase channel results can be fixed to be a multiple of the SIMD lane width. Resolves final changes for the conversion from interleaved sample arrays to complexsamples buffers for distributing baseband samples to channels and processing chains. Updates tuner channel sources and all decoders to receive new complex samples buffers, removing the previous reusable complex buffers as the default baseband samples buffer object. Still to resolve is the ComplexMixer implementations. Needs validation and a calibration implementation with an update to the complex mixer factory. Updates the DMR decoder to use optimal (scalar vs vector) implementations of filter and AGC controls. Updates the AM demodulator for separated I&Q float sample processing. Code review and testing changes. updates build script for runtime configuration. Integrates calibration manager with main sdrtrunk application. Updates NBFMDecoder to use new optimized FIR and Decimation filter options. Updates real half-band decimation filters to select the optimal (scalar vs vector) implementation. Adds calibration manager plugins. Adds calibration manager and plugins to determine the optimal (scalar vs vector) implementation type to use for various classes of dsp components. Adds vector squelching FM demodulator and cleans up the IIR filter and power squelch to use all floats. Adds vector implementation of FM demodulator. This introduces a new interface that accepts i/q samples as two separate float arrays, versus an interleaved array, which enables more efficient processing. This new complex sample interface will be used across the codebase eventually. Adds ComplexOscillator and a SIMD version VectorComplexOscillator. Deprecates the LowPhaseNoiseOscillator because the ComplexOscillator is about 35% faster. The vectorized version is about 43% faster when SIMD lane width is 8x. Adds new vector complex filters and new real oscillators. Note: the RealOscillator using straight Java math sin() function is 3x slower than the existing legacy implementation. Will replace this with a complex oscillator that only uses the real part. Updates ComplexFIRFilter to be 50% more efficient. Adds 23 tap filter implementations. Will not add 63-tap implementations because they are slower than the default vector implementation. Adds 15-tap customized vector half band filters. Adds initial custom complex vector half-band decimation filters for 11-tap and 15-tap decimation filters.. Adds vector complex half band filter implementations. Note: performance of the generic 64-bit 2-lane filter is horrible and is not included. Optimizes complex half-band filter to be 27% more efficient. Implements vectorized real half-band filter implementations. Implements a new FIR filter class that processes sample buffers instead of single sample at a time. Refactored all of the calibratons to be time-duration based. Testing on windows i7 gen 3 CPU showed that it took 1000x longer for one of the calibrations to run, versus my AMD 5800x. Changed gradle jvm args so that the windows plaf export is always applied. Updates gradle build script to ensure incubator module is included and to cleanup javafx library management for building runtime images. Testing tweaks and changes. Adds logging limiter to dispatcher for buffer overflows Adds User Preferences editor for performing Vector/SIMD calibrations and new startup dialog prompting the user to perform calibrations. Updates calibration manager and all calibration implementations to add warm-up and test phases and to reduce the overall time it takes to calibrate a system. Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -17,9 +17,9 @@ package io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.sample.Provider;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
|
||||
public abstract class ComplexSource extends Source implements Provider<ReusableComplexBuffer>
|
||||
public abstract class ComplexSource extends Source implements Provider<ComplexSamples>
|
||||
{
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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.source;
|
||||
|
||||
import io.github.dsheirer.sample.Provider;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
|
||||
|
||||
|
||||
public abstract class RealSource extends Source implements Provider<ReusableFloatBuffer>
|
||||
public abstract class RealSource extends Source implements Provider<float[]>
|
||||
{
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.mixer;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ComplexSampleAdapter;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -28,7 +31,7 @@ import javax.sound.sampled.TargetDataLine;
|
||||
public class ComplexMixer
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexMixer.class);
|
||||
private MixerReader<ReusableComplexBuffer> mMixerReader;
|
||||
private MixerReader<INativeBuffer> mMixerReader;
|
||||
private String mName;
|
||||
|
||||
/**
|
||||
@@ -38,12 +41,11 @@ public class ComplexMixer
|
||||
* @param targetDataLine - mixer or sound card to be used
|
||||
* @param format - audio format
|
||||
* @param name - token name to use for this mixer
|
||||
* @param complexSampleAdapter - adapter to convert byte array data read from the mixer into ReusableComplexBuffer.
|
||||
* @param sampleAdapter - adapter to convert byte array data read from the mixer into ReusableComplexBuffer.
|
||||
*/
|
||||
public ComplexMixer(TargetDataLine targetDataLine, AudioFormat format, String name,
|
||||
ComplexSampleAdapter complexSampleAdapter)
|
||||
public ComplexMixer(TargetDataLine targetDataLine, AudioFormat format, String name, ISampleAdapter sampleAdapter)
|
||||
{
|
||||
mMixerReader = new MixerReader<>(format, targetDataLine, complexSampleAdapter);
|
||||
mMixerReader = new MixerReader<INativeBuffer>(format, targetDataLine, sampleAdapter);
|
||||
mName = name;
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ public class ComplexMixer
|
||||
mMixerReader.stop();
|
||||
}
|
||||
|
||||
public void setBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void setBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mMixerReader.setBufferListener(listener);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.mixer;
|
||||
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
@@ -84,7 +87,7 @@ public class MixerManager
|
||||
if(dataLine != null)
|
||||
{
|
||||
return new RealMixerSource(dataLine, AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO,
|
||||
new RealShortAdapter("RealMixerSource - Mono"));
|
||||
new RealShortAdapter());
|
||||
}
|
||||
}
|
||||
catch(LineUnavailableException e)
|
||||
@@ -108,7 +111,7 @@ public class MixerManager
|
||||
if(dataLine != null)
|
||||
{
|
||||
return new RealMixerSource(dataLine, AudioFormats.PCM_SIGNED_8KHZ_16BITS_STEREO,
|
||||
new RealChannelShortAdapter(mixerConfig.getChannel(), "RealMixerSource-Stereo"));
|
||||
new RealChannelShortAdapter(mixerConfig.getChannel()));
|
||||
}
|
||||
}
|
||||
catch(LineUnavailableException e)
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.mixer;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.AbstractSampleAdapter;
|
||||
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.heartbeat.HeartbeatManager;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
@@ -37,7 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* the samples to an array of floats using the specified adapter. Dispatches float arrays to the registered
|
||||
* buffer listener.
|
||||
*/
|
||||
public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
public class MixerReader<T> implements Runnable
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(MixerReader.class);
|
||||
|
||||
@@ -48,14 +50,14 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private ScheduledFuture mScheduledFuture;
|
||||
private int mBytesRead;
|
||||
private AbstractSampleAdapter<T> mSampleAdapter;
|
||||
private Listener<T> mReusableBufferListener;
|
||||
private ISampleAdapter<T> mSampleAdapter;
|
||||
private Listener<T> mListener;
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
private AudioFormat mAudioFormat;
|
||||
private HeartbeatManager mHeartbeatManager;
|
||||
|
||||
public MixerReader(AudioFormat audioFormat, TargetDataLine targetDataLine,
|
||||
AbstractSampleAdapter<T> abstractSampleAdapter, HeartbeatManager heartbeatManager)
|
||||
ISampleAdapter<T> abstractSampleAdapter, HeartbeatManager heartbeatManager)
|
||||
{
|
||||
mTargetDataLine = targetDataLine;
|
||||
mAudioFormat = audioFormat;
|
||||
@@ -66,7 +68,7 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
mBufferSize = (int)(mAudioFormat.getSampleRate() * 0.1) * mAudioFormat.getFrameSize();
|
||||
}
|
||||
|
||||
public MixerReader(AudioFormat audioFormat, TargetDataLine targetDataLine, AbstractSampleAdapter<T> abstractSampleAdapter)
|
||||
public MixerReader(AudioFormat audioFormat, TargetDataLine targetDataLine, ISampleAdapter<T> abstractSampleAdapter)
|
||||
{
|
||||
this(audioFormat, targetDataLine, abstractSampleAdapter, new HeartbeatManager());
|
||||
}
|
||||
@@ -210,9 +212,9 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
//Sample adapter automatically sets initial listener count to one.
|
||||
T reusableBuffer = mSampleAdapter.convert(mBuffer);
|
||||
|
||||
if(reusableBuffer != null && mReusableBufferListener != null)
|
||||
if(reusableBuffer != null && mListener != null)
|
||||
{
|
||||
mReusableBufferListener.receive(reusableBuffer);
|
||||
mListener.receive(reusableBuffer);
|
||||
}
|
||||
}
|
||||
else if(mBytesRead > 0)
|
||||
@@ -220,9 +222,9 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
//Sample adapter automatically sets initial listener count to one.
|
||||
T reusableBuffer = mSampleAdapter.convert(Arrays.copyOf(mBuffer, mBytesRead));
|
||||
|
||||
if(reusableBuffer != null && mReusableBufferListener != null)
|
||||
if(reusableBuffer != null && mListener != null)
|
||||
{
|
||||
mReusableBufferListener.receive(reusableBuffer);
|
||||
mListener.receive(reusableBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,7 +249,7 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
*/
|
||||
public void setBufferListener(Listener<T> listener)
|
||||
{
|
||||
mReusableBufferListener = listener;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,7 +257,7 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
*/
|
||||
public void removeBufferListener()
|
||||
{
|
||||
mReusableBufferListener = null;
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,7 +298,7 @@ public class MixerReader<T extends ReusableFloatBuffer> implements Runnable
|
||||
{
|
||||
stop();
|
||||
mHeartbeatManager = null;
|
||||
mReusableBufferListener = null;
|
||||
mListener = null;
|
||||
mSourceEventListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.mixer;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.AbstractSampleAdapter;
|
||||
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.source.RealSource;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
@@ -40,7 +42,7 @@ public class RealMixerSource extends RealSource
|
||||
* @param sampleAdapter - adapter to convert byte array data read from the
|
||||
* mixer into float array data.
|
||||
*/
|
||||
public RealMixerSource(TargetDataLine targetDataLine, AudioFormat format, AbstractSampleAdapter sampleAdapter)
|
||||
public RealMixerSource(TargetDataLine targetDataLine, AudioFormat format, ISampleAdapter sampleAdapter)
|
||||
{
|
||||
mMixerReader = new MixerReader(format, targetDataLine, sampleAdapter, getHeartbeatManager());
|
||||
}
|
||||
@@ -101,7 +103,7 @@ public class RealMixerSource extends RealSource
|
||||
/**
|
||||
* Sets the listener to receive sample data in reusable buffers.
|
||||
*/
|
||||
public void setListener(Listener<ReusableFloatBuffer> listener)
|
||||
public void setListener(Listener<float[]> listener)
|
||||
{
|
||||
mMixerReader.setBufferListener(listener);
|
||||
}
|
||||
@@ -110,7 +112,7 @@ public class RealMixerSource extends RealSource
|
||||
* Removes the listener from receiving sample data.
|
||||
* @param listener
|
||||
*/
|
||||
public void removeListener(Listener<ReusableFloatBuffer> listener)
|
||||
public void removeListener(Listener<float[]> listener)
|
||||
{
|
||||
mMixerReader.removeBufferListener();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* Copyright (C) 2014-2022 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
|
||||
@@ -18,13 +18,13 @@
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.buffer.INativeBufferProvider;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderFactory;
|
||||
import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder;
|
||||
import io.github.dsheirer.record.wave.NativeBufferWaveRecorder;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.IReusableComplexBufferProvider;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.ISourceEventListener;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
@@ -40,16 +40,16 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.SortedSet;
|
||||
|
||||
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
|
||||
IReusableComplexBufferProvider, Listener<ReusableComplexBuffer>, ITunerErrorListener
|
||||
INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
|
||||
protected ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster();
|
||||
protected Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster();
|
||||
protected FrequencyController mFrequencyController;
|
||||
private int mMiddleUnusableHalfBandwidth;
|
||||
private double mUsableBandwidthPercentage;
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
private int mMeasuredFrequencyError;
|
||||
private ComplexBufferWaveRecorder mRecorder;
|
||||
private NativeBufferWaveRecorder mRecorder;
|
||||
private ITunerErrorListener mTunerErrorListener;
|
||||
|
||||
/**
|
||||
@@ -137,13 +137,13 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
case REQUEST_START_SAMPLE_STREAM:
|
||||
if(sourceEvent.getSource() instanceof Listener)
|
||||
{
|
||||
addBufferListener((Listener<ReusableComplexBuffer>)sourceEvent.getSource());
|
||||
addBufferListener((Listener<INativeBuffer>)sourceEvent.getSource());
|
||||
}
|
||||
break;
|
||||
case REQUEST_STOP_SAMPLE_STREAM:
|
||||
if(sourceEvent.getSource() instanceof Listener)
|
||||
{
|
||||
removeBufferListener((Listener<ReusableComplexBuffer>)sourceEvent.getSource());
|
||||
removeBufferListener((Listener<INativeBuffer>)sourceEvent.getSource());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -357,18 +357,18 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
* Adds the listener to receive complex buffer samples
|
||||
*/
|
||||
@Override
|
||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mReusableBufferBroadcaster.addListener(listener);
|
||||
mNativeBufferBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving complex buffer samples
|
||||
*/
|
||||
@Override
|
||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mReusableBufferBroadcaster.removeListener(listener);
|
||||
mNativeBufferBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,24 +377,24 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
@Override
|
||||
public boolean hasBufferListeners()
|
||||
{
|
||||
return mReusableBufferBroadcaster.hasListeners();
|
||||
return mNativeBufferBroadcaster.hasListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the buffer to any registered listeners
|
||||
*/
|
||||
protected void broadcast(ReusableComplexBuffer reusableComplexBuffer)
|
||||
protected void broadcast(INativeBuffer complexSamples)
|
||||
{
|
||||
mReusableBufferBroadcaster.broadcast(reusableComplexBuffer);
|
||||
mNativeBufferBroadcaster.broadcast(complexSamples);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Listener<T> interface to receive and distribute complex buffers from subclass implementations
|
||||
*/
|
||||
@Override
|
||||
public void receive(ReusableComplexBuffer complexBuffer)
|
||||
public void receive(INativeBuffer nativeBuffer)
|
||||
{
|
||||
broadcast(complexBuffer);
|
||||
broadcast(nativeBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,13 +480,13 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
|
||||
/**
|
||||
* Records the complex I/Q buffers produced by the tuner
|
||||
* @param recorderManager to obtain a baseband recorder
|
||||
* @param userPreferences to obtain a baseband recorder
|
||||
*/
|
||||
public void startRecorder(UserPreferences userPreferences)
|
||||
{
|
||||
if(!isRecording())
|
||||
{
|
||||
mRecorder = RecorderFactory.getBasebandRecorder("TUNER_" + getFrequency(), userPreferences);
|
||||
mRecorder = RecorderFactory.getTunerRecorder("TUNER_" + getFrequency(), userPreferences);
|
||||
mRecorder.setSampleRate((float)getSampleRate());
|
||||
mRecorder.start();
|
||||
addBufferListener(mRecorder);
|
||||
|
||||
@@ -1,160 +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.source.tuner.airspy;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.dc.DCRemovalFilter;
|
||||
import io.github.dsheirer.dsp.filter.hilbert.HilbertTransform;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public class AirspySampleConverter extends NativeBufferConverter
|
||||
{
|
||||
private static final float SCALE_SIGNED_12_BIT_TO_FLOAT = 1.0f / 2048.0f;
|
||||
|
||||
private DCRemovalFilter mDCFilter = new DCRemovalFilter(0.01f);
|
||||
private HilbertTransform mHilbertTransform = new HilbertTransform();
|
||||
private boolean mSamplePacking = false;
|
||||
private FloatBuffer mFloatBuffer;
|
||||
private float[] mConvertedSamples;
|
||||
|
||||
/**
|
||||
* Adapter to translate byte buffers received from the airspy tuner into
|
||||
* float buffers for processing.
|
||||
*/
|
||||
public AirspySampleConverter()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FloatBuffer convertSamples(ByteBuffer buffer, int length)
|
||||
{
|
||||
float[] samples = convert(buffer);
|
||||
|
||||
if(mFloatBuffer == null || mFloatBuffer.capacity() != samples.length)
|
||||
{
|
||||
mFloatBuffer = FloatBuffer.allocate(samples.length);
|
||||
}
|
||||
|
||||
mFloatBuffer.rewind();
|
||||
mFloatBuffer.put(samples);
|
||||
|
||||
return mFloatBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample packing places two 12-bit samples into 3 bytes when enabled or
|
||||
* places two 12-bit samples into 4 bytes when disabled.
|
||||
*
|
||||
* @param enabled
|
||||
*/
|
||||
public void setSamplePacking(boolean enabled)
|
||||
{
|
||||
mSamplePacking = enabled;
|
||||
}
|
||||
|
||||
private float[] convert(ByteBuffer samples)
|
||||
{
|
||||
if(mSamplePacking)
|
||||
{
|
||||
convertPacked(samples.order(ByteOrder.LITTLE_ENDIAN));
|
||||
}
|
||||
else
|
||||
{
|
||||
convertUnpacked(samples);
|
||||
}
|
||||
|
||||
mDCFilter.filter(mConvertedSamples);
|
||||
|
||||
return mHilbertTransform.filter(mConvertedSamples);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the byte array containing unsigned 12-bit short values into
|
||||
* signed float values in the range -1 to 1;
|
||||
*
|
||||
* @param buffer - native byte buffer containing unsigned 16-bit values
|
||||
*/
|
||||
private void convertUnpacked(ByteBuffer buffer)
|
||||
{
|
||||
buffer.rewind();
|
||||
|
||||
if(mConvertedSamples == null || mConvertedSamples.length != buffer.capacity() / 2)
|
||||
{
|
||||
mConvertedSamples = new float[buffer.capacity() / 2];
|
||||
}
|
||||
|
||||
int pointer = 0;
|
||||
|
||||
|
||||
while(buffer.remaining() >= 2)
|
||||
{
|
||||
byte lsb = buffer.get();
|
||||
byte msb = buffer.get();
|
||||
mConvertedSamples[pointer++] = scale((lsb & 0xFF) | (msb << 8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts every 3 bytes containing a pair of 12-bit unsigned values into
|
||||
* a pair of float values in the range -1 to 1;
|
||||
*
|
||||
* @param buffer - native byte buffer containing packet 12-bit unsigned samples
|
||||
*/
|
||||
private void convertPacked(ByteBuffer buffer)
|
||||
{
|
||||
buffer.rewind();
|
||||
|
||||
int sampleCount = buffer.capacity() / 3 * 2;
|
||||
|
||||
if(mConvertedSamples == null || mConvertedSamples.length != sampleCount)
|
||||
{
|
||||
mConvertedSamples = new float[sampleCount];
|
||||
}
|
||||
|
||||
int pointer = 0;
|
||||
|
||||
byte b1;
|
||||
byte b2;
|
||||
byte b3;
|
||||
int first;
|
||||
int second;
|
||||
|
||||
while(buffer.remaining() >= 3)
|
||||
{
|
||||
b1 = buffer.get();
|
||||
b2 = buffer.get();
|
||||
b3 = buffer.get();
|
||||
|
||||
first = ((b1 << 4) & 0xFF0) | ((b2 >> 4) & 0xF);
|
||||
mConvertedSamples[pointer++] = scale(first);
|
||||
|
||||
second = ((b2 << 8) & 0xF00) | (b3 & 0xFF);
|
||||
mConvertedSamples[pointer++] = scale(second);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts unsigned 12-bit values to signed 12-bit values and then scales
|
||||
* the signed value to a signed float value in range: -1.0 : +1.0
|
||||
*/
|
||||
public static float scale(int value)
|
||||
{
|
||||
return (float) ((value & 0xFFF) - 2048) * SCALE_SIGNED_12_BIT_TO_FLOAT;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,25 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.airspy;
|
||||
|
||||
import io.github.dsheirer.buffer.airspy.AirspyNativeBufferFactory;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
@@ -76,7 +74,7 @@ public class AirspyTunerController extends USBTunerController
|
||||
private Device mDevice;
|
||||
private DeviceHandle mDeviceHandle;
|
||||
|
||||
private AirspySampleConverter mSampleAdapter = new AirspySampleConverter();
|
||||
private AirspyNativeBufferFactory mNativeBufferFactory = new AirspyNativeBufferFactory();
|
||||
private AirspyDeviceInformation mDeviceInfo;
|
||||
private List<AirspySampleRate> mSampleRates = new ArrayList<>();
|
||||
private int mSampleRate = 0;
|
||||
@@ -166,7 +164,7 @@ public class AirspyTunerController extends USBTunerController
|
||||
|
||||
String deviceName = "Airspy " + getDeviceInfo().getSerialNumber();
|
||||
|
||||
mUSBTransferProcessor = new USBTransferProcessor(deviceName, mDeviceHandle, mSampleAdapter,
|
||||
mUSBTransferProcessor = new USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferFactory,
|
||||
USB_TRANSFER_BUFFER_SIZE, this);
|
||||
}
|
||||
|
||||
@@ -489,7 +487,7 @@ public class AirspyTunerController extends USBTunerController
|
||||
|
||||
/* If we didn't throw an exception above, then update the sample adapter
|
||||
* to process samples accordingly */
|
||||
mSampleAdapter.setSamplePacking(enabled);
|
||||
mNativeBufferFactory.setSamplePacking(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.buffer.NativeBufferPoisonPill;
|
||||
import io.github.dsheirer.dsp.filter.cic.PrimeCicDecimationFilter;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.mixer.IOscillator;
|
||||
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||
import io.github.dsheirer.sample.IOverflowListener;
|
||||
import io.github.dsheirer.dsp.mixer.ComplexMixer;
|
||||
import io.github.dsheirer.dsp.mixer.ComplexMixerFactory;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
|
||||
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.ComplexSamples;
|
||||
import io.github.dsheirer.sample.complex.ComplexSamplesRepackager;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.util.Dispatcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -35,24 +38,24 @@ import java.util.List;
|
||||
* CIC decimation filter that requires the decimation rate to be an integer multiple. Sample buffer processing
|
||||
* occurs on a scheduled runnable thread.
|
||||
*/
|
||||
public class CICTunerChannelSource extends TunerChannelSource implements Listener<ReusableComplexBuffer>
|
||||
public class CICTunerChannelSource<T extends INativeBuffer> extends TunerChannelSource implements Listener<T>
|
||||
{
|
||||
// private final static Logger mLog = LoggerFactory.getLogger(CICTunerChannelSource.class);
|
||||
|
||||
//Maximum number of filled buffers for the blocking queue
|
||||
private static final int BUFFER_MAX_CAPACITY = 300;
|
||||
|
||||
//Threshold for resetting buffer overflow condition
|
||||
private static final int BUFFER_OVERFLOW_RESET_THRESHOLD = 100;
|
||||
|
||||
private OverflowableReusableBufferTransferQueue<ReusableComplexBuffer> mBuffer;
|
||||
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("CICTunerChannelSource");
|
||||
private IOscillator mFrequencyCorrectionMixer;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
private List<ReusableComplexBuffer> mSampleBuffers = new ArrayList<>();
|
||||
//Samples repackager is set to 2048 (a power of 2) to align with channel processing chain requirements.
|
||||
private final ComplexSamplesRepackager mSamplesRepackager = new ComplexSamplesRepackager(1024);
|
||||
private Dispatcher<T> mBufferDispatcher;
|
||||
private ComplexMixer mFrequencyCorrectionMixer;
|
||||
private PrimeCicDecimationFilter mIDecimationFilter;
|
||||
private PrimeCicDecimationFilter mQDecimationFilter;
|
||||
private double mChannelSampleRate;
|
||||
private long mChannelFrequencyCorrection = 0;
|
||||
private long mTunerFrequency;
|
||||
private Listener<ComplexSamples> mListener;
|
||||
|
||||
/**
|
||||
* Constructs a frequency translating and CIC decimating channel source.
|
||||
@@ -71,29 +74,35 @@ public class CICTunerChannelSource extends TunerChannelSource implements Listene
|
||||
|
||||
int decimation = (int)(sampleRate / channelSpecification.getMinimumSampleRate());
|
||||
|
||||
mDecimationFilter = new ComplexPrimeCICDecimate(sampleRate, decimation, channelSpecification.getPassFrequency(),
|
||||
channelSpecification.getStopFrequency());
|
||||
mIDecimationFilter = new PrimeCicDecimationFilter(sampleRate, decimation, channelSpecification.getPassFrequency(),
|
||||
channelSpecification.getStopFrequency());
|
||||
mQDecimationFilter = new PrimeCicDecimationFilter(sampleRate, decimation, channelSpecification.getPassFrequency(),
|
||||
channelSpecification.getStopFrequency());
|
||||
|
||||
mBuffer = new OverflowableReusableBufferTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD);
|
||||
mBufferDispatcher = new Dispatcher(BUFFER_MAX_CAPACITY, "sdrtrunk cic channel " +
|
||||
tunerChannel.getFrequency(), new NativeBufferPoisonPill());
|
||||
mBufferDispatcher.setListener(new NativeBufferProcessor());
|
||||
|
||||
//Setup the frequency mixer to the current source frequency
|
||||
mChannelSampleRate = sampleRate / (double)decimation;
|
||||
mTunerFrequency = tunerChannel.getFrequency();
|
||||
long frequencyOffset = mTunerFrequency - getTunerChannel().getFrequency();
|
||||
|
||||
mFrequencyCorrectionMixer = new LowPhaseNoiseOscillator(frequencyOffset, sampleRate);
|
||||
mFrequencyCorrectionMixer = ComplexMixerFactory.getMixer(frequencyOffset, sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an overflow listener to be notified in the internal buffer is in an
|
||||
* overflow state.
|
||||
*
|
||||
* @param listener to receiver updates to the source overflow state
|
||||
*/
|
||||
@Override
|
||||
public void setOverflowListener(IOverflowListener listener)
|
||||
public void start()
|
||||
{
|
||||
mBuffer.setOverflowListener(listener);
|
||||
super.start();
|
||||
mBufferDispatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
super.stop();
|
||||
mBufferDispatcher.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,9 +115,9 @@ public class CICTunerChannelSource extends TunerChannelSource implements Listene
|
||||
* Primary interface for receiving incoming complex sample buffers to be frequency translated and decimated.
|
||||
*/
|
||||
@Override
|
||||
public void receive(ReusableComplexBuffer buffer)
|
||||
public void receive(T complexSamples)
|
||||
{
|
||||
mBuffer.offer(buffer);
|
||||
mBufferDispatcher.receive(complexSamples);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,21 +200,14 @@ public class CICTunerChannelSource extends TunerChannelSource implements Listene
|
||||
/**
|
||||
* Sets the listener to receive the complex buffer sample output from this channel
|
||||
*
|
||||
* @param complexBufferListener to receive complex buffers
|
||||
* @param listener to receive complex buffers
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener<ReusableComplexBuffer> complexBufferListener)
|
||||
public void setListener(Listener<ComplexSamples> listener)
|
||||
{
|
||||
mDecimationFilter.setListener(complexBufferListener);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ReusableComplexBuffer> listener)
|
||||
{
|
||||
mDecimationFilter.removeListener();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double getSampleRate()
|
||||
{
|
||||
@@ -213,37 +215,33 @@ public class CICTunerChannelSource extends TunerChannelSource implements Listene
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary processing method that is invoked on a recurring basis to process any queued complex buffers.
|
||||
*
|
||||
* Mixes the target frequency to baseband and then passes the buffer to the CIC decimation filter
|
||||
* Processes native buffers received from the dispatcher and sends to the registered listener
|
||||
*/
|
||||
protected void processSamples()
|
||||
public class NativeBufferProcessor implements Listener<T>
|
||||
{
|
||||
mBuffer.drainTo(mSampleBuffers);
|
||||
|
||||
for(ReusableComplexBuffer complexBuffer : mSampleBuffers)
|
||||
@Override
|
||||
public void receive(T nativeBuffer)
|
||||
{
|
||||
float[] samples = complexBuffer.getSamples();
|
||||
getHeartbeatManager().broadcast();
|
||||
|
||||
ReusableComplexBuffer translatedComplexBuffer = mReusableComplexBufferQueue.getBuffer(samples.length);
|
||||
float[] translatedSamples = translatedComplexBuffer.getSamples();
|
||||
|
||||
/* Perform frequency translation */
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
if(mListener != null)
|
||||
{
|
||||
mFrequencyCorrectionMixer.rotate();
|
||||
Iterator<ComplexSamples> iterator = nativeBuffer.iterator();
|
||||
|
||||
translatedSamples[x] = Complex.multiplyInphase(samples[x], samples[x + 1],
|
||||
mFrequencyCorrectionMixer.inphase(), mFrequencyCorrectionMixer.quadrature());
|
||||
while(iterator.hasNext())
|
||||
{
|
||||
ComplexSamples basebanded = mFrequencyCorrectionMixer.mix(iterator.next());
|
||||
float[] i = mIDecimationFilter.decimate(basebanded.i());
|
||||
float[] q = mQDecimationFilter.decimate(basebanded.q());
|
||||
|
||||
translatedSamples[x + 1] = Complex.multiplyQuadrature(samples[x], samples[x + 1],
|
||||
mFrequencyCorrectionMixer.inphase(), mFrequencyCorrectionMixer.quadrature());
|
||||
List<ComplexSamples> repackaged = mSamplesRepackager.process(i, q);
|
||||
|
||||
for(ComplexSamples samples: repackaged)
|
||||
{
|
||||
mListener.receive(samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDecimationFilter.receive(translatedComplexBuffer);
|
||||
complexBuffer.decrementUserCount();
|
||||
}
|
||||
|
||||
mSampleBuffers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.buffer.NativeBufferPoisonPill;
|
||||
import io.github.dsheirer.dsp.filter.decimate.DecimationFilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.mixer.ComplexMixer;
|
||||
import io.github.dsheirer.dsp.mixer.ComplexMixerFactory;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.util.Dispatcher;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Complex sample source that provides a frequency-translated and decimated sample buffer stream. Uses a
|
||||
* CIC decimation filter that requires the decimation rate to be an integer multiple. Sample buffer processing
|
||||
* occurs on a scheduled runnable thread.
|
||||
*/
|
||||
public class HalfBandTunerChannelSource<T extends INativeBuffer> extends TunerChannelSource implements Listener<T>
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(HalfBandTunerChannelSource.class);
|
||||
|
||||
//Maximum number of filled buffers for the blocking queue
|
||||
private static final int BUFFER_MAX_CAPACITY = 600;
|
||||
|
||||
private Dispatcher<T> mBufferDispatcher;
|
||||
private ComplexMixer mFrequencyCorrectionMixer;
|
||||
private IRealDecimationFilter mIDecimationFilter;
|
||||
private IRealDecimationFilter mQDecimationFilter;
|
||||
private double mChannelSampleRate;
|
||||
private long mChannelFrequencyCorrection = 0;
|
||||
private long mTunerFrequency;
|
||||
private Listener<ComplexSamples> mListener;
|
||||
|
||||
/**
|
||||
* Constructs a frequency translating and CIC decimating channel source.
|
||||
*
|
||||
* @param producerSourceEventListener to receive sample stream start/stop requests
|
||||
* @param tunerChannel that details the desired channel frequency and bandwidth
|
||||
* @param sampleRate of the incoming sample stream
|
||||
* @param channelSpecification for the requested channel.
|
||||
* @throws FilterDesignException if a final cleanup filter cannot be designed using the remez filter
|
||||
* designer and the filter parameters.
|
||||
*/
|
||||
public HalfBandTunerChannelSource(Listener<SourceEvent> producerSourceEventListener, TunerChannel tunerChannel,
|
||||
double sampleRate, ChannelSpecification channelSpecification) throws FilterDesignException
|
||||
{
|
||||
super(producerSourceEventListener, tunerChannel);
|
||||
|
||||
int desiredDecimation = (int)(sampleRate / channelSpecification.getMinimumSampleRate());
|
||||
int decimation = DecimationFilterFactory.getDecimationRate(desiredDecimation);
|
||||
|
||||
mIDecimationFilter = DecimationFilterFactory.getRealDecimationFilter(decimation);
|
||||
mQDecimationFilter = DecimationFilterFactory.getRealDecimationFilter(decimation);
|
||||
|
||||
mBufferDispatcher = new Dispatcher(BUFFER_MAX_CAPACITY, "sdrtrunk heterodyne channel " +
|
||||
tunerChannel.getFrequency(), new NativeBufferPoisonPill());
|
||||
mBufferDispatcher.setListener(new NativeBufferProcessor());
|
||||
|
||||
//Setup the frequency mixer to the current source frequency
|
||||
mChannelSampleRate = sampleRate / (double)decimation;
|
||||
mTunerFrequency = tunerChannel.getFrequency();
|
||||
long frequencyOffset = mTunerFrequency - getTunerChannel().getFrequency();
|
||||
mFrequencyCorrectionMixer = ComplexMixerFactory.getMixer(frequencyOffset, sampleRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
super.start();
|
||||
mBufferDispatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
super.stop();
|
||||
mBufferDispatcher.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary interface for receiving incoming complex sample buffers to be frequency translated and decimated.
|
||||
*/
|
||||
@Override
|
||||
public void receive(T complexSamples)
|
||||
{
|
||||
mBufferDispatcher.receive(complexSamples);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/updates the center frequency for the sample streaming being sent from the producer.
|
||||
*
|
||||
* @param frequency in hertz
|
||||
*/
|
||||
@Override
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mTunerFrequency = frequency;
|
||||
updateMixerFrequencyOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current frequency correction being applied to the channel sample stream
|
||||
*
|
||||
* @return correction in hertz
|
||||
*/
|
||||
public long getFrequencyCorrection()
|
||||
{
|
||||
return mChannelFrequencyCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the frequency correction value and broadcasts the change to the registered downstream listener.
|
||||
*
|
||||
* @param correction current frequency correction value.
|
||||
*/
|
||||
public void setFrequencyCorrection(long correction)
|
||||
{
|
||||
mChannelFrequencyCorrection = correction;
|
||||
updateMixerFrequencyOffset();
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mChannelFrequencyCorrection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the local mixer frequency offset from the tuned frequency,
|
||||
* channel's requested frequency, and channel frequency correction.
|
||||
*/
|
||||
private void updateMixerFrequencyOffset()
|
||||
{
|
||||
long offset = mTunerFrequency - getTunerChannel().getFrequency() - mChannelFrequencyCorrection;
|
||||
mFrequencyCorrectionMixer.setFrequency(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sample rate of the incoming sample stream from the producer
|
||||
*
|
||||
* @param sampleRate in hertz
|
||||
*/
|
||||
@Override
|
||||
protected void setSampleRate(double sampleRate)
|
||||
{
|
||||
//Not implemented. Sample rate changes are not permitted once sample stream starts
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frequency correction for the outbound sample stream to the consumer
|
||||
*
|
||||
* @param correction in hertz
|
||||
*/
|
||||
@Override
|
||||
protected void setChannelFrequencyCorrection(long correction)
|
||||
{
|
||||
mChannelFrequencyCorrection = correction;
|
||||
broadcastConsumerSourceEvent(SourceEvent.channelFrequencyCorrectionChange(correction));
|
||||
updateMixerFrequencyOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency correction value currently being applied to the outbound sample stream
|
||||
*/
|
||||
@Override
|
||||
public long getChannelFrequencyCorrection()
|
||||
{
|
||||
return mChannelFrequencyCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener to receive the complex buffer sample output from this channel
|
||||
*
|
||||
* @param listener to receive complex buffers
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener<ComplexSamples> listener)
|
||||
{
|
||||
if(listener == null)
|
||||
{
|
||||
//Wait for the native buffer processor thread to die before we nullify the listener
|
||||
stop();
|
||||
}
|
||||
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleRate()
|
||||
{
|
||||
return mChannelSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes native buffers received from the dispatcher and sends to the registered listener
|
||||
*/
|
||||
public class NativeBufferProcessor implements Listener<T>
|
||||
{
|
||||
@Override
|
||||
public void receive(T nativeBuffer)
|
||||
{
|
||||
getHeartbeatManager().broadcast();
|
||||
|
||||
Listener<ComplexSamples> listener = mListener;
|
||||
|
||||
if(listener != null)
|
||||
{
|
||||
Iterator<ComplexSamples> iterator = nativeBuffer.iterator();
|
||||
|
||||
while(iterator.hasNext())
|
||||
{
|
||||
ComplexSamples basebanded = mFrequencyCorrectionMixer.mix(iterator.next());
|
||||
float[] i = mIDecimationFilter.decimateReal(basebanded.i());
|
||||
float[] q = mQDecimationFilter.decimateReal(basebanded.q());
|
||||
listener.receive(new ComplexSamples(i, q));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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
|
||||
@@ -15,14 +14,14 @@
|
||||
*
|
||||
* 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.source.tuner.channel;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
@@ -53,7 +52,7 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
|
||||
private List<Long> mLockedFrequencies = new ArrayList<>();
|
||||
private int mFrequencyListPointer = 0;
|
||||
private ChannelSpecification mChannelSpecification;
|
||||
private Listener<ReusableComplexBuffer> mReusableComplexBufferListener;
|
||||
private Listener<ComplexSamples> mComplexSamplesListener;
|
||||
private Listener<Heartbeat> mHeartbeatListener;
|
||||
private String mPreferredTuner;
|
||||
private AtomicBoolean mChangingChannels = new AtomicBoolean();
|
||||
@@ -93,7 +92,7 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
|
||||
{
|
||||
//Shutdown the existing tuner channel source
|
||||
mTunerChannelSource.stop();
|
||||
mTunerChannelSource.removeListener(mReusableComplexBufferListener);
|
||||
mTunerChannelSource.setListener(null);
|
||||
mTunerChannelSource.removeSourceEventListener();
|
||||
mTunerChannelSource.removeHeartbeatListener(mHeartbeatListener);
|
||||
mTunerChannelSource.dispose();
|
||||
@@ -122,7 +121,7 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
|
||||
{
|
||||
mTunerChannelSource = (TunerChannelSource)source;
|
||||
mTunerChannelSource.setSourceEventListener(mConsumerSourceEventAdapter);
|
||||
mTunerChannelSource.setListener(mReusableComplexBufferListener);
|
||||
mTunerChannelSource.setListener(mComplexSamplesListener);
|
||||
mTunerChannelSource.addHeartbeatListener(mHeartbeatListener);
|
||||
mTunerChannelSource.start();
|
||||
mTunerChannel = nextChannel;
|
||||
@@ -295,36 +294,16 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSamples()
|
||||
public void setListener(Listener<ComplexSamples> complexSamplesListener)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.processSamples();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ReusableComplexBuffer> complexBufferListener)
|
||||
{
|
||||
mReusableComplexBufferListener = complexBufferListener;
|
||||
mComplexSamplesListener = complexSamplesListener;
|
||||
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.setListener(complexBufferListener);
|
||||
mTunerChannelSource.setListener(complexSamplesListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ReusableComplexBuffer> listener)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.removeListener(listener);
|
||||
}
|
||||
|
||||
mReusableComplexBufferListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleRate()
|
||||
{
|
||||
|
||||
@@ -1,46 +1,48 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.buffer.NativeBufferPoisonPill;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
import io.github.dsheirer.source.ISourceEventListener;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.util.Dispatcher;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Pass-through channel source that simply passes complex sample buffers from the tuner controller
|
||||
* directly to the registered listener
|
||||
*/
|
||||
public class PassThroughChannelSource extends TunerChannelSource implements ISourceEventListener,
|
||||
Listener<ReusableComplexBuffer>
|
||||
Listener<INativeBuffer>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PassThroughChannelSource.class);
|
||||
private TunerController mTunerController;
|
||||
private OverflowableReusableBufferTransferQueue<ReusableComplexBuffer> mBufferQueue =
|
||||
new OverflowableReusableBufferTransferQueue<>(500, 100);
|
||||
private List<ReusableComplexBuffer> mBuffersToProcess = new ArrayList<>();
|
||||
private Listener<ReusableComplexBuffer> mComplexBufferListener;
|
||||
private Dispatcher<INativeBuffer> mBufferDispatcher;
|
||||
private Listener<ComplexSamples> mComplexSamplesListener;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
@@ -54,6 +56,23 @@ public class PassThroughChannelSource extends TunerChannelSource implements ISou
|
||||
{
|
||||
super(listener, tunerChannel);
|
||||
mTunerController = tunerController;
|
||||
mBufferDispatcher = new Dispatcher<>(500, "sdrtrunk pass-through channel " +
|
||||
tunerChannel.getFrequency(), new NativeBufferPoisonPill());
|
||||
mBufferDispatcher.setListener(new BufferProcessor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
super.start();
|
||||
mBufferDispatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
super.stop();
|
||||
mBufferDispatcher.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,35 +100,9 @@ public class PassThroughChannelSource extends TunerChannelSource implements ISou
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ReusableComplexBuffer> complexBufferListener)
|
||||
public void setListener(Listener<ComplexSamples> complexSamplesListener)
|
||||
{
|
||||
mComplexBufferListener = complexBufferListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ReusableComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSamples()
|
||||
{
|
||||
mBufferQueue.drainTo(mBuffersToProcess);
|
||||
|
||||
for(ReusableComplexBuffer buffer: mBuffersToProcess)
|
||||
{
|
||||
if(mComplexBufferListener != null)
|
||||
{
|
||||
mComplexBufferListener.receive(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
mBuffersToProcess.clear();
|
||||
mComplexSamplesListener = complexSamplesListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,8 +112,27 @@ public class PassThroughChannelSource extends TunerChannelSource implements ISou
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||
public void receive(INativeBuffer buffer)
|
||||
{
|
||||
mBufferQueue.offer(reusableComplexBuffer);
|
||||
mBufferDispatcher.receive(buffer);
|
||||
}
|
||||
|
||||
public class BufferProcessor implements Listener<INativeBuffer>
|
||||
{
|
||||
@Override
|
||||
public void receive(INativeBuffer nativeBuffer)
|
||||
{
|
||||
getHeartbeatManager().broadcast();
|
||||
|
||||
if(mComplexSamplesListener != null)
|
||||
{
|
||||
Iterator<ComplexSamples> iterator = nativeBuffer.iterator();
|
||||
|
||||
while(iterator.hasNext())
|
||||
{
|
||||
mComplexSamplesListener.receive(iterator.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,33 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
import io.github.dsheirer.source.ComplexSource;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceEventListenerToProcessorAdapter;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class TunerChannelSource extends ComplexSource implements ISourceEventProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class);
|
||||
@@ -43,7 +36,7 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
protected TunerChannel mTunerChannel;
|
||||
private Listener<SourceEvent> mProducerSourceEventListener;
|
||||
private Listener<SourceEvent> mConsumerSourceEventListener;
|
||||
private ScheduledIntervalProcessor mScheduledIntervalProcessor = new ScheduledIntervalProcessor();
|
||||
// private ScheduledIntervalProcessor mScheduledIntervalProcessor = new ScheduledIntervalProcessor();
|
||||
|
||||
/**
|
||||
* Tuner Channel Source is a Digital Drop Channel (DDC) abstract class that defines the minimum functionality
|
||||
@@ -99,15 +92,15 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
|
||||
/**
|
||||
* Sets the listener to receive the complex buffer sample output from this channel
|
||||
* @param complexBufferListener to receive complex buffers
|
||||
* @param complexSamplesListener to receive complex buffers
|
||||
*/
|
||||
public abstract void setListener(Listener<ReusableComplexBuffer> complexBufferListener);
|
||||
public abstract void setListener(Listener<ComplexSamples> complexSamplesListener);
|
||||
|
||||
/**
|
||||
* Commands sub-class to process queued samples and distribute them to the consumer. This method will be invoked
|
||||
* by an interval timer.
|
||||
*/
|
||||
protected abstract void processSamples();
|
||||
// protected abstract void processSamples();
|
||||
|
||||
/**
|
||||
* Tuner channel for this tuner channel source
|
||||
@@ -125,7 +118,6 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
//Broadcast current frequency and sample rate so consumer can configure correctly
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyChange(this, getFrequency(), "Startup"));
|
||||
broadcastProducerSourceEvent(SourceEvent.startSampleStreamRequest(this));
|
||||
mScheduledIntervalProcessor.start();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +128,6 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
{
|
||||
broadcastProducerSourceEvent(SourceEvent.stopSampleStreamRequest(this));
|
||||
broadcastProducerSourceEvent(SourceEvent.sourceDisposeRequest(this));
|
||||
mScheduledIntervalProcessor.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -261,94 +252,94 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
mConsumerSourceEventListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processor to periodically invoke buffer sample processing on an interval timer. At each interval this processor
|
||||
* sends a heartbeat to the registered consumer and then commands the sub-class implementation to process any
|
||||
* queued buffers and distribute complex buffer sample(s) to the registered consumer.
|
||||
*/
|
||||
public class ScheduledIntervalProcessor implements Runnable
|
||||
{
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
private boolean mStopped = false;
|
||||
|
||||
/**
|
||||
* Commands this processor to do a shutdown at the end of this or the next iteration. Once successfully
|
||||
* shutdown, it will invoke the performDisposal() method to cleanup this instance.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
mStopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts buffer processing on a fixed interval using a scheduled thread pool
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
if(mScheduledFuture == null)
|
||||
{
|
||||
mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(this, 0,
|
||||
BUFFER_PROCESSOR_RUN_INTERVAL_MILLISECONDS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the Runnable interface to periodically send a heartbeat and then process buffer samples.
|
||||
*/
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!mStopped)
|
||||
{
|
||||
try
|
||||
{
|
||||
getHeartbeatManager().broadcast();
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
mLog.error("Error while sending heartbeat", t);
|
||||
}
|
||||
}
|
||||
|
||||
if(!mStopped)
|
||||
{
|
||||
try
|
||||
{
|
||||
processSamples();
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
mLog.error("Error while processing samples", t);
|
||||
}
|
||||
}
|
||||
|
||||
if(mStopped)
|
||||
{
|
||||
if(mScheduledFuture != null)
|
||||
{
|
||||
//Set may-interrupt to false so that we can complete this iteration
|
||||
mScheduledFuture.cancel(false);
|
||||
}
|
||||
|
||||
mScheduledFuture = null;
|
||||
|
||||
try
|
||||
{
|
||||
getHeartbeatManager().broadcast();
|
||||
performDisposal();
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
mLog.error("Error during final shutdown processing of samples", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
mLog.error("Error during heartbeat processing", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * Processor to periodically invoke buffer sample processing on an interval timer. At each interval this processor
|
||||
// * sends a heartbeat to the registered consumer and then commands the sub-class implementation to process any
|
||||
// * queued buffers and distribute complex buffer sample(s) to the registered consumer.
|
||||
// */
|
||||
// public class ScheduledIntervalProcessor implements Runnable
|
||||
// {
|
||||
// private ScheduledFuture<?> mScheduledFuture;
|
||||
// private boolean mStopped = false;
|
||||
//
|
||||
// /**
|
||||
// * Commands this processor to do a shutdown at the end of this or the next iteration. Once successfully
|
||||
// * shutdown, it will invoke the performDisposal() method to cleanup this instance.
|
||||
// */
|
||||
// public void stop()
|
||||
// {
|
||||
// mStopped = true;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Starts buffer processing on a fixed interval using a scheduled thread pool
|
||||
// */
|
||||
// public void start()
|
||||
// {
|
||||
// if(mScheduledFuture == null)
|
||||
// {
|
||||
// mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(this, 0,
|
||||
// BUFFER_PROCESSOR_RUN_INTERVAL_MILLISECONDS, TimeUnit.MILLISECONDS);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Implementation of the Runnable interface to periodically send a heartbeat and then process buffer samples.
|
||||
// */
|
||||
// @Override
|
||||
// public void run()
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// if(!mStopped)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// getHeartbeatManager().broadcast();
|
||||
// }
|
||||
// catch(Throwable t)
|
||||
// {
|
||||
// mLog.error("Error while sending heartbeat", t);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(!mStopped)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// processSamples();
|
||||
// }
|
||||
// catch(Throwable t)
|
||||
// {
|
||||
// mLog.error("Error while processing samples", t);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(mStopped)
|
||||
// {
|
||||
// if(mScheduledFuture != null)
|
||||
// {
|
||||
// //Set may-interrupt to false so that we can complete this iteration
|
||||
// mScheduledFuture.cancel(false);
|
||||
// }
|
||||
//
|
||||
// mScheduledFuture = null;
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// getHeartbeatManager().broadcast();
|
||||
// performDisposal();
|
||||
// }
|
||||
// catch(Throwable t)
|
||||
// {
|
||||
// mLog.error("Error during final shutdown processing of samples", t);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch(Throwable t)
|
||||
// {
|
||||
// mLog.error("Error during heartbeat processing", t);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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
|
||||
@@ -14,13 +14,13 @@
|
||||
*
|
||||
* 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.source.tuner.fcd;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ComplexShortAdapter;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.mixer.ComplexMixer;
|
||||
import io.github.dsheirer.source.tuner.MixerTunerType;
|
||||
@@ -90,11 +90,11 @@ public abstract class FCDTunerController extends TunerController
|
||||
}
|
||||
|
||||
mComplexMixer = new ComplexMixer( mixerTDL, tunerType.getAudioFormat(), tunerType.getDisplayString(),
|
||||
new ComplexShortAdapter(tunerType.getDisplayString()));
|
||||
new ComplexShortAdapter());
|
||||
|
||||
mComplexMixer.setBufferSize(tunerType.getAudioFormat().getFrameSize() * getBufferSampleCount());
|
||||
|
||||
mComplexMixer.setBufferListener(mReusableBufferBroadcaster);
|
||||
mComplexMixer.setBufferListener(mNativeBufferBroadcaster);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,7 +107,7 @@ public abstract class FCDTunerController extends TunerController
|
||||
* Overrides the super class functionality to auto-start the complex mixer and provide samples to listeners
|
||||
*/
|
||||
@Override
|
||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
boolean hasExistingListeners = hasBufferListeners();
|
||||
|
||||
@@ -124,7 +124,7 @@ public abstract class FCDTunerController extends TunerController
|
||||
* more registered listeners
|
||||
*/
|
||||
@Override
|
||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
super.removeBufferListener(listener);
|
||||
|
||||
|
||||
@@ -1,32 +1,28 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.hackrf;
|
||||
|
||||
import io.github.dsheirer.buffer.SignedByteNativeBufferFactory;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.SignedByteSampleConverter;
|
||||
import org.apache.commons.io.EndianUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -61,7 +57,7 @@ public class HackRFTunerController extends USBTunerController
|
||||
public static final double USABLE_BANDWIDTH_PERCENT = 0.90;
|
||||
public static final int DC_SPIKE_AVOID_BUFFER = 5000;
|
||||
|
||||
private NativeBufferConverter mNativeBufferConverter = new SignedByteSampleConverter();
|
||||
private SignedByteNativeBufferFactory mNativeBufferFactory = new SignedByteNativeBufferFactory();
|
||||
private USBTransferProcessor mUSBTransferProcessor;
|
||||
|
||||
private HackRFSampleRate mSampleRate = HackRFSampleRate.RATE_5_0;
|
||||
@@ -131,7 +127,7 @@ public class HackRFTunerController extends USBTunerController
|
||||
name = "HackRF - Unidentified Serial";
|
||||
}
|
||||
|
||||
mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mNativeBufferConverter,
|
||||
mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mNativeBufferFactory,
|
||||
USB_TRANSFER_BUFFER_SIZE, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.buffer.NativeSampleDelayBuffer;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexDelayBuffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.channel.CICTunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
import io.github.dsheirer.source.tuner.channel.HalfBandTunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import org.slf4j.Logger;
|
||||
@@ -48,11 +45,12 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
|
||||
private final static int DELAY_BUFFER_DURATION_MILLISECONDS = 2000;
|
||||
|
||||
private List<CICTunerChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
||||
// private List<CICTunerChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
||||
private List<HalfBandTunerChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
||||
private SortedSet<TunerChannel> mTunerChannels = new TreeSet<>();
|
||||
private TunerController mTunerController;
|
||||
private ChannelSourceEventProcessor mChannelSourceEventProcessor = new ChannelSourceEventProcessor();
|
||||
private ReusableComplexDelayBuffer mSampleDelayBuffer;
|
||||
private NativeSampleDelayBuffer mSampleDelayBuffer;
|
||||
|
||||
public HeterodyneChannelSourceManager(TunerController tunerController)
|
||||
{
|
||||
@@ -80,8 +78,11 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
try
|
||||
{
|
||||
//Attempt to create the channel source first, in case we get a filter design exception
|
||||
CICTunerChannelSource tunerChannelSource = new CICTunerChannelSource(mChannelSourceEventProcessor,
|
||||
tunerChannel, mTunerController.getSampleRate(), channelSpecification);
|
||||
// CICTunerChannelSource tunerChannelSource = new CICTunerChannelSource(mChannelSourceEventProcessor,
|
||||
// tunerChannel, mTunerController.getSampleRate(), channelSpecification);
|
||||
|
||||
HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
|
||||
tunerChannel, mTunerController.getSampleRate(), channelSpecification);
|
||||
|
||||
//Add to the list of channel sources so that it will receive the tuner frequency change
|
||||
mChannelSources.add(tunerChannelSource);
|
||||
@@ -181,7 +182,8 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
*/
|
||||
private void broadcastToChannels(SourceEvent sourceEvent)
|
||||
{
|
||||
for(CICTunerChannelSource channelSource : mChannelSources)
|
||||
// for(CICTunerChannelSource channelSource : mChannelSources)
|
||||
for(HalfBandTunerChannelSource channelSource : mChannelSources)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -201,7 +203,8 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
*/
|
||||
private void updateTunerFrequency(long tunerFrequency)
|
||||
{
|
||||
for(CICTunerChannelSource channelSource : mChannelSources)
|
||||
// for(CICTunerChannelSource channelSource : mChannelSources)
|
||||
for(HalfBandTunerChannelSource channelSource : mChannelSources)
|
||||
{
|
||||
channelSource.setFrequency(tunerFrequency);
|
||||
}
|
||||
@@ -216,19 +219,13 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
if(mSampleDelayBuffer == null)
|
||||
{
|
||||
int delayBufferSize = (int)(DELAY_BUFFER_DURATION_MILLISECONDS / mTunerController.getBufferDuration());
|
||||
mSampleDelayBuffer = new ReusableComplexDelayBuffer(delayBufferSize, mTunerController.getBufferDuration());
|
||||
|
||||
mLog.debug("Created/registered complex sample delay buffer of size [" + delayBufferSize +
|
||||
"] buffers and delay duration [" + DELAY_BUFFER_DURATION_MILLISECONDS +
|
||||
"ms] for tuner controller [" + mTunerController.getClass().getName() +
|
||||
"] with buffer duration [" + mTunerController.getBufferDuration() + "]");
|
||||
|
||||
mSampleDelayBuffer = new NativeSampleDelayBuffer(delayBufferSize, mTunerController.getBufferDuration());
|
||||
mTunerController.addBufferListener(mSampleDelayBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregisters the complex sample delay buffer and disposes of any queued reusable buffers.
|
||||
* De-registers the complex sample delay buffer and disposes of any queued reusable buffers.
|
||||
*/
|
||||
private void stopDelayBuffer()
|
||||
{
|
||||
@@ -251,28 +248,32 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
switch(sourceEvent.getEvent())
|
||||
{
|
||||
case REQUEST_START_SAMPLE_STREAM:
|
||||
if(sourceEvent.getSource() instanceof CICTunerChannelSource)
|
||||
if(sourceEvent.getSource() instanceof HalfBandTunerChannelSource)
|
||||
{
|
||||
startDelayBuffer();
|
||||
|
||||
//The start sample stream request contains a start timestamp and the delay buffer
|
||||
//will preload the channel with delayed sample buffers that either contain the
|
||||
//timestamp or occur later/newer than the timestamp.
|
||||
mSampleDelayBuffer.addListener((CICTunerChannelSource)sourceEvent.getSource(),
|
||||
sourceEvent.getValue().longValue());
|
||||
// mSampleDelayBuffer.addListener((CICTunerChannelSource)sourceEvent.getSource(),
|
||||
// sourceEvent.getValue().longValue());
|
||||
mSampleDelayBuffer.addListener((HalfBandTunerChannelSource)sourceEvent.getSource(),
|
||||
sourceEvent.getValue().longValue());
|
||||
}
|
||||
break;
|
||||
case REQUEST_STOP_SAMPLE_STREAM:
|
||||
if(sourceEvent.getSource() instanceof CICTunerChannelSource)
|
||||
if(sourceEvent.getSource() instanceof HalfBandTunerChannelSource)
|
||||
{
|
||||
mSampleDelayBuffer.removeListener((CICTunerChannelSource)sourceEvent.getSource());
|
||||
// mSampleDelayBuffer.removeListener((CICTunerChannelSource)sourceEvent.getSource());
|
||||
mSampleDelayBuffer.removeListener((HalfBandTunerChannelSource)sourceEvent.getSource());
|
||||
stopDelayBuffer();
|
||||
}
|
||||
break;
|
||||
case REQUEST_SOURCE_DISPOSE:
|
||||
if(sourceEvent.getSource() instanceof CICTunerChannelSource)
|
||||
if(sourceEvent.getSource() instanceof HalfBandTunerChannelSource)
|
||||
{
|
||||
CICTunerChannelSource channelSource = (CICTunerChannelSource)sourceEvent.getSource();
|
||||
// CICTunerChannelSource channelSource = (CICTunerChannelSource)sourceEvent.getSource();
|
||||
HalfBandTunerChannelSource channelSource = (HalfBandTunerChannelSource) sourceEvent.getSource();
|
||||
mChannelSources.remove(channelSource);
|
||||
mTunerChannels.remove(channelSource.getTunerChannel());
|
||||
channelSource.dispose();
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.manager;
|
||||
|
||||
@@ -405,6 +402,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
|
||||
* Allocates a tuner channel source for the tuner channel.
|
||||
*
|
||||
* @param tunerChannel for requested source
|
||||
* @param channelSpecification for the requested channel
|
||||
* @return allocated DDC tuner channel source, or null if the channel cannot be provided by this source manager
|
||||
*/
|
||||
@Override
|
||||
@@ -434,7 +432,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
|
||||
}
|
||||
|
||||
//If we're successful to here, allocate the channel
|
||||
return mPolyphaseChannelManager.getChannel(tunerChannel, channelSpecification);
|
||||
return mPolyphaseChannelManager.getChannel(tunerChannel);
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.recording;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
@@ -73,15 +70,7 @@ public class RecordingTunerController extends TunerController
|
||||
}
|
||||
|
||||
mComplexWaveSource = new ComplexWaveSource(new File(recordingPath), true);
|
||||
mComplexWaveSource.setListener(new Listener<ReusableComplexBuffer>()
|
||||
{
|
||||
@Override
|
||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||
{
|
||||
//Send to parent class to broadcast to listeners
|
||||
broadcast(reusableComplexBuffer);
|
||||
}
|
||||
});
|
||||
mComplexWaveSource.setListener(complexSamples -> broadcast(complexSamples));
|
||||
|
||||
try
|
||||
{
|
||||
@@ -135,7 +124,7 @@ public class RecordingTunerController extends TunerController
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
super.addBufferListener(listener);
|
||||
|
||||
@@ -150,13 +139,13 @@ public class RecordingTunerController extends TunerController
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
super.removeBufferListener(listener);
|
||||
|
||||
if(!mReusableBufferBroadcaster.hasListeners() && mComplexWaveSource != null)
|
||||
if(!mNativeBufferBroadcaster.hasListeners() && mComplexWaveSource != null)
|
||||
{
|
||||
mComplexWaveSource.setListener((Listener<ReusableComplexBuffer>)null);
|
||||
mComplexWaveSource.setListener((Listener<INativeBuffer>)null);
|
||||
mComplexWaveSource.stop();
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
@@ -1,36 +1,32 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.rtl;
|
||||
|
||||
import io.github.dsheirer.buffer.ByteNativeBufferFactory;
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.ITunerErrorListener;
|
||||
import io.github.dsheirer.source.tuner.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.ByteSampleConverter;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.Device;
|
||||
@@ -79,7 +75,7 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
|
||||
private SampleRate mSampleRate = DEFAULT_SAMPLE_RATE;
|
||||
|
||||
protected NativeBufferConverter mNativeBufferConverter = new ByteSampleConverter();
|
||||
protected ByteNativeBufferFactory mNativeBufferFactory = new ByteNativeBufferFactory();
|
||||
protected int mOscillatorFrequency = 28800000; //28.8 MHz
|
||||
protected USBTransferProcessor mUSBTransferProcessor;
|
||||
protected Descriptor mDescriptor;
|
||||
@@ -162,7 +158,7 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
|
||||
String deviceName = getTunerType().getLabel() + " " + getUniqueID();
|
||||
|
||||
mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferConverter,
|
||||
mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferFactory,
|
||||
USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE, this);
|
||||
}
|
||||
|
||||
@@ -1526,7 +1522,7 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
* Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started.
|
||||
*/
|
||||
@Override
|
||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
boolean hasExistingListeners = hasBufferListeners();
|
||||
|
||||
@@ -1542,7 +1538,7 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
* Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners.
|
||||
*/
|
||||
@Override
|
||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
super.removeBufferListener(listener);
|
||||
|
||||
@@ -1564,15 +1560,15 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
*
|
||||
* @param deviceName to use when logging information or errors
|
||||
* @param deviceHandle to the USB bulk transfer device
|
||||
* @param nativeBufferConverter specific to the tuner's byte buffer format for converting to floating point I/Q samples
|
||||
* @param nativeBufferFactory specific to the tuner's byte buffer format for converting to floating point I/Q samples
|
||||
* @param bufferSize in bytes. Should be a multiple of two: 65536, 131072 or 262144.
|
||||
* @param tunerErrorListener to receive error state message
|
||||
*/
|
||||
public RTL2832USBTransferProcessor(String deviceName, DeviceHandle deviceHandle,
|
||||
NativeBufferConverter nativeBufferConverter, int bufferSize,
|
||||
ByteNativeBufferFactory nativeBufferFactory, int bufferSize,
|
||||
ITunerErrorListener tunerErrorListener)
|
||||
{
|
||||
super(deviceName, deviceHandle, nativeBufferConverter, bufferSize, tunerErrorListener);
|
||||
super(deviceName, deviceHandle, nativeBufferFactory, bufferSize, tunerErrorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.rtl.e4k;
|
||||
|
||||
@@ -256,7 +253,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
|
||||
String deviceName = getTunerType().getLabel() + " " + getUniqueID();
|
||||
|
||||
mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferConverter,
|
||||
mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferFactory,
|
||||
USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.tuner.test;
|
||||
|
||||
import io.github.dsheirer.dsp.mixer.IOscillator;
|
||||
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||
import io.github.dsheirer.buffer.FloatNativeBuffer;
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.dsp.oscillator.IComplexOscillator;
|
||||
import io.github.dsheirer.dsp.oscillator.OscillatorFactory;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.slf4j.Logger;
|
||||
@@ -33,12 +36,11 @@ public class SampleGenerator
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(SampleGenerator.class);
|
||||
|
||||
private ReusableBufferBroadcaster mComplexBufferBroadcaster = new ReusableBufferBroadcaster();
|
||||
private IOscillator mOscillator;
|
||||
private Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster<>();
|
||||
private IComplexOscillator mComplexOscillator;
|
||||
private int mSweepUpdateInterval;
|
||||
private long mInterval;
|
||||
private int mSamplesPerInterval;
|
||||
private boolean mReuseBuffers;
|
||||
private int mSamplesPerInterval = 65536;
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
|
||||
/**
|
||||
@@ -48,22 +50,20 @@ public class SampleGenerator
|
||||
*
|
||||
* @param sampleRate of the complex samples
|
||||
* @param frequency of the tone produced by the generator
|
||||
* @param interval in milliseconds for generating samples
|
||||
* @param sweepUpdateRate to turn on sweeping of the tone frequency where the frequency is incremented by the
|
||||
* rate specified at each interval, resetting to 1 Hz after reaching/exceeding the highest frequency.
|
||||
*/
|
||||
public SampleGenerator(int sampleRate, long frequency, long interval, int sweepUpdateRate)
|
||||
public SampleGenerator(int sampleRate, long frequency, int sweepUpdateRate)
|
||||
{
|
||||
if(FastMath.abs(sweepUpdateRate) >= sampleRate)
|
||||
{
|
||||
throw new IllegalArgumentException("Sweep update rate cannot be greater than sample rate");
|
||||
}
|
||||
|
||||
mOscillator = new LowPhaseNoiseOscillator(frequency, sampleRate);
|
||||
mInterval = interval;
|
||||
mSweepUpdateInterval = sweepUpdateRate;
|
||||
mComplexOscillator = OscillatorFactory.getComplexOscillator(frequency, sampleRate);
|
||||
|
||||
updateSamplesPerInterval();
|
||||
mInterval = 1000 / (sampleRate / mSamplesPerInterval);
|
||||
mSweepUpdateInterval = sweepUpdateRate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,19 +73,10 @@ public class SampleGenerator
|
||||
*
|
||||
* @param sampleRate of the complex samples
|
||||
* @param frequency of the tone produced by the generator
|
||||
* @param interval in milliseconds for generating samples
|
||||
*/
|
||||
public SampleGenerator(int sampleRate, long frequency, long interval)
|
||||
public SampleGenerator(int sampleRate, long frequency)
|
||||
{
|
||||
this(sampleRate, frequency, interval, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the number of complex samples generated per interval
|
||||
*/
|
||||
private void updateSamplesPerInterval()
|
||||
{
|
||||
mSamplesPerInterval = (int)((double)mOscillator.getSampleRate() * ((double)mInterval / 1000.0));
|
||||
this(sampleRate, frequency, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,11 +116,11 @@ public class SampleGenerator
|
||||
*
|
||||
* @param listener to receive complex sample buffers
|
||||
*/
|
||||
public void addListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mComplexBufferBroadcaster.addListener(listener);
|
||||
mNativeBufferBroadcaster.addListener(listener);
|
||||
|
||||
if(mComplexBufferBroadcaster.getListenerCount() == 1)
|
||||
if(mNativeBufferBroadcaster.getListenerCount() == 1)
|
||||
{
|
||||
start();
|
||||
}
|
||||
@@ -138,11 +129,11 @@ public class SampleGenerator
|
||||
/**
|
||||
* Removes the listener and stops the sample generator if there are no more listeners.
|
||||
*/
|
||||
public void removeListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mComplexBufferBroadcaster.removeListener(listener);
|
||||
mNativeBufferBroadcaster.removeListener(listener);
|
||||
|
||||
if(mComplexBufferBroadcaster.getListenerCount() == 0)
|
||||
if(mNativeBufferBroadcaster.getListenerCount() == 0)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
@@ -154,7 +145,7 @@ public class SampleGenerator
|
||||
*/
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
mOscillator.setFrequency(frequency);
|
||||
mComplexOscillator.setFrequency(frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +153,7 @@ public class SampleGenerator
|
||||
*/
|
||||
public long getFrequency()
|
||||
{
|
||||
return (long)mOscillator.getFrequency();
|
||||
return (long) mComplexOscillator.getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,13 +162,13 @@ public class SampleGenerator
|
||||
*/
|
||||
public void setSampleRate(int sampleRate)
|
||||
{
|
||||
mOscillator.setSampleRate(sampleRate);
|
||||
updateSamplesPerInterval();
|
||||
mComplexOscillator.setSampleRate(sampleRate);
|
||||
mInterval = 1000 / (sampleRate / mSamplesPerInterval);
|
||||
}
|
||||
|
||||
public double getSampleRate()
|
||||
{
|
||||
return mOscillator.getSampleRate();
|
||||
return mComplexOscillator.getSampleRate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,44 +177,52 @@ public class SampleGenerator
|
||||
public class Generator implements Runnable
|
||||
{
|
||||
private int mTriggerInterval = 0;
|
||||
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("SampleGenerator");
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if(mComplexBufferBroadcaster.hasListeners())
|
||||
try
|
||||
{
|
||||
ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mSamplesPerInterval);
|
||||
|
||||
mOscillator.generateComplex(reusableComplexBuffer);
|
||||
|
||||
mComplexBufferBroadcaster.broadcast(reusableComplexBuffer);
|
||||
|
||||
if(mSweepUpdateInterval != 0)
|
||||
if(mNativeBufferBroadcaster.hasListeners())
|
||||
{
|
||||
mTriggerInterval++;
|
||||
float[] samples = mComplexOscillator.generate(mSamplesPerInterval);
|
||||
|
||||
if(mTriggerInterval >= 10)
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
FloatNativeBuffer buffer = new FloatNativeBuffer(samples, now);
|
||||
|
||||
mNativeBufferBroadcaster.broadcast(buffer);
|
||||
|
||||
if(mSweepUpdateInterval != 0)
|
||||
{
|
||||
mTriggerInterval = 0;
|
||||
mTriggerInterval++;
|
||||
|
||||
long updatedFrequency = (long)mOscillator.getFrequency() + mSweepUpdateInterval;
|
||||
if(mTriggerInterval >= 10)
|
||||
{
|
||||
mTriggerInterval = 0;
|
||||
|
||||
if(updatedFrequency > mOscillator.getSampleRate() / 2)
|
||||
{
|
||||
mOscillator.setFrequency(mOscillator.getSampleRate() / -2);
|
||||
}
|
||||
else if(updatedFrequency < mOscillator.getSampleRate() / -2)
|
||||
{
|
||||
mOscillator.setFrequency(mOscillator.getSampleRate() / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
mOscillator.setFrequency(updatedFrequency);
|
||||
long updatedFrequency = (long) mComplexOscillator.getFrequency() + mSweepUpdateInterval;
|
||||
|
||||
if(updatedFrequency > mComplexOscillator.getSampleRate() / 2)
|
||||
{
|
||||
mComplexOscillator.setFrequency(mComplexOscillator.getSampleRate() / -2);
|
||||
}
|
||||
else if(updatedFrequency < mComplexOscillator.getSampleRate() / -2)
|
||||
{
|
||||
mComplexOscillator.setFrequency(mComplexOscillator.getSampleRate() / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
mComplexOscillator.setFrequency(updatedFrequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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
|
||||
@@ -14,12 +14,12 @@
|
||||
*
|
||||
* 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.source.tuner.test;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
@@ -32,7 +32,7 @@ public class TestTunerController extends TunerController
|
||||
|
||||
public static final long MINIMUM_FREQUENCY = 1l;
|
||||
public static final long MAXIMUM_FREQUENCY = 1000000000l;
|
||||
public static final int SAMPLE_RATE = 10000000;
|
||||
public static final int SAMPLE_RATE = 2_400_000;
|
||||
public static final int DC_NOISE_BANDWIDTH = 0;
|
||||
public static final double USABLE_BANDWIDTH_PERCENTAGE = 1.00;
|
||||
|
||||
@@ -50,9 +50,9 @@ public class TestTunerController extends TunerController
|
||||
super(MINIMUM_FREQUENCY, MAXIMUM_FREQUENCY, DC_NOISE_BANDWIDTH, USABLE_BANDWIDTH_PERCENTAGE);
|
||||
|
||||
int sweepRate = 0; //Hz per interval
|
||||
long initialToneFrequency = SAMPLE_RATE / 2 + 100;
|
||||
mSampleGenerator = new SampleGenerator(SAMPLE_RATE, initialToneFrequency, SAMPLE_GENERATION_INTERVAL,
|
||||
sweepRate);
|
||||
// long initialToneFrequency = SAMPLE_RATE / 2 + 100;
|
||||
long initialToneFrequency = 50000;
|
||||
mSampleGenerator = new SampleGenerator(SAMPLE_RATE, initialToneFrequency, sweepRate);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -78,13 +78,13 @@ public class TestTunerController extends TunerController
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mSampleGenerator.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mSampleGenerator.removeListener(listener);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.usb;
|
||||
|
||||
@@ -86,18 +83,8 @@ public class USBMasterProcessor
|
||||
{
|
||||
mProcessor.reset();
|
||||
mProcessorThread = new Thread(mProcessor);
|
||||
mProcessorThread.setName("USB Event Processor");
|
||||
mProcessorThread.setDaemon(true);
|
||||
|
||||
try
|
||||
{
|
||||
mProcessorThread.setPriority(Thread.MAX_PRIORITY);
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
{
|
||||
//Do nothing ... couldn't set the priority
|
||||
}
|
||||
|
||||
mProcessorThread.setName("sdrtrunk USB event processor");
|
||||
mProcessorThread.setPriority(Thread.MAX_PRIORITY);
|
||||
mProcessorThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,28 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.tuner.usb;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.buffer.INativeBufferFactory;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.tuner.ITunerErrorListener;
|
||||
import io.github.dsheirer.source.tuner.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -59,13 +56,13 @@ public class USBTransferProcessor implements TransferCallback
|
||||
private List<Transfer> mTransfersToDispose = new ArrayList<>();
|
||||
private List<Transfer> mTransfersToSubmit = new ArrayList<>();
|
||||
|
||||
//Tuner format-specific byte buffer to IQ float sample converter
|
||||
private NativeBufferConverter mNativeBufferConverter;
|
||||
//Tuner specific native buffer factory for processing/conversion of raw samples
|
||||
private INativeBufferFactory mNativeBufferFactory;
|
||||
|
||||
//Byte array transfer buffers size in bytes
|
||||
private int mBufferSize;
|
||||
|
||||
private Listener<ReusableComplexBuffer> mComplexBufferListener;
|
||||
private Listener<INativeBuffer> mNativeBufferListener;
|
||||
|
||||
//Handle to the USB bulk transfer device
|
||||
private DeviceHandle mUsbBulkTransferDeviceHandle;
|
||||
@@ -84,16 +81,16 @@ public class USBTransferProcessor implements TransferCallback
|
||||
*
|
||||
* @param deviceName to use when logging information or errors
|
||||
* @param usbBulkTransferDeviceHandle to the USB bulk transfer device
|
||||
* @param nativeBufferConverter specific to the tuner's byte buffer format for converting to floating point I/Q samples
|
||||
* @param nativeBufferFactory specific to the tuner's byte buffer format for converting to floating point I/Q samples
|
||||
* @param bufferSize in bytes. Should be a multiple of two: 65536, 131072 or 262144.
|
||||
*/
|
||||
public USBTransferProcessor(String deviceName, DeviceHandle usbBulkTransferDeviceHandle,
|
||||
NativeBufferConverter nativeBufferConverter, int bufferSize,
|
||||
INativeBufferFactory nativeBufferFactory, int bufferSize,
|
||||
ITunerErrorListener tunerErrorListener)
|
||||
{
|
||||
mDeviceName = deviceName;
|
||||
mUsbBulkTransferDeviceHandle = usbBulkTransferDeviceHandle;
|
||||
mNativeBufferConverter = nativeBufferConverter;
|
||||
mNativeBufferFactory = nativeBufferFactory;
|
||||
mBufferSize = bufferSize;
|
||||
mITunerErrorListener = tunerErrorListener;
|
||||
}
|
||||
@@ -358,11 +355,11 @@ public class USBTransferProcessor implements TransferCallback
|
||||
/**
|
||||
* Sets the listener and auto-starts the buffer processor
|
||||
*/
|
||||
public void setListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void setListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
if(mComplexBufferListener == null || !mComplexBufferListener.equals(listener))
|
||||
if(mNativeBufferListener == null || !mNativeBufferListener.equals(listener))
|
||||
{
|
||||
mComplexBufferListener = listener;
|
||||
mNativeBufferListener = listener;
|
||||
|
||||
boolean success = start();
|
||||
|
||||
@@ -378,10 +375,10 @@ public class USBTransferProcessor implements TransferCallback
|
||||
*/
|
||||
public void removeListener()
|
||||
{
|
||||
if(mComplexBufferListener != null)
|
||||
if(mNativeBufferListener != null)
|
||||
{
|
||||
stop();
|
||||
mComplexBufferListener = null;
|
||||
mNativeBufferListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,14 +552,13 @@ public class USBTransferProcessor implements TransferCallback
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
ByteBuffer nativeBuffer = transfer.buffer();
|
||||
|
||||
ReusableComplexBuffer reusableComplexBuffer =
|
||||
mNativeBufferConverter.convert(nativeBuffer, transfer.actualLength());
|
||||
|
||||
if(mComplexBufferListener != null)
|
||||
if(mNativeBufferListener != null)
|
||||
{
|
||||
mComplexBufferListener.receive(reusableComplexBuffer);
|
||||
//Pass the transfer's byte buffer so the native buffer factory can make a copy of the
|
||||
//byte array contents and package it as a native buffer.
|
||||
INativeBuffer nativeBuffer = mNativeBufferFactory.getBuffer(transfer.buffer(),
|
||||
System.currentTimeMillis());
|
||||
mNativeBufferListener.receive(nativeBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,7 +573,7 @@ public class USBTransferProcessor implements TransferCallback
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool.SCHEDULED.submit(() -> restart());
|
||||
ThreadPool.CACHED.submit(() -> restart());
|
||||
transfer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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
|
||||
@@ -14,12 +14,12 @@
|
||||
*
|
||||
* 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.source.tuner.usb;
|
||||
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
|
||||
public abstract class USBTunerController extends TunerController
|
||||
@@ -44,7 +44,7 @@ public abstract class USBTunerController extends TunerController
|
||||
* Adds the IQ buffer listener and automatically starts buffer transfer processing, if not already started.
|
||||
*/
|
||||
@Override
|
||||
public void addBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void addBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
boolean hasExistingListeners = hasBufferListeners();
|
||||
|
||||
@@ -60,7 +60,7 @@ public abstract class USBTunerController extends TunerController
|
||||
* Removes the IQ buffer listener and stops buffer transfer processing if there are no more listeners.
|
||||
*/
|
||||
@Override
|
||||
public void removeBufferListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeBufferListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
super.removeBufferListener(listener);
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.tuner.usb.converter;
|
||||
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public abstract class NativeBufferConverter
|
||||
{
|
||||
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("NativeBufferConverter");
|
||||
|
||||
/**
|
||||
* Converts native byte buffers into complex float samples and produces reusable complex sample buffers. Tracks
|
||||
* each reusable buffer until the downstream consumer(s) are finished with the buffer and then reuses the buffer.
|
||||
@@ -34,23 +34,20 @@ public abstract class NativeBufferConverter
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the native byte buffer to complex float samples and returns the samples in a reusable buffer. Internally
|
||||
* tracks each reusable buffer until all consumers indicate they are finished processing the buffer and then reuses
|
||||
* the buffer.
|
||||
* Converts the native byte buffer to complex float samples.
|
||||
*
|
||||
* @param byteBuffer containing native memory byte samples
|
||||
* @return native buffer samples converted to complex floats loaded into a reusable buffer
|
||||
* @return native buffer samples converted to interleaved complex floats
|
||||
*/
|
||||
public ReusableComplexBuffer convert(ByteBuffer byteBuffer, int length)
|
||||
public InterleavedComplexSamples convert(ByteBuffer byteBuffer, int length)
|
||||
{
|
||||
FloatBuffer floatBuffer = convertSamples(byteBuffer, length);
|
||||
|
||||
ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(floatBuffer.capacity());
|
||||
float[] samples = new float[floatBuffer.capacity()];
|
||||
floatBuffer.rewind();
|
||||
floatBuffer.get(samples);
|
||||
|
||||
//The reusable buffer will rewind the float buffer to the beginning
|
||||
reusableComplexBuffer.reloadFrom(floatBuffer, System.currentTimeMillis());
|
||||
|
||||
return reusableComplexBuffer;
|
||||
return new InterleavedComplexSamples(samples, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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.source.tuner.usb.converter;
|
||||
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for native samples byte buffer. This class holds a copy of the byte array of samples
|
||||
* that was copied from a native byte buffer into the JVM heap space.
|
||||
*
|
||||
* Consumers of this sample buffer must make a copy of the contents in either interleaved or non-interleaved
|
||||
* sample array buffers.
|
||||
*/
|
||||
public abstract class NativeSampleBuffer
|
||||
{
|
||||
private byte[] mSamples;
|
||||
|
||||
public NativeSampleBuffer(byte[] samples)
|
||||
{
|
||||
mSamples = samples;
|
||||
}
|
||||
|
||||
protected byte[] getSamples()
|
||||
{
|
||||
return mSamples;
|
||||
}
|
||||
|
||||
public abstract List<ComplexSamples> convert();
|
||||
|
||||
public abstract List<InterleavedComplexSamples> convertInterleaved();
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.source.tuner.usb.converter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -77,4 +80,10 @@ public class SignedByteSampleConverter extends NativeBufferConverter
|
||||
|
||||
return mFloatBuffer;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SignedByteSampleConverter converter = new SignedByteSampleConverter();
|
||||
int a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.source.wave;
|
||||
|
||||
import io.github.dsheirer.buffer.FloatNativeBuffer;
|
||||
import io.github.dsheirer.buffer.INativeBuffer;
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
|
||||
import io.github.dsheirer.source.ComplexSource;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.source.IControllableFileSource;
|
||||
import io.github.dsheirer.source.IFrameLocationListener;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
@@ -44,7 +42,7 @@ import java.util.Arrays;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ComplexWaveSource extends ComplexSource implements IControllableFileSource, AutoCloseable
|
||||
public class ComplexWaveSource extends Source implements IControllableFileSource, AutoCloseable
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexWaveSource.class);
|
||||
|
||||
@@ -52,10 +50,9 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
private int mBytesPerFrame;
|
||||
private int mFrameCounter = 0;
|
||||
private long mFrequency = 0;
|
||||
private Listener<ReusableComplexBuffer> mListener;
|
||||
private Listener<INativeBuffer> mListener;
|
||||
private AudioInputStream mInputStream;
|
||||
private File mFile;
|
||||
private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexWaveSource");
|
||||
private boolean mAutoReplay;
|
||||
private ScheduledFuture<?> mReplayController;
|
||||
|
||||
@@ -85,6 +82,11 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
this(file, false);
|
||||
}
|
||||
|
||||
@Override public SampleType getSampleType()
|
||||
{
|
||||
return SampleType.COMPLEX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
@@ -167,7 +169,6 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
@Override
|
||||
public long getFrameCount() throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -275,11 +276,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
}
|
||||
|
||||
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
|
||||
|
||||
ReusableComplexBuffer reusableBuffer = mReusableComplexBufferQueue.getBuffer(samples.length);
|
||||
System.arraycopy(samples, 0, reusableBuffer.getSamples(), 0, samples.length);
|
||||
reusableBuffer.setTimestamp(System.currentTimeMillis());
|
||||
mListener.receive(reusableBuffer);
|
||||
mListener.receive(new FloatNativeBuffer(samples, System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,8 +285,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
* Registers the listener to receive sample buffers as they are read from
|
||||
* the wave file
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void setListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
@@ -297,7 +293,7 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
/**
|
||||
* Unregisters the listener from receiving sample buffers
|
||||
*/
|
||||
public void removeListener(Listener<ReusableComplexBuffer> listener)
|
||||
public void removeListener(Listener<INativeBuffer> listener)
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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 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.
|
||||
* 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/>
|
||||
******************************************************************************/
|
||||
* 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.source.wave;
|
||||
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
|
||||
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.source.IControllableFileSource;
|
||||
import io.github.dsheirer.source.IFrameLocationListener;
|
||||
import io.github.dsheirer.source.RealSource;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -36,16 +36,14 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RealWaveSource extends RealSource implements IControllableFileSource, AutoCloseable
|
||||
public class RealWaveSource extends Source implements IControllableFileSource, AutoCloseable
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(RealWaveSource.class);
|
||||
|
||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("RealWaveSource");
|
||||
private IFrameLocationListener mFrameLocationListener;
|
||||
private int mBytesPerFrame;
|
||||
private int mFrameCounter = 0;
|
||||
private long mFrequency = 0;
|
||||
private Listener<ReusableFloatBuffer> mListener;
|
||||
private Listener<float[]> mListener;
|
||||
private AudioInputStream mInputStream;
|
||||
private File mFile;
|
||||
|
||||
@@ -54,6 +52,11 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
@Override public SampleType getSampleType()
|
||||
{
|
||||
return SampleType.REAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
@@ -229,11 +232,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
}
|
||||
|
||||
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
|
||||
|
||||
ReusableFloatBuffer reusableFloatBuffer = mReusableBufferQueue.getBuffer(samples.length);
|
||||
reusableFloatBuffer.reloadFrom(samples, System.currentTimeMillis());
|
||||
|
||||
mListener.receive(reusableFloatBuffer);
|
||||
mListener.receive(samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,8 +240,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
/**
|
||||
* Registers the listener to receive sample buffers as they are read from the wave file
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener<ReusableFloatBuffer> listener)
|
||||
public void setListener(Listener<float[]> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
@@ -250,8 +248,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
/**
|
||||
* Unregisters the listener from receiving sample buffers
|
||||
*/
|
||||
@Override
|
||||
public void removeListener(Listener<ReusableFloatBuffer> listener)
|
||||
public void removeListener(Listener<float[]> listener)
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user