diff --git a/src/main/java/io/github/dsheirer/channel/state/ChannelState.java b/src/main/java/io/github/dsheirer/channel/state/ChannelState.java
index 2ba741e4..f2d069d5 100644
--- a/src/main/java/io/github/dsheirer/channel/state/ChannelState.java
+++ b/src/main/java/io/github/dsheirer/channel/state/ChannelState.java
@@ -32,8 +32,8 @@ import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.event.CallEvent;
import io.github.dsheirer.module.decode.event.ICallEventProvider;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.heartbeat.Heartbeat;
diff --git a/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator_CB.java b/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator_CB.java
deleted file mode 100644
index 4a22ba6b..00000000
--- a/src/main/java/io/github/dsheirer/dsp/am/AMDemodulator_CB.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2014,2015 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- ******************************************************************************/
-package io.github.dsheirer.dsp.am;
-
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
-import io.github.dsheirer.sample.real.RealBuffer;
-
-public class AMDemodulator_CB extends AMDemodulator implements Listener
-{
- private Listener mListener;
-
- public AMDemodulator_CB( float gain )
- {
- super( gain );
- }
-
- @Override
- public void receive( ComplexBuffer buffer )
- {
- if( mListener != null )
- {
- float[] samples = buffer.getSamples();
-
- int half = samples.length / 2;
-
- float[] demodulated = new float[ half ];
-
- for( int x = 0; x < half; x++ )
- {
- int index = x * 2;
-
- demodulated[ x ] = demodulate( samples[ index ], samples[ index + 1 ] );
- }
-
- mListener.receive( new RealBuffer( demodulated ) );
- }
- }
-
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-
- public void removeListener()
- {
- mListener = null;
- }
-
- public void dispose()
- {
- mListener = null;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java
index e2bf21b0..91ebda5c 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ComplexPolyphaseChannelizerM2.java
@@ -20,10 +20,10 @@ package io.github.dsheirer.dsp.filter.channelizer;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
-import io.github.dsheirer.sample.real.IOverflowListener;
import org.jtransforms.fft.FloatFFT_1D;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java
index 1df13430..0ee7e268 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/ContinuousBufferProcessor.java
@@ -15,9 +15,9 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.channelizer;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.OverflowableTransferQueue;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java
index 4e41ffbe..07e065f1 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelSource.java
@@ -17,9 +17,9 @@ package io.github.dsheirer.dsp.filter.channelizer;
import io.github.dsheirer.dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor;
import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
@@ -30,7 +30,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
{
private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelSource.class);
- private ReusableBufferAssembler mReusableBufferAssembler;
+ private ReusableComplexBufferAssembler mReusableComplexBufferAssembler;
private IPolyphaseChannelOutputProcessor mPolyphaseChannelOutputProcessor;
private double mChannelSampleRate;
private long mIndexCenterFrequency;
@@ -54,7 +54,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
super(producerSourceEventListener, tunerChannel);
mPolyphaseChannelOutputProcessor = outputProcessor;
mChannelSampleRate = channelSampleRate;
- mReusableBufferAssembler = new ReusableBufferAssembler(2500, mChannelSampleRate);
+ mReusableComplexBufferAssembler = new ReusableComplexBufferAssembler(2500, mChannelSampleRate);
setFrequency(centerFrequency);
}
@@ -64,7 +64,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
@Override
public void setListener(final Listener listener)
{
- mReusableBufferAssembler.setListener(listener);
+ mReusableComplexBufferAssembler.setListener(listener);
}
/**
@@ -73,7 +73,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
@Override
public void removeListener(Listener listener)
{
- mReusableBufferAssembler.setListener(null);
+ mReusableComplexBufferAssembler.setListener(null);
}
/**
@@ -112,7 +112,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
//Fully process the residual channel results buffer of the previous channel output processor
if(existingProcessor != null)
{
- existingProcessor.processChannelResults(mReusableBufferAssembler);
+ existingProcessor.processChannelResults(mReusableComplexBufferAssembler);
}
//Finally, setup the frequency offset for the output processor and reset the frequency correction value
@@ -133,7 +133,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
*/
public void receiveChannelResults(ReusableChannelResultsBuffer channelResultsBuffer)
{
- mReusableBufferAssembler.updateTimestamp(channelResultsBuffer.getTimestamp());
+ mReusableComplexBufferAssembler.updateTimestamp(channelResultsBuffer.getTimestamp());
mPolyphaseChannelOutputProcessor.receiveChannelResults(channelResultsBuffer);
}
@@ -161,9 +161,9 @@ public class PolyphaseChannelSource extends TunerChannelSource
@Override
public void dispose()
{
- if(mReusableBufferAssembler != null)
+ if(mReusableComplexBufferAssembler != null)
{
- mReusableBufferAssembler.dispose();
+ mReusableComplexBufferAssembler.dispose();
}
if(mPolyphaseChannelOutputProcessor != null)
@@ -212,7 +212,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
//Lock on the output processor so that it can't be changed in the middle of processing
synchronized(mPolyphaseChannelOutputProcessor)
{
- mPolyphaseChannelOutputProcessor.processChannelResults(mReusableBufferAssembler);
+ mPolyphaseChannelOutputProcessor.processChannelResults(mReusableComplexBufferAssembler);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java
index 872700bb..43c1e858 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/ChannelOutputProcessor.java
@@ -20,10 +20,10 @@ package io.github.dsheirer.dsp.filter.channelizer.output;
import io.github.dsheirer.dsp.mixer.IOscillator;
import io.github.dsheirer.dsp.mixer.Oscillator;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
-import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
-import io.github.dsheirer.sample.real.IOverflowListener;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
import io.github.dsheirer.source.Source;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -99,10 +99,10 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
/**
* Processes all enqueued polyphase channelizer results until the internal queue is empty
- * @param reusableBufferAssembler to receive the processed channel results
+ * @param reusableComplexBufferAssembler to receive the processed channel results
*/
@Override
- public void processChannelResults(ReusableBufferAssembler reusableBufferAssembler)
+ public void processChannelResults(ReusableComplexBufferAssembler reusableComplexBufferAssembler)
{
try
{
@@ -110,7 +110,7 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
if(toProcess > 0)
{
- process(mChannelResultsToProcess, reusableBufferAssembler);
+ process(mChannelResultsToProcess, reusableComplexBufferAssembler);
}
}
catch(Throwable throwable)
@@ -124,10 +124,10 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
/**
* Sub-class implementation to process one polyphase channelizer result array.
* @param channelResults to process
- * @param reusableBufferAssembler to receive the processed channelizer results
+ * @param reusableComplexBufferAssembler to receive the processed channelizer results
*/
public abstract void process(List channelResults,
- ReusableBufferAssembler reusableBufferAssembler);
+ ReusableComplexBufferAssembler reusableComplexBufferAssembler);
/**
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java
index 95c45055..70eb7c4a 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java
@@ -18,8 +18,8 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.channelizer.output;
-import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
import io.github.dsheirer.source.Source;
import java.util.List;
@@ -35,9 +35,9 @@ public interface IPolyphaseChannelOutputProcessor
/**
* Process the channel output channel results queue and deliver the output to the listener
*
- * @param reusableBufferAssembler to receive the processed channel results
+ * @param reusableComplexBufferAssembler to receive the processed channel results
*/
- void processChannelResults(ReusableBufferAssembler reusableBufferAssembler);
+ void processChannelResults(ReusableComplexBufferAssembler reusableComplexBufferAssembler);
/**
* Sets the desired frequency offset from center. The samples will be mixed with an oscillator set to this offset
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java
index d06f1e44..ece7eedd 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelOutputProcessor.java
@@ -18,9 +18,9 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.channelizer.output;
-import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -74,11 +74,11 @@ public class OneChannelOutputProcessor extends ChannelOutputProcessor
* extracted frequency-corrected channel I/Q sample set to the complex sample listener.
*
* @param channelResults to process containing a list of channel array of I/Q sample pairs (I0,Q0,I1,Q1...In,Qn)
- * @param reusableBufferAssembler to receive the extracted, frequency-translated channel results
+ * @param reusableComplexBufferAssembler to receive the extracted, frequency-translated channel results
*/
@Override
public void process(List channelResults,
- ReusableBufferAssembler reusableBufferAssembler)
+ ReusableComplexBufferAssembler reusableComplexBufferAssembler)
{
for(ReusableChannelResultsBuffer channelResultsBuffer: channelResults)
{
@@ -91,7 +91,7 @@ public class OneChannelOutputProcessor extends ChannelOutputProcessor
getFrequencyCorrectionMixer().mixComplex(channelBuffer.getSamples());
}
- reusableBufferAssembler.receive(channelBuffer);
+ reusableComplexBufferAssembler.receive(channelBuffer);
}
catch(IllegalArgumentException iae)
{
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java
index 7852bd6d..34cca3a1 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelOutputProcessor.java
@@ -21,9 +21,9 @@ import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter2;
import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
import io.github.dsheirer.dsp.mixer.FS4DownConverter;
-import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -119,11 +119,11 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
* extracted frequency-corrected channel I/Q sample set to the complex sample listener.
*
* @param channelResultsBuffers to process containing an array of channel I/Q sample pairs (I0,Q0,I1,Q1...In,Qn)
- * @param reusableBufferAssembler to receive the extracted, frequency-translated channel results
+ * @param reusableComplexBufferAssembler to receive the extracted, frequency-translated channel results
*/
@Override
public void process(List channelResultsBuffers,
- ReusableBufferAssembler reusableBufferAssembler)
+ ReusableComplexBufferAssembler reusableComplexBufferAssembler)
{
for(ReusableChannelResultsBuffer buffer: channelResultsBuffers)
{
@@ -141,7 +141,7 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
ReusableComplexBuffer lowPassFiltered = mLowPassFilter.filter(synthesized);
- reusableBufferAssembler.receive(lowPassFiltered);
+ reusableComplexBufferAssembler.receive(lowPassFiltered);
buffer.decrementUserCount();
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/cic/ComplexPrimeCICDecimate.java b/src/main/java/io/github/dsheirer/dsp/filter/cic/ComplexPrimeCICDecimate.java
index 2ad5d95e..54c2db59 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/cic/ComplexPrimeCICDecimate.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/cic/ComplexPrimeCICDecimate.java
@@ -1,19 +1,16 @@
/*******************************************************************************
- * sdrtrunk
- * Copyright (C) 2014-2017 Dennis Sheirer
+ * 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 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
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
*
******************************************************************************/
package io.github.dsheirer.dsp.filter.cic;
@@ -21,19 +18,19 @@ package io.github.dsheirer.dsp.filter.cic;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.Filters;
import io.github.dsheirer.dsp.filter.Window;
-import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
-import io.github.dsheirer.dsp.filter.halfband.complex.HalfBandFilter_CB_CB;
+import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter2;
+import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandFilter;
import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
import io.github.dsheirer.sample.complex.ComplexSampleListener;
-import io.github.dsheirer.sample.complex.ComplexToComplexBufferAssembler;
import io.github.dsheirer.sample.decimator.ComplexDecimator;
import org.apache.commons.lang3.Validate;
import java.util.ArrayList;
import java.util.List;
-public class ComplexPrimeCICDecimate implements Listener
+public class ComplexPrimeCICDecimate implements Listener
{
public static int[] PRIMES = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
@@ -87,7 +84,7 @@ public class ComplexPrimeCICDecimate implements Listener
}
else
{
- /* Wire the current stage to the previous stage */
+ /* Wire the current stage to the previous stage */
mDecimatingStages.get(x - 1).setListener(stage);
}
}
@@ -116,7 +113,7 @@ public class ComplexPrimeCICDecimate implements Listener
/**
* Adds a listener to receive the output of this CIC decimation filter
*/
- public void setListener(Listener listener)
+ public void setListener(Listener listener)
{
mOutput.setListener(listener);
}
@@ -166,7 +163,7 @@ public class ComplexPrimeCICDecimate implements Listener
* Primary input method for receiving sample arrays composed as I,Q,I,Q, etc.
*/
@Override
- public void receive(ComplexBuffer buffer)
+ public void receive(ReusableComplexBuffer buffer)
{
if(mFirstDecimatingStage != null)
{
@@ -177,6 +174,8 @@ public class ComplexPrimeCICDecimate implements Listener
mFirstDecimatingStage.receive(samples[x], samples[x + 1]);
}
}
+
+ buffer.decrementUserCount();
}
/**
@@ -289,11 +288,11 @@ public class ComplexPrimeCICDecimate implements Listener
public void receive(float i, float q)
{
- /* Subtract the oldest sample and add back in the newest */
+ /* Subtract the oldest sample and add back in the newest */
mISum = mISum - mISamples[mSamplePointer] + i;
mQSum = mQSum - mQSamples[mSamplePointer] + q;
- /* Overwrite the oldest sample with the newest */
+ /* Overwrite the oldest sample with the newest */
mISamples[mSamplePointer] = i;
mQSamples[mSamplePointer] = q;
@@ -352,27 +351,37 @@ public class ComplexPrimeCICDecimate implements Listener
public class Output implements ComplexSampleListener
{
/* Decimated output buffers will contain 1024 samples */
- private ComplexToComplexBufferAssembler mAssembler =
- new ComplexToComplexBufferAssembler(2048);
+ private ReusableComplexBufferAssembler mAssembler = new ReusableComplexBufferAssembler(2048, 48000.0);
- private ComplexFIRFilter_CB_CB mCleanupFilter;
- private HalfBandFilter_CB_CB mHalfBandFilter = new HalfBandFilter_CB_CB(
+ private ComplexFIRFilter2 mCleanupFilter;
+ private ComplexHalfBandFilter mHalfBandFilter = new ComplexHalfBandFilter(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 0.4f, false);
+ private Listener mReusableComplexBufferListener;
public Output(int outputSampleRate, int passFrequency, int attenuation,
Window.WindowType windowType)
{
- mCleanupFilter = new ComplexFIRFilter_CB_CB(FilterFactory
- .getCICCleanupFilter(outputSampleRate,
- passFrequency,
- attenuation,
- windowType), 0.4f);
+ mCleanupFilter = new ComplexFIRFilter2(FilterFactory
+ .getCICCleanupFilter(outputSampleRate, passFrequency, attenuation, windowType), 0.4f);
//Bypassing the CIC cleanup filter for now
- mAssembler.setListener(mHalfBandFilter);
-
-// mAssembler.setListener( mCleanupFilter );
-// mCleanupFilter.setListener( mHalfBandFilter );
+ mAssembler.setListener(new Listener()
+ {
+ @Override
+ public void receive(ReusableComplexBuffer reusableComplexBuffer)
+ {
+ if(mReusableComplexBufferListener != null)
+ {
+ ReusableComplexBuffer cleanupFiltered = mCleanupFilter.filter(reusableComplexBuffer);
+ ReusableComplexBuffer halfBandFiltered = mHalfBandFilter.filter(cleanupFiltered);
+ mReusableComplexBufferListener.receive(halfBandFiltered);
+ }
+ else
+ {
+ reusableComplexBuffer.decrementUserCount();
+ }
+ }
+ });
}
public void dispose()
@@ -390,23 +399,17 @@ public class ComplexPrimeCICDecimate implements Listener
@Override
public void receive(float inphase, float quadrature)
{
- mAssembler.receive(inphase, quadrature);
+ mAssembler.receive(new float[]{inphase, quadrature});
}
- /**
- * Adds a listener to receive output samples
- */
- public void setListener(Listener listener)
+ public void setListener(Listener listener)
{
- mHalfBandFilter.setListener(listener);
+ mReusableComplexBufferListener = listener;
}
- /**
- * Removes the listener from receiving output samples
- */
public void removeListener()
{
- mHalfBandFilter.removeListener();
+ mReusableComplexBufferListener = null;
}
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java b/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java
index 2b1b2b82..87b444b7 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/cic/RealPrimeCICDecimate.java
@@ -1,17 +1,17 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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
******************************************************************************/
@@ -20,13 +20,13 @@ package io.github.dsheirer.dsp.filter.cic;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.Filters;
import io.github.dsheirer.dsp.filter.Window.WindowType;
-import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter_RB_RB;
-import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter_RB_RB;
+import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter2;
+import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter;
import io.github.dsheirer.sample.Listener;
+import io.github.dsheirer.sample.buffer.ReusableBuffer;
+import io.github.dsheirer.sample.buffer.ReusableBufferAssembler;
import io.github.dsheirer.sample.decimator.RealDecimator;
-import io.github.dsheirer.sample.real.RealBuffer;
import io.github.dsheirer.sample.real.RealSampleListener;
-import io.github.dsheirer.sample.real.RealToRealBufferAssembler;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,381 +34,389 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
-public class RealPrimeCICDecimate
+public class RealPrimeCICDecimate
{
- private final static Logger mLog =
- LoggerFactory.getLogger( RealPrimeCICDecimate.class );
-
- public static int[] PRIMES = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
- 59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,
- 157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,
- 257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,
- 367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,
- 467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,
- 599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691 };
-
- private ArrayList mDecimatingStages =
- new ArrayList();
-
- private DecimatingStage mFirstDecimatingStage;
+ private final static Logger mLog = LoggerFactory.getLogger(RealPrimeCICDecimate.class);
- private Output mOutput;
-
- private int mOutputBufferSize = 2048;
+ public static int[] PRIMES = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
+ 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
+ 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251,
+ 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
+ 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
+ 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593,
+ 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691};
- /**
- * Non-Recursive Prime-Factor CIC Filter with float sample array inputs and
- * decimated float sample output.
- *
- * Implements the CIC filter described in Understanding Digital Signal
- * Processing, 3e, Lyons, on page 769. This filter is comprised of multiple
- * decimating stages each with a prime factor decimation rate. Multiple
- * stages are cascaded to achieve the overall decimation rate.
- *
- * This filter supports a maximum decimation rate of 700. This filter can
- * be adapted to higher decimation rates by adding additional prime factors
- * to the PRIMES array.
- *
- * @param decimation - overall decimation rate
- * @param order - filter order
- */
- public RealPrimeCICDecimate( int decimation, int order, int passFrequency,
- int attenuation, WindowType windowType )
- {
- this( decimation, order, passFrequency, attenuation, windowType, 2048 );
- }
-
- public RealPrimeCICDecimate( int decimation, int order, int passFrequency,
- int attenuation, WindowType windowType, int outputBufferSize )
- {
- Validate.isTrue(decimation <= 700);
+ private List mDecimatingStages = new ArrayList();
+ private DecimatingStage mFirstDecimatingStage;
+ private Output mOutput;
- mOutputBufferSize = outputBufferSize;
+ private int mOutputBufferSize = 2048;
- List stageSizes = getPrimeFactors( decimation );
-
- for( int x = 0; x < stageSizes.size(); x++ )
- {
- DecimatingStage stage = new DecimatingStage( stageSizes.get( x ), order );
-
- mDecimatingStages.add( stage );
-
- if( x == 0 )
- {
- /* Reference to first stage -- will receive all samples */
- mFirstDecimatingStage = stage;
- }
- else
- {
- /* Wire the current stage to the previous stage */
- mDecimatingStages.get( x - 1 ).setListener( stage );
- }
- }
-
- mOutput = new Output( 48000, passFrequency, attenuation, windowType,
- outputBufferSize );
-
- mDecimatingStages.get( mDecimatingStages.size() - 1 )
- .setListener( mOutput );
- }
-
- public void dispose()
- {
- for( DecimatingStage stage: mDecimatingStages )
- {
- stage.dispose();
- }
-
- mDecimatingStages.clear();
- mDecimatingStages = null;
- mFirstDecimatingStage = null;
-
- mOutput.dispose();
- mOutput = null;
- }
-
- /**
- * Adds a listener to receive the output of this CIC decimation filter
- */
- public void setListener( Listener listener )
- {
- mOutput.setListener( listener );
- }
-
- /**
- * Removes listener from output of this CIC decimation filter
- */
- public void removeListener()
- {
- mOutput.removeListener();
- }
-
- /**
- * Calculates the prime factors of the decimation rate up to a maximum
- * decimation rate of 700. If you wish to have decimation rates higher
- * than 700, then add additional prime factors to the PRIMES array.
- *
- * @param decimation - integral decimation rate
- * @return - ordered list (smallest to largest) of prime factors
- */
- public static List getPrimeFactors( int decimation )
- {
- ArrayList stages = new ArrayList();
-
- int pointer = 0;
-
- while( decimation > 0 && pointer < PRIMES.length )
- {
- int prime = PRIMES[ pointer ];
-
- if( decimation % prime == 0 )
- {
- stages.add( prime );
-
- decimation /= prime;
- }
- else
- {
- pointer++;
- }
- }
-
- return stages;
- }
-
- /**
- * Primary input method for receiving real buffers.
- */
- public void receive( RealBuffer buffer )
+ /**
+ * Non-Recursive Prime-Factor CIC Filter with float sample array inputs and
+ * decimated float sample output.
+ *
+ * Implements the CIC filter described in Understanding Digital Signal
+ * Processing, 3e, Lyons, on page 769. This filter is comprised of multiple
+ * decimating stages each with a prime factor decimation rate. Multiple
+ * stages are cascaded to achieve the overall decimation rate.
+ *
+ * This filter supports a maximum decimation rate of 700. This filter can
+ * be adapted to higher decimation rates by adding additional prime factors
+ * to the PRIMES array.
+ *
+ * @param decimation - overall decimation rate
+ * @param order - filter order
+ */
+ public RealPrimeCICDecimate(int decimation, int order, int passFrequency, int attenuation, WindowType windowType)
{
- if( mFirstDecimatingStage != null )
- {
- for( float sample: buffer.getSamples() )
- {
- mFirstDecimatingStage.receive( sample );
- }
- }
+ this(decimation, order, passFrequency, attenuation, windowType, 2048);
}
-
- /**
- * Decimating stage combines multiple CIC stages with a decimator. The
- * number of stages is indicated by the order value and the size indicates
- * the decimation rate of this stage.
- */
- public class DecimatingStage implements RealSampleListener
- {
- private ArrayList mStages = new ArrayList();
- private Stage mFirstStage;
- private RealDecimator mDecimator;
-
- public DecimatingStage( int size, int order )
- {
- for( int x = 0; x < order; x++ )
- {
- Stage stage;
-
- if( size == 2 )
- {
- stage = new TwoStage();
- }
- else
- {
- stage = new Stage( size );
- }
-
- mStages.add( stage );
-
- if( x == 0 )
- {
- mFirstStage = stage;
- }
- else
- {
- mStages.get( x - 1 ).setListener( stage );
- }
- }
-
- mDecimator = new RealDecimator( size );
-
- mStages.get( mStages.size() - 1 ).setListener( mDecimator );
- }
-
- public void dispose()
- {
- for( Stage stage: mStages )
- {
- stage.dispose();
- }
-
- mStages.clear();
- mDecimator.dispose();
- mDecimator = null;
- mFirstStage = null;
- mStages = null;
- }
- @Override
- public void receive( float sample )
+ public RealPrimeCICDecimate(int decimation, int order, int passFrequency, int attenuation, WindowType windowType, int outputBufferSize)
+ {
+ Validate.isTrue(decimation <= 700);
+
+ mOutputBufferSize = outputBufferSize;
+
+ List stageSizes = getPrimeFactors(decimation);
+
+ for(int x = 0; x < stageSizes.size(); x++)
{
- mFirstStage.receive( sample );
- }
-
- public void setListener( RealSampleListener listener )
- {
- mDecimator.setListener( listener );
- }
- }
-
- /**
- * Single non-decimating CIC stage component. Uses a circular buffer and a
- * running average internally to implement the stage so that stage size has
- * essentially no impact on the computational requirements of the stage
- */
- public class Stage implements RealSampleListener
- {
- protected RealSampleListener mListener;
-
- private float[] mSamples;
-
- protected float mSum;
-
- private int mSamplePointer = 0;
- private int mSize;
-
- protected float mGain;
-
- public Stage()
- {
- }
+ DecimatingStage stage = new DecimatingStage(stageSizes.get(x), order);
- public Stage( int size )
- {
- mSize = size - 1;
-
- mSamples = new float[ mSize ];
-
- mGain = 1.0f / (float)size;
- }
-
- public void dispose()
- {
- mListener = null;
- }
-
- public void receive( float sample )
- {
- /* Subtract the oldest sample and add back in the newest */
- mSum = mSum - mSamples[ mSamplePointer ] + sample;
+ mDecimatingStages.add(stage);
- /* Overwrite the oldest sample with the newest */
- mSamples[ mSamplePointer ] = sample;
-
- mSamplePointer++;
-
- if( mSamplePointer >= mSize )
- {
- mSamplePointer = 0;
- }
-
- if( mListener != null )
- {
- mListener.receive( mSum * mGain );
- }
- }
-
- public void setListener( RealSampleListener listener )
- {
- mListener = listener;
- }
- }
-
- /**
- * Size 2 stage that removes the unnecessary circular buffer management for
- * a two-stage.
- */
- public class TwoStage extends Stage
- {
- public TwoStage()
- {
- super();
-
- mGain = 0.5f;
- }
-
- public void receive( float sample )
- {
- float sum = mSum + sample;
-
- mSum = sample;
-
- if( mListener != null )
- {
- mListener.receive( sum * mGain );
- }
- }
- }
-
- /**
- * Output adapter - applies gain correction, applies cleanup filter, casts
- * double-valued samples into float-valued complex sample and sends the
- * result to the registered listener.
- */
- public class Output implements RealSampleListener
- {
- /* Decimated output buffers will contain 1024 samples */
- private RealToRealBufferAssembler mAssembler;
-
- private RealFIRFilter_RB_RB mCleanupFilter;
- private HalfBandFilter_RB_RB mHalfBandFilter = new HalfBandFilter_RB_RB(
- Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 0.4f, false );
-
- public Output( int outputSampleRate, int passFrequency, int attenuation,
- WindowType windowType, int outputBufferSize )
- {
- mCleanupFilter = new RealFIRFilter_RB_RB( FilterFactory
- .getCICCleanupFilter( outputSampleRate,
- passFrequency,
- attenuation,
- windowType ), 0.4f );
-
- mAssembler = new RealToRealBufferAssembler( outputBufferSize );
- mAssembler.setListener( mCleanupFilter );
- mCleanupFilter.setListener( mHalfBandFilter );
-
- }
-
- public void dispose()
- {
- mAssembler.dispose();
- mCleanupFilter.dispose();
- mHalfBandFilter.dispose();
- }
-
- /**
- * Receiver method for the output adapter to receive a filtered,
- * decimated sample, apply gain correction, apply cleanup filtering
- * and output the sample values as a complex sample.
- */
- @Override
- public void receive( float sample )
- {
- mAssembler.receive( sample * 32.0f );
- }
-
- /**
- * Adds a listener to receive output samples
- */
- public void setListener( Listener listener )
- {
- mHalfBandFilter.setListener( listener );
+ if(x == 0)
+ {
+ /* Reference to first stage -- will receive all samples */
+ mFirstDecimatingStage = stage;
+ }
+ else
+ {
+ /* Wire the current stage to the previous stage */
+ mDecimatingStages.get(x - 1).setListener(stage);
+ }
}
- /**
- * Removes the listener from receiving output samples
- */
+ mOutput = new Output(48000, passFrequency, attenuation, windowType,
+ outputBufferSize);
+
+ mDecimatingStages.get(mDecimatingStages.size() - 1)
+ .setListener(mOutput);
+ }
+
+ public void dispose()
+ {
+ for(DecimatingStage stage : mDecimatingStages)
+ {
+ stage.dispose();
+ }
+
+ mDecimatingStages.clear();
+ mDecimatingStages = null;
+ mFirstDecimatingStage = null;
+
+ mOutput.dispose();
+ mOutput = null;
+ }
+
+ /**
+ * Adds a listener to receive the output of this CIC decimation filter
+ */
+ public void setListener(Listener listener)
+ {
+ mOutput.setListener(listener);
+ }
+
+ /**
+ * Removes listener from output of this CIC decimation filter
+ */
+ public void removeListener()
+ {
+ mOutput.removeListener();
+ }
+
+ /**
+ * Calculates the prime factors of the decimation rate up to a maximum
+ * decimation rate of 700. If you wish to have decimation rates higher
+ * than 700, then add additional prime factors to the PRIMES array.
+ *
+ * @param decimation - integral decimation rate
+ * @return - ordered list (smallest to largest) of prime factors
+ */
+ public static List getPrimeFactors(int decimation)
+ {
+ ArrayList stages = new ArrayList();
+
+ int pointer = 0;
+
+ while(decimation > 0 && pointer < PRIMES.length)
+ {
+ int prime = PRIMES[pointer];
+
+ if(decimation % prime == 0)
+ {
+ stages.add(prime);
+
+ decimation /= prime;
+ }
+ else
+ {
+ pointer++;
+ }
+ }
+
+ return stages;
+ }
+
+ /**
+ * Primary input method for receiving real buffers.
+ */
+ public void receive(ReusableBuffer buffer)
+ {
+ if(mFirstDecimatingStage != null)
+ {
+ for(float sample : buffer.getSamples())
+ {
+ mFirstDecimatingStage.receive(sample);
+ }
+ }
+
+ buffer.decrementUserCount();
+ }
+
+ /**
+ * Decimating stage combines multiple CIC stages with a decimator. The
+ * number of stages is indicated by the order value and the size indicates
+ * the decimation rate of this stage.
+ */
+ public class DecimatingStage implements RealSampleListener
+ {
+ private ArrayList mStages = new ArrayList();
+ private Stage mFirstStage;
+ private RealDecimator mDecimator;
+
+ public DecimatingStage(int size, int order)
+ {
+ for(int x = 0; x < order; x++)
+ {
+ Stage stage;
+
+ if(size == 2)
+ {
+ stage = new TwoStage();
+ }
+ else
+ {
+ stage = new Stage(size);
+ }
+
+ mStages.add(stage);
+
+ if(x == 0)
+ {
+ mFirstStage = stage;
+ }
+ else
+ {
+ mStages.get(x - 1).setListener(stage);
+ }
+ }
+
+ mDecimator = new RealDecimator(size);
+
+ mStages.get(mStages.size() - 1).setListener(mDecimator);
+ }
+
+ public void dispose()
+ {
+ for(Stage stage : mStages)
+ {
+ stage.dispose();
+ }
+
+ mStages.clear();
+ mDecimator.dispose();
+ mDecimator = null;
+ mFirstStage = null;
+ mStages = null;
+ }
+
+ @Override
+ public void receive(float sample)
+ {
+ mFirstStage.receive(sample);
+ }
+
+ public void setListener(RealSampleListener listener)
+ {
+ mDecimator.setListener(listener);
+ }
+ }
+
+ /**
+ * Single non-decimating CIC stage component. Uses a circular buffer and a
+ * running average internally to implement the stage so that stage size has
+ * essentially no impact on the computational requirements of the stage
+ */
+ public class Stage implements RealSampleListener
+ {
+ protected RealSampleListener mListener;
+
+ private float[] mSamples;
+
+ protected float mSum;
+
+ private int mSamplePointer = 0;
+ private int mSize;
+
+ protected float mGain;
+
+ public Stage()
+ {
+ }
+
+ public Stage(int size)
+ {
+ mSize = size - 1;
+
+ mSamples = new float[mSize];
+
+ mGain = 1.0f / (float)size;
+ }
+
+ public void dispose()
+ {
+ mListener = null;
+ }
+
+ public void receive(float sample)
+ {
+ /* Subtract the oldest sample and add back in the newest */
+ mSum = mSum - mSamples[mSamplePointer] + sample;
+
+ /* Overwrite the oldest sample with the newest */
+ mSamples[mSamplePointer] = sample;
+
+ mSamplePointer++;
+
+ if(mSamplePointer >= mSize)
+ {
+ mSamplePointer = 0;
+ }
+
+ if(mListener != null)
+ {
+ mListener.receive(mSum * mGain);
+ }
+ }
+
+ public void setListener(RealSampleListener listener)
+ {
+ mListener = listener;
+ }
+ }
+
+ /**
+ * Size 2 stage that removes the unnecessary circular buffer management for
+ * a two-stage.
+ */
+ public class TwoStage extends Stage
+ {
+ public TwoStage()
+ {
+ super();
+
+ mGain = 0.5f;
+ }
+
+ public void receive(float sample)
+ {
+ float sum = mSum + sample;
+
+ mSum = sample;
+
+ if(mListener != null)
+ {
+ mListener.receive(sum * mGain);
+ }
+ }
+ }
+
+ /**
+ * Output adapter - applies gain correction, applies cleanup filter, casts
+ * double-valued samples into float-valued complex sample and sends the
+ * result to the registered listener.
+ */
+ public class Output implements RealSampleListener
+ {
+ /* Decimated output buffers will contain 1024 samples */
+ private ReusableBufferAssembler mAssembler;
+ private Listener mReusableBufferListener;
+
+ private RealFIRFilter2 mCleanupFilter;
+ private HalfBandFilter mHalfBandFilter = new HalfBandFilter(
+ Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 0.4f, false);
+
+ public Output(int outputSampleRate, int passFrequency, int attenuation, WindowType windowType, int outputBufferSize)
+ {
+ mCleanupFilter = new RealFIRFilter2(FilterFactory.getCICCleanupFilter(outputSampleRate, passFrequency,
+ attenuation, windowType), 0.4f);
+
+ mAssembler = new ReusableBufferAssembler(outputBufferSize);
+ mAssembler.setListener(new Listener()
+ {
+ @Override
+ public void receive(ReusableBuffer reusableBuffer)
+ {
+
+ if(mReusableBufferListener != null)
+ {
+ ReusableBuffer cleanupFiltered = mCleanupFilter.filter(reusableBuffer);
+ ReusableBuffer halfBandFiltered = mHalfBandFilter.filter(cleanupFiltered);
+ mReusableBufferListener.receive(halfBandFiltered);
+ }
+ else
+ {
+ reusableBuffer.decrementUserCount();
+ }
+ }
+ });
+ }
+
+ public void dispose()
+ {
+ mAssembler.dispose();
+ mCleanupFilter.dispose();
+ mHalfBandFilter.dispose();
+ }
+
+ /**
+ * Receiver method for the output adapter to receive a filtered,
+ * decimated sample, apply gain correction, apply cleanup filtering
+ * and output the sample values as a complex sample.
+ */
+ @Override
+ public void receive(float sample)
+ {
+ mAssembler.receive(sample * 32.0f);
+ }
+
+ /**
+ * Adds a listener to receive output samples
+ */
+ public void setListener(Listener listener)
+ {
+ mReusableBufferListener = listener;
+ }
+
+ /**
+ * Removes the listener from receiving output samples
+ */
public void removeListener()
{
- mHalfBandFilter.removeListener();
+ mReusableBufferListener = null;
}
- }
+ }
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/correction/IQCorrectionFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/correction/IQCorrectionFilter.java
index ca219ac5..1264201a 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/correction/IQCorrectionFilter.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/correction/IQCorrectionFilter.java
@@ -18,13 +18,15 @@
******************************************************************************/
package io.github.dsheirer.dsp.filter.correction;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
public class IQCorrectionFilter
{
private float mRatio = 0.00001f;
private float mAverageInphase = 0.0f;
private float mAverageQuadrature = 0.0f;
+ private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("IQCorrectionFilter");
public IQCorrectionFilter(float ratio)
{
@@ -35,17 +37,23 @@ public class IQCorrectionFilter
{
}
- public void filter(ComplexBuffer buffer)
+ public ReusableComplexBuffer filter(ReusableComplexBuffer buffer)
{
float[] samples = buffer.getSamples();
+ ReusableComplexBuffer filtered = mReusableComplexBufferQueue.getBuffer(samples.length);
+ filtered.incrementUserCount();
+ float[] filteredSamples = filtered.getSamples();
+
for(int x = 0; x < samples.length; x += 2)
{
mAverageInphase = mAverageInphase + (mRatio * (samples[x] - mAverageInphase));
- samples[x] -= mAverageInphase;
+ filteredSamples[x] = samples[x] - mAverageInphase;
mAverageQuadrature = mAverageQuadrature + (mRatio * (samples[x + 1] - mAverageQuadrature));
- samples[x + 1] -= mAverageQuadrature;
+ filteredSamples[x + 1] = samples[x + 1] - mAverageQuadrature;
}
+
+ return filtered;
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java
deleted file mode 100644
index a61f04f2..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.dsp.filter.fir.complex;
-
-import io.github.dsheirer.dsp.filter.fir.FIRFilter;
-import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter;
-import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
-import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
-import io.github.dsheirer.sample.complex.Complex;
-
-@Deprecated //Use ComplexFIRFilter2 instead
-public class ComplexFIRFilter extends FIRFilter
-{
- private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("Complex FIR Filter");
- private RealFIRFilter mIFilter;
- private RealFIRFilter mQFilter;
- private float[] mTemporaryBuffer;
-
- /**
- * Complex FIR Filter for processing complex sample pairs. Wraps two real
- * FIR filters for processing each of the inphase and quadrature samples.
- *
- * @param coefficients - filter taps
- * @param gain - gain to apply to filtered outputs - use 1.0f for no gain
- */
- public ComplexFIRFilter(float[] coefficients, float gain)
- {
- mIFilter = new RealFIRFilter(coefficients, gain);
- mQFilter = new RealFIRFilter(coefficients, gain);
- }
-
- public float[] getCoefficients()
- {
- return mIFilter.getCoefficients();
- }
-
- public float filterInphase(float sample)
- {
- return mIFilter.filter(sample);
- }
-
- public float currentInphaseValue()
- {
- return mIFilter.currentValue();
- }
-
- public float filterQuadrature(float sample)
- {
- return mQFilter.filter(sample);
- }
-
- public float currentQuadratureValue()
- {
- return mQFilter.currentValue();
- }
-
- public Complex filter(Complex sample)
- {
- float i = filterInphase(sample.inphase());
- float q = filterQuadrature(sample.quadrature());
-
- return new Complex(i, q);
- }
-
- public float[] filter(float[] samples)
- {
- if(mTemporaryBuffer == null || mTemporaryBuffer.length != samples.length)
- {
- mTemporaryBuffer = new float[samples.length];
- }
-
- System.arraycopy(samples, 0, mTemporaryBuffer, 0, samples.length);
-
- for(int x = 0; x < samples.length; x += 2)
- {
- samples[x] = filterInphase(mTemporaryBuffer[x]);
- samples[x + 1] = filterQuadrature(mTemporaryBuffer[x + 1]);
- }
-
- return samples;
- }
-
- /**
- * Filters the complex samples from the buffer and returns a new complex buffer with the filtered output
- *
- * @param originalBuffer with complex samples to filter
- * @return new buffer containing filtered complex samples
- */
- public ReusableComplexBuffer filter(ReusableComplexBuffer originalBuffer)
- {
- ReusableComplexBuffer filteredBuffer = mReusableComplexBufferQueue.getBuffer(originalBuffer.getSamples().length);
- filteredBuffer.setTimestamp(originalBuffer.getTimestamp());
-
- float[] samples = originalBuffer.getSamples();
- float[] filteredSamples = filteredBuffer.getSamples();
-
- for(int x = 0; x < originalBuffer.getSamples().length; x += 2)
- {
- filteredSamples[x] = filterInphase(samples[x]);
- filteredSamples[x + 1] = filterQuadrature(samples[x + 1]);
- }
-
- originalBuffer.decrementUserCount();
- filteredBuffer.incrementUserCount();
-
- return filteredBuffer;
- }
-
- @Override
- public void dispose()
- {
- mIFilter.dispose();
- mQFilter.dispose();
- mReusableComplexBufferQueue.dispose();
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter_CB_CB.java b/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter_CB_CB.java
deleted file mode 100644
index bb1e3c0a..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter_CB_CB.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package io.github.dsheirer.dsp.filter.fir.complex;
-
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
-
-@Deprecated //Use ComplexFIRFilter2 instead
-public class ComplexFIRFilter_CB_CB extends ComplexFIRFilter implements Listener
-{
- private Listener mListener;
-
- /**
- * Complex FIR Filter for processing complex buffers. Wraps two real FIR
- * filters for processing each of the inphase and quadrature samples.
- *
- * @param coefficients - odd length symmetric filter taps
- * @param gain - gain value to apply to each of the filtered samples
- */
- public ComplexFIRFilter_CB_CB(float[] coefficients, float gain)
- {
- super(coefficients, gain);
- }
-
- public void dispose()
- {
- mListener = null;
- }
-
- @Override
- public void receive(ComplexBuffer buffer)
- {
- if(mListener != null)
- {
- float[] samples = buffer.getSamples();
-
- for(int x = 0; x < samples.length; x += 2)
- {
- samples[x] = filterInphase(samples[x]);
- samples[x + 1] = filterQuadrature(samples[x + 1]);
- }
-
- mListener.receive(buffer);
- }
- }
-
- /**
- * Filters the samples and send the results to the registered listener
- */
- public void receive(float[] samples)
- {
- if(mListener != null)
- {
- float[] filtered = filter(samples);
-
- //TODO: this should be a reusable buffer here.
- mListener.receive(new ComplexBuffer(filtered));
- }
- }
-
- public void setListener(Listener listener)
- {
- mListener = listener;
- }
-
- public void removeListener()
- {
- mListener = null;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter.java
deleted file mode 100644
index bc42fb6b..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.dsp.filter.fir.real;
-
-import io.github.dsheirer.dsp.filter.fir.FIRFilter;
-
-@Deprecated //Use RealFIRFilter2 instead
-public class RealFIRFilter extends FIRFilter
-{
- private float[] mBuffer;
- private int mBufferSize = 1;
- private int mBufferPointer = 0;
- private int[][] mIndexMap;
-
- private float[] mCoefficients;
- private float mGain;
- private float mAccumulator;
-
- /**
- * Float sample FIR filter base class.
- *
- * @param coefficients - filter coefficients
- * @param gain value to apply to the filtered output - use 1.0f for no gain
- */
- public RealFIRFilter(float[] coefficients, float gain)
- {
- mCoefficients = coefficients;
- mGain = gain;
-
- mBufferSize = mCoefficients.length;
-
- mBuffer = new float[mBufferSize];
- mBufferPointer = mBufferSize - 1;
-
- generateIndexMap(mBufferSize);
- }
-
- public float[] getCoefficients()
- {
- return mCoefficients;
- }
-
- @Override
- public void dispose()
- {
- mCoefficients = null;
- mIndexMap = null;
- mBuffer = null;
- }
-
- /**
- * Loads the sample into the circular buffer without calculating a filtered value.
- * @param sample to load
- */
- public void load(float sample)
- {
- mBuffer[mBufferPointer] = sample;
-
- mBufferPointer--;
-
- if(mBufferPointer < 0)
- {
- mBufferPointer += mBufferSize;
- }
- }
-
- /**
- * Loads the sample into the circular buffer and calculates a filtered sample output.
- * @param sample to load
- * @return filtered value
- */
- public float filter(float sample)
- {
- mBuffer[mBufferPointer] = sample;
-
- mAccumulator = 0.0f;
-
- for(int x = 0; x < mBufferSize; x++)
- {
- mAccumulator += mCoefficients[x] * mBuffer[mIndexMap[mBufferPointer][x]];
- }
-
- mBufferPointer--;
-
- if(mBufferPointer < 0)
- {
- mBufferPointer += mBufferSize;
- }
-
- /* Apply gain and return the filtered value */
- mAccumulator *= mGain;
-
- return mAccumulator;
- }
-
- /**
- * Current output value for the filter after the filter() method has been invoked.
- * @return
- */
- public float currentValue()
- {
- return mAccumulator;
- }
-
- /**
- * Generates a circular buffer index map to support lookup of the translated
- * index based on the current buffer pointer and the desired sample index.
- */
- private void generateIndexMap(int size)
- {
- mIndexMap = new int[size][size];
-
- for(int x = 0; x < size; x++)
- {
- for(int y = 0; y < size; y++)
- {
- int z = x + y;
-
- mIndexMap[x][y] = z < size ? z : z - size;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter_RB_RB.java b/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter_RB_RB.java
deleted file mode 100644
index 5f9a7669..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/fir/real/RealFIRFilter_RB_RB.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package io.github.dsheirer.dsp.filter.fir.real;
-
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.real.RealBuffer;
-
-@Deprecated //Use RealFIRFilter2 version instead
-public class RealFIRFilter_RB_RB extends RealFIRFilter
- implements Listener
-{
- private Listener mListener;
-
- /**
- * Real Buffer Float FIR filter with streaming float buffer provider and
- * listener interfaces.
- *
- * @param coefficients
- * @param gain
- */
- public RealFIRFilter_RB_RB( float[] coefficients, float gain )
- {
- super( coefficients, gain );
- }
-
- @Override
- public void dispose()
- {
- super.dispose();
-
- mListener = null;
- }
-
- @Override
- public void receive( RealBuffer buffer )
- {
- if( mListener != null )
- {
- mListener.receive( filter( buffer ) );
- }
- }
-
- /**
- * Filters the buffer samples
- *
- * @param buffer
- * @return
- */
- public RealBuffer filter( RealBuffer buffer )
- {
- float[] samples = buffer.getSamples();
-
- for( int x = 0; x < samples.length; x++ )
- {
- samples[ x ] = filter( samples[ x ] );
- }
-
- return buffer;
- }
-
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-
- public void removeListener()
- {
- mListener = null;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/halfband/complex/ComplexHalfBandFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/halfband/complex/ComplexHalfBandFilter.java
new file mode 100644
index 00000000..7684676e
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/dsp/filter/halfband/complex/ComplexHalfBandFilter.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * sdr-trunk
+ * Copyright (C) 2014-2018 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
+ *
+ ******************************************************************************/
+package io.github.dsheirer.dsp.filter.halfband.complex;
+
+import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter;
+import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
+
+public class ComplexHalfBandFilter
+{
+ private HalfBandFilter mIFilter;
+ private HalfBandFilter mQFilter;
+ private boolean mDecimate;
+ private boolean mDecimateFlag;
+
+ /**
+ * @param coefficients
+ * @param gain
+ * @param decimate
+ */
+ public ComplexHalfBandFilter(float[] coefficients, float gain, boolean decimate)
+ {
+ mIFilter = new HalfBandFilter(coefficients, gain);
+ mQFilter = new HalfBandFilter(coefficients, gain);
+ mDecimate = decimate;
+ }
+
+ public void dispose()
+ {
+ mIFilter.dispose();
+ mQFilter.dispose();
+ }
+
+ public ReusableComplexBuffer filter(ReusableComplexBuffer buffer)
+ {
+ throw new IllegalStateException("This filter has to be updated to work with reusable buffers");
+
+// if(mDecimate)
+// {
+// float[] samples = buffer.getSamples();
+//
+// int half = samples.length / 2;
+//
+// float[] decimated;
+//
+// if(half % 2 == 0 || mDecimateFlag)
+// {
+// decimated = new float[half];
+// }
+// else
+// {
+// /* If inbound buffer size is odd-length, then we have to
+// * adjust when the first operation is non-decimation, since
+// * that will produce an outbound buffer 1 sample larger */
+// decimated = new float[half + 1];
+// }
+//
+// int decimatedPointer = 0;
+//
+// for(int x = 0; x < samples.length; x += 2)
+// {
+// /* Insert the sample but don't filter */
+// if(mDecimateFlag)
+// {
+// mIFilter.insert(samples[x]);
+// mQFilter.insert(samples[x + 1]);
+// }
+// else
+// {
+// decimated[decimatedPointer++] = mIFilter.filter(samples[x]);
+// decimated[decimatedPointer++] = mQFilter.filter(samples[x + 1]);
+// }
+//
+// /* Toggle the decimation flag for every sample */
+// mDecimateFlag = !mDecimateFlag;
+// }
+//
+// //return buffer
+// }
+// else
+// {
+// /* Non Decimate - filter each of the values and return the buffer */
+// float[] samples = buffer.getSamples();
+//
+// for(int x = 0; x < samples.length; x += 2)
+// {
+// samples[x] = mIFilter.filter(samples[x]);
+// samples[x + 1] = mQFilter.filter(samples[x + 1]);
+// }
+//
+// //return buffer
+// }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/halfband/complex/HalfBandFilter_CB_CB.java b/src/main/java/io/github/dsheirer/dsp/filter/halfband/complex/HalfBandFilter_CB_CB.java
deleted file mode 100644
index 337077be..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/halfband/complex/HalfBandFilter_CB_CB.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package io.github.dsheirer.dsp.filter.halfband.complex;
-
-import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
-
-public class HalfBandFilter_CB_CB implements Listener
-{
- private HalfBandFilter mIFilter;
- private HalfBandFilter mQFilter;
-
- private boolean mDecimate;
- private boolean mDecimateFlag;
-
- private Listener mListener;
-
- /**
- *
- * @param coefficients
- * @param gain
- * @param decimate
- */
- public HalfBandFilter_CB_CB( float[] coefficients, float gain, boolean decimate )
- {
- mIFilter = new HalfBandFilter( coefficients, gain );
- mQFilter = new HalfBandFilter( coefficients, gain );
-
- mDecimate = decimate;
- }
-
- public void dispose()
- {
- mIFilter.dispose();
- mQFilter.dispose();
-
- mListener = null;
- }
-
- @Override
- public void receive( ComplexBuffer buffer )
- {
- if( mListener != null )
- {
- if( mDecimate )
- {
- float[] samples = buffer.getSamples();
-
- int half = samples.length / 2;
-
- float[] decimated;
-
- if( half % 2 == 0 || mDecimateFlag )
- {
- decimated = new float[ half ];
- }
- else
- {
- /* If inbound buffer size is odd-length, then we have to
- * adjust when the first operation is non-decimation, since
- * that will produce an outbound buffer 1 sample larger */
- decimated = new float[ half + 1 ];
- }
-
- int decimatedPointer = 0;
-
- for( int x = 0; x < samples.length; x += 2 )
- {
- /* Insert the sample but don't filter */
- if( mDecimateFlag )
- {
- mIFilter.insert( samples[ x ] );
- mQFilter.insert( samples[ x + 1 ] );
- }
- else
- {
- decimated[ decimatedPointer++ ] = mIFilter.filter( samples[ x ] );
- decimated[ decimatedPointer++ ] = mQFilter.filter( samples[ x + 1 ] );
- }
-
- /* Toggle the decimation flag for every sample */
- mDecimateFlag = !mDecimateFlag;
- }
-
- if( mListener != null )
- {
- mListener.receive( new ComplexBuffer( decimated ) );
- }
- }
- else
- {
- /* Non Decimate - filter each of the values and return the buffer */
- float[] samples = buffer.getSamples();
-
- for( int x = 0; x < samples.length; x += 2 )
- {
- samples[ x ] = mIFilter.filter( samples[ x ] );
- samples[ x + 1 ] = mQFilter.filter( samples[ x + 1 ] );
- }
-
- if( mListener != null )
- {
- mListener.receive( buffer );
- }
- }
- }
- }
-
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-
- public void removeListener()
- {
- mListener = null;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java
index 678cb8e5..21255f08 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter.java
@@ -1,162 +1,189 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
******************************************************************************/
package io.github.dsheirer.dsp.filter.halfband.real;
+import io.github.dsheirer.sample.buffer.ReusableBuffer;
+import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import org.apache.commons.lang3.Validate;
public class HalfBandFilter
{
- private float[] mBuffer;
+ private float[] mBuffer;
private int mBufferSize = 1; //Temporary initial value
- private int mBufferPointer = 0;
-
- private float mGain;
- private float[] mCoefficients;
- private int[][] mIndexMap;
-
- private int mCenterCoefficient;
- private int mCenterCoefficientMapIndex;
+ private int mBufferPointer = 0;
- /**
- * Half-Band filter for processing real float samples.
- *
- * Takes advantage of the 0-valued FIR half-band coefficents inherent
- * in the half-band filter and does not calculate those coefficients.
- *
- * This reduces the workload to (tap-size - 1) / 4 + 1 calculations per sample.
- *
- * @param filter - filter coefficients
- * @param gain - gain multiplier. Use 1.0 for unity/no gain
- */
- public HalfBandFilter( float[] coefficients, float gain )
- {
- mCoefficients = coefficients;
- mGain = gain;
-
- mBufferSize = mCoefficients.length;
- mBuffer = new float[ mBufferSize ];
-
- generateIndexMap( mCoefficients.length );
- }
+ private float mGain;
+ private float[] mCoefficients;
+ private int[][] mIndexMap;
- public void dispose()
- {
- }
+ private int mCenterCoefficient;
+ private int mCenterCoefficientMapIndex;
- /**
- * Inserts the sample into the buffer without calculating a filtered value
- */
- public void insert( float sample )
- {
- mBuffer[ mBufferPointer ] = sample;
+ private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("HalfBandFilter");
- mBufferPointer++;
-
- mBufferPointer = mBufferPointer % mBufferSize;
- }
+ /**
+ * Half-Band filter for processing real float samples.
+ *
+ * Takes advantage of the 0-valued FIR half-band coefficents inherent
+ * in the half-band filter and does not calculate those coefficients.
+ *
+ * This reduces the workload to (tap-size - 1) / 4 + 1 calculations per sample.
+ *
+ * @param filter - filter coefficients
+ * @param gain - gain multiplier. Use 1.0 for unity/no gain
+ */
+ public HalfBandFilter(float[] coefficients, float gain)
+ {
+ //TODO: update this to use SIMD structures with 2 float arrays and a toggle operation
- /**
- * Calculate the filtered value by applying the coefficients against
- * the complex samples in mBuffer
- */
- public float filter( float sample )
- {
- insert( sample );
-
- float accumulator = 0;
- //Start with the center tap value
- accumulator += mCoefficients[ mCenterCoefficient ] *
- mBuffer[ mIndexMap[ mBufferPointer ][ mCenterCoefficientMapIndex ] ];
-
- //For the remaining coefficients, add the symmetric samples, oldest and newest
- //first, then multiply by the single coefficient
- for( int x = 0; x < mCenterCoefficientMapIndex; x += 2 )
- {
- accumulator += mCoefficients[ x ] *
- ( mBuffer[ mIndexMap[ mBufferPointer ][ x ] ] +
- mBuffer[ mIndexMap[ mBufferPointer ][ x + 1 ] ] );
- }
+ mCoefficients = coefficients;
+ mGain = gain;
- return accumulator * mGain;
- }
-
- /**
- * Creates an n X (n + 1 / 2) index map enabling quick access to the
- * circular buffer samples.
- *
- * As the buffer shifts right with each subsequent sample, we have to move
- * the index pointers with it, for efficient access of the samples.
- *
- * The first array index value in the index map corresponds to the current
- * buffer pointer location.
- *
- * The second array index value points to the samples that should be
- * multiplied by the coefficients as follows:
- *
- * 0 = center tap sample, to be multiplied by center coefficient
- *
- * 0 = sample( 1 )
- * 1 = sample( size - 1 )
- *
- * Indexes 0 and 1 will be multiplied by coefficient( 0 ).
- *
- * Subsequent indexes 3, 4, etc, point to the oldest and newest samples that
- * correspond to the matching ( 3 ) coefficient index.
- *
- * @param odd-sized number of filter taps (ie coefficients) and buffer
- */
- private void generateIndexMap( int size )
- {
- //Ensure we have an odd size
- Validate.isTrue(size % 2 == 1);
+ mBufferSize = mCoefficients.length;
+ mBuffer = new float[mBufferSize];
- int mapWidth = ( ( size + 1 ) / 2 ) + 1;
-
- //Set center tap index for coefficients array
- mCenterCoefficient = ( size - 1 ) / 2;
- mCenterCoefficientMapIndex = mCenterCoefficient + 1;
+ generateIndexMap(mCoefficients.length);
+ }
- mIndexMap = new int[ size ][ mapWidth ];
+ public HalfBandFilter(float[] coefficients, float gain, boolean decimate)
+ {
+ this(coefficients, gain);
- //Setup the first row, buffer pointer index 0, as a starting point
- for( int x = 0; x < mapWidth - 2; x += 2 )
- {
- mIndexMap[ 0 ][ x ] = x;
- mIndexMap[ 0 ][ x + 1 ] = size - 1 - x;
- }
+ throw new IllegalStateException("This filter must be updated to support non-decimate option");
+ }
- //Place center tap index in last element
- mIndexMap[ 0 ][ mCenterCoefficientMapIndex ] = mCenterCoefficient;
-
- //For each subsequent row, increment the previous row's value by 1,
- //subtracting size as needed, to keep the values between 0 and size - 1
- for( int x = 1; x < size; x++ )
- {
- for( int y = 0; y < mapWidth; y++ )
- {
- mIndexMap[ x ][ y ] = mIndexMap[ x - 1 ][ y ] + 1;
-
- if( mIndexMap[ x ][ y ] >= size )
- {
- mIndexMap[ x ][ y ] -= size;
- }
- }
- }
- }
+ public void dispose()
+ {
+ }
+
+ /**
+ * Inserts the sample into the buffer without calculating a filtered value
+ */
+ public void insert(float sample)
+ {
+ mBuffer[mBufferPointer] = sample;
+
+ mBufferPointer++;
+
+ mBufferPointer = mBufferPointer % mBufferSize;
+ }
+
+ public ReusableBuffer filter(ReusableBuffer input)
+ {
+ float[] inputSamples = input.getSamples();
+ ReusableBuffer output = mReusableBufferQueue.getBuffer(inputSamples.length);
+ float[] outputSamples = output.getSamples();
+
+ for(int x = 0; x < inputSamples.length; x++)
+ {
+ outputSamples[x] = filter(inputSamples[x]);
+ }
+
+ output.incrementUserCount();
+ input.decrementUserCount();
+
+ return output;
+ }
+
+ /**
+ * Calculate the filtered value by applying the coefficients against the samples in mBuffer
+ */
+ public float filter(float sample)
+ {
+ insert(sample);
+
+ float accumulator = 0;
+
+ //Start with the center tap value
+ accumulator += mCoefficients[mCenterCoefficient] * mBuffer[mIndexMap[mBufferPointer][mCenterCoefficientMapIndex]];
+
+ //For the remaining coefficients, add the symmetric samples, oldest and newest
+ //first, then multiply by the single coefficient
+ for(int x = 0; x < mCenterCoefficientMapIndex; x += 2)
+ {
+ accumulator += mCoefficients[x] * (mBuffer[mIndexMap[mBufferPointer][x]] + mBuffer[mIndexMap[mBufferPointer][x + 1]]);
+ }
+
+ return accumulator * mGain;
+ }
+
+ /**
+ * Creates an n X (n + 1 / 2) index map enabling quick access to the
+ * circular buffer samples.
+ *
+ * As the buffer shifts right with each subsequent sample, we have to move
+ * the index pointers with it, for efficient access of the samples.
+ *
+ * The first array index value in the index map corresponds to the current
+ * buffer pointer location.
+ *
+ * The second array index value points to the samples that should be
+ * multiplied by the coefficients as follows:
+ *
+ * 0 = center tap sample, to be multiplied by center coefficient
+ *
+ * 0 = sample( 1 )
+ * 1 = sample( size - 1 )
+ *
+ * Indexes 0 and 1 will be multiplied by coefficient( 0 ).
+ *
+ * Subsequent indexes 3, 4, etc, point to the oldest and newest samples that
+ * correspond to the matching ( 3 ) coefficient index.
+ *
+ * @param odd-sized number of filter taps (ie coefficients) and buffer
+ */
+ private void generateIndexMap(int size)
+ {
+ //Ensure we have an odd size
+ Validate.isTrue(size % 2 == 1);
+
+ int mapWidth = ((size + 1) / 2) + 1;
+
+ //Set center tap index for coefficients array
+ mCenterCoefficient = (size - 1) / 2;
+ mCenterCoefficientMapIndex = mCenterCoefficient + 1;
+
+ mIndexMap = new int[size][mapWidth];
+
+ //Setup the first row, buffer pointer index 0, as a starting point
+ for(int x = 0; x < mapWidth - 2; x += 2)
+ {
+ mIndexMap[0][x] = x;
+ mIndexMap[0][x + 1] = size - 1 - x;
+ }
+
+ //Place center tap index in last element
+ mIndexMap[0][mCenterCoefficientMapIndex] = mCenterCoefficient;
+
+ //For each subsequent row, increment the previous row's value by 1,
+ //subtracting size as needed, to keep the values between 0 and size - 1
+ for(int x = 1; x < size; x++)
+ {
+ for(int y = 0; y < mapWidth; y++)
+ {
+ mIndexMap[x][y] = mIndexMap[x - 1][y] + 1;
+
+ if(mIndexMap[x][y] >= size)
+ {
+ mIndexMap[x][y] -= size;
+ }
+ }
+ }
+ }
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter_RB_RB.java b/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter_RB_RB.java
deleted file mode 100644
index 914d9f2b..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/halfband/real/HalfBandFilter_RB_RB.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package io.github.dsheirer.dsp.filter.halfband.real;
-
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.real.RealBuffer;
-
-public class HalfBandFilter_RB_RB extends HalfBandFilter implements Listener
-{
- private boolean mDecimate;
- private boolean mDecimateFlag;
- private Listener mListener;
-
- /**
- * Halfband filter for real buffers with optional decimation by two.
- *
- * If this filter is used in non-decimating mode, the filter will overwrite
- * the inbound sample buffer with the filtered samples. This will cause
- * issues if the buffers are being used across several processes are sharing
- * the buffer, since this filter will modify the contents of the object, so
- * consider making a copy of the buffer prior to feeding the buffer to this
- * filter.
- *
- * If used in decimating mode, a new (half-length) buffer will be created
- * for the filtered samples.
- *
- * @param coefficients - filter kernel
- * @param gain - gain to apply to the outputs
- * @param decimate - true for decimate by 2, or false for no decimation
- */
- public HalfBandFilter_RB_RB( float[] coefficients, float gain, boolean decimate )
- {
- super( coefficients, gain );
-
- mDecimate = decimate;
- }
-
- public void dispose()
- {
- super.dispose();
-
- mListener = null;
- }
-
- @Override
- public void receive( RealBuffer buffer )
- {
- if( mListener != null )
- {
- mListener.receive( filter( buffer ) );
- }
- }
-
- public RealBuffer filter( RealBuffer buffer )
- {
- if( mDecimate )
- {
- float[] samples = buffer.getSamples();
-
- int half = samples.length / 2;
-
- float[] decimated;
-
- if( half % 2 == 0 || mDecimateFlag )
- {
- decimated = new float[ half ];
- }
- else
- {
- /* If inbound buffer size is odd-length, then we have to
- * adjust when the first operation is non-decimation, since
- * that will produce an outbound buffer 1 sample larger */
- decimated = new float[ half + 1 ];
- }
-
- int decimatedPointer = 0;
-
- for( float sample: samples )
- {
- /* Insert the sample but don't filter */
- if( mDecimateFlag )
- {
- insert( sample );
- }
- else
- {
- decimated[ decimatedPointer++ ] = filter( sample );
- }
-
- /* Toggle the decimation flag for every sample */
- mDecimateFlag = !mDecimateFlag;
- }
-
- return new RealBuffer( decimated );
- }
- else
- {
- /* Non Decimate - filter each of the values and return the buffer */
- float[] samples = buffer.getSamples();
-
- for( int x = 0; x < samples.length; x++ )
- {
- samples[ x ] = filter( samples[ x ] );
- }
-
- return buffer;
- }
- }
-
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-
- public void removeListener()
- {
- mListener = null;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/HilbertTransform.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/HilbertTransform.java
index 973ee726..98894616 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/HilbertTransform.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/HilbertTransform.java
@@ -1,281 +1,245 @@
+/*******************************************************************************
+ * sdr-trunk
+ * Copyright (C) 2014-2018 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
+ *
+ ******************************************************************************/
package io.github.dsheirer.dsp.filter.hilbert;
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2015 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
- ******************************************************************************/
-
import io.github.dsheirer.dsp.filter.Filters;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
-import io.github.dsheirer.sample.real.RealBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
-public class HilbertTransform implements Listener
+public class HilbertTransform
{
- private static final Logger mLog = LoggerFactory.getLogger( HilbertTransform.class );
+ private static final Logger mLog = LoggerFactory.getLogger(HilbertTransform.class);
- private float[] mHilbertFilter;
-
- private Listener mListener;
-
- private float[] mBuffer;
+ private float[] mHilbertFilter;
+ private float[] mBuffer;
private int mBufferSize;
- private int mBufferPointer;
-
- private int[][] mIndexMap;
- private int mMapHeight;
- private int mCenterTapIndex;
- private float mCenterCoefficent;
-
- private boolean mInvertFlag = false;
-
- /**
- * Hilbert transform filter used for converting real-valued samples into
- * complex valued samples using frequency translation (FS/4) and a half-band
- * filter.
- *
- * This filter uses a circular sample buffer and a pre-calculated
- * index map to correctly map the filter coefficients to the circular delay
- * buffer contents as each new sample is added to the buffer and processed.
- *
- * Half-band filter coefficients used in this filter must be of length N
- * where (N + 1) is a multiple of 4. This filter uses a pre-defined half
- * band filter with 47 coefficients.
- *
- * This transform process is described in Understanding Digital Signal
- * Processing, Lyons, 3e, 2011, sections 13.1.2 and 13.1.3 (p 674-678) and
- * implemented as described in Section 13.37.1 and 13.37.2 (p 802-804)
- */
- public HilbertTransform()
- {
- convertHalfBandToHilbert( Filters.HALF_BAND_FILTER_47T.getCoefficients() );
-
- mBufferSize = mHilbertFilter.length + 1;
- mBuffer = new float[ mBufferSize ];
-
- mCenterCoefficent = mHilbertFilter[ mHilbertFilter.length / 2 ];
+ private int mBufferPointer;
+ private int[][] mIndexMap;
+ private int mMapHeight;
+ private int mCenterTapIndex;
+ private float mCenterCoefficent;
- generateIndexMap( mHilbertFilter.length );
- }
+ private boolean mInvertFlag = false;
- @Override
- public void receive( RealBuffer buffer )
- {
- if( mListener != null )
- {
- mListener.receive( filter( buffer ) );
- }
- }
-
- /**
- * Sets the listener to receive filtered complex buffers.
- */
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-
- /**
- * Applies Hilbert transform to the real sample buffer and returns a
- * complex sample buffer
- */
- public ComplexBuffer filter( RealBuffer buffer )
- {
- return new ComplexBuffer( filter( buffer.getSamples() ) );
- }
+ /**
+ * Hilbert transform filter used for converting real-valued samples into
+ * complex valued samples using frequency translation (FS/4) and a half-band
+ * filter.
+ *
+ * This filter uses a circular sample buffer and a pre-calculated
+ * index map to correctly map the filter coefficients to the circular delay
+ * buffer contents as each new sample is added to the buffer and processed.
+ *
+ * Half-band filter coefficients used in this filter must be of length N
+ * where (N + 1) is a multiple of 4. This filter uses a pre-defined half
+ * band filter with 47 coefficients.
+ *
+ * This transform process is described in Understanding Digital Signal
+ * Processing, Lyons, 3e, 2011, sections 13.1.2 and 13.1.3 (p 674-678) and
+ * implemented as described in Section 13.37.1 and 13.37.2 (p 802-804)
+ */
+ public HilbertTransform()
+ {
+ convertHalfBandToHilbert(Filters.HALF_BAND_FILTER_47T.getCoefficients());
- /**
- * Filters the continuous real-sample stream by treating the stream as a
- * set of interleaved values and applying two hilbert filters against each
- * interleaved set (I & Q). Frequency translation has already been
- * pre-applied to the hilbert filter coefficients.
- *
- * Filtering of the inphase component is a simple multiply by the center
- * coefficient (0.5) since all of the other coefficients are zero-valued.
- *
- * Filtering of the quadrature component uses a folded FIR structure and
- * expects the hilbert coefficients to be symmetric with all negative valued
- * coefficients below the center coefficient and all positive-valued coefficients
- * above the center coefficient. So, convolution only applies the filter
- * coefficient against the difference of the two samples.
- *
- * ( coefficient * value1 ) + (-coefficient * value2 ) = coefficient * ( value1 - value2 )
- *
- * Performs frequency translation by FS/2 on the final filtered values by
- * applying a sequence of 1,-1 (sign change) to each I/Q output sample.
- */
- public float[] filter( float[] samples )
- {
- float accumulator;
+ mBufferSize = mHilbertFilter.length + 1;
+ mBuffer = new float[mBufferSize];
- for( int y = 0; y < samples.length; y +=2 )
- {
- insert( samples[ y ] );
- insert( samples[ y + 1 ] );
-
- accumulator = 0.0f;
+ mCenterCoefficent = mHilbertFilter[mHilbertFilter.length / 2];
- int index = mBufferPointer / 2;
+ generateIndexMap(mHilbertFilter.length);
+ }
- for( int x = 0; x < mHilbertFilter.length / 2; x += 2 )
- {
- accumulator += mHilbertFilter[ x ] *
- ( mBuffer[ mIndexMap[ index ][ x + 1] ] -
- mBuffer[ mIndexMap[ index ][ x ] ] );
- }
+ /**
+ * Filters the continuous real-sample stream by treating the stream as a
+ * set of interleaved values and applying two hilbert filters against each
+ * interleaved set (I & Q). Frequency translation has already been
+ * pre-applied to the hilbert filter coefficients.
+ *
+ * Filtering of the inphase component is a simple multiply by the center
+ * coefficient (0.5) since all of the other coefficients are zero-valued.
+ *
+ * Filtering of the quadrature component uses a folded FIR structure and
+ * expects the hilbert coefficients to be symmetric with all negative valued
+ * coefficients below the center coefficient and all positive-valued coefficients
+ * above the center coefficient. So, convolution only applies the filter
+ * coefficient against the difference of the two samples.
+ *
+ * ( coefficient * value1 ) + (-coefficient * value2 ) = coefficient * ( value1 - value2 )
+ *
+ * Performs frequency translation by FS/2 on the final filtered values by
+ * applying a sequence of 1,-1 (sign change) to each I/Q output sample.
+ */
+ public float[] filter(float[] samples)
+ {
+ float accumulator;
- //Perform FS/2 frequency translation on the final filtered values
- if( mInvertFlag )
- {
- //inphase
- samples[ y ] = -( mBuffer[ mIndexMap[ index ][ mCenterTapIndex ] ] );
+ for(int y = 0; y < samples.length; y += 2)
+ {
+ insert(samples[y]);
+ insert(samples[y + 1]);
- //quadrature
- samples[ y + 1 ] = -accumulator;
- }
- else
- {
- //inphase
- samples[ y ] = mBuffer[ mIndexMap[ index ][ mCenterTapIndex ] ];
+ accumulator = 0.0f;
- //quadrature
- samples[ y + 1 ] = accumulator;
- }
-
- mInvertFlag = !mInvertFlag;
- }
-
- return samples;
- }
-
- /**
- * Inserts the sample into the circular buffer, overwriting the oldest value
- */
- private void insert( float sample )
- {
- mBuffer[ mBufferPointer++ ] = sample;
+ int index = mBufferPointer / 2;
- mBufferPointer = mBufferPointer % mBufferSize;
- }
-
- /**
- * Creates an index map to support efficient lookup of sample indexes from
- * the circular buffer.
- *
- * The first index of the map corresponds to the current buffer pointer
- * setting.
- *
- * The second index is structured in sample pairs to align with
- * the hilbert filter coefficients. For example, the first iteration of
- * the filter would use filter coefficient 0 and the index map values 0 and
- * 1 would be pointing to samples 46 and 0.
- *
- * The final element of each index set is the index of the center sample.
- */
- private void generateIndexMap( int size )
- {
- mMapHeight = size / 2 + 1;
- int mapWidth = mMapHeight + 1;
-
- mIndexMap = new int[ mMapHeight ][ mapWidth ];
+ for(int x = 0; x < mHilbertFilter.length / 2; x += 2)
+ {
+ accumulator += mHilbertFilter[x] *
+ (mBuffer[mIndexMap[index][x + 1]] -
+ mBuffer[mIndexMap[index][x]]);
+ }
- //Setup the first row with buffer pointer index 0 as a starting point
- for( int x = 0; x < mapWidth - 1; x += 2 )
- {
- mIndexMap[ 0 ][ x ] = size - 1 - x;
- mIndexMap[ 0 ][ x + 1 ] = x;
- }
-
- //Place the center index at the end of the array
- mCenterTapIndex = mapWidth - 1;
-
- mIndexMap[ 0 ][ mCenterTapIndex ] = size / 2;
+ //Perform FS/2 frequency translation on the final filtered values
+ if(mInvertFlag)
+ {
+ //inphase
+ samples[y] = -(mBuffer[mIndexMap[index][mCenterTapIndex]]);
- //For each subsequent row, increment the previous row's value by 2,
- //wrapping as needed, to keep the values between 0 and size - 1
- for( int x = 1; x < mMapHeight; x++ )
- {
- for( int y = 0; y < mapWidth; y++ )
- {
- mIndexMap[ x ][ y ] = mIndexMap[ x - 1 ][ y ] + 2;
-
- if( mIndexMap[ x ][ y ] >= size )
- {
- mIndexMap[ x ][ y ] -= size + 1;
+ //quadrature
+ samples[y + 1] = -accumulator;
+ }
+ else
+ {
+ //inphase
+ samples[y] = mBuffer[mIndexMap[index][mCenterTapIndex]];
- //Special handling for center tap wrap around
- if( y == mCenterTapIndex && mIndexMap[ x ][ y ] < 0 )
- {
- mIndexMap[ x ][ y ] = size;
- }
- }
- }
- }
- }
+ //quadrature
+ samples[y + 1] = accumulator;
+ }
- /**
- * Logs the index map contents
- */
- public void logIndexMap()
- {
- for( int[] indexSet: mIndexMap )
- {
- mLog.debug( "Row:" + Arrays.toString( indexSet ) );
- }
- }
+ mInvertFlag = !mInvertFlag;
+ }
- /**
- * Converts the half-band filter coefficients for use as hilbert transform
- * filter coefficients. Sets all even-numbered coefficients left of center
- * to negative and all even-numbered coefficients right of center to positive
- * which applies a FS/4 frequency translation to the coefficients.
- *
- * Note: even though the coefficients above the center coefficient are being
- * defined, they are unused during the convolution process since we're using
- * a folded FIR structure to exploit the symmetric nature of the half-band
- * filter coefficients. The polarity difference between the upper and lower
- * halves is accounted for in the filter() method.
- *
- * Note: we apply a 2.0 gain to the coefficients to compensate for the loss
- * of splitting the signal via two filters.
- */
- private void convertHalfBandToHilbert( float[] coefficients )
- {
- mHilbertFilter = new float[ coefficients.length ];
-
- int middle = coefficients.length / 2;
-
- for( int x = 0; x < coefficients.length; x++ )
- {
- if( x < middle )
- {
- mHilbertFilter[ x ] = 2.0f * -Math.abs( coefficients[ x ] );
- }
- else if( x > middle )
- {
- mHilbertFilter[ x ] = 2.0f * Math.abs( coefficients[ x ] );
- }
- else
- {
- mHilbertFilter[ x ] = 2.0f * coefficients[ x ];
- }
- }
- }
+ return samples;
+ }
+
+ /**
+ * Inserts the sample into the circular buffer, overwriting the oldest value
+ */
+ private void insert(float sample)
+ {
+ mBuffer[mBufferPointer++] = sample;
+
+ mBufferPointer = mBufferPointer % mBufferSize;
+ }
+
+ /**
+ * Creates an index map to support efficient lookup of sample indexes from
+ * the circular buffer.
+ *
+ * The first index of the map corresponds to the current buffer pointer
+ * setting.
+ *
+ * The second index is structured in sample pairs to align with
+ * the hilbert filter coefficients. For example, the first iteration of
+ * the filter would use filter coefficient 0 and the index map values 0 and
+ * 1 would be pointing to samples 46 and 0.
+ *
+ * The final element of each index set is the index of the center sample.
+ */
+ private void generateIndexMap(int size)
+ {
+ mMapHeight = size / 2 + 1;
+ int mapWidth = mMapHeight + 1;
+
+ mIndexMap = new int[mMapHeight][mapWidth];
+
+ //Setup the first row with buffer pointer index 0 as a starting point
+ for(int x = 0; x < mapWidth - 1; x += 2)
+ {
+ mIndexMap[0][x] = size - 1 - x;
+ mIndexMap[0][x + 1] = x;
+ }
+
+ //Place the center index at the end of the array
+ mCenterTapIndex = mapWidth - 1;
+
+ mIndexMap[0][mCenterTapIndex] = size / 2;
+
+ //For each subsequent row, increment the previous row's value by 2,
+ //wrapping as needed, to keep the values between 0 and size - 1
+ for(int x = 1; x < mMapHeight; x++)
+ {
+ for(int y = 0; y < mapWidth; y++)
+ {
+ mIndexMap[x][y] = mIndexMap[x - 1][y] + 2;
+
+ if(mIndexMap[x][y] >= size)
+ {
+ mIndexMap[x][y] -= size + 1;
+
+ //Special handling for center tap wrap around
+ if(y == mCenterTapIndex && mIndexMap[x][y] < 0)
+ {
+ mIndexMap[x][y] = size;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Logs the index map contents
+ */
+ public void logIndexMap()
+ {
+ for(int[] indexSet : mIndexMap)
+ {
+ mLog.debug("Row:" + Arrays.toString(indexSet));
+ }
+ }
+
+ /**
+ * Converts the half-band filter coefficients for use as hilbert transform
+ * filter coefficients. Sets all even-numbered coefficients left of center
+ * to negative and all even-numbered coefficients right of center to positive
+ * which applies a FS/4 frequency translation to the coefficients.
+ *
+ * Note: even though the coefficients above the center coefficient are being
+ * defined, they are unused during the convolution process since we're using
+ * a folded FIR structure to exploit the symmetric nature of the half-band
+ * filter coefficients. The polarity difference between the upper and lower
+ * halves is accounted for in the filter() method.
+ *
+ * Note: we apply a 2.0 gain to the coefficients to compensate for the loss
+ * of splitting the signal via two filters.
+ */
+ private void convertHalfBandToHilbert(float[] coefficients)
+ {
+ mHilbertFilter = new float[coefficients.length];
+
+ int middle = coefficients.length / 2;
+
+ for(int x = 0; x < coefficients.length; x++)
+ {
+ if(x < middle)
+ {
+ mHilbertFilter[x] = 2.0f * -Math.abs(coefficients[x]);
+ }
+ else if(x > middle)
+ {
+ mHilbertFilter[x] = 2.0f * Math.abs(coefficients[x]);
+ }
+ else
+ {
+ mHilbertFilter[x] = 2.0f * coefficients[x];
+ }
+ }
+ }
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/InterpolatingHilbertTransform.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/InterpolatingHilbertTransform.java
deleted file mode 100644
index 75f7b9f2..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/InterpolatingHilbertTransform.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package io.github.dsheirer.dsp.filter.hilbert;
-
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2015 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
- *
- * ----------------------------------------------------------------------------
- * Half-band filter coefficients retrieved October 2015 from:
- * https://github.com/airspy/host/libairspy/src/filters.h
- *
- * Copyright (C) 2014, Youssef Touil
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- ******************************************************************************/
-
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
-import io.github.dsheirer.sample.real.RealBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Arrays;
-
-public class InterpolatingHilbertTransform implements Listener
-{
- private static final Logger mLog = LoggerFactory.getLogger( InterpolatingHilbertTransform.class );
-
- private static final float[] HALF_BAND_FILTER =
- {
- -0.000998606272947510f, 0.0f, 0.001695637278417295f, 0.0f,
- -0.003054430179754289f, 0.0f, 0.005055504379767936f, 0.0f,
- -0.007901319195893647f, 0.0f, 0.011873357051047719f, 0.0f,
- -0.017411159379930066f, 0.0f, 0.025304817427568772f, 0.0f,
- -0.037225225204559217f, 0.0f, 0.057533286997004301f, 0.0f,
- -0.102327462004259350f, 0.0f, 0.317034472508947400f, 0.5f,
- 0.317034472508947400f, 0.0f, -0.102327462004259350f, 0.0f,
- 0.057533286997004301f, 0.0f, -0.037225225204559217f, 0.0f,
- 0.025304817427568772f, 0.0f, -0.017411159379930066f, 0.0f,
- 0.011873357051047719f, 0.0f, -0.007901319195893647f, 0.0f,
- 0.005055504379767936f, 0.0f, -0.003054430179754289f, 0.0f,
- 0.001695637278417295f, 0.0f, -0.000998606272947510f
- };
-
- private static final float GAIN = 2.0f;
-
- private Listener mListener;
-
- private float[] mBuffer;
- private int mBufferSize;
- private int mBufferPointer;
- private int mGroupDelayedInphaseTapPointIndex;
-
- private float[] mCoefficients;
- private int[][] mIndexMap;
-
-
- /**
- * Hilbert transform filter used for converting real-valued samples into
- * complex valued samples using frequency translation (FS/4) and a half-band
- * filter.
- *
- * This filter uses a circular sample buffer and a pre-calculated
- * index map to correctly map the filter coefficients to the circular delay
- * buffer contents as each new sample is added to the buffer and processed.
- *
- * Half-band filter coefficients used in this filter must be of length N
- * where (N + 1) is a multiple of 4. This filter uses a pre-defined half
- * band filter with 47 coefficients.
- *
- * This transform process is described in Understanding Digital Signal
- * Processing, Lyons, 3e, 2011, sections 13.1.2 and 13.1.3 (p 674-678) and
- * implemented as described in Section 13.37.1 and 13.37.2 (p 802-804)
- */
- public InterpolatingHilbertTransform()
- {
- mBufferSize = HALF_BAND_FILTER.length;
- mBuffer = new float[ mBufferSize ];
-
- createHilbertCoefficients();
-
- generateIndexMap( mBufferSize );
- }
-
- @Override
- public void receive( RealBuffer buffer )
- {
- if( mListener != null )
- {
- mListener.receive( filter( buffer ) );
- }
- }
-
- /**
- * Sets the listener to receive filtered complex buffers.
- */
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-
- /**
- * Applies Hilbert transform to the real sample buffer and returns a
- * complex sample buffer
- */
- public ComplexBuffer filter( RealBuffer buffer )
- {
- return new ComplexBuffer( filter( buffer.getSamples() ) );
- }
-
- /**
- * Applies a hilbert transform to an array of real samples and returns an
- * array twice as long containing I,Q,I,Q ... complex samples
- */
- public float[] filter( float[] samples )
- {
- float[] filtered = new float[ samples.length * 2 ];
-
- float accumulator;
-
- for( int y = 0; y < samples.length; y++ )
- {
- insert( samples[ y ] );
-
- accumulator = 0.0f;
-
- for( int x = 0; x < mCoefficients.length; x++ )
- {
- accumulator += mCoefficients[ x ] *
- mBuffer[ mIndexMap[ mBufferPointer ][ x ] ] ;
- }
-
- int index = y * 2;
-
- /* We use the buffered sample at the half group delay point as the
- * Inphase value and the accumulator as the quadrature value */
- filtered[ index ] = mBuffer[ mIndexMap[ mBufferPointer ]
- [ mGroupDelayedInphaseTapPointIndex ] ];
-
- filtered[ index + 1 ] = accumulator;
- }
-
- return filtered;
- }
-
- /**
- * Inserts the sample into the circular buffer, overwriting the oldest value
- */
- private void insert( float sample )
- {
- mBuffer[ mBufferPointer ] = sample;
-
- mBufferPointer++;
-
- mBufferPointer = mBufferPointer % mBufferSize;
- }
-
-
- /**
- * Creates an N x (N + 1 / 2) index map enabling quick access to the
- * circular buffer samples to support convolution.
- *
- * As the buffer pointer shifts right, as each sample is added, we use the
- * index map pointed to by the buffer pointer, so that the filter coefficients
- * are pointing to the correct circular buffer samples.
- *
- * We add an extra index to each index map with a value that points to the
- * current index of the middle sample in the buffer, so that we can retrieve
- * that value as the half-group delayed sample that forms the inphase
- * component.
- */
- private void generateIndexMap( int size )
- {
- int mapWidth = ( ( size + 1 ) / 2 ) + 1;
-
- int center = ( size - 1 ) / 2;
-
- //Set center tap index for coefficients array
- mGroupDelayedInphaseTapPointIndex = center + 1;
-
- mIndexMap = new int[ size ][ mapWidth ];
-
- //Setup the first row with buffer pointer index 0 as a starting point
- for( int x = 0; x < mapWidth - 1; x++ )
- {
- mIndexMap[ 0 ][ x ] = size - 1 - ( x * 2 );
- }
-
- //Place the group delayed in-phase sample tap point in last element of
- //the first row
- mIndexMap[ 0 ][ mGroupDelayedInphaseTapPointIndex ] = center;
-
- //For each subsequent row, increment the previous row's value by 1,
- //subtracting size as needed, to keep the values between 0 and size - 1
- for( int x = 1; x < size; x++ )
- {
- for( int y = 0; y < mapWidth; y++ )
- {
- mIndexMap[ x ][ y ] = mIndexMap[ x - 1 ][ y ] + 1;
-
- if( mIndexMap[ x ][ y ] >= size )
- {
- mIndexMap[ x ][ y ] -= size;
- }
- }
- }
- }
-
- public void logIndexMap()
- {
- for( int[] indexSet: mIndexMap )
- {
- mLog.debug( "Row:" + Arrays.toString( indexSet ) );
- }
- }
-
- /**
- * Converts the half-band filter coefficients into a packed set of hilbert
- * coefficients by removing all of the odd index, zero-valued coefficients
- * and the center 0.5 coefficient. Then, all coefficients left of the
- * original center are made negative and all coefficients right of the
- * original center are made positive. These coefficient sign modifications
- * effectively incorporate a frequency translation by FS/4 into the hilbert
- * coefficients. A gain of 2.0 is applied to the coefficients to offset the
- * gain of 0.5 induced by the filter.
- */
- private void createHilbertCoefficients()
- {
- int half = ( HALF_BAND_FILTER.length + 1 ) / 2;
- int middle = half / 2;
-
- mCoefficients = new float[ half ];
-
- /* Pack all of the even numbered HB coefficients into our coefficient
- * array and pre-apply a gain of two to offset the loss in the filter */
- for( int x = 0; x < half; x++ )
- {
- mCoefficients[ x ] = HALF_BAND_FILTER[ x * 2 ] * GAIN;
-
- /* Make all of the left of center coefficients negative */
- if( x < middle && mCoefficients[ x ] > 0.0f )
- {
- mCoefficients[ x ] = -mCoefficients[ x ];
- }
- /* Make all of the right of center coefficients positive */
- else if( x >= middle && mCoefficients[ x ] < 0.0f )
- {
- mCoefficients[ x ] = -mCoefficients[ x ];
- }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/iir/DeemphasisFilter.java b/src/main/java/io/github/dsheirer/dsp/filter/iir/DeemphasisFilter.java
index ea14ac02..601f4a38 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/iir/DeemphasisFilter.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/iir/DeemphasisFilter.java
@@ -1,7 +1,20 @@
+/*******************************************************************************
+ * sdr-trunk
+ * Copyright (C) 2014-2018 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
+ *
+ ******************************************************************************/
package io.github.dsheirer.dsp.filter.iir;
-import io.github.dsheirer.sample.real.RealBuffer;
-
public class DeemphasisFilter
{
private static final float MAX_SAMPLE_VALUE = 0.95f;
@@ -45,16 +58,4 @@ public class DeemphasisFilter
return samples;
}
-
- public RealBuffer filter( RealBuffer buffer )
- {
- float[] samples = buffer.getSamples();
-
- for( int x = 0; x < samples.length; x++ )
- {
- samples[ x ] = filter( samples[ x ] );
- }
-
- return buffer;
- }
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java b/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java
index 3cb99948..48f2bf4b 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java
@@ -19,7 +19,6 @@ import io.github.dsheirer.buffer.FloatCircularBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
import io.github.dsheirer.sample.complex.Complex;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
import io.github.dsheirer.sample.complex.ComplexSampleListener;
public class ComplexFeedForwardGainControl implements ComplexSampleListener
@@ -137,17 +136,6 @@ public class ComplexFeedForwardGainControl implements ComplexSampleListener
return processed;
}
- /**
- * Applies gain to the complex sample buffer
- * @param buffer to apply gain
- * @return buffer with gain applied samples
- */
- public ComplexBuffer filter(ComplexBuffer buffer)
- {
- float[] filtered = filter(buffer.getSamples());
- return new ComplexBuffer(filtered);
- }
-
/**
* Applies gain to the complex sample buffer
* @param buffer to apply gain
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/NonClippingGain.java b/src/main/java/io/github/dsheirer/dsp/gain/NonClippingGain.java
index ebfab2df..612e284f 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/NonClippingGain.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/NonClippingGain.java
@@ -1,7 +1,5 @@
package io.github.dsheirer.dsp.gain;
-import io.github.dsheirer.sample.real.RealBuffer;
-
public class NonClippingGain
{
private float mGain;
@@ -50,16 +48,4 @@ public class NonClippingGain
return samples;
}
-
- /**
- * Applies gain to the real buffer
- */
- public RealBuffer apply( RealBuffer buffer )
- {
- float[] samples = buffer.getSamples();
-
- apply( samples );
-
- return buffer;
- }
}
diff --git a/src/main/java/io/github/dsheirer/gui/channelizer/SynthesizerViewer.java b/src/main/java/io/github/dsheirer/gui/channelizer/SynthesizerViewer.java
index 14e9aedf..5875990c 100644
--- a/src/main/java/io/github/dsheirer/gui/channelizer/SynthesizerViewer.java
+++ b/src/main/java/io/github/dsheirer/gui/channelizer/SynthesizerViewer.java
@@ -21,11 +21,11 @@ import io.github.dsheirer.dsp.filter.design.FilterDesignException;
import io.github.dsheirer.dsp.mixer.FS4DownConverter;
import io.github.dsheirer.dsp.mixer.IOscillator;
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
diff --git a/src/main/java/io/github/dsheirer/module/ProcessingChain.java b/src/main/java/io/github/dsheirer/module/ProcessingChain.java
index 11de7e21..c517a9b7 100644
--- a/src/main/java/io/github/dsheirer/module/ProcessingChain.java
+++ b/src/main/java/io/github/dsheirer/module/ProcessingChain.java
@@ -54,11 +54,6 @@ import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
-import io.github.dsheirer.sample.real.IFilteredRealBufferListener;
-import io.github.dsheirer.sample.real.IFilteredRealBufferProvider;
-import io.github.dsheirer.sample.real.IUnFilteredRealBufferListener;
-import io.github.dsheirer.sample.real.IUnFilteredRealBufferProvider;
-import io.github.dsheirer.sample.real.RealBuffer;
import io.github.dsheirer.source.ComplexSource;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.ISourceEventProvider;
@@ -97,18 +92,16 @@ public class ProcessingChain implements IChannelEventListener
{
private final static Logger mLog = LoggerFactory.getLogger(ProcessingChain.class);
- private Broadcaster mAttributeChangeRequestBroadcaster = new Broadcaster<>();
private ReusableBufferBroadcaster mAudioPacketBroadcaster = new ReusableBufferBroadcaster<>();
+ private ReusableBufferBroadcaster mDemodulatedAudioBufferBroadcaster = new ReusableBufferBroadcaster();
+ private ReusableBufferBroadcaster mBasebandComplexBufferBroadcaster = new ReusableBufferBroadcaster();
+ private Broadcaster mAttributeChangeRequestBroadcaster = new Broadcaster<>();
private Broadcaster mCallEventBroadcaster = new Broadcaster<>();
private Broadcaster mChannelEventBroadcaster = new Broadcaster<>();
- private ReusableBufferBroadcaster mComplexBufferBroadcaster = new ReusableBufferBroadcaster();
- private ReusableBufferBroadcaster mDemodulatedAudioBufferBroadcaster = new ReusableBufferBroadcaster();
private Broadcaster mDecoderStateEventBroadcaster = new Broadcaster<>();
private Broadcaster mHeartbeatBroadcaster = new Broadcaster<>();
private Broadcaster mSourceEventBroadcaster = new Broadcaster<>();
private Broadcaster mMessageBroadcaster = new Broadcaster<>();
- private Broadcaster mFilteredRealBufferBroadcaster = new Broadcaster<>();
- private Broadcaster mUnFilteredRealBufferBroadcaster = new Broadcaster<>();
private Broadcaster mSquelchStateBroadcaster = new Broadcaster<>();
private AtomicBoolean mRunning = new AtomicBoolean();
@@ -169,9 +162,8 @@ public class ProcessingChain implements IChannelEventListener
mAudioPacketBroadcaster.dispose();
mCallEventBroadcaster.dispose();
mChannelEventBroadcaster.dispose();
- mComplexBufferBroadcaster.dispose();
+ mBasebandComplexBufferBroadcaster.dispose();
mMessageBroadcaster.dispose();
- mFilteredRealBufferBroadcaster.dispose();
mSquelchStateBroadcaster.dispose();
}
@@ -316,11 +308,6 @@ public class ProcessingChain implements IChannelEventListener
mDecoderStateEventBroadcaster.addListener(((IDecoderStateEventListener) module).getDecoderStateListener());
}
- if(module instanceof IFilteredRealBufferListener)
- {
- mFilteredRealBufferBroadcaster.addListener(((IFilteredRealBufferListener) module).getFilteredRealBufferListener());
- }
-
if(module instanceof IHeartbeatListener)
{
mHeartbeatBroadcaster.addListener(((IHeartbeatListener)module).getHeartbeatListener());
@@ -338,7 +325,7 @@ public class ProcessingChain implements IChannelEventListener
if(module instanceof IReusableComplexBufferListener)
{
- mComplexBufferBroadcaster.addListener(((IReusableComplexBufferListener)module).getReusableComplexBufferListener());
+ mBasebandComplexBufferBroadcaster.addListener(((IReusableComplexBufferListener)module).getReusableComplexBufferListener());
}
if(module instanceof ISourceEventListener)
@@ -355,11 +342,6 @@ public class ProcessingChain implements IChannelEventListener
{
mSquelchStateBroadcaster.addListener(((ISquelchStateListener) module).getSquelchStateListener());
}
-
- if(module instanceof IUnFilteredRealBufferListener)
- {
- mUnFilteredRealBufferBroadcaster.addListener(((IUnFilteredRealBufferListener) module).getUnFilteredRealBufferListener());
- }
}
/**
@@ -393,11 +375,6 @@ public class ProcessingChain implements IChannelEventListener
mDecoderStateEventBroadcaster.removeListener(((IDecoderStateEventListener) module).getDecoderStateListener());
}
- if(module instanceof IFilteredRealBufferListener)
- {
- mFilteredRealBufferBroadcaster.removeListener(((IFilteredRealBufferListener) module).getFilteredRealBufferListener());
- }
-
if(module instanceof IHeartbeatListener)
{
mHeartbeatBroadcaster.removeListener(((IHeartbeatListener)module).getHeartbeatListener());
@@ -410,7 +387,7 @@ public class ProcessingChain implements IChannelEventListener
if(module instanceof IReusableComplexBufferListener)
{
- mComplexBufferBroadcaster.removeListener(((IReusableComplexBufferListener) module).getReusableComplexBufferListener());
+ mBasebandComplexBufferBroadcaster.removeListener(((IReusableComplexBufferListener) module).getReusableComplexBufferListener());
}
if(module instanceof ISourceEventListener)
@@ -427,11 +404,6 @@ public class ProcessingChain implements IChannelEventListener
{
mSquelchStateBroadcaster.removeListener(((ISquelchStateListener) module).getSquelchStateListener());
}
-
- if(module instanceof IUnFilteredRealBufferListener)
- {
- mUnFilteredRealBufferBroadcaster.removeListener(((IUnFilteredRealBufferListener) module).getUnFilteredRealBufferListener());
- }
}
/**
@@ -475,11 +447,6 @@ public class ProcessingChain implements IChannelEventListener
((IMessageProvider) module).setMessageListener(mMessageBroadcaster);
}
- if(module instanceof IFilteredRealBufferProvider)
- {
- ((IFilteredRealBufferProvider) module).setFilteredRealBufferListener(mFilteredRealBufferBroadcaster);
- }
-
if(module instanceof IMessageProvider)
{
((IMessageProvider) module).setMessageListener(mMessageBroadcaster);
@@ -499,11 +466,6 @@ public class ProcessingChain implements IChannelEventListener
{
((ISquelchStateProvider) module).setSquelchStateListener(mSquelchStateBroadcaster);
}
-
- if(module instanceof IUnFilteredRealBufferProvider)
- {
- ((IUnFilteredRealBufferProvider) module).setUnFilteredRealBufferListener(mUnFilteredRealBufferBroadcaster);
- }
}
/**
@@ -547,11 +509,6 @@ public class ProcessingChain implements IChannelEventListener
((IMessageProvider) module).setMessageListener(null);
}
- if(module instanceof IFilteredRealBufferProvider)
- {
- ((IFilteredRealBufferProvider) module).setFilteredRealBufferListener(null);
- }
-
if(module instanceof IMessageProvider)
{
((IMessageProvider) module).setMessageListener(null);
@@ -571,11 +528,6 @@ public class ProcessingChain implements IChannelEventListener
{
((ISquelchStateProvider) module).setSquelchStateListener(null);
}
-
- if(module instanceof IUnFilteredRealBufferProvider)
- {
- ((IUnFilteredRealBufferProvider) module).setUnFilteredRealBufferListener(null);
- }
}
/**
@@ -609,7 +561,7 @@ public class ProcessingChain implements IChannelEventListener
switch(mSource.getSampleType())
{
case COMPLEX:
- ((ComplexSource) mSource).setListener(mComplexBufferBroadcaster);
+ ((ComplexSource) mSource).setListener(mBasebandComplexBufferBroadcaster);
break;
case REAL:
((RealSource) mSource).setListener(mDemodulatedAudioBufferBroadcaster);
@@ -657,7 +609,7 @@ public class ProcessingChain implements IChannelEventListener
switch(mSource.getSampleType())
{
case COMPLEX:
- ((ComplexSource) mSource).removeListener(mComplexBufferBroadcaster);
+ ((ComplexSource) mSource).removeListener(mBasebandComplexBufferBroadcaster);
break;
case REAL:
((RealSource) mSource).removeListener(mDemodulatedAudioBufferBroadcaster);
@@ -796,6 +748,9 @@ public class ProcessingChain implements IChannelEventListener
}
}
+ /**
+ * Removes the listener from receiving decoded messages from all decoders.
+ */
public void removeMessageListener(Listener listener)
{
mMessageBroadcaster.removeListener(listener);
@@ -832,14 +787,20 @@ public class ProcessingChain implements IChannelEventListener
mSquelchStateBroadcaster.removeListener(listener);
}
- public void addRealBufferListener(Listener listener)
+ /**
+ * Adds listener to receive demodulated audio buffers from an modules that produce demodulated audio.
+ */
+ public void addDemodulatedAudioListener(Listener listener)
{
- mFilteredRealBufferBroadcaster.addListener(listener);
+ mDemodulatedAudioBufferBroadcaster.addListener(listener);
}
- public void removeRealBufferListener(Listener listener)
+ /**
+ * Removes the listener from receiving demodulated audio buffers.
+ */
+ public void removeDemodulatedAudioListener(Listener listener)
{
- mFilteredRealBufferBroadcaster.removeListener(listener);
+ mDemodulatedAudioBufferBroadcaster.removeListener(listener);
}
@Override
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java
index 5f3d4215..3bf17098 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java
@@ -2,13 +2,13 @@ package io.github.dsheirer.module.decode.p25;
import io.github.dsheirer.dsp.gain.DirectGainControl;
import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.real.RealBuffer;
+import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.real.RealSampleListener;
import io.github.dsheirer.sample.real.RealSampleProvider;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.SourceEvent;
-public class C4FMSymbolFilter implements Listener, ISourceEventListener, RealSampleProvider
+public class C4FMSymbolFilter implements Listener, ISourceEventListener, RealSampleProvider
{
private static final float TAPS[][] =
{
@@ -215,7 +215,7 @@ public class C4FMSymbolFilter implements Listener, ISourceEventListe
}
@Override
- public void receive(RealBuffer buffer)
+ public void receive(ReusableBuffer buffer)
{
for(float sample : buffer.getSamples())
{
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java
index de5766dd..8c3851ac 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java
@@ -1,3 +1,18 @@
+/*******************************************************************************
+ * sdr-trunk
+ * Copyright (C) 2014-2018 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
+ *
+ ******************************************************************************/
package io.github.dsheirer.module.decode.p25.audio;
import io.github.dsheirer.audio.AudioFormats;
diff --git a/src/main/java/io/github/dsheirer/record/RecorderManager.java b/src/main/java/io/github/dsheirer/record/RecorderManager.java
index c3be7605..d6351867 100644
--- a/src/main/java/io/github/dsheirer/record/RecorderManager.java
+++ b/src/main/java/io/github/dsheirer/record/RecorderManager.java
@@ -20,10 +20,10 @@ import io.github.dsheirer.channel.metadata.Metadata;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.record.wave.AudioPacketWaveRecorder;
import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.OverflowableTransferQueue;
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/github/dsheirer/sample/ConversionUtils.java b/src/main/java/io/github/dsheirer/sample/ConversionUtils.java
index 9cc988ff..57b08bd8 100644
--- a/src/main/java/io/github/dsheirer/sample/ConversionUtils.java
+++ b/src/main/java/io/github/dsheirer/sample/ConversionUtils.java
@@ -1,7 +1,6 @@
package io.github.dsheirer.sample;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
-import io.github.dsheirer.sample.real.RealBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -53,24 +52,6 @@ public class ConversionUtils
return converted;
}
- /**
- * Converts the float samples in a complex buffer to a little endian 16-bit
- * buffer
- */
- public static ByteBuffer convertToSigned16BitSamples(Buffer buffer)
- {
- return convertToSigned16BitSamples(buffer.getSamples());
- }
-
- /**
- * Converts the float samples in a complex buffer to a little endian 16-bit
- * buffer
- */
- public static ByteBuffer convertToSigned16BitSamples(RealBuffer buffer)
- {
- return convertToSigned16BitSamples(buffer.getSamples());
- }
-
/**
* Converts the float samples in a complex buffer to a little endian 16-bit
* buffer
diff --git a/src/main/java/io/github/dsheirer/sample/complex/ComplexBuffer.java b/src/main/java/io/github/dsheirer/sample/IOverflowListener.java
similarity index 76%
rename from src/main/java/io/github/dsheirer/sample/complex/ComplexBuffer.java
rename to src/main/java/io/github/dsheirer/sample/IOverflowListener.java
index edc3d4ce..209bf74f 100644
--- a/src/main/java/io/github/dsheirer/sample/complex/ComplexBuffer.java
+++ b/src/main/java/io/github/dsheirer/sample/IOverflowListener.java
@@ -13,17 +13,13 @@
* If not, see
*
******************************************************************************/
-package io.github.dsheirer.sample.complex;
+package io.github.dsheirer.sample;
-import io.github.dsheirer.sample.Buffer;
-
-public class ComplexBuffer extends Buffer
+public interface IOverflowListener
{
/**
- * Wrapper around float array containing interleaved I/Q samples
+ * Indicates that the source is in overflow state (true) or out of overflow state (false)
+ * @param overflow true to indicate an overflow state
*/
- public ComplexBuffer(float[] samples)
- {
- super(samples);
- }
+ void sourceOverflow(boolean overflow);
}
diff --git a/src/main/java/io/github/dsheirer/sample/OverflowableTransferQueue.java b/src/main/java/io/github/dsheirer/sample/OverflowableTransferQueue.java
index c342ac3f..b125a442 100644
--- a/src/main/java/io/github/dsheirer/sample/OverflowableTransferQueue.java
+++ b/src/main/java/io/github/dsheirer/sample/OverflowableTransferQueue.java
@@ -18,7 +18,6 @@
******************************************************************************/
package io.github.dsheirer.sample;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.source.Source;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java
index 111c33cb..d6e17209 100644
--- a/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java
+++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableBufferAssembler.java
@@ -15,131 +15,66 @@
******************************************************************************/
package io.github.dsheirer.sample.buffer;
-import io.github.dsheirer.dsp.filter.channelizer.SampleTimestampManager;
import io.github.dsheirer.sample.Listener;
-import org.apache.commons.lang3.Validate;
-
-import java.nio.FloatBuffer;
+import io.github.dsheirer.sample.real.RealSampleListener;
/**
- * Assembles complex float samples into a ComplexBuffer containing an array of floats. Monitors incoming sample count
- * to accurately assign a relative timestamp to each assembled buffer.
+ * Assembles single float samples into a ReusableBuffer containing an array of floats
*/
-public class ReusableBufferAssembler
+public class ReusableBufferAssembler implements RealSampleListener
{
- private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ReusableBufferAssembler");
- private SampleTimestampManager mTimestampManager;
- private FloatBuffer mBuffer;
private int mBufferSize;
- private long mCurrentBufferTimestamp;
- private Listener mListener;
+ private int mBufferPointer;
+ private ReusableBuffer mCurrentBuffer;
+ private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("Real");
- public ReusableBufferAssembler(int bufferSize, double sampleRate)
+ private Listener mListener;
+
+ public ReusableBufferAssembler(int bufferSize)
{
- Validate.isTrue(bufferSize % 2 == 0);
mBufferSize = bufferSize;
- mBuffer = FloatBuffer.allocate(mBufferSize);
- mTimestampManager = new SampleTimestampManager(sampleRate);
- }
-
- /**
- * Updates the reference timestamp to use for all subsequent samples that are assembled. This timestamp should
- * identify the relative timestamp of the first/next sample that is received by this assembler.
- * @param timestamp to use relative to the incoming sample arrays.
- */
- public void updateTimestamp(long timestamp)
- {
- mTimestampManager.setReferenceTimestamp(timestamp);
-
- if(mBuffer.position() == 0)
- {
- mCurrentBufferTimestamp = timestamp;
- }
}
public void dispose()
{
- mReusableComplexBufferQueue.dispose();
mListener = null;
}
- /**
- * Adds the samples to this assembler. As each buffer is assembled, it will be dispatched to the registered
- * listener.
- *
- * @param samples to assemble
- */
- public void receive(float[] samples)
+ public void reset()
{
- if(mBuffer.remaining() >= samples.length)
- {
- mBuffer.put(samples);
- mTimestampManager.increment(samples.length / 2);
+ mCurrentBuffer.decrementUserCount();
+ mCurrentBuffer = null;
+ mBufferPointer = 0;
+ }
- if(!mBuffer.hasRemaining())
+ @Override
+ public void receive(float sample)
+ {
+ if(mCurrentBuffer == null)
+ {
+ mCurrentBuffer = mReusableBufferQueue.getBuffer(mBufferSize);
+ mCurrentBuffer.incrementUserCount();
+ mBufferPointer = 0;
+ }
+
+ mCurrentBuffer.getSamples()[mBufferPointer++] = sample;
+
+ if (mBufferPointer >= mBufferSize)
+ {
+ if (mListener != null)
{
- flush();
+ mListener.receive(mCurrentBuffer);
}
- }
- else
- {
- int offset = 0;
-
- while(offset < samples.length)
+ else
{
- int toCopy = mBuffer.remaining();
-
- if((samples.length - offset) < toCopy)
- {
- toCopy = samples.length - offset;
- }
-
- mBuffer.put(samples, offset, toCopy);
-
- offset += toCopy;
- mTimestampManager.increment(toCopy / 2);
-
- if(!mBuffer.hasRemaining())
- {
- flush();
- }
+ mCurrentBuffer.decrementUserCount();
}
+
+ mCurrentBuffer = null;
}
}
- /**
- * Adds the samples to this assembler. As each buffer is assembled, it will be dispatched to the registered
- * listener.
- */
- public void receive(ReusableComplexBuffer samplesBuffer)
- {
- receive(samplesBuffer.getSamples());
- samplesBuffer.decrementUserCount();
- }
-
- /**
- * Flushes the current buffer contents to the registered listener
- */
- public void flush()
- {
- if(mListener != null && mBuffer.position() > 0)
- {
- mBuffer.rewind();
- ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mBufferSize);
- reusableComplexBuffer.reloadFrom(mBuffer, mCurrentBufferTimestamp);
- reusableComplexBuffer.incrementUserCount();
- mListener.receive(reusableComplexBuffer);
- }
-
- mBuffer.rewind();
- mCurrentBufferTimestamp = mTimestampManager.getCurrentTimestamp();
- }
-
- /**
- * Sets the listener to receive the output from this buffer assembler. Note: the listener is responsible for
- * managing the user count for any buffers received from this buffer assembler.
- */
- public void setListener(Listener listener)
+ public void setListener(Listener listener)
{
mListener = listener;
}
diff --git a/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferAssembler.java b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferAssembler.java
new file mode 100644
index 00000000..7e1fbaee
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/sample/buffer/ReusableComplexBufferAssembler.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * sdr-trunk
+ * Copyright (C) 2014-2018 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
+ *
+ ******************************************************************************/
+package io.github.dsheirer.sample.buffer;
+
+import io.github.dsheirer.dsp.filter.channelizer.SampleTimestampManager;
+import io.github.dsheirer.sample.Listener;
+import org.apache.commons.lang3.Validate;
+
+import java.nio.FloatBuffer;
+
+/**
+ * Assembles complex float samples into a ComplexBuffer containing an array of floats. Monitors incoming sample count
+ * to accurately assign a relative timestamp to each assembled buffer.
+ */
+public class ReusableComplexBufferAssembler
+{
+ private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ReusableComplexBufferAssembler");
+ private SampleTimestampManager mTimestampManager;
+ private FloatBuffer mBuffer;
+ private int mBufferSize;
+ private long mCurrentBufferTimestamp;
+ private Listener mListener;
+
+ public ReusableComplexBufferAssembler(int bufferSize, double sampleRate)
+ {
+ Validate.isTrue(bufferSize % 2 == 0);
+ mBufferSize = bufferSize;
+ mBuffer = FloatBuffer.allocate(mBufferSize);
+ mTimestampManager = new SampleTimestampManager(sampleRate);
+ }
+
+ /**
+ * Updates the reference timestamp to use for all subsequent samples that are assembled. This timestamp should
+ * identify the relative timestamp of the first/next sample that is received by this assembler.
+ * @param timestamp to use relative to the incoming sample arrays.
+ */
+ public void updateTimestamp(long timestamp)
+ {
+ mTimestampManager.setReferenceTimestamp(timestamp);
+
+ if(mBuffer.position() == 0)
+ {
+ mCurrentBufferTimestamp = timestamp;
+ }
+ }
+
+ public void dispose()
+ {
+ mReusableComplexBufferQueue.dispose();
+ mListener = null;
+ }
+
+ /**
+ * Adds the samples to this assembler. As each buffer is assembled, it will be dispatched to the registered
+ * listener.
+ *
+ * @param samples to assemble
+ */
+ public void receive(float[] samples)
+ {
+ if(mBuffer.remaining() >= samples.length)
+ {
+ mBuffer.put(samples);
+ mTimestampManager.increment(samples.length / 2);
+
+ if(!mBuffer.hasRemaining())
+ {
+ flush();
+ }
+ }
+ else
+ {
+ int offset = 0;
+
+ while(offset < samples.length)
+ {
+ int toCopy = mBuffer.remaining();
+
+ if((samples.length - offset) < toCopy)
+ {
+ toCopy = samples.length - offset;
+ }
+
+ mBuffer.put(samples, offset, toCopy);
+
+ offset += toCopy;
+ mTimestampManager.increment(toCopy / 2);
+
+ if(!mBuffer.hasRemaining())
+ {
+ flush();
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds the samples to this assembler. As each buffer is assembled, it will be dispatched to the registered
+ * listener.
+ */
+ public void receive(ReusableComplexBuffer samplesBuffer)
+ {
+ receive(samplesBuffer.getSamples());
+ samplesBuffer.decrementUserCount();
+ }
+
+ /**
+ * Flushes the current buffer contents to the registered listener
+ */
+ public void flush()
+ {
+ if(mListener != null && mBuffer.position() > 0)
+ {
+ mBuffer.rewind();
+ ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(mBufferSize);
+ reusableComplexBuffer.reloadFrom(mBuffer, mCurrentBufferTimestamp);
+ reusableComplexBuffer.incrementUserCount();
+ mListener.receive(reusableComplexBuffer);
+ }
+
+ mBuffer.rewind();
+ mCurrentBufferTimestamp = mTimestampManager.getCurrentTimestamp();
+ }
+
+ /**
+ * Sets the listener to receive the output from this buffer assembler. Note: the listener is responsible for
+ * managing the user count for any buffers received from this buffer assembler.
+ */
+ public void setListener(Listener listener)
+ {
+ mListener = listener;
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/sample/complex/ComplexBufferToStreamConverter.java b/src/main/java/io/github/dsheirer/sample/complex/ComplexBufferToStreamConverter.java
deleted file mode 100644
index 9a13b4da..00000000
--- a/src/main/java/io/github/dsheirer/sample/complex/ComplexBufferToStreamConverter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.github.dsheirer.sample.complex;
-
-import io.github.dsheirer.sample.Listener;
-
-/**
- * Real sample buffer to stream converter
- */
-public class ComplexBufferToStreamConverter implements Listener
-{
- private ComplexSampleListener mListener;
-
- public void dispose()
- {
- mListener = null;
- }
-
- @Override
- public void receive( ComplexBuffer buffer )
- {
- if( mListener != null )
- {
- float[] samples = buffer.getSamples();
-
- for( int x = 0; x < samples.length; x += 2 )
- {
- mListener.receive( samples[ x ], samples[ x + 1 ] );
- }
- }
- }
-
- public void setListener( ComplexSampleListener listener )
- {
- mListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/sample/complex/ComplexToComplexBufferAssembler.java b/src/main/java/io/github/dsheirer/sample/complex/ComplexToComplexBufferAssembler.java
deleted file mode 100644
index 88cdb58b..00000000
--- a/src/main/java/io/github/dsheirer/sample/complex/ComplexToComplexBufferAssembler.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2015 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- ******************************************************************************/
-package io.github.dsheirer.sample.complex;
-
-import io.github.dsheirer.sample.Listener;
-import org.apache.commons.lang3.Validate;
-
-/**
- * Assembles complex float samples into a ComplexBuffer containing an array of floats
- */
-public class ComplexToComplexBufferAssembler implements ComplexSampleListener
-{
- private int mBufferSize;
- private float[] mBuffer;
- private int mBufferPointer;
-
- private Listener mListener;
-
- public ComplexToComplexBufferAssembler( int bufferSize )
- {
- Validate.isTrue(bufferSize % 2 == 0);
-
- mBufferSize = bufferSize;
- mBuffer = new float[ mBufferSize ];
- }
-
- public void dispose()
- {
- mListener = null;
- mBuffer = null;
- }
-
- public void reset()
- {
- mBuffer = new float[ mBufferSize ];
- mBufferPointer = 0;
- }
-
- @Override
- public void receive( float i, float q )
- {
- if( mBufferPointer >= mBufferSize )
- {
- if( mListener != null )
- {
- mListener.receive( new ComplexBuffer( mBuffer ) );
- }
-
- mBuffer = new float[ mBufferSize ];
- mBufferPointer = 0;
- }
-
- mBuffer[ mBufferPointer ] = i;
-
- mBufferPointer++;
-
- mBuffer[ mBufferPointer ] = q;
-
- mBufferPointer++;
- }
-
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/sample/complex/RateCounter_CB.java b/src/main/java/io/github/dsheirer/sample/complex/RateCounter_CB.java
deleted file mode 100644
index 433b6653..00000000
--- a/src/main/java/io/github/dsheirer/sample/complex/RateCounter_CB.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package io.github.dsheirer.sample.complex;
-
-import io.github.dsheirer.sample.Listener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RateCounter_CB implements Listener
-{
- private final static Logger mLog =
- LoggerFactory.getLogger( RateCounter_CB.class );
-
- private Listener mListener;
- private long mCount;
- private long mStartTime = -1;
-
- private String mName;
-
- public RateCounter_CB()
- {
- mName = "UNNAMED";
- }
-
- public RateCounter_CB( String name )
- {
- mName = name;
- }
-
- @Override
- public void receive( ComplexBuffer buffer )
- {
- if( mStartTime == -1 )
- {
- mStartTime = System.currentTimeMillis();
- }
-
- mCount += ( buffer.getSamples().length / 2 );
-
- long elapsed = System.currentTimeMillis() - mStartTime;
-
- if( elapsed != 0 )
- {
- mLog.debug( "[" + mName + "] Sample Rate: " + ( mCount / elapsed ) + " kHz" );
- }
-
- if( mListener != null )
- {
- mListener.receive( buffer );
- }
- }
-
- public void setListener( Listener listener )
- {
- mListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/IFilteredRealBufferListener.java b/src/main/java/io/github/dsheirer/sample/real/IFilteredRealBufferListener.java
deleted file mode 100644
index 11465aea..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/IFilteredRealBufferListener.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package io.github.dsheirer.sample.real;
-
-import io.github.dsheirer.sample.Listener;
-
-public interface IFilteredRealBufferListener
-{
- public Listener getFilteredRealBufferListener();
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/IFilteredRealBufferProvider.java b/src/main/java/io/github/dsheirer/sample/real/IFilteredRealBufferProvider.java
deleted file mode 100644
index ead47fae..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/IFilteredRealBufferProvider.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.github.dsheirer.sample.real;
-
-import io.github.dsheirer.sample.Listener;
-
-public interface IFilteredRealBufferProvider
-{
- public void setFilteredRealBufferListener( Listener listener );
- public void removeFilteredRealBufferListener();
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/IOverflowListener.java b/src/main/java/io/github/dsheirer/sample/real/IOverflowListener.java
deleted file mode 100644
index 79930e64..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/IOverflowListener.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*******************************************************************************
- * sdrtrunk
- * Copyright (C) 2014-2017 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.sample.real;
-
-public interface IOverflowListener
-{
- /**
- * Indicates that the source is in overflow state (true) or out of overflow state (false)
- * @param overflow true to indicate an overflow state
- */
- void sourceOverflow(boolean overflow);
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/IUnFilteredRealBufferListener.java b/src/main/java/io/github/dsheirer/sample/real/IUnFilteredRealBufferListener.java
deleted file mode 100644
index 52a1e35b..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/IUnFilteredRealBufferListener.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package io.github.dsheirer.sample.real;
-
-import io.github.dsheirer.sample.Listener;
-
-public interface IUnFilteredRealBufferListener
-{
- public Listener getUnFilteredRealBufferListener();
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/IUnFilteredRealBufferProvider.java b/src/main/java/io/github/dsheirer/sample/real/IUnFilteredRealBufferProvider.java
deleted file mode 100644
index 90100395..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/IUnFilteredRealBufferProvider.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.github.dsheirer.sample.real;
-
-import io.github.dsheirer.sample.Listener;
-
-public interface IUnFilteredRealBufferProvider
-{
- public void setUnFilteredRealBufferListener( Listener listener );
- public void removeUnFilteredRealBufferListener();
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/RealBuffer.java b/src/main/java/io/github/dsheirer/sample/real/RealBuffer.java
deleted file mode 100644
index 7050e1bf..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/RealBuffer.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.sample.real;
-
-import io.github.dsheirer.sample.Buffer;
-
-import java.util.Arrays;
-
-public class RealBuffer extends Buffer
-{
- /**
- * Wrapper around float array containing real float samples
- */
- public RealBuffer(float[] samples)
- {
- super(samples);
- }
-
- /**
- * Creates a deep copy of the buffer and a shallow (reference) copy of the source event
- */
- public RealBuffer copyOf()
- {
- float[] copy = Arrays.copyOf(getSamples(), getSamples().length);
-
- return new RealBuffer(copy);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/sample/real/RealToRealBufferAssembler.java b/src/main/java/io/github/dsheirer/sample/real/RealToRealBufferAssembler.java
deleted file mode 100644
index 08e07783..00000000
--- a/src/main/java/io/github/dsheirer/sample/real/RealToRealBufferAssembler.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2015 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- ******************************************************************************/
-package io.github.dsheirer.sample.real;
-
-import io.github.dsheirer.sample.Listener;
-
-/**
- * Assembles single float samples into a RealBuffer containing an array of floats
- */
-public class RealToRealBufferAssembler implements RealSampleListener
-{
- private int mBufferSize;
- private float[] mBuffer;
- private int mBufferPointer;
-
- private Listener mListener;
-
- public RealToRealBufferAssembler(int bufferSize)
- {
- mBufferSize = bufferSize;
- mBuffer = new float[mBufferSize];
- }
-
- public void dispose()
- {
- mListener = null;
- mBuffer = null;
- }
-
- public void reset()
- {
- mBuffer = new float[mBufferSize];
- mBufferPointer = 0;
- }
-
- @Override
- public void receive(float sample)
- {
- mBuffer[mBufferPointer++] = sample;
-
- if (mBufferPointer >= mBufferSize)
- {
- if (mListener != null)
- {
- mListener.receive(new RealBuffer(mBuffer));
- }
-
- mBuffer = new float[mBufferSize];
- mBufferPointer = 0;
- }
- }
-
- public void setListener(Listener listener)
- {
- mListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/source/Source.java b/src/main/java/io/github/dsheirer/source/Source.java
index 404a2cec..5e378606 100644
--- a/src/main/java/io/github/dsheirer/source/Source.java
+++ b/src/main/java/io/github/dsheirer/source/Source.java
@@ -18,8 +18,8 @@
package io.github.dsheirer.source;
import io.github.dsheirer.module.Module;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.SampleType;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.source.heartbeat.HeartbeatManager;
import io.github.dsheirer.source.heartbeat.IHeartbeatProvider;
diff --git a/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java b/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java
index 51c68e44..4e58e197 100644
--- a/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java
+++ b/src/main/java/io/github/dsheirer/source/mixer/ComplexMixer.java
@@ -38,7 +38,7 @@ 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 ComplexBuffer.
+ * @param complexSampleAdapter - adapter to convert byte array data read from the mixer into ReusableComplexBuffer.
*/
public ComplexMixer(TargetDataLine targetDataLine, AudioFormat format, String name,
ComplexSampleAdapter complexSampleAdapter)
diff --git a/src/main/java/io/github/dsheirer/source/tuner/channel/CICTunerChannelSource.java b/src/main/java/io/github/dsheirer/source/tuner/channel/CICTunerChannelSource.java
index efddbc58..ac6e5b4f 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/channel/CICTunerChannelSource.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/channel/CICTunerChannelSource.java
@@ -20,11 +20,11 @@ import io.github.dsheirer.dsp.filter.Window;
import io.github.dsheirer.dsp.filter.cic.ComplexPrimeCICDecimate;
import io.github.dsheirer.dsp.mixer.IOscillator;
import io.github.dsheirer.dsp.mixer.Oscillator;
-import io.github.dsheirer.sample.Buffer;
import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.OverflowableTransferQueue;
+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.ComplexBuffer;
import io.github.dsheirer.source.tuner.Tuner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,12 +45,12 @@ public class CICTunerChannelSource
private static double CHANNEL_RATE = 48000.0;
private static int CHANNEL_PASS_FREQUENCY = 12000;
- private OverflowableTransferQueue mBuffer;
-
+ private OverflowableReusableBufferTransferQueue mBuffer;
+ private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("CICTunerChannelSource");
private IOscillator mFrequencyCorrectionMixer;
private ComplexPrimeCICDecimate mDecimationFilter;
- private Listener mListener;
- private List mSampleBuffers = new ArrayList();
+ private Listener mListener;
+ private List mSampleBuffers = new ArrayList<>();
private long mTunerFrequency = 0;
private double mTunerSampleRate;
private long mChannelFrequencyCorrection = 0;
@@ -68,7 +68,7 @@ public class CICTunerChannelSource
*/
public CICTunerChannelSource(Tuner tuner, TunerChannel tunerChannel)
{
- mBuffer = new OverflowableTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD);
+ mBuffer = new OverflowableReusableBufferTransferQueue<>(BUFFER_MAX_CAPACITY, BUFFER_OVERFLOW_RESET_THRESHOLD);
// mBuffer.setSourceOverflowListener(this);
//Setup the frequency translator to the current source frequency
@@ -120,12 +120,12 @@ public class CICTunerChannelSource
* Primary input method for receiving complex sample buffers from the wideband source (ie tuner)
* @param buffer to receive and eventually process
*/
- public void receive(ComplexBuffer buffer)
+ public void receive(ReusableComplexBuffer buffer)
{
mBuffer.offer(buffer);
}
- public void setListener(Listener listener)
+ public void setListener(Listener listener)
{
/* Save a pointer to the listener so that if we have to change the
* decimation filter, we can re-add the listener */
@@ -134,7 +134,7 @@ public class CICTunerChannelSource
mDecimationFilter.setListener(listener);
}
- public void removeListener(Listener listener)
+ public void removeListener(Listener listener)
{
mDecimationFilter.removeListener();
}
@@ -181,14 +181,13 @@ public class CICTunerChannelSource
{
mBuffer.drainTo(mSampleBuffers, 20);
- for(Buffer buffer : mSampleBuffers)
+ for(ReusableComplexBuffer buffer : mSampleBuffers)
{
float[] samples = buffer.getSamples();
- /* We make a copy of the buffer so that we don't affect
- * anyone else that is using the same buffer, like other
- * channels or the spectral display */
- float[] translated = new float[samples.length];
+ ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(samples.length);
+ reusableComplexBuffer.incrementUserCount();
+ float[] translated = reusableComplexBuffer.getSamples();
/* Perform frequency translation */
for(int x = 0; x < samples.length; x += 2)
@@ -206,8 +205,10 @@ public class CICTunerChannelSource
if(filter != null)
{
- filter.receive(new ComplexBuffer(translated));
+ filter.receive(reusableComplexBuffer);
}
+
+ buffer.decrementUserCount();
}
mSampleBuffers.clear();
diff --git a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java
index fb565cf1..6d91aa7a 100644
--- a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java
+++ b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java
@@ -21,12 +21,13 @@ import io.github.dsheirer.controller.channel.ChannelEventListener;
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
import io.github.dsheirer.dsp.filter.Filters;
import io.github.dsheirer.dsp.filter.Window.WindowType;
-import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter_RB_RB;
+import io.github.dsheirer.dsp.filter.halfband.real.HalfBandFilter;
import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
+import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.buffer.ReusableComplexBufferQueue;
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
import io.github.dsheirer.settings.ColorSettingMenuItem;
@@ -74,7 +75,7 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
private int mSampleBufferSize = 2400;
- private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB(
+ private HalfBandFilter mDecimatingFilter = new HalfBandFilter(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true);
private AtomicBoolean mEnabled = new AtomicBoolean();
@@ -215,8 +216,7 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
if(processingChain != null)
{
-// processingChain.addRealBufferListener(this);
-
+ processingChain.addDemodulatedAudioListener(this);
mDFTProcessor.start();
}
}
@@ -226,12 +226,11 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
{
if(mCurrentChannel != null && mCurrentChannel.isProcessing())
{
- ProcessingChain processingChain = mChannelProcessingManager
- .getProcessingChain(mCurrentChannel);
+ ProcessingChain processingChain = mChannelProcessingManager.getProcessingChain(mCurrentChannel);
if(processingChain != null)
{
-// processingChain.removeRealBufferListener(this);
+ processingChain.removeDemodulatedAudioListener(this);
}
}
@@ -270,15 +269,14 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
@Override
public void receive(ReusableBuffer buffer)
{
- throw new IllegalStateException("This must be updated to work with reusable buffers");
-// RealBuffer decimated = mDecimatingFilter.filter(buffer);
-//
-// //Hack: we're placing real samples in a complex buffer that the DFT
-// //processor is expecting.
-// ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(decimated.getSamples().length);
-// reusableComplexBuffer.reloadFrom(decimated.getSamples(), System.currentTimeMillis());
-// reusableComplexBuffer.incrementUserCount();
-// mDFTProcessor.receive(reusableComplexBuffer);
+ ReusableBuffer decimated = mDecimatingFilter.filter(buffer);
+
+ //Hack: we're placing real samples in a complex buffer that the DFT
+ //processor is expecting.
+ ReusableComplexBuffer reusableComplexBuffer = mReusableComplexBufferQueue.getBuffer(decimated.getSamples().length);
+ reusableComplexBuffer.reloadFrom(decimated.getSamples(), System.currentTimeMillis());
+ reusableComplexBuffer.incrementUserCount();
+ mDFTProcessor.receive(reusableComplexBuffer);
}
/**
diff --git a/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java b/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java
index 9c0f11c6..83debd0c 100644
--- a/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java
+++ b/src/main/java/io/github/dsheirer/spectrum/DFTProcessor.java
@@ -18,10 +18,10 @@ package io.github.dsheirer.spectrum;
import io.github.dsheirer.dsp.filter.Window;
import io.github.dsheirer.dsp.filter.Window.WindowType;
import io.github.dsheirer.properties.SystemProperties;
+import io.github.dsheirer.sample.IOverflowListener;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
-import io.github.dsheirer.sample.real.IOverflowListener;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;