Updates pull request from Roman Tsypuk to convert the build system from

ant to gradle.  Removes linux and windows application launch scripts and
produces an executable jar with all resources included.
This commit is contained in:
Denny
2017-12-17 07:28:03 -05:00
parent a1535c4157
commit 9316599dec
981 changed files with 8368 additions and 9049 deletions

View File

@@ -0,0 +1,86 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Broadcasts an item to multiple listeners
*/
public class Broadcaster<T> implements Listener<T>
{
private List<Listener<T>> mListeners = new CopyOnWriteArrayList<>();
@Override
public void receive( T t )
{
broadcast( t );
}
/**
* Clear listeners to prepare for garbage collection
*/
public void dispose()
{
mListeners.clear();
}
public boolean hasListeners()
{
return !mListeners.isEmpty();
}
public int getListenerCount()
{
return mListeners.size();
}
public List<Listener<T>> getListeners()
{
return mListeners;
}
public void addListener( Listener<T> listener )
{
if(listener == null)
{
throw new IllegalArgumentException("Listener cannot be null");
}
mListeners.add( listener );
}
public void removeListener( Listener<T> listener )
{
mListeners.remove( listener );
}
public void clear()
{
mListeners.clear();
}
public void broadcast( T t )
{
for( Listener<T> listener: mListeners )
{
listener.receive( t );
}
}
}

View File

@@ -0,0 +1,24 @@
package io.github.dsheirer.sample;
public class Buffer
{
protected float[] mSamples;
public Buffer( float[] samples )
{
mSamples = samples;
}
public float[] getSamples()
{
return mSamples;
}
/**
* Cleanup method to nullify all data and references
*/
public void dispose()
{
mSamples = null;
}
}

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample;
/**
* Buffer overflow event. Used for broadcasting overflow events to listeners.
*/
public class BufferOverflow
{
private String mSource;
public BufferOverflow( String source )
{
mSource = source;
}
public String getSource()
{
return mSource;
}
}

View File

@@ -0,0 +1,72 @@
package io.github.dsheirer.sample;
import io.github.dsheirer.sample.real.RealBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
/**
* Utilities for converting to/from signed 16-bit sample byte arrays and float buffers
*/
public class ConversionUtils
{
public static float[] convertFromSigned16BitSamples( byte[] bytes )
{
return convertFromSigned16BitSamples( ByteBuffer.wrap( bytes ) );
}
/**
* Converts the byte buffer containing 16-bit samples into a float array
*/
public static float[] convertFromSigned16BitSamples( ByteBuffer buffer )
{
ShortBuffer byteBuffer =
buffer.order( ByteOrder.LITTLE_ENDIAN ).asShortBuffer();
float[] samples = new float[ buffer.limit() / 2 ];
for( int x = 0; x < samples.length; x++ )
{
samples[ x ] = (float)byteBuffer.get() / 32767.0f;
}
return samples;
}
/**
* Converts the float samples into a little-endian 16-bit sample byte buffer.
* @param samples - float array of sample data
* @return - little-endian 16-bit sample byte buffer
*/
public static ByteBuffer convertToSigned16BitSamples( float[] samples )
{
ByteBuffer converted = ByteBuffer.allocate( samples.length * 2 );
converted.order( ByteOrder.LITTLE_ENDIAN );
for( float sample: samples )
{
converted.putShort( (short)( sample * Short.MAX_VALUE ) );
}
return converted;
}
/**
* Converts the float samples in a complex buffer to a little endian 16-bit
* buffer
*/
public static ByteBuffer convertToSigned16BitSamples( Buffer buffer )
{
return convertToSigned16BitSamples( buffer.getSamples() );
}
/**
* Converts the float samples in a complex buffer to a little endian 16-bit
* buffer
*/
public static ByteBuffer convertToSigned16BitSamples( RealBuffer buffer )
{
return convertToSigned16BitSamples( buffer.getSamples() );
}
}

View File

@@ -0,0 +1,23 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample;
public interface Listener<T>
{
public void receive( T t );
}

View File

@@ -0,0 +1,128 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.sample;
import io.github.dsheirer.sample.real.IOverflowListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class OverflowableTransferQueue<E>
{
private final static Logger mLog = LoggerFactory.getLogger(OverflowableTransferQueue.class);
public enum State {NORMAL, OVERFLOW};
private IOverflowListener mOverflowListener;
private LinkedTransferQueue<E> mQueue = new LinkedTransferQueue<E>();
private AtomicInteger mCounter = new AtomicInteger();
private AtomicBoolean mOverflow = new AtomicBoolean();
private int mMaximumSize;
private int mResetThreshold;
/**
* Concurrent transfer queue that couples a higher-throughput linked transfer queue with an atomic integer for
* monitoring queue size. When the queue size exceeds maximum size (overflow), all inbound elements are ignored
* until the queue size is reduced to or below the reset threshold.
*
* @param maximumSize of the queue. Overflow state will occur once queue size exceeds this value.
* @param resetThreshold for resetting overflow state to normal, once queue size is at or below this value.
*/
public OverflowableTransferQueue(int maximumSize, int resetThreshold)
{
mMaximumSize = maximumSize;
mResetThreshold = resetThreshold;
}
/**
* Adds the element to the queue if able to do so without exceeding maximum queue size. Otherwise, ignores
* the element.
*/
public void offer(E e)
{
if(!mOverflow.get())
{
mQueue.offer(e);
int size = mCounter.incrementAndGet();
if(size > mMaximumSize)
{
setOverflow(true);
}
}
}
/**
* Retrieves elements from the queue into the collection up to the maximum number of elements specified
*/
public int drainTo(Collection<? super E> collection, int maxElements)
{
int drainCount = mQueue.drainTo(collection, maxElements);
int size = mCounter.addAndGet(-drainCount);
if(mOverflow.get() && size <= mResetThreshold)
{
setOverflow(false);
}
return drainCount;
}
/**
* Sets a listener to receive overflow state change events
*/
public void setOverflowListener(IOverflowListener listener)
{
mOverflowListener = listener;
}
/**
* Toggles the overflow state and broadcast state change to listener
*/
private void setOverflow(boolean overflow)
{
if(mOverflow.compareAndSet(!overflow, overflow))
{
if(mOverflowListener != null)
{
mOverflowListener.sourceOverflow(overflow);
}
}
}
/**
* Clears all elements from the queue and resets the internal counter to 0
*/
public void clear()
{
synchronized(mQueue)
{
mQueue.clear();
mCounter.set(0);
mOverflow.set(false);
}
}
}

View File

@@ -0,0 +1,25 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample;
public interface Provider<T>
{
public void setListener( Listener<T> listener );
public void removeListener( Listener<T> listener );
}

View File

@@ -0,0 +1,8 @@
package io.github.dsheirer.sample;
public enum SampleType
{
COMPLEX, //Baseband
REAL, //Demodulated
COMPLEX_AND_REAL; //Baseband and Demodulated
}

View File

@@ -0,0 +1,52 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.adapter;
public class ByteSampleAdapter implements ISampleAdapter
{
private final static float[] LOOKUP_VALUES;
/**
* Creates a static lookup table that converts the 8-bit valued range
* from 0 - 255 into scaled float values of -1.0 to 0 to 1.0
*/
static
{
LOOKUP_VALUES = new float[ 256 ];
for( int x = 0; x < 256; x++ )
{
LOOKUP_VALUES[ x ] = (float)( x - 127 ) / 128.0f;
}
}
@Override
public float[] convert( byte[] samples )
{
float[] convertedSamples = new float[ samples.length ];
int pointer = 0;
for( byte sample: samples )
{
/* Convert byte value into float from the lookup table */
convertedSamples[ pointer++ ] = LOOKUP_VALUES[ ( sample & 0xFF ) ];
}
return convertedSamples;
}
}

View File

@@ -0,0 +1,87 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.source.mixer.MixerChannel;
import org.apache.commons.lang3.Validate;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Converts 16-bit little endian byte data into an array of floats
*/
public class ChannelShortAdapter implements ISampleAdapter
{
private ShortToFloatMap mMap = new ShortToFloatMap();
private ByteOrder mByteOrder = ByteOrder.LITTLE_ENDIAN;
private MixerChannel mMixerChannel;
public ChannelShortAdapter( MixerChannel channel )
{
/* Only use with LEFT/RIGHT channels */
Validate.isTrue(channel != MixerChannel.MONO);
mMixerChannel = channel;
}
@Override
public float[] convert( byte[] samples )
{
float[] processed = new float[ samples.length / 4 ];
int pointer = 0;
/* Wrap byte array in a byte buffer so we can process them as shorts */
ByteBuffer buffer = ByteBuffer.wrap( samples );
/* Set endian to correct byte ordering */
buffer.order( mByteOrder );
while( buffer.hasRemaining() )
{
if( mMixerChannel == MixerChannel.LEFT )
{
processed[ pointer ] = mMap.get( buffer.getShort() );
/* Throw away the right channel */
buffer.getShort();
}
else
{
/* Throw away the left channel */
buffer.getShort();
processed[ pointer ] = mMap.get( buffer.getShort() );
}
pointer++;
}
return processed;
}
/**
* Set byte interpretation to little or big endian. Defaults to LITTLE
* endian
*/
public void setByteOrder( ByteOrder order )
{
mByteOrder = order;
}
}

View File

@@ -0,0 +1,57 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.source.mixer.MixerChannel;
import java.util.List;
/**
* Receives complex samples and send either the left channel or the right
* channel to the short sample listener
*/
public class ComplexToFloatSampleConverter implements Listener<List<Complex>>
{
private MixerChannel mChannel;
private Listener<Float> mListener;
public ComplexToFloatSampleConverter( Listener<Float> listener,
MixerChannel channel )
{
mListener = listener;
mChannel = channel;
}
@Override
public void receive( List<Complex> samples )
{
for( Complex sample: samples )
{
mListener.receive( mChannel == MixerChannel.LEFT ?
sample.left() :
sample.right() );
}
}
public Listener<Float> getListener()
{
return mListener;
}
}

View File

@@ -0,0 +1,61 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.Complex;
public class FloatArrayToComplexAdapter implements Listener<Float[]>
{
private Listener<Complex> mListener;
@Override
public void receive( Float[] samples )
{
if( samples != null )
{
for( int x = 0; x < samples.length; x += 2 )
{
if( mListener != null &&
samples[ x ] != null &&
samples[ x + 1 ] != null )
{
mListener.receive( new Complex( samples[ x ],
samples[ x + 1 ] ) );
}
}
samples = null;
}
}
public void setListener( Listener<Complex> listener )
{
mListener = listener;
}
public void removeListener( Listener<Complex> listener )
{
mListener = null;
}
public void dispose()
{
mListener = null;
}
}

View File

@@ -0,0 +1,27 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.adapter;
/*
* Adapter to convert byte data received from a data stream into float[]
* samples
*/
public interface ISampleAdapter
{
public abstract float[] convert( byte[] samples );
}

View File

@@ -0,0 +1,62 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Converts 16-bit little endian byte data into an array of floats
*/
public class ShortAdapter implements ISampleAdapter
{
private ShortToFloatMap mMap = new ShortToFloatMap();
private ByteOrder mByteOrder = ByteOrder.LITTLE_ENDIAN;
@Override
public float[] convert( byte[] samples )
{
float[] processed = new float[ samples.length / 2 ];
int pointer = 0;
/* Wrap byte array in a byte buffer so we can process them as shorts */
ByteBuffer buffer = ByteBuffer.wrap( samples );
/* Set endian to correct byte ordering */
buffer.order( mByteOrder );
while( buffer.hasRemaining() )
{
processed[ pointer ] = mMap.get( buffer.getShort() );
pointer++;
}
return processed;
}
/**
* Set byte interpretation to little or big endian. Defaults to LITTLE
* endian
*/
public void setByteOrder( ByteOrder order )
{
mByteOrder = order;
}
}

View File

@@ -0,0 +1,19 @@
package io.github.dsheirer.sample.adapter;
public class ShortToFloatMap
{
private static float[] MAP = new float[ 65536 ];
static
{
for( int x = 0; x < 65536; x++ )
{
MAP[ x] = (float)( x - 32768 ) / 32768.0f;
}
}
public float get( short value )
{
return MAP[ 32768 + value ];
}
}

View File

@@ -0,0 +1,25 @@
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.source.tuner.hackrf.HackRFTunerController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test
{
private final static Logger mLog =
LoggerFactory.getLogger( HackRFTunerController.class );
public static void main( String[] args )
{
mLog.debug( "Starting" );
ShortToFloatMap map1 = new ShortToFloatMap();
for( short x = -32768; x < -32758; x++ )
{
mLog.debug( "X:" + x + " value:" + map1.get( x ) );
}
mLog.debug( "Finished" );
}
}

View File

@@ -0,0 +1,433 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
/**
* Complex sample and related utility methods
*/
public class Complex implements Serializable
{
private final static Logger mLog =
LoggerFactory.getLogger( Complex.class );
private static final long serialVersionUID = 1L;
private float mLeft;
private float mRight;
public Complex( float left, float right )
{
mLeft = left;
mRight = right;
}
public Complex()
{
this( 0.0f, 0.0f );
}
public void setInphase( float inphase )
{
mLeft = inphase;
}
public void setQuadrature( float quadrature )
{
mRight = quadrature;
}
public void setValues( float inphase, float quadrature )
{
mLeft = inphase;
mRight = quadrature;
}
public Complex copy()
{
return new Complex( mLeft, mRight );
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( "I:" );
sb.append( mLeft );
sb.append( " Q:" );
sb.append( mRight );
return sb.toString();
}
/**
* Returns a new sample representing the conjugate of this one
*/
public Complex conjugate()
{
return new Complex( mLeft, -mRight );
}
/**
* Multiplies this sample by the scalor value
*/
public void multiply( float scalor )
{
mLeft *= scalor;
mRight *= scalor;
}
public static Complex multiply( Complex sample, float scalor )
{
return new Complex( sample.left() * scalor,
sample.right() * scalor );
}
/**
* Calculates the inphase component of multiplying two complex numbers, A and B.
*/
public static float multiplyInphase( float inphaseA, float quadratureA, float inphaseB, float quadratureB )
{
return ( inphaseA * inphaseB ) - ( quadratureA * quadratureB );
}
/**
* Calculates the quadrature component of multiplying two complex numbers, A and B.
*/
public static float multiplyQuadrature( float inphaseA, float quadratureA, float inphaseB, float quadratureB )
{
return ( quadratureA * inphaseB ) + ( inphaseA * quadratureB );
}
/**
* Multiplies this sample by the multiplier sample
*/
public void multiply( Complex multiplier )
{
float inphase = multiplyInphase( inphase(), quadrature(),
multiplier.inphase(), multiplier.quadrature() );
float quadrature = multiplyQuadrature( inphase(), quadrature(),
multiplier.inphase(), multiplier.quadrature() );
mLeft = inphase;
mRight = quadrature;
}
/**
* Multiplies both samples returning a new sample with the results
*/
public static Complex multiply( Complex sample1, Complex sample2 )
{
float inphase = multiplyInphase( sample1.inphase(), sample1.quadrature(),
sample2.inphase(), sample2.quadrature() );
float quadrature = multiplyQuadrature( sample1.inphase(), sample1.quadrature(),
sample2.inphase(), sample2.quadrature() );
return new Complex( inphase, quadrature );
}
public static Complex multiply( Complex sample,
Float inphase, Float quadrature )
{
float i = multiplyInphase( sample.inphase(), sample.quadrature(),
inphase, quadrature );
float q = multiplyQuadrature( sample.inphase(), sample.quadrature(),
inphase, quadrature );
return new Complex( i, q );
}
public static Complex multiply( Float inphase, Float quadrature, Complex sample )
{
float i = multiplyInphase( inphase, quadrature, sample.inphase(), sample.quadrature() );
float q = multiplyQuadrature( inphase, quadrature, sample.inphase(), sample.quadrature() );
return new Complex( i, q );
}
public static Complex multiply( float inphaseA, float quadratureA, float inphaseB, float quadratureB )
{
float i = multiplyInphase( inphaseA, quadratureA, inphaseB, quadratureB );
float q = multiplyQuadrature( inphaseA, quadratureA, inphaseB, quadratureB );
return new Complex( i, q );
}
/**
* Adds the adder sample value to this sample
*/
public void add( Complex adder )
{
mLeft += adder.left();
mRight += adder.right();
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static Complex add( Complex first, Complex second )
{
return new Complex( first.left() + second.left(),
first.right() + second.right() );
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static Complex subtract( Complex first, Complex second )
{
return new Complex( first.left() - second.left(),
first.right() - second.right() );
}
/**
* Magnitude of this sample
*/
public float magnitude()
{
return (float)Math.sqrt( magnitudeSquared() );
}
public static float magnitude( float inphase, float quadrature )
{
return (float)Math.sqrt( ( inphase * inphase ) + ( quadrature * quadrature ) );
}
/**
* Magnitude squared of this sample
*/
public float magnitudeSquared()
{
return norm();
}
/**
* Norm of this sample = ( i * i ) + ( q * q )
*/
public float norm()
{
return (float)( ( inphase() * inphase() ) +
( quadrature() * quadrature() ) );
}
/**
* Returns the vector length to 1 (unit circle)
*/
public void normalize()
{
float magnitude = magnitude();
if( magnitude != 0 )
{
multiply( (float)( 1.0f / magnitude() ) );
}
}
/**
* Returns the vector length to 1 (unit circle),
* avoiding square root multiplication
*/
public void fastNormalize()
{
multiply( (float)( 1.95f - magnitudeSquared() ) );
}
public float left()
{
return mLeft;
}
public float right()
{
return mRight;
}
public float inphase()
{
return mLeft;
}
/**
* Absolute value of in-phase component
*/
public float inPhaseAbsolute()
{
return Math.abs( mLeft );
}
public float quadrature()
{
return mRight;
}
/**
* Absolute value of quadrature component
*/
public float quadratureAbsolute()
{
return Math.abs( mRight );
}
public float x()
{
return mLeft;
}
public float y()
{
return mRight;
}
public float real()
{
return mLeft;
}
/**
* Absolute value of real component
*/
public float realAbsolute()
{
return Math.abs( mLeft );
}
public float imaginary()
{
return mRight;
}
/**
* Absolute value of imaginary component
*/
public float imaginaryAbsolute()
{
return Math.abs( mRight );
}
/**
* Returns the greater absolute value between left and right values
*/
public float maximumAbsolute()
{
if( Math.abs( mLeft ) > Math.abs( mRight ) )
{
return Math.abs( mLeft );
}
else
{
return Math.abs( mRight );
}
}
/**
* Creates a new complex sample representing the angle with unit circle
* magnitude
* @param angle in radians
* @return
*/
public static Complex fromAngle( float angle )
{
return new Complex( (float)Math.cos( angle ),
(float)Math.sin( angle ) );
}
/**
* Angle of this sample in radians
*/
public float angle()
{
return (float)Math.atan2( y(), x() );
}
/**
* Constrains the i and q quantities to +/- value.
*
* @param value - maximum absolute value
*/
public void clip( float value )
{
if( mLeft > value )
{
mLeft = value;
}
else if( mLeft < -value )
{
mLeft = -value;
}
if( mRight > value )
{
mRight = value;
}
else if( mRight < -value )
{
mRight = -value;
}
}
/**
* Angle of this sample in degrees
*/
public float polarAngle()
{
return (float)Math.toDegrees( angle() );
}
/**
* Provides an approximate magnitude value for this sample.
*/
public float envelope()
{
return envelope( mLeft, mRight );
}
public static float envelope( float inphase, float quadrature )
{
float inphaseAbsolute = Math.abs( inphase );
float quadratureAbsolute = Math.abs( quadrature );
if( inphaseAbsolute > quadratureAbsolute )
{
return inphaseAbsolute + ( 0.4f * quadratureAbsolute );
}
else
{
return quadratureAbsolute + ( 0.4f * inphaseAbsolute );
}
}
public static void main( String[] args )
{
double angle = Math.PI; //180 degrees
Complex s1 = new Complex( (float)Math.sin( angle ), (float)Math.cos( angle ) );
Complex tap = new Complex( 1.0f, -0.1f );
Complex convolved = Complex.multiply( s1, tap );
mLog.debug( "s: " + s1.toString() +
" t: " + tap.toString() +
" convolved: " + convolved.toString() );
}
}

View File

@@ -0,0 +1,26 @@
package io.github.dsheirer.sample.complex;
import io.github.dsheirer.sample.Buffer;
import java.util.Arrays;
public class ComplexBuffer extends Buffer
{
/**
* Wrapper around float array containing interleaved I/Q samples
*/
public ComplexBuffer( float[] samples )
{
super( samples );
}
/**
* Creates a deep copy of the buffer
*/
public ComplexBuffer copyOf()
{
float[] copy = Arrays.copyOf( mSamples, mSamples.length );
return new ComplexBuffer( copy );
}
}

View File

@@ -0,0 +1,35 @@
package io.github.dsheirer.sample.complex;
import io.github.dsheirer.sample.Listener;
/**
* Real sample buffer to stream converter
*/
public class ComplexBufferToStreamConverter implements Listener<ComplexBuffer>
{
private ComplexSampleListener mListener;
public void dispose()
{
mListener = null;
}
@Override
public void receive( ComplexBuffer buffer )
{
if( mListener != null )
{
float[] samples = buffer.getSamples();
for( int x = 0; x < samples.length; x += 2 )
{
mListener.receive( samples[ x ], samples[ x + 1 ] );
}
}
}
public void setListener( ComplexSampleListener listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,72 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.Provider;
import java.util.ArrayList;
import java.util.List;
public class ComplexSampleAssembler implements Listener<Complex>,
Provider<List<Complex>>
{
private ArrayList<Complex> mBuffer;
private int mBufferSize;
private Listener<List<Complex>> mListener;
public ComplexSampleAssembler( int bufferSize )
{
mBufferSize = bufferSize;
mBuffer = new ArrayList<>();
}
public void dispose()
{
mBuffer.clear();
mListener = null;
}
@Override
public void receive( Complex sample )
{
mBuffer.add( sample );
if( mBuffer.size() >= mBufferSize )
{
if( mListener != null )
{
mListener.receive( mBuffer );
}
mBuffer = new ArrayList<>();
}
}
@Override
public void setListener( Listener<List<Complex>> listener )
{
mListener = listener;
}
@Override
public void removeListener( Listener<List<Complex>> listener )
{
mListener = null;
}
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Broadcasts received float samples to multiple listeners
*/
public class ComplexSampleBroadcaster implements ComplexSampleListener
{
private CopyOnWriteArrayList<ComplexSampleListener> mListeners =
new CopyOnWriteArrayList<ComplexSampleListener>();
@Override
public void receive( float i, float q )
{
broadcast( i, q );
}
/**
* Clear listeners to prepare for garbage collection
*/
public void dispose()
{
mListeners.clear();
}
public boolean hasListeners()
{
return !mListeners.isEmpty();
}
public int getListenerCount()
{
return mListeners.size();
}
public void addListener( ComplexSampleListener listener )
{
mListeners.add( listener );
}
public void removeListener( ComplexSampleListener listener )
{
mListeners.remove( listener );
}
public void clear()
{
mListeners.clear();
}
public void broadcast( float i, float q )
{
for( ComplexSampleListener listener: mListeners )
{
listener.receive( i, q );
}
}
}

View File

@@ -0,0 +1,25 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
import java.util.List;
public interface ComplexSampleListListener
{
public void receive( List<Complex> samples );
}

View File

@@ -0,0 +1,6 @@
package io.github.dsheirer.sample.complex;
public interface ComplexSampleListener
{
public void receive( float i, float q );
}

View File

@@ -0,0 +1,49 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
public class ComplexSampleUtils
{
public static Complex multiply( Complex a,
Complex b )
{
return new Complex(
( a.inphase() * b.inphase() ) - ( a.quadrature() * b.quadrature() ),
( ( a.quadrature() * b.inphase() ) + ( a.inphase() * b.quadrature() ) ) );
}
public static Complex minus( Complex a, Complex b )
{
return new Complex( a.inphase() - b.inphase(),
a.quadrature() - b.quadrature() );
}
public static double magnitude( Complex sample )
{
return Math.sqrt( magnitudeSquared( sample ) );
}
public static int magnitudeSquared( Complex sample )
{
return (int)( ( sample.inphase() * sample.inphase() ) +
( sample.quadrature() * sample.quadrature() ) );
}
}

View File

@@ -0,0 +1,81 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
import io.github.dsheirer.sample.Listener;
import org.apache.commons.lang3.Validate;
/**
* Assembles complex float samples into a ComplexBuffer containing an array of floats
*/
public class ComplexToComplexBufferAssembler implements ComplexSampleListener
{
private int mBufferSize;
private float[] mBuffer;
private int mBufferPointer;
private Listener<ComplexBuffer> mListener;
public ComplexToComplexBufferAssembler( int bufferSize )
{
Validate.isTrue(bufferSize % 2 == 0);
mBufferSize = bufferSize;
mBuffer = new float[ mBufferSize ];
}
public void dispose()
{
mListener = null;
mBuffer = null;
}
public void reset()
{
mBuffer = new float[ mBufferSize ];
mBufferPointer = 0;
}
@Override
public void receive( float i, float q )
{
if( mBufferPointer >= mBufferSize )
{
if( mListener != null )
{
mListener.receive( new ComplexBuffer( mBuffer ) );
}
mBuffer = new float[ mBufferSize ];
mBufferPointer = 0;
}
mBuffer[ mBufferPointer ] = i;
mBufferPointer++;
mBuffer[ mBufferPointer ] = q;
mBufferPointer++;
}
public void setListener( Listener<ComplexBuffer> listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,8 @@
package io.github.dsheirer.sample.complex;
import io.github.dsheirer.sample.Listener;
public interface IComplexBufferListener
{
public Listener<ComplexBuffer> getComplexBufferListener();
}

View File

@@ -0,0 +1,55 @@
package io.github.dsheirer.sample.complex;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RateCounter_CB implements Listener<ComplexBuffer>
{
private final static Logger mLog =
LoggerFactory.getLogger( RateCounter_CB.class );
private Listener<ComplexBuffer> mListener;
private long mCount;
private long mStartTime = -1;
private String mName;
public RateCounter_CB()
{
mName = "UNNAMED";
}
public RateCounter_CB( String name )
{
mName = name;
}
@Override
public void receive( ComplexBuffer buffer )
{
if( mStartTime == -1 )
{
mStartTime = System.currentTimeMillis();
}
mCount += ( buffer.getSamples().length / 2 );
long elapsed = System.currentTimeMillis() - mStartTime;
if( elapsed != 0 )
{
mLog.debug( "[" + mName + "] Sample Rate: " + ( mCount / elapsed ) + " kHz" );
}
if( mListener != null )
{
mListener.receive( buffer );
}
}
public void setListener( Listener<ComplexBuffer> listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.complex;
/**
* Poison Pill class to kill a processing thread. Where a thread accepts
* ComplexSample objects, send this class to the thread as a sentinal value
* to kill the processing thread.
*/
public class ThreadKiller extends Complex
{
private static final long serialVersionUID = 1L;
public ThreadKiller()
{
super( 0, 0 );
}
}

View File

@@ -0,0 +1,58 @@
package io.github.dsheirer.sample.decimator;
import io.github.dsheirer.sample.complex.ComplexSampleListener;
public class ComplexDecimator implements ComplexSampleListener
{
private ComplexSampleListener mListener;
private int mCounter = 0;
private int mDecimationRate;
/**
* Constructs a new Decimator object with the specified decimation rate.
*/
public ComplexDecimator( int rate )
{
mDecimationRate = rate;
}
public void dispose()
{
mListener = null;
}
/**
* Sets a new decimation rate. Rate can be changed after this object
* is constructed.
*/
public synchronized void setDecimationRate( int rate )
{
mDecimationRate = rate;
}
/**
* Receives samples allowing only 1 of every (rate) sample to go on
* to the registered listener
*/
@Override
public void receive( float i, float q )
{
mCounter++;
if( mCounter >= mDecimationRate )
{
mListener.receive( i, q );
mCounter = 0;
}
}
/**
* Sets the decimated output listener
*/
public void setListener( ComplexSampleListener listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,72 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.decimator;
import io.github.dsheirer.sample.Listener;
public class Decimator<T> implements Listener<T>
{
private int mDecimationFactor;
private int mDecimationPointer = 0;
private Listener<T> mListener;
/**
* Constructs the class to consume samples and decimate them by the
* DECIMATIONFACTOR.
*
* @param decimationFactor - number of samples to decimate. Provides one
* sample to registered listeners and discards the next decimationFactor - 1
* samples.
*/
public Decimator( int decimationFactor )
{
mDecimationFactor = decimationFactor;
}
/**
* Receives and broadcasts a sample and then discards the next
* decimationFactor -1 samples
*/
public void receive( T t )
{
if( mDecimationPointer == 0 )
{
if( mListener != null )
{
mListener.receive( t );
}
}
mDecimationPointer++;
//Reset the decimation pointer once it equals the decimation factor
if( mDecimationPointer == mDecimationFactor )
{
mDecimationPointer = 0;
}
}
/**
* Adds a sample listener to receive samples
*/
public void setListener( Listener<T> listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,58 @@
package io.github.dsheirer.sample.decimator;
import io.github.dsheirer.sample.real.RealSampleListener;
public class RealDecimator implements RealSampleListener
{
private RealSampleListener mListener;
private int mCounter = 0;
private int mDecimationRate;
/**
* Constructs a new Decimator object with the specified decimation rate.
*/
public RealDecimator( int rate )
{
mDecimationRate = rate;
}
public void dispose()
{
mListener = null;
}
/**
* Sets a new decimation rate. Rate can be changed after this object
* is constructed.
*/
public synchronized void setDecimationRate( int rate )
{
mDecimationRate = rate;
}
/**
* Receives samples allowing only 1 of every (rate) sample to go on
* to the registered listener
*/
@Override
public void receive( float sample )
{
mCounter++;
if( mCounter >= mDecimationRate )
{
mListener.receive( sample );
mCounter = 0;
}
}
/**
* Sets the decimated output listener
*/
public void setListener( RealSampleListener listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,8 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
public interface IFilteredRealBufferListener
{
public Listener<RealBuffer> getFilteredRealBufferListener();
}

View File

@@ -0,0 +1,9 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
public interface IFilteredRealBufferProvider
{
public void setFilteredRealBufferListener( Listener<RealBuffer> listener );
public void removeFilteredRealBufferListener();
}

View File

@@ -0,0 +1,28 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.sample.real;
public interface IOverflowListener
{
/**
* Indicates that the source is in overflow state (true) or out of overflow state (false)
* @param overflow true to indicate an overflow state
*/
void sourceOverflow(boolean overflow);
}

View File

@@ -0,0 +1,8 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
public interface IUnFilteredRealBufferListener
{
public Listener<RealBuffer> getUnFilteredRealBufferListener();
}

View File

@@ -0,0 +1,9 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
public interface IUnFilteredRealBufferProvider
{
public void setUnFilteredRealBufferListener( Listener<RealBuffer> listener );
public void removeUnFilteredRealBufferListener();
}

View File

@@ -0,0 +1,55 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RateCounter_RB implements Listener<RealBuffer>
{
private final static Logger mLog =
LoggerFactory.getLogger( RateCounter_RB.class );
private Listener<RealBuffer> mListener;
private long mCount;
private long mStartTime = -1;
private String mName;
public RateCounter_RB()
{
mName = "UNNAMED";
}
public RateCounter_RB( String name )
{
mName = name;
}
@Override
public void receive( RealBuffer buffer )
{
if( mStartTime == -1 )
{
mStartTime = System.currentTimeMillis();
}
mCount += buffer.getSamples().length;
long elapsed = System.currentTimeMillis() - mStartTime;
if( elapsed != 0 )
{
mLog.debug( "[" + mName + "] Sample Rate: " + ( mCount / elapsed ) + " kHz" );
}
if( mListener != null )
{
mListener.receive( buffer );
}
}
public void setListener( Listener<RealBuffer> listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,26 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Buffer;
import java.util.Arrays;
public class RealBuffer extends Buffer
{
/**
* Wrapper around float array containing real float samples
*/
public RealBuffer( float[] samples )
{
super( samples );
}
/**
* Creates a deep copy of the buffer
*/
public RealBuffer copyOf()
{
float[] copy = Arrays.copyOf( mSamples, mSamples.length );
return new RealBuffer( copy );
}
}

View File

@@ -0,0 +1,33 @@
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
/**
* Real sample buffer to stream converter
*/
public class RealBufferToStreamConverter implements Listener<RealBuffer>
{
private RealSampleListener mListener;
@Override
public void receive( RealBuffer buffer )
{
if( mListener != null )
{
for( float sample: buffer.getSamples() )
{
mListener.receive( sample );
}
}
}
public void dispose()
{
mListener = null;
}
public void setListener( RealSampleListener listener )
{
mListener = listener;
}
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.real;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Broadcasts a received float sample to multiple listeners
*/
public class RealSampleBroadcaster implements RealSampleListener
{
private CopyOnWriteArrayList<RealSampleListener> mListeners =
new CopyOnWriteArrayList<RealSampleListener>();
@Override
public void receive( float sample )
{
broadcast( sample );
}
/**
* Clear listeners to prepare for garbage collection
*/
public void dispose()
{
mListeners.clear();
}
public boolean hasListeners()
{
return !mListeners.isEmpty();
}
public int getListenerCount()
{
return mListeners.size();
}
public void addListener( RealSampleListener listener )
{
mListeners.add( listener );
}
public void removeListener( RealSampleListener listener )
{
mListeners.remove( listener );
}
public void clear()
{
mListeners.clear();
}
public void broadcast( float sample )
{
for( RealSampleListener listener: mListeners )
{
listener.receive( sample );
}
}
}

View File

@@ -0,0 +1,6 @@
package io.github.dsheirer.sample.real;
public interface RealSampleListener
{
public void receive( float sample );
}

View File

@@ -0,0 +1,8 @@
package io.github.dsheirer.sample.real;
public interface RealSampleProvider
{
public void setListener( RealSampleListener listener );
public void removeListener( RealSampleListener listener );
}

View File

@@ -0,0 +1,72 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package io.github.dsheirer.sample.real;
import io.github.dsheirer.sample.Listener;
/**
* Assembles single float samples into a RealBuffer containing an array of floats
*/
public class RealToRealBufferAssembler implements RealSampleListener
{
private int mBufferSize;
private float[] mBuffer;
private int mBufferPointer;
private Listener<RealBuffer> mListener;
public RealToRealBufferAssembler(int bufferSize)
{
mBufferSize = bufferSize;
mBuffer = new float[mBufferSize];
}
public void dispose()
{
mListener = null;
mBuffer = null;
}
public void reset()
{
mBuffer = new float[mBufferSize];
mBufferPointer = 0;
}
@Override
public void receive(float sample)
{
mBuffer[mBufferPointer++] = sample;
if (mBufferPointer >= mBufferSize)
{
if (mListener != null)
{
mListener.receive(new RealBuffer(mBuffer));
}
mBuffer = new float[mBufferSize];
mBufferPointer = 0;
}
}
public void setListener(Listener<RealBuffer> listener)
{
mListener = listener;
}
}