From 0cd7046a2a9f349e2458fa42360cbc8635e162da Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sat, 17 Aug 2013 19:21:14 +0000 Subject: [PATCH] Moved audio input to the audio thread. Change source URLs in teh CMake scripts for the kvasd binaries. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3563 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- CMakeLists.txt | 12 ++++---- Detector.hpp | 17 +++++------ mainwindow.cpp | 78 ++++++++++++++++++++++++++++---------------------- mainwindow.h | 10 ++++++- soundin.cpp | 10 +++---- soundin.h | 18 ++++++------ 6 files changed, 79 insertions(+), 66 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f11bf101..11416a2e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,7 @@ elseif (CMAKE_HOST_WIN32) add_definitions (-DWIN32) endif () -add_definitions (-DWSJT_SOFT_KEYING) +# add_definitions (-DWSJT_SOFT_KEYING) set_property (DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) @@ -124,15 +124,13 @@ add_subdirectory (lib) # # fetch kvasd # -if (WIN32) - set (kvasd_NAME KVASD.EXE) -elseif (APPLE) - set (kvasd_NAME KVASD_gfortran_Mac${CMAKE_EXECUTABLE_SUFFIX}) +if (APPLE) + set (kvasd_NAME http://svn.berlios.de/wsvn/wsjt/trunk/KVASD_gfortran_Mac${CMAKE_EXECUTABLE_SUFFIX}) else () - set (kvasd_NAME KVASD_g95${CMAKE_EXECUTABLE_SUFFIX}) + set (kvasd_NAME http://www.physics.princeton.edu/pulsar/K1JT/kvasd${CMAKE_EXECUTABLE_SUFFIX}) endif () file ( - DOWNLOAD http://svn.berlios.de/wsvn/wsjt/trunk/${kvasd_NAME} contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX} + DOWNLOAD ${kvasd_NAME} contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX} STATUS kvasd_STATUS LOG kvasd_LOG SHOW_PROGRESS diff --git a/Detector.hpp b/Detector.hpp index 8282d7262..65aef4d8d 100644 --- a/Detector.hpp +++ b/Detector.hpp @@ -22,14 +22,7 @@ public: // Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned framesPerSignal, QObject * parent = 0); - bool open (Channel channel = Mono) {return AudioDevice::open (QIODevice::WriteOnly, channel);} - bool isMonitoring () const {return m_monitoring;} - void setMonitoring (bool newState) {m_monitoring = newState;} - - bool reset (); - - Q_SIGNAL void framesWritten (qint64); protected: qint64 readData (char * /* data */, qint64 /* maxSize */) @@ -40,13 +33,21 @@ protected: 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;} + 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; unsigned m_framesPerSignal; - bool m_monitoring; + bool volatile m_monitoring; bool m_starting; }; diff --git a/mainwindow.cpp b/mainwindow.cpp index aa7d6046a..29ac44cec 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -47,7 +47,7 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the ui(new Ui::MainWindow), m_wideGraph (new WideGraph (settings)), m_logDlg (new LogQSO (settings, this)), - m_detector (RX_SAMPLE_RATE, NTMAX / 2, 6912 / 2, this), + m_detector (RX_SAMPLE_RATE, NTMAX / 2, 6912 / 2), m_audioInputDevice (QAudioDeviceInfo::defaultInputDevice ()), // start with default m_modulator (TX_SAMPLE_RATE, NTMAX / 2), m_audioOutputDevice (QAudioDeviceInfo::defaultOutputDevice ()), // start with default @@ -58,15 +58,17 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the connect (this, &MainWindow::finished, this, &MainWindow::close); - // start sound out thread and hook up slots & signals for shutdown management + // start audio thread and hook up slots & signals for shutdown management - // these two objects need to be in the other thread so that invoking + // these objects need to be in the audio thread so that invoking // their slots is done in a thread safe way - m_soundOutput.moveToThread (&m_soundOutputThread); - m_modulator.moveToThread (&m_soundOutputThread); + m_soundOutput.moveToThread (&m_audioThread); + m_modulator.moveToThread (&m_audioThread); + m_soundInput.moveToThread (&m_audioThread); + m_detector.moveToThread (&m_audioThread); - connect (this, &MainWindow::finished, &m_soundOutputThread, &QThread::quit); // quit thread event loop - connect (&m_soundOutputThread, &QThread::finished, &m_soundOutputThread, &QThread::deleteLater); // disposal + connect (this, &MainWindow::finished, &m_audioThread, &QThread::quit); // quit thread event loop + connect (&m_audioThread, &QThread::finished, &m_audioThread, &QThread::deleteLater); // disposal // hook up sound output stream slots & signals connect (this, SIGNAL (startAudioOutputStream (QAudioDeviceInfo const&, unsigned)), &m_soundOutput, SLOT (startStream (QAudioDeviceInfo const&, unsigned))); @@ -80,15 +82,26 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the connect (this, SIGNAL(transmitFrequency (unsigned)), &m_modulator, SLOT (setFrequency (unsigned))); connect (this, SIGNAL (endTransmitMessage ()), &m_modulator, SLOT (close ())); connect (this, SIGNAL (tune (bool)), &m_modulator, SLOT (tune (bool))); - connect ( - this - , SIGNAL (sendMessage (unsigned, double, unsigned, AudioDevice::Channel, bool, double)) - , &m_modulator - , SLOT (open (unsigned, double, unsigned, AudioDevice::Channel, bool, double)) - ); + connect (this, SIGNAL (sendMessage (unsigned, double, unsigned, AudioDevice::Channel, bool, double)) + , &m_modulator, SLOT (open (unsigned, double, unsigned, AudioDevice::Channel, bool, double))); - // start the sound output thread - m_soundOutputThread.start (QThread::HighPriority); + // 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 (stopAudioInputStream ()), &m_soundInput, SLOT (stop ())); + + connect(&m_soundInput, SIGNAL (error (QString)), this, SLOT (showSoundInError (QString))); + // connect(&m_soundInput, SIGNAL(status(QString)), this, SLOT(showStatusMessage(QString))); + + // hook up the detector + connect (this, SIGNAL (startDetector (AudioDevice::Channel)), &m_detector, SLOT (open (AudioDevice::Channel))); + connect (this, SIGNAL (detectorSetMonitoring (bool)), &m_detector, SLOT (setMonitoring (bool))); + connect (this, SIGNAL (detectorClose ()), &m_detector, SLOT (close ())); + + connect(&m_detector, SIGNAL (framesWritten (qint64)), this, SLOT (dataSink (qint64))); + + // start the audio thread + m_audioThread.start (QThread::HighPriority); // setup the waterfall @@ -140,11 +153,6 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the setWindowTitle(Program_Title_Version); - connect(&m_detector, &Detector::framesWritten, this, &MainWindow::dataSink); - connect(&m_soundInput, SIGNAL(error(QString)), this, - SLOT(showSoundInError(QString))); - // connect(&m_soundInput, SIGNAL(status(QString)), this, - // SLOT(showStatusMessage(QString))); createStatusBar(); connect(&proc_jt9, SIGNAL(readyReadStandardOutput()), @@ -369,13 +377,13 @@ MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *the watcher2 = new QFutureWatcher; connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished())); - m_detector.open (m_audioInputChannel); - m_soundInput.start(m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector); + Q_EMIT startDetector (m_audioInputChannel); + Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector); Q_EMIT transmitFrequency (m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0)); Q_EMIT muteAudioOutput (false); m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF - m_detector.setMonitoring(m_monitoring); + Q_EMIT detectorSetMonitoring (m_monitoring); m_diskData=false; // Create "m_worked", a dictionary of all calls in wsjtx.log @@ -820,10 +828,10 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog m_After73=dlg.m_After73; if(dlg.m_restartSoundIn) { - m_soundInput.stop (); - m_detector.close (); - m_detector.open (m_audioInputChannel); - m_soundInput.start(m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector); + Q_EMIT stopAudioInputStream (); + Q_EMIT detectorClose (); + Q_EMIT startDetector (m_audioInputChannel); + Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector); } if(dlg.m_restartSoundOut) { @@ -859,8 +867,8 @@ void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog void MainWindow::on_monitorButton_clicked() //Monitor { m_monitoring=true; - m_detector.setMonitoring(true); - // m_soundInput.start(m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector); + Q_EMIT detectorSetMonitoring (true); + // Q_EMIT startAudioInputStream (m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector); m_diskData=false; } @@ -1097,13 +1105,13 @@ void MainWindow::OnExit() quitFile.remove(); Q_EMIT finished (); - m_soundOutputThread.wait (); + m_audioThread.wait (); } void MainWindow::on_stopButton_clicked() //stopButton { m_monitoring=false; - m_detector.setMonitoring(m_monitoring); + Q_EMIT detectorSetMonitoring (m_monitoring); m_loopall=false; } @@ -1128,7 +1136,7 @@ void MainWindow::on_actionWide_Waterfall_triggered() //Display Waterfalls void MainWindow::on_actionOpen_triggered() //Open File { m_monitoring=false; - m_detector.setMonitoring(m_monitoring); + Q_EMIT detectorSetMonitoring (m_monitoring); QString fname; fname=QFileDialog::getOpenFileName(this, "Open File", m_path, "WSJT Files (*.wav)"); @@ -1695,7 +1703,7 @@ void MainWindow::guiUpdate() signalMeter->setValue(0); m_monitoring=false; - m_detector.setMonitoring(false); + Q_EMIT detectorSetMonitoring (false); m_btxok=true; Q_EMIT muteAudioOutput (false); m_transmitting=true; @@ -1823,7 +1831,7 @@ void MainWindow::startTx2() transmit (snr); signalMeter->setValue(0); m_monitoring=false; - m_detector.setMonitoring(false); + Q_EMIT detectorSetMonitoring (false); m_btxok=true; Q_EMIT muteAudioOutput (false); m_transmitting=true; @@ -1842,7 +1850,7 @@ void MainWindow::stopTx() lab1->setText(""); ptt0Timer->start(200); //Sequencer delay m_monitoring=true; - m_detector.setMonitoring(true); + Q_EMIT detectorSetMonitoring (true); } void MainWindow::stopTx2() diff --git a/mainwindow.h b/mainwindow.h index 9d60532e2..54315b9c5 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -181,6 +181,14 @@ private slots: private: Q_SIGNAL void startAudioOutputStream (QAudioDeviceInfo, unsigned channels); Q_SIGNAL void stopAudioOutputStream (); + + Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink); + Q_SIGNAL void stopAudioInputStream (); + + Q_SIGNAL void startDetector (AudioDevice::Channel); + Q_SIGNAL void detectorSetMonitoring (bool); + Q_SIGNAL void detectorClose (); + Q_SIGNAL void finished (); Q_SIGNAL void muteAudioOutput (bool = true); Q_SIGNAL void transmitFrequency (unsigned); @@ -228,7 +236,7 @@ private: QAudioDeviceInfo m_audioOutputDevice; AudioDevice::Channel m_audioOutputChannel; SoundOutput m_soundOutput; - QThread m_soundOutputThread; + QThread m_audioThread; qint32 m_TRperiod; qint32 m_nsps; diff --git a/soundin.cpp b/soundin.cpp index b2c2714e7..5dacd7aef 100644 --- a/soundin.cpp +++ b/soundin.cpp @@ -38,7 +38,7 @@ bool SoundInput::audioError () const return result; } -bool SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int framesPerBuffer, QIODevice * sink) +void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int framesPerBuffer, QIODevice * sink) { Q_ASSERT (0 < channels && channels < 3); Q_ASSERT (sink); @@ -55,26 +55,26 @@ bool SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int fr if (!format.isValid ()) { Q_EMIT error (tr ("Requested input audio format is not valid.")); - return false; + return; } // this function lies! // if (!device.isFormatSupported (format)) // { // Q_EMIT error (tr ("Requested input audio format is not supported on device.")); - // return false; + // return; // } m_stream.reset (new QAudioInput (device, format, this)); if (audioError ()) { - return false; + return; } connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged); m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer)); m_stream->start (sink); - return audioError () ? false : true; + audioError (); } void SoundInput::handleStateChanged (QAudio::State newState) const diff --git a/soundin.h b/soundin.h index 660978882..f153957e6 100644 --- a/soundin.h +++ b/soundin.h @@ -26,22 +26,20 @@ class SoundInput : public QObject ~SoundInput (); -Q_SIGNALS: - void error (QString message) const; - void status (QString message) const; + private: + Q_SIGNAL void error (QString message) const; + Q_SIGNAL void status (QString message) const; -public Q_SLOTS: // sink must exist from the start call to any following stop () call - bool start(QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink); - void stop(); + Q_SLOT void start(QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink); + Q_SLOT void stop(); + + // used internally + Q_SLOT void handleStateChanged (QAudio::State) const; -private: bool audioError () const; QScopedPointer m_stream; - -private Q_SLOTS: - void handleStateChanged (QAudio::State) const; }; #endif