From 98b9e203927560ba408ea03ea6757071656ac9e4 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 14 Dec 2016 22:48:39 +0100 Subject: [PATCH] Make a dedicated CW transition smoothing class --- plugins/channeltx/modssb/ssbmod.cpp | 57 ++------------------- plugins/channeltx/modssb/ssbmod.h | 7 +-- sdrbase/dsp/cwkeyer.cpp | 79 +++++++++++++++++++++++++++++ sdrbase/dsp/cwkeyer.h | 19 +++++++ 4 files changed, 104 insertions(+), 58 deletions(-) diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index c674bcb73..2f7dc15b0 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -52,12 +52,7 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) : m_afInput(SSBModInputNone), m_levelCalcCount(0), m_peakLevel(0.0f), - m_levelSum(0.0f), - m_fadeInCounter(0), - m_fadeOutCounter(0), - m_nbFadeSamples(96), - m_fadeInSamples(0), - m_fadeOutSamples(0) + m_levelSum(0.0f) { setObjectName("SSBMod"); @@ -98,7 +93,7 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) : m_cwKeyer.setWPM(13); m_cwKeyer.setMode(CWKeyer::CWNone); - makeFadeSamples(); + m_cwSmoother.setNbFadeSamples(96); // 2 ms at 48 kHz apply(); } @@ -120,9 +115,6 @@ SSBMod::~SSBMod() delete m_DSBFilterBuffer; } - delete[] m_fadeInSamples; - delete[] m_fadeOutSamples; - DSPEngine::instance()->removeAudioSource(&m_audioFifo); } @@ -314,17 +306,7 @@ void SSBMod::pullAF(Complex& sample) if (m_cwKeyer.getSample()) { - m_fadeOutCounter = 0; - - if (m_fadeInCounter < m_nbFadeSamples) - { - fadeFactor = m_fadeInSamples[m_fadeInCounter]; - m_fadeInCounter++; - } - else - { - fadeFactor = 1.0f; - } + m_cwSmoother.getFadeSample(true, fadeFactor); if (m_running.m_dsb) { @@ -343,13 +325,8 @@ void SSBMod::pullAF(Complex& sample) } else { - m_fadeInCounter = 0; - - if (m_fadeOutCounter < m_nbFadeSamples) + if (m_cwSmoother.getFadeSample(false, fadeFactor)) { - fadeFactor = m_fadeOutSamples[m_fadeOutCounter]; - m_fadeOutCounter++; - if (m_running.m_dsb) { Real t = m_toneNco.next() * fadeFactor; @@ -502,29 +479,6 @@ void SSBMod::pullAF(Complex& sample) } } -void SSBMod::makeFadeSamples() -{ - if (m_fadeInSamples) { - delete[] m_fadeInSamples; - } - - if (m_fadeOutSamples) { - delete[] m_fadeOutSamples; - } - - m_fadeInSamples = new Real[m_nbFadeSamples]; - m_fadeOutSamples = new Real[m_nbFadeSamples]; - - for (int i = 0; i < m_nbFadeSamples; i++) - { - m_fadeInSamples[i] = sin((i/ (Real) m_nbFadeSamples) * M_PI_2); - m_fadeOutSamples[i] = cos((i/ (Real) m_nbFadeSamples) * M_PI_2); - } - - m_fadeInCounter = 0; - m_fadeOutCounter = 0; -} - void SSBMod::calculateLevel(Complex& sample) { Real t = sample.real(); // TODO: possibly adjust depending on sample type @@ -720,8 +674,7 @@ void SSBMod::apply() { m_settingsMutex.lock(); m_cwKeyer.setSampleRate(m_config.m_audioSampleRate); - m_nbFadeSamples = m_config.m_audioSampleRate / 500; // 2ms - makeFadeSamples(); + m_cwSmoother.setNbFadeSamples(m_config.m_audioSampleRate / 500); // 2 ms m_settingsMutex.unlock(); } diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index f8ce91cd7..53f18d5ad 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -383,11 +383,7 @@ private: Real m_peakLevel; Real m_levelSum; CWKeyer m_cwKeyer; - int m_fadeInCounter; - int m_fadeOutCounter; - int m_nbFadeSamples; - Real *m_fadeInSamples; - Real *m_fadeOutSamples; + CWSmoother m_cwSmoother; static const int m_levelNbSamples; @@ -395,7 +391,6 @@ private: void pullAF(Complex& sample); void calculateLevel(Complex& sample); void modulateSample(); - void makeFadeSamples(); void openFileStream(); void seekFileStream(int seekPercentage); }; diff --git a/sdrbase/dsp/cwkeyer.cpp b/sdrbase/dsp/cwkeyer.cpp index 2e51183ed..8ea6f95e2 100644 --- a/sdrbase/dsp/cwkeyer.cpp +++ b/sdrbase/dsp/cwkeyer.cpp @@ -451,3 +451,82 @@ bool CWKeyer::eom() { return !(m_textPointer < m_text.length()); } + +CWSmoother::CWSmoother() : + m_fadeInCounter(0), + m_fadeOutCounter(0), + m_nbFadeSamples(0), + m_fadeInSamples(0), + m_fadeOutSamples(0) +{ + setNbFadeSamples(96); // default is 2ms at 48 kHz sample rate +} + +CWSmoother::~CWSmoother() +{ + delete[] m_fadeInSamples; + delete[] m_fadeOutSamples; +} + +void CWSmoother::setNbFadeSamples(unsigned int nbFadeSamples) +{ + if (nbFadeSamples != m_nbFadeSamples) + { + QMutexLocker mutexLocker(&m_mutex); + + m_nbFadeSamples = nbFadeSamples; + + if (m_fadeInSamples) delete[] m_fadeInSamples; + if (m_fadeOutSamples) delete[] m_fadeOutSamples; + + m_fadeInSamples = new float[m_nbFadeSamples]; + m_fadeOutSamples = new float[m_nbFadeSamples]; + + for (int i = 0; i < m_nbFadeSamples; i++) + { + m_fadeInSamples[i] = sin((i/ (float) m_nbFadeSamples) * M_PI_2); + m_fadeOutSamples[i] = cos((i/ (float) m_nbFadeSamples) * M_PI_2); + } + + m_fadeInCounter = 0; + m_fadeOutCounter = 0; + } +} + +bool CWSmoother::getFadeSample(bool on, float& sample) +{ + QMutexLocker mutexLocker(&m_mutex); + + if (on) + { + m_fadeOutCounter = 0; + + if (m_fadeInCounter < m_nbFadeSamples) + { + sample = m_fadeInSamples[m_fadeInCounter]; + m_fadeInCounter++; + return true; + } + else + { + sample = 1.0f; + return false; + } + } + else + { + m_fadeInCounter = 0; + + if (m_fadeOutCounter < m_nbFadeSamples) + { + sample = m_fadeOutSamples[m_fadeOutCounter]; + m_fadeOutCounter++; + return true; + } + else + { + sample = 0.0f; + return false; + } + } +} diff --git a/sdrbase/dsp/cwkeyer.h b/sdrbase/dsp/cwkeyer.h index 113b16f85..7fcca31b0 100644 --- a/sdrbase/dsp/cwkeyer.h +++ b/sdrbase/dsp/cwkeyer.h @@ -99,6 +99,25 @@ private: void nextStateText(); }; +/** + * Ancillary class to smooth out CW transitions with a sine shape + */ +class CWSmoother +{ +public: + CWSmoother(); + ~CWSmoother(); + void setNbFadeSamples(unsigned int nbFadeSamples); + bool getFadeSample(bool on, float& sample); + +private: + QMutex m_mutex; + int m_fadeInCounter; + int m_fadeOutCounter; + unsigned int m_nbFadeSamples; + float *m_fadeInSamples; + float *m_fadeOutSamples; +}; #endif /* SDRBASE_DSP_CWKEYER_H_ */