diff --git a/plugins/feature/demodanalyzer/demodanalyzerworker.h b/plugins/feature/demodanalyzer/demodanalyzerworker.h index 4399972d6..cc191c977 100644 --- a/plugins/feature/demodanalyzer/demodanalyzerworker.h +++ b/plugins/feature/demodanalyzer/demodanalyzerworker.h @@ -109,7 +109,6 @@ public: private: DataFifo *m_dataFifo; - int m_channelSampleRate; int m_sinkSampleRate; MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object diff --git a/plugins/feature/morsedecoder/CMakeLists.txt b/plugins/feature/morsedecoder/CMakeLists.txt index 8eefe5a54..4b8e4a94e 100644 --- a/plugins/feature/morsedecoder/CMakeLists.txt +++ b/plugins/feature/morsedecoder/CMakeLists.txt @@ -18,6 +18,7 @@ set(morsedecoder_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${GGMORSE_INCLUDE_DIR} ) if(NOT SERVER_MODE) @@ -51,6 +52,7 @@ target_link_libraries(${TARGET_NAME} ${TARGET_LIB} sdrbase ${TARGET_LIB_GUI} + ${GGMORSE_LIBRARIES} ) install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/feature/morsedecoder/morsedecoder.cpp b/plugins/feature/morsedecoder/morsedecoder.cpp index 913904bdf..5573f0464 100644 --- a/plugins/feature/morsedecoder/morsedecoder.cpp +++ b/plugins/feature/morsedecoder/morsedecoder.cpp @@ -38,6 +38,7 @@ MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgStartStop, Message) MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgReportChannels, Message) MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgSelectChannel, Message) MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgReportSampleRate, Message) +MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgReportText, Message) const char* const MorseDecoder::m_featureIdURI = "sdrangel.feature.morsedecoder"; const char* const MorseDecoder::m_featureId = "MorseDecoder"; @@ -238,6 +239,26 @@ bool MorseDecoder::handleMessage(const Message& cmd) return true; } + else if (MsgReportText::match(cmd)) + { + MsgReportText& report = (MsgReportText&) cmd; + + // Write to log file + if (m_logFile.isOpen()) + { + // Format text + m_logStream << MorseDecoderSettings::formatText(report.getText()); + } + + if (getMessageQueueToGUI()) + { + MsgReportText *msg = new MsgReportText(report); + getMessageQueueToGUI()->push(msg); + } + + // TODO: send via UDP + return true; + } else { return false; @@ -278,6 +299,29 @@ void MorseDecoder::applySettings(const MorseDecoderSettings& settings, const QLi m_worker->getInputMessageQueue()->push(msg); } + if (settingsKeys.contains("logEnabled") + || settingsKeys.contains("logFilename") + || force) + { + if (m_logFile.isOpen()) + { + m_logStream.flush(); + m_logFile.close(); + } + if (settings.m_logEnabled && !settings.m_logFilename.isEmpty()) + { + m_logFile.setFileName(settings.m_logFilename); + if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) + { + qDebug() << "RttyDemod::applySettings - Logging to: " << settings.m_logFilename; + m_logStream.setDevice(&m_logFile); + } + else + { + qDebug() << "RttyDemod::applySettings - Unable to open log file: " << settings.m_logFilename; + } + } + } if (settings.m_useReverseAPI) { diff --git a/plugins/feature/morsedecoder/morsedecoder.h b/plugins/feature/morsedecoder/morsedecoder.h index e302c8293..31e76c5c4 100644 --- a/plugins/feature/morsedecoder/morsedecoder.h +++ b/plugins/feature/morsedecoder/morsedecoder.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "feature/feature.h" #include "util/message.h" @@ -148,6 +150,29 @@ public: {} }; + class MsgReportText : public Message { + MESSAGE_CLASS_DECLARATION + + public: + QString getText() const { return m_text; } + + static MsgReportText* create(const QString& text) { + return new MsgReportText(text); + } + + float m_estimatedPitchHz; + float m_estimatedSpeedWPM; + float m_signalThreshold; + float m_costFunction; + + private: + QString m_text; + + MsgReportText(const QString& text) : + m_text(text) + {} + }; + MorseDecoder(WebAPIAdapterInterface *webAPIAdapterInterface); virtual ~MorseDecoder(); virtual void destroy() { delete this; } @@ -202,6 +227,8 @@ private: ChannelAPI *m_selectedChannel; ObjectPipe *m_dataPipe; int m_sampleRate; + QFile m_logFile; + QTextStream m_logStream; QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; diff --git a/plugins/feature/morsedecoder/morsedecodergui.cpp b/plugins/feature/morsedecoder/morsedecodergui.cpp index 5c74b22d9..894a6230b 100644 --- a/plugins/feature/morsedecoder/morsedecodergui.cpp +++ b/plugins/feature/morsedecoder/morsedecodergui.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "feature/featureuiset.h" #include "dsp/spectrumvis.h" @@ -109,6 +110,12 @@ bool MorseDecoderGUI::handleMessage(const Message& message) return true; } + else if (MorseDecoder::MsgReportText::match(message)) + { + MorseDecoder::MsgReportText& report = (MorseDecoder::MsgReportText&) message; + textReceived(report.getText()); + updateMorseStats(report.m_estimatedPitchHz, report.m_estimatedSpeedWPM, report.m_costFunction); + } return false; } @@ -125,6 +132,35 @@ void MorseDecoderGUI::handleInputMessages() } } +void MorseDecoderGUI::textReceived(const QString& text) +{ + // Is the scroll bar at the bottom? + int scrollPos = ui->text->verticalScrollBar()->value(); + bool atBottom = scrollPos >= ui->text->verticalScrollBar()->maximum(); + + // Move cursor to end where we want to append new text + // (user may have moved it by clicking / highlighting text) + ui->text->moveCursor(QTextCursor::End); + + // Restore scroll position + ui->text->verticalScrollBar()->setValue(scrollPos); + + // Format and insert text + ui->text->insertPlainText(MorseDecoderSettings::formatText(text)); + + // Scroll to bottom, if we we're previously at the bottom + if (atBottom) { + ui->text->verticalScrollBar()->setValue(ui->text->verticalScrollBar()->maximum()); + } +} + +void MorseDecoderGUI::updateMorseStats(float estPitch, float estWPM, float cost) +{ + ui->pitchText->setText(QString("%1 Hz").arg(estPitch, 0, 'f', 1)); + ui->speedText->setText(QString("%1 WPM").arg(estWPM, 0, 'f', 0)); + ui->cText->setText(QString("%1").arg(cost, 0, 'f', 3)); +} + void MorseDecoderGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; @@ -157,6 +193,7 @@ MorseDecoderGUI::MorseDecoderGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe m_morseDecoder = reinterpret_cast(feature); m_morseDecoder->setMessageQueueToGUI(&m_inputMessageQueue); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -199,6 +236,9 @@ void MorseDecoderGUI::displaySettings() setTitle(m_settings.m_title); blockApplySettings(true); getRollupContents()->restoreState(m_rollupState); + ui->statLock->setChecked(!m_settings.m_auto); + ui->logFilename->setToolTip(QString(".txt log filename: %1").arg(m_settings.m_logFilename)); + ui->logEnable->setChecked(m_settings.m_logEnabled); blockApplySettings(false); } @@ -304,6 +344,44 @@ void MorseDecoderGUI::on_channelApply_clicked() } } +void MorseDecoderGUI::on_statLock_toggled(bool checked) +{ + m_settings.m_auto = !checked; + m_settingsKeys.append("auto"); + applySettings(); +} + +void MorseDecoderGUI::on_logEnable_clicked(bool checked) +{ + m_settings.m_logEnabled = checked; + m_settingsKeys.append("logEnabled"); + applySettings(); +} + +void MorseDecoderGUI::on_logFilename_clicked() +{ + // Get filename to save to + QFileDialog fileDialog(nullptr, "Select file to log received text to", "", "*.txt"); + fileDialog.setAcceptMode(QFileDialog::AcceptSave); + + if (fileDialog.exec()) + { + QStringList fileNames = fileDialog.selectedFiles(); + if (fileNames.size() > 0) + { + m_settings.m_logFilename = fileNames[0]; + ui->logFilename->setToolTip(QString(".txt log filename: %1").arg(m_settings.m_logFilename)); + m_settingsKeys.append("logFilename"); + applySettings(); + } + } +} + +void MorseDecoderGUI::on_clearTable_clicked() +{ + ui->text->clear(); +} + void MorseDecoderGUI::tick() { } @@ -353,4 +431,8 @@ void MorseDecoderGUI::makeUIConnections() QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &MorseDecoderGUI::on_startStop_toggled); QObject::connect(ui->channels, qOverload(&QComboBox::currentIndexChanged), this, &MorseDecoderGUI::on_channels_currentIndexChanged); QObject::connect(ui->channelApply, &QPushButton::clicked, this, &MorseDecoderGUI::on_channelApply_clicked); + QObject::connect(ui->statLock, &QToolButton::toggled, this, &MorseDecoderGUI::on_statLock_toggled); + QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &MorseDecoderGUI::on_logEnable_clicked); + QObject::connect(ui->logFilename, &QToolButton::clicked, this, &MorseDecoderGUI::on_logFilename_clicked); + QObject::connect(ui->clearTable, &QPushButton::clicked, this, &MorseDecoderGUI::on_clearTable_clicked); } diff --git a/plugins/feature/morsedecoder/morsedecodergui.h b/plugins/feature/morsedecoder/morsedecodergui.h index 4de50ec28..b09144c8f 100644 --- a/plugins/feature/morsedecoder/morsedecodergui.h +++ b/plugins/feature/morsedecoder/morsedecodergui.h @@ -78,6 +78,8 @@ private: void displaySampleRate(int sampleRate); void updateChannelList(); bool handleMessage(const Message& message); + void textReceived(const QString& text); + void updateMorseStats(float estPitch, float estWPM, float cost); void makeUIConnections(); private slots: @@ -87,6 +89,10 @@ private slots: void on_startStop_toggled(bool checked); void on_channels_currentIndexChanged(int index); void on_channelApply_clicked(); + void on_statLock_toggled(bool checked); + void on_clearTable_clicked(); + void on_logEnable_clicked(bool checked=false); + void on_logFilename_clicked(); void updateStatus(); void tick(); diff --git a/plugins/feature/morsedecoder/morsedecodergui.ui b/plugins/feature/morsedecoder/morsedecodergui.ui index 58e57b76f..257081815 100644 --- a/plugins/feature/morsedecoder/morsedecodergui.ui +++ b/plugins/feature/morsedecoder/morsedecodergui.ui @@ -6,8 +6,8 @@ 0 0 - 407 - 407 + 422 + 810 @@ -18,7 +18,7 @@ - 407 + 422 407 @@ -36,13 +36,13 @@ 0 10 - 401 + 420 121 - 401 + 420 0 @@ -307,13 +307,6 @@ - - - - Qt::Vertical - - - @@ -332,6 +325,42 @@ + + + + Cost + + + + + + + + 55 + 0 + + + + 3000.000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -383,42 +412,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - C - - - - - - - - 55 - 0 - - - - 3000.000 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -428,19 +421,22 @@ 0 130 - 401 + 420 271 - - Morse Text - 0 0 + + + 420 + 0 + + diff --git a/plugins/feature/morsedecoder/morsedecodersettings.cpp b/plugins/feature/morsedecoder/morsedecodersettings.cpp index d379cab79..b91d6d55a 100644 --- a/plugins/feature/morsedecoder/morsedecodersettings.cpp +++ b/plugins/feature/morsedecoder/morsedecodersettings.cpp @@ -51,6 +51,7 @@ void MorseDecoderSettings::resetToDefaults() m_udpPort = 9999; m_logFilename = "cw_log.txt"; m_logEnabled = false; + m_auto = true; } QByteArray MorseDecoderSettings::serialize() const @@ -77,6 +78,7 @@ QByteArray MorseDecoderSettings::serialize() const s.writeU32(24, m_udpPort); s.writeString(25, m_logFilename); s.writeBool(26, m_logEnabled); + s.writeBool(27, m_auto); return s.final(); } @@ -135,6 +137,7 @@ bool MorseDecoderSettings::deserialize(const QByteArray& data) d.readString(25, &m_logFilename, "cw_log.txt"); d.readBool(26, &m_logEnabled, false); + d.readBool(27, &m_auto, true); return true; } @@ -186,6 +189,15 @@ void MorseDecoderSettings::applySettings(const QStringList& settingsKeys, const if (settingsKeys.contains("logFilename")) { m_logFilename = settings.m_logFilename; } + if (settingsKeys.contains("auto")) { + m_auto = settings.m_auto; + } + if (settingsKeys.contains("logEnabled")) { + m_logEnabled = settings.m_logEnabled; + } + if (settingsKeys.contains("logFilename")) { + m_logFilename = settings.m_logFilename; + } } QString MorseDecoderSettings::getDebugString(const QStringList& settingsKeys, bool force) const @@ -231,6 +243,33 @@ QString MorseDecoderSettings::getDebugString(const QStringList& settingsKeys, bo if (settingsKeys.contains("logFilename") || force) { ostr << " m_logFilename: " << m_logFilename.toStdString(); } + if (settingsKeys.contains("auto") || force) { + ostr << " m_auto: " << m_auto; + } + if (settingsKeys.contains("logEnabled") || force) { + ostr << " m_logEnabled: " << m_logEnabled; + } + if (settingsKeys.contains("logFilename") || force) { + ostr << " m_logFilename: " << m_logFilename.toStdString(); + } return QString(ostr.str().c_str()); } + +QString MorseDecoderSettings::formatText(const QString& text) +{ + // Format text + QString showText = text.simplified(); + + if (text.size() > 3) + { + if (text.right(1)[0].isSpace()) { + showText.append(text.right(1)); + } + if (text.left(1)[0].isSpace()) { + showText = text.left(1) + showText; + } + } + + return showText; +} diff --git a/plugins/feature/morsedecoder/morsedecodersettings.h b/plugins/feature/morsedecoder/morsedecodersettings.h index 51df14ae3..8a63f0b8d 100644 --- a/plugins/feature/morsedecoder/morsedecodersettings.h +++ b/plugins/feature/morsedecoder/morsedecodersettings.h @@ -40,6 +40,7 @@ struct MorseDecoderSettings uint16_t m_udpPort; QString m_logFilename; bool m_logEnabled; + bool m_auto; //!< Auto pitch and speed MorseDecoderSettings(); void resetToDefaults(); @@ -50,6 +51,8 @@ struct MorseDecoderSettings void applySettings(const QStringList& settingsKeys, const MorseDecoderSettings& settings); QString getDebugString(const QStringList& settingsKeys, bool force=false) const; + static QString formatText(const QString& text); + static const QStringList m_channelURIs; }; diff --git a/plugins/feature/morsedecoder/morsedecoderworker.cpp b/plugins/feature/morsedecoder/morsedecoderworker.cpp index 06f8e7186..327a3ec7e 100644 --- a/plugins/feature/morsedecoder/morsedecoderworker.cpp +++ b/plugins/feature/morsedecoder/morsedecoderworker.cpp @@ -20,6 +20,7 @@ #include "dsp/scopevis.h" #include "dsp/datafifo.h" +#include "morsedecoder.h" #include "morsedecoderworker.h" MESSAGE_CLASS_DEFINITION(MorseDecoderWorker::MsgConfigureMorseDecoderWorker, Message) @@ -28,15 +29,30 @@ MESSAGE_CLASS_DEFINITION(MorseDecoderWorker::MsgConnectFifo, Message) MorseDecoderWorker::MorseDecoderWorker() : m_dataFifo(nullptr), m_msgQueueToFeature(nullptr), - m_sampleBufferSize(0), - m_nbBytes(0) + m_auto(false), + m_pitchHz(-1), + m_speedWPM(-1) { qDebug("MorseDecoderWorker::MorseDecoderWorker"); + m_ggMorseParameters = new GGMorse::Parameters{ + 48000.0f, // sampleRateInp: capture sample rate + 48000.0f, // sampleRateOut: playback sample rate + GGMorse::kDefaultSamplesPerFrame, // samplesPerFrame: number of samples per audio frame (128) + GGMORSE_SAMPLE_FORMAT_I16, // sampleFormatInp: format of the captured audio samples + GGMORSE_SAMPLE_FORMAT_I16 // sampleFormatOut: format of the playback audio samples + }; + m_ggMorse = new GGMorse(*m_ggMorseParameters); + auto parametersDecode = m_ggMorse->getDefaultParametersDecode(); // auto pitch [200, 1200 Hz], auto speed, apply low pass and high pass + parametersDecode.applyFilterHighPass = false; + m_ggMorse->setParametersDecode(parametersDecode); + applySampleRate(48000); } MorseDecoderWorker::~MorseDecoderWorker() { m_inputMessageQueue.clear(); + delete m_ggMorse; + delete m_ggMorseParameters; } void MorseDecoderWorker::reset() @@ -63,31 +79,113 @@ void MorseDecoderWorker::feedPart( DataFifo::DataType dataType ) { - int nbBytes; + int countBytes = end - begin; + int bytesLeft = m_bytesBufferSize - m_bytesBufferCount; - switch(dataType) + if (dataType == DataFifo::DataTypeCI16) // (re, im) -> one sample conversion { - case DataFifo::DataTypeCI16: - nbBytes = 4; - break; - case DataFifo::DataTypeI16: - default: - nbBytes = 2; + countBytes /= 2; + + if (countBytes != m_convBuffer.size()) { + m_convBuffer.resize(countBytes); + } + + int16_t *s = (int16_t*) begin; + int16_t *b = (int16_t*) m_convBuffer.begin(); + + for (int is = 0; is < countBytes; is++) + { + int32_t re = s[2*is]; + int32_t im = s[2*is+1]; + b[is] = (int16_t) ((re+im) / 2); + } + + if (countBytes >= bytesLeft) + { + std::copy(m_convBuffer.begin(), m_convBuffer.begin() + bytesLeft, m_bytesBuffer.begin() + m_bytesBufferCount); // fill buffer + int unprocessedBytes = processBuffer(m_convBuffer); + std::copy(m_convBuffer.begin() + bytesLeft - unprocessedBytes, m_convBuffer.end(), m_bytesBuffer.begin()); + m_bytesBufferCount = bytesLeft + unprocessedBytes; + } + else + { + std::copy(m_convBuffer.begin(), m_convBuffer.end(), m_bytesBuffer.begin() + m_bytesBufferCount); + m_bytesBufferCount += countBytes; + } + } + else + { + if (countBytes >= bytesLeft) + { + std::copy(begin, begin + bytesLeft, m_bytesBuffer.begin() + m_bytesBufferCount); // fill buffer + int unprocessedBytes = processBuffer(m_bytesBuffer); + std::copy(begin + bytesLeft - unprocessedBytes, end, m_bytesBuffer.begin()); + m_bytesBufferCount = bytesLeft + unprocessedBytes; + } + else + { + std::copy(begin, end, m_bytesBuffer.begin() + m_bytesBufferCount); + m_bytesBufferCount += countBytes; + } + } +} + +int MorseDecoderWorker::processBuffer(QByteArray& bytesBuffer) +{ + uint32_t samplesHave = bytesBuffer.size() / 2; + uint32_t samplesTotal = bytesBuffer.size() / 2; + int bytesLeft = 0; + + GGMorse::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) + { + if (samplesHave*2 < nMaxBytes) + { + if (samplesHave != 0) + { + bytesLeft = samplesHave*2; + qDebug("MorseDecoderWorker::processBuffer::cbWaveformInp: nMaxBytes: %u / %u samples left buffer size: %u", + nMaxBytes, samplesHave, bytesBuffer.size()); + } + + return 0; + } + + samplesHave -= nMaxBytes/2; + // qDebug("MorseDecoderWorker::processBuffer::cbWaveformInp: samplesTotal: %u samplesHave: %u nMaxBytes: %u", + // samplesTotal, samplesHave, nMaxBytes); + memcpy(data, bytesBuffer.data() + (samplesTotal - samplesHave)*2, nMaxBytes); + return (int) nMaxBytes; + }; + + bool result = m_ggMorse->decode(cbWaveformInp); + + if (result) + { + GGMorse::TxRx dst; + m_ggMorse->takeRxData(dst); + QString text; + std::for_each( + dst.begin(), + dst.end(), + [&](const uint8_t c) { text.append(c); } + ); + + const GGMorse::Statistics& stats = m_ggMorse->getStatistics(); + m_pitchHz = stats.estimatedPitch_Hz; + m_speedWPM = stats.estimatedSpeed_wpm; + + if (m_msgQueueToFeature) + { + MorseDecoder::MsgReportText *msg = MorseDecoder::MsgReportText::create(text); + msg->m_costFunction = stats.costFunction; + msg->m_estimatedPitchHz = m_settings.m_auto ? stats.estimatedPitch_Hz : m_pitchHz; + msg->m_estimatedSpeedWPM = m_settings.m_auto ? stats.estimatedSpeed_wpm : m_speedWPM; + msg->m_signalThreshold = stats.signalThreshold; + m_msgQueueToFeature->push(msg); + } } - m_nbBytes = nbBytes; - int countSamples = (end - begin) / nbBytes; - - if (countSamples > m_sampleBufferSize) - { - m_sampleBuffer.resize(countSamples); - m_sampleBufferSize = countSamples; - } - - // TODO - // for (int i = 0; i < countSamples; i++) { - // processSample(dataType, begin, countSamples, i); - // } + return bytesLeft; } void MorseDecoderWorker::handleInputMessages() @@ -120,7 +218,7 @@ bool MorseDecoderWorker::handleMessage(const Message& cmd) MsgConnectFifo& msg = (MsgConnectFifo&) cmd; m_dataFifo = msg.getFifo(); bool doConnect = msg.getConnect(); - qDebug("DemodAnalyzerWorker::handleMessage: MsgConnectFifo: %s", (doConnect ? "connect" : "disconnect")); + qDebug("MorseDecoderWorker::handleMessage: MsgConnectFifo: %s", (doConnect ? "connect" : "disconnect")); if (doConnect) { QObject::connect( @@ -153,6 +251,25 @@ void MorseDecoderWorker::applySettings(const MorseDecoderSettings& settings, con { qDebug() << "MorseDecoderWorker::applySettings:" << settings.getDebugString(settingsKeys, force) << force; + if (settingsKeys.contains("auto") || force) + { + auto parametersDecode = m_ggMorse->getDefaultParametersDecode(); + parametersDecode.applyFilterHighPass = false; + + if (settings.m_auto) + { + parametersDecode.frequency_hz = -1.0f; // auto + parametersDecode.speed_wpm = -1.0f; // auto + } + else + { + parametersDecode.frequency_hz = m_pitchHz; + parametersDecode.speed_wpm = m_speedWPM; + } + + m_ggMorse->setParametersDecode(parametersDecode); + } + if (force) { m_settings = settings; } else { @@ -163,7 +280,16 @@ void MorseDecoderWorker::applySettings(const MorseDecoderSettings& settings, con void MorseDecoderWorker::applySampleRate(int sampleRate) { + QMutexLocker mutexLocker(&m_mutex); m_sinkSampleRate = sampleRate; + m_ggMorseParameters->sampleRateInp = sampleRate; + int ggMorseBlockSize = (sampleRate / GGMorse::kBaseSampleRate)*GGMorse::kDefaultSamplesPerFrame; + // m_bytesBufferSize = (GGMorse::kBaseSampleRate/GGMorse::kDefaultSamplesPerFrame)*ggMorseBlockSize*10; // ~10s + m_bytesBufferSize = sampleRate*10 + ggMorseBlockSize; + m_bytesBuffer.resize(m_bytesBufferSize); + m_bytesBufferCount = 0; + qDebug("MorseDecoderWorker::applySampleRate: m_sinkSampleRate: %d ggMorseBlockSize: %d m_bytesBufferSize: %d", + m_sinkSampleRate, ggMorseBlockSize, m_bytesBufferSize); } void MorseDecoderWorker::handleData() diff --git a/plugins/feature/morsedecoder/morsedecoderworker.h b/plugins/feature/morsedecoder/morsedecoderworker.h index 67cb614eb..28cb0c4dd 100644 --- a/plugins/feature/morsedecoder/morsedecoderworker.h +++ b/plugins/feature/morsedecoder/morsedecoderworker.h @@ -20,6 +20,8 @@ #include +#include "ggmorse/ggmorse.h" + #include #include #include @@ -31,7 +33,6 @@ #include "morsedecodersettings.h" - class MorseDecoderWorker : public QObject { Q_OBJECT public: @@ -100,10 +101,16 @@ private: MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object MorseDecoderSettings m_settings; double m_magsq; - SampleVector m_sampleBuffer; - int m_sampleBufferSize; - int m_nbBytes; + QByteArray m_bytesBuffer; + int m_bytesBufferSize; + int m_bytesBufferCount; + QByteArray m_convBuffer; QRecursiveMutex m_mutex; + GGMorse::Parameters *m_ggMorseParameters; + GGMorse *m_ggMorse; + bool m_auto; + float m_pitchHz; + float m_speedWPM; void feedPart( const QByteArray::const_iterator& begin, @@ -112,6 +119,31 @@ private: ); bool handleMessage(const Message& cmd); + int processBuffer(QByteArray& bytesBuffer); //!< return the number of bytes left + + // inline void processSample( + // DataFifo::DataType dataType, + // const QByteArray::const_iterator& begin, + // int nbBytesPerSample, + // int i + // ) + // { + // int16_t *s = (int16_t*) begin + (i*nbBytesPerSample); + + // switch(dataType) + // { + // case DataFifo::DataTypeI16: { + // m_sampleBuffer[i] = *s; + // } + // break; + // case DataFifo::DataTypeCI16: { + // int32_t re = s[2*i]; + // int32_t im = s[2*i+1]; + // m_sampleBuffer[i] = (int16_t) ((re+im) / 2); + // } + // break; + // } + // } private slots: void handleInputMessages();