1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 17:58:43 -05:00

Make a dedicated CW transition smoothing class

This commit is contained in:
f4exb 2016-12-14 22:48:39 +01:00
parent 599ff3d672
commit 98b9e20392
4 changed files with 104 additions and 58 deletions

View File

@ -52,12 +52,7 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) :
m_afInput(SSBModInputNone), m_afInput(SSBModInputNone),
m_levelCalcCount(0), m_levelCalcCount(0),
m_peakLevel(0.0f), m_peakLevel(0.0f),
m_levelSum(0.0f), m_levelSum(0.0f)
m_fadeInCounter(0),
m_fadeOutCounter(0),
m_nbFadeSamples(96),
m_fadeInSamples(0),
m_fadeOutSamples(0)
{ {
setObjectName("SSBMod"); setObjectName("SSBMod");
@ -98,7 +93,7 @@ SSBMod::SSBMod(BasebandSampleSink* sampleSink) :
m_cwKeyer.setWPM(13); m_cwKeyer.setWPM(13);
m_cwKeyer.setMode(CWKeyer::CWNone); m_cwKeyer.setMode(CWKeyer::CWNone);
makeFadeSamples(); m_cwSmoother.setNbFadeSamples(96); // 2 ms at 48 kHz
apply(); apply();
} }
@ -120,9 +115,6 @@ SSBMod::~SSBMod()
delete m_DSBFilterBuffer; delete m_DSBFilterBuffer;
} }
delete[] m_fadeInSamples;
delete[] m_fadeOutSamples;
DSPEngine::instance()->removeAudioSource(&m_audioFifo); DSPEngine::instance()->removeAudioSource(&m_audioFifo);
} }
@ -314,17 +306,7 @@ void SSBMod::pullAF(Complex& sample)
if (m_cwKeyer.getSample()) if (m_cwKeyer.getSample())
{ {
m_fadeOutCounter = 0; m_cwSmoother.getFadeSample(true, fadeFactor);
if (m_fadeInCounter < m_nbFadeSamples)
{
fadeFactor = m_fadeInSamples[m_fadeInCounter];
m_fadeInCounter++;
}
else
{
fadeFactor = 1.0f;
}
if (m_running.m_dsb) if (m_running.m_dsb)
{ {
@ -343,13 +325,8 @@ void SSBMod::pullAF(Complex& sample)
} }
else else
{ {
m_fadeInCounter = 0; if (m_cwSmoother.getFadeSample(false, fadeFactor))
if (m_fadeOutCounter < m_nbFadeSamples)
{ {
fadeFactor = m_fadeOutSamples[m_fadeOutCounter];
m_fadeOutCounter++;
if (m_running.m_dsb) if (m_running.m_dsb)
{ {
Real t = m_toneNco.next() * fadeFactor; 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) void SSBMod::calculateLevel(Complex& sample)
{ {
Real t = sample.real(); // TODO: possibly adjust depending on sample type Real t = sample.real(); // TODO: possibly adjust depending on sample type
@ -720,8 +674,7 @@ void SSBMod::apply()
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
m_cwKeyer.setSampleRate(m_config.m_audioSampleRate); m_cwKeyer.setSampleRate(m_config.m_audioSampleRate);
m_nbFadeSamples = m_config.m_audioSampleRate / 500; // 2ms m_cwSmoother.setNbFadeSamples(m_config.m_audioSampleRate / 500); // 2 ms
makeFadeSamples();
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }

View File

@ -383,11 +383,7 @@ private:
Real m_peakLevel; Real m_peakLevel;
Real m_levelSum; Real m_levelSum;
CWKeyer m_cwKeyer; CWKeyer m_cwKeyer;
int m_fadeInCounter; CWSmoother m_cwSmoother;
int m_fadeOutCounter;
int m_nbFadeSamples;
Real *m_fadeInSamples;
Real *m_fadeOutSamples;
static const int m_levelNbSamples; static const int m_levelNbSamples;
@ -395,7 +391,6 @@ private:
void pullAF(Complex& sample); void pullAF(Complex& sample);
void calculateLevel(Complex& sample); void calculateLevel(Complex& sample);
void modulateSample(); void modulateSample();
void makeFadeSamples();
void openFileStream(); void openFileStream();
void seekFileStream(int seekPercentage); void seekFileStream(int seekPercentage);
}; };

View File

@ -451,3 +451,82 @@ bool CWKeyer::eom()
{ {
return !(m_textPointer < m_text.length()); 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;
}
}
}

View File

@ -99,6 +99,25 @@ private:
void nextStateText(); 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_ */ #endif /* SDRBASE_DSP_CWKEYER_H_ */