mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
[WIP] Updates the LTR-Standard and LTR-Net decoders to use a new LTR
decoder with a zero-crossing symbol timing error detector. The new decoder is optimized for 8 kHz FM demodulated audio produced by the AudioModule.
This commit is contained in:
@@ -2,10 +2,10 @@ package io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.sample.Provider;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||
|
||||
|
||||
public abstract class RealSource extends Source implements Provider<RealBuffer>
|
||||
public abstract class RealSource extends Source implements Provider<ReusableBuffer>
|
||||
{
|
||||
@Override
|
||||
public SampleType getSampleType()
|
||||
|
||||
@@ -19,6 +19,9 @@ package io.github.dsheirer.source.mixer;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.adapter.ISampleAdapter;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.source.RealSource;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
@@ -29,14 +32,14 @@ import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class RealMixerSource extends RealSource
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(RealMixerSource.class);
|
||||
|
||||
private ReusableBufferBroadcaster<ReusableBuffer> mBufferBroadcaster = new ReusableBufferBroadcaster<>();
|
||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("RealMixerSource");
|
||||
private long mFrequency = 0;
|
||||
private int mBufferSize = 16384;
|
||||
|
||||
@@ -103,9 +106,9 @@ public class RealMixerSource extends RealSource
|
||||
{
|
||||
}
|
||||
|
||||
public void setListener(Listener<RealBuffer> listener)
|
||||
public void setListener(Listener<ReusableBuffer> listener)
|
||||
{
|
||||
mSampleListeners.add(listener);
|
||||
mBufferBroadcaster.addListener(listener);
|
||||
|
||||
/* If this is the first listener, start the reader thread */
|
||||
if(!mBufferReader.isRunning())
|
||||
@@ -117,38 +120,17 @@ public class RealMixerSource extends RealSource
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(Listener<RealBuffer> listener)
|
||||
public void removeListener(Listener<ReusableBuffer> listener)
|
||||
{
|
||||
mSampleListeners.remove(listener);
|
||||
mBufferBroadcaster.removeListener(listener);
|
||||
|
||||
/* If this is the laster listener, stop the reader thread */
|
||||
/* If this is the last listener, stop the reader thread */
|
||||
if(mSampleListeners.isEmpty())
|
||||
{
|
||||
mBufferReader.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcast(RealBuffer samples)
|
||||
{
|
||||
Iterator<Listener<RealBuffer>> it = mSampleListeners.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
Listener<RealBuffer> next = it.next();
|
||||
|
||||
/* if this is the last (or only) listener, send him the original
|
||||
* buffer, otherwise send him a copy of the buffer */
|
||||
if(it.hasNext())
|
||||
{
|
||||
next.receive(samples.copyOf());
|
||||
}
|
||||
else
|
||||
{
|
||||
next.receive(samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double getSampleRate()
|
||||
{
|
||||
if(mTargetDataLine != null)
|
||||
@@ -240,11 +222,14 @@ public class RealMixerSource extends RealSource
|
||||
mTargetDataLine.read(buffer, 0, buffer.length);
|
||||
|
||||
/* Convert samples to float array */
|
||||
float[] samples =
|
||||
mSampleAdapter.convert(buffer);
|
||||
//TODO: change this sample adapter over to use reusable buffers and move the buffer queue into the adapter
|
||||
float[] samples = mSampleAdapter.convert(buffer);
|
||||
|
||||
/* Dispatch samples to registered listeners */
|
||||
broadcast(new RealBuffer(samples));
|
||||
ReusableBuffer reusableBuffer = mReusableBufferQueue.getBuffer(samples.length);
|
||||
reusableBuffer.reloadFrom(samples, System.currentTimeMillis());
|
||||
reusableBuffer.incrementUserCount();
|
||||
mBufferBroadcaster.broadcast(reusableBuffer);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
|
||||
import io.github.dsheirer.sample.buffer.IReusableComplexBufferProvider;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.ISourceEventListener;
|
||||
@@ -33,7 +33,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
|
||||
IReusableBufferProvider<ReusableComplexBuffer>, Listener<ReusableComplexBuffer>
|
||||
IReusableComplexBufferProvider, Listener<ReusableComplexBuffer>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
|
||||
protected ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster();
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ComplexWaveSource extends ComplexSource implements IControllableFileSource
|
||||
public class ComplexWaveSource extends ComplexSource implements IControllableFileSource, AutoCloseable
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexWaveSource.class);
|
||||
|
||||
@@ -275,4 +275,26 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
|
||||
{
|
||||
mFrameLocationListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the file is a supported audio file type
|
||||
*/
|
||||
public static boolean supports(File file)
|
||||
{
|
||||
try(AudioInputStream ais = AudioSystem.getAudioInputStream(file))
|
||||
{
|
||||
AudioFormat format = ais.getFormat();
|
||||
|
||||
if(format.getChannels() == 2 && format.getSampleSizeInBits() == 16)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Do nothing, we'll return a default of false
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ package io.github.dsheirer.source.wave;
|
||||
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
|
||||
import io.github.dsheirer.source.IControllableFileSource;
|
||||
import io.github.dsheirer.source.IFrameLocationListener;
|
||||
import io.github.dsheirer.source.RealSource;
|
||||
@@ -39,11 +40,12 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(RealWaveSource.class);
|
||||
|
||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("RealWaveSource");
|
||||
private IFrameLocationListener mFrameLocationListener;
|
||||
private int mBytesPerFrame;
|
||||
private int mFrameCounter = 0;
|
||||
private long mFrequency = 0;
|
||||
private Listener<RealBuffer> mListener;
|
||||
private Listener<ReusableBuffer> mListener;
|
||||
private AudioInputStream mInputStream;
|
||||
private File mFile;
|
||||
|
||||
@@ -52,7 +54,7 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
//Not implemented
|
||||
@@ -226,20 +228,22 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
buffer = Arrays.copyOf(buffer, samplesRead);
|
||||
}
|
||||
|
||||
float[] samples = ConversionUtils
|
||||
.convertFromSigned16BitSamples(buffer);
|
||||
float[] samples = ConversionUtils.convertFromSigned16BitSamples(buffer);
|
||||
|
||||
mListener.receive(new RealBuffer(samples));
|
||||
ReusableBuffer reusableBuffer = mReusableBufferQueue.getBuffer(samples.length);
|
||||
reusableBuffer.reloadFrom(samples, System.currentTimeMillis());
|
||||
reusableBuffer.incrementUserCount();
|
||||
|
||||
mListener.receive(reusableBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive sample buffers as they are read from
|
||||
* the wave file
|
||||
* Registers the listener to receive sample buffers as they are read from the wave file
|
||||
*/
|
||||
@Override
|
||||
public void setListener(Listener<RealBuffer> listener)
|
||||
public void setListener(Listener<ReusableBuffer> listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
@@ -247,7 +251,8 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
/**
|
||||
* Unregisters the listener from receiving sample buffers
|
||||
*/
|
||||
public void removeListener(Listener<RealBuffer> listener)
|
||||
@Override
|
||||
public void removeListener(Listener<ReusableBuffer> listener)
|
||||
{
|
||||
mListener = null;
|
||||
}
|
||||
@@ -285,4 +290,26 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
|
||||
{
|
||||
mFrameLocationListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the file is a supported audio file type
|
||||
*/
|
||||
public static boolean supports(File file)
|
||||
{
|
||||
try(AudioInputStream ais = AudioSystem.getAudioInputStream(file))
|
||||
{
|
||||
AudioFormat format = ais.getFormat();
|
||||
|
||||
if(format.getChannels() == 1 && format.getSampleSizeInBits() == 16)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Do nothing, we'll return a default of false
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user