[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:
Denny
2018-06-02 08:47:48 -04:00
parent c13315f731
commit a898be265f
64 changed files with 2660 additions and 1285 deletions

View File

@@ -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()

View File

@@ -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)
{

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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;
}
}