mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-09-09 06:46:39 -04:00
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
105 lines
2.0 KiB
C++
105 lines
2.0 KiB
C++
#ifndef AUDIODEVICE_HPP__
|
|
#define AUDIODEVICE_HPP__
|
|
|
|
#include <QIODevice>
|
|
|
|
class QDataStream;
|
|
|
|
//
|
|
// abstract base class for audio devices
|
|
//
|
|
class AudioDevice : public QIODevice
|
|
{
|
|
public:
|
|
enum Channel {Mono, Left, Right, Both}; // these are mapped to combobox index so don't change
|
|
|
|
static char const * toString (Channel c)
|
|
{
|
|
return Mono == c ? "Mono" : Left == c ? "Left" : Right == c ? "Right" : "Both";
|
|
}
|
|
|
|
static Channel fromString (QString const& str)
|
|
{
|
|
QString s (str.toCaseFolded ().trimmed ().toLatin1 ());
|
|
return "both" == s ? Both : "right" == s ? Right : "left" == s ? Left : Mono;
|
|
}
|
|
|
|
bool open (OpenMode mode, Channel channel)
|
|
{
|
|
m_channel = channel;
|
|
|
|
// ensure we are unbuffered
|
|
return QIODevice::open (mode | QIODevice::Unbuffered);
|
|
}
|
|
|
|
bool isSequential () const {return true;}
|
|
|
|
size_t bytesPerFrame () const {return sizeof (qint16) * (Mono == m_channel ? 1 : 2);}
|
|
|
|
Channel channel () const {return m_channel;}
|
|
|
|
protected:
|
|
AudioDevice (QObject * parent = 0)
|
|
: QIODevice (parent)
|
|
{
|
|
}
|
|
|
|
void store (char const * source, size_t numFrames, qint16 * dest)
|
|
{
|
|
qint16 const * begin (reinterpret_cast<qint16 const *> (source));
|
|
for ( qint16 const * i = begin; i != begin + numFrames * (bytesPerFrame () / sizeof (qint16)); i += bytesPerFrame () / sizeof (qint16))
|
|
{
|
|
switch (m_channel)
|
|
{
|
|
case Mono:
|
|
*dest++ = *i;
|
|
break;
|
|
|
|
case Right:
|
|
*dest++ = *(i + 1);
|
|
break;
|
|
|
|
case Both: // should be able to happen but if it
|
|
// does we'll take left
|
|
Q_ASSERT (Both == m_channel);
|
|
case Left:
|
|
*dest++ = *i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
qint16 * load (qint16 const sample, qint16 * dest)
|
|
{
|
|
switch (m_channel)
|
|
{
|
|
case Mono:
|
|
*dest++ = sample;
|
|
break;
|
|
|
|
case Left:
|
|
*dest++ = sample;
|
|
*dest++ = 0;
|
|
break;
|
|
|
|
case Right:
|
|
*dest++ = 0;
|
|
*dest++ = sample;
|
|
break;
|
|
|
|
case Both:
|
|
*dest++ = sample;
|
|
*dest++ = sample;
|
|
break;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
private:
|
|
Channel m_channel;
|
|
};
|
|
|
|
Q_DECLARE_METATYPE (AudioDevice::Channel);
|
|
|
|
#endif
|