diff --git a/plugins/channeltx/udpsink/udpsink.cpp b/plugins/channeltx/udpsink/udpsink.cpp index 6b64f74dd..aae466f8f 100644 --- a/plugins/channeltx/udpsink/udpsink.cpp +++ b/plugins/channeltx/udpsink/udpsink.cpp @@ -46,15 +46,20 @@ UDPSink::UDPSink(MessageQueue* uiMessageQueue, UDPSinkGUI* udpSinkGUI, BasebandS m_squelchCloseCount(0), m_squelchThreshold(4800), m_modPhasor(0.0f), + m_SSBFilterBufferIndex(0), m_settingsMutex(QMutex::Recursive) { setObjectName("UDPSink"); m_udpHandler.setFeedbackMessageQueue(&m_inputMessageQueue); + m_SSBFilter = new fftfilt(m_config.m_lowCutoff / m_config.m_inputSampleRate, m_config.m_rfBandwidth / m_config.m_inputSampleRate, m_ssbFftLen); + m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size apply(true); } UDPSink::~UDPSink() { + delete[] m_SSBFilterBuffer; + delete m_SSBFilter; } void UDPSink::start() @@ -193,6 +198,45 @@ void UDPSink::modulateSample() m_modSample.imag(0.0f); } } + else if ((m_running.m_sampleFormat == FormatLSBMono) || (m_running.m_sampleFormat == FormatUSBMono)) + { + FixReal t; + Complex c, ci; + fftfilt::cmplx *filtered; + int n_out = 0; + + m_udpHandler.readSample(t); + m_inMovingAverage.feed((t*t)/1073741824.0); + m_inMagsq = m_inMovingAverage.average(); + + calculateSquelch(m_inMagsq); + + if (m_squelchOpen) + { + ci.real((t / 32768.0f) * m_running.m_gain); + ci.imag(0.0f); + + n_out = m_SSBFilter->runSSB(ci, &filtered, (m_running.m_sampleFormat == FormatUSBMono)); + + if (n_out > 0) + { + memcpy((void *) m_SSBFilterBuffer, (const void *) filtered, n_out*sizeof(Complex)); + m_SSBFilterBufferIndex = 0; + } + + c = m_SSBFilterBuffer[m_SSBFilterBufferIndex]; + m_modSample.real(m_SSBFilterBuffer[m_SSBFilterBufferIndex].real() * 32768.0f); + m_modSample.imag(m_SSBFilterBuffer[m_SSBFilterBufferIndex].imag() * 32768.0f); + m_SSBFilterBufferIndex++; + + calculateLevel(m_modSample); + } + else + { + m_modSample.real(0.0f); + m_modSample.imag(0.0f); + } + } else { m_modSample.real(0.0f); @@ -468,6 +512,7 @@ void UDPSink::apply(bool force) m_inMovingAverage.resize(m_config.m_inputSampleRate * 0.01, 1e-10); // 10 ms m_squelchThreshold = m_config.m_inputSampleRate * m_config.m_squelchGate; initSquelch(m_squelchOpen); + m_SSBFilter->create_filter(m_config.m_lowCutoff / m_config.m_inputSampleRate, m_config.m_rfBandwidth / m_config.m_inputSampleRate); m_settingsMutex.unlock(); } diff --git a/plugins/channeltx/udpsink/udpsink.h b/plugins/channeltx/udpsink/udpsink.h index 2814a01b2..5f47f2d09 100644 --- a/plugins/channeltx/udpsink/udpsink.h +++ b/plugins/channeltx/udpsink/udpsink.h @@ -24,6 +24,7 @@ #include "dsp/interpolator.h" #include "dsp/movingaverage.h" #include "dsp/nco.h" +#include "dsp/fftfilt.h" #include "util/message.h" #include "udpsinkudphandler.h" @@ -223,6 +224,7 @@ private: Real m_inputSampleRate; qint64 m_inputFrequencyOffset; Real m_rfBandwidth; + Real m_lowCutoff; int m_fmDeviation; Real m_amModFactor; bool m_channelMute; @@ -241,6 +243,7 @@ private: m_inputSampleRate(48000), m_inputFrequencyOffset(0), m_rfBandwidth(12500), + m_lowCutoff(300), m_fmDeviation(1.0), m_amModFactor(0.95), m_channelMute(false), @@ -292,11 +295,15 @@ private: int m_squelchCloseCount; int m_squelchThreshold; - float m_modPhasor; //!< Phasor for FM modulation + float m_modPhasor; //!< Phasor for FM modulation + fftfilt* m_SSBFilter; //!< Complex filter for SSB modulation + Complex* m_SSBFilterBuffer; + int m_SSBFilterBufferIndex; QMutex m_settingsMutex; static const int m_sampleRateAverageItems = 17; + static const int m_ssbFftLen = 1024; void apply(bool force); void modulateSample(); diff --git a/plugins/channeltx/udpsink/udpsinkgui.cpp b/plugins/channeltx/udpsink/udpsinkgui.cpp index 158407db7..00df4b431 100644 --- a/plugins/channeltx/udpsink/udpsinkgui.cpp +++ b/plugins/channeltx/udpsink/udpsinkgui.cpp @@ -416,6 +416,7 @@ void UDPSinkGUI::applySettings(bool force) force); ui->applyBtn->setEnabled(false); + ui->applyBtn->setStyleSheet("QPushButton { background:rgb(79,79,79); }"); } } @@ -452,36 +453,43 @@ void UDPSinkGUI::on_sampleFormat_currentIndexChanged(int index) } ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_sampleRate_textEdited(const QString& arg1 __attribute__((unused))) { ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_rfBandwidth_textEdited(const QString& arg1 __attribute__((unused))) { ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_fmDeviation_textEdited(const QString& arg1 __attribute__((unused))) { ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_amModPercent_textEdited(const QString& arg1 __attribute__((unused))) { ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_udpAddress_textEdited(const QString& arg1 __attribute__((unused))) { ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_udpPort_textEdited(const QString& arg1 __attribute__((unused))) { ui->applyBtn->setEnabled(true); + ui->applyBtn->setStyleSheet("QPushButton { background-color : green; }"); } void UDPSinkGUI::on_gain_valueChanged(int value)