mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 17:28:50 -05:00
Morse Decoder: basic functionality
This commit is contained in:
parent
4387f54f0d
commit
39bc799509
@ -109,7 +109,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
DataFifo *m_dataFifo;
|
DataFifo *m_dataFifo;
|
||||||
int m_channelSampleRate;
|
|
||||||
int m_sinkSampleRate;
|
int m_sinkSampleRate;
|
||||||
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
||||||
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
|
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
|
||||||
|
@ -18,6 +18,7 @@ set(morsedecoder_HEADERS
|
|||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||||
|
${GGMORSE_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT SERVER_MODE)
|
if(NOT SERVER_MODE)
|
||||||
@ -51,6 +52,7 @@ target_link_libraries(${TARGET_NAME}
|
|||||||
${TARGET_LIB}
|
${TARGET_LIB}
|
||||||
sdrbase
|
sdrbase
|
||||||
${TARGET_LIB_GUI}
|
${TARGET_LIB_GUI}
|
||||||
|
${GGMORSE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
|
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
|
||||||
|
@ -38,6 +38,7 @@ MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgStartStop, Message)
|
|||||||
MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgReportChannels, Message)
|
MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgReportChannels, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgSelectChannel, Message)
|
MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgSelectChannel, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(MorseDecoder::MsgReportSampleRate, 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_featureIdURI = "sdrangel.feature.morsedecoder";
|
||||||
const char* const MorseDecoder::m_featureId = "MorseDecoder";
|
const char* const MorseDecoder::m_featureId = "MorseDecoder";
|
||||||
@ -238,6 +239,26 @@ bool MorseDecoder::handleMessage(const Message& cmd)
|
|||||||
|
|
||||||
return true;
|
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
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -278,6 +299,29 @@ void MorseDecoder::applySettings(const MorseDecoderSettings& settings, const QLi
|
|||||||
m_worker->getInputMessageQueue()->push(msg);
|
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)
|
if (settings.m_useReverseAPI)
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QRecursiveMutex>
|
#include <QRecursiveMutex>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
#include "feature/feature.h"
|
#include "feature/feature.h"
|
||||||
#include "util/message.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);
|
MorseDecoder(WebAPIAdapterInterface *webAPIAdapterInterface);
|
||||||
virtual ~MorseDecoder();
|
virtual ~MorseDecoder();
|
||||||
virtual void destroy() { delete this; }
|
virtual void destroy() { delete this; }
|
||||||
@ -202,6 +227,8 @@ private:
|
|||||||
ChannelAPI *m_selectedChannel;
|
ChannelAPI *m_selectedChannel;
|
||||||
ObjectPipe *m_dataPipe;
|
ObjectPipe *m_dataPipe;
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
|
QFile m_logFile;
|
||||||
|
QTextStream m_logStream;
|
||||||
|
|
||||||
QNetworkAccessManager *m_networkManager;
|
QNetworkAccessManager *m_networkManager;
|
||||||
QNetworkRequest m_networkRequest;
|
QNetworkRequest m_networkRequest;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
#include "feature/featureuiset.h"
|
#include "feature/featureuiset.h"
|
||||||
#include "dsp/spectrumvis.h"
|
#include "dsp/spectrumvis.h"
|
||||||
@ -109,6 +110,12 @@ bool MorseDecoderGUI::handleMessage(const Message& message)
|
|||||||
|
|
||||||
return true;
|
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;
|
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 MorseDecoderGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
||||||
{
|
{
|
||||||
(void) widget;
|
(void) widget;
|
||||||
@ -157,6 +193,7 @@ MorseDecoderGUI::MorseDecoderGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
|
|||||||
m_morseDecoder = reinterpret_cast<MorseDecoder*>(feature);
|
m_morseDecoder = reinterpret_cast<MorseDecoder*>(feature);
|
||||||
m_morseDecoder->setMessageQueueToGUI(&m_inputMessageQueue);
|
m_morseDecoder->setMessageQueueToGUI(&m_inputMessageQueue);
|
||||||
|
|
||||||
|
|
||||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
||||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
|
||||||
@ -199,6 +236,9 @@ void MorseDecoderGUI::displaySettings()
|
|||||||
setTitle(m_settings.m_title);
|
setTitle(m_settings.m_title);
|
||||||
blockApplySettings(true);
|
blockApplySettings(true);
|
||||||
getRollupContents()->restoreState(m_rollupState);
|
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);
|
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()
|
void MorseDecoderGUI::tick()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -353,4 +431,8 @@ void MorseDecoderGUI::makeUIConnections()
|
|||||||
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &MorseDecoderGUI::on_startStop_toggled);
|
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &MorseDecoderGUI::on_startStop_toggled);
|
||||||
QObject::connect(ui->channels, qOverload<int>(&QComboBox::currentIndexChanged), this, &MorseDecoderGUI::on_channels_currentIndexChanged);
|
QObject::connect(ui->channels, qOverload<int>(&QComboBox::currentIndexChanged), this, &MorseDecoderGUI::on_channels_currentIndexChanged);
|
||||||
QObject::connect(ui->channelApply, &QPushButton::clicked, this, &MorseDecoderGUI::on_channelApply_clicked);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,8 @@ private:
|
|||||||
void displaySampleRate(int sampleRate);
|
void displaySampleRate(int sampleRate);
|
||||||
void updateChannelList();
|
void updateChannelList();
|
||||||
bool handleMessage(const Message& message);
|
bool handleMessage(const Message& message);
|
||||||
|
void textReceived(const QString& text);
|
||||||
|
void updateMorseStats(float estPitch, float estWPM, float cost);
|
||||||
void makeUIConnections();
|
void makeUIConnections();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@ -87,6 +89,10 @@ private slots:
|
|||||||
void on_startStop_toggled(bool checked);
|
void on_startStop_toggled(bool checked);
|
||||||
void on_channels_currentIndexChanged(int index);
|
void on_channels_currentIndexChanged(int index);
|
||||||
void on_channelApply_clicked();
|
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 updateStatus();
|
||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>407</width>
|
<width>422</width>
|
||||||
<height>407</height>
|
<height>810</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -18,7 +18,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>407</width>
|
<width>422</width>
|
||||||
<height>407</height>
|
<height>407</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
@ -36,13 +36,13 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>401</width>
|
<width>420</width>
|
||||||
<height>121</height>
|
<height>121</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>401</width>
|
<width>420</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
@ -307,13 +307,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="statLock">
|
<widget class="QToolButton" name="statLock">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@ -332,6 +325,42 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="cLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cost</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="cText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>55</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>3000.000</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="logEnable">
|
<widget class="ButtonSwitch" name="logEnable">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
@ -383,42 +412,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="cLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>C</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="cText">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>55</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>3000.000</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -428,19 +421,22 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>130</y>
|
<y>130</y>
|
||||||
<width>401</width>
|
<width>420</width>
|
||||||
<height>271</height>
|
<height>271</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Morse Text</string>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>420</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTextEdit" name="text"/>
|
<widget class="QTextEdit" name="text"/>
|
||||||
|
@ -51,6 +51,7 @@ void MorseDecoderSettings::resetToDefaults()
|
|||||||
m_udpPort = 9999;
|
m_udpPort = 9999;
|
||||||
m_logFilename = "cw_log.txt";
|
m_logFilename = "cw_log.txt";
|
||||||
m_logEnabled = false;
|
m_logEnabled = false;
|
||||||
|
m_auto = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray MorseDecoderSettings::serialize() const
|
QByteArray MorseDecoderSettings::serialize() const
|
||||||
@ -77,6 +78,7 @@ QByteArray MorseDecoderSettings::serialize() const
|
|||||||
s.writeU32(24, m_udpPort);
|
s.writeU32(24, m_udpPort);
|
||||||
s.writeString(25, m_logFilename);
|
s.writeString(25, m_logFilename);
|
||||||
s.writeBool(26, m_logEnabled);
|
s.writeBool(26, m_logEnabled);
|
||||||
|
s.writeBool(27, m_auto);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -135,6 +137,7 @@ bool MorseDecoderSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
d.readString(25, &m_logFilename, "cw_log.txt");
|
d.readString(25, &m_logFilename, "cw_log.txt");
|
||||||
d.readBool(26, &m_logEnabled, false);
|
d.readBool(26, &m_logEnabled, false);
|
||||||
|
d.readBool(27, &m_auto, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -186,6 +189,15 @@ void MorseDecoderSettings::applySettings(const QStringList& settingsKeys, const
|
|||||||
if (settingsKeys.contains("logFilename")) {
|
if (settingsKeys.contains("logFilename")) {
|
||||||
m_logFilename = settings.m_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
|
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) {
|
if (settingsKeys.contains("logFilename") || force) {
|
||||||
ostr << " m_logFilename: " << m_logFilename.toStdString();
|
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());
|
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;
|
||||||
|
}
|
||||||
|
@ -40,6 +40,7 @@ struct MorseDecoderSettings
|
|||||||
uint16_t m_udpPort;
|
uint16_t m_udpPort;
|
||||||
QString m_logFilename;
|
QString m_logFilename;
|
||||||
bool m_logEnabled;
|
bool m_logEnabled;
|
||||||
|
bool m_auto; //!< Auto pitch and speed
|
||||||
|
|
||||||
MorseDecoderSettings();
|
MorseDecoderSettings();
|
||||||
void resetToDefaults();
|
void resetToDefaults();
|
||||||
@ -50,6 +51,8 @@ struct MorseDecoderSettings
|
|||||||
void applySettings(const QStringList& settingsKeys, const MorseDecoderSettings& settings);
|
void applySettings(const QStringList& settingsKeys, const MorseDecoderSettings& settings);
|
||||||
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
|
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
|
||||||
|
|
||||||
|
static QString formatText(const QString& text);
|
||||||
|
|
||||||
static const QStringList m_channelURIs;
|
static const QStringList m_channelURIs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "dsp/scopevis.h"
|
#include "dsp/scopevis.h"
|
||||||
#include "dsp/datafifo.h"
|
#include "dsp/datafifo.h"
|
||||||
|
|
||||||
|
#include "morsedecoder.h"
|
||||||
#include "morsedecoderworker.h"
|
#include "morsedecoderworker.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(MorseDecoderWorker::MsgConfigureMorseDecoderWorker, Message)
|
MESSAGE_CLASS_DEFINITION(MorseDecoderWorker::MsgConfigureMorseDecoderWorker, Message)
|
||||||
@ -28,15 +29,30 @@ MESSAGE_CLASS_DEFINITION(MorseDecoderWorker::MsgConnectFifo, Message)
|
|||||||
MorseDecoderWorker::MorseDecoderWorker() :
|
MorseDecoderWorker::MorseDecoderWorker() :
|
||||||
m_dataFifo(nullptr),
|
m_dataFifo(nullptr),
|
||||||
m_msgQueueToFeature(nullptr),
|
m_msgQueueToFeature(nullptr),
|
||||||
m_sampleBufferSize(0),
|
m_auto(false),
|
||||||
m_nbBytes(0)
|
m_pitchHz(-1),
|
||||||
|
m_speedWPM(-1)
|
||||||
{
|
{
|
||||||
qDebug("MorseDecoderWorker::MorseDecoderWorker");
|
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()
|
MorseDecoderWorker::~MorseDecoderWorker()
|
||||||
{
|
{
|
||||||
m_inputMessageQueue.clear();
|
m_inputMessageQueue.clear();
|
||||||
|
delete m_ggMorse;
|
||||||
|
delete m_ggMorseParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MorseDecoderWorker::reset()
|
void MorseDecoderWorker::reset()
|
||||||
@ -63,31 +79,113 @@ void MorseDecoderWorker::feedPart(
|
|||||||
DataFifo::DataType dataType
|
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:
|
countBytes /= 2;
|
||||||
nbBytes = 4;
|
|
||||||
break;
|
if (countBytes != m_convBuffer.size()) {
|
||||||
case DataFifo::DataTypeI16:
|
m_convBuffer.resize(countBytes);
|
||||||
default:
|
}
|
||||||
nbBytes = 2;
|
|
||||||
|
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;
|
return bytesLeft;
|
||||||
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);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MorseDecoderWorker::handleInputMessages()
|
void MorseDecoderWorker::handleInputMessages()
|
||||||
@ -120,7 +218,7 @@ bool MorseDecoderWorker::handleMessage(const Message& cmd)
|
|||||||
MsgConnectFifo& msg = (MsgConnectFifo&) cmd;
|
MsgConnectFifo& msg = (MsgConnectFifo&) cmd;
|
||||||
m_dataFifo = msg.getFifo();
|
m_dataFifo = msg.getFifo();
|
||||||
bool doConnect = msg.getConnect();
|
bool doConnect = msg.getConnect();
|
||||||
qDebug("DemodAnalyzerWorker::handleMessage: MsgConnectFifo: %s", (doConnect ? "connect" : "disconnect"));
|
qDebug("MorseDecoderWorker::handleMessage: MsgConnectFifo: %s", (doConnect ? "connect" : "disconnect"));
|
||||||
|
|
||||||
if (doConnect) {
|
if (doConnect) {
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
@ -153,6 +251,25 @@ void MorseDecoderWorker::applySettings(const MorseDecoderSettings& settings, con
|
|||||||
{
|
{
|
||||||
qDebug() << "MorseDecoderWorker::applySettings:" << settings.getDebugString(settingsKeys, force) << force;
|
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) {
|
if (force) {
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
} else {
|
} else {
|
||||||
@ -163,7 +280,16 @@ void MorseDecoderWorker::applySettings(const MorseDecoderSettings& settings, con
|
|||||||
|
|
||||||
void MorseDecoderWorker::applySampleRate(int sampleRate)
|
void MorseDecoderWorker::applySampleRate(int sampleRate)
|
||||||
{
|
{
|
||||||
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
m_sinkSampleRate = sampleRate;
|
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()
|
void MorseDecoderWorker::handleData()
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ggmorse/ggmorse.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QRecursiveMutex>
|
#include <QRecursiveMutex>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
@ -31,7 +33,6 @@
|
|||||||
|
|
||||||
#include "morsedecodersettings.h"
|
#include "morsedecodersettings.h"
|
||||||
|
|
||||||
|
|
||||||
class MorseDecoderWorker : public QObject {
|
class MorseDecoderWorker : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@ -100,10 +101,16 @@ private:
|
|||||||
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
|
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
|
||||||
MorseDecoderSettings m_settings;
|
MorseDecoderSettings m_settings;
|
||||||
double m_magsq;
|
double m_magsq;
|
||||||
SampleVector m_sampleBuffer;
|
QByteArray m_bytesBuffer;
|
||||||
int m_sampleBufferSize;
|
int m_bytesBufferSize;
|
||||||
int m_nbBytes;
|
int m_bytesBufferCount;
|
||||||
|
QByteArray m_convBuffer;
|
||||||
QRecursiveMutex m_mutex;
|
QRecursiveMutex m_mutex;
|
||||||
|
GGMorse::Parameters *m_ggMorseParameters;
|
||||||
|
GGMorse *m_ggMorse;
|
||||||
|
bool m_auto;
|
||||||
|
float m_pitchHz;
|
||||||
|
float m_speedWPM;
|
||||||
|
|
||||||
void feedPart(
|
void feedPart(
|
||||||
const QByteArray::const_iterator& begin,
|
const QByteArray::const_iterator& begin,
|
||||||
@ -112,6 +119,31 @@ private:
|
|||||||
);
|
);
|
||||||
|
|
||||||
bool handleMessage(const Message& cmd);
|
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:
|
private slots:
|
||||||
void handleInputMessages();
|
void handleInputMessages();
|
||||||
|
Loading…
Reference in New Issue
Block a user