AM demod: use AM settings class and associated applySettings method

This commit is contained in:
f4exb 2017-09-26 23:19:49 +02:00
parent 42533f2fa3
commit 69a94c6004
5 changed files with 285 additions and 106 deletions

View File

@ -3,12 +3,14 @@ project(am)
set(am_SOURCES
amdemod.cpp
amdemodgui.cpp
amdemodsettings.cpp
amdemodplugin.cpp
)
set(am_HEADERS
amdemod.h
amdemodgui.h
amdemodsettings.h
amdemodplugin.h
)

View File

@ -43,14 +43,12 @@ AMDemod::AMDemod() :
{
setObjectName("AMDemod");
m_config.m_inputSampleRate = 96000;
m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 5000;
m_config.m_squelch = -40.0;
m_config.m_volume = 2.0;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
apply();
// m_config.m_inputSampleRate = 96000;
// m_config.m_inputFrequencyOffset = 0;
// m_config.m_rfBandwidth = 5000;
// m_config.m_squelch = -40.0;
// m_config.m_volume = 2.0;
// m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0;
@ -60,7 +58,9 @@ AMDemod::AMDemod() :
m_magsq = 0.0;
DSPEngine::instance()->addAudioSink(&m_audioFifo);
m_udpBufferAudio = new UDPSink<qint16>(this, m_udpBlockSize, m_config.m_udpPort);
m_udpBufferAudio = new UDPSink<qint16>(this, m_udpBlockSize, m_settings.m_udpPort);
applySettings(m_settings, true);
}
AMDemod::~AMDemod()
@ -142,8 +142,8 @@ void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector
void AMDemod::start()
{
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset;
m_squelchCount = 0;
m_audioFifo.clear();
@ -161,41 +161,45 @@ bool AMDemod::handleMessage(const Message& cmd)
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
AMDemodSettings settings = m_settings;
apply();
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
applySettings(settings);
qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true;
}
else if (MsgConfigureAMDemod::match(cmd))
{
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch();
m_config.m_audioMute = cfg.getAudioMute();
m_config.m_bandpassEnable = cfg.getBandpassEnable();
m_config.m_copyAudioToUDP = cfg.getCopyAudioToUDP();
m_config.m_udpAddress = cfg.getUDPAddress();
m_config.m_udpPort = cfg.getUDPPort();
AMDemodSettings settings = m_settings;
apply(cfg.getForce());
settings.m_rfBandwidth = cfg.getRFBandwidth();
settings.m_volume = cfg.getVolume();
settings.m_squelch = cfg.getSquelch();
settings.m_audioMute = cfg.getAudioMute();
settings.m_bandpassEnable = cfg.getBandpassEnable();
settings.m_copyAudioToUDP = cfg.getCopyAudioToUDP();
settings.m_udpAddress = cfg.getUDPAddress();
settings.m_udpPort = cfg.getUDPPort();
qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:"
<< " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch
<< " m_audioMute: " << m_config.m_audioMute
<< " m_bandpassEnable: " << m_config.m_bandpassEnable
<< " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP
<< " m_udpAddress: " << m_config.m_udpAddress
<< " m_udpPort: " << m_config.m_udpPort;
applySettings(settings);
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;
return true;
}
@ -205,40 +209,77 @@ bool AMDemod::handleMessage(const Message& cmd)
}
}
void AMDemod::apply(bool force)
//void AMDemod::apply(bool force)
//{
//
// if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
// (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force)
// {
// m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
// }
//
// if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
// (m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
// (m_config.m_audioSampleRate != m_running.m_audioSampleRate) ||
// (m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force)
// {
// m_settingsMutex.lock();
// m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f);
// m_interpolatorDistanceRemain = 0;
// m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
// m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f);
// m_settingsMutex.unlock();
// }
//
// if ((m_config.m_squelch != m_running.m_squelch) || force)
// {
// m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0);
// m_squelchLevel *= m_squelchLevel;
// qDebug("AMDemod::applySettings: m_squelchLevel: %f", m_squelchLevel);
// }
//
// if ((m_config.m_udpAddress != m_running.m_udpAddress)
// || (m_config.m_udpPort != m_running.m_udpPort) || force)
// {
// m_udpBufferAudio->setAddress(m_config.m_udpAddress);
// m_udpBufferAudio->setPort(m_config.m_udpPort);
// }
//
// m_running = m_config;
//}
void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
{
if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force)
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate) ||
(m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f);
m_settingsMutex.unlock();
}
if ((m_config.m_squelch != m_running.m_squelch) || force)
{
m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0);
m_squelchLevel *= m_squelchLevel;
}
if ((m_config.m_udpAddress != m_running.m_udpAddress)
|| (m_config.m_udpPort != m_running.m_udpPort) || force)
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) ||
(m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force)
{
m_udpBufferAudio->setAddress(m_config.m_udpAddress);
m_udpBufferAudio->setPort(m_config.m_udpPort);
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
}
m_running = m_config;
if((m_settings.m_inputSampleRate != settings.m_inputSampleRate) ||
(m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
(m_settings.m_audioSampleRate != settings.m_audioSampleRate) ||
(m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_bandpass.create(301, settings.m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f);
m_settingsMutex.unlock();
}
if ((m_settings.m_squelch != settings.m_squelch) || force)
{
m_squelchLevel = pow(10.0, settings.m_squelch / 10.0);
}
if ((m_settings.m_udpAddress != settings.m_udpAddress)
|| (m_settings.m_udpPort != settings.m_udpPort) || force)
{
m_udpBufferAudio->setAddress(const_cast<QString&>(settings.m_udpAddress));
m_udpBufferAudio->setPort(settings.m_udpPort);
}
m_settings = settings;
}

View File

@ -27,6 +27,7 @@
#include "dsp/bandpass.h"
#include "audio/audiofifo.h"
#include "util/message.h"
#include "amdemodsettings.h"
class AMDemod : public BasebandSampleSink {
Q_OBJECT
@ -137,36 +138,37 @@ private:
RSRunning
};
struct Config {
int m_inputSampleRate;
qint64 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_squelch;
Real m_volume;
quint32 m_audioSampleRate;
bool m_audioMute;
bool m_bandpassEnable;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
// struct Config {
// int m_inputSampleRate;
// qint64 m_inputFrequencyOffset;
// Real m_rfBandwidth;
// Real m_squelch;
// Real m_volume;
// quint32 m_audioSampleRate;
// bool m_audioMute;
// bool m_bandpassEnable;
// bool m_copyAudioToUDP;
// QString m_udpAddress;
// quint16 m_udpPort;
//
// Config() :
// m_inputSampleRate(-1),
// m_inputFrequencyOffset(0),
// m_rfBandwidth(-1),
// m_squelch(0),
// m_volume(0),
// m_audioSampleRate(0),
// m_audioMute(false),
// m_bandpassEnable(false),
// m_copyAudioToUDP(false),
// m_udpAddress("127.0.0.1"),
// m_udpPort(9999)
// { }
// };
Config() :
m_inputSampleRate(-1),
m_inputFrequencyOffset(0),
m_rfBandwidth(-1),
m_squelch(0),
m_volume(0),
m_audioSampleRate(0),
m_audioMute(false),
m_bandpassEnable(false),
m_copyAudioToUDP(false),
m_udpAddress("127.0.0.1"),
m_udpPort(9999)
{ }
};
Config m_config;
Config m_running;
AMDemodSettings m_settings;
// Config m_config;
// Config m_running;
NCO m_nco;
Interpolator m_interpolator;
@ -194,7 +196,8 @@ private:
QMutex m_settingsMutex;
void apply(bool force = false);
// void apply(bool force = false);
void applySettings(const AMDemodSettings& settings, bool force = false);
void processOneSample(Complex &ci)
{
@ -213,9 +216,9 @@ private:
if (m_magsq >= m_squelchLevel)
{
if (m_squelchCount <= m_running.m_audioSampleRate / 10)
if (m_squelchCount <= m_settings.m_audioSampleRate / 10)
{
if (m_squelchCount == m_running.m_audioSampleRate / 20) {
if (m_squelchCount == m_settings.m_audioSampleRate / 20) {
m_volumeAGC.fill(1.0);
}
@ -232,28 +235,28 @@ private:
qint16 sample;
if ((m_squelchCount >= m_running.m_audioSampleRate / 20) && !m_running.m_audioMute)
if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute)
{
Real demod = sqrt(magsq);
m_volumeAGC.feed(demod);
demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue();
if (m_running.m_bandpassEnable)
if (m_settings.m_bandpassEnable)
{
demod = m_bandpass.filter(demod);
demod /= 301.0f;
}
Real attack = (m_squelchCount - 0.05f * m_running.m_audioSampleRate) / (0.05f * m_running.m_audioSampleRate);
sample = demod * attack * 2048 * m_running.m_volume;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate);
sample = demod * attack * 2048 * m_settings.m_volume;
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
m_squelchOpen = true;
}
else
{
sample = 0;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(0);
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0);
m_squelchOpen = false;
}
@ -273,6 +276,7 @@ private:
m_audioBufferFill = 0;
}
}
};
#endif // INCLUDE_AMDEMOD_H

View File

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "amdemodsettings.h"
AMDemodSettings::AMDemodSettings()
{
resetToDefaults();
}
void AMDemodSettings::resetToDefaults()
{
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0;
m_rfBandwidth = 5000;
m_squelch = -40.0;
m_volume = 2.0;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_audioMute = false;
m_bandpassEnable = false;
m_copyAudioToUDP = false;
m_udpAddress = "127.0.0.1";
m_udpPort = 9999;
}
QByteArray AMDemodSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, m_rfBandwidth/1000);
s.writeS32(4, m_volume*10);
s.writeS32(5, m_squelch*10);
s.writeBlob(6, m_channelMarkerBytes);
s.writeBool(8, m_bandpassEnable);
return s.final();
}
bool AMDemodSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
QString strtmp;
d.readS32(1, &m_inputFrequencyOffset, 0);
d.readS32(2, &tmp, 4);
m_rfBandwidth = 1000 * tmp;
d.readS32(4, &tmp, 20);
m_volume = tmp * 0.1;
d.readS32(5, &tmp, -40);
m_squelch = tmp * 0.1;
d.readBlob(6, &m_channelMarkerBytes);
d.readBool(8, &m_bandpassEnable, false);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_
#define PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_
#include <QByteArray>
struct AMDemodSettings
{
int m_inputSampleRate;
qint32 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_squelch;
Real m_volume;
quint32 m_audioSampleRate;
bool m_audioMute;
bool m_bandpassEnable;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
QByteArray m_channelMarkerBytes;
AMDemodSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_ */