1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-04 16:01:14 -05:00

Demods : use specific method to apply channelizer sample rate and frequency offset changes. Separate this data from settings

This commit is contained in:
f4exb 2017-12-29 11:04:47 +01:00
parent 906d04dd41
commit d476736487
25 changed files with 386 additions and 332 deletions

View File

@ -39,7 +39,8 @@ const int AMDemod::m_udpBlockSize = 512;
AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) : AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI), ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_absoluteFrequencyOffset(0), m_inputSampleRate(48000),
m_inputFrequencyOffset(0),
m_squelchOpen(false), m_squelchOpen(false),
m_magsqSum(0.0f), m_magsqSum(0.0f),
m_magsqPeak(0.0f), m_magsqPeak(0.0f),
@ -129,9 +130,7 @@ void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector
void AMDemod::start() void AMDemod::start()
{ {
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_settings.m_inputSampleRate qDebug("AMDemod::start");
<< " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset;
m_squelchCount = 0; m_squelchCount = 0;
m_audioFifo.clear(); m_audioFifo.clear();
} }
@ -146,16 +145,11 @@ bool AMDemod::handleMessage(const Message& cmd)
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
AMDemodSettings settings = m_settings;
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
applySettings(settings);
qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:" qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate << " inputSampleRate: " << notif.getSampleRate()
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset; << " inputFrequencyOffset: " << notif.getFrequencyOffset();
applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
return true; return true;
} }
@ -163,39 +157,22 @@ bool AMDemod::handleMessage(const Message& cmd)
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
qDebug() << "AMDemod::handleMessage: MsgConfigureChannelizer:" qDebug() << "AMDemod::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate() << " sampleRate: " << cfg.getSampleRate()
<< " inputFrequencyOffset: " << cfg.getCenterFrequency(); << " inputFrequencyOffset: " << cfg.getCenterFrequency();
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
return true; return true;
} }
else if (MsgConfigureAMDemod::match(cmd)) else if (MsgConfigureAMDemod::match(cmd))
{ {
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd; MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod";
AMDemodSettings settings = cfg.getSettings(); applySettings(cfg.getSettings(), cfg.getForce());
// These settings are set with DownChannelizer::MsgChannelizerNotification
m_absoluteFrequencyOffset = settings.m_inputFrequencyOffset;
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
applySettings(settings, cfg.getForce());
qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:"
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioMute: " << settings.m_audioMute
<< " m_bandpassEnable: " << settings.m_bandpassEnable
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << cfg.getForce();
return true; return true;
} }
@ -205,23 +182,53 @@ bool AMDemod::handleMessage(const Message& cmd)
} }
} }
void AMDemod::applySettings(const AMDemodSettings& settings, bool force) void AMDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset)
{ {
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || qDebug() << "AMDemod::applyChannelSettings:"
(m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force) << " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset;
if ((m_inputFrequencyOffset != inputFrequencyOffset) ||
(m_inputSampleRate != inputSampleRate))
{ {
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate); m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
} }
if((m_settings.m_inputSampleRate != settings.m_inputSampleRate) || if (m_inputSampleRate != inputSampleRate)
(m_settings.m_rfBandwidth != settings.m_rfBandwidth) || {
m_settingsMutex.lock();
m_interpolator.create(16, m_inputSampleRate, m_settings.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_settingsMutex.unlock();
}
m_inputSampleRate = inputSampleRate;
m_inputFrequencyOffset = inputFrequencyOffset;
}
void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
{
qDebug() << "AMDemod::applySettings: MsgConfigureAMDemod:"
<< " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioMute: " << settings.m_audioMute
<< " m_bandpassEnable: " << settings.m_bandpassEnable
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << force;
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
(m_settings.m_audioSampleRate != settings.m_audioSampleRate) || (m_settings.m_audioSampleRate != settings.m_audioSampleRate) ||
(m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force) (m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force)
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.2f); m_interpolator.create(16, m_inputSampleRate, settings.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; m_interpolatorDistance = (Real) m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_bandpass.create(301, settings.m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f); m_bandpass.create(301, settings.m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }

View File

@ -126,7 +126,8 @@ private:
ThreadedBasebandSampleSink* m_threadedChannelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DownChannelizer* m_channelizer;
int m_absoluteFrequencyOffset; int m_inputSampleRate;
int m_inputFrequencyOffset;
AMDemodSettings m_settings; AMDemodSettings m_settings;
NCO m_nco; NCO m_nco;
@ -155,7 +156,7 @@ private:
QMutex m_settingsMutex; QMutex m_settingsMutex;
// void apply(bool force = false); void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset);
void applySettings(const AMDemodSettings& settings, bool force = false); void applySettings(const AMDemodSettings& settings, bool force = false);
void processOneSample(Complex &ci) void processOneSample(Complex &ci)

View File

@ -29,7 +29,6 @@ AMDemodSettings::AMDemodSettings() :
void AMDemodSettings::resetToDefaults() void AMDemodSettings::resetToDefaults()
{ {
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_rfBandwidth = 5000; m_rfBandwidth = 5000;
m_squelch = -40.0; m_squelch = -40.0;

View File

@ -23,7 +23,6 @@ class Serializable;
struct AMDemodSettings struct AMDemodSettings
{ {
int m_inputSampleRate;
qint32 m_inputFrequencyOffset; qint32 m_inputFrequencyOffset;
Real m_rfBandwidth; Real m_rfBandwidth;
Real m_squelch; Real m_squelch;

View File

@ -42,7 +42,8 @@ const int BFMDemod::m_udpBlockSize = 512;
BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) : BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI), ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_absoluteFrequencyOffset(0), m_inputSampleRate(384000),
m_inputFrequencyOffset(0),
m_audioFifo(250000), m_audioFifo(250000),
m_settingsMutex(QMutex::Recursive), m_settingsMutex(QMutex::Recursive),
m_pilotPLL(19000/384000, 50/384000, 0.01), m_pilotPLL(19000/384000, 50/384000, 0.01),
@ -311,16 +312,11 @@ bool BFMDemod::handleMessage(const Message& cmd)
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
BFMDemodSettings settings = m_settings;
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
applySettings(settings);
qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification:" qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate << " inputSampleRate: " << notif.getSampleRate()
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset; << " inputFrequencyOffset: " << notif.getFrequencyOffset();
applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
if (getMessageQueueToGUI()) if (getMessageQueueToGUI())
{ {
@ -334,40 +330,21 @@ bool BFMDemod::handleMessage(const Message& cmd)
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug() << "BFMDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
m_channelizer->configure(m_channelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(), cfg.getSampleRate(),
cfg.getCenterFrequency()); cfg.getCenterFrequency());
qDebug() << "BFMDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
return true; return true;
} }
else if (MsgConfigureBFMDemod::match(cmd)) else if (MsgConfigureBFMDemod::match(cmd))
{ {
MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd; MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd;
qDebug() << "BFMDemod::handleMessage: MsgConfigureBFMDemod";
BFMDemodSettings settings = cfg.getSettings(); applySettings(cfg.getSettings(), cfg.getForce());
// These settings are set with DownChannelizer::MsgChannelizerNotification
m_absoluteFrequencyOffset = settings.m_inputFrequencyOffset;
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
applySettings(settings, cfg.getForce());
qDebug() << "BFMDemod::handleMessage: MsgConfigureBFMDemod:"
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioStereo: " << settings.m_audioStereo
<< " m_lsbStereo: " << settings.m_lsbStereo
<< " m_showPilot: " << settings.m_showPilot
<< " m_rdsActive: " << settings.m_rdsActive
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << cfg.getForce();
return true; return true;
} }
@ -386,57 +363,97 @@ bool BFMDemod::handleMessage(const Message& cmd)
} }
} }
void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) void BFMDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset)
{ {
if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) qDebug() << "BFMDemod::applyChannelSettings:"
|| (settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force) << " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset;
if((inputFrequencyOffset != m_inputFrequencyOffset) ||
(inputSampleRate != m_inputSampleRate))
{ {
m_pilotPLL.configure(19000.0/settings.m_inputSampleRate, 50.0/settings.m_inputSampleRate, 0.01); m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
} }
if((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || if (inputSampleRate != m_inputSampleRate)
(settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force)
{ {
qDebug() << "BFMDemod::handleMessage: m_nco.setFreq"; m_pilotPLL.configure(19000.0/inputSampleRate, 50.0/inputSampleRate, 0.01);
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
}
if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) ||
(settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
{
m_settingsMutex.lock(); m_settingsMutex.lock();
qDebug() << "BFMDemod::handleMessage: m_interpolator.create";
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_afBandwidth); m_interpolator.create(16, inputSampleRate, m_settings.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) settings.m_inputSampleRate / settings.m_audioSampleRate; m_interpolatorDistanceRemain = (Real) inputSampleRate / m_settings.m_audioSampleRate;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; m_interpolatorDistance = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_interpolatorStereo.create(16, settings.m_inputSampleRate, settings.m_afBandwidth); m_interpolatorStereo.create(16, inputSampleRate, m_settings.m_afBandwidth);
m_interpolatorStereoDistanceRemain = (Real) settings.m_inputSampleRate / settings.m_audioSampleRate; m_interpolatorStereoDistanceRemain = (Real) inputSampleRate / m_settings.m_audioSampleRate;
m_interpolatorStereoDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; m_interpolatorStereoDistance = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_interpolatorRDS.create(4, settings.m_inputSampleRate, 600.0); m_interpolatorRDS.create(4, inputSampleRate, 600.0);
m_interpolatorRDSDistanceRemain = (Real) settings.m_inputSampleRate / 250000.0; m_interpolatorRDSDistanceRemain = (Real) inputSampleRate / 250000.0;
m_interpolatorRDSDistance = (Real) settings.m_inputSampleRate / 250000.0; m_interpolatorRDSDistance = (Real) inputSampleRate / 250000.0;
Real lowCut = -(m_settings.m_rfBandwidth / 2.0) / inputSampleRate;
Real hiCut = (m_settings.m_rfBandwidth / 2.0) / inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
m_phaseDiscri.setFMScaling(inputSampleRate / m_fmExcursion);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || m_inputSampleRate = inputSampleRate;
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || m_inputFrequencyOffset = inputFrequencyOffset;
}
void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
{
qDebug() << "BFMDemod::applySettings: MsgConfigureBFMDemod:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioStereo: " << settings.m_audioStereo
<< " m_lsbStereo: " << settings.m_lsbStereo
<< " m_showPilot: " << settings.m_showPilot
<< " m_rdsActive: " << settings.m_rdsActive
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << force;
if ((settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force)
{
m_pilotPLL.configure(19000.0/m_inputSampleRate, 50.0/m_inputSampleRate, 0.01);
}
if((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_inputSampleRate, settings.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) m_inputSampleRate / settings.m_audioSampleRate;
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_interpolatorStereo.create(16, m_inputSampleRate, settings.m_afBandwidth);
m_interpolatorStereoDistanceRemain = (Real) m_inputSampleRate / settings.m_audioSampleRate;
m_interpolatorStereoDistance = (Real) m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_interpolatorRDS.create(4, m_inputSampleRate, 600.0);
m_interpolatorRDSDistanceRemain = (Real) m_inputSampleRate / 250000.0;
m_interpolatorRDSDistance = (Real) m_inputSampleRate / 250000.0;
m_settingsMutex.unlock();
}
if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) ||
(settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) (settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
Real lowCut = -(settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate; Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
Real hiCut = (settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate; Real hiCut = (settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut); m_rfFilter->create_filter(lowCut, hiCut);
m_phaseDiscri.setFMScaling(settings.m_inputSampleRate / m_fmExcursion); m_phaseDiscri.setFMScaling(m_inputSampleRate / m_fmExcursion);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
qDebug() << "BFMDemod::handleMessage: m_rfFilter->create_filter: sampleRate: "
<< settings.m_inputSampleRate
<< " lowCut: " << lowCut * settings.m_inputSampleRate
<< " hiCut: " << hiCut * settings.m_inputSampleRate;
} }
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || if ((settings.m_afBandwidth != m_settings.m_afBandwidth) ||

View File

@ -117,7 +117,7 @@ public:
virtual void destroy() { delete this; } virtual void destroy() { delete this; }
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
int getSampleRate() const { return m_settings.m_inputSampleRate; } int getSampleRate() const { return m_inputSampleRate; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
@ -167,8 +167,9 @@ private:
ThreadedBasebandSampleSink* m_threadedChannelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DownChannelizer* m_channelizer;
int m_inputSampleRate;
int m_inputFrequencyOffset;
BFMDemodSettings m_settings; BFMDemodSettings m_settings;
int m_absoluteFrequencyOffset;
NCO m_nco; NCO m_nco;
Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational) Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
@ -224,6 +225,7 @@ private:
static const int m_udpBlockSize; static const int m_udpBlockSize;
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset);
void applySettings(const BFMDemodSettings& settings, bool force = false); void applySettings(const BFMDemodSettings& settings, bool force = false);
}; };

View File

@ -36,7 +36,6 @@ BFMDemodSettings::BFMDemodSettings() :
void BFMDemodSettings::resetToDefaults() void BFMDemodSettings::resetToDefaults()
{ {
m_inputSampleRate = 384000;
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_rfBandwidth = getRFBW(5); m_rfBandwidth = getRFBW(5);
m_afBandwidth = 15000; m_afBandwidth = 15000;

View File

@ -21,7 +21,6 @@ class Serializable;
struct BFMDemodSettings struct BFMDemodSettings
{ {
int m_inputSampleRate;
qint64 m_inputFrequencyOffset; qint64 m_inputFrequencyOffset;
Real m_rfBandwidth; Real m_rfBandwidth;
Real m_afBandwidth; Real m_afBandwidth;

View File

@ -42,7 +42,8 @@ const int DSDDemod::m_udpBlockSize = 512;
DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI), ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_absoluteFrequencyOffset(0), m_inputSampleRate(48000),
m_inputFrequencyOffset(0),
m_interpolatorDistance(0.0f), m_interpolatorDistance(0.0f),
m_interpolatorDistanceRemain(0.0f), m_interpolatorDistanceRemain(0.0f),
m_sampleCount(0), m_sampleCount(0),
@ -325,21 +326,17 @@ bool DSDDemod::handleMessage(const Message& cmd)
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: inputSampleRate: " << notif.getSampleRate()
<< " inputFrequencyOffset: " << notif.getFrequencyOffset();
DSDDemodSettings settings = m_settings; applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
applySettings(settings);
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug("DSDDemod::handleMessage: MsgConfigureChannelizer");
m_channelizer->configure(m_channelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(), cfg.getSampleRate(),
@ -350,17 +347,54 @@ bool DSDDemod::handleMessage(const Message& cmd)
else if (MsgConfigureDSDDemod::match(cmd)) else if (MsgConfigureDSDDemod::match(cmd))
{ {
MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd; MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd;
qDebug("DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth");
DSDDemodSettings settings = cfg.getSettings(); applySettings(cfg.getSettings(), cfg.getForce());
// These settings are set with DownChannelizer::MsgChannelizerNotification return true;
m_absoluteFrequencyOffset = settings.m_inputFrequencyOffset; }
settings.m_inputSampleRate = m_settings.m_inputSampleRate; else if (MsgConfigureMyPosition::match(cmd))
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset; {
MsgConfigureMyPosition& cfg = (MsgConfigureMyPosition&) cmd;
m_dsdDecoder.setMyPoint(cfg.getMyLatitude(), cfg.getMyLongitude());
return true;
}
else
{
return false;
}
}
applySettings(settings, cfg.getForce()); void DSDDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset)
{
qDebug() << "DSDDemod::applyChannelSettings:"
<< " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset;
qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_settings.m_rfBandwidth if ((inputFrequencyOffset != m_inputFrequencyOffset) ||
(inputSampleRate != m_inputSampleRate))
{
m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
}
if (inputSampleRate != m_inputSampleRate)
{
m_settingsMutex.lock();
m_interpolator.create(16, inputSampleRate, (m_settings.m_rfBandwidth) / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_settingsMutex.unlock();
}
m_inputSampleRate = inputSampleRate;
m_inputFrequencyOffset = inputFrequencyOffset;
}
void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force)
{
qDebug() << "DSDDemod::applySettings: "
<< " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << m_settings.m_rfBandwidth
<< " m_fmDeviation: " << m_settings.m_fmDeviation << " m_fmDeviation: " << m_settings.m_fmDeviation
<< " m_demodGain: " << m_settings.m_demodGain << " m_demodGain: " << m_settings.m_demodGain
<< " m_volume: " << m_settings.m_volume << " m_volume: " << m_settings.m_volume
@ -378,37 +412,14 @@ bool DSDDemod::handleMessage(const Message& cmd)
<< " m_udpAddress: " << m_settings.m_udpAddress << " m_udpAddress: " << m_settings.m_udpAddress
<< " m_udpPort: " << m_settings.m_udpPort << " m_udpPort: " << m_settings.m_udpPort
<< " m_highPassFilter: "<< m_settings.m_highPassFilter << " m_highPassFilter: "<< m_settings.m_highPassFilter
<< " force: " << cfg.getForce(); << " force: " << force;
return true; if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
}
else if (MsgConfigureMyPosition::match(cmd))
{
MsgConfigureMyPosition& cfg = (MsgConfigureMyPosition&) cmd;
m_dsdDecoder.setMyPoint(cfg.getMyLatitude(), cfg.getMyLongitude());
return true;
}
else
{
return false;
}
}
void DSDDemod::applySettings(DSDDemodSettings& settings, bool force)
{
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
(settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force)
{
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
}
if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) ||
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
m_interpolator.create(16, settings.m_inputSampleRate, (settings.m_rfBandwidth) / 2.2); m_interpolator.create(16, m_inputSampleRate, (settings.m_rfBandwidth) / 2.2);
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; m_interpolatorDistance = (Real) m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation); m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
@ -458,7 +469,7 @@ void DSDDemod::applySettings(DSDDemodSettings& settings, bool force)
if ((settings.m_udpAddress != m_settings.m_udpAddress) if ((settings.m_udpAddress != m_settings.m_udpAddress)
|| (settings.m_udpPort != m_settings.m_udpPort) || force) || (settings.m_udpPort != m_settings.m_udpPort) || force)
{ {
m_udpBufferAudio->setAddress(settings.m_udpAddress); m_udpBufferAudio->setAddress(const_cast<QString&>(settings.m_udpAddress));
m_udpBufferAudio->setPort(settings.m_udpPort); m_udpBufferAudio->setPort(settings.m_udpPort);
} }

View File

@ -160,8 +160,9 @@ private:
ThreadedBasebandSampleSink* m_threadedChannelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DownChannelizer* m_channelizer;
int m_inputSampleRate;
int m_inputFrequencyOffset;
DSDDemodSettings m_settings; DSDDemodSettings m_settings;
int m_absoluteFrequencyOffset;
NCO m_nco; NCO m_nco;
Interpolator m_interpolator; Interpolator m_interpolator;
@ -201,7 +202,8 @@ private:
static const int m_udpBlockSize; static const int m_udpBlockSize;
void applySettings(DSDDemodSettings& settings, bool force = false); void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset);
void applySettings(const DSDDemodSettings& settings, bool force = false);
}; };
#endif // INCLUDE_DSDDEMOD_H #endif // INCLUDE_DSDDEMOD_H

View File

@ -30,7 +30,6 @@ DSDDemodSettings::DSDDemodSettings() :
void DSDDemodSettings::resetToDefaults() void DSDDemodSettings::resetToDefaults()
{ {
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_rfBandwidth = 12500.0; m_rfBandwidth = 12500.0;
m_fmDeviation = 5000.0; m_fmDeviation = 5000.0;
@ -63,7 +62,6 @@ QByteArray DSDDemodSettings::serialize() const
s.writeS32(3, m_demodGain*100.0); s.writeS32(3, m_demodGain*100.0);
s.writeS32(4, m_fmDeviation/100.0); s.writeS32(4, m_fmDeviation/100.0);
s.writeS32(5, m_squelch*10.0); s.writeS32(5, m_squelch*10.0);
s.writeS32(6, m_inputSampleRate);
s.writeU32(7, m_rgbColor); s.writeU32(7, m_rgbColor);
s.writeS32(8, m_squelchGate); s.writeS32(8, m_squelchGate);
s.writeS32(9, m_volume*10.0); s.writeS32(9, m_volume*10.0);
@ -120,7 +118,6 @@ bool DSDDemodSettings::deserialize(const QByteArray& data)
m_fmDeviation = tmp * 100.0; m_fmDeviation = tmp * 100.0;
d.readS32(5, &tmp, -400); d.readS32(5, &tmp, -400);
m_squelch = tmp / 10.0; m_squelch = tmp / 10.0;
d.readS32(6, &m_inputSampleRate, 96000);
d.readU32(7, &m_rgbColor); d.readU32(7, &m_rgbColor);
d.readS32(8, &m_squelchGate, 5); d.readS32(8, &m_squelchGate, 5);
d.readS32(9, &tmp, 20); d.readS32(9, &tmp, 20);

View File

@ -23,7 +23,6 @@ class Serializable;
struct DSDDemodSettings struct DSDDemodSettings
{ {
int m_inputSampleRate;
qint64 m_inputFrequencyOffset; qint64 m_inputFrequencyOffset;
Real m_rfBandwidth; Real m_rfBandwidth;
Real m_fmDeviation; Real m_fmDeviation;

View File

@ -312,6 +312,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
void NFMDemod::start() void NFMDemod::start()
{ {
qDebug() << "NFMDemod::start"; qDebug() << "NFMDemod::start";
m_squelchCount = 0;
m_audioFifo.clear(); m_audioFifo.clear();
m_phaseDiscri.reset(); m_phaseDiscri.reset();
} }
@ -334,6 +335,7 @@ bool NFMDemod::handleMessage(const Message& cmd)
else if (MsgConfigureChannelizer::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug() << "NFMDemod::handleMessage: MsgConfigureChannelizer:" qDebug() << "NFMDemod::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate() << " sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency(); << " centerFrequency: " << cfg.getCenterFrequency();
@ -347,10 +349,9 @@ bool NFMDemod::handleMessage(const Message& cmd)
else if (MsgConfigureNFMDemod::match(cmd)) else if (MsgConfigureNFMDemod::match(cmd))
{ {
MsgConfigureNFMDemod& cfg = (MsgConfigureNFMDemod&) cmd; MsgConfigureNFMDemod& cfg = (MsgConfigureNFMDemod&) cmd;
NFMDemodSettings settings = cfg.getSettings();
qDebug() << "NFMDemod::handleMessage: MsgConfigureNFMDemod"; qDebug() << "NFMDemod::handleMessage: MsgConfigureNFMDemod";
applySettings(settings, cfg.getForce()); applySettings(cfg.getSettings(), cfg.getForce());
return true; return true;
} }

View File

@ -62,13 +62,13 @@ SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
m_LowCutoff = 300; m_LowCutoff = 300;
m_volume = 2.0; m_volume = 2.0;
m_spanLog2 = 3; m_spanLog2 = 3;
m_sampleRate = 96000; m_inputSampleRate = 48000;
m_absoluteFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_nco.setFreq(m_absoluteFrequencyOffset, m_sampleRate);
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_interpolator.create(16, m_sampleRate, 5000); m_nco.setFreq(m_inputFrequencyOffset, m_inputSampleRate);
m_sampleDistanceRemain = (Real) m_sampleRate / m_audioSampleRate; m_interpolator.create(16, m_inputSampleRate, 5000);
m_sampleDistanceRemain = (Real) m_inputSampleRate / m_audioSampleRate;
m_audioBuffer.resize(1<<9); m_audioBuffer.resize(1<<9);
m_audioBufferFill = 0; m_audioBufferFill = 0;
@ -172,7 +172,7 @@ void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
n_out = SSBFilter->runSSB(ci, &sideband, m_usb); n_out = SSBFilter->runSSB(ci, &sideband, m_usb);
} }
m_sampleDistanceRemain += (Real)m_sampleRate / m_audioSampleRate; m_sampleDistanceRemain += (Real) m_inputSampleRate / m_audioSampleRate;
} }
else else
{ {
@ -297,62 +297,30 @@ bool SSBDemod::handleMessage(const Message& cmd)
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug("SSBDemod::handleMessage: MsgChannelizerNotification: m_sampleRate");
m_settingsMutex.lock(); applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
m_sampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
m_interpolator.create(16, m_sampleRate, m_Bandwidth);
m_sampleDistanceRemain = m_sampleRate / m_audioSampleRate;
m_settingsMutex.unlock();
qDebug() << "SSBDemod::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
<< " frequencyOffset" << notif.getFrequencyOffset();
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug() << "SSBDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
m_channelizer->configure(m_channelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(), cfg.getSampleRate(),
cfg.getCenterFrequency()); cfg.getCenterFrequency());
qDebug() << "SSBDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
return true; return true;
} }
else if (MsgConfigureSSBDemod::match(cmd)) else if (MsgConfigureSSBDemod::match(cmd))
{ {
MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd; MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd;
qDebug("SSBDemod::handleMessage: MsgConfigureSSBDemod");
SSBDemodSettings settings = cfg.getSettings(); applySettings(cfg.getSettings(), cfg.getForce());
// These settings are set with DownChannelizer::MsgChannelizerNotificatione
m_absoluteFrequencyOffset = settings.m_inputFrequencyOffset; // save as absolut frequency shift in baseband
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
applySettings(settings, cfg.getForce());
qDebug() << "SSBDemod::handleMessage: MsgConfigureSSBDemod:"
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_lowCutoff: " << settings.m_lowCutoff
<< " m_volume: " << settings.m_volume
<< " m_spanLog2: " << settings.m_spanLog2
<< " m_audioBinaual: " << settings.m_audioBinaural
<< " m_audioFlipChannels: " << settings.m_audioFlipChannels
<< " m_dsb: " << settings.m_dsb
<< " m_audioMute: " << settings.m_audioMute
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_agcActive: " << settings.m_agc
<< " m_agcClamping: " << settings.m_agcClamping
<< " m_agcTimeLog2: " << settings.m_agcTimeLog2
<< " agcPowerThreshold: " << settings.m_agcPowerThreshold
<< " agcThresholdGate: " << settings.m_agcThresholdGate;
return true; return true;
} }
@ -369,17 +337,49 @@ bool SSBDemod::handleMessage(const Message& cmd)
} }
} }
void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force) void SSBDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset)
{ {
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || qDebug() << "SSBDemod::applyChannelSettings:"
(m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force) << " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset;
if ((m_inputFrequencyOffset != inputFrequencyOffset) ||
(m_inputSampleRate != inputSampleRate))
{ {
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate); m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
} }
if (m_inputSampleRate != inputSampleRate)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_inputSampleRate, m_settings.m_rfBandwidth * 2.0f);
m_settingsMutex.unlock();
}
if((m_settings.m_inputSampleRate != settings.m_inputSampleRate) || m_inputSampleRate = inputSampleRate;
(m_settings.m_rfBandwidth != settings.m_rfBandwidth) || m_inputFrequencyOffset = inputFrequencyOffset;
}
void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
{
qDebug() << "SSBDemod::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_lowCutoff: " << settings.m_lowCutoff
<< " m_volume: " << settings.m_volume
<< " m_spanLog2: " << settings.m_spanLog2
<< " m_audioBinaual: " << settings.m_audioBinaural
<< " m_audioFlipChannels: " << settings.m_audioFlipChannels
<< " m_dsb: " << settings.m_dsb
<< " m_audioMute: " << settings.m_audioMute
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_agcActive: " << settings.m_agc
<< " m_agcClamping: " << settings.m_agcClamping
<< " m_agcTimeLog2: " << settings.m_agcTimeLog2
<< " agcPowerThreshold: " << settings.m_agcPowerThreshold
<< " agcThresholdGate: " << settings.m_agcThresholdGate;
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
(m_settings.m_lowCutoff != settings.m_lowCutoff) || (m_settings.m_lowCutoff != settings.m_lowCutoff) ||
(m_settings.m_audioSampleRate != settings.m_audioSampleRate) || force) (m_settings.m_audioSampleRate != settings.m_audioSampleRate) || force)
{ {
@ -393,8 +393,9 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
band = -band; band = -band;
lowCutoff = -lowCutoff; lowCutoff = -lowCutoff;
m_usb = false; m_usb = false;
} else } else {
m_usb = true; m_usb = true;
}
if (band < 100.0f) if (band < 100.0f)
{ {
@ -406,7 +407,7 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
m_LowCutoff = lowCutoff; m_LowCutoff = lowCutoff;
m_settingsMutex.lock(); m_settingsMutex.lock();
m_interpolator.create(16, m_sampleRate, band * 2.0f); m_interpolator.create(16, m_inputSampleRate, band * 2.0f);
SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate); SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate);
DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate); DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate);
m_settingsMutex.unlock(); m_settingsMutex.unlock();

View File

@ -241,8 +241,8 @@ private:
int m_spanLog2; int m_spanLog2;
fftfilt::cmplx m_sum; fftfilt::cmplx m_sum;
int m_undersampleCount; int m_undersampleCount;
int m_sampleRate; int m_inputSampleRate;
int m_absoluteFrequencyOffset; int m_inputFrequencyOffset;
bool m_audioBinaual; bool m_audioBinaual;
bool m_audioFlipChannels; bool m_audioFlipChannels;
bool m_usb; bool m_usb;
@ -278,6 +278,7 @@ private:
QMutex m_settingsMutex; QMutex m_settingsMutex;
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset);
void applySettings(const SSBDemodSettings& settings, bool force = false); void applySettings(const SSBDemodSettings& settings, bool force = false);
}; };

View File

@ -44,7 +44,6 @@ void SSBDemodSettings::resetToDefaults()
m_lowCutoff = 300; m_lowCutoff = 300;
m_volume = 3.0; m_volume = 3.0;
m_spanLog2 = 3; m_spanLog2 = 3;
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_udpAddress = "127.0.0.1"; m_udpAddress = "127.0.0.1";

View File

@ -23,7 +23,6 @@ class Serializable;
struct SSBDemodSettings struct SSBDemodSettings
{ {
int m_inputSampleRate;
qint32 m_inputFrequencyOffset; qint32 m_inputFrequencyOffset;
quint32 m_audioSampleRate; quint32 m_audioSampleRate;
Real m_rfBandwidth; Real m_rfBandwidth;

View File

@ -40,7 +40,8 @@ const int WFMDemod::m_udpBlockSize = 512;
WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) : WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) :
ChannelSinkAPI(m_channelIdURI), ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_absoluteFrequencyOffset(0), m_inputSampleRate(384000),
m_inputFrequencyOffset(0),
m_squelchOpen(false), m_squelchOpen(false),
m_magsq(0.0f), m_magsq(0.0f),
m_magsqSum(0.0f), m_magsqSum(0.0f),
@ -210,55 +211,32 @@ bool WFMDemod::handleMessage(const Message& cmd)
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "WFMDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << notif.getSampleRate()
<< " m_inputFrequencyOffset: " << notif.getFrequencyOffset();
WFMDemodSettings settings = m_settings; applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
applySettings(settings);
qDebug() << "WFMDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug() << "WFMDemod::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate()
<< " inputFrequencyOffset: " << cfg.getCenterFrequency();
m_channelizer->configure(m_channelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(), cfg.getSampleRate(),
cfg.getCenterFrequency()); cfg.getCenterFrequency());
qDebug() << "WFMDemod::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate()
<< " inputFrequencyOffset: " << cfg.getCenterFrequency();
return true; return true;
} }
else if (MsgConfigureWFMDemod::match(cmd)) else if (MsgConfigureWFMDemod::match(cmd))
{ {
MsgConfigureWFMDemod& cfg = (MsgConfigureWFMDemod&) cmd; MsgConfigureWFMDemod& cfg = (MsgConfigureWFMDemod&) cmd;
qDebug("WFMDemod::handleMessage: MsgConfigureWFMDemod");
WFMDemodSettings settings = cfg.getSettings(); applySettings(cfg.getSettings(), cfg.getForce());
// These settings are set with DownChannelizer::MsgChannelizerNotification
m_absoluteFrequencyOffset = settings.m_inputFrequencyOffset;
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
applySettings(settings, cfg.getForce());
qDebug() << "WFMDemod::handleMessage: MsgConfigureWFMDemod:"
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_afBandwidth: " << settings.m_afBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << cfg.getForce();
return true; return true;
} }
@ -275,30 +253,64 @@ bool WFMDemod::handleMessage(const Message& cmd)
} }
} }
void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force) void WFMDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset)
{ {
if((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || qDebug() << "WFMDemod::applyChannelSettings:"
(settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force) << " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset;
if((inputFrequencyOffset != m_inputFrequencyOffset) ||
(inputSampleRate != m_inputSampleRate))
{ {
qDebug() << "WFMDemod::applySettings: m_nco.setFreq"; m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
} }
if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || if (inputSampleRate != m_inputSampleRate)
(settings.m_audioSampleRate != m_settings.m_audioSampleRate) || {
qDebug() << "WFMDemod::applyChannelSettings: m_interpolator.create";
m_interpolator.create(16, inputSampleRate, m_settings.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
qDebug() << "WFMDemod::applySettings: m_rfFilter->create_filter";
Real lowCut = -(m_settings.m_rfBandwidth / 2.0) / inputSampleRate;
Real hiCut = (m_settings.m_rfBandwidth / 2.0) / inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
m_fmExcursion = m_settings.m_rfBandwidth / (Real) inputSampleRate;
m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion);
qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion);
}
m_inputSampleRate = inputSampleRate;
m_inputFrequencyOffset = inputFrequencyOffset;
}
void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force)
{
qDebug() << "WFMDemod::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_afBandwidth: " << settings.m_afBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << force;
if((settings.m_audioSampleRate != m_settings.m_audioSampleRate) ||
(settings.m_afBandwidth != m_settings.m_afBandwidth) || (settings.m_afBandwidth != m_settings.m_afBandwidth) ||
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
qDebug() << "WFMDemod::applySettings: m_interpolator.create"; qDebug() << "WFMDemod::applySettings: m_interpolator.create";
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_afBandwidth); m_interpolator.create(16, m_inputSampleRate, settings.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; m_interpolatorDistanceRemain = (Real) m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; m_interpolatorDistance = (Real) m_inputSampleRate / (Real) settings.m_audioSampleRate;
qDebug() << "WFMDemod::applySettings: m_rfFilter->create_filter"; qDebug() << "WFMDemod::applySettings: m_rfFilter->create_filter";
Real lowCut = -(settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate; Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
Real hiCut = (settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate; Real hiCut = (settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut); m_rfFilter->create_filter(lowCut, hiCut);
m_fmExcursion = settings.m_rfBandwidth / (Real) settings.m_inputSampleRate; m_fmExcursion = settings.m_rfBandwidth / (Real) m_inputSampleRate;
m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion); m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion);
qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion); qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion);
m_settingsMutex.unlock(); m_settingsMutex.unlock();

View File

@ -132,8 +132,9 @@ private:
ThreadedBasebandSampleSink* m_threadedChannelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DownChannelizer* m_channelizer;
int m_inputSampleRate;
int m_inputFrequencyOffset;
WFMDemodSettings m_settings; WFMDemodSettings m_settings;
int m_absoluteFrequencyOffset;
NCO m_nco; NCO m_nco;
Interpolator m_interpolator; //!< Interpolator between sample rate sent from DSP engine and requested RF bandwidth (rational) Interpolator m_interpolator; //!< Interpolator between sample rate sent from DSP engine and requested RF bandwidth (rational)
@ -166,6 +167,7 @@ private:
static const int m_udpBlockSize; static const int m_udpBlockSize;
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset);
void applySettings(const WFMDemodSettings& settings, bool force = false); void applySettings(const WFMDemodSettings& settings, bool force = false);
}; };

View File

@ -36,7 +36,6 @@ WFMDemodSettings::WFMDemodSettings() :
void WFMDemodSettings::resetToDefaults() void WFMDemodSettings::resetToDefaults()
{ {
m_inputSampleRate = 384000;
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_rfBandwidth = getRFBW(5); m_rfBandwidth = getRFBW(5);
m_afBandwidth = 15000; m_afBandwidth = 15000;

View File

@ -22,7 +22,6 @@ class Serializable;
struct WFMDemodSettings struct WFMDemodSettings
{ {
int m_inputSampleRate;
qint64 m_inputFrequencyOffset; qint64 m_inputFrequencyOffset;
Real m_rfBandwidth; Real m_rfBandwidth;
Real m_afBandwidth; Real m_afBandwidth;

View File

@ -39,7 +39,8 @@ const QString UDPSrc::m_channelId = "UDPSrc";
UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) : UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI), ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_absoluteFrequencyOffset(0), m_inputSampleRate(48000),
m_inputFrequencyOffset(0),
m_outMovingAverage(480, 1e-10), m_outMovingAverage(480, 1e-10),
m_inMovingAverage(480, 1e-10), m_inMovingAverage(480, 1e-10),
m_amMovingAverage(1200, 1e-10), m_amMovingAverage(1200, 1e-10),
@ -64,9 +65,9 @@ UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) :
m_audioBuffer.resize(1<<9); m_audioBuffer.resize(1<<9);
m_audioBufferFill = 0; m_audioBufferFill = 0;
m_nco.setFreq(0, m_settings.m_inputSampleRate); m_nco.setFreq(0, m_inputSampleRate);
m_interpolator.create(16, m_settings.m_inputSampleRate, m_settings.m_rfBandwidth / 2.0); m_interpolator.create(16, m_inputSampleRate, m_settings.m_rfBandwidth / 2.0);
m_sampleDistanceRemain = m_settings.m_inputSampleRate / m_settings.m_outputSampleRate; m_sampleDistanceRemain = m_inputSampleRate / m_settings.m_outputSampleRate;
m_spectrumEnabled = false; m_spectrumEnabled = false;
m_nextSSBId = 0; m_nextSSBId = 0;
m_nextS16leId = 0; m_nextS16leId = 0;
@ -162,7 +163,7 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
Sample ss(ci.real(), ci.imag()); Sample ss(ci.real(), ci.imag());
m_sampleBuffer.push_back(ss); m_sampleBuffer.push_back(ss);
m_sampleDistanceRemain += m_settings.m_inputSampleRate / m_settings.m_outputSampleRate; m_sampleDistanceRemain += m_inputSampleRate / m_settings.m_outputSampleRate;
calculateSquelch(m_inMagsq); calculateSquelch(m_inMagsq);
@ -323,66 +324,33 @@ bool UDPSrc::handleMessage(const Message& cmd)
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "UDPSrc::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << notif.getSampleRate()
UDPSrcSettings settings;
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
//apply(false);
applySettings(settings);
qDebug() << "UDPSrc::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate
<< " frequencyOffset: " << notif.getFrequencyOffset(); << " frequencyOffset: " << notif.getFrequencyOffset();
applyChannelSettings(notif.getSampleRate(), notif.getFrequencyOffset());
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
qDebug() << "UDPSrc::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
m_channelizer->configure(m_channelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(), cfg.getSampleRate(),
cfg.getCenterFrequency()); cfg.getCenterFrequency());
qDebug() << "UDPSrc::handleMessage: MsgConfigureChannelizer:"
<< " sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
return true; return true;
} }
else if (MsgConfigureUDPSrc::match(cmd)) else if (MsgConfigureUDPSrc::match(cmd))
{ {
MsgConfigureUDPSrc& cfg = (MsgConfigureUDPSrc&) cmd; MsgConfigureUDPSrc& cfg = (MsgConfigureUDPSrc&) cmd;
qDebug("UDPSrc::handleMessage: MsgConfigureUDPSrc");
UDPSrcSettings settings = cfg.getSettings(); applySettings(cfg.getSettings(), cfg.getForce());
// These settings are set with DownChannelizer::MsgChannelizerNotification
m_absoluteFrequencyOffset = settings.m_inputFrequencyOffset;
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
applySettings(settings, cfg.getForce());
qDebug() << "UDPSrc::handleMessage: MsgConfigureUDPSrc: "
<< " m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_audioActive: " << settings.m_audioActive
<< " m_audioStereo: " << settings.m_audioStereo
<< " m_gain: " << settings.m_gain
<< " m_volume: " << settings.m_volume
<< " m_squelchEnabled: " << settings.m_squelchEnabled
<< " m_squelchdB: " << settings.m_squelchdB
<< " m_squelchGate" << settings.m_squelchGate
<< " m_agc" << settings.m_agc
<< " m_sampleFormat: " << settings.m_sampleFormat
<< " m_outputSampleRate: " << settings.m_outputSampleRate
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_fmDeviation: " << settings.m_fmDeviation
<< " m_udpAddressStr: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " m_audioPort: " << settings.m_audioPort
<< " force: " << cfg.getForce();
return true; return true;
} }
@ -477,18 +445,59 @@ void UDPSrc::audioReadyRead()
//qDebug("UDPSrc::audioReadyRead: done"); //qDebug("UDPSrc::audioReadyRead: done");
} }
void UDPSrc::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset)
{
qDebug() << "UDPSrc::applyChannelSettings:"
<< " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset;
if((inputFrequencyOffset != m_inputFrequencyOffset) ||
(inputSampleRate != m_inputSampleRate))
{
m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
}
if (inputSampleRate != m_inputSampleRate)
{
m_settingsMutex.lock();
m_interpolator.create(16, inputSampleRate, m_settings.m_rfBandwidth / 2.0);
m_sampleDistanceRemain = inputSampleRate / m_settings.m_outputSampleRate;
m_settingsMutex.unlock();
}
m_inputSampleRate = inputSampleRate;
m_inputFrequencyOffset = inputFrequencyOffset;
}
void UDPSrc::applySettings(const UDPSrcSettings& settings, bool force) void UDPSrc::applySettings(const UDPSrcSettings& settings, bool force)
{ {
qDebug() << "UDPSrc::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_audioActive: " << settings.m_audioActive
<< " m_audioStereo: " << settings.m_audioStereo
<< " m_gain: " << settings.m_gain
<< " m_volume: " << settings.m_volume
<< " m_squelchEnabled: " << settings.m_squelchEnabled
<< " m_squelchdB: " << settings.m_squelchdB
<< " m_squelchGate" << settings.m_squelchGate
<< " m_agc" << settings.m_agc
<< " m_sampleFormat: " << settings.m_sampleFormat
<< " m_outputSampleRate: " << settings.m_outputSampleRate
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_fmDeviation: " << settings.m_fmDeviation
<< " m_udpAddressStr: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " m_audioPort: " << settings.m_audioPort
<< " force: " << force;
m_settingsMutex.lock(); m_settingsMutex.lock();
if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
(settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || (settings.m_rfBandwidth != m_settings.m_rfBandwidth) ||
(settings.m_outputSampleRate != m_settings.m_outputSampleRate) || force) (settings.m_outputSampleRate != m_settings.m_outputSampleRate) || force)
{ {
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate); m_interpolator.create(16, m_inputSampleRate, settings.m_rfBandwidth / 2.0);
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.0); m_sampleDistanceRemain = m_inputSampleRate / settings.m_outputSampleRate;
m_sampleDistanceRemain = settings.m_inputSampleRate / settings.m_outputSampleRate;
if ((settings.m_sampleFormat == UDPSrcSettings::FormatLSB) || if ((settings.m_sampleFormat == UDPSrcSettings::FormatLSB) ||
(settings.m_sampleFormat == UDPSrcSettings::FormatLSBMono) || (settings.m_sampleFormat == UDPSrcSettings::FormatLSBMono) ||

View File

@ -146,8 +146,9 @@ protected:
ThreadedBasebandSampleSink* m_threadedChannelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DownChannelizer* m_channelizer;
int m_inputSampleRate;
int m_inputFrequencyOffset;
UDPSrcSettings m_settings; UDPSrcSettings m_settings;
int m_absoluteFrequencyOffset;
QUdpSocket *m_audioSocket; QUdpSocket *m_audioSocket;
@ -197,6 +198,7 @@ protected:
QMutex m_settingsMutex; QMutex m_settingsMutex;
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset);
void applySettings(const UDPSrcSettings& settings, bool force = false); void applySettings(const UDPSrcSettings& settings, bool force = false);
inline void calculateSquelch(double value) inline void calculateSquelch(double value)

View File

@ -32,7 +32,6 @@ void UDPSrcSettings::resetToDefaults()
{ {
m_outputSampleRate = 48000; m_outputSampleRate = 48000;
m_sampleFormat = FormatS16LE; m_sampleFormat = FormatS16LE;
m_inputSampleRate = 48000;
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_rfBandwidth = 12500; m_rfBandwidth = 12500;
m_fmDeviation = 2500; m_fmDeviation = 2500;

View File

@ -41,7 +41,6 @@ struct UDPSrcSettings
float m_outputSampleRate; float m_outputSampleRate;
SampleFormat m_sampleFormat; SampleFormat m_sampleFormat;
float m_inputSampleRate;
int64_t m_inputFrequencyOffset; int64_t m_inputFrequencyOffset;
float m_rfBandwidth; float m_rfBandwidth;
int m_fmDeviation; int m_fmDeviation;