diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 4923f1993..8fdda4c9d 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -67,6 +67,7 @@ NFMMod::NFMMod() : m_magsq = 0.0; m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate); + m_ctcssNco.setFreq(88.5, m_config.m_audioSampleRate); DSPEngine::instance()->addAudioSource(&m_audioFifo); // CW keyer @@ -88,9 +89,19 @@ void NFMMod::configure(MessageQueue* messageQueue, float toneFrequency, float volumeFactor, bool audioMute, - bool playLoop) + bool playLoop, + bool ctcssOn, + float ctcssFrequency) { - Message* cmd = MsgConfigureNFMMod::create(rfBandwidth, afBandwidth, fmDeviation, toneFrequency, volumeFactor, audioMute, playLoop); + Message* cmd = MsgConfigureNFMMod::create(rfBandwidth, + afBandwidth, + fmDeviation, + toneFrequency, + volumeFactor, + audioMute, + playLoop, + ctcssOn, + ctcssFrequency); messageQueue->push(cmd); } @@ -140,10 +151,18 @@ void NFMMod::modulateSample() pullAF(t); calculateLevel(t); - // 378 = 302 * 1.25; 302 = number of filter taps (established experimentally) - m_modPhasor += (m_running.m_fmDeviation / (float) m_running.m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 378.0f); - m_modSample.real(cos(m_modPhasor) * 32678.0f); - m_modSample.imag(sin(m_modPhasor) * 32678.0f); + if (m_running.m_ctcssOn) + { + m_modPhasor += (m_running.m_fmDeviation / (float) m_running.m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 378.0f * m_ctcssNco.next()) * (M_PI / 378.0f); + } + else + { + // 378 = 302 * 1.25; 302 = number of filter taps (established experimentally) + m_modPhasor += (m_running.m_fmDeviation / (float) m_running.m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 378.0f); + } + + m_modSample.real(cos(m_modPhasor) * 29204.0f); // -1 dB + m_modSample.imag(sin(m_modPhasor) * 29204.0f); } void NFMMod::pullAF(Real& sample) @@ -275,6 +294,8 @@ bool NFMMod::handleMessage(const Message& cmd) m_config.m_volumeFactor = cfg.getVolumeFactor(); m_config.m_audioMute = cfg.getAudioMute(); m_config.m_playLoop = cfg.getPlayLoop(); + m_config.m_ctcssOn = cfg.getCTCSSOn(); + m_config.m_ctcssFrequency = cfg.getCTCSSFrequency(); apply(); @@ -285,7 +306,9 @@ bool NFMMod::handleMessage(const Message& cmd) << " m_toneFrequency: " << m_config.m_toneFrequency << " m_volumeFactor: " << m_config.m_volumeFactor << " m_audioMute: " << m_config.m_audioMute - << " m_playLoop: " << m_config.m_playLoop; + << " m_playLoop: " << m_config.m_playLoop + << " m_ctcssOn: " << m_config.m_ctcssOn + << " m_ctcssFrequency: " << m_config.m_ctcssFrequency; return true; } @@ -378,6 +401,14 @@ void NFMMod::apply() m_cwSmoother.setNbFadeSamples(m_config.m_audioSampleRate / 250); // 4 ms } + if ((m_config.m_ctcssFrequency != m_running.m_ctcssFrequency) || + (m_config.m_audioSampleRate != m_running.m_audioSampleRate)) + { + m_settingsMutex.lock(); + m_ctcssNco.setFreq(m_config.m_ctcssFrequency, m_config.m_audioSampleRate); + m_settingsMutex.unlock(); + } + m_running.m_outputSampleRate = m_config.m_outputSampleRate; m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset; m_running.m_rfBandwidth = m_config.m_rfBandwidth; @@ -387,6 +418,8 @@ void NFMMod::apply() m_running.m_audioSampleRate = m_config.m_audioSampleRate; m_running.m_audioMute = m_config.m_audioMute; m_running.m_playLoop = m_config.m_playLoop; + m_running.m_ctcssOn = m_config.m_ctcssOn; + m_running.m_ctcssFrequency = m_config.m_ctcssFrequency; } void NFMMod::openFileStream() diff --git a/plugins/channeltx/modnfm/nfmmod.h b/plugins/channeltx/modnfm/nfmmod.h index 9cc54cfa0..7dd3b9375 100644 --- a/plugins/channeltx/modnfm/nfmmod.h +++ b/plugins/channeltx/modnfm/nfmmod.h @@ -24,6 +24,7 @@ #include "dsp/basebandsamplesource.h" #include "dsp/nco.h" +#include "dsp/ncof.h" #include "dsp/interpolator.h" #include "dsp/lowpass.h" #include "dsp/bandpass.h" @@ -184,7 +185,9 @@ public: float toneFrequency, float volumeFactor, bool audioMute, - bool playLoop); + bool playLoop, + bool ctcssOn, + float ctcssFrequency); virtual void pull(Sample& sample); virtual void start(); @@ -218,10 +221,28 @@ private: float getVolumeFactor() const { return m_volumeFactor; } bool getAudioMute() const { return m_audioMute; } bool getPlayLoop() const { return m_playLoop; } + bool getCTCSSOn() const { return m_ctcssOn; } + float getCTCSSFrequency() const { return m_ctcssFrequency; } - static MsgConfigureNFMMod* create(Real rfBandwidth, Real afBandwidth, float fmDeviation, float toneFrequency, float volumeFactor, bool audioMute, bool playLoop) + static MsgConfigureNFMMod* create(Real rfBandwidth, + Real afBandwidth, + float fmDeviation, + float toneFrequency, + float volumeFactor, + bool audioMute, + bool playLoop, + bool ctcssOn, + float ctcssFrequency) { - return new MsgConfigureNFMMod(rfBandwidth, afBandwidth, fmDeviation, toneFrequency, volumeFactor, audioMute, playLoop); + return new MsgConfigureNFMMod(rfBandwidth, + afBandwidth, + fmDeviation, + toneFrequency, + volumeFactor, + audioMute, + playLoop, + ctcssOn, + ctcssFrequency); } private: @@ -232,8 +253,18 @@ private: float m_volumeFactor; bool m_audioMute; bool m_playLoop; + bool m_ctcssOn; + float m_ctcssFrequency; - MsgConfigureNFMMod(Real rfBandwidth, Real afBandwidth, float fmDeviation, float toneFrequency, float volumeFactor, bool audioMute, bool playLoop) : + MsgConfigureNFMMod(Real rfBandwidth, + Real afBandwidth, + float fmDeviation, + float toneFrequency, + float volumeFactor, + bool audioMute, + bool playLoop, + bool ctcssOn, + float ctcssFrequency) : Message(), m_rfBandwidth(rfBandwidth), m_afBandwidth(afBandwidth), @@ -241,7 +272,9 @@ private: m_toneFrequency(toneFrequency), m_volumeFactor(volumeFactor), m_audioMute(audioMute), - m_playLoop(playLoop) + m_playLoop(playLoop), + m_ctcssOn(ctcssOn), + m_ctcssFrequency(ctcssFrequency) { } }; @@ -269,6 +302,8 @@ private: quint32 m_audioSampleRate; bool m_audioMute; bool m_playLoop; + bool m_ctcssOn; + float m_ctcssFrequency; Config() : m_outputSampleRate(-1), @@ -280,7 +315,9 @@ private: m_volumeFactor(1.0f), m_audioSampleRate(0), m_audioMute(false), - m_playLoop(false) + m_playLoop(false), + m_ctcssOn(false), + m_ctcssFrequency(88.5) { } }; @@ -290,7 +327,8 @@ private: Config m_running; NCO m_carrierNco; - NCO m_toneNco; + NCOF m_toneNco; + NCOF m_ctcssNco; float m_modPhasor; //!< baseband modulator phasor Complex m_modSample; Interpolator m_interpolator; diff --git a/plugins/channeltx/modnfm/nfmmodgui.cpp b/plugins/channeltx/modnfm/nfmmodgui.cpp index c2ab2d722..1c8e998f5 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.cpp +++ b/plugins/channeltx/modnfm/nfmmodgui.cpp @@ -330,6 +330,17 @@ void NFMModGUI::on_showFileDialog_clicked(bool checked) } } +void NFMModGUI::on_ctcss_currentIndexChanged(int index) +{ + applySettings(); +} + +void NFMModGUI::on_ctcssOn_toggled(bool checked) +{ + applySettings(); +} + + void NFMModGUI::configureFileName() { qDebug() << "FileSourceGui::configureFileName: " << m_fileName.toStdString().c_str(); @@ -457,7 +468,9 @@ void NFMModGUI::applySettings() ui->toneFrequency->value() * 10.0f, ui->volume->value() / 10.0f, ui->audioMute->isChecked(), - ui->playLoop->isChecked()); + ui->playLoop->isChecked(), + ui->ctcssOn->isChecked(), + m_ctcssTones[ui->ctcss->currentIndex()]); } } diff --git a/plugins/channeltx/modnfm/nfmmodgui.h b/plugins/channeltx/modnfm/nfmmodgui.h index 958e4340a..9dcae122c 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.h +++ b/plugins/channeltx/modnfm/nfmmodgui.h @@ -76,6 +76,9 @@ private slots: void on_navTimeSlider_valueChanged(int value); void on_showFileDialog_clicked(bool checked); + void on_ctcss_currentIndexChanged(int index); + void on_ctcssOn_toggled(bool checked); + void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDoubleClicked();