WSJT-X/Detector.hpp
Bill Somerville 3fbf5a5686 Fix defects in audio down-sampling on some platforms.
The filter used for 4 times down-sampling cannot handle sample streams
where the hardware or drivers deliver chunks of data that are not
multiples of 4 frames long. This seems to be prevalent on some Linux
platforms. Also de-interleaving of single channel audio from stereo
streams was no longer supported.

I have changed the input strategy to de-interleave the incoming
sample stream into an intermediate buffer large enough to hold all the
samples required for a single unit of processing (one basic waterfall
interval) and apply the down-sampling filter to the whole intermediate
buffer just prior dispatch to the FFT generator.

This now means that we are now using the ubiquitous 48kHz hardware
sample rate for both input and output of audio across all platforms
and decoding a single channel of a stereo stream is again
supported. The down-sampling to 12kHz is done with a high quality FIR
49-tap low pass filter specifically designed by Joe (K1JT) for
operation in a 4kHz bandwidth.



git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3585 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
2013-09-28 18:34:27 +00:00

67 lines
1.9 KiB
C++

#ifndef DETECTOR_HPP__
#define DETECTOR_HPP__
#include "AudioDevice.hpp"
#include <QScopedArrayPointer>
//
// output device that distributes data in predefined chunks via a signal
//
// the underlying device for this abstraction is just the buffer that
// stores samples throughout a receiving period
//
class Detector : public AudioDevice
{
Q_OBJECT;
Q_PROPERTY (bool monitoring READ isMonitoring WRITE setMonitoring);
public:
//
// if the data buffer were not global storage and fixed size then we
// might want maximum size passed as constructor arguments
//
// we down sample by a factor of 4
//
// the framesPerSignal argument is the number after down sampling
//
Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned framesPerSignal, QObject * parent = 0);
bool isMonitoring () const {return m_monitoring;}
protected:
qint64 readData (char * /* data */, qint64 /* maxSize */)
{
return -1; // we don't produce data
}
qint64 writeData (char const * data, qint64 maxSize);
private:
// these are private because we want thread safety, must be called via Qt queued connections
Q_SLOT void open (AudioDevice::Channel channel = Mono) {AudioDevice::open (QIODevice::WriteOnly, channel);}
Q_SLOT void setMonitoring (bool newState) {m_monitoring = newState; m_bufferPos = 0;}
Q_SLOT bool reset ();
Q_SLOT void close () {AudioDevice::close ();}
Q_SIGNAL void framesWritten (qint64);
void clear (); // discard buffer contents
unsigned secondInPeriod () const;
unsigned m_frameRate;
unsigned m_period;
qint32 m_framesPerSignal; // after down sampling
bool volatile m_monitoring;
bool m_starting;
QScopedArrayPointer<short> m_buffer; // de-interleaved sample buffer
// big enough for all the
// samples for one increment of
// data (a signals worth) at
// the input sample rate
unsigned m_bufferPos;
};
#endif