kopia lustrzana https://gitlab.com/eliggett/wfview
rodzic
fd6d132fd3
commit
9eb89a9cb1
128
cwsender.cpp
128
cwsender.cpp
|
@ -1,6 +1,8 @@
|
|||
#include "cwsender.h"
|
||||
#include "ui_cwsender.h"
|
||||
|
||||
#include "logcategories.h"
|
||||
|
||||
cwSender::cwSender(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::cwSender)
|
||||
|
@ -16,11 +18,43 @@ cwSender::cwSender(QWidget *parent) :
|
|||
ui->statusbar->setToolTipDuration(3000);
|
||||
this->setToolTipDuration(3000);
|
||||
connect(ui->textToSendEdit->lineEdit(), &QLineEdit::textEdited, this, &cwSender::textChanged);
|
||||
|
||||
toneThread = new QThread(this);
|
||||
toneThread->setObjectName("sidetone()");
|
||||
|
||||
tone = new cwSidetone(sidetoneLevel, ui->wpmSpin->value(),ui->pitchSpin->value(),ui->dashSpin->value(),this);
|
||||
tone->moveToThread(toneThread);
|
||||
toneThread->start();
|
||||
|
||||
connect(toneThread, &QThread::finished,
|
||||
[=]() { tone->deleteLater(); });
|
||||
connect(this, &cwSender::sidetone,
|
||||
[=](const QString& text) { tone->send(text); });
|
||||
connect(this, &cwSender::setKeySpeed,
|
||||
[=](const unsigned char& wpm) { tone->setSpeed(wpm); });
|
||||
connect(this, &cwSender::setDashRatio,
|
||||
[=](const unsigned char& ratio) { tone->setRatio(ratio); });
|
||||
connect(this, &cwSender::setPitch,
|
||||
[=](const unsigned char& pitch) { tone->setFrequency(pitch); });
|
||||
connect(this, &cwSender::setLevel,
|
||||
[=](const unsigned char& level) { tone->setLevel(level); });
|
||||
|
||||
connect( this, SIGNAL( pitchChanged(int) ), ui->pitchSpin, SLOT( setValue(int) ) );
|
||||
connect( this, SIGNAL( dashChanged(int) ), ui->dashSpin, SLOT( setValue(int) ) );
|
||||
connect( this, SIGNAL( wpmChanged(int) ), ui->wpmSpin, SLOT( setValue(int) ) );
|
||||
}
|
||||
|
||||
cwSender::~cwSender()
|
||||
{
|
||||
qDebug(logCW()) << "Running CW Sender destructor.";
|
||||
|
||||
if (toneThread != Q_NULLPTR) {
|
||||
toneThread->quit();
|
||||
toneThread->wait();
|
||||
toneThread = Q_NULLPTR;
|
||||
tone = Q_NULLPTR;
|
||||
}
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
@ -33,32 +67,53 @@ void cwSender::showEvent(QShowEvent *event)
|
|||
|
||||
void cwSender::handleKeySpeed(unsigned char wpm)
|
||||
{
|
||||
if ((wpm >= 6) && (wpm <= 48))
|
||||
if (wpm != ui->wpmSpin->value() && (wpm >= ui->wpmSpin->minimum()) && (wpm <= ui->wpmSpin->maximum()))
|
||||
{
|
||||
ui->wpmSpin->blockSignals(true);
|
||||
ui->wpmSpin->setValue(wpm);
|
||||
emit wpmChanged((int)wpm);
|
||||
ui->wpmSpin->blockSignals(false);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(tone, [=]() {
|
||||
tone->setSpeed(wpm);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setKeySpeed(ratio);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::handleDashRatio(unsigned char ratio)
|
||||
{
|
||||
double calc = double(ratio/10);
|
||||
if ((calc >= 2.8) && (ratio <= 4.5))
|
||||
if (calc != ui->dashSpin->value() && (calc >= ui->dashSpin->minimum()) && (ratio <= ui->dashSpin->maximum()))
|
||||
{
|
||||
ui->dashSpin->blockSignals(true);
|
||||
ui->dashSpin->setValue(calc);
|
||||
emit dashChanged(calc);
|
||||
ui->dashSpin->blockSignals(false);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(tone, [=]() {
|
||||
tone->setRatio(ratio);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setDashRatio(ratio);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::handlePitch(unsigned char pitch) {
|
||||
quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0;
|
||||
if (cwPitch >= 300 && cwPitch <= 900)
|
||||
int cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0;
|
||||
if (cwPitch != ui->pitchSpin->value() && cwPitch >= ui->pitchSpin->minimum() && cwPitch <= ui->pitchSpin->maximum())
|
||||
{
|
||||
ui->pitchSpin->blockSignals(true);
|
||||
ui->pitchSpin->setValue(cwPitch);
|
||||
emit pitchChanged(cwPitch);
|
||||
ui->pitchSpin->blockSignals(false);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(tone, [=]() {
|
||||
tone->setFrequency(pitch);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setPitch(tone);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,12 +143,18 @@ void cwSender::textChanged(QString text)
|
|||
{
|
||||
int toSend = text.mid(0, 30).size();
|
||||
if (toSend > 0) {
|
||||
emit sendCW(text.mid(0, 30));
|
||||
ui->textToSendEdit->clearEditText();
|
||||
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
ui->transcriptText->insertPlainText(text.mid(0, 30).toUpper());
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
|
||||
emit sendCW(text.mid(0, 30));
|
||||
emit sidetone(text.mid(0,30));
|
||||
|
||||
}
|
||||
if( (currentMode != modeCW) && (currentMode != modeCW_R) )
|
||||
{
|
||||
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +164,7 @@ void cwSender::on_sendBtn_clicked()
|
|||
if( (ui->textToSendEdit->currentText().length() > 0) &&
|
||||
(ui->textToSendEdit->currentText().length() <= 30) )
|
||||
{
|
||||
emit sendCW(ui->textToSendEdit->currentText());
|
||||
QString text = ui->textToSendEdit->currentText();
|
||||
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
ui->transcriptText->insertPlainText(ui->textToSendEdit->currentText().toUpper()+"\n");
|
||||
|
@ -122,10 +183,12 @@ void cwSender::on_sendBtn_clicked()
|
|||
|
||||
ui->textToSendEdit->setFocus();
|
||||
ui->statusbar->showMessage("Sending CW", 3000);
|
||||
emit sendCW(text);
|
||||
emit sidetone(text);
|
||||
}
|
||||
if( (currentMode==modeCW) || (currentMode==modeCW_R) )
|
||||
|
||||
if( (currentMode != modeCW) && (currentMode != modeCW_R) )
|
||||
{
|
||||
} else {
|
||||
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
|
||||
}
|
||||
}
|
||||
|
@ -217,6 +280,18 @@ void cwSender::on_macro10btn_clicked()
|
|||
processMacroButton(10, ui->macro10btn);
|
||||
}
|
||||
|
||||
void cwSender::on_sidetoneEnableChk_clicked(bool clicked)
|
||||
{
|
||||
ui->sidetoneLevelSlider->setEnabled(clicked);
|
||||
}
|
||||
|
||||
void cwSender::on_sidetoneLevelSlider_valueChanged(int val)
|
||||
{
|
||||
sidetoneLevel = val;
|
||||
emit setLevel(val);
|
||||
}
|
||||
|
||||
|
||||
void cwSender::processMacroButton(int buttonNumber, QPushButton *btn)
|
||||
{
|
||||
if(ui->macroEditChk->isChecked())
|
||||
|
@ -250,14 +325,15 @@ void cwSender::runMacroButton(int buttonNumber)
|
|||
outText.replace("9", "N");
|
||||
}
|
||||
|
||||
for (int i = 0; i < outText.size(); i = i + 30) {
|
||||
emit sendCW(outText.mid(i,30));
|
||||
}
|
||||
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
ui->transcriptText->insertPlainText(outText.toUpper()+"\n");
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
|
||||
for (int i = 0; i < outText.size(); i = i + 30) {
|
||||
emit sendCW(outText.mid(i,30));
|
||||
emit sidetone(outText.mid(i,30));
|
||||
}
|
||||
|
||||
ui->textToSendEdit->setFocus();
|
||||
|
||||
|
||||
|
@ -332,6 +408,16 @@ bool cwSender::getSendImmediate()
|
|||
return ui->sendImmediateChk->isChecked();
|
||||
}
|
||||
|
||||
bool cwSender::getSidetoneEnable()
|
||||
{
|
||||
return ui->sidetoneEnableChk->isChecked();
|
||||
}
|
||||
|
||||
int cwSender::getSidetoneLevel()
|
||||
{
|
||||
return ui->sidetoneLevelSlider->value();
|
||||
}
|
||||
|
||||
void cwSender::setCutNumbers(bool val)
|
||||
{
|
||||
ui->cutNumbersChk->setChecked(val);
|
||||
|
@ -342,6 +428,16 @@ void cwSender::setSendImmediate(bool val)
|
|||
ui->sendImmediateChk->setChecked(val);
|
||||
}
|
||||
|
||||
void cwSender::setSidetoneEnable(bool val)
|
||||
{
|
||||
ui->sidetoneEnableChk->setChecked(val);
|
||||
}
|
||||
|
||||
void cwSender::setSidetoneLevel(int val)
|
||||
{
|
||||
ui->sidetoneLevelSlider->setValue(val);
|
||||
}
|
||||
|
||||
QStringList cwSender::getMacroText()
|
||||
{
|
||||
// This is for preference saving:
|
||||
|
|
22
cwsender.h
22
cwsender.h
|
@ -6,11 +6,10 @@
|
|||
#include <QFont>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QThread>
|
||||
#include <math.h>
|
||||
#include "cwsidetone.h"
|
||||
#include "wfviewtypes.h"
|
||||
#include "logcategories.h"
|
||||
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class cwSender;
|
||||
|
@ -27,8 +26,12 @@ public:
|
|||
void setMacroText(QStringList macros);
|
||||
void setCutNumbers(bool val);
|
||||
void setSendImmediate(bool val);
|
||||
void setSidetoneEnable(bool val);
|
||||
void setSidetoneLevel(int val);
|
||||
bool getCutNumbers();
|
||||
bool getSendImmediate();
|
||||
bool getSidetoneEnable();
|
||||
int getSidetoneLevel();
|
||||
|
||||
signals:
|
||||
void sendCW(QString cwMessage);
|
||||
|
@ -36,8 +39,13 @@ signals:
|
|||
void setKeySpeed(unsigned char wpm);
|
||||
void setDashRatio(unsigned char ratio);
|
||||
void setPitch(unsigned char pitch);
|
||||
void setLevel(int level);
|
||||
void setBreakInMode(unsigned char b);
|
||||
void getCWSettings();
|
||||
void sidetone(QString text);
|
||||
void pitchChanged(int val);
|
||||
void dashChanged(int val);
|
||||
void wpmChanged(int val);
|
||||
|
||||
public slots:
|
||||
void handleKeySpeed(unsigned char wpm);
|
||||
|
@ -86,16 +94,24 @@ private slots:
|
|||
|
||||
void on_sequenceSpin_valueChanged(int arg1);
|
||||
|
||||
void on_sidetoneEnableChk_clicked(bool clicked);
|
||||
|
||||
void on_sidetoneLevelSlider_valueChanged(int val);
|
||||
|
||||
private:
|
||||
Ui::cwSender *ui;
|
||||
QString macroText[11];
|
||||
int sequenceNumber = 1;
|
||||
int lastSentPos = 0;
|
||||
mode_kind currentMode;
|
||||
int sidetoneLevel=0;
|
||||
void processMacroButton(int buttonNumber, QPushButton *btn);
|
||||
void runMacroButton(int buttonNumber);
|
||||
void editMacroButton(int buttonNumber, QPushButton *btn);
|
||||
void setMacroButtonText(QString btnText, QPushButton *btn);
|
||||
cwSidetone* tone=Q_NULLPTR;
|
||||
QThread* toneThread = Q_NULLPTR;
|
||||
|
||||
};
|
||||
|
||||
#endif // CWSENDER_H
|
||||
|
|
76
cwsender.ui
76
cwsender.ui
|
@ -192,11 +192,56 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="spacerLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopBtn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Stop sending CW</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Local Sidetone Level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sidetoneLevelSlider">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="sidetoneEnableChk">
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
|
@ -214,6 +259,17 @@
|
|||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sendBtn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send</string>
|
||||
</property>
|
||||
|
@ -225,16 +281,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopBtn">
|
||||
<property name="toolTip">
|
||||
<string>Stop sending CW</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="textToSendEdit">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
#include "cwsidetone.h"
|
||||
|
||||
#include "logcategories.h"
|
||||
#include "qapplication.h"
|
||||
|
||||
cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* parent) :
|
||||
parent(parent),
|
||||
volume(level),
|
||||
speed(speed),
|
||||
frequency(freq),
|
||||
ratio(ratio)
|
||||
{
|
||||
|
||||
/*
|
||||
* Characters to match Icom table
|
||||
* Unknown characters will return '?'
|
||||
*/
|
||||
cwTable.clear();
|
||||
cwTable['0'] = "-----";
|
||||
cwTable['1'] = ".----";
|
||||
cwTable['2'] = "..---";
|
||||
cwTable['3'] = "...--";
|
||||
cwTable['4'] = "....-";
|
||||
cwTable['5'] = ".....";
|
||||
cwTable['6'] = "-....";
|
||||
cwTable['7'] = "--...";
|
||||
cwTable['8'] = "---..";
|
||||
cwTable['9'] = "----.";
|
||||
|
||||
cwTable['A'] = ".-";
|
||||
cwTable['B'] = "-...";
|
||||
cwTable['C'] = "-.-.";
|
||||
cwTable['D'] = "-..";
|
||||
cwTable['E'] = ".";
|
||||
cwTable['F'] = "..-.";
|
||||
cwTable['G'] = "--.";
|
||||
cwTable['H'] = "....";
|
||||
cwTable['I'] = "..";
|
||||
cwTable['J'] = ".---";
|
||||
cwTable['K'] = "-.-";
|
||||
cwTable['L'] = ".-..";
|
||||
cwTable['M'] = "--";
|
||||
cwTable['N'] = "-.";
|
||||
cwTable['O'] = "---";
|
||||
cwTable['P'] = ".--.";
|
||||
cwTable['Q'] = "--.-";
|
||||
cwTable['R'] = ".-.";
|
||||
cwTable['S'] = "...";
|
||||
cwTable['T'] = "-";
|
||||
cwTable['U'] = "..-";
|
||||
cwTable['V'] = "...-";
|
||||
cwTable['W'] = ".--";
|
||||
cwTable['X'] = "-..-";
|
||||
cwTable['Y'] = "-.--";
|
||||
cwTable['Z'] = "--..";
|
||||
|
||||
cwTable['/'] = "-..-.";
|
||||
cwTable['?'] = "..--..";
|
||||
cwTable['.'] = ".-.-.-";
|
||||
cwTable['-'] = "-....-";
|
||||
cwTable[','] = "--..--";
|
||||
cwTable[':'] = "---...";
|
||||
cwTable['\''] = ".----.";
|
||||
cwTable['('] = "-.--.-";
|
||||
cwTable[')'] = "-.--.-";
|
||||
cwTable['='] = "-...-";
|
||||
cwTable['+'] = ".-.-.";
|
||||
cwTable['"'] = ".-..-.";
|
||||
|
||||
cwTable[' '] = " ";
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
cwSidetone::~cwSidetone()
|
||||
{
|
||||
output->stop();
|
||||
delete output;
|
||||
}
|
||||
|
||||
void cwSidetone::init()
|
||||
{
|
||||
format.setSampleRate(44100);
|
||||
format.setChannelCount(1);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setCodec("audio/pcm");
|
||||
format.setSampleSize(16);
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice());
|
||||
#else
|
||||
format.setSampleFormat(QAudioFormat::Int16);
|
||||
QAudioDevice device = QMediaDevices::defaultAudioOutput();
|
||||
#endif
|
||||
|
||||
if (!device.isFormatSupported(format)) {
|
||||
qWarning(logCW()) << "Default format not supported, using preferred";
|
||||
format = device.preferredFormat();
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
output = new QAudioOutput(device,format);
|
||||
#else
|
||||
output = new QAudioSink(device,format);
|
||||
#endif
|
||||
output->setVolume((qreal)volume/100.0);
|
||||
}
|
||||
|
||||
void cwSidetone::send(QString text)
|
||||
{
|
||||
text=text.simplified();
|
||||
buffer.clear();
|
||||
QString currentChar;
|
||||
int pos = 0;
|
||||
while (pos < text.size())
|
||||
{
|
||||
QChar ch = text.at(pos).toUpper();
|
||||
if (ch == NULL)
|
||||
{
|
||||
currentChar = cwTable[' '];
|
||||
}
|
||||
else if (this->cwTable.contains(ch))
|
||||
{
|
||||
currentChar = cwTable[ch];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentChar=cwTable['?'];
|
||||
}
|
||||
generateMorse(currentChar);
|
||||
pos++;
|
||||
}
|
||||
outputDevice = output->start();
|
||||
if (outputDevice) {
|
||||
qint64 written = outputDevice->write(buffer);
|
||||
while (written < buffer.size())
|
||||
{
|
||||
written += outputDevice->write(buffer.data()+written, buffer.size() - written);
|
||||
QApplication::processEvents();
|
||||
}
|
||||
}
|
||||
//qInfo(logCW()) << "Sending" << this->currentChar;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
void cwSidetone::generateMorse(QString morse)
|
||||
{
|
||||
|
||||
int dit = int(double(SIDETONE_MULTIPLIER / this->speed * SIDETONE_MULTIPLIER));
|
||||
int dah = int(dit * this->ratio);
|
||||
|
||||
for (int i=0;i<morse.size();i++)
|
||||
{
|
||||
QChar c = morse.at(i);
|
||||
if (c == '-')
|
||||
{
|
||||
buffer.append(generateData(dah,this->frequency));
|
||||
} else if (c == '.')
|
||||
{
|
||||
buffer.append(generateData(dit,this->frequency));
|
||||
} else // Space char
|
||||
{
|
||||
buffer.append(generateData(dah+dit,0));
|
||||
}
|
||||
|
||||
if (i+1<morse.size())
|
||||
{
|
||||
buffer.append(generateData(dit,0));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append(generateData(dah,0)); // inter-character space
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray cwSidetone::generateData(qint64 len, qint64 freq)
|
||||
{
|
||||
QByteArray data;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
const int channels = format.channels();
|
||||
const int channelBytes = format.sampleSize() / 8;
|
||||
#else
|
||||
const int channels = format.channelCount();
|
||||
const int channelBytes = format.bytesPerSample();
|
||||
#endif
|
||||
|
||||
const int sampleRate = format.sampleRate();
|
||||
qint64 length = (sampleRate * channels * channelBytes) * len / 100000;
|
||||
const int sampleBytes = channels * channelBytes;
|
||||
|
||||
length -= length % sampleBytes;
|
||||
Q_UNUSED(sampleBytes) // suppress warning in release builds
|
||||
|
||||
data.resize(length);
|
||||
unsigned char *ptr = reinterpret_cast<unsigned char *>(data.data());
|
||||
int sampleIndex = 0;
|
||||
|
||||
while (length) {
|
||||
const qreal x = qSin(2 * M_PI * freq * qreal(sampleIndex % sampleRate) / sampleRate);
|
||||
for (int i=0; i<channels; ++i) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt)
|
||||
#else
|
||||
if (format.sampleFormat() == QAudioFormat::UInt8)
|
||||
#endif
|
||||
{
|
||||
const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255);
|
||||
*reinterpret_cast<quint8*>(ptr) = value;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
} else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt)
|
||||
#else
|
||||
} else if (format.sampleFormat() == QAudioFormat::Int16)
|
||||
#endif
|
||||
{
|
||||
qint16 value = static_cast<qint16>(x * 32767);
|
||||
qToLittleEndian<qint16>(value, ptr);
|
||||
}
|
||||
|
||||
ptr += channelBytes;
|
||||
length -= channelBytes;
|
||||
}
|
||||
++sampleIndex;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void cwSidetone::setSpeed(unsigned char speed)
|
||||
{
|
||||
this->speed = (int)speed;
|
||||
}
|
||||
|
||||
void cwSidetone::setFrequency(unsigned char frequency)
|
||||
{
|
||||
this->frequency = round((((600.0 / 255.0) * frequency) + 300) / 5.0) * 5.0;
|
||||
}
|
||||
|
||||
void cwSidetone::setRatio(unsigned char ratio)
|
||||
{
|
||||
this->ratio = (double)ratio/10.0;
|
||||
}
|
||||
|
||||
void cwSidetone::setLevel(int level) {
|
||||
volume = level;
|
||||
if (output != Q_NULLPTR) {
|
||||
output->setVolume((qreal)level/100.0);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef CWSIDETONE_H
|
||||
#define CWSIDETONE_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QAudioOutput>
|
||||
#include <QMap>
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioOutput>
|
||||
#else
|
||||
#include <QAudioDevice>
|
||||
#include <QAudioSink>
|
||||
#include <QMediaDevices>
|
||||
#endif
|
||||
|
||||
#include <QtMath>
|
||||
#include <QtEndian>
|
||||
#include <QTimer>
|
||||
|
||||
#define SIDETONE_MULTIPLIER 386.0
|
||||
|
||||
class cwSidetone : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit cwSidetone(int level, int speed, int freq, double ratio, QWidget *parent = 0);
|
||||
~cwSidetone();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
public slots:
|
||||
void send(QString text);
|
||||
void setSpeed(unsigned char speed);
|
||||
void setFrequency(unsigned char frequency);
|
||||
void setRatio(unsigned char ratio);
|
||||
void setLevel(int level);
|
||||
private:
|
||||
void init();
|
||||
|
||||
void generateMorse(QString morse);
|
||||
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;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
QAudioOutput* output = Q_NULLPTR;
|
||||
#else
|
||||
QAudioSink* output = Q_NULLPTR;
|
||||
#endif
|
||||
QIODevice* outputDevice = Q_NULLPTR;
|
||||
};
|
||||
|
||||
#endif // CWSIDETONE_H
|
21
wfmain.cpp
21
wfmain.cpp
|
@ -2439,6 +2439,8 @@ void wfmain::loadSettings()
|
|||
settings->beginGroup("Keyer");
|
||||
cw->setCutNumbers(settings->value("CutNumbers", false).toBool());
|
||||
cw->setSendImmediate(settings->value("SendImmediate", false).toBool());
|
||||
cw->setSidetoneEnable(settings->value("SidetoneEnabled", false).toBool());
|
||||
cw->setSidetoneLevel(settings->value("SidetoneLevel", 0).toInt());
|
||||
int numMemories = settings->beginReadArray("macros");
|
||||
if(numMemories==10)
|
||||
{
|
||||
|
@ -2969,6 +2971,8 @@ void wfmain::saveSettings()
|
|||
settings->beginGroup("Keyer");
|
||||
settings->setValue("CutNumbers", cw->getCutNumbers());
|
||||
settings->setValue("SendImmediate", cw->getSendImmediate());
|
||||
settings->setValue("SidetoneEnabled", cw->getSidetoneEnable());
|
||||
settings->setValue("SidetoneLevel", cw->getSidetoneLevel());
|
||||
QStringList macroList = cw->getMacroText();
|
||||
if(macroList.length() == 10)
|
||||
{
|
||||
|
@ -5695,11 +5699,15 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter)
|
|||
if (currentModeInfo.mk != (mode_kind)mode || currentModeInfo.filter != filter)
|
||||
{
|
||||
|
||||
removePeriodicRapidCmd(cmdGetCwPitch);
|
||||
// Remove all "Slow" commands (they will be added later if needed)
|
||||
removeSlowPeriodicCommand(cmdGetCwPitch);
|
||||
removeSlowPeriodicCommand(cmdGetDashRatio);
|
||||
removeSlowPeriodicCommand(cmdGetKeySpeed);
|
||||
removeSlowPeriodicCommand(cmdGetPassband);
|
||||
removeSlowPeriodicCommand(cmdGetTPBFInner);
|
||||
removeSlowPeriodicCommand(cmdGetTPBFOuter);
|
||||
|
||||
|
||||
quint16 maxPassbandHz = 0;
|
||||
switch ((mode_kind)mode) {
|
||||
case modeFM:
|
||||
|
@ -5714,8 +5722,9 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter)
|
|||
break;
|
||||
case modeCW:
|
||||
case modeCW_R:
|
||||
insertPeriodicRapidCmdUnique(cmdGetCwPitch);
|
||||
issueDelayedCommandUnique(cmdGetCwPitch);
|
||||
insertSlowPeriodicCommand(cmdGetCwPitch,128);
|
||||
insertSlowPeriodicCommand(cmdGetDashRatio,128);
|
||||
insertSlowPeriodicCommand(cmdGetKeySpeed,128);
|
||||
maxPassbandHz = 3600;
|
||||
break;
|
||||
case modeAM:
|
||||
|
@ -5770,9 +5779,9 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter)
|
|||
|
||||
if (currentModeInfo.mk != modeFM)
|
||||
{
|
||||
insertSlowPeriodicCommand(cmdGetPassband, 128);
|
||||
insertSlowPeriodicCommand(cmdGetTPBFInner, 128);
|
||||
insertSlowPeriodicCommand(cmdGetTPBFOuter, 128);
|
||||
insertSlowPeriodicCommand(cmdGetPassband,128);
|
||||
insertSlowPeriodicCommand(cmdGetTPBFInner,128);
|
||||
insertSlowPeriodicCommand(cmdGetTPBFOuter,128);
|
||||
issueDelayedCommandUnique(cmdGetPassband);
|
||||
issueDelayedCommandUnique(cmdGetTPBFInner);
|
||||
issueDelayedCommandUnique(cmdGetTPBFOuter);
|
||||
|
|
|
@ -218,6 +218,7 @@ INCLUDEPATH += resampler
|
|||
|
||||
SOURCES += main.cpp\
|
||||
cwsender.cpp \
|
||||
cwsidetone.cpp \
|
||||
loggingwindow.cpp \
|
||||
wfmain.cpp \
|
||||
commhandler.cpp \
|
||||
|
@ -256,6 +257,7 @@ HEADERS += wfmain.h \
|
|||
colorprefs.h \
|
||||
commhandler.h \
|
||||
cwsender.h \
|
||||
cwsidetone.h \
|
||||
loggingwindow.h \
|
||||
prefs.h \
|
||||
printhex.h \
|
||||
|
|
Ładowanie…
Reference in New Issue