From 581691befba6d92ba6da321cf6fa6845237a2299 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Thu, 3 Apr 2014 19:29:13 +0000 Subject: [PATCH] Rearranged sequencing of audio streams and devices. The code was starting streams linked to closed devices which may be causing issues on the Mac version. I have refactored to ensure that devices are always opened before related audio streams are started. Made .h C++ headers emacs friendly. Removed some code in the MainWindow contructor that read the log file but failed to check if the file exists and didn't do anything with the data anyway. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3977 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- AudioDevice.cpp | 4 +- AudioDevice.hpp | 2 +- Detector.cpp | 124 ++++++++--------- Detector.hpp | 21 ++- Modulator.cpp | 275 ++++++++++++++++++++---------------- Modulator.hpp | 45 +++--- about.h | 1 + decodedtext.h | 1 + displaytext.h | 1 + getfile.h | 1 + logqso.h | 1 + mainwindow.cpp | 83 ++++------- mainwindow.h | 362 ++++++++++++++++++++++++------------------------ meterwidget.h | 1 + plotter.h | 1 + psk_reporter.h | 1 + signalmeter.h | 1 + sleep.h | 1 + soundin.cpp | 73 ++++++---- soundin.h | 21 +-- soundout.cpp | 85 +++++------- soundout.h | 26 ++-- widegraph.h | 1 + 23 files changed, 566 insertions(+), 566 deletions(-) diff --git a/AudioDevice.cpp b/AudioDevice.cpp index 871273d19..a557aa66e 100644 --- a/AudioDevice.cpp +++ b/AudioDevice.cpp @@ -13,11 +13,11 @@ namespace } static_initializer; } -bool AudioDevice::open (OpenMode mode, Channel channel) +bool AudioDevice::initialize (OpenMode mode, Channel channel) { m_channel = channel; - // ensure we are unbuffered + // open and ensure we are unbuffered if possible return QIODevice::open (mode | QIODevice::Unbuffered); } diff --git a/AudioDevice.hpp b/AudioDevice.hpp index 63f8b5999..0f78b2ba8 100644 --- a/AudioDevice.hpp +++ b/AudioDevice.hpp @@ -24,7 +24,7 @@ public: return "both" == s ? Both : "right" == s ? Right : "left" == s ? Left : Mono; } - bool open (OpenMode mode, Channel channel); + bool initialize (OpenMode mode, Channel channel); bool isSequential () const {return true;} diff --git a/Detector.cpp b/Detector.cpp index 48a251b49..5125775db 100644 --- a/Detector.cpp +++ b/Detector.cpp @@ -7,7 +7,7 @@ #include "moc_Detector.cpp" extern "C" { -void fil4_(qint16*, qint32*, qint16*, qint32*); + void fil4_(qint16*, qint32*, qint16*, qint32*); } Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, @@ -21,7 +21,7 @@ Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, , m_monitoring (false) , m_starting (false) , m_buffer ((downSampleFactor > 1) ? - new short [framesPerSignal * downSampleFactor] : 0) + new short [framesPerSignal * downSampleFactor] : 0) , m_bufferPos (0) { clear (); @@ -50,76 +50,76 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) if (m_monitoring) { // no torn frames Q_ASSERT (!(maxSize % static_cast (bytesPerFrame ()))); - // these are in terms of input frames (not down sampled) - size_t framesAcceptable ((sizeof (jt9com_.d2) / - sizeof (jt9com_.d2[0]) - jt9com_.kin) * m_downSampleFactor); - size_t framesAccepted (qMin (static_cast (maxSize / - bytesPerFrame ()), framesAcceptable)); + // these are in terms of input frames (not down sampled) + 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 ())) { - qDebug () << "dropped " << maxSize / bytesPerFrame () - framesAccepted - << " frames of data on the floor!"; - } + if (framesAccepted < static_cast (maxSize / bytesPerFrame ())) { + qDebug () << "dropped " << maxSize / bytesPerFrame () - framesAccepted + << " frames of data on the floor!"; + } - for (unsigned remaining = framesAccepted; remaining; ) { - size_t numFramesProcessed (qMin (m_framesPerSignal * - m_downSampleFactor - m_bufferPos, remaining)); + for (unsigned remaining = framesAccepted; remaining; ) { + size_t numFramesProcessed (qMin (m_framesPerSignal * + m_downSampleFactor - m_bufferPos, remaining)); - 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; - if(framesToProcess==13824 and jt9com_.kin>=0 and jt9com_.kin<1440000) { - fil4_(&m_buffer[0], &framesToProcess, &jt9com_.d2[jt9com_.kin], - &framesAfterDownSample); - jt9com_.kin += framesAfterDownSample; - } else { - qDebug() << "framesToProcess = " << framesToProcess; - qDebug() << "jt9com_.kin = " << jt9com_.kin; - qDebug() << "secondInPeriod = " << secondInPeriod(); + 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; + if(framesToProcess==13824 and jt9com_.kin>=0 and jt9com_.kin<1440000) { + fil4_(&m_buffer[0], &framesToProcess, &jt9com_.d2[jt9com_.kin], + &framesAfterDownSample); + jt9com_.kin += framesAfterDownSample; + } else { + qDebug() << "framesToProcess = " << framesToProcess; + qDebug() << "jt9com_.kin = " << jt9com_.kin; + qDebug() << "secondInPeriod = " << secondInPeriod(); + } + 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; } - 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 ()) { + if (!m_starting) { + // next samples will be in new period so wrap around to + // start of buffer + // + // we don't bother calling reset () since we expect to fill + // the whole buffer and don't need to waste cycles zeroing + jt9com_.kin = 0; + m_bufferPos = 0; + m_starting = true; + } + } else if(m_starting) { + m_starting = false; } + remaining -= numFramesProcessed; } - - if (!secondInPeriod ()) { - if (!m_starting) { - // next samples will be in new period so wrap around to - // start of buffer - // - // we don't bother calling reset () since we expect to fill - // the whole buffer and don't need to waste cycles zeroing - jt9com_.kin = 0; - m_bufferPos = 0; - m_starting = true; - } - } else if(m_starting) { - m_starting = false; - } - remaining -= numFramesProcessed; + } else { + jt9com_.kin = 0; + m_bufferPos = 0; } -} else { -jt9com_.kin = 0; -m_bufferPos = 0; -} -return maxSize; // we drop any data past the end of the buffer on - // the floor until the next period starts + return maxSize; // we drop any data past the end of the buffer on + // the floor until the next period starts } unsigned Detector::secondInPeriod () const diff --git a/Detector.hpp b/Detector.hpp index 3004408be..cb14702d1 100644 --- a/Detector.hpp +++ b/Detector.hpp @@ -30,6 +30,11 @@ public: bool isMonitoring () const {return m_monitoring;} + Q_SLOT void setMonitoring (bool newState) {m_monitoring = newState; m_bufferPos = 0;} + Q_SLOT bool reset (); + + Q_SIGNAL void framesWritten (qint64) const; + protected: qint64 readData (char * /* data */, qint64 /* maxSize */) { @@ -39,14 +44,6 @@ 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; m_bufferPos = 0;} - Q_SLOT bool reset (); - Q_SLOT void close () {AudioDevice::close ();} - - Q_SIGNAL void framesWritten (qint64) const; - void clear (); // discard buffer contents unsigned secondInPeriod () const; @@ -57,10 +54,10 @@ private: bool volatile m_monitoring; bool m_starting; QScopedArrayPointer 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 + // big enough for all the + // samples for one increment of + // data (a signals worth) at + // the input sample rate unsigned m_bufferPos; }; diff --git a/Modulator.cpp b/Modulator.cpp index 927882023..2153a65e2 100644 --- a/Modulator.cpp +++ b/Modulator.cpp @@ -24,27 +24,31 @@ double const Modulator::m_twoPi = 2.0 * 3.141592653589793238462; // m_nspd=3072; //18.75 WPM unsigned const Modulator::m_nspd = 2048 + 512; // 22.5 WPM -Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, \ - QObject * parent) - : AudioDevice (parent) - , m_phi (0.0) - , m_framesSent (0) - , m_frameRate (frameRate) - , m_period (periodLengthInSeconds) - , m_state (Idle) - , m_tuning (false) - , m_muted (false) +Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent) + : AudioDevice {parent} + , m_stream {nullptr} + , m_phi {0.0} + , m_framesSent {0} + , m_frameRate {frameRate} + , m_period {periodLengthInSeconds} + , m_state {Idle} + , m_tuning {false} + , m_muted {false} { qsrand (QDateTime::currentMSecsSinceEpoch()); // Initialize random seed } -void Modulator::open (unsigned symbolsLength, double framesPerSymbol, \ - unsigned frequency, Channel channel, bool synchronize, double dBSNR) +void Modulator::start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput * stream, Channel channel, bool synchronize, double dBSNR) { // Time according to this computer which becomes our base time qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; -// qDebug () << "Modulator: Using soft keying for CW is " << SOFT_KEYING;; + if (m_state != Idle) + { + stop (); + } + + // qDebug () << "Modulator: Using soft keying for CW is " << SOFT_KEYING;; m_symbolsLength = symbolsLength; m_framesSent = 0; @@ -63,7 +67,7 @@ void Modulator::open (unsigned symbolsLength, double framesPerSymbol, \ unsigned mstr = ms0 % (1000 * m_period); // ms in period m_ic = (mstr / 1000) * m_frameRate; // we start exactly N seconds - // into period where N is the next whole second + // into period where N is the next whole second m_silentFrames = 0; // calculate number of silent frames to send @@ -71,11 +75,38 @@ void Modulator::open (unsigned symbolsLength, double framesPerSymbol, \ m_silentFrames = m_ic + m_frameRate - (mstr * m_frameRate / 1000); } -// qDebug () << "Modulator: starting at " << m_ic / m_frameRate << " sec, sending " << m_silentFrames << " silent frames"; + // qDebug () << "Modulator: starting at " << m_ic / m_frameRate << " sec, sending " << m_silentFrames << " silent frames"; - AudioDevice::open (QIODevice::ReadOnly, channel); + initialize (QIODevice::ReadOnly, channel); Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ? - Synchronizing : Active)); + Synchronizing : Active)); + m_stream = stream; + if (m_stream) + { + m_stream->start (this); + } +} + +void Modulator::stop () +{ + if (m_stream) + { + m_stream->reset (); + } + close (); +} + +void Modulator::close () +{ + if (m_stream) + { + m_stream->stop (); + } + if (m_state != Idle) + { + Q_EMIT stateChanged ((m_state = Idle)); + } + AudioDevice::close (); } qint64 Modulator::readData (char * data, qint64 maxSize) @@ -92,141 +123,143 @@ qint64 Modulator::readData (char * data, qint64 maxSize) qint16 * samples (reinterpret_cast (data)); qint16 * end (samples + numFrames * (bytesPerFrame () / sizeof (qint16))); -// qDebug () << "Modulator: " << numFrames << " requested, m_ic = " << m_ic << ", tune mode is " << m_tuning; -// qDebug() << "C" << maxSize << numFrames << bytesPerFrame(); + // qDebug () << "Modulator: " << numFrames << " requested, m_ic = " << m_ic << ", tune mode is " << m_tuning; + // qDebug() << "C" << maxSize << numFrames << bytesPerFrame(); switch (m_state) - { - case Synchronizing: - { - if (m_silentFrames) { // send silence up to first second - numFrames = qMin (m_silentFrames, numFrames); - for ( ; samples != end; samples = load (0, samples)) { // silence - } - m_silentFrames -= numFrames; - return numFrames * bytesPerFrame (); - } + { + case Synchronizing: + { + if (m_silentFrames) { // send silence up to first second + numFrames = qMin (m_silentFrames, numFrames); + for ( ; samples != end; samples = load (0, samples)) { // silence + } + m_silentFrames -= numFrames; + return numFrames * bytesPerFrame (); + } - Q_EMIT stateChanged ((m_state = Active)); - m_ramp = 0; // prepare for CW wave shaping - } + Q_EMIT stateChanged ((m_state = Active)); + m_ramp = 0; // prepare for CW wave shaping + } // fall through - case Active: - { - unsigned isym (m_tuning ? 0 : m_ic / (4.0 * m_nsps)); // Actual fsample=48000 - if (isym >= m_symbolsLength && icw[0] > 0) { // start CW condition - // Output the CW ID - m_dphi = m_twoPi * m_frequency / m_frameRate; - unsigned const ic0 = m_symbolsLength * 4 * m_nsps; - unsigned j (0); - qint64 framesGenerated (0); + case Active: + { + unsigned isym (m_tuning ? 0 : m_ic / (4.0 * m_nsps)); // Actual fsample=48000 + if (isym >= m_symbolsLength && icw[0] > 0) { // start CW condition + // Output the CW ID + m_dphi = m_twoPi * m_frequency / m_frameRate; + unsigned const ic0 = m_symbolsLength * 4 * m_nsps; + unsigned j (0); + qint64 framesGenerated (0); - while (samples != end) { - m_phi += m_dphi; - if (m_phi > m_twoPi) m_phi -= m_twoPi; + while (samples != end) { + m_phi += m_dphi; + if (m_phi > m_twoPi) m_phi -= m_twoPi; - qint16 sample ((SOFT_KEYING ? qAbs (m_ramp - 1) : - (m_ramp ? 32767 : 0)) * qSin (m_phi)); + qint16 sample ((SOFT_KEYING ? qAbs (m_ramp - 1) : + (m_ramp ? 32767 : 0)) * qSin (m_phi)); - j = (m_ic - ic0 - 1) / m_nspd + 1; - bool l0 (icw[j] && icw[j] <= 1); // first element treated specially as it's a count - j = (m_ic - ic0) / m_nspd + 1; + j = (m_ic - ic0 - 1) / m_nspd + 1; + bool l0 (icw[j] && icw[j] <= 1); // first element treated specially as it's a count + j = (m_ic - ic0) / m_nspd + 1; - if ((m_ramp != 0 && m_ramp != std::numeric_limits::min ()) || - !!icw[j] != l0) { - if (!!icw[j] != l0) { - Q_ASSERT (m_ramp == 0 || m_ramp == std::numeric_limits::min ()); + if ((m_ramp != 0 && m_ramp != std::numeric_limits::min ()) || + !!icw[j] != l0) { + if (!!icw[j] != l0) { + Q_ASSERT (m_ramp == 0 || m_ramp == std::numeric_limits::min ()); + } + m_ramp += RAMP_INCREMENT; // ramp + } + + if (j < NUM_CW_SYMBOLS) { // stop condition + // if (!m_ramp && !icw[j]) + // { + // sample = 0; + // } + + samples = load (postProcessSample (sample), samples); + ++framesGenerated; + ++m_ic; + } } - m_ramp += RAMP_INCREMENT; // ramp + + if (j > static_cast (icw[0])) + { + close (); + } + + m_framesSent += framesGenerated; + return framesGenerated * bytesPerFrame (); } - if (j < NUM_CW_SYMBOLS) { // stop condition - // if (!m_ramp && !icw[j]) - // { - // sample = 0; - // } + double const baud (12000.0 / m_nsps); + // fade out parameters (no fade out for tuning) + unsigned const i0 = m_tuning ? 999 * m_nsps : + (m_symbolsLength - 0.017) * 4.0 * m_nsps; + unsigned const i1 = m_tuning ? 999 * m_nsps : + m_symbolsLength * 4.0 * m_nsps; - samples = load (postProcessSample (sample), samples); - ++framesGenerated; + for (unsigned i = 0; i < numFrames; ++i) { + isym = m_tuning ? 0 : m_ic / (4.0 * m_nsps); //Actual fsample=48000 + if (isym != m_isym0) { + if(m_toneSpacing==0.0) { + toneFrequency0=m_frequency + itone[isym]*baud; + } else { + toneFrequency0=m_frequency + itone[isym]*m_toneSpacing; + } + m_dphi = m_twoPi * toneFrequency0 / m_frameRate; + m_isym0 = isym; + } + + int j=m_ic/480; + if(m_fSpread>0.0 and j!=j0) { + float x1=(float)rand()/RAND_MAX; + float x2=(float)rand()/RAND_MAX; + toneFrequency = toneFrequency0 + 0.5*m_fSpread*(x1+x2-1.0); + m_dphi = m_twoPi * toneFrequency / m_frameRate; + j0=j; + } + + m_phi += m_dphi; + if (m_phi > m_twoPi) m_phi -= m_twoPi; + if (m_ic > i0) m_amp = 0.98 * m_amp; + if (m_ic > i1) m_amp = 0.0; + + samples = load (postProcessSample (m_amp * qSin (m_phi)), samples); ++m_ic; } - } - if (j > static_cast (icw[0])) { - Q_EMIT stateChanged ((m_state = Idle)); - } + if (m_amp == 0.0) { // TODO G4WJS: compare double with zero might not be wise + if (icw[0] == 0) { + // no CW ID to send + Q_EMIT stateChanged ((m_state = Idle)); + m_framesSent += numFrames; + return numFrames * bytesPerFrame (); + } - m_framesSent += framesGenerated; - return framesGenerated * bytesPerFrame (); - } - - double const baud (12000.0 / m_nsps); - // fade out parameters (no fade out for tuning) - unsigned const i0 = m_tuning ? 999 * m_nsps : - (m_symbolsLength - 0.017) * 4.0 * m_nsps; - unsigned const i1 = m_tuning ? 999 * m_nsps : - m_symbolsLength * 4.0 * m_nsps; - - for (unsigned i = 0; i < numFrames; ++i) { - isym = m_tuning ? 0 : m_ic / (4.0 * m_nsps); //Actual fsample=48000 - if (isym != m_isym0) { - if(m_toneSpacing==0.0) { - toneFrequency0=m_frequency + itone[isym]*baud; - } else { - toneFrequency0=m_frequency + itone[isym]*m_toneSpacing; + m_phi = 0.0; } - m_dphi = m_twoPi * toneFrequency0 / m_frameRate; - m_isym0 = isym; - } - int j=m_ic/480; - if(m_fSpread>0.0 and j!=j0) { - float x1=(float)rand()/RAND_MAX; - float x2=(float)rand()/RAND_MAX; - toneFrequency = toneFrequency0 + 0.5*m_fSpread*(x1+x2-1.0); - m_dphi = m_twoPi * toneFrequency / m_frameRate; - j0=j; - } - - m_phi += m_dphi; - if (m_phi > m_twoPi) m_phi -= m_twoPi; - if (m_ic > i0) m_amp = 0.98 * m_amp; - if (m_ic > i1) m_amp = 0.0; - - samples = load (postProcessSample (m_amp * qSin (m_phi)), samples); - ++m_ic; - } - - if (m_amp == 0.0) { // TODO G4WJS: compare double with zero might not be wise - if (icw[0] == 0) { - // no CW ID to send - Q_EMIT stateChanged ((m_state = Idle)); + // done for this chunk - continue on next call m_framesSent += numFrames; return numFrames * bytesPerFrame (); } + // fall through - m_phi = 0.0; + case Idle: + break; } - // done for this chunk - continue on next call - m_framesSent += numFrames; - return numFrames * bytesPerFrame (); - } - Q_EMIT stateChanged ((m_state = Idle)); - // fall through - - case Idle: - break; - } - Q_ASSERT (Idle == m_state); + close (); + return 0; } qint16 Modulator::postProcessSample (qint16 sample) const { if (m_muted) { // silent frame - sample = 0; + sample = 0; } else if (m_addNoise) { // Test frame, we'll add noise qint32 s = m_fac * (gran () + sample * m_snr / 32768.0); if (s > std::numeric_limits::max ()) { diff --git a/Modulator.hpp b/Modulator.hpp index d6ec3a5a9..230e3f7ec 100644 --- a/Modulator.hpp +++ b/Modulator.hpp @@ -3,11 +3,7 @@ #include "AudioDevice.hpp" -#ifdef UNIX -# define NUM_CHANNELS 2 -#else -# define NUM_CHANNELS 1 -#endif +class QAudioOutput; // // Input device that generates PCM audio frames that encode a message @@ -16,20 +12,17 @@ // Output can be muted while underway, preserving waveform timing when // transmission is resumed. // -class Modulator : public AudioDevice +class Modulator + : public AudioDevice { Q_OBJECT; - Q_PROPERTY (unsigned frequency READ frequency WRITE setFrequency); - Q_PROPERTY (bool tuning READ isTuning WRITE tune); - Q_PROPERTY (bool muted READ isMuted WRITE mute); - public: enum ModulatorState {Synchronizing, Active, Idle}; - Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = 0); + Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = nullptr); - Q_SLOT void open (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, AudioDevice::Channel, bool synchronize = true, double dBSNR = 99.); + void close () override; bool isTuning () const {return m_tuning;} bool isMuted () const {return m_muted;} @@ -37,6 +30,13 @@ public: bool isActive () const {return m_state != Idle;} void setWide9(double d1, double d2) {m_toneSpacing=d1; m_fSpread=d2;} + Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput *, Channel = Mono, bool synchronize = true, double dBSNR = 99.); + Q_SLOT void stop (); + Q_SLOT void tune (bool newState = true) {m_tuning = newState;} + Q_SLOT void mute (bool newState = true) {m_muted = newState;} + Q_SLOT void setFrequency (unsigned newFrequency) {m_frequency = newFrequency;} + Q_SIGNAL void stateChanged (ModulatorState) const; + protected: qint64 readData (char * data, qint64 maxSize); qint64 writeData (char const * /* data */, qint64 /* maxSize */) @@ -44,24 +44,11 @@ protected: return -1; // we don't consume data } -private: - /* private because we epect to run in a thread and don't want direct - C++ calls made, instead they must be invoked via the Qt - signal/slot mechanism which is thread safe */ - Q_SLOT void close () - { - Q_EMIT stateChanged ((m_state = Idle)); - AudioDevice::close (); - } - - Q_SLOT void tune (bool newState = true) {m_tuning = newState;} - Q_SLOT void mute (bool newState = true) {m_muted = newState;} - Q_SLOT void setFrequency (unsigned newFrequency) {m_frequency = newFrequency;} - Q_SIGNAL void stateChanged (ModulatorState) const; - private: qint16 postProcessSample (qint16 sample) const; + QAudioOutput * m_stream; + unsigned m_symbolsLength; static double const m_twoPi; @@ -80,8 +67,8 @@ private: qint64 m_silentFrames; qint64 m_framesSent; - int m_frameRate; - int m_period; + unsigned m_frameRate; + unsigned m_period; ModulatorState volatile m_state; bool volatile m_tuning; diff --git a/about.h b/about.h index 02e9239e4..c2ac75d1b 100644 --- a/about.h +++ b/about.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef ABOUTDLG_H #define ABOUTDLG_H diff --git a/decodedtext.h b/decodedtext.h index e60a91d40..47dcd63a2 100644 --- a/decodedtext.h +++ b/decodedtext.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- /* * Class to handle the formatted string as returned from the fortran decoder * diff --git a/displaytext.h b/displaytext.h index 1307b37a9..8ed3b0ac4 100644 --- a/displaytext.h +++ b/displaytext.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef DISPLAYTEXT_H #define DISPLAYTEXT_H diff --git a/getfile.h b/getfile.h index 2e255d1a4..4cd104514 100644 --- a/getfile.h +++ b/getfile.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef GETFILE_H #define GETFILE_H #include diff --git a/logqso.h b/logqso.h index 72121e76e..47047750a 100644 --- a/logqso.h +++ b/logqso.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef LogQSO_H #define LogQSO_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 5b7ce0c84..9e65c3c08 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -36,7 +36,6 @@ int icw[NUM_CW_SYMBOLS]; //Dits for CW ID int outBufSize; int rc; -qint32 g_COMportOpen; qint32 g_iptt; static int nc1=1; wchar_t buffer[256]; @@ -134,37 +133,30 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme connect (m_audioThread, &QThread::finished, m_audioThread, &QThread::deleteLater); // disposal // hook up sound output stream slots & signals - connect (this, SIGNAL (startAudioOutputStream (QAudioDeviceInfo const&, unsigned, unsigned)), &m_soundOutput, SLOT (startStream (QAudioDeviceInfo const&, unsigned, unsigned))); - connect (this, SIGNAL (stopAudioOutputStream ()), &m_soundOutput, SLOT (stopStream ())); + connect (this, &MainWindow::initializeAudioOutputStream, &m_soundOutput, &SoundOutput::setFormat); connect (&m_soundOutput, &SoundOutput::error, this, &MainWindow::showSoundOutError); // connect (&m_soundOutput, &SoundOutput::status, this, &MainWindow::showStatusMessage); - connect (this, SIGNAL (outAttenuationChanged (qreal)), &m_soundOutput, SLOT (setAttenuation (qreal))); + connect (this, &MainWindow::outAttenuationChanged, &m_soundOutput, &SoundOutput::setAttenuation); // hook up Modulator slots - connect (this, SIGNAL (muteAudioOutput (bool)), &m_modulator, SLOT (mute (bool))); - 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, &MainWindow::muteAudioOutput, &m_modulator, &Modulator::mute); + connect (this, &MainWindow::transmitFrequency, &m_modulator, &Modulator::setFrequency); + connect (this, &MainWindow::endTransmitMessage, &m_modulator, &Modulator::stop); + connect (this, &MainWindow::tune, &m_modulator, &Modulator::tune); + connect (this, &MainWindow::sendMessage, &m_modulator, &Modulator::start); // hook up the audio input stream - 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 (this, &MainWindow::startAudioInputStream, &m_soundInput, &SoundInput::start); connect (this, &MainWindow::finished, &m_soundInput, &SoundInput::stop); + connect (this, &MainWindow::finished, this, &MainWindow::close); - connect(&m_soundInput, SIGNAL (error (QString)), this, SLOT (showSoundInError (QString))); - // connect(&m_soundInput, SIGNAL(status(QString)), this, SLOT(showStatusMessage(QString))); + connect(&m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError); + // connect(&m_soundInput, &SoundInput::status, this, &MainWindow::showStatusMessage); // 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))); + connect (this, &MainWindow::detectorSetMonitoring, &m_detector, &Detector::setMonitoring); + connect(&m_detector, &Detector::framesWritten, this, &MainWindow::dataSink); // setup the waterfall connect(m_wideGraph.data (), SIGNAL(freezeDecode2(int)),this, @@ -281,7 +273,7 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme ptt0Timer = new QTimer(this); ptt0Timer->setSingleShot(true); - connect (ptt0Timer, SIGNAL (timeout ()), &m_modulator, SLOT (close ())); + connect (ptt0Timer, &QTimer::timeout, &m_modulator, &Modulator::stop); connect(ptt0Timer, SIGNAL(timeout()), this, SLOT(stopTx2())); ptt1Timer = new QTimer(this); ptt1Timer->setSingleShot(true); @@ -293,7 +285,7 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme tuneButtonTimer= new QTimer(this); tuneButtonTimer->setSingleShot(true); - connect (tuneButtonTimer, SIGNAL (timeout ()), &m_modulator, SLOT (close ())); + connect (tuneButtonTimer, &QTimer::timeout, &m_modulator, &Modulator::stop); connect(tuneButtonTimer, SIGNAL(timeout()), this, SLOT(on_stopTxButton_clicked())); @@ -328,7 +320,6 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme m_inGain=0; m_dataAvailable=false; g_iptt=0; - g_COMportOpen=0; m_secID=0; m_blankLine=false; m_decodedText2=false; @@ -423,26 +414,13 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme watcher2 = new QFutureWatcher; connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished())); - Q_EMIT startDetector (m_config.audio_input_channel ()); - Q_EMIT startAudioInputStream (m_config.audio_input_device (), AudioDevice::Mono == m_config.audio_input_channel () ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor); + Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, &m_detector, m_downSampleFactor, m_config.audio_input_channel ()); + Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); Q_EMIT transmitFrequency (m_txFreq - m_XIT); Q_EMIT muteAudioOutput (false); - // Create "m_worked", a dictionary of all calls in wsjtx.log - QFile f(m_config.data_path ().absoluteFilePath ("wsjtx.log")); - f.open(QIODevice::ReadOnly | QIODevice::Text); - QTextStream in(&f); - QString line,t,callsign; - for(int i=0; i<99999; i++) { - line=in.readLine(); - if(line.length()<=0) break; - t=line.mid(18,12); - callsign=t.mid(0,t.indexOf(",")); - } - f.close(); - - t="UTC dB DT Freq Message"; + auto t = "UTC dB DT Freq Message"; ui->decodedTextLabel->setText(t); ui->decodedTextLabel2->setText(t); @@ -450,10 +428,8 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme ui->label_9->setStyleSheet("QLabel{background-color: #aabec8}"); ui->label_10->setStyleSheet("QLabel{background-color: #aabec8}"); - ui->labUTC->setStyleSheet( \ - "QLabel { background-color : black; color : yellow; }"); - ui->labDialFreq->setStyleSheet( \ - "QLabel { background-color : black; color : yellow; }"); + ui->labUTC->setStyleSheet("QLabel { background-color : black; color : yellow; }"); + ui->labDialFreq->setStyleSheet("QLabel { background-color : black; color : yellow; }"); m_config.transceiver_online (true); qsy (m_lastMonitoredFrequency); @@ -665,14 +641,10 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog if(m_mode=="JT9W-1") m_toneSpacing=pow(2,m_config.jt9w_bw_mult ())*12000.0/6912.0; if(m_config.restart_audio_input ()) { - Q_EMIT stopAudioInputStream (); - Q_EMIT detectorClose (); - Q_EMIT startDetector (m_config.audio_input_channel ()); - Q_EMIT startAudioInputStream (m_config.audio_input_device (), AudioDevice::Mono == m_config.audio_input_channel () ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor); + Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, &m_detector, m_downSampleFactor, m_config.audio_input_channel ()); } if(m_config.restart_audio_output ()) { - Q_EMIT stopAudioOutputStream (); - Q_EMIT startAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); + Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); } auto_tx_label->setText (m_config.quick_call () ? "Tx-Enable Armed" : "Tx-Enable Disarmed"); @@ -709,7 +681,6 @@ void MainWindow::on_monitorButton_clicked (bool checked) } Q_EMIT detectorSetMonitoring (checked); - // Q_EMIT startAudioInputStream (m_params.audio_input_device, AudioDevice::Mono == m_params.audio_input_channel ? 1 : 2, m_framesAudioInputBuffered, &m_detector, m_downSampleFactor); } else { @@ -1431,7 +1402,6 @@ void MainWindow::guiUpdate() static char msgsent[29]; static int nsendingsh=0; static int giptt00=-1; - static int gcomport00=-1; static double onAirFreq0=0.0; QString rt; @@ -1670,9 +1640,8 @@ void MainWindow::guiUpdate() m_sec0=nsec; } - if(g_iptt!=giptt00 or g_COMportOpen!=gcomport00) { + if(g_iptt!=giptt00) { giptt00=g_iptt; - gcomport00=g_COMportOpen; } iptt0=g_iptt; @@ -1706,7 +1675,6 @@ void MainWindow::startTx2() void MainWindow::stopTx() { Q_EMIT endTransmitMessage (); - Q_EMIT stopAudioOutputStream (); m_transmitting=false; if ("JT9+JT65" == m_mode) ui->pbTxMode->setEnabled(true); g_iptt=0; @@ -2859,13 +2827,12 @@ void MainWindow::transmit (double snr) { if (m_modeTx == "JT65") { - Q_EMIT sendMessage (NUM_JT65_SYMBOLS, 4096.0 * 12000.0 / 11025.0, m_txFreq - m_XIT, m_config.audio_output_channel (), true, snr); + Q_EMIT sendMessage (NUM_JT65_SYMBOLS, 4096.0 * 12000.0 / 11025.0, m_txFreq - m_XIT, m_soundOutput.stream (), m_config.audio_output_channel (), true, snr); } else { - Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - m_XIT, m_config.audio_output_channel (), true, snr); + Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - m_XIT, m_soundOutput.stream (), m_config.audio_output_channel (), true, snr); } - Q_EMIT startAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); } void MainWindow::on_outAttenuation_valueChanged (int a) diff --git a/mainwindow.h b/mainwindow.h index 1397f7317..51bb8509b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef MAINWINDOW_H #define MAINWINDOW_H #ifdef QT5 @@ -13,6 +14,7 @@ #include #include "soundin.h" +#include "AudioDevice.hpp" #include "soundout.h" #include "commons.h" #include "Radio.hpp" @@ -37,7 +39,7 @@ extern int icw[NUM_CW_SYMBOLS]; //Dits for CW ID //--------------------------------------------------------------- MainWindow namespace Ui { - class MainWindow; + class MainWindow; } class QSettings; @@ -46,6 +48,7 @@ class WideGraph; class LogQSO; class Transceiver; class Astro; +class QAudioOutput; class MainWindow : public QMainWindow { @@ -175,11 +178,10 @@ private slots: private: void enable_DXCC_entity (bool on); - Q_SIGNAL void startAudioOutputStream (QAudioDeviceInfo, unsigned channels, unsigned msBuffered) const; + Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo, unsigned channels, unsigned msBuffered) const; Q_SIGNAL void stopAudioOutputStream () const; - Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor) const; - Q_SIGNAL void stopAudioInputStream () const; + Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel) const; Q_SIGNAL void startDetector (AudioDevice::Channel) const; Q_SIGNAL void detectorSetMonitoring (bool) const; @@ -190,7 +192,7 @@ private: Q_SIGNAL void transmitFrequency (unsigned) const; Q_SIGNAL void endTransmitMessage () const; Q_SIGNAL void tune (bool = true) const; - Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, AudioDevice::Channel, bool synchronize = true, double dBSNR = 99.) const; + Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, QAudioOutput *, AudioDevice::Channel = AudioDevice::Mono, bool synchronize = true, double dBSNR = 99.) const; Q_SIGNAL void outAttenuationChanged (qreal) const; private: @@ -212,185 +214,185 @@ private: Frequency m_dialFreq; - qint64 m_msErase; - qint64 m_secBandChanged; + qint64 m_msErase; + qint64 m_secBandChanged; - qint32 m_waterfallAvg; - qint32 m_ntx; - qint32 m_timeout; - qint32 m_rxFreq; - qint32 m_txFreq; - int m_XIT; - qint32 m_setftx; - qint32 m_ndepth; - qint32 m_sec0; - qint32 m_RxLog; - qint32 m_nutc0; - qint32 m_nrx; - qint32 m_hsym; + qint32 m_waterfallAvg; + qint32 m_ntx; + qint32 m_timeout; + qint32 m_rxFreq; + qint32 m_txFreq; + int m_XIT; + qint32 m_setftx; + qint32 m_ndepth; + qint32 m_sec0; + qint32 m_RxLog; + qint32 m_nutc0; + qint32 m_nrx; + qint32 m_hsym; - Detector m_detector; - SoundInput m_soundInput; + Detector m_detector; + SoundInput m_soundInput; - Modulator m_modulator; - SoundOutput m_soundOutput; - QThread * m_audioThread; + Modulator m_modulator; + SoundOutput m_soundOutput; + QThread * m_audioThread; - qint32 m_TRperiod; - qint32 m_nsps; - qint32 m_hsymStop; - qint32 m_len1; - qint32 m_inGain; - qint32 m_nsave; - qint32 m_ncw; - qint32 m_secID; - QString m_band; - qint32 m_repeatMsg; - qint32 m_watchdogLimit; - qint32 m_fMax; - qint32 m_EMEbandIndex; - qint32 m_toneMultIndex; - qint32 m_astroFont; + qint32 m_TRperiod; + qint32 m_nsps; + qint32 m_hsymStop; + qint32 m_len1; + qint32 m_inGain; + qint32 m_nsave; + qint32 m_ncw; + qint32 m_secID; + QString m_band; + qint32 m_repeatMsg; + qint32 m_watchdogLimit; + qint32 m_fMax; + qint32 m_EMEbandIndex; + qint32 m_toneMultIndex; + qint32 m_astroFont; - bool m_btxok; //True if OK to transmit - bool m_btxMute; //True if transmit should be muted - bool m_diskData; - bool m_loopall; - bool m_decoderBusy; - bool m_txFirst; - bool m_auto; - bool m_restart; - bool m_startAnother; - bool m_saveDecoded; - bool m_saveAll; - bool m_widebandDecode; - bool m_call3Modified; - bool m_dataAvailable; - bool m_killAll; - bool m_bdecoded; - bool m_monitorStartOFF; - bool m_pskReporterInit; - bool m_noSuffix; - bool m_toRTTY; - bool m_dBtoComments; - bool m_promptToLog; - bool m_blankLine; - bool m_insertBlank; - bool m_displayDXCCEntity; - bool m_clearCallGrid; - bool m_bMiles; - bool m_decodedText2; - bool m_freeText; - bool m_quickCall; - bool m_73TxDisable; - bool m_sent73; - bool m_runaway; - bool m_bMultipleOK; - bool m_lockTxFreq; - bool m_tx2QSO; - bool m_CATerror; - bool m_plus2kHz; - bool m_bAstroData; + bool m_btxok; //True if OK to transmit + bool m_btxMute; //True if transmit should be muted + bool m_diskData; + bool m_loopall; + bool m_decoderBusy; + bool m_txFirst; + bool m_auto; + bool m_restart; + bool m_startAnother; + bool m_saveDecoded; + bool m_saveAll; + bool m_widebandDecode; + bool m_call3Modified; + bool m_dataAvailable; + bool m_killAll; + bool m_bdecoded; + bool m_monitorStartOFF; + bool m_pskReporterInit; + bool m_noSuffix; + bool m_toRTTY; + bool m_dBtoComments; + bool m_promptToLog; + bool m_blankLine; + bool m_insertBlank; + bool m_displayDXCCEntity; + bool m_clearCallGrid; + bool m_bMiles; + bool m_decodedText2; + bool m_freeText; + bool m_quickCall; + bool m_73TxDisable; + bool m_sent73; + bool m_runaway; + bool m_bMultipleOK; + bool m_lockTxFreq; + bool m_tx2QSO; + bool m_CATerror; + bool m_plus2kHz; + bool m_bAstroData; - float m_pctZap; + float m_pctZap; - // labels in status bar - QLabel * tx_status_label; - QLabel * mode_label; - QLabel * last_tx_label; - QLabel * auto_tx_label; + // labels in status bar + QLabel * tx_status_label; + QLabel * mode_label; + QLabel * last_tx_label; + QLabel * auto_tx_label; - QMessageBox msgBox0; + QMessageBox msgBox0; - QFuture* future1; - QFuture* future2; - QFuture* future3; - QFutureWatcher* watcher1; - QFutureWatcher* watcher2; - QFutureWatcher* watcher3; + QFuture* future1; + QFuture* future2; + QFuture* future3; + QFutureWatcher* watcher1; + QFutureWatcher* watcher2; + QFutureWatcher* watcher3; - QProcess proc_jt9; + QProcess proc_jt9; - QTimer m_guiTimer; - QTimer* ptt1Timer; //StartTx delay - QTimer* ptt0Timer; //StopTx delay - QTimer* logQSOTimer; - QTimer* killFileTimer; - QTimer* tuneButtonTimer; + QTimer m_guiTimer; + QTimer* ptt1Timer; //StartTx delay + QTimer* ptt0Timer; //StopTx delay + QTimer* logQSOTimer; + QTimer* killFileTimer; + QTimer* tuneButtonTimer; - QString m_path; - QString m_pbdecoding_style1; - QString m_pbmonitor_style; - QString m_pbAutoOn_style; - QString m_pbTune_style; - QString m_baseCall; - QString m_hisCall; - QString m_hisGrid; - QString m_appDir; - QString m_dxccPfx; - QString m_palette; - QString m_dateTime; - QString m_mode; - QString m_modeTx; - QString m_fname; - QString m_rpt; - QString m_rptSent; - QString m_rptRcvd; - QString m_qsoStart; - QString m_qsoStop; - QString m_cmnd; - QString m_msgSent0; - QString m_fileToSave; + QString m_path; + QString m_pbdecoding_style1; + QString m_pbmonitor_style; + QString m_pbAutoOn_style; + QString m_pbTune_style; + QString m_baseCall; + QString m_hisCall; + QString m_hisGrid; + QString m_appDir; + QString m_dxccPfx; + QString m_palette; + QString m_dateTime; + QString m_mode; + QString m_modeTx; + QString m_fname; + QString m_rpt; + QString m_rptSent; + QString m_rptRcvd; + QString m_qsoStart; + QString m_qsoStop; + QString m_cmnd; + QString m_msgSent0; + QString m_fileToSave; - QStringList m_prefix; - QStringList m_suffix; + QStringList m_prefix; + QStringList m_suffix; - QHash m_pfx; - QHash m_sfx; + QHash m_pfx; + QHash m_sfx; - QDateTime m_dateTimeQSO; - QRect m_astroGeom; + QDateTime m_dateTimeQSO; + QRect m_astroGeom; - QSharedMemory *mem_jt9; - // Multiple instances: - QString mykey_jt9; - PSK_Reporter *psk_Reporter; - SignalMeter *signalMeter; - LogBook m_logBook; - DecodedText m_QSOText; - unsigned m_msAudioOutputBuffered; - unsigned m_framesAudioInputBuffered; - unsigned m_downSampleFactor; - QThread::Priority m_audioThreadPriority; - bool m_bandEdited; - bool m_splitMode; - bool m_monitoring; - bool m_transmitting; - bool m_tune; - Frequency m_lastMonitoredFrequency; - double m_toneSpacing; + QSharedMemory *mem_jt9; + // Multiple instances: + QString mykey_jt9; + PSK_Reporter *psk_Reporter; + SignalMeter *signalMeter; + LogBook m_logBook; + DecodedText m_QSOText; + unsigned m_msAudioOutputBuffered; + unsigned m_framesAudioInputBuffered; + unsigned m_downSampleFactor; + QThread::Priority m_audioThreadPriority; + bool m_bandEdited; + bool m_splitMode; + bool m_monitoring; + bool m_transmitting; + bool m_tune; + Frequency m_lastMonitoredFrequency; + double m_toneSpacing; -//---------------------------------------------------- private functions - void readSettings(); - void setDecodedTextFont (QFont const&); - void writeSettings(); - void createStatusBar(); - void updateStatusBar(); - void msgBox(QString t); - void genStdMsgs(QString rpt); - void lookup(); - void ba2msg(QByteArray ba, char* message); - void msgtype(QString t, QLineEdit* tx); - void stub(); - void statusChanged(); - void qsy(Frequency f); - bool gridOK(QString g); - bool shortList(QString callsign); - QString baseCall(QString t); - void transmit (double snr = 99.); - void rigFailure (QString const& reason, QString const& detail); - void pskSetLocal (); - void displayDialFrequency (); + //---------------------------------------------------- private functions + void readSettings(); + void setDecodedTextFont (QFont const&); + void writeSettings(); + void createStatusBar(); + void updateStatusBar(); + void msgBox(QString t); + void genStdMsgs(QString rpt); + void lookup(); + void ba2msg(QByteArray ba, char* message); + void msgtype(QString t, QLineEdit* tx); + void stub(); + void statusChanged(); + void qsy(Frequency f); + bool gridOK(QString g); + bool shortList(QString callsign); + QString baseCall(QString t); + void transmit (double snr = 99.); + void rigFailure (QString const& reason, QString const& detail); + void pskSetLocal (); + void displayDialFrequency (); }; extern void getfile(QString fname, int ntrperiod); @@ -402,25 +404,25 @@ extern void getDev(int* numDevices,char hostAPI_DeviceName[][50], extern int ptt(int nport, int ntx, int* iptt, int* nopen); extern "C" { -//----------------------------------------------------- C and Fortran routines -void symspec_(int* k, int* ntrperiod, int* nsps, int* ingain, int* nflatten, - float* px, float s[], float* df3, int* nhsym, int* npts8); + //----------------------------------------------------- C and Fortran routines + void symspec_(int* k, int* ntrperiod, int* nsps, int* ingain, int* nflatten, + float* px, float s[], float* df3, int* nhsym, int* npts8); -void genjt9_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, int len1, int len2); + void genjt9_(char* msg, int* ichk, char* msgsent, int itone[], + int* itext, int len1, int len2); -void gen65_(char* msg, int* ichk, char* msgsent, int itone[], - int* itext, int len1, int len2); + void gen65_(char* msg, int* ichk, char* msgsent, int itone[], + int* itext, int len1, int len2); -bool stdmsg_(const char* msg, int len); + bool stdmsg_(const char* msg, int len); -void azdist_(char* MyGrid, char* HisGrid, double* utch, int* nAz, int* nEl, - int* nDmiles, int* nDkm, int* nHotAz, int* nHotABetter, - int len1, int len2); + void azdist_(char* MyGrid, char* HisGrid, double* utch, int* nAz, int* nEl, + int* nDmiles, int* nDkm, int* nHotAz, int* nHotABetter, + int len1, int len2); -void morse_(char* msg, int* icw, int* ncw, int len); + void morse_(char* msg, int* icw, int* ncw, int len); -int ptt_(int nport, int ntx, int* iptt, int* nopen); + int ptt_(int nport, int ntx, int* iptt, int* nopen); } diff --git a/meterwidget.h b/meterwidget.h index 7b51efb65..fbc27b6b9 100644 --- a/meterwidget.h +++ b/meterwidget.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef METERWIDGET_H #define METERWIDGET_H diff --git a/plotter.h b/plotter.h index 99aa8b31d..b824cc2c1 100644 --- a/plotter.h +++ b/plotter.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- /////////////////////////////////////////////////////////////////////////// // Some code in this file and accompanying files is based on work by // Moe Wheatley, AE4Y, released under the "Simplified BSD License". diff --git a/psk_reporter.h b/psk_reporter.h index 46bc72756..4baaa4c15 100644 --- a/psk_reporter.h +++ b/psk_reporter.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef PSK_REPORTER_H #define PSK_REPORTER_H diff --git a/signalmeter.h b/signalmeter.h index ea1aa6295..c5e21d61d 100644 --- a/signalmeter.h +++ b/signalmeter.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef SIGNALMETER_H #define SIGNALMETER_H diff --git a/sleep.h b/sleep.h index c11188c2a..c170c9c55 100644 --- a/sleep.h +++ b/sleep.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef SLEEP_H #define SLEEP_H #include diff --git a/soundin.cpp b/soundin.cpp index 377242bf6..cf0d500ae 100644 --- a/soundin.cpp +++ b/soundin.cpp @@ -15,40 +15,41 @@ bool SoundInput::audioError () const if (m_stream) { switch (m_stream->error ()) - { - case QAudio::OpenError: - Q_EMIT error (tr ("An error opening the audio input device has occurred.")); - break; + { + case QAudio::OpenError: + Q_EMIT error (tr ("An error opening the audio input device has occurred.")); + break; - case QAudio::IOError: - Q_EMIT error (tr ("An error occurred during read from the audio input device.")); - break; + case QAudio::IOError: + Q_EMIT error (tr ("An error occurred during read from the audio input device.")); + break; - case QAudio::UnderrunError: - Q_EMIT error (tr ("Audio data not being fed to the audio input device fast enough.")); - break; + case QAudio::UnderrunError: + Q_EMIT error (tr ("Audio data not being fed to the audio input device fast enough.")); + break; - case QAudio::FatalError: - Q_EMIT error (tr ("Non-recoverable error, audio input device not usable at this time.")); - break; + case QAudio::FatalError: + Q_EMIT error (tr ("Non-recoverable error, audio input device not usable at this time.")); + break; - case QAudio::NoError: - result = false; - break; - } + case QAudio::NoError: + result = false; + break; + } } return result; } -void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor) +void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel channel) { - Q_ASSERT (0 < channels && channels < 3); Q_ASSERT (sink); - stop(); + stop (); + + m_sink = sink; QAudioFormat format (device.preferredFormat()); - format.setChannelCount (channels); + format.setChannelCount (AudioDevice::Mono == channel ? 1 : 2); format.setCodec ("audio/pcm"); format.setSampleRate (12000 * downSampleFactor); format.setSampleType (QAudioFormat::SignedInt); @@ -74,9 +75,17 @@ void SoundInput::start(QAudioDeviceInfo const& device, unsigned channels, int fr } connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged); + m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer)); - m_stream->start (sink); - audioError (); + if (sink->initialize (QIODevice::WriteOnly, channel)) + { + m_stream->start (sink); + audioError (); + } + else + { + Q_EMIT error (tr ("Failed to initialize audio sink device")); + } } void SoundInput::handleStateChanged (QAudio::State newState) const @@ -97,13 +106,13 @@ void SoundInput::handleStateChanged (QAudio::State newState) const case QAudio::StoppedState: if (audioError ()) - { - Q_EMIT status (tr ("Error")); - } + { + Q_EMIT status (tr ("Error")); + } else - { - Q_EMIT status (tr ("Stopped")); - } + { + Q_EMIT status (tr ("Stopped")); + } break; } } @@ -115,8 +124,14 @@ void SoundInput::stop() m_stream->stop (); } m_stream.reset (); + + if (m_sink) + { + m_sink->close (); + } } SoundInput::~SoundInput () { + stop (); } diff --git a/soundin.h b/soundin.h index 652075960..51c526238 100644 --- a/soundin.h +++ b/soundin.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef SOUNDIN_H__ #define SOUNDIN_H__ @@ -6,9 +7,10 @@ #include #include +#include "AudioDevice.hpp" + class QAudioDeviceInfo; class QAudioInput; -class QIODevice; // Gets audio data from sound sample source and passes it to a sink device class SoundInput @@ -16,28 +18,31 @@ class SoundInput { Q_OBJECT; - public: - SoundInput (QObject * parent = 0) - : QObject (parent) +public: + SoundInput (QObject * parent = nullptr) + : QObject {parent} + , m_sink {nullptr} { } ~SoundInput (); - // sink must exist from the start call to any following stop () call - Q_SLOT void start(QAudioDeviceInfo const&, unsigned channels, int framesPerBuffer, QIODevice * sink, unsigned downSampleFactor); - Q_SLOT void stop(); + // sink must exist from the start call until the next start call or + // stop call + Q_SLOT void start(QAudioDeviceInfo const&, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel = AudioDevice::Mono); + Q_SLOT void stop (); - private: Q_SIGNAL void error (QString message) const; Q_SIGNAL void status (QString message) const; +private: // used internally Q_SLOT void handleStateChanged (QAudio::State) const; bool audioError () const; QScopedPointer m_stream; + AudioDevice * m_sink; }; #endif diff --git a/soundout.cpp b/soundout.cpp index 5a74ac405..f8830d715 100644 --- a/soundout.cpp +++ b/soundout.cpp @@ -21,27 +21,27 @@ bool SoundOutput::audioError () const Q_ASSERT_X (m_stream, "SoundOutput", "programming error"); if (m_stream) { switch (m_stream->error ()) - { - case QAudio::OpenError: - Q_EMIT error (tr ("An error opening the audio output device has occurred.")); - break; + { + case QAudio::OpenError: + Q_EMIT error (tr ("An error opening the audio output device has occurred.")); + break; - case QAudio::IOError: - Q_EMIT error (tr ("An error occurred during write to the audio output device.")); - break; + case QAudio::IOError: + Q_EMIT error (tr ("An error occurred during write to the audio output device.")); + break; - case QAudio::UnderrunError: - Q_EMIT error (tr ("Audio data not being fed to the audio output device fast enough.")); - break; + case QAudio::UnderrunError: + Q_EMIT error (tr ("Audio data not being fed to the audio output device fast enough.")); + break; - case QAudio::FatalError: - Q_EMIT error (tr ("Non-recoverable error, audio output device not usable at this time.")); - break; + case QAudio::FatalError: + Q_EMIT error (tr ("Non-recoverable error, audio output device not usable at this time.")); + break; - case QAudio::NoError: - result = false; - break; - } + case QAudio::NoError: + result = false; + break; + } } return result; } @@ -54,8 +54,7 @@ SoundOutput::SoundOutput (QIODevice * source) Q_ASSERT (source); } -void SoundOutput::startStream (QAudioDeviceInfo const& device, \ - unsigned channels, unsigned msBuffered) +void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered) { Q_ASSERT (0 < channels && channels < 3); @@ -70,24 +69,23 @@ void SoundOutput::startStream (QAudioDeviceInfo const& device, \ format.setSampleType (QAudioFormat::SignedInt); format.setSampleSize (16); if (!format.isValid ()) - { - Q_EMIT error (tr ("Requested output audio format is not valid.")); - } + { + Q_EMIT error (tr ("Requested output audio format is not valid.")); + } if (!device.isFormatSupported (format)) - { - Q_EMIT error (tr ("Requested output audio format is not supported on device.")); - } + { + Q_EMIT error (tr ("Requested output audio format is not supported on device.")); + } m_stream.reset (new QAudioOutput (device, format)); audioError (); m_stream->setVolume (m_volume); m_stream->setNotifyInterval(100); - connect (m_stream.data(), &QAudioOutput::stateChanged, this, \ - &SoundOutput::handleStateChanged); + connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged); m_currentDevice = device; -// qDebug() << "A" << m_volume << m_stream->notifyInterval(); + // qDebug() << "A" << m_volume << m_stream->notifyInterval(); } // @@ -103,12 +101,8 @@ void SoundOutput::startStream (QAudioDeviceInfo const& device, \ // we have to set this before every start on the stream because the // Windows implementation seems to forget the buffer size after a // stop. - m_stream->setBufferSize (m_stream->format().bytesForDuration( - (msBuffered ? msBuffered : MS_BUFFERED) * 1000)); -// qDebug() << "B" << m_stream->bufferSize() << m_stream->periodSize() << m_stream->notifyInterval(); - - m_stream->start (m_source); - audioError (); + m_stream->setBufferSize (m_stream->format().bytesForDuration((msBuffered ? msBuffered : MS_BUFFERED) * 1000)); + // qDebug() << "B" << m_stream->bufferSize() << m_stream->periodSize() << m_stream->notifyInterval(); } void SoundOutput::suspend () @@ -138,7 +132,7 @@ void SoundOutput::setAttenuation (qreal a) { Q_ASSERT (0. <= a && a <= 99.); m_volume = qPow (10., -a / 10.); -// qDebug () << "SoundOut: attn = " << a << ", vol = " << m_volume; + // qDebug () << "SoundOut: attn = " << a << ", vol = " << m_volume; if (m_stream) { m_stream->setVolume (m_volume); @@ -154,15 +148,6 @@ void SoundOutput::resetAttenuation () } } -void SoundOutput::stopStream () -{ - if (m_stream) - { - m_stream->stop (); - audioError (); - } -} - void SoundOutput::handleStateChanged (QAudio::State newState) { switch (newState) @@ -185,13 +170,13 @@ void SoundOutput::handleStateChanged (QAudio::State newState) case QAudio::StoppedState: m_active = false; if (audioError ()) - { - Q_EMIT status (tr ("Error")); - } + { + Q_EMIT status (tr ("Error")); + } else - { - Q_EMIT status (tr ("Stopped")); - } + { + Q_EMIT status (tr ("Stopped")); + } break; } } diff --git a/soundout.h b/soundout.h index 811a8893c..12ba25d97 100644 --- a/soundout.h +++ b/soundout.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef SOUNDOUT_H__ #define SOUNDOUT_H__ @@ -14,39 +15,36 @@ class SoundOutput : public QObject { Q_OBJECT; - + Q_PROPERTY(bool running READ isRunning); Q_PROPERTY(unsigned attenuation READ attenuation WRITE setAttenuation RESET resetAttenuation); - - public: + +public: SoundOutput (QIODevice * source); ~SoundOutput (); - + bool isRunning() const {return m_active;} qreal attenuation () const; + QAudioOutput * stream () {return m_stream.data ();} - private Q_SLOTS: - /* private because we expect to run in a thread and don't want direct - C++ calls made, instead they must be invoked via the Qt - signal/slot mechanism which is thread safe */ - void startStream (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u); +public Q_SLOTS: + void setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u); void suspend (); void resume (); - void stopStream (); void setAttenuation (qreal); /* unsigned */ void resetAttenuation (); /* to zero */ - - Q_SIGNALS: + +Q_SIGNALS: void error (QString message) const; void status (QString message) const; private: bool audioError () const; - private Q_SLOTS: +private Q_SLOTS: void handleStateChanged (QAudio::State); - private: +private: QScopedPointer m_stream; QIODevice * m_source; diff --git a/widegraph.h b/widegraph.h index 909d28830..3ba972336 100644 --- a/widegraph.h +++ b/widegraph.h @@ -1,3 +1,4 @@ +// -*- Mode: C++ -*- #ifndef WIDEGRAPH_H #define WIDEGRAPH_H