diff --git a/src/main/java/io/github/dsheirer/buffer/AbstractNativeBuffer.java b/src/main/java/io/github/dsheirer/buffer/AbstractNativeBuffer.java
new file mode 100644
index 00000000..ddee858c
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/buffer/AbstractNativeBuffer.java
@@ -0,0 +1,70 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
+package io.github.dsheirer.buffer;
+
+/**
+ * Base native buffer class.
+ */
+public abstract class AbstractNativeBuffer implements INativeBuffer
+{
+ private long mTimestamp;
+ private float mSamplesPerMillisecond;
+
+ /**
+ * Constructs an instance
+ * @param timestamp for the start of this buffer
+ * @param samplesPerMillisecond to calculate the time offset of sub-buffers extracted from this native buffer.
+ */
+ public AbstractNativeBuffer(long timestamp, float samplesPerMillisecond)
+ {
+ mTimestamp = timestamp;
+ mSamplesPerMillisecond = samplesPerMillisecond;
+ }
+
+ /**
+ * Timestamp for the start of this buffer
+ * @return timestamp in milliseconds
+ */
+ @Override
+ public long getTimestamp()
+ {
+ return mTimestamp;
+ }
+
+ /**
+ * Quantity of samples representing one millisecond of sample data, used for calculating fragment timestamp offsets.
+ * @return samples per millisecond count.
+ */
+ public float getSamplesPerMillisecond()
+ {
+ return mSamplesPerMillisecond;
+ }
+
+ /**
+ * Calculates the timestamp for a samples buffer fragment based on where it is extracted from relative to the
+ * native buffer starting timestamp.
+ * @param samplesPointer for the start of the fragment. Note: this value will be divided by 2 to account for I/Q sample pairs.
+ * @return timestamp adjusted to the fragment or sub-buffer start sample.
+ */
+ protected long getFragmentTimestamp(int samplesPointer)
+ {
+ return getTimestamp() + (long)(samplesPointer / 2 / getSamplesPerMillisecond());
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/buffer/AbstractNativeBufferFactory.java b/src/main/java/io/github/dsheirer/buffer/AbstractNativeBufferFactory.java
new file mode 100644
index 00000000..0e96eecb
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/buffer/AbstractNativeBufferFactory.java
@@ -0,0 +1,44 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
+package io.github.dsheirer.buffer;
+
+/**
+ * Base class for native buffer factories.
+ */
+public abstract class AbstractNativeBufferFactory implements INativeBufferFactory
+{
+ private float mSamplesPerMillisecond = 0.0f;
+
+ @Override
+ public void setSamplesPerMillisecond(float samplesPerMillisecond)
+ {
+ mSamplesPerMillisecond = samplesPerMillisecond;
+ }
+
+ /**
+ * Quantity of I/Q sample pairs per milli-second at the current sample rate to use in calculating an accurate
+ * timestamp for sub-buffer that are generated from the native buffer.
+ * @return samples per millisecond.
+ */
+ public float getSamplesPerMillisecond()
+ {
+ return mSamplesPerMillisecond;
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/buffer/ByteNativeBuffer.java b/src/main/java/io/github/dsheirer/buffer/ByteNativeBuffer.java
index 6594f6a6..bfe81129 100644
--- a/src/main/java/io/github/dsheirer/buffer/ByteNativeBuffer.java
+++ b/src/main/java/io/github/dsheirer/buffer/ByteNativeBuffer.java
@@ -27,7 +27,7 @@ import java.util.Iterator;
* Native buffer sample array wrapper class that provides access to a stream of either interleaved or
* non-interleaved complex sample buffers converted from the raw byte sample array.
*/
-public class ByteNativeBuffer implements INativeBuffer
+public class ByteNativeBuffer extends AbstractNativeBuffer
{
private static final int FRAGMENT_SIZE = 2048;
private final static float[] LOOKUP_VALUES;
@@ -46,16 +46,17 @@ public class ByteNativeBuffer implements INativeBuffer
}
private byte[] mSamples;
- private long mTimestamp;
/**
* Constructs an instance
* @param samples to process
* @param timestamp of the samples
* @param averageDc measured from sample stream
+ * @param samplesPerMillisecond to calculate derivative timestamps for sub-buffers.
*/
- public ByteNativeBuffer(byte[] samples, long timestamp, float averageDc)
+ public ByteNativeBuffer(byte[] samples, long timestamp, float averageDc, float samplesPerMillisecond)
{
+ super(timestamp, samplesPerMillisecond);
//Ensure we're an even multiple of the fragment size. Typically, this will be 64k or 128k
if(samples.length % FRAGMENT_SIZE != 0)
{
@@ -63,7 +64,6 @@ public class ByteNativeBuffer implements INativeBuffer
}
mSamples = samples;
- mTimestamp = timestamp;
mAverageDc = averageDc;
}
@@ -73,12 +73,6 @@ public class ByteNativeBuffer implements INativeBuffer
return mSamples.length / 2;
}
- @Override
- public long getTimestamp()
- {
- return mTimestamp;
- }
-
@Override
public Iterator iterator()
{
@@ -104,6 +98,8 @@ public class ByteNativeBuffer implements INativeBuffer
@Override
public ComplexSamples next()
{
+ long timestamp = getFragmentTimestamp(mSamplesPointer);
+
float[] i = new float[FRAGMENT_SIZE];
float[] q = new float[FRAGMENT_SIZE];
int samplesOffset = mSamplesPointer;
@@ -115,8 +111,7 @@ public class ByteNativeBuffer implements INativeBuffer
}
mSamplesPointer = samplesOffset;
-
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
@@ -136,6 +131,8 @@ public class ByteNativeBuffer implements INativeBuffer
@Override
public InterleavedComplexSamples next()
{
+ long timestamp = getFragmentTimestamp(mSamplesPointer);
+
float[] converted = new float[FRAGMENT_SIZE * 2];
int samplesPointer = mSamplesPointer;
@@ -147,7 +144,7 @@ public class ByteNativeBuffer implements INativeBuffer
mSamplesPointer = samplesPointer;
- return new InterleavedComplexSamples(converted, mTimestamp);
+ return new InterleavedComplexSamples(converted, timestamp);
}
}
}
diff --git a/src/main/java/io/github/dsheirer/buffer/ByteNativeBufferFactory.java b/src/main/java/io/github/dsheirer/buffer/ByteNativeBufferFactory.java
index 257a5d1e..ba395321 100644
--- a/src/main/java/io/github/dsheirer/buffer/ByteNativeBufferFactory.java
+++ b/src/main/java/io/github/dsheirer/buffer/ByteNativeBufferFactory.java
@@ -24,7 +24,7 @@ import java.nio.ByteBuffer;
/**
* Implements a factory for creating ByteNativeBuffer instances
*/
-public class ByteNativeBufferFactory implements INativeBufferFactory
+public class ByteNativeBufferFactory extends AbstractNativeBufferFactory
{
private DcCorrectionManager mDcCorrectionManager = new DcCorrectionManager();
@@ -39,7 +39,7 @@ public class ByteNativeBufferFactory implements INativeBufferFactory
calculateDc(copy);
}
- return new ByteNativeBuffer(copy, timestamp, mDcCorrectionManager.getAverageDc());
+ return new ByteNativeBuffer(copy, timestamp, mDcCorrectionManager.getAverageDc(), getSamplesPerMillisecond());
}
/**
diff --git a/src/main/java/io/github/dsheirer/buffer/FloatNativeBuffer.java b/src/main/java/io/github/dsheirer/buffer/FloatNativeBuffer.java
index e1a9fbf1..daf4999b 100644
--- a/src/main/java/io/github/dsheirer/buffer/FloatNativeBuffer.java
+++ b/src/main/java/io/github/dsheirer/buffer/FloatNativeBuffer.java
@@ -22,35 +22,24 @@ package io.github.dsheirer.buffer;
import io.github.dsheirer.sample.SampleUtils;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
-
import java.util.Iterator;
/**
* Simple native buffer implementation that simply wraps a single, existing, non-native sample buffer.
*/
-public class FloatNativeBuffer implements INativeBuffer
+public class FloatNativeBuffer extends AbstractNativeBuffer
{
private float[] mInterleavedComplexSamples;
- private long mTimestamp;
/**
* Constructs an instance
- * @param complexSamples to wrap
+ * @param complexSamples interleaved to wrap
* @param timestamp for the buffer
*/
- public FloatNativeBuffer(float[] complexSamples, long timestamp)
+ public FloatNativeBuffer(float[] complexSamples, long timestamp, float samplesPerMillisecond)
{
+ super(timestamp, samplesPerMillisecond);
mInterleavedComplexSamples = complexSamples;
- mTimestamp = timestamp;
- }
-
- /**
- * Constructs an instance
- * @param complexSamples to wrap
- */
- public FloatNativeBuffer(float[] complexSamples)
- {
- this(complexSamples, System.currentTimeMillis());
}
/**
@@ -58,9 +47,9 @@ public class FloatNativeBuffer implements INativeBuffer
* @param samples to wrap
* @param timestamp for the buffer
*/
- public FloatNativeBuffer(ComplexSamples samples, long timestamp)
+ public FloatNativeBuffer(ComplexSamples samples)
{
- this(SampleUtils.interleave(samples), timestamp);
+ this(SampleUtils.interleave(samples), samples.timestamp(), 0.0f);
}
/**
@@ -69,7 +58,7 @@ public class FloatNativeBuffer implements INativeBuffer
*/
public FloatNativeBuffer(InterleavedComplexSamples samples)
{
- this(samples.samples(), samples.timestamp());
+ this(samples.samples(), samples.timestamp(), 0.0f);
}
@Override
@@ -90,12 +79,6 @@ public class FloatNativeBuffer implements INativeBuffer
return mInterleavedComplexSamples.length / 2;
}
- @Override
- public long getTimestamp()
- {
- return mTimestamp;
- }
-
private class ComplexSamplesIterator implements Iterator
{
private boolean mEmpty;
@@ -115,7 +98,7 @@ public class FloatNativeBuffer implements INativeBuffer
}
mEmpty = true;
- return SampleUtils.deinterleave(mInterleavedComplexSamples);
+ return SampleUtils.deinterleave(mInterleavedComplexSamples, getTimestamp());
}
}
@@ -139,7 +122,7 @@ public class FloatNativeBuffer implements INativeBuffer
}
mEmpty = true;
- return new InterleavedComplexSamples(mInterleavedComplexSamples, mTimestamp);
+ return new InterleavedComplexSamples(mInterleavedComplexSamples, getTimestamp());
}
}
}
diff --git a/src/main/java/io/github/dsheirer/buffer/INativeBufferFactory.java b/src/main/java/io/github/dsheirer/buffer/INativeBufferFactory.java
index fb15bb54..a6632dc6 100644
--- a/src/main/java/io/github/dsheirer/buffer/INativeBufferFactory.java
+++ b/src/main/java/io/github/dsheirer/buffer/INativeBufferFactory.java
@@ -33,7 +33,15 @@ public interface INativeBufferFactory
*
* @param samples byte array copied from native memory
* @param timestamp of the samples
+ * @param samplesPerMillisecond to calculate timestamp offset for child buffers.
* @return instance
*/
INativeBuffer getBuffer(ByteBuffer samples, long timestamp);
+
+ /**
+ * Sets the samples per millisecond rate based on the current sample rate.
+ *
+ * @param samplesPerMillisecond to calculate timestamp offset for child buffers.
+ */
+ void setSamplesPerMillisecond(float samplesPerMillisecond);
}
diff --git a/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBuffer.java b/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBuffer.java
index 0d363213..f87ea66a 100644
--- a/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBuffer.java
+++ b/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBuffer.java
@@ -21,14 +21,13 @@ package io.github.dsheirer.buffer;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
-
import java.util.Iterator;
/**
* Native buffer sample array wrapper class that provides access to a stream of either interleaved or
* non-interleaved complex sample buffers converted from the raw byte sample array.
*/
-public class SignedByteNativeBuffer implements INativeBuffer
+public class SignedByteNativeBuffer extends AbstractNativeBuffer
{
private static final int FRAGMENT_SIZE = 2048;
private final static float[] LOOKUP_VALUES;
@@ -47,7 +46,6 @@ public class SignedByteNativeBuffer implements INativeBuffer
}
private byte[] mSamples;
- private long mTimestamp;
private float mIAverageDc;
private float mQAverageDc;
@@ -57,9 +55,12 @@ public class SignedByteNativeBuffer implements INativeBuffer
* @param timestamp of the samples
* @param iAverageDc of the sample stream
* @param qAverageDc of the sample stream
+ * @param samplesPerMillisecond to calculate sub-buffer timestamps
*/
- public SignedByteNativeBuffer(byte[] samples, long timestamp, float iAverageDc, float qAverageDc)
+ public SignedByteNativeBuffer(byte[] samples, long timestamp, float iAverageDc, float qAverageDc, float samplesPerMillisecond)
{
+ super(timestamp, samplesPerMillisecond);
+
//Ensure we're an even multiple of the fragment size. Typically, this will be 64k or 128k
if(samples.length % FRAGMENT_SIZE != 0)
{
@@ -67,17 +68,10 @@ public class SignedByteNativeBuffer implements INativeBuffer
}
mSamples = samples;
- mTimestamp = timestamp;
mIAverageDc = iAverageDc;
mQAverageDc = qAverageDc;
}
- @Override
- public long getTimestamp()
- {
- return mTimestamp;
- }
-
@Override
public int sampleCount()
{
@@ -112,6 +106,8 @@ public class SignedByteNativeBuffer implements INativeBuffer
@Override
public ComplexSamples next()
{
+ long timestamp = getFragmentTimestamp(mSamplesPointer);
+
float[] i = new float[FRAGMENT_SIZE];
float[] q = new float[FRAGMENT_SIZE];
int samplesOffset = mSamplesPointer;
@@ -123,7 +119,7 @@ public class SignedByteNativeBuffer implements INativeBuffer
}
mSamplesPointer = samplesOffset;
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
@@ -143,6 +139,8 @@ public class SignedByteNativeBuffer implements INativeBuffer
@Override
public InterleavedComplexSamples next()
{
+ long timestamp = getFragmentTimestamp(mSamplesPointer);
+
float[] converted = new float[FRAGMENT_SIZE * 2];
int samplesOffset = mSamplesPointer;
@@ -155,7 +153,7 @@ public class SignedByteNativeBuffer implements INativeBuffer
mSamplesPointer = samplesOffset;
- return new InterleavedComplexSamples(converted, mTimestamp);
+ return new InterleavedComplexSamples(converted, timestamp);
}
}
}
diff --git a/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBufferFactory.java b/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBufferFactory.java
index 699b946b..f21511fc 100644
--- a/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBufferFactory.java
+++ b/src/main/java/io/github/dsheirer/buffer/SignedByteNativeBufferFactory.java
@@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
/**
* Implements a factory for creating SignedByteNativeBuffer instances
*/
-public class SignedByteNativeBufferFactory implements INativeBufferFactory
+public class SignedByteNativeBufferFactory extends AbstractNativeBufferFactory
{
/**
* DC removal calculations will run once a minute
@@ -78,7 +78,7 @@ public class SignedByteNativeBufferFactory implements INativeBufferFactory
calculateDc(copy);
}
- return new SignedByteNativeBuffer(copy, timestamp, mIAverageDc, mQAverageDc);
+ return new SignedByteNativeBuffer(copy, timestamp, mIAverageDc, mQAverageDc, getSamplesPerMillisecond());
}
/**
diff --git a/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIterator.java b/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIterator.java
index e41bec7b..cd035cd4 100644
--- a/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIterator.java
+++ b/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIterator.java
@@ -20,7 +20,6 @@
package io.github.dsheirer.buffer.airspy;
import io.github.dsheirer.dsp.filter.hilbert.HilbertTransform;
-
import java.util.Iterator;
/**
@@ -42,8 +41,9 @@ public abstract class AirspyBufferIterator implements Iterator
protected float[] mQBuffer = new float[FRAGMENT_SIZE + Q_OVERLAP];
protected short[] mSamples;
protected int mSamplesPointer = 0;
- protected long mTimestamp;
protected float mAverageDc;
+ private long mTimestamp;
+ private float mSamplesPerMillisecond;
/**
* Constructs an instance
@@ -52,8 +52,10 @@ public abstract class AirspyBufferIterator implements Iterator
* @param residualQ samples from previous buffer
* @param averageDc as measured
* @param timestamp of the buffer
+ * @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
- public AirspyBufferIterator(short[] samples, short[] residualI, short[] residualQ, float averageDc, long timestamp)
+ public AirspyBufferIterator(short[] samples, short[] residualI, short[] residualQ, float averageDc, long timestamp,
+ float samplesPerMillisecond)
{
if(residualI.length != I_OVERLAP || residualQ.length != Q_OVERLAP)
{
@@ -73,6 +75,7 @@ public abstract class AirspyBufferIterator implements Iterator
mAverageDc = averageDc;
mSamples = samples;
mTimestamp = timestamp;
+ mSamplesPerMillisecond = samplesPerMillisecond;
//Transfer and scale the residual I & Q samples from the previous buffer
for(int i = 0; i < residualI.length; i++)
@@ -86,6 +89,17 @@ public abstract class AirspyBufferIterator implements Iterator
}
}
+ /**
+ * Calculates the timestamp for a samples buffer fragment based on where it is extracted from relative to the
+ * native buffer starting timestamp.
+ * @param samplesPointer for the start of the fragment. Note: this value will be divided by 2 to account for I/Q sample pairs.
+ * @return timestamp adjusted to the fragment or sub-buffer start sample.
+ */
+ protected long getFragmentTimestamp(int samplesPointer)
+ {
+ return mTimestamp + (long)(samplesPointer / 2 / mSamplesPerMillisecond);
+ }
+
@Override
public boolean hasNext()
{
diff --git a/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIteratorScalar.java b/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIteratorScalar.java
index 805f8f43..d2f60ab4 100644
--- a/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIteratorScalar.java
+++ b/src/main/java/io/github/dsheirer/buffer/airspy/AirspyBufferIteratorScalar.java
@@ -20,7 +20,6 @@
package io.github.dsheirer.buffer.airspy;
import io.github.dsheirer.sample.complex.ComplexSamples;
-
import java.util.Arrays;
/**
@@ -36,10 +35,11 @@ public class AirspyBufferIteratorScalar extends AirspyBufferIterator iterator()
{
return switch(mInterleavedImplementation)
{
- case VECTOR_SIMD_512 -> new AirspyBufferIteratorVector512Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- case VECTOR_SIMD_256-> new AirspyBufferIteratorVector256Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- case VECTOR_SIMD_128-> new AirspyBufferIteratorVector128Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- case VECTOR_SIMD_64 ->new AirspyBufferIteratorVector64Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- default -> new AirspyBufferIteratorScalar(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
+ case VECTOR_SIMD_512 -> new AirspyBufferIteratorVector512Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ case VECTOR_SIMD_256-> new AirspyBufferIteratorVector256Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ case VECTOR_SIMD_128-> new AirspyBufferIteratorVector128Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ case VECTOR_SIMD_64 ->new AirspyBufferIteratorVector64Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ default -> new AirspyBufferIteratorScalar(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
};
}
@@ -99,11 +93,11 @@ public class AirspyNativeBuffer implements INativeBuffer
{
return switch(mInterleavedImplementation)
{
- case VECTOR_SIMD_512 -> new AirspyInterleavedBufferIteratorVector512Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- case VECTOR_SIMD_256-> new AirspyInterleavedBufferIteratorVector256Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- case VECTOR_SIMD_128-> new AirspyInterleavedBufferIteratorVector128Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- case VECTOR_SIMD_64 ->new AirspyInterleavedBufferIteratorVector64Bits(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
- default -> new AirspyInterleavedBufferIteratorScalar(mSamples, mResidualI, mResidualQ, mAverageDc, mTimestamp);
+ case VECTOR_SIMD_512 -> new AirspyInterleavedBufferIteratorVector512Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ case VECTOR_SIMD_256-> new AirspyInterleavedBufferIteratorVector256Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ case VECTOR_SIMD_128-> new AirspyInterleavedBufferIteratorVector128Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ case VECTOR_SIMD_64 ->new AirspyInterleavedBufferIteratorVector64Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
+ default -> new AirspyInterleavedBufferIteratorScalar(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
};
}
}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/buffer/airspy/AirspyNativeBufferFactory.java b/src/main/java/io/github/dsheirer/buffer/airspy/AirspyNativeBufferFactory.java
index b8c349eb..03552407 100644
--- a/src/main/java/io/github/dsheirer/buffer/airspy/AirspyNativeBufferFactory.java
+++ b/src/main/java/io/github/dsheirer/buffer/airspy/AirspyNativeBufferFactory.java
@@ -19,19 +19,18 @@
package io.github.dsheirer.buffer.airspy;
+import io.github.dsheirer.buffer.AbstractNativeBufferFactory;
import io.github.dsheirer.buffer.INativeBuffer;
-import io.github.dsheirer.buffer.INativeBufferFactory;
import io.github.dsheirer.vector.calibrate.CalibrationManager;
import io.github.dsheirer.vector.calibrate.CalibrationType;
import io.github.dsheirer.vector.calibrate.Implementation;
-
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
* Implements a factory for creating SignedByteNativeBuffer instances
*/
-public class AirspyNativeBufferFactory implements INativeBufferFactory
+public class AirspyNativeBufferFactory extends AbstractNativeBufferFactory
{
private boolean mSamplePacking = false;
private short[] mResidualI = new short[AirspyBufferIterator.I_OVERLAP];
@@ -106,7 +105,7 @@ public class AirspyNativeBufferFactory implements INativeBufferFactory
INativeBuffer nativeBuffer = new AirspyNativeBuffer(samples,
Arrays.copyOf(mResidualI, mResidualI.length),
Arrays.copyOf(mResidualQ, mResidualQ.length), mConverter.getAverageDc(), timestamp,
- mInterleavedIteratorImplementation, mNonInterleavedIteratorImplementation);
+ mInterleavedIteratorImplementation, mNonInterleavedIteratorImplementation, getSamplesPerMillisecond());
extractResidual(samples);
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 fb90d83f..08b1f8ec 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
@@ -46,6 +46,7 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
private double mChannelSampleRate;
private long mIndexCenterFrequency;
private long mChannelFrequencyCorrection;
+ private long mCurrentSamplesTimestamp;
private ReentrantLock mOutputProcessorLock = new ReentrantLock();
/**
@@ -106,6 +107,7 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
public void receive(ComplexSamples complexSamples)
{
mStreamHeartbeatProcessor.receive(complexSamples);
+ mCurrentSamplesTimestamp = complexSamples.timestamp();
}
/**
@@ -222,7 +224,7 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
{
if(mPolyphaseChannelOutputProcessor != null)
{
- mPolyphaseChannelOutputProcessor.receiveChannelResults(channelResultsList);
+ mPolyphaseChannelOutputProcessor.receiveChannelResults(channelResultsList, mCurrentSamplesTimestamp);
}
}
finally
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/TwoChannelSynthesizerM2.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/TwoChannelSynthesizerM2.java
index 995bf6ce..f1929860 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/TwoChannelSynthesizerM2.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/TwoChannelSynthesizerM2.java
@@ -156,7 +156,7 @@ public class TwoChannelSynthesizerM2
mTopBlockFlag = !mTopBlockFlag;
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, channelBuffer1.timestamp());
}
/**
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 09343108..df5a936e 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
@@ -33,6 +33,7 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
private Dispatcher> mChannelResultsDispatcher;
protected Listener mComplexSamplesListener;
private int mInputChannelCount;
+ private long mCurrentSampleTimestamp = System.currentTimeMillis();
/**
* Base class for polyphase channelizer output channel processing. Provides built-in frequency translation
@@ -49,6 +50,15 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
mChannelResultsDispatcher.setListener(floats -> process(floats));
}
+ /**
+ * Timestamp for the current series of samples.
+ * @return time in milliseconds to use with assembled complex sample buffers.
+ */
+ protected long getCurrentSampleTimestamp()
+ {
+ return mCurrentSampleTimestamp;
+ }
+
@Override
public void start()
{
@@ -81,9 +91,10 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
}
@Override
- public void receiveChannelResults(List channelResultsList)
+ public void receiveChannelResults(List channelResultsList, long timestamp)
{
mChannelResultsDispatcher.receive(channelResultsList);
+ mCurrentSampleTimestamp = timestamp;
}
/**
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 ec347451..1bfd7836 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
@@ -36,8 +36,9 @@ public interface IPolyphaseChannelOutputProcessor
/**
* Receive and enqueue output results from the polyphase analysis channelizer
* @param channelResults to enqueue
+ * @param timestamp for the first channel results buffer
*/
- void receiveChannelResults(List channelResults);
+ void receiveChannelResults(List channelResults, long timestamp);
/**
* Listener to receive assembled complex samples buffers
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/MixerAssembler.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/MixerAssembler.java
index f610ab84..9ac7799e 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/MixerAssembler.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/MixerAssembler.java
@@ -65,7 +65,8 @@ public abstract class MixerAssembler
/**
* Access the fully assembled buffer when hasBuffer() indicates that a buffer is ready.
+ * @param timestamp to use for the assembled complex samples buffer
* @return true if a full buffer is assembled and ready.
*/
- public abstract ComplexSamples getBuffer();
+ public abstract ComplexSamples getBuffer(long timestamp);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelMixerAssembler.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelMixerAssembler.java
index df9e1e36..988f3099 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelMixerAssembler.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/OneChannelMixerAssembler.java
@@ -61,9 +61,9 @@ public class OneChannelMixerAssembler extends MixerAssembler
* @return assembled buffer.
*/
@Override
- public ComplexSamples getBuffer()
+ public ComplexSamples getBuffer(long timestamp)
{
- ComplexSamples buffer = mSampleAssembler.getBufferAndReset();
+ ComplexSamples buffer = mSampleAssembler.getBufferAndReset(timestamp);
if(getMixer().hasFrequency())
{
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 f6bdaaa1..73137095 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
@@ -90,7 +90,7 @@ public class OneChannelOutputProcessor extends ChannelOutputProcessor
if(mMixerAssembler.hasBuffer())
{
- ComplexSamples buffer = mMixerAssembler.getBuffer();
+ ComplexSamples buffer = mMixerAssembler.getBuffer(getCurrentSampleTimestamp());
if(mComplexSamplesListener != null)
{
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/SampleAssembler.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/SampleAssembler.java
index af696548..f63c9f63 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/SampleAssembler.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/SampleAssembler.java
@@ -76,9 +76,9 @@ public class SampleAssembler
/**
* Extracts the full buffer from this assembler and resets the assembler to accept more samples.
*/
- public ComplexSamples getBufferAndReset()
+ public ComplexSamples getBufferAndReset(long timestamp)
{
- ComplexSamples buffer = new ComplexSamples(mI, mQ);
+ ComplexSamples buffer = new ComplexSamples(mI, mQ, timestamp);
reset();
return buffer;
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelMixerAssembler.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelMixerAssembler.java
index a0f944ed..d216ccf9 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelMixerAssembler.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/output/TwoChannelMixerAssembler.java
@@ -76,13 +76,14 @@ public class TwoChannelMixerAssembler extends MixerAssembler
/**
* Access the assembled buffer. Frequency offset and gain are applied to the returned buffer.
+ * @param timestamp to use for the assembled buffer
* @return assembled buffer.
*/
@Override
- public ComplexSamples getBuffer()
+ public ComplexSamples getBuffer(long timestamp)
{
- ComplexSamples channel1 = mChannel1SampleAssembler.getBufferAndReset();
- ComplexSamples channel2 = mChannel2SampleAssembler.getBufferAndReset();
+ ComplexSamples channel1 = mChannel1SampleAssembler.getBufferAndReset(timestamp);
+ ComplexSamples channel2 = mChannel2SampleAssembler.getBufferAndReset(timestamp);
//Synthesize two channels into one, reducing sample rate by 2 so it's same as single channel rate
ComplexSamples buffer = mTwoChannelSynthesizer.process(channel1, channel2);
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 11d01b51..98c2fe31 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
@@ -90,7 +90,7 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
* Extract the channel from the channel results array, apply frequency translation, and deliver the
* extracted frequency-corrected channel I/Q sample set to the complex sample listener.
*
- * @param lists to process containing a list of a list of an array of channel I/Q sample pairs (I0,Q0,I1,Q1...In,Qn)
+ * @param channelResultsList to process containing a list of a list of an array of channel I/Q sample pairs (I0,Q0,I1,Q1...In,Qn)
*/
@Override
public void process(List channelResultsList)
@@ -102,7 +102,7 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
if(mMixerAssembler.hasBuffer())
{
- ComplexSamples buffer = mMixerAssembler.getBuffer();
+ ComplexSamples buffer = mMixerAssembler.getBuffer(getCurrentSampleTimestamp());
if(mComplexSamplesListener != 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 aacd5870..bbdc1569 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
@@ -80,9 +80,10 @@ public abstract class HilbertTransform
/**
* Converts the real sample array to complex samples as half the sample rate
* @param samples to convert
+ * @param timestamp of the first sample
* @return converted samples
*/
- public abstract ComplexSamples filter(float[] samples);
+ public abstract ComplexSamples filter(float[] samples, long timestamp);
/**
* Converts the half-band filter coefficients for use as hilbert transform filter coefficients. Sets all
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/LegacyHilbertTransform.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/LegacyHilbertTransform.java
deleted file mode 100644
index dcaa0660..00000000
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/LegacyHilbertTransform.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- * ****************************************************************************
- */
-package io.github.dsheirer.dsp.filter.hilbert;
-
-import org.apache.commons.math3.util.FastMath;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Arrays;
-
-public class LegacyHilbertTransform
-{
- private static final Logger mLog = LoggerFactory.getLogger(LegacyHilbertTransform.class);
-
- 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 LegacyHilbertTransform()
- {
- convertHalfBandToHilbert(HilbertTransform.HALF_BAND_FILTER_47_TAP);
-
- mBufferSize = mHilbertFilter.length + 1;
- mBuffer = new float[mBufferSize];
-
- mCenterCoefficent = mHilbertFilter[mHilbertFilter.length / 2];
-
- generateIndexMap(mHilbertFilter.length);
- }
-
- /**
- * 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;
-
- for(int y = 0; y < samples.length; y += 2)
- {
- insert(samples[y]);
- insert(samples[y + 1]);
-
- accumulator = 0.0f;
-
- int index = mBufferPointer / 2;
-
- for(int x = 0; x < mHilbertFilter.length / 2; x += 2)
- {
- accumulator += mHilbertFilter[x] *
- (mBuffer[mIndexMap[index][x + 1]] -
- mBuffer[mIndexMap[index][x]]);
- }
-
- //Perform FS/2 frequency translation on the final filtered values
- if(mInvertFlag)
- {
- //inphase
- samples[y] = -(mBuffer[mIndexMap[index][mCenterTapIndex]]);
-
- //quadrature
- samples[y + 1] = -accumulator;
- }
- else
- {
- //inphase
- samples[y] = mBuffer[mIndexMap[index][mCenterTapIndex]];
-
- //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;
-
- 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 * -FastMath.abs(coefficients[x]);
- }
- else if(x > middle)
- {
- mHilbertFilter[x] = 2.0f * FastMath.abs(coefficients[x]);
- }
- else
- {
- mHilbertFilter[x] = 2.0f * coefficients[x];
- }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/ScalarHilbertTransform.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/ScalarHilbertTransform.java
index 3c66beeb..244b066b 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/ScalarHilbertTransform.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/ScalarHilbertTransform.java
@@ -23,7 +23,6 @@ import io.github.dsheirer.dsp.oscillator.IRealOscillator;
import io.github.dsheirer.dsp.oscillator.OscillatorFactory;
import io.github.dsheirer.sample.SampleUtils;
import io.github.dsheirer.sample.complex.ComplexSamples;
-
import java.util.Arrays;
/**
@@ -35,9 +34,10 @@ public class ScalarHilbertTransform extends HilbertTransform
/**
* Filters the real samples array into complex samples at half the sample rate.
* @param realSamples to filter
+ * @param timestamp of the first sample
* @return complex samples at half the sample rate
*/
- public ComplexSamples filter(float[] realSamples)
+ public ComplexSamples filter(float[] realSamples, long timestamp)
{
int bufferLength = realSamples.length / 2;
@@ -52,7 +52,7 @@ public class ScalarHilbertTransform extends HilbertTransform
mQBuffer = qTemp;
}
- ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples);
+ ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples, timestamp);
System.arraycopy(deinterleaved.i(), 0, mIBuffer, mIOverlap, deinterleaved.i().length);
System.arraycopy(deinterleaved.q(), 0, mQBuffer, mQOverlap, deinterleaved.q().length);
@@ -78,7 +78,7 @@ public class ScalarHilbertTransform extends HilbertTransform
System.arraycopy(mIBuffer, mIBuffer.length - mIOverlap, mIBuffer, 0, mIOverlap);
System.arraycopy(mQBuffer, mQBuffer.length - mQOverlap, mQBuffer, 0, mQOverlap);
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
public static void main(String[] args)
@@ -104,8 +104,8 @@ public class ScalarHilbertTransform extends HilbertTransform
if(validate)
{
- ComplexSamples scalar = hilbertTransform.filter(realSamples);
- ComplexSamples vector = vector512.filter(realSamples);
+ ComplexSamples scalar = hilbertTransform.filter(realSamples, 0l);
+ ComplexSamples vector = vector512.filter(realSamples, start);
System.out.println("SI: " + Arrays.toString(scalar.i()));
System.out.println("VI: " + Arrays.toString(vector.i()));
@@ -119,7 +119,7 @@ public class ScalarHilbertTransform extends HilbertTransform
{
// ComplexSamples filtered = hilbertTransform.filter(realSamples);
// ComplexSamples filtered = vectorDefault.filter(realSamples);
- ComplexSamples filtered = vector512.filter(realSamples);
+ ComplexSamples filtered = vector512.filter(realSamples, start);
// ComplexSamples filtered = vector256.filter(realSamples);
// ComplexSamples filtered = vector128.filter(realSamples);
// ComplexSamples filtered = vector64.filter(realSamples);
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform128Bits.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform128Bits.java
index 3aa34efd..8b851c71 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform128Bits.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform128Bits.java
@@ -37,9 +37,10 @@ public class VectorHilbertTransform128Bits extends HilbertTransform
/**
* Filters the real samples array into complex samples at half the sample rate.
* @param realSamples to filter
+ * @param timestamp of the first sample
* @return complex samples at half the sample rate
*/
- public ComplexSamples filter(float[] realSamples)
+ public ComplexSamples filter(float[] realSamples, long timestamp)
{
int bufferLength = realSamples.length / 2;
@@ -54,7 +55,7 @@ public class VectorHilbertTransform128Bits extends HilbertTransform
mQBuffer = qTemp;
}
- ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples);
+ ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples, timestamp);
VectorUtilities.checkComplexArrayLength(deinterleaved.i(), deinterleaved.q(), VECTOR_SPECIES);
System.arraycopy(deinterleaved.i(), 0, mIBuffer, mIOverlap, deinterleaved.i().length);
@@ -91,6 +92,6 @@ public class VectorHilbertTransform128Bits extends HilbertTransform
System.arraycopy(mIBuffer, mIBuffer.length - mIOverlap, mIBuffer, 0, mIOverlap);
System.arraycopy(mQBuffer, mQBuffer.length - mQOverlap, mQBuffer, 0, mQOverlap);
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform256Bits.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform256Bits.java
index 782a53cd..2d18f04c 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform256Bits.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform256Bits.java
@@ -37,9 +37,10 @@ public class VectorHilbertTransform256Bits extends HilbertTransform
/**
* Filters the real samples array into complex samples at half the sample rate.
* @param realSamples to filter
+ * @param timestamp of the first sample
* @return complex samples at half the sample rate
*/
- public ComplexSamples filter(float[] realSamples)
+ public ComplexSamples filter(float[] realSamples, long timestamp)
{
int bufferLength = realSamples.length / 2;
@@ -54,7 +55,7 @@ public class VectorHilbertTransform256Bits extends HilbertTransform
mQBuffer = qTemp;
}
- ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples);
+ ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples, timestamp);
VectorUtilities.checkComplexArrayLength(deinterleaved.i(), deinterleaved.q(), VECTOR_SPECIES);
System.arraycopy(deinterleaved.i(), 0, mIBuffer, mIOverlap, deinterleaved.i().length);
@@ -85,6 +86,6 @@ public class VectorHilbertTransform256Bits extends HilbertTransform
System.arraycopy(mIBuffer, mIBuffer.length - mIOverlap, mIBuffer, 0, mIOverlap);
System.arraycopy(mQBuffer, mQBuffer.length - mQOverlap, mQBuffer, 0, mQOverlap);
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform512Bits.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform512Bits.java
index 240a0121..5982df4c 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform512Bits.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform512Bits.java
@@ -22,12 +22,11 @@ package io.github.dsheirer.dsp.filter.hilbert;
import io.github.dsheirer.sample.SampleUtils;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.vector.VectorUtilities;
+import java.util.Arrays;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
-import java.util.Arrays;
-
/**
* Implements a Hilbert transform using vector SIMD operations against a pre-defined 47-tap filter.
* As described in Understanding Digital Signal Processing, Lyons, 3e, 2011, Section 13.37.2 (p 804-805)
@@ -53,9 +52,10 @@ public class VectorHilbertTransform512Bits extends HilbertTransform
/**
* Filters the real samples array into complex samples at half the sample rate.
* @param realSamples to filter
+ * @param timestamp of the first sample
* @return complex samples at half the sample rate
*/
- public ComplexSamples filter(float[] realSamples)
+ public ComplexSamples filter(float[] realSamples, long timestamp)
{
int bufferLength = realSamples.length / 2;
@@ -70,7 +70,7 @@ public class VectorHilbertTransform512Bits extends HilbertTransform
mQBuffer = qTemp;
}
- ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples);
+ ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples, timestamp);
VectorUtilities.checkComplexArrayLength(deinterleaved.i(), deinterleaved.q(), VECTOR_SPECIES);
System.arraycopy(deinterleaved.i(), 0, mIBuffer, mIOverlap, deinterleaved.i().length);
@@ -103,6 +103,6 @@ public class VectorHilbertTransform512Bits extends HilbertTransform
System.arraycopy(mIBuffer, mIBuffer.length - mIOverlap, mIBuffer, 0, mIOverlap);
System.arraycopy(mQBuffer, mQBuffer.length - mQOverlap, mQBuffer, 0, mQOverlap);
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform64Bits.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform64Bits.java
index e242ae85..cbc286b9 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform64Bits.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransform64Bits.java
@@ -37,9 +37,10 @@ public class VectorHilbertTransform64Bits extends HilbertTransform
/**
* Filters the real samples array into complex samples at half the sample rate.
* @param realSamples to filter
+ * @param timestamp of the first sample
* @return complex samples at half the sample rate
*/
- public ComplexSamples filter(float[] realSamples)
+ public ComplexSamples filter(float[] realSamples, long timestamp)
{
int bufferLength = realSamples.length / 2;
@@ -54,7 +55,7 @@ public class VectorHilbertTransform64Bits extends HilbertTransform
mQBuffer = qTemp;
}
- ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples);
+ ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples, timestamp);
VectorUtilities.checkComplexArrayLength(deinterleaved.i(), deinterleaved.q(), VECTOR_SPECIES);
System.arraycopy(deinterleaved.i(), 0, mIBuffer, mIOverlap, deinterleaved.i().length);
@@ -103,6 +104,6 @@ public class VectorHilbertTransform64Bits extends HilbertTransform
System.arraycopy(mIBuffer, mIBuffer.length - mIOverlap, mIBuffer, 0, mIOverlap);
System.arraycopy(mQBuffer, mQBuffer.length - mQOverlap, mQBuffer, 0, mQOverlap);
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransformDefaultBits.java b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransformDefaultBits.java
index 138ecb00..21f87a53 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransformDefaultBits.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/hilbert/VectorHilbertTransformDefaultBits.java
@@ -37,9 +37,10 @@ public class VectorHilbertTransformDefaultBits extends HilbertTransform
/**
* Filters the real samples array into complex samples at half the sample rate.
* @param realSamples to filter
+ * @param timestamp of the first sample
* @return complex samples at half the sample rate
*/
- public ComplexSamples filter(float[] realSamples)
+ public ComplexSamples filter(float[] realSamples, long timestamp)
{
int bufferLength = realSamples.length / 2;
@@ -54,7 +55,7 @@ public class VectorHilbertTransformDefaultBits extends HilbertTransform
mQBuffer = qTemp;
}
- ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples);
+ ComplexSamples deinterleaved = SampleUtils.deinterleave(realSamples, timestamp);
VectorUtilities.checkComplexArrayLength(deinterleaved.i(), deinterleaved.q(), VECTOR_SPECIES);
System.arraycopy(deinterleaved.i(), 0, mIBuffer, mIOverlap, deinterleaved.i().length);
@@ -84,6 +85,6 @@ public class VectorHilbertTransformDefaultBits extends HilbertTransform
System.arraycopy(mIBuffer, mIBuffer.length - mIOverlap, mIBuffer, 0, mIOverlap);
System.arraycopy(mQBuffer, mQBuffer.length - mQOverlap, mQBuffer, 0, mQOverlap);
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGain.java b/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGain.java
index 6f8c0469..037993b4 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGain.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGain.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.dsp.gain.complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
@@ -46,7 +65,7 @@ public abstract class ComplexGain
*/
public ComplexSamples apply(ComplexSamples samples)
{
- return apply(samples.i(), samples.q());
+ return apply(samples.i(), samples.q(), samples.timestamp());
}
/**
@@ -56,7 +75,8 @@ public abstract class ComplexGain
* original sample buffer.
* @param i samples to amplify
* @param q samples to amplify
+ * @param timestamp of the first sample
* @return amplified samples
*/
- public abstract ComplexSamples apply(float[] i, float q[]);
+ public abstract ComplexSamples apply(float[] i, float q[], long timestamp);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGainControl.java b/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGainControl.java
index afe8a477..3497fa80 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGainControl.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/complex/ComplexGainControl.java
@@ -18,13 +18,9 @@
*/
package io.github.dsheirer.dsp.gain.complex;
-import io.github.dsheirer.sample.SampleUtils;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
-import java.text.DecimalFormat;
-import java.util.Arrays;
-
public class ComplexGainControl implements IComplexGainControl
{
public static final float OBJECTIVE_ENVELOPE = 1.0f;
@@ -48,9 +44,10 @@ public class ComplexGainControl implements IComplexGainControl
* gain for the single sample in the buffer that has the largest envelope.
* @param i samples
* @param q samples
+ * @param timestamp of the first sample
* @return processed/amplified buffer
*/
- @Override public ComplexSamples process(float[] i, float[] q)
+ @Override public ComplexSamples process(float[] i, float[] q, long timestamp)
{
float maxEnvelope = MINIMUM_ENVELOPE;
@@ -70,45 +67,6 @@ public class ComplexGainControl implements IComplexGainControl
qProcessed[x] = q[x] * gain;
}
- return new ComplexSamples(iProcessed, qProcessed);
- }
-
- public static void main(String[] args)
- {
- int sampleSize = 2048;
- ComplexSamples samples = SampleUtils.generateComplexRandomVectorLength(sampleSize);
- ComplexGainControl scalar = new ComplexGainControl();
- VectorComplexGainControl vector = new VectorComplexGainControl();
-
- boolean validate = false;
-
- if(validate)
- {
- ComplexSamples scalarSamples = scalar.process(samples.i(), samples.q());
- ComplexSamples vectorSamples = vector.process(samples.i(), samples.q());
-
- System.out.println("SCALAR I: " + Arrays.toString(scalarSamples.i()));
- System.out.println("VECTOR I: " + Arrays.toString(vectorSamples.i()));
- System.out.println("SCALAR Q: " + Arrays.toString(scalarSamples.q()));
- System.out.println("VECTOR Q: " + Arrays.toString(vectorSamples.q()));
- }
- else
- {
- double accumulator = 0.0d;
- int iterations = 10_000_000;
- long start = System.currentTimeMillis();
-
- for(int x = 0; x < iterations; x++)
- {
-// ComplexSamples processed = scalar.process(samples.i(), samples.q());
- ComplexSamples processed = vector.process(samples.i(), samples.q());
- accumulator += processed.i()[3];
- }
-
- double elapsed = System.currentTimeMillis() - start;
- DecimalFormat df = new DecimalFormat("0.000");
- System.out.println("Accumulator: " + accumulator);
- System.out.println("Test Complete. Elapsed Time: " + df.format(elapsed / 1000.0d) + " seconds");
- }
+ return new ComplexSamples(iProcessed, qProcessed, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/complex/IComplexGainControl.java b/src/main/java/io/github/dsheirer/dsp/gain/complex/IComplexGainControl.java
index bc2be9eb..b1ae3cba 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/complex/IComplexGainControl.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/complex/IComplexGainControl.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.dsp.gain.complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
@@ -13,5 +32,5 @@ public interface IComplexGainControl
* @param q samples
* @return amplified gain samples
*/
- ComplexSamples process(float[] i, float[] q);
+ ComplexSamples process(float[] i, float[] q, long timestamp);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/complex/ScalarComplexGain.java b/src/main/java/io/github/dsheirer/dsp/gain/complex/ScalarComplexGain.java
index d6cb9875..300df62c 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/complex/ScalarComplexGain.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/complex/ScalarComplexGain.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.dsp.gain.complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
@@ -22,7 +41,7 @@ public class ScalarComplexGain extends ComplexGain
* @param q samples to amplify
* @return amplified samples
*/
- @Override public ComplexSamples apply(float[] i, float[] q)
+ @Override public ComplexSamples apply(float[] i, float[] q, long timestamp)
{
for(int x = 0; x < i.length; x++)
{
@@ -30,6 +49,6 @@ public class ScalarComplexGain extends ComplexGain
q[x] *= mGain;
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGain.java b/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGain.java
index 899eda23..6b610c09 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGain.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGain.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.dsp.gain.complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
@@ -27,7 +46,7 @@ public class VectorComplexGain extends ComplexGain
* @param q samples to amplify
* @return amplified samples.
*/
- @Override public ComplexSamples apply(float[] i, float[] q)
+ @Override public ComplexSamples apply(float[] i, float[] q, long timestamp)
{
VectorUtilities.checkComplexArrayLength(i, q, VECTOR_SPECIES);
@@ -37,6 +56,6 @@ public class VectorComplexGain extends ComplexGain
FloatVector.fromArray(VECTOR_SPECIES, q, x).mul(mGain).intoArray(q, x);
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGainControl.java b/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGainControl.java
index 2d6d15b5..52dbd4a8 100644
--- a/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGainControl.java
+++ b/src/main/java/io/github/dsheirer/dsp/gain/complex/VectorComplexGainControl.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.dsp.gain.complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
@@ -18,7 +37,7 @@ public class VectorComplexGainControl implements IComplexGainControl
private static final float MINIMUM_ENVELOPE = 0.0001f;
private static final float ENVELOPE_ESTIMATE = 0.4f;
- @Override public ComplexSamples process(float[] i, float[] q)
+ @Override public ComplexSamples process(float[] i, float[] q, long timestamp)
{
VectorUtilities.checkComplexArrayLength(i, q, VECTOR_SPECIES);
@@ -47,6 +66,6 @@ public class VectorComplexGainControl implements IComplexGainControl
FloatVector.fromArray(VECTOR_SPECIES, q, bufferPointer).mul(gain).intoArray(qProcessed, bufferPointer);
}
- return new ComplexSamples(iProcessed, qProcessed);
+ return new ComplexSamples(iProcessed, qProcessed, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/mixer/ComplexMixer.java b/src/main/java/io/github/dsheirer/dsp/mixer/ComplexMixer.java
index 3f531d60..8f34fce7 100644
--- a/src/main/java/io/github/dsheirer/dsp/mixer/ComplexMixer.java
+++ b/src/main/java/io/github/dsheirer/dsp/mixer/ComplexMixer.java
@@ -84,11 +84,12 @@ public abstract class ComplexMixer
/**
* Generates complex samples from the underlying oscillator
* @param sampleCount to generate
+ * @param timestamp of the first sample
* @return complex samples
*/
- protected ComplexSamples generate(int sampleCount)
+ protected ComplexSamples generate(int sampleCount, long timestamp)
{
- return mOscillator.generateComplexSamples(sampleCount);
+ return mOscillator.generateComplexSamples(sampleCount, timestamp);
}
/**
@@ -98,7 +99,7 @@ public abstract class ComplexMixer
*/
public ComplexSamples mix(ComplexSamples samples)
{
- return mix(samples.i(), samples.q());
+ return mix(samples.i(), samples.q(), samples.timestamp());
}
/**
@@ -117,7 +118,5 @@ public abstract class ComplexMixer
* @param q complex samples to mix
* @return mixed samples
*/
- public abstract ComplexSamples mix(float[] i, float[] q);
-
-
+ public abstract ComplexSamples mix(float[] i, float[] q, long timestamp);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/mixer/ScalarComplexMixer.java b/src/main/java/io/github/dsheirer/dsp/mixer/ScalarComplexMixer.java
index bd4cdd60..aa39afe7 100644
--- a/src/main/java/io/github/dsheirer/dsp/mixer/ScalarComplexMixer.java
+++ b/src/main/java/io/github/dsheirer/dsp/mixer/ScalarComplexMixer.java
@@ -52,11 +52,12 @@ public class ScalarComplexMixer extends ComplexMixer
* Mixes the complex I & Q samples with samples generated from an oscillator.
* @param iSamples complex samples to mix
* @param qSamples complex samples to mix
+ * @param timestamp of the first sample
* @return mixed samples
*/
- @Override public ComplexSamples mix(float[] iSamples, float[] qSamples)
+ @Override public ComplexSamples mix(float[] iSamples, float[] qSamples, long timestamp)
{
- ComplexSamples mixer = generate(iSamples.length);
+ ComplexSamples mixer = generate(iSamples.length, timestamp);
float[] iMixer = mixer.i();
float[] qMixer = mixer.q();
@@ -82,7 +83,7 @@ public class ScalarComplexMixer extends ComplexMixer
@Override
public ComplexSamples mix(InterleavedComplexSamples samples)
{
- ComplexSamples mixer = generate(samples.samples().length / 2);
+ ComplexSamples mixer = generate(samples.samples().length / 2, samples.timestamp());
float[] iMixer = mixer.i();
float[] qMixer = mixer.q();
diff --git a/src/main/java/io/github/dsheirer/dsp/mixer/VectorComplexMixer.java b/src/main/java/io/github/dsheirer/dsp/mixer/VectorComplexMixer.java
index b41bae2d..c8cfea15 100644
--- a/src/main/java/io/github/dsheirer/dsp/mixer/VectorComplexMixer.java
+++ b/src/main/java/io/github/dsheirer/dsp/mixer/VectorComplexMixer.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.dsp.mixer;
import io.github.dsheirer.sample.complex.ComplexSamples;
@@ -26,14 +45,15 @@ public class VectorComplexMixer extends ComplexMixer
* Mixes the complex I & Q samples with samples generated from an oscillator.
* @param iSamples complex samples to mix
* @param qSamples complex samples to mix
+ * @param timestamp for the first sample
* @return mixed samples
*/
- @Override public ComplexSamples mix(float[] iSamples, float[] qSamples)
+ @Override public ComplexSamples mix(float[] iSamples, float[] qSamples, long timestamp)
{
VectorUtilities.checkComplexArrayLength(iSamples, qSamples, VECTOR_SPECIES);
//Reuse this complex samples buffer to store the results and return to caller
- ComplexSamples mixer = generate(iSamples.length);
+ ComplexSamples mixer = generate(iSamples.length, timestamp);
float[] iMixer = mixer.i();
float[] qMixer = mixer.q();
diff --git a/src/main/java/io/github/dsheirer/dsp/oscillator/IComplexOscillator.java b/src/main/java/io/github/dsheirer/dsp/oscillator/IComplexOscillator.java
index 9b79e190..e774e885 100644
--- a/src/main/java/io/github/dsheirer/dsp/oscillator/IComplexOscillator.java
+++ b/src/main/java/io/github/dsheirer/dsp/oscillator/IComplexOscillator.java
@@ -33,7 +33,8 @@ public interface IComplexOscillator extends IOscillator
/**
* Generates the specified number of complex samples into a complex samples object.
* @param sampleCount number of complex samples to generate.
+ * @param timestamp for the first sample
* @return generated samples
*/
- ComplexSamples generateComplexSamples(int sampleCount);
+ ComplexSamples generateComplexSamples(int sampleCount, long timestamp);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/oscillator/ScalarComplexOscillator.java b/src/main/java/io/github/dsheirer/dsp/oscillator/ScalarComplexOscillator.java
index e945ae15..29f8d08f 100644
--- a/src/main/java/io/github/dsheirer/dsp/oscillator/ScalarComplexOscillator.java
+++ b/src/main/java/io/github/dsheirer/dsp/oscillator/ScalarComplexOscillator.java
@@ -96,7 +96,7 @@ public class ScalarComplexOscillator extends AbstractOscillator implements IComp
}
@Override
- public ComplexSamples generateComplexSamples(int sampleCount)
+ public ComplexSamples generateComplexSamples(int sampleCount, long timestamp)
{
float[] iSamples = new float[sampleCount];
float[] qSamples = new float[sampleCount];
@@ -133,6 +133,6 @@ public class ScalarComplexOscillator extends AbstractOscillator implements IComp
mPreviousInphase = previousInphase;
mPreviousQuadrature = previousQuadrature;
- return new ComplexSamples(iSamples, qSamples);
+ return new ComplexSamples(iSamples, qSamples, timestamp);
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/oscillator/VectorComplexOscillator.java b/src/main/java/io/github/dsheirer/dsp/oscillator/VectorComplexOscillator.java
index 3c362dde..cea9b836 100644
--- a/src/main/java/io/github/dsheirer/dsp/oscillator/VectorComplexOscillator.java
+++ b/src/main/java/io/github/dsheirer/dsp/oscillator/VectorComplexOscillator.java
@@ -21,14 +21,13 @@ package io.github.dsheirer.dsp.oscillator;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.vector.VectorUtilities;
+import java.util.Arrays;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorSpecies;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Arrays;
-
/**
* Complex oscillator that uses JDK17 SIMD vector operations to generate complex sample arrays.
*
@@ -145,9 +144,10 @@ public class VectorComplexOscillator extends AbstractOscillator implements IComp
/**
* Generates complex samples.
* @param sampleCount number of samples to generate and length of the resulting float array.
+ * @param timestamp of the first sample
* @return generated samples
*/
- @Override public ComplexSamples generateComplexSamples(int sampleCount)
+ @Override public ComplexSamples generateComplexSamples(int sampleCount, long timestamp)
{
if(sampleCount % VECTOR_SPECIES.length() != 0)
{
@@ -184,6 +184,6 @@ public class VectorComplexOscillator extends AbstractOscillator implements IComp
previousInphase.intoArray(mPreviousInphases, 0);
previousQuadrature.intoArray(mPreviousQuadratures, 0);
- return new ComplexSamples(iSamples, qSamples);
+ return new ComplexSamples(iSamples, qSamples, timestamp);
}
}
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 1167a036..734d1355 100644
--- a/src/main/java/io/github/dsheirer/gui/channelizer/SynthesizerViewer.java
+++ b/src/main/java/io/github/dsheirer/gui/channelizer/SynthesizerViewer.java
@@ -34,6 +34,9 @@ import io.github.dsheirer.spectrum.DFTSize;
import io.github.dsheirer.spectrum.SpectrumPanel;
import io.github.dsheirer.spectrum.converter.ComplexDecibelConverter;
import io.github.dsheirer.util.ThreadPool;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.util.concurrent.TimeUnit;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,9 +48,6 @@ import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import java.awt.Dimension;
-import java.awt.EventQueue;
-import java.util.concurrent.TimeUnit;
public class SynthesizerViewer extends JFrame
{
@@ -281,15 +281,15 @@ public class SynthesizerViewer extends JFrame
@Override
public void run()
{
- ComplexSamples channel1Buffer = getChannel1ControlPanel().getOscillator().generateComplexSamples(mSamplesPerCycle);
- ComplexSamples channel2Buffer = getChannel2ControlPanel().getOscillator().generateComplexSamples(mSamplesPerCycle);
+ ComplexSamples channel1Buffer = getChannel1ControlPanel().getOscillator().generateComplexSamples(mSamplesPerCycle, 0l);
+ ComplexSamples channel2Buffer = getChannel2ControlPanel().getOscillator().generateComplexSamples(mSamplesPerCycle, 0l);
ComplexSamples synthesizedBuffer = mSynthesizer.process(channel1Buffer, channel2Buffer);
- getChannel1Panel().receive(new FloatNativeBuffer(channel1Buffer, System.currentTimeMillis()));
+ getChannel1Panel().receive(new FloatNativeBuffer(channel1Buffer));
- getChannel2Panel().receive(new FloatNativeBuffer(channel2Buffer, System.currentTimeMillis()));
+ getChannel2Panel().receive(new FloatNativeBuffer(channel2Buffer));
- getSpectrumPanel().receive(new FloatNativeBuffer(synthesizedBuffer, System.currentTimeMillis()));
+ getSpectrumPanel().receive(new FloatNativeBuffer(synthesizedBuffer));
}
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoder.java b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoder.java
index 32c3bf6e..5b6f19b2 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoder.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoder.java
@@ -42,12 +42,11 @@ import io.github.dsheirer.sample.complex.IComplexSamplesListener;
import io.github.dsheirer.source.ISourceEventListener;
import io.github.dsheirer.source.ISourceEventProvider;
import io.github.dsheirer.source.SourceEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* DMR decoder module.
@@ -147,7 +146,7 @@ public class DMRDecoder extends FeedbackDecoder implements ISourceEventListener,
@Override
public void receive(ComplexSamples samples)
{
- mMessageFramer.setCurrentTime(System.currentTimeMillis());
+ mMessageFramer.setCurrentTime(samples.timestamp());
float[] i = mIBasebandFilter.filter(samples.i());
float[] q = mQBasebandFilter.filter(samples.q());
@@ -155,7 +154,7 @@ public class DMRDecoder extends FeedbackDecoder implements ISourceEventListener,
//Process buffer for power measurements
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderInstrumented.java
index 1c7d1433..cb078cea 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderInstrumented.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderInstrumented.java
@@ -53,20 +53,20 @@ public class DMRDecoderInstrumented extends DMRDecoder
@Override
public void receive(ComplexSamples samples)
{
- mMessageFramer.setCurrentTime(System.currentTimeMillis());
+ mMessageFramer.setCurrentTime(samples.timestamp());
float[] i = mIBasebandFilter.filter(samples.i());
float[] q = mQBasebandFilter.filter(samples.q());
if(mFilteredSymbolListener != null)
{
- mFilteredSymbolListener.receive(new ComplexSamples(i, q));
+ mFilteredSymbolListener.receive(new ComplexSamples(i, q, samples.timestamp()));
}
//Process buffer for power measurements
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java
index de5d4af9..f29d4fad 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java
@@ -1,23 +1,20 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
+ * 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.phase1;
@@ -35,11 +32,10 @@ import io.github.dsheirer.dsp.psk.pll.PLLBandwidth;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.source.SourceEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.util.HashMap;
import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class P25P1DecoderC4FM extends P25P1Decoder
{
@@ -110,7 +106,7 @@ public class P25P1DecoderC4FM extends P25P1Decoder
//Process the buffer for power meter measurements (before gain is applied)
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java
index 6101314b..0e3ee04c 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java
@@ -49,20 +49,20 @@ public class P25P1DecoderC4FMInstrumented extends P25P1DecoderC4FM
@Override
public void receive(ComplexSamples samples)
{
- mMessageFramer.setCurrentTime(System.currentTimeMillis());
+ mMessageFramer.setCurrentTime(samples.timestamp());
float[] i = mIBasebandFilter.filter(samples.i());
float[] q = mQBasebandFilter.filter(samples.q());
if(mFilteredSymbolListener != null)
{
- mFilteredSymbolListener.receive(new ComplexSamples(i, q));
+ mFilteredSymbolListener.receive(new ComplexSamples(i, q, samples.timestamp()));
}
//Process the buffer for power meter measurements (before gain is applied)
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java
index 6db8f44f..5f86ddfc 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java
@@ -1,23 +1,20 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
+ * 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.phase1;
@@ -34,11 +31,10 @@ import io.github.dsheirer.dsp.window.WindowType;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.source.SourceEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.util.HashMap;
import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class P25P1DecoderLSM extends P25P1Decoder
{
@@ -107,7 +103,7 @@ public class P25P1DecoderLSM extends P25P1Decoder
@Override
public void receive(ComplexSamples samples)
{
- mMessageFramer.setCurrentTime(System.currentTimeMillis());
+ mMessageFramer.setCurrentTime(samples.timestamp());
//The filter will decrement the user count when finished
float[] i = mIBasebandFilter.filter(samples.i());
@@ -116,7 +112,7 @@ public class P25P1DecoderLSM extends P25P1Decoder
//Process the buffer for power measurements
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java
index 2cf8b055..9969e16c 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java
@@ -50,7 +50,7 @@ public class P25P1DecoderLSMInstrumented extends P25P1DecoderLSM
@Override
public void receive(ComplexSamples samples)
{
- mMessageFramer.setCurrentTime(System.currentTimeMillis());
+ mMessageFramer.setCurrentTime(samples.timestamp());
//The filter will decrement the user count when finished
float[] i = mIBasebandFilter.filter(samples.i());
@@ -58,13 +58,13 @@ public class P25P1DecoderLSMInstrumented extends P25P1DecoderLSM
if(mFilteredSymbolListener != null)
{
- mFilteredSymbolListener.receive(new ComplexSamples(i, q));
+ mFilteredSymbolListener.receive(new ComplexSamples(i, q, samples.timestamp()));
}
//Process the buffer for power measurements
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java
index 1cf97217..9667cc15 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java
@@ -1,23 +1,20 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
+ * 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.phase2;
@@ -40,11 +37,10 @@ import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameter
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.source.SourceEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.util.HashMap;
import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* P25 Phase 2 HDQPSK 2-timeslot Decoder
@@ -121,7 +117,7 @@ public class P25P2DecoderHDQPSK extends P25P2Decoder implements IdentifierUpdate
//Process the buffer for power measurements
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java
index d6f53e92..ab269b92 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java
@@ -71,7 +71,7 @@ public class P25P2DecoderHDQPSKInstrumented extends P25P2DecoderHDQPSK
//Process the buffer for power measurements
mPowerMonitor.process(i, q);
- ComplexSamples amplified = mAGC.process(i, q);
+ ComplexSamples amplified = mAGC.process(i, q, samples.timestamp());
mQPSKDemodulator.receive(amplified);
}
diff --git a/src/main/java/io/github/dsheirer/record/wave/ComplexSamplesWaveRecorder.java b/src/main/java/io/github/dsheirer/record/wave/ComplexSamplesWaveRecorder.java
index 39140ded..c2e921e0 100644
--- a/src/main/java/io/github/dsheirer/record/wave/ComplexSamplesWaveRecorder.java
+++ b/src/main/java/io/github/dsheirer/record/wave/ComplexSamplesWaveRecorder.java
@@ -28,14 +28,14 @@ import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.util.Dispatcher;
import io.github.dsheirer.util.ThreadPool;
import io.github.dsheirer.util.TimeStamp;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.sound.sampled.AudioFormat;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sound.sampled.AudioFormat;
/**
* WAVE audio recorder module for recording complex (I&Q) samples to a wave file
@@ -46,7 +46,7 @@ public class ComplexSamplesWaveRecorder extends Module implements IComplexSample
private final static Logger mLog = LoggerFactory.getLogger(ComplexSamplesWaveRecorder.class);
private Dispatcher mBufferProcessor = new Dispatcher<>(500,
- "sdrtrunk complex wave recorder", new ComplexSamples(new float[0], new float[0]));
+ "sdrtrunk complex wave recorder", new ComplexSamples(new float[0], new float[0], System.currentTimeMillis()));
private AtomicBoolean mRunning = new AtomicBoolean();
private BufferWaveWriter mWriter;
diff --git a/src/main/java/io/github/dsheirer/sample/SampleUtils.java b/src/main/java/io/github/dsheirer/sample/SampleUtils.java
index 255a26bc..32dbeb68 100644
--- a/src/main/java/io/github/dsheirer/sample/SampleUtils.java
+++ b/src/main/java/io/github/dsheirer/sample/SampleUtils.java
@@ -21,9 +21,8 @@ package io.github.dsheirer.sample;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.sample.complex.ComplexSamples;
-import org.apache.commons.math3.util.FastMath;
-
import java.util.Random;
+import org.apache.commons.math3.util.FastMath;
public class SampleUtils
{
@@ -33,9 +32,10 @@ public class SampleUtils
* Converts from an interleaved complex sample array to a sample record with the
* I and Q in separate arrays.
* @param samples that are interleaved complex samples
+ * @param timestamp of the samples
* @return deinterleaved complex samples instance
*/
- public static ComplexSamples deinterleave(float[] samples)
+ public static ComplexSamples deinterleave(float[] samples, long timestamp)
{
float[] i = new float[samples.length / 2];
float[] q = new float[samples.length / 2];
@@ -49,7 +49,7 @@ public class SampleUtils
q[x] = samples[offset + 1];
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp);
}
/**
@@ -94,7 +94,7 @@ public class SampleUtils
q[x] = (float)Math.sin(angle);
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, System.currentTimeMillis());
}
/**
@@ -119,7 +119,7 @@ public class SampleUtils
q[x] *= gain;
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, System.currentTimeMillis());
}
public static Complex multiply(Complex a, Complex b)
diff --git a/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java b/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java
index 0efef045..40f0d543 100644
--- a/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java
+++ b/src/main/java/io/github/dsheirer/sample/adapter/ComplexShortAdapter.java
@@ -20,11 +20,10 @@ package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Converts 16-bit/2-byte little endian byte data into a reusable buffer of complex float sample data
@@ -62,7 +61,7 @@ public class ComplexShortAdapter implements ISampleAdapter
long now = System.currentTimeMillis();
- return new FloatNativeBuffer(convertedSamples, now);
+ return new FloatNativeBuffer(convertedSamples, now, 192.0f);
}
/**
diff --git a/src/main/java/io/github/dsheirer/sample/complex/ComplexSamples.java b/src/main/java/io/github/dsheirer/sample/complex/ComplexSamples.java
index 9d6fb0cd..936d3936 100644
--- a/src/main/java/io/github/dsheirer/sample/complex/ComplexSamples.java
+++ b/src/main/java/io/github/dsheirer/sample/complex/ComplexSamples.java
@@ -22,7 +22,7 @@ package io.github.dsheirer.sample.complex;
/**
* Wrapper for a complex sample array where I and Q samples are in separate arrays.
*/
-public record ComplexSamples(float[] i, float[] q)
+public record ComplexSamples(float[] i, float[] q, long timestamp)
{
/**
* Converts this non-interleaved complex samples to interleaved.
diff --git a/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesNativeBufferAdapter.java b/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesNativeBufferAdapter.java
index 5597c317..137ef18e 100644
--- a/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesNativeBufferAdapter.java
+++ b/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesNativeBufferAdapter.java
@@ -28,7 +28,6 @@ import java.util.Iterator;
public class ComplexSamplesNativeBufferAdapter implements INativeBuffer
{
private ComplexSamples mComplexSamples;
- private long mTimestamp = System.currentTimeMillis();
/**
* Constructs an instance
@@ -60,7 +59,7 @@ public class ComplexSamplesNativeBufferAdapter implements INativeBuffer
@Override
public long getTimestamp()
{
- return mTimestamp;
+ return mComplexSamples.timestamp();
}
/**
diff --git a/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesRepackager.java b/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesRepackager.java
deleted file mode 100644
index 1164e3e7..00000000
--- a/src/main/java/io/github/dsheirer/sample/complex/ComplexSamplesRepackager.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- * ****************************************************************************
- */
-
-package io.github.dsheirer.sample.complex;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Processes I & Q sample arrays into uniform length complex samples buffers.
- */
-public class ComplexSamplesRepackager
-{
- private int mSize;
- private float[] mIResidual = new float[0];
- private float[] mQResidual = new float[0];
-
- /**
- * Constructs an instance.
- * @param size or length of the output complex samples.
- */
- public ComplexSamplesRepackager(int size)
- {
- mSize = size;
- }
-
- /**
- * Combines the I & Q sample arrays with any residual leftover from the previous invocation and
- * chunks the arrays up into uniform length complex sample buffers, storing any leftover samples
- * as residual to use in the next processing invocation. If the length of the sample arguments
- * combined with any residual is not enough to create at least one buffer, those samples will be
- * added to the residual and used in the next operation, and no complex sample buffer will be
- * returned.
- *
- * @param i samples array to repackage
- * @param q samples array to repackage
- * @return zero or more complex samples of uniform length.
- */
- public List process(float[] i, float[] q)
- {
- float[] iCombined = new float[mIResidual.length + i.length];
- float[] qCombined = new float[mQResidual.length + q.length];
-
- if(mIResidual.length > 0)
- {
- System.arraycopy(mIResidual, 0, iCombined, 0, mIResidual.length);
- System.arraycopy(mQResidual, 0, qCombined, 0, mQResidual.length);
- }
-
- System.arraycopy(i, 0, iCombined, mIResidual.length, i.length);
- System.arraycopy(q, 0, qCombined, mQResidual.length, q.length);
-
- int processed = 0;
-
- List samples = new ArrayList<>();
-
- while((processed + mSize) < iCombined.length)
- {
- float[] iChunk = Arrays.copyOfRange(iCombined, processed, processed + mSize);
- float[] qChunk = Arrays.copyOfRange(qCombined, processed, processed + mSize);
- samples.add(new ComplexSamples(iChunk, qChunk));
- processed += mSize;
- }
-
- if(processed < iCombined.length)
- {
- mIResidual = Arrays.copyOfRange(iCombined, processed, iCombined.length);
- mQResidual = Arrays.copyOfRange(qCombined, processed, qCombined.length);
- }
- else
- {
- mIResidual = new float[0];
- mQResidual = new float[0];
- }
-
- return samples;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/sample/complex/InterleavedComplexSamples.java b/src/main/java/io/github/dsheirer/sample/complex/InterleavedComplexSamples.java
index d08ac31b..b42e47f7 100644
--- a/src/main/java/io/github/dsheirer/sample/complex/InterleavedComplexSamples.java
+++ b/src/main/java/io/github/dsheirer/sample/complex/InterleavedComplexSamples.java
@@ -41,6 +41,6 @@ public record InterleavedComplexSamples(float[] samples, long timestamp) impleme
q[x] = samples()[x / 2 + 1];
}
- return new ComplexSamples(i, q);
+ return new ComplexSamples(i, q, timestamp());
}
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java
index 9d125e34..7c74f998 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java
@@ -26,6 +26,12 @@ import io.github.dsheirer.source.tuner.ITunerErrorListener;
import io.github.dsheirer.source.tuner.TunerType;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.usb.USBTunerController;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
import org.apache.commons.io.EndianUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,12 +39,6 @@ import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;
import javax.usb.UsbException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
/**
* Airspy tuner controller
@@ -272,6 +272,7 @@ public class AirspyTunerController extends USBTunerController
*/
public void setSampleRate(AirspySampleRate rate) throws LibUsbException, UsbException, SourceException
{
+ getNativeBufferFactory().setSamplesPerMillisecond((float)rate.getRate() / 1000.0f);
if(rate.getRate() != mSampleRate)
{
int result = readByte(Command.SET_SAMPLE_RATE, 0, rate.getIndex(), true);
diff --git a/src/main/java/io/github/dsheirer/source/tuner/channel/HalfBandTunerChannelSource.java b/src/main/java/io/github/dsheirer/source/tuner/channel/HalfBandTunerChannelSource.java
index 23e02c88..2df83923 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/channel/HalfBandTunerChannelSource.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/channel/HalfBandTunerChannelSource.java
@@ -29,11 +29,10 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.util.Dispatcher;
+import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Iterator;
-
/**
* Complex sample source that provides a frequency-translated and decimated sample buffer stream. Uses a
* CIC decimation filter that requires the decimation rate to be an integer multiple. Sample buffer processing
@@ -229,7 +228,7 @@ public class HalfBandTunerChannelSource extends TunerCh
ComplexSamples basebanded = mFrequencyCorrectionMixer.mix(iterator.next());
float[] i = mIDecimationFilter.decimateReal(basebanded.i());
float[] q = mQDecimationFilter.decimateReal(basebanded.q());
- mStreamHeartbeatProcessor.receive(new ComplexSamples(i, q));
+ mStreamHeartbeatProcessor.receive(new ComplexSamples(i, q, basebanded.timestamp()));
}
}
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java
index eaedae4f..3d20b81a 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java
@@ -25,6 +25,10 @@ import io.github.dsheirer.source.tuner.ITunerErrorListener;
import io.github.dsheirer.source.tuner.TunerType;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.usb.USBTunerController;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.EnumSet;
import org.apache.commons.io.EndianUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,10 +36,6 @@ import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;
import javax.usb.UsbException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.EnumSet;
public class HackRFTunerController extends USBTunerController
{
@@ -404,6 +404,7 @@ public class HackRFTunerController extends USBTunerController
mFrequencyController.setSampleRate(rate.getRate());
setBasebandFilter(rate.getFilter());
mSampleRate = rate;
+ getNativeBufferFactory().setSamplesPerMillisecond((float)getSampleRate() / 1000.0f);
}
public void setSampleRateManual(int frequency, int divider) throws UsbException
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java
index 65de47e5..876ae8a3 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerController.java
@@ -27,6 +27,12 @@ import io.github.dsheirer.source.tuner.TunerFactory;
import io.github.dsheirer.source.tuner.TunerType;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.usb.USBTunerController;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.usb4java.DeviceHandle;
@@ -35,12 +41,6 @@ import org.usb4java.LibUsbException;
import javax.usb.UsbDisconnectedException;
import javax.usb.UsbException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.locks.ReentrantLock;
/**
* RTL-2832 tuner controller implementation.
@@ -953,6 +953,9 @@ public class RTL2832TunerController extends USBTunerController
setSampleRateFilters(sampleRate.getRate());
mSampleRate = sampleRate;
mFrequencyController.setSampleRate(sampleRate.getRate());
+
+ //Updates native buffer factory so that sample buffers can be accurately timestamped
+ getNativeBufferFactory().setSamplesPerMillisecond(sampleRate.getRate() / 1000.0f);
}
finally
{
diff --git a/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java b/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java
index 8914c7fa..69e39893 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/test/SampleGenerator.java
@@ -25,13 +25,12 @@ import io.github.dsheirer.dsp.oscillator.OscillatorFactory;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.util.ThreadPool;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
public class SampleGenerator
{
private final static Logger mLog = LoggerFactory.getLogger(SampleGenerator.class);
@@ -189,7 +188,7 @@ public class SampleGenerator
long now = System.currentTimeMillis();
- FloatNativeBuffer buffer = new FloatNativeBuffer(samples, now);
+ FloatNativeBuffer buffer = new FloatNativeBuffer(samples, now, 0.0f);
mNativeBufferBroadcaster.broadcast(buffer);
diff --git a/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java b/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java
index e089d192..d6d74a99 100644
--- a/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java
+++ b/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java
@@ -28,6 +28,11 @@ import io.github.dsheirer.source.IFrameLocationListener;
import io.github.dsheirer.source.Source;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.util.ThreadPool;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,11 +41,6 @@ import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
public class ComplexWaveSource extends Source implements IControllableFileSource, AutoCloseable
{
@@ -276,7 +276,8 @@ public class ComplexWaveSource extends Source implements IControllableFileSource
}
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
- mListener.receive(new FloatNativeBuffer(samples, System.currentTimeMillis()));
+ mListener.receive(new FloatNativeBuffer(samples, System.currentTimeMillis(),
+ mInputStream.getFormat().getSampleRate() / 1000.0f));
}
}
}
diff --git a/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedCalibration.java b/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedCalibration.java
index 249d70bd..e0d2093d 100644
--- a/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedCalibration.java
+++ b/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedCalibration.java
@@ -214,7 +214,7 @@ public class AirspyUnpackedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorScalar iterator = new AirspyBufferIteratorScalar(samples, residualI,
- residualQ, 0.0f, System.currentTimeMillis());
+ residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -235,7 +235,7 @@ public class AirspyUnpackedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector64Bits iterator = new AirspyBufferIteratorVector64Bits(samples, residualI,
- residualQ, 0.0f, System.currentTimeMillis());
+ residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -255,7 +255,7 @@ public class AirspyUnpackedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector128Bits iterator = new AirspyBufferIteratorVector128Bits(samples, residualI,
- residualQ, 0.0f, System.currentTimeMillis());
+ residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -276,7 +276,8 @@ public class AirspyUnpackedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector256Bits iterator =
- new AirspyBufferIteratorVector256Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
+ new AirspyBufferIteratorVector256Bits(samples, residualI, residualQ, 0.0f,
+ System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -297,7 +298,8 @@ public class AirspyUnpackedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector512Bits iterator =
- new AirspyBufferIteratorVector512Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
+ new AirspyBufferIteratorVector512Bits(samples, residualI, residualQ, 0.0f,
+ System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
diff --git a/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedInterleavedCalibration.java b/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedInterleavedCalibration.java
index 893c44f8..daf7accf 100644
--- a/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedInterleavedCalibration.java
+++ b/src/main/java/io/github/dsheirer/vector/calibrate/airspy/AirspyUnpackedInterleavedCalibration.java
@@ -225,7 +225,7 @@ public class AirspyUnpackedInterleavedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorScalar iterator = new AirspyInterleavedBufferIteratorScalar(samples, residualI,
- residualQ, 0.0f, System.currentTimeMillis());
+ residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -246,7 +246,7 @@ public class AirspyUnpackedInterleavedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorVector64Bits iterator = new AirspyInterleavedBufferIteratorVector64Bits(samples, residualI,
- residualQ, 0.0f, System.currentTimeMillis());
+ residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -267,7 +267,7 @@ public class AirspyUnpackedInterleavedCalibration extends Calibration
for(int x = 0; x < ITERATION_DURATION_MS; x++)
{
AirspyInterleavedBufferIteratorVector128Bits iterator = new AirspyInterleavedBufferIteratorVector128Bits(samples, residualI,
- residualQ, 0.0f, System.currentTimeMillis());
+ residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -288,7 +288,7 @@ public class AirspyUnpackedInterleavedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorVector256Bits iterator =
- new AirspyInterleavedBufferIteratorVector256Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
+ new AirspyInterleavedBufferIteratorVector256Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
@@ -309,7 +309,8 @@ public class AirspyUnpackedInterleavedCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorVector512Bits iterator =
- new AirspyInterleavedBufferIteratorVector512Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
+ new AirspyInterleavedBufferIteratorVector512Bits(samples, residualI, residualQ, 0.0f,
+ System.currentTimeMillis(), 0.0f);
while(iterator.hasNext() && ((System.currentTimeMillis() - start) < ITERATION_DURATION_MS))
{
diff --git a/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainCalibration.java b/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainCalibration.java
index d5811b75..f1248e8c 100644
--- a/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainCalibration.java
+++ b/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainCalibration.java
@@ -121,7 +121,7 @@ public class ComplexGainCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples amplified = scalar.apply(i, q);
+ ComplexSamples amplified = scalar.apply(i, q, start);
accumulator += amplified.i()[2];
count++;
}
@@ -140,7 +140,7 @@ public class ComplexGainCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples amplified = scalar.apply(i, q);
+ ComplexSamples amplified = scalar.apply(i, q, start);
accumulator += amplified.i()[2];
count++;
}
diff --git a/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainControlCalibration.java b/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainControlCalibration.java
index ea5146e7..708b5d3f 100644
--- a/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainControlCalibration.java
+++ b/src/main/java/io/github/dsheirer/vector/calibrate/gain/ComplexGainControlCalibration.java
@@ -116,7 +116,7 @@ public class ComplexGainControlCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples amplified = mScalarGainControl.process(i, q);
+ ComplexSamples amplified = mScalarGainControl.process(i, q, 0l);
accumulator += amplified.i()[2];
count++;
}
@@ -133,7 +133,7 @@ public class ComplexGainControlCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples amplified = mVectorGainControl.process(i, q);
+ ComplexSamples amplified = mVectorGainControl.process(i, q, 0l);
accumulator += amplified.i()[2];
count++;
}
diff --git a/src/main/java/io/github/dsheirer/vector/calibrate/hilbert/HilbertCalibration.java b/src/main/java/io/github/dsheirer/vector/calibrate/hilbert/HilbertCalibration.java
index 0a71df56..ce1f545d 100644
--- a/src/main/java/io/github/dsheirer/vector/calibrate/hilbert/HilbertCalibration.java
+++ b/src/main/java/io/github/dsheirer/vector/calibrate/hilbert/HilbertCalibration.java
@@ -255,7 +255,7 @@ public class HilbertCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples complex = mScalar.filter(samples);
+ ComplexSamples complex = mScalar.filter(samples, start);
accumulator += complex.i()[0];
count++;
}
@@ -272,7 +272,7 @@ public class HilbertCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples complex = mVectorPreferred.filter(samples);
+ ComplexSamples complex = mVectorPreferred.filter(samples, start);
accumulator += complex.i()[0];
count++;
}
@@ -289,7 +289,7 @@ public class HilbertCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples complex = mVector512.filter(samples);
+ ComplexSamples complex = mVector512.filter(samples, start);
accumulator += complex.i()[0];
count++;
}
@@ -306,7 +306,7 @@ public class HilbertCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples complex = mVector256.filter(samples);
+ ComplexSamples complex = mVector256.filter(samples, start);
accumulator += complex.i()[0];
count++;
}
@@ -323,7 +323,7 @@ public class HilbertCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples complex = mVector128.filter(samples);
+ ComplexSamples complex = mVector128.filter(samples, start);
accumulator += complex.i()[0];
count++;
}
@@ -340,7 +340,7 @@ public class HilbertCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples complex = mVector64.filter(samples);
+ ComplexSamples complex = mVector64.filter(samples, start);
accumulator += complex.i()[0];
count++;
}
diff --git a/src/main/java/io/github/dsheirer/vector/calibrate/mixer/ComplexMixerCalibration.java b/src/main/java/io/github/dsheirer/vector/calibrate/mixer/ComplexMixerCalibration.java
index 9bc312fe..94011d42 100644
--- a/src/main/java/io/github/dsheirer/vector/calibrate/mixer/ComplexMixerCalibration.java
+++ b/src/main/java/io/github/dsheirer/vector/calibrate/mixer/ComplexMixerCalibration.java
@@ -115,7 +115,7 @@ public class ComplexMixerCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples mixed = mScalarComplexMixer.mix(i, q);
+ ComplexSamples mixed = mScalarComplexMixer.mix(i, q, start);
accumulator += mixed.i()[2];
count++;
}
@@ -131,7 +131,7 @@ public class ComplexMixerCalibration extends Calibration
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
- ComplexSamples mixed = mVectorComplexMixer.mix(i, q);
+ ComplexSamples mixed = mVectorComplexMixer.mix(i, q, start);
accumulator += mixed.i()[2];
count++;
}