From 62f923d8ad38f4823d62569df71d8726c01616cd Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Sat, 18 Feb 2023 13:18:42 +0000 Subject: [PATCH] Add support for push audio and various other fixes --- cwsender.cpp | 2 + cwsidetone.cpp | 134 +++++++++++++++++++++++++++++-------------------- cwsidetone.h | 31 ++++++------ 3 files changed, 98 insertions(+), 69 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index 6b60b59..d31d384 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -38,6 +38,8 @@ cwSender::cwSender(QWidget *parent) : [=](const unsigned char& pitch) { tone->setFrequency(pitch); }); connect(this, &cwSender::setLevel, [=](const unsigned char& level) { tone->setLevel(level); }); + connect(this, &cwSender::stopCW, + [=]() { tone->stopSending(); }); } cwSender::~cwSender() diff --git a/cwsidetone.cpp b/cwsidetone.cpp index a34b771..b8542a7 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -1,7 +1,6 @@ #include "cwsidetone.h" #include "logcategories.h" -#include "qapplication.h" cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* parent) : parent(parent), @@ -74,8 +73,8 @@ cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* pa cwSidetone::~cwSidetone() { + this->stop(); output->stop(); - delete output; } void cwSidetone::init() @@ -89,7 +88,7 @@ void cwSidetone::init() format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice()); #else - format.setSampleFormat(QAudioFormat::Float); + format.setSampleFormat(QAudioFormat::Int16); QAudioDevice device = QMediaDevices::defaultAudioOutput(); #endif if (!device.isNull()) { @@ -99,9 +98,9 @@ void cwSidetone::init() } #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - output = new QAudioOutput(device,format); + output.reset(new QAudioOutput(device,format)); #else - output = new QAudioSink(device,format); + output.reset(new QAudioSink(device,format)); #endif #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) @@ -110,75 +109,93 @@ void cwSidetone::init() #else qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 type: %3") .arg(device.description()).arg(volume).arg(format.sampleRate()).arg(format.sampleFormat()); -#endif - - - outputDevice = output->start(); +#endif } + this->start(); // Start QIODevice } void cwSidetone::send(QString text) { - messages.push_back(text.simplified()); - - if (messages.size() > 1) { - // There are already queued messages so just return - return; - } + text=text.simplified(); QString currentChar; - if (output->state() == QAudio::StoppedState || output->state() == QAudio::SuspendedState) { - output->resume(); - } - for (auto txt = messages.begin(); txt != messages.end();) + int pos = 0; + while (pos < text.size()) { - int pos = 0; - buffer.clear(); - - while (pos < txt->size()) + QChar ch = text.at(pos).toUpper(); + if (ch == NULL) { - QChar ch = txt->at(pos).toUpper(); - if (ch == NULL) - { - currentChar = cwTable[' ']; - } - else if (this->cwTable.contains(ch)) - { - currentChar = cwTable[ch]; - } - else - { - currentChar=cwTable['?']; - } - generateMorse(currentChar); - pos++; + currentChar = cwTable[' ']; } - if (outputDevice != Q_NULLPTR) { - qint64 written = 0; - while (written != -1 && written < buffer.size()) - { - written += outputDevice->write(buffer.data() + written, buffer.size() - written); - QApplication::processEvents(); - } - if (written == -1) - { - qWarning(logCW()) << QString("Sidetone sending error occurred, aborting (%0 bytes of %1 remaining)").arg(buffer.size()-written).arg(buffer.size()); - } + else if (this->cwTable.contains(ch)) + { + currentChar = cwTable[ch]; } - txt = messages.erase(txt); + else + { + currentChar=cwTable['?']; + } + generateMorse(currentChar); + pos++; } //qInfo(logCW()) << "Sending" << this->currentChar; - emit finished(); + if (output->state() == QAudio::StoppedState) + { + output->start(this); + } + + if (output->state() == QAudio::IdleState) { + output->suspend(); + output->resume(); + } return; } + +void cwSidetone::start() +{ + open(QIODevice::ReadOnly); +} + +void cwSidetone::stop() +{ + close(); +} + +qint64 cwSidetone::readData(char *data, qint64 len) +{ + QMutexLocker locker(&mutex); + const qint64 total = qMin((buffer.size()), len); + memcpy(data, buffer.constData(), total); + buffer.remove(0,total); + if (buffer.size() == 0) { + emit finished(); + } + return total; +} + +qint64 cwSidetone::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; +} + +qint64 cwSidetone::bytesAvailable() const +{ + return buffer.size() + QIODevice::bytesAvailable(); +} + void cwSidetone::generateMorse(QString morse) { int dit = int(double(SIDETONE_MULTIPLIER / this->speed * SIDETONE_MULTIPLIER)); - int dah = int(dit * this->ratio); + int dah = int(double(dit * this->ratio)); + + QMutexLocker locker(&mutex); for (int i=0;i(ptr) = static_cast((1.0 + x) / 2 * 255); else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) - *reinterpret_cast(ptr) = static_cast(x * 32767); + *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt) *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleType() == QAudioFormat::Float) @@ -248,7 +265,7 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) if (format.sampleFormat() == QAudioFormat::UInt8) *reinterpret_cast(ptr) = static_cast((1.0 + x) / 2 * 255); else if (format.sampleFormat() == QAudioFormat::Int16) - *reinterpret_cast(ptr) = static_cast(x * 32767); + *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleFormat() == QAudioFormat::Int32) *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleFormat() == QAudioFormat::Float) @@ -284,3 +301,10 @@ void cwSidetone::setRatio(unsigned char ratio) void cwSidetone::setLevel(int level) { volume = level; } + +void cwSidetone::stopSending() { + QMutexLocker locker(&mutex); + buffer.clear(); +} + + diff --git a/cwsidetone.h b/cwsidetone.h index e43ec97..5fb9436 100644 --- a/cwsidetone.h +++ b/cwsidetone.h @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) #include @@ -14,22 +18,24 @@ #include #endif -#include -#include -#include - -#include - //#define SIDETONE_MULTIPLIER 386.0 #define SIDETONE_MULTIPLIER 1095.46 -class cwSidetone : public QObject +class cwSidetone : public QIODevice { Q_OBJECT public: explicit cwSidetone(int level, int speed, int freq, double ratio, QWidget *parent = 0); ~cwSidetone(); + void start(); + void stop(); + + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + qint64 bytesAvailable() const override; + qint64 size() const override { return buffer.size(); } + signals: void finished(); public slots: @@ -38,6 +44,7 @@ public slots: void setFrequency(unsigned char frequency); void setRatio(unsigned char ratio); void setLevel(int level); + void stopSending(); private: void init(); @@ -45,22 +52,18 @@ private: QByteArray generateData(qint64 len, qint64 freq); QByteArray buffer; QMap< QChar, QString> cwTable; - int position = 0; - int charSpace = 20; - int wordSpace = 60; QWidget* parent; int volume; int speed; int frequency; double ratio; QAudioFormat format; - std::deque messages; + QMutex mutex; #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - QAudioOutput* output = Q_NULLPTR; + QScopedPointer output; #else - QAudioSink* output = Q_NULLPTR; + QScopedPointer output; #endif - QIODevice* outputDevice = Q_NULLPTR; }; #endif // CWSIDETONE_H