mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 17:58:43 -05:00
UDP source plugin: implemented squelch gate
This commit is contained in:
parent
2c3f7fe690
commit
587d38665d
@ -30,17 +30,9 @@ MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcConfigureImmediate, Message)
|
||||
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcSpectrum, Message)
|
||||
|
||||
UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampleSink* spectrum) :
|
||||
m_udpPort(9999),
|
||||
m_gain(1.0),
|
||||
m_audioActive(false),
|
||||
m_audioStereo(false),
|
||||
m_volume(20),
|
||||
m_fmDeviation(2500),
|
||||
m_outMovingAverage(480, 1e-10),
|
||||
m_inMovingAverage(480, 1e-10),
|
||||
m_audioFifo(4, 24000),
|
||||
m_squelch(1e-6),
|
||||
m_squelchEnabled(true),
|
||||
m_squelchOpen(false),
|
||||
m_squelchOpenCount(0),
|
||||
m_squelchCloseCount(0),
|
||||
@ -49,22 +41,17 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampl
|
||||
{
|
||||
setObjectName("UDPSrc");
|
||||
|
||||
m_udpBuffer = new UDPSink<Sample>(this, udpBlockSize, m_udpPort);
|
||||
m_udpBufferMono = new UDPSink<FixReal>(this, udpBlockSize, m_udpPort);
|
||||
m_udpBuffer = new UDPSink<Sample>(this, udpBlockSize, m_config.m_udpPort);
|
||||
m_udpBufferMono = new UDPSink<FixReal>(this, udpBlockSize, m_config.m_udpPort);
|
||||
m_audioSocket = new QUdpSocket(this);
|
||||
m_udpAudioBuf = new char[m_udpAudioPayloadSize];
|
||||
|
||||
m_audioBuffer.resize(1<<9);
|
||||
m_audioBufferFill = 0;
|
||||
|
||||
m_inputSampleRate = 96000;
|
||||
m_sampleFormat = FormatS16LE;
|
||||
m_outputSampleRate = 48000;
|
||||
m_rfBandwidth = 32000;
|
||||
m_audioPort = m_udpPort - 1;
|
||||
m_nco.setFreq(0, m_inputSampleRate);
|
||||
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0);
|
||||
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
|
||||
m_nco.setFreq(0, m_config.m_inputSampleRate);
|
||||
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.0);
|
||||
m_sampleDistanceRemain = m_config.m_inputSampleRate / m_config.m_outputSampleRate;
|
||||
m_uiMessageQueue = uiMessageQueue;
|
||||
m_udpSrcGUI = udpSrcGUI;
|
||||
m_spectrum = spectrum;
|
||||
@ -77,13 +64,13 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampl
|
||||
m_scale = 0;
|
||||
m_magsq = 0;
|
||||
m_inMagsq = 0;
|
||||
UDPFilter = new fftfilt(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate, udpBlockSize);
|
||||
UDPFilter = new fftfilt(0.0, (m_config.m_rfBandwidth / 2.0) / m_config.m_outputSampleRate, udpBlockSize);
|
||||
|
||||
m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation));
|
||||
m_phaseDiscri.setFMScaling((float) m_config. m_outputSampleRate / (2.0f * m_config.m_fmDeviation));
|
||||
|
||||
if (m_audioSocket->bind(QHostAddress::LocalHost, m_audioPort))
|
||||
if (m_audioSocket->bind(QHostAddress::LocalHost, m_config.m_audioPort))
|
||||
{
|
||||
qDebug("UDPSrc::UDPSrc: bind audio socket to port %d", m_audioPort);
|
||||
qDebug("UDPSrc::UDPSrc: bind audio socket to port %d", m_config.m_audioPort);
|
||||
connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection);
|
||||
}
|
||||
else
|
||||
@ -101,9 +88,10 @@ UDPSrc::~UDPSrc()
|
||||
delete m_udpBufferMono;
|
||||
delete[] m_udpAudioBuf;
|
||||
if (UDPFilter) delete UDPFilter;
|
||||
if (m_audioActive) DSPEngine::instance()->removeAudioSink(&m_audioFifo);
|
||||
if (m_running.m_audioActive) DSPEngine::instance()->removeAudioSink(&m_audioFifo);
|
||||
}
|
||||
|
||||
/** what needs the "apply" button validation */
|
||||
void UDPSrc::configure(MessageQueue* messageQueue,
|
||||
SampleFormat sampleFormat,
|
||||
Real outputSampleRate,
|
||||
@ -111,7 +99,8 @@ void UDPSrc::configure(MessageQueue* messageQueue,
|
||||
int fmDeviation,
|
||||
QString& udpAddress,
|
||||
int udpPort,
|
||||
int audioPort)
|
||||
int audioPort,
|
||||
bool force)
|
||||
{
|
||||
Message* cmd = MsgUDPSrcConfigure::create(sampleFormat,
|
||||
outputSampleRate,
|
||||
@ -119,17 +108,21 @@ void UDPSrc::configure(MessageQueue* messageQueue,
|
||||
fmDeviation,
|
||||
udpAddress,
|
||||
udpPort,
|
||||
audioPort);
|
||||
audioPort,
|
||||
force);
|
||||
messageQueue->push(cmd);
|
||||
}
|
||||
|
||||
/** changes applied immediately */
|
||||
void UDPSrc::configureImmediate(MessageQueue* messageQueue,
|
||||
bool audioActive,
|
||||
bool audioStereo,
|
||||
Real boost,
|
||||
int volume,
|
||||
Real squelchDB,
|
||||
bool squelchEnabled)
|
||||
Real squelchGate,
|
||||
bool squelchEnabled,
|
||||
bool force)
|
||||
{
|
||||
Message* cmd = MsgUDPSrcConfigureImmediate::create(
|
||||
audioActive,
|
||||
@ -137,7 +130,9 @@ void UDPSrc::configureImmediate(MessageQueue* messageQueue,
|
||||
boost,
|
||||
volume,
|
||||
squelchDB,
|
||||
squelchEnabled);
|
||||
squelchGate,
|
||||
squelchEnabled,
|
||||
force);
|
||||
messageQueue->push(cmd);
|
||||
}
|
||||
|
||||
@ -171,11 +166,11 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
|
||||
Sample ss(ci.real(), ci.imag());
|
||||
m_sampleBuffer.push_back(ss);
|
||||
|
||||
m_sampleDistanceRemain += m_inputSampleRate / m_outputSampleRate;
|
||||
m_sampleDistanceRemain += m_running.m_inputSampleRate / m_running.m_outputSampleRate;
|
||||
|
||||
calculateSquelch(m_inMagsq);
|
||||
|
||||
if (m_sampleFormat == FormatLSB) // binaural LSB
|
||||
if (m_running.m_sampleFormat == FormatLSB) // binaural LSB
|
||||
{
|
||||
int n_out = UDPFilter->runSSB(ci, &sideband, false);
|
||||
|
||||
@ -183,14 +178,14 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
|
||||
{
|
||||
for (int i = 0; i < n_out; i++)
|
||||
{
|
||||
l = m_squelchOpen ? sideband[i].real() * m_gain : 0;
|
||||
r = m_squelchOpen ? sideband[i].imag() * m_gain : 0;
|
||||
l = m_squelchOpen ? sideband[i].real() * m_running.m_gain : 0;
|
||||
r = m_squelchOpen ? sideband[i].imag() * m_running.m_gain : 0;
|
||||
m_udpBuffer->write(Sample(l, r));
|
||||
m_outMovingAverage.feed((l*l + r*r) / (1<<30));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_sampleFormat == FormatUSB) // binaural USB
|
||||
if (m_running.m_sampleFormat == FormatUSB) // binaural USB
|
||||
{
|
||||
int n_out = UDPFilter->runSSB(ci, &sideband, true);
|
||||
|
||||
@ -198,26 +193,26 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
|
||||
{
|
||||
for (int i = 0; i < n_out; i++)
|
||||
{
|
||||
l = m_squelchOpen ? sideband[i].real() * m_gain : 0;
|
||||
r = m_squelchOpen ? sideband[i].imag() * m_gain : 0;
|
||||
l = m_squelchOpen ? sideband[i].real() * m_running.m_gain : 0;
|
||||
r = m_squelchOpen ? sideband[i].imag() * m_running.m_gain : 0;
|
||||
m_udpBuffer->write(Sample(l, r));
|
||||
m_outMovingAverage.feed((l*l + r*r) / (1<<30));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_sampleFormat == FormatNFM)
|
||||
else if (m_running.m_sampleFormat == FormatNFM)
|
||||
{
|
||||
double demod = m_squelchOpen ? 32768.0 * m_phaseDiscri.phaseDiscriminator(ci) * m_gain : 0;
|
||||
double demod = m_squelchOpen ? 32768.0 * m_phaseDiscri.phaseDiscriminator(ci) * m_running.m_gain : 0;
|
||||
m_udpBuffer->write(Sample(demod, demod));
|
||||
m_outMovingAverage.feed((demod * demod) / (1<<30));
|
||||
}
|
||||
else if (m_sampleFormat == FormatNFMMono)
|
||||
else if (m_running.m_sampleFormat == FormatNFMMono)
|
||||
{
|
||||
FixReal demod = m_squelchOpen ? (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_gain) : 0;
|
||||
FixReal demod = m_squelchOpen ? (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_running.m_gain) : 0;
|
||||
m_udpBufferMono->write(demod);
|
||||
m_outMovingAverage.feed((demod * demod) / 1073741824.0);
|
||||
}
|
||||
else if (m_sampleFormat == FormatLSBMono) // Monaural LSB
|
||||
else if (m_running.m_sampleFormat == FormatLSBMono) // Monaural LSB
|
||||
{
|
||||
int n_out = UDPFilter->runSSB(ci, &sideband, false);
|
||||
|
||||
@ -225,13 +220,13 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
|
||||
{
|
||||
for (int i = 0; i < n_out; i++)
|
||||
{
|
||||
l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_gain : 0;
|
||||
l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_running.m_gain : 0;
|
||||
m_udpBufferMono->write(l);
|
||||
m_outMovingAverage.feed((l * l) / (1<<30));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_sampleFormat == FormatUSBMono) // Monaural USB
|
||||
else if (m_running.m_sampleFormat == FormatUSBMono) // Monaural USB
|
||||
{
|
||||
int n_out = UDPFilter->runSSB(ci, &sideband, true);
|
||||
|
||||
@ -239,15 +234,15 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
|
||||
{
|
||||
for (int i = 0; i < n_out; i++)
|
||||
{
|
||||
l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_gain : 0;
|
||||
l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_running.m_gain : 0;
|
||||
m_udpBufferMono->write(l);
|
||||
m_outMovingAverage.feed((l * l) / (1<<30));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_sampleFormat == FormatAMMono)
|
||||
else if (m_running.m_sampleFormat == FormatAMMono)
|
||||
{
|
||||
FixReal demod = m_squelchOpen ? (FixReal) (sqrt(inMagSq) * m_gain) : 0;
|
||||
FixReal demod = m_squelchOpen ? (FixReal) (sqrt(inMagSq) * m_running.m_gain) : 0;
|
||||
m_udpBufferMono->write(demod);
|
||||
m_outMovingAverage.feed((demod * demod) / (1<<30));
|
||||
}
|
||||
@ -255,9 +250,9 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
|
||||
{
|
||||
if (m_squelchOpen)
|
||||
{
|
||||
Sample s(ci.real() * m_gain, ci.imag() * m_gain);
|
||||
Sample s(ci.real() * m_running.m_gain, ci.imag() * m_running.m_gain);
|
||||
m_udpBuffer->write(s);
|
||||
m_outMovingAverage.feed((inMagSq*m_gain*m_gain) / (1<<30));
|
||||
m_outMovingAverage.feed((inMagSq*m_running.m_gain*m_running.m_gain) / (1<<30));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -298,68 +293,38 @@ bool UDPSrc::handleMessage(const Message& cmd)
|
||||
{
|
||||
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
|
||||
|
||||
m_settingsMutex.lock();
|
||||
m_config.m_inputSampleRate = notif.getSampleRate();
|
||||
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
|
||||
|
||||
m_inputSampleRate = notif.getSampleRate();
|
||||
m_nco.setFreq(-notif.getFrequencyOffset(), m_inputSampleRate);
|
||||
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0);
|
||||
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
|
||||
apply(false);
|
||||
|
||||
m_settingsMutex.unlock();
|
||||
qDebug() << "UDPSrc::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate
|
||||
<< " frequencyOffset: " << notif.getFrequencyOffset();
|
||||
|
||||
qDebug() << "UDPSrc::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_inputSampleRate
|
||||
<< " frequencyOffset: " << notif.getFrequencyOffset();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
else if (MsgUDPSrcConfigureImmediate::match(cmd))
|
||||
{
|
||||
MsgUDPSrcConfigureImmediate& cfg = (MsgUDPSrcConfigureImmediate&) cmd;
|
||||
|
||||
m_settingsMutex.lock();
|
||||
m_config.m_audioActive = cfg.getAudioActive();
|
||||
m_config.m_audioStereo = cfg.getAudioStereo();
|
||||
m_config.m_gain = cfg.getGain();
|
||||
m_config.m_volume = cfg.getVolume();
|
||||
m_config.m_squelch = CalcDb::powerFromdB(cfg.getSquelchDB());
|
||||
m_config.m_squelchGate = cfg.getSquelchGate();
|
||||
m_config.m_squelchEnabled = cfg.getSquelchEnabled();
|
||||
|
||||
if (cfg.getAudioActive() != m_audioActive)
|
||||
{
|
||||
m_audioActive = cfg.getAudioActive();
|
||||
|
||||
if (m_audioActive)
|
||||
{
|
||||
m_audioBufferFill = 0;
|
||||
DSPEngine::instance()->addAudioSink(&m_audioFifo);
|
||||
}
|
||||
else
|
||||
{
|
||||
DSPEngine::instance()->removeAudioSink(&m_audioFifo);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.getAudioStereo() != m_audioStereo)
|
||||
{
|
||||
m_audioStereo = cfg.getAudioStereo();
|
||||
}
|
||||
|
||||
if (cfg.getGain() != m_gain)
|
||||
{
|
||||
m_gain = cfg.getGain();
|
||||
}
|
||||
|
||||
if (cfg.getVolume() != m_volume)
|
||||
{
|
||||
m_volume = cfg.getVolume();
|
||||
}
|
||||
|
||||
m_squelch = CalcDb::powerFromdB(cfg.getSquelchDB());
|
||||
m_squelchEnabled = cfg.getSquelchEnabled();
|
||||
|
||||
m_settingsMutex.unlock();
|
||||
apply(cfg.getForce());
|
||||
|
||||
qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigureImmediate: "
|
||||
<< " m_audioActive: " << m_audioActive
|
||||
<< " m_audioStereo: " << m_audioStereo
|
||||
<< " m_gain: " << m_gain
|
||||
<< " m_squelchEnabled: " << m_squelchEnabled
|
||||
<< " m_squelch: " << m_squelch
|
||||
<< " getSquelchDB: " << cfg.getSquelchDB();
|
||||
<< " m_audioActive: " << m_config.m_audioActive
|
||||
<< " m_audioStereo: " << m_config.m_audioStereo
|
||||
<< " m_gain: " << m_config.m_gain
|
||||
<< " m_squelchEnabled: " << m_config.m_squelchEnabled
|
||||
<< " m_squelch: " << m_config.m_squelch
|
||||
<< " getSquelchDB: " << cfg.getSquelchDB()
|
||||
<< " m_squelchGate" << m_config.m_squelchGate;
|
||||
|
||||
return true;
|
||||
|
||||
@ -368,67 +333,22 @@ bool UDPSrc::handleMessage(const Message& cmd)
|
||||
{
|
||||
MsgUDPSrcConfigure& cfg = (MsgUDPSrcConfigure&) cmd;
|
||||
|
||||
m_settingsMutex.lock();
|
||||
m_config.m_sampleFormat = cfg.getSampleFormat();
|
||||
m_config.m_outputSampleRate = cfg.getOutputSampleRate();
|
||||
m_config.m_rfBandwidth = cfg.getRFBandwidth();
|
||||
m_config.m_udpAddressStr = cfg.getUDPAddress();
|
||||
m_config.m_udpPort = cfg.getUDPPort();
|
||||
m_config.m_audioPort = cfg.getAudioPort();
|
||||
m_config.m_fmDeviation = cfg.getFMDeviation();
|
||||
|
||||
m_sampleFormat = cfg.getSampleFormat();
|
||||
m_outputSampleRate = cfg.getOutputSampleRate();
|
||||
m_rfBandwidth = cfg.getRFBandwidth();
|
||||
apply(cfg.getForce());
|
||||
|
||||
if (cfg.getUDPAddress() != m_udpAddressStr)
|
||||
{
|
||||
m_udpAddressStr = cfg.getUDPAddress();
|
||||
m_udpBuffer->setAddress(m_udpAddressStr);
|
||||
m_udpBufferMono->setAddress(m_udpAddressStr);
|
||||
}
|
||||
|
||||
if (cfg.getUDPPort() != m_udpPort)
|
||||
{
|
||||
m_udpPort = cfg.getUDPPort();
|
||||
m_udpBuffer->setPort(m_udpPort);
|
||||
m_udpBufferMono->setPort(m_udpPort);
|
||||
}
|
||||
|
||||
if (cfg.getAudioPort() != m_audioPort)
|
||||
{
|
||||
m_audioPort = cfg.getAudioPort();
|
||||
|
||||
disconnect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()));
|
||||
delete m_audioSocket;
|
||||
m_audioSocket = new QUdpSocket(this);
|
||||
|
||||
if (m_audioSocket->bind(QHostAddress::LocalHost, m_audioPort))
|
||||
{
|
||||
connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection);
|
||||
qDebug("UDPSrc::handleMessage: audio socket bound to port %d", m_audioPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning("UDPSrc::handleMessage: cannot bind audio socket");
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.getFMDeviation() != m_fmDeviation)
|
||||
{
|
||||
m_fmDeviation = cfg.getFMDeviation();
|
||||
m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation));
|
||||
}
|
||||
|
||||
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0);
|
||||
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
|
||||
UDPFilter->create_filter(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate);
|
||||
|
||||
m_inMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10); // 10 ms
|
||||
m_outMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10); // 10 ms
|
||||
m_squelchThreshold = m_outputSampleRate * 0.05; // 50 ms
|
||||
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigure: m_sampleFormat: " << m_sampleFormat
|
||||
<< " m_outputSampleRate: " << m_outputSampleRate
|
||||
<< " m_rfBandwidth: " << m_rfBandwidth
|
||||
<< " m_udpAddressStr: " << m_udpAddressStr
|
||||
<< " m_udpPort: " << m_udpPort
|
||||
<< " m_audioPort: " << m_audioPort;
|
||||
qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigure: m_sampleFormat: " << m_config.m_sampleFormat
|
||||
<< " m_outputSampleRate: " << m_config.m_outputSampleRate
|
||||
<< " m_rfBandwidth: " << m_config.m_rfBandwidth
|
||||
<< " m_udpAddressStr: " << m_config.m_udpAddressStr
|
||||
<< " m_udpPort: " << m_config.m_udpPort
|
||||
<< " m_audioPort: " << m_config.m_audioPort;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -455,6 +375,83 @@ bool UDPSrc::handleMessage(const Message& cmd)
|
||||
}
|
||||
}
|
||||
|
||||
void UDPSrc::apply(bool force)
|
||||
{
|
||||
m_settingsMutex.lock();
|
||||
|
||||
if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
|
||||
(m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
|
||||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
|
||||
(m_config.m_outputSampleRate != m_running.m_outputSampleRate) || force)
|
||||
{
|
||||
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
|
||||
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.0);
|
||||
m_sampleDistanceRemain = m_config.m_inputSampleRate / m_config.m_outputSampleRate;
|
||||
|
||||
m_squelchThreshold = m_config.m_outputSampleRate * m_config.m_squelchGate;
|
||||
initSquelch(m_squelchOpen);
|
||||
|
||||
m_inMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10); // 10 ms
|
||||
m_outMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10); // 10 ms
|
||||
}
|
||||
|
||||
if ((m_config.m_audioActive != m_config.m_audioActive) || force)
|
||||
{
|
||||
if (m_config.m_audioActive)
|
||||
{
|
||||
m_audioBufferFill = 0;
|
||||
DSPEngine::instance()->addAudioSink(&m_audioFifo);
|
||||
}
|
||||
else
|
||||
{
|
||||
DSPEngine::instance()->removeAudioSink(&m_audioFifo);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_config.m_squelchGate != m_running.m_squelchGate) || force)
|
||||
{
|
||||
m_squelchThreshold = m_config.m_outputSampleRate * m_config.m_squelchGate;
|
||||
}
|
||||
|
||||
if ((m_config.m_udpAddressStr != m_running.m_udpAddressStr) || force)
|
||||
{
|
||||
m_udpBuffer->setAddress(m_config.m_udpAddressStr);
|
||||
m_udpBufferMono->setAddress(m_config.m_udpAddressStr);
|
||||
}
|
||||
|
||||
if ((m_config.m_udpPort != m_running.m_udpPort) || force)
|
||||
{
|
||||
m_udpBuffer->setPort(m_config.m_udpPort);
|
||||
m_udpBufferMono->setPort(m_config.m_udpPort);
|
||||
}
|
||||
|
||||
if ((m_config.m_audioPort != m_running.m_audioPort) || force)
|
||||
{
|
||||
disconnect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()));
|
||||
delete m_audioSocket;
|
||||
m_audioSocket = new QUdpSocket(this);
|
||||
|
||||
if (m_audioSocket->bind(QHostAddress::LocalHost, m_config.m_audioPort))
|
||||
{
|
||||
connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection);
|
||||
qDebug("UDPSrc::handleMessage: audio socket bound to port %d", m_config.m_audioPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning("UDPSrc::handleMessage: cannot bind audio socket");
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_config.m_fmDeviation != m_running.m_fmDeviation) || force)
|
||||
{
|
||||
m_phaseDiscri.setFMScaling((float) m_config.m_outputSampleRate / (2.0f * m_config.m_fmDeviation));
|
||||
}
|
||||
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
m_running = m_config;
|
||||
}
|
||||
|
||||
void UDPSrc::audioReadyRead()
|
||||
{
|
||||
while (m_audioSocket->hasPendingDatagrams())
|
||||
@ -463,16 +460,16 @@ void UDPSrc::audioReadyRead()
|
||||
qint64 udpReadBytes = m_audioSocket->readDatagram(m_udpAudioBuf, pendingDataSize, 0, 0);
|
||||
//qDebug("UDPSrc::audioReadyRead: %lld", udpReadBytes);
|
||||
|
||||
if (m_audioActive)
|
||||
if (m_running.m_audioActive)
|
||||
{
|
||||
if (m_audioStereo)
|
||||
if (m_running.m_audioStereo)
|
||||
{
|
||||
for (int i = 0; i < udpReadBytes - 3; i += 4)
|
||||
{
|
||||
qint16 l_sample = (qint16) *(&m_udpAudioBuf[i]);
|
||||
qint16 r_sample = (qint16) *(&m_udpAudioBuf[i+2]);
|
||||
m_audioBuffer[m_audioBufferFill].l = l_sample * m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].r = r_sample * m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].l = l_sample * m_running.m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].r = r_sample * m_running.m_volume;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
@ -493,8 +490,8 @@ void UDPSrc::audioReadyRead()
|
||||
for (int i = 0; i < udpReadBytes - 1; i += 2)
|
||||
{
|
||||
qint16 sample = (qint16) *(&m_udpAudioBuf[i]);
|
||||
m_audioBuffer[m_audioBufferFill].l = sample * m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample * m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].l = sample * m_running.m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample * m_running.m_volume;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
|
@ -67,14 +67,17 @@ public:
|
||||
int fmDeviation,
|
||||
QString& udpAddress,
|
||||
int udpPort,
|
||||
int audioPort);
|
||||
int audioPort,
|
||||
bool force);
|
||||
void configureImmediate(MessageQueue* messageQueue,
|
||||
bool audioActive,
|
||||
bool audioStereo,
|
||||
Real gain,
|
||||
int volume,
|
||||
Real squelchDB,
|
||||
bool squelchEnabled);
|
||||
Real squelchGate,
|
||||
bool squelchEnabled,
|
||||
bool force);
|
||||
void setSpectrum(MessageQueue* messageQueue, bool enabled);
|
||||
double getMagSq() const { return m_magsq; }
|
||||
double getInMagSq() const { return m_inMagsq; }
|
||||
@ -102,6 +105,7 @@ protected:
|
||||
const QString& getUDPAddress() const { return m_udpAddress; }
|
||||
int getUDPPort() const { return m_udpPort; }
|
||||
int getAudioPort() const { return m_audioPort; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgUDPSrcConfigure* create(SampleFormat
|
||||
sampleFormat,
|
||||
@ -110,7 +114,8 @@ protected:
|
||||
int fmDeviation,
|
||||
QString& udpAddress,
|
||||
int udpPort,
|
||||
int audioPort)
|
||||
int audioPort,
|
||||
bool force)
|
||||
{
|
||||
return new MsgUDPSrcConfigure(sampleFormat,
|
||||
sampleRate,
|
||||
@ -118,7 +123,8 @@ protected:
|
||||
fmDeviation,
|
||||
udpAddress,
|
||||
udpPort,
|
||||
audioPort);
|
||||
audioPort,
|
||||
force);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -129,6 +135,7 @@ protected:
|
||||
QString m_udpAddress;
|
||||
int m_udpPort;
|
||||
int m_audioPort;
|
||||
bool m_force;
|
||||
|
||||
MsgUDPSrcConfigure(SampleFormat sampleFormat,
|
||||
Real outputSampleRate,
|
||||
@ -136,7 +143,8 @@ protected:
|
||||
int fmDeviation,
|
||||
QString& udpAddress,
|
||||
int udpPort,
|
||||
int audioPort) :
|
||||
int audioPort,
|
||||
bool force) :
|
||||
Message(),
|
||||
m_sampleFormat(sampleFormat),
|
||||
m_outputSampleRate(outputSampleRate),
|
||||
@ -144,7 +152,8 @@ protected:
|
||||
m_fmDeviation(fmDeviation),
|
||||
m_udpAddress(udpAddress),
|
||||
m_udpPort(udpPort),
|
||||
m_audioPort(audioPort)
|
||||
m_audioPort(audioPort),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -157,7 +166,9 @@ protected:
|
||||
bool getAudioActive() const { return m_audioActive; }
|
||||
bool getAudioStereo() const { return m_audioStereo; }
|
||||
Real getSquelchDB() const { return m_squelchDB; }
|
||||
Real getSquelchGate() const { return m_squelchGate; }
|
||||
bool getSquelchEnabled() const { return m_squelchEnabled; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgUDPSrcConfigureImmediate* create(
|
||||
bool audioActive,
|
||||
@ -165,7 +176,9 @@ protected:
|
||||
int gain,
|
||||
int volume,
|
||||
Real squelchDB,
|
||||
bool squelchEnabled)
|
||||
Real squelchGate,
|
||||
bool squelchEnabled,
|
||||
bool force)
|
||||
{
|
||||
return new MsgUDPSrcConfigureImmediate(
|
||||
audioActive,
|
||||
@ -173,7 +186,9 @@ protected:
|
||||
gain,
|
||||
volume,
|
||||
squelchDB,
|
||||
squelchEnabled);
|
||||
squelchGate,
|
||||
squelchEnabled,
|
||||
force);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -182,7 +197,9 @@ protected:
|
||||
bool m_audioActive;
|
||||
bool m_audioStereo;
|
||||
Real m_squelchDB;
|
||||
Real m_squelchGate; // seconds
|
||||
bool m_squelchEnabled;
|
||||
bool m_force;
|
||||
|
||||
MsgUDPSrcConfigureImmediate(
|
||||
bool audioActive,
|
||||
@ -190,14 +207,18 @@ protected:
|
||||
Real gain,
|
||||
int volume,
|
||||
Real squelchDB,
|
||||
bool squelchEnabled) :
|
||||
Real squelchGate,
|
||||
bool squelchEnabled,
|
||||
bool force) :
|
||||
Message(),
|
||||
m_gain(gain),
|
||||
m_volume(volume),
|
||||
m_audioActive(audioActive),
|
||||
m_audioStereo(audioStereo),
|
||||
m_squelchDB(squelchDB),
|
||||
m_squelchEnabled(squelchEnabled)
|
||||
m_squelchGate(squelchGate),
|
||||
m_squelchEnabled(squelchEnabled),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -221,23 +242,54 @@ protected:
|
||||
{ }
|
||||
};
|
||||
|
||||
struct Config {
|
||||
Real m_outputSampleRate;
|
||||
SampleFormat m_sampleFormat;
|
||||
Real m_inputSampleRate;
|
||||
qint64 m_inputFrequencyOffset;
|
||||
Real m_rfBandwidth;
|
||||
int m_fmDeviation;
|
||||
bool m_channelMute;
|
||||
Real m_gain;
|
||||
Real m_squelch; //!< squared magnitude
|
||||
Real m_squelchGate; //!< seconds
|
||||
bool m_squelchEnabled;
|
||||
bool m_audioActive;
|
||||
bool m_audioStereo;
|
||||
int m_volume;
|
||||
|
||||
QString m_udpAddressStr;
|
||||
quint16 m_udpPort;
|
||||
quint16 m_audioPort;
|
||||
|
||||
Config() :
|
||||
m_outputSampleRate(48000),
|
||||
m_sampleFormat(FormatS16LE),
|
||||
m_inputSampleRate(48000),
|
||||
m_inputFrequencyOffset(0),
|
||||
m_rfBandwidth(12500),
|
||||
m_fmDeviation(2500),
|
||||
m_channelMute(false),
|
||||
m_gain(1.0),
|
||||
m_squelch(1e-6),
|
||||
m_squelchGate(0.0),
|
||||
m_squelchEnabled(true),
|
||||
m_audioActive(false),
|
||||
m_audioStereo(false),
|
||||
m_volume(20),
|
||||
m_udpAddressStr("127.0.0.1"),
|
||||
m_udpPort(9999),
|
||||
m_audioPort(9998)
|
||||
{}
|
||||
};
|
||||
|
||||
Config m_config;
|
||||
Config m_running;
|
||||
|
||||
MessageQueue* m_uiMessageQueue;
|
||||
UDPSrcGUI* m_udpSrcGUI;
|
||||
QUdpSocket *m_audioSocket;
|
||||
|
||||
int m_inputSampleRate;
|
||||
|
||||
int m_sampleFormat;
|
||||
Real m_outputSampleRate;
|
||||
Real m_rfBandwidth;
|
||||
QString m_udpAddressStr;
|
||||
quint16 m_udpPort;
|
||||
quint16 m_audioPort;
|
||||
Real m_gain;
|
||||
bool m_audioActive;
|
||||
bool m_audioStereo;
|
||||
int m_volume;
|
||||
int m_fmDeviation;
|
||||
double m_magsq;
|
||||
double m_inMagsq;
|
||||
MovingAverage<double> m_outMovingAverage;
|
||||
@ -270,34 +322,54 @@ protected:
|
||||
|
||||
PhaseDiscriminators m_phaseDiscri;
|
||||
|
||||
Real m_squelch; //!< squared magnitude
|
||||
bool m_squelchEnabled;
|
||||
bool m_squelchOpen;
|
||||
int m_squelchOpenCount;
|
||||
int m_squelchCloseCount;
|
||||
int m_squelchThreshold;
|
||||
int m_squelchThreshold; //!< number of samples computed from given gate
|
||||
|
||||
QMutex m_settingsMutex;
|
||||
|
||||
void apply(bool force);
|
||||
|
||||
inline void calculateSquelch(double value)
|
||||
{
|
||||
if ((!m_squelchEnabled) || (value > m_squelch))
|
||||
if ((!m_running.m_squelchEnabled) || (value > m_running.m_squelch))
|
||||
{
|
||||
if (m_squelchOpenCount < m_squelchThreshold) {
|
||||
m_squelchOpenCount++;
|
||||
} else {
|
||||
m_squelchCloseCount = m_squelchThreshold;
|
||||
if (m_squelchThreshold == 0)
|
||||
{
|
||||
m_squelchOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_squelchOpenCount < m_squelchThreshold)
|
||||
{
|
||||
m_squelchOpenCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_squelchCloseCount = m_squelchThreshold;
|
||||
m_squelchOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_squelchCloseCount > 0) {
|
||||
m_squelchCloseCount--;
|
||||
} else {
|
||||
m_squelchOpenCount = 0;
|
||||
if (m_squelchThreshold == 0)
|
||||
{
|
||||
m_squelchOpen = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_squelchCloseCount > 0)
|
||||
{
|
||||
m_squelchCloseCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_squelchOpenCount = 0;
|
||||
m_squelchOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,8 +197,8 @@ bool UDPSrcGUI::deserialize(const QByteArray& data)
|
||||
blockApplySettings(false);
|
||||
m_channelMarker.blockSignals(false);
|
||||
|
||||
applySettingsImmediate();
|
||||
applySettings();
|
||||
applySettingsImmediate(true);
|
||||
applySettings(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -297,8 +297,8 @@ UDPSrcGUI::UDPSrcGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget*
|
||||
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
|
||||
|
||||
displaySettings();
|
||||
applySettingsImmediate();
|
||||
applySettings();
|
||||
applySettingsImmediate(true);
|
||||
applySettings(true);
|
||||
}
|
||||
|
||||
UDPSrcGUI::~UDPSrcGUI()
|
||||
@ -323,9 +323,10 @@ void UDPSrcGUI::displaySettings()
|
||||
ui->gainText->setText(tr("%1").arg(ui->gain->value()/10.0, 0, 'f', 1));
|
||||
ui->volumeText->setText(QString("%1").arg(ui->volume->value()));
|
||||
ui->squelchText->setText(tr("%1").arg(ui->squelch->value()*1.0, 0, 'f', 0));
|
||||
ui->squelchGateText->setText(tr("%1").arg(ui->squelchGate->value()*10.0, 0, 'f', 0));
|
||||
}
|
||||
|
||||
void UDPSrcGUI::applySettingsImmediate()
|
||||
void UDPSrcGUI::applySettingsImmediate(bool force)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
@ -340,12 +341,14 @@ void UDPSrcGUI::applySettingsImmediate()
|
||||
m_gain,
|
||||
m_volume,
|
||||
ui->squelch->value() * 1.0f,
|
||||
ui->squelch->value() != -100);
|
||||
ui->squelchGate->value() * 0.01f,
|
||||
ui->squelch->value() != -100,
|
||||
force);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UDPSrcGUI::applySettings()
|
||||
void UDPSrcGUI::applySettings(bool force)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
@ -461,7 +464,8 @@ void UDPSrcGUI::applySettings()
|
||||
fmDeviation,
|
||||
m_udpAddress,
|
||||
udpPort,
|
||||
audioPort);
|
||||
audioPort,
|
||||
force);
|
||||
|
||||
ui->applyBtn->setEnabled(false);
|
||||
}
|
||||
@ -554,6 +558,12 @@ void UDPSrcGUI::on_squelch_valueChanged(int value)
|
||||
applySettingsImmediate();
|
||||
}
|
||||
|
||||
void UDPSrcGUI::on_squelchGate_valueChanged(int value)
|
||||
{
|
||||
ui->squelchGateText->setText(tr("%1").arg(value*10.0, 0, 'f', 0));
|
||||
applySettingsImmediate();
|
||||
}
|
||||
|
||||
void UDPSrcGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
||||
{
|
||||
if ((widget == ui->spectrumBox) && (m_udpSrc != 0))
|
||||
|
@ -75,6 +75,7 @@ private slots:
|
||||
void on_gain_valueChanged(int value);
|
||||
void on_volume_valueChanged(int value);
|
||||
void on_squelch_valueChanged(int value);
|
||||
void on_squelchGate_valueChanged(int value);
|
||||
void tick();
|
||||
|
||||
private:
|
||||
@ -111,8 +112,8 @@ private:
|
||||
virtual ~UDPSrcGUI();
|
||||
|
||||
void blockApplySettings(bool block);
|
||||
void applySettings();
|
||||
void applySettingsImmediate();
|
||||
void applySettings(bool force = false);
|
||||
void applySettingsImmediate(bool force = false);
|
||||
void displaySettings();
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
|
@ -236,6 +236,38 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="inputPower">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Input power (dB) to which squelch applies</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-100.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
@ -637,18 +669,40 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="inputPower">
|
||||
<widget class="QDial" name="squelchGate">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Squelch gate (ms)</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="squelchGateText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<width>24</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Input power (dB) to which squelch applies</string>
|
||||
<string>Squelch gate (ms)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-100.0</string>
|
||||
<string>000</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
|
Loading…
Reference in New Issue
Block a user