From 688943e779435d24503b8c1ada7be274d6ba54a4 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 4 Oct 2013 19:00:29 +0000 Subject: [PATCH] Fix audio input rate issue on Windows Vista Windows Vista has a broken rate converter which gets invoked when an input audio stream at 48kHz sampel rate is requested. I've no idea why our application can't get exclusive access to the audio input device and have a unconverted stream direct at 48kHz. To get around this our down sampling filter for audio input from 48kHz to 12kHz is disaabled by default on Windows Vista, instead we request a 12kHz stream and process it directly. This default behviour can be overriden by specifying the following settings value: [Tune] Audio\DisableInputResampling=false This settings value defaults to true on Windows Vista and false everywhere else so normally needn't be present. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3588 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- Detector.cpp | 49 ++++++++++++++++++++++++++++++------------------- Detector.hpp | 5 +++-- main.cpp | 15 ++++++++++++++- mainwindow.cpp | 15 ++++++++------- mainwindow.h | 7 ++++--- soundin.cpp | 4 ++-- soundin.h | 2 +- 7 files changed, 62 insertions(+), 35 deletions(-) diff --git a/Detector.cpp b/Detector.cpp index 240d17571..045d6380c 100644 --- a/Detector.cpp +++ b/Detector.cpp @@ -10,19 +10,15 @@ extern "C" { void fil4_(qint16*, qint32*, qint16*, qint32*); } -namespace -{ - unsigned const downsampleFactor = 4; -} - -Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned framesPerSignal, QObject * parent) +Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned framesPerSignal, unsigned downSampleFactor, QObject * parent) : AudioDevice (parent) , m_frameRate (frameRate) , m_period (periodLengthInSeconds) + , m_downSampleFactor (downSampleFactor) , m_framesPerSignal (framesPerSignal) , m_monitoring (false) , m_starting (false) - , m_buffer (new short [framesPerSignal * downsampleFactor]) + , m_buffer ((downSampleFactor > 1) ? new short [framesPerSignal * downSampleFactor] : 0) , m_bufferPos (0) { clear (); @@ -53,7 +49,7 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) Q_ASSERT (!(maxSize % static_cast (bytesPerFrame ()))); // no torn frames // these are in terms of input frames (not down sampled) - size_t framesAcceptable ((sizeof (jt9com_.d2) / sizeof (jt9com_.d2[0]) - jt9com_.kin) * downsampleFactor); + size_t framesAcceptable ((sizeof (jt9com_.d2) / sizeof (jt9com_.d2[0]) - jt9com_.kin) * m_downSampleFactor); size_t framesAccepted (qMin (static_cast (maxSize / bytesPerFrame ()), framesAcceptable)); if (framesAccepted < static_cast (maxSize / bytesPerFrame ())) @@ -63,18 +59,33 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) for (unsigned remaining = framesAccepted; remaining; ) { - size_t numFramesProcessed (qMin (m_framesPerSignal * downsampleFactor - m_bufferPos, remaining)); - store (&data[(framesAccepted - remaining) * bytesPerFrame ()], numFramesProcessed, &m_buffer[m_bufferPos]); - m_bufferPos += numFramesProcessed; - if (m_bufferPos == m_framesPerSignal * downsampleFactor && m_monitoring) - { - qint32 framesToProcess (m_framesPerSignal * downsampleFactor); - qint32 framesAfterDownSample; - fil4_(&m_buffer[0], &framesToProcess, &jt9com_.d2[jt9com_.kin], &framesAfterDownSample); - m_bufferPos = 0; + size_t numFramesProcessed (qMin (m_framesPerSignal * m_downSampleFactor - m_bufferPos, remaining)); - jt9com_.kin += framesAfterDownSample; - Q_EMIT framesWritten (jt9com_.kin); + if (m_downSampleFactor > 1) + { + store (&data[(framesAccepted - remaining) * bytesPerFrame ()], numFramesProcessed, &m_buffer[m_bufferPos]); + m_bufferPos += numFramesProcessed; + if (m_bufferPos == m_framesPerSignal * m_downSampleFactor && m_monitoring) + { + qint32 framesToProcess (m_framesPerSignal * m_downSampleFactor); + qint32 framesAfterDownSample; + fil4_(&m_buffer[0], &framesToProcess, &jt9com_.d2[jt9com_.kin], &framesAfterDownSample); + jt9com_.kin += framesAfterDownSample; + Q_EMIT framesWritten (jt9com_.kin); + m_bufferPos = 0; + } + + } + else + { + store (&data[(framesAccepted - remaining) * bytesPerFrame ()], numFramesProcessed, &jt9com_.d2[jt9com_.kin]); + m_bufferPos += numFramesProcessed; + jt9com_.kin += numFramesProcessed; + if (m_bufferPos == static_cast (m_framesPerSignal) && m_monitoring) + { + Q_EMIT framesWritten (jt9com_.kin); + m_bufferPos = 0; + } } if (!secondInPeriod ()) diff --git a/Detector.hpp b/Detector.hpp index 46fb32f27..6003b7fd8 100644 --- a/Detector.hpp +++ b/Detector.hpp @@ -26,7 +26,7 @@ public: // // the framesPerSignal argument is the number after down sampling // - Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned framesPerSignal, QObject * parent = 0); + Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned framesPerSignal, unsigned downSampleFactor = 4u, QObject * parent = 0); bool isMonitoring () const {return m_monitoring;} @@ -52,7 +52,8 @@ private: unsigned m_frameRate; unsigned m_period; - qint32 m_framesPerSignal; // after down sampling + unsigned m_downSampleFactor; + qint32 m_framesPerSignal; // after any down sampling bool volatile m_monitoring; bool m_starting; QScopedArrayPointer m_buffer; // de-interleaved sample buffer diff --git a/main.cpp b/main.cpp index c52f259c7..ad348a014 100644 --- a/main.cpp +++ b/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "mainwindow.h" @@ -55,8 +56,20 @@ int main(int argc, char *argv[]) } memset(to,0,size); //Zero all decoding params in shared memory + settings.beginGroup ("Tune"); + + // deal with Windows Vista input audio rate converter problems + unsigned downSampleFactor = settings.value ("Audio/DisableInputResampling", +#if defined (Q_OS_WIN) + QSysInfo::WV_VISTA == QSysInfo::WindowsVersion ? true : false +#else + false +#endif + ).toBool () ? 1u : 4u; + settings.endGroup (); + // Multiple instances: Call MainWindow() with the UUID key - MainWindow w(&settings, &mem_jt9, &my_key, fontSize2, fontWeight2); + MainWindow w(&settings, &mem_jt9, &my_key, fontSize2, fontWeight2, downSampleFactor); w.show(); QObject::connect (&a, SIGNAL (lastWindowClosed()), &a, SLOT (quit())); diff --git a/mainwindow.cpp b/mainwindow.cpp index 3b9e9a361..10e784f7c 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -42,14 +42,14 @@ QString Program_Title_Version=" WSJT-X v1.2.1, r" + rev.mid(6,4) + //-------------------------------------------------- MainWindow constructor // Multiple instances: new arg *thekey MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *thekey, - qint32 fontSize2, qint32 fontWeight2, + qint32 fontSize2, qint32 fontWeight2, unsigned downSampleFactor, QWidget *parent) : QMainWindow(parent), m_settings (settings), ui(new Ui::MainWindow), m_wideGraph (new WideGraph (settings)), m_logDlg (new LogQSO (settings, this)), - m_detector (RX_SAMPLE_RATE, NTMAX / 2, 6912 / 2), + m_detector (RX_SAMPLE_RATE, NTMAX / 2, 6912 / 2, downSampleFactor), m_audioInputDevice (QAudioDeviceInfo::defaultInputDevice ()), // start with default m_modulator (TX_SAMPLE_RATE, NTMAX / 2), m_audioOutputDevice (QAudioDeviceInfo::defaultOutputDevice ()), // start with default @@ -57,6 +57,7 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the psk_Reporter (new PSK_Reporter (this)), m_msAudioOutputBuffered (0u), m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10), + m_downSampleFactor (downSampleFactor), m_audioThreadPriority (QThread::HighPriority) { ui->setupUi(this); @@ -91,8 +92,8 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the , &m_modulator, SLOT (open (unsigned, double, unsigned, AudioDevice::Channel, bool, double))); // hook up the audio input stream - connect (this, SIGNAL (startAudioInputStream (QAudioDeviceInfo const&, unsigned, int, QIODevice *)) - , &m_soundInput, SLOT (start (QAudioDeviceInfo const&, unsigned, int, QIODevice *))); + connect (this, SIGNAL (startAudioInputStream (QAudioDeviceInfo const&, unsigned, int, QIODevice *, unsigned)) + , &m_soundInput, SLOT (start (QAudioDeviceInfo const&, unsigned, int, QIODevice *, unsigned))); connect (this, SIGNAL (stopAudioInputStream ()), &m_soundInput, SLOT (stop ())); connect(&m_soundInput, SIGNAL (error (QString)), this, SLOT (showSoundInError (QString))); @@ -394,7 +395,7 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished())); Q_EMIT startDetector (m_audioInputChannel); - Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, m_framesAudioInputBuffered, &m_detector); + Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor); Q_EMIT transmitFrequency (m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0)); Q_EMIT muteAudioOutput (false); @@ -855,7 +856,7 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog Q_EMIT stopAudioInputStream (); Q_EMIT detectorClose (); Q_EMIT startDetector (m_audioInputChannel); - Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, m_framesAudioInputBuffered, &m_detector); + Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor); } if(dlg.m_restartSoundOut) { @@ -892,7 +893,7 @@ void MainWindow::on_monitorButton_clicked() //Monitor { m_monitoring=true; Q_EMIT detectorSetMonitoring (true); - // Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, m_framesAudioInputBuffered, &m_detector); + // Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor); m_diskData=false; } diff --git a/mainwindow.h b/mainwindow.h index 270ddacba..1bb456d91 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -48,8 +48,8 @@ class MainWindow : public QMainWindow // Multiple instances: call MainWindow() with *thekey public: - explicit MainWindow(QSettings *, QSharedMemory *shdmem, QString *thekey, \ - qint32 fontSize2, qint32 fontWeight2, \ + explicit MainWindow(QSettings *, QSharedMemory *shdmem, QString *thekey, + qint32 fontSize2, qint32 fontWeight2, unsigned downSampleFactor, QWidget *parent = 0); ~MainWindow(); @@ -184,7 +184,7 @@ private slots: Q_SIGNAL void startAudioOutputStream (QAudioDeviceInfo, unsigned channels, unsigned msBuffered); Q_SIGNAL void stopAudioOutputStream (); - Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink); + Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor); Q_SIGNAL void stopAudioInputStream (); Q_SIGNAL void startDetector (AudioDevice::Channel); @@ -391,6 +391,7 @@ private: DecodedText m_QSOText; unsigned m_msAudioOutputBuffered; unsigned m_framesAudioInputBuffered; + unsigned m_downSampleFactor; QThread::Priority m_audioThreadPriority; diff --git a/soundin.cpp b/soundin.cpp index 32f478586..caf61d376 100644 --- a/soundin.cpp +++ b/soundin.cpp @@ -38,7 +38,7 @@ bool SoundInput::audioError () const return result; } -void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int framesPerBuffer, QIODevice * sink) +void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor) { Q_ASSERT (0 < channels && channels < 3); Q_ASSERT (sink); @@ -48,7 +48,7 @@ void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int fr QAudioFormat format (device.preferredFormat()); format.setChannelCount (channels); format.setCodec ("audio/pcm"); - format.setSampleRate (48000); + format.setSampleRate (12000 * downSampleFactor); format.setSampleType (QAudioFormat::SignedInt); format.setSampleSize (16); diff --git a/soundin.h b/soundin.h index f153957e6..8f8c663d7 100644 --- a/soundin.h +++ b/soundin.h @@ -31,7 +31,7 @@ class SoundInput : public QObject Q_SIGNAL void status (QString message) const; // sink must exist from the start call to any following stop () call - Q_SLOT void start(QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink); + Q_SLOT void start(QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor); Q_SLOT void stop(); // used internally