1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 01:55:48 -05:00

Multiple audio support: SSB demodulator

This commit is contained in:
f4exb 2018-03-27 11:17:11 +02:00
parent d683c90c43
commit 4fbb8f74c8
16 changed files with 129 additions and 62 deletions

View File

@ -223,6 +223,8 @@ bool AMDemod::handleMessage(const Message& cmd)
void AMDemod::applyAudioSampleRate(int sampleRate)
{
qDebug("AMDemod::applyAudioSampleRate: %d", sampleRate);
MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create(
sampleRate, m_settings.m_inputFrequencyOffset);
m_inputMessageQueue.push(channelConfigMsg);

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<width>396</width>
<height>170</height>
</rect>
</property>
@ -42,7 +42,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<width>390</width>
<height>131</height>
</rect>
</property>

View File

@ -1,5 +1,7 @@
project(ssb)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(ssb_SOURCES
ssbdemod.cpp
ssbdemodgui.cpp

View File

@ -45,13 +45,13 @@ Toggles between SSB (icon with one sideband signal) and DSB (icon with double si
<h3>8: Spectrum display frequency span</h3>
The 48 kHz channel sample rate is further decimated by powers of two for the spectrum display and in channel filter limits. This effectively sets the total available bandwidth depending on the decimation:
The audio sample rate SR is further decimated by powers of two for the spectrum display and in channel filter limits. This effectively sets the total available bandwidth depending on the decimation:
- 1 (no decimation): 24 kHz (SSB) or 48 kHz (DSB)
- 2: 12 kHz (SSB) or 24 kHz (DSB)
- 4: 6 kHz (SSB) or 12 kHz (DSB)
- 8: 3 kHz (SSB) or 6 kHz (DSB)
- 16: 1.5 kHz (SSB) or 3 kHz (DSB)
- 1 (no decimation): SR/2 (SSB) or SR (DSB)
- 2: SR/4 (SSB) or SR/2 (DSB)
- 4: SR/8 (SSB) or SR/4 (DSB)
- 8: SR/16 (SSB) or SR/8 (DSB)
- 16: SR/32 (SSB) or SR/16 (DSB)
The span value display is set as follows depending on the SSB or DSB mode:

View File

@ -87,7 +87,6 @@ SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen);
DSBFilter = new fftfilt((2.0f * m_Bandwidth) / m_audioSampleRate, 2 * ssbFftLen);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioNetSink = new AudioNetSink(0); // parent thread allocated dynamically - no RTP
m_audioNetSink->setDestination(m_settings.m_udpAddress, m_settings.m_udpPort);
@ -336,6 +335,20 @@ bool SSBDemod::handleMessage(const Message& cmd)
m_audioNetSink->moveToThread(const_cast<QThread*>(thread)); // use the thread for udp sinks
return true;
}
else if (DSPConfigureAudio::match(cmd))
{
DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
uint32_t sampleRate = cfg.getSampleRate();
qDebug() << "SSBDemod::handleMessage: DSPConfigureAudio:"
<< " sampleRate: " << sampleRate;
if (sampleRate != m_audioSampleRate) {
applyAudioSampleRate(sampleRate);
}
return true;
}
else if (DSPSignalNotification::match(cmd))
{
return true;
@ -370,7 +383,7 @@ void SSBDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffse
m_settingsMutex.lock();
m_interpolator.create(16, inputSampleRate, m_Bandwidth * 1.5f, 2.0f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_audioSampleRate;
m_settingsMutex.unlock();
}
@ -378,6 +391,31 @@ void SSBDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffse
m_inputFrequencyOffset = inputFrequencyOffset;
}
void SSBDemod::applyAudioSampleRate(int sampleRate)
{
qDebug("SSBDemod::applyAudioSampleRate: %d", sampleRate);
MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create(
sampleRate, m_settings.m_inputFrequencyOffset);
m_inputMessageQueue.push(channelConfigMsg);
m_settingsMutex.lock();
m_interpolator.create(16, m_inputSampleRate, m_Bandwidth * 1.5f, 2.0f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) sampleRate;
SSBFilter->create_filter(m_LowCutoff / (float) sampleRate, m_Bandwidth / (float) sampleRate);
DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) sampleRate);
m_settingsMutex.unlock();
m_audioSampleRate = sampleRate;
if (m_guiMessageQueue) // forward to GUI if any
{
DSPConfigureAudio *cfg = new DSPConfigureAudio(m_audioSampleRate);
m_guiMessageQueue->push(cfg);
}
}
void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
{
qDebug() << "SSBDemod::applySettings:"
@ -395,17 +433,17 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
<< " m_agcClamping: " << settings.m_agcClamping
<< " m_agcTimeLog2: " << settings.m_agcTimeLog2
<< " agcPowerThreshold: " << settings.m_agcPowerThreshold
<< " agcThresholdGate: " << settings.m_agcThresholdGate;
<< " agcThresholdGate: " << settings.m_agcThresholdGate
<< " m_audioDeviceName: " << settings.m_audioDeviceName
<< " force: " << force;
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
(m_settings.m_lowCutoff != settings.m_lowCutoff) ||
(m_settings.m_audioSampleRate != settings.m_audioSampleRate) || force)
(m_settings.m_lowCutoff != settings.m_lowCutoff) || force)
{
float band, lowCutoff;
band = settings.m_rfBandwidth;
lowCutoff = settings.m_lowCutoff;
m_audioSampleRate = settings.m_audioSampleRate;
if (band < 0) {
band = -band;
@ -427,7 +465,7 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
m_settingsMutex.lock();
m_interpolator.create(16, m_inputSampleRate, m_Bandwidth * 1.5f, 2.0f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) m_settings.m_audioSampleRate;
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) 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);
m_settingsMutex.unlock();
@ -490,6 +528,18 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
m_audioNetSink->setDestination(settings.m_udpAddress, settings.m_udpPort);
}
if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
{
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
if (m_audioSampleRate != audioSampleRate) {
applyAudioSampleRate(audioSampleRate);
}
}
m_spanLog2 = settings.m_spanLog2;
m_audioBinaual = settings.m_audioBinaural;
m_audioFlipChannels = settings.m_audioFlipChannels;

View File

@ -120,6 +120,7 @@ public:
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
uint32_t getAudioSampleRate() const { return m_audioSampleRate; }
double getMagSq() const { return m_magsq; }
bool getAudioActive() const { return m_audioActive; }
@ -282,6 +283,7 @@ private:
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
void applySettings(const SSBDemodSettings& settings, bool force = false);
void applyAudioSampleRate(int sampleRate);
};
#endif // INCLUDE_SSBDEMOD_H

View File

@ -9,11 +9,14 @@
#include "ui_ssbdemodgui.h"
#include "dsp/spectrumvis.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "gui/glspectrum.h"
#include "gui/basicchannelsettingsdialog.h"
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "util/db.h"
#include "gui/crightclickenabler.h"
#include "gui/audioselectdialog.h"
#include "mainwindow.h"
#include "ssbdemod.h"
@ -77,9 +80,31 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
}
}
bool SSBDemodGUI::handleMessage(const Message& message __attribute__((unused)))
bool SSBDemodGUI::handleMessage(const Message& message)
{
return false;
if (DSPConfigureAudio::match(message))
{
qDebug("SSBDemodGUI::handleMessage: DSPConfigureAudio: %d", m_ssbDemod->getAudioSampleRate());
applyBandwidths(); // will update spectrum details with new sample rate
return true;
}
else
{
return false;
}
}
void SSBDemodGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
delete message;
}
}
}
void SSBDemodGUI::channelMarkerChangedByCursor()
@ -249,6 +274,9 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
m_ssbDemod->setMessageQueueToGUI(getInputMessageQueue());
m_ssbDemod->setSampleSink(m_spectrumVis);
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
@ -284,6 +312,7 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
@ -316,7 +345,7 @@ void SSBDemodGUI::applySettings(bool force)
if (m_doApplySettings)
{
SSBDemod::MsgConfigureChannelizer* channelConfigMsg = SSBDemod::MsgConfigureChannelizer::create(
48000, m_channelMarker.getCenterFrequency());
m_ssbDemod->getAudioSampleRate(), m_channelMarker.getCenterFrequency());
m_ssbDemod->getInputMessageQueue()->push(channelConfigMsg);
SSBDemod::MsgConfigureSSBDemod* message = SSBDemod::MsgConfigureSSBDemod::create( m_settings, force);
@ -328,10 +357,10 @@ void SSBDemodGUI::applyBandwidths(bool force)
{
bool dsb = ui->dsb->isChecked();
int spanLog2 = ui->spanLog2->value();
m_spectrumRate = 48000 / (1<<spanLog2);
m_spectrumRate = m_ssbDemod->getAudioSampleRate() / (1<<spanLog2);
int bw = ui->BW->value();
int lw = ui->lowCut->value();
int bwMax = 480/(1<<spanLog2);
int bwMax = m_ssbDemod->getAudioSampleRate() / (100*(1<<spanLog2));
int tickInterval = m_spectrumRate / 1200;
tickInterval = tickInterval == 0 ? 1 : tickInterval;
@ -545,6 +574,19 @@ void SSBDemodGUI::enterEvent(QEvent*)
m_channelMarker.setHighlighted(true);
}
void SSBDemodGUI::audioSelect()
{
qDebug("SSBDemodGUI::audioSelect");
AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName);
audioSelect.exec();
if (audioSelect.m_selected)
{
m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName;
applySettings();
}
}
void SSBDemodGUI::tick()
{
double magsqAvg, magsqPeak;

View File

@ -98,6 +98,8 @@ private slots:
void on_copyAudioToUDP_toggled(bool copy);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();
void audioSelect();
void tick();
};

View File

@ -6,19 +6,19 @@
<rect>
<x>0</x>
<y>0</y>
<width>413</width>
<width>412</width>
<height>190</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<width>412</width>
<height>0</height>
</size>
</property>

View File

@ -53,11 +53,11 @@ void SSBDemodSettings::resetToDefaults()
m_volume = 3.0;
m_spanLog2 = 3;
m_inputFrequencyOffset = 0;
m_audioSampleRate = DSPEngine::instance()->getDefaultAudioSampleRate();
m_udpAddress = "127.0.0.1";
m_udpPort = 9999;
m_rgbColor = QColor(0, 255, 0).rgb();
m_title = "SSB Demodulator";
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
}
QByteArray SSBDemodSettings::serialize() const
@ -83,6 +83,7 @@ QByteArray SSBDemodSettings::serialize() const
s.writeS32(14, m_agcThresholdGate);
s.writeBool(15, m_agcClamping);
s.writeString(16, m_title);
s.writeString(17, m_audioDeviceName);
return s.final();
}
@ -127,6 +128,7 @@ bool SSBDemodSettings::deserialize(const QByteArray& data)
d.readS32(14, &m_agcThresholdGate, 4);
d.readBool(15, &m_agcClamping, false);
d.readString(16, &m_title, "SSB Demodulator");
d.readString(17, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
return true;
}

View File

@ -24,7 +24,6 @@ class Serializable;
struct SSBDemodSettings
{
qint32 m_inputFrequencyOffset;
quint32 m_audioSampleRate;
Real m_rfBandwidth;
Real m_lowCutoff;
Real m_volume;
@ -43,6 +42,7 @@ struct SSBDemodSettings
quint16 m_udpPort;
quint32 m_rgbColor;
QString m_title;
QString m_audioDeviceName;
Serializable *m_channelMarker;
Serializable *m_spectrumGUI;

View File

@ -1539,9 +1539,6 @@ margin-bottom: 20px;
"copyAudioToUDP" : {
"type" : "integer"
},
"copyAudioUseRTP" : {
"type" : "integer"
},
"udpAddress" : {
"type" : "string"
},
@ -18063,7 +18060,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2018-03-27T01:15:44.809+02:00
Generated 2018-03-27T09:54:41.046+02:00
</div>
</div>
</div>

View File

@ -37,8 +37,6 @@ NFMDemodSettings:
type: integer
copyAudioToUDP:
type: integer
copyAudioUseRTP:
type: integer
udpAddress:
type: string
udpPort:

View File

@ -1539,9 +1539,6 @@ margin-bottom: 20px;
"copyAudioToUDP" : {
"type" : "integer"
},
"copyAudioUseRTP" : {
"type" : "integer"
},
"udpAddress" : {
"type" : "string"
},
@ -18063,7 +18060,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2018-03-27T01:15:44.809+02:00
Generated 2018-03-27T09:54:41.046+02:00
</div>
</div>
</div>

View File

@ -54,8 +54,6 @@ SWGNFMDemodSettings::SWGNFMDemodSettings() {
m_audio_sample_rate_isSet = false;
copy_audio_to_udp = 0;
m_copy_audio_to_udp_isSet = false;
copy_audio_use_rtp = 0;
m_copy_audio_use_rtp_isSet = false;
udp_address = nullptr;
m_udp_address_isSet = false;
udp_port = 0;
@ -98,8 +96,6 @@ SWGNFMDemodSettings::init() {
m_audio_sample_rate_isSet = false;
copy_audio_to_udp = 0;
m_copy_audio_to_udp_isSet = false;
copy_audio_use_rtp = 0;
m_copy_audio_use_rtp_isSet = false;
udp_address = new QString("");
m_udp_address_isSet = false;
udp_port = 0;
@ -125,7 +121,6 @@ SWGNFMDemodSettings::cleanup() {
if(udp_address != nullptr) {
delete udp_address;
}
@ -173,8 +168,6 @@ SWGNFMDemodSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&copy_audio_to_udp, pJson["copyAudioToUDP"], "qint32", "");
::SWGSDRangel::setValue(&copy_audio_use_rtp, pJson["copyAudioUseRTP"], "qint32", "");
::SWGSDRangel::setValue(&udp_address, pJson["udpAddress"], "QString", "QString");
::SWGSDRangel::setValue(&udp_port, pJson["udpPort"], "qint32", "");
@ -238,9 +231,6 @@ SWGNFMDemodSettings::asJsonObject() {
if(m_copy_audio_to_udp_isSet){
obj->insert("copyAudioToUDP", QJsonValue(copy_audio_to_udp));
}
if(m_copy_audio_use_rtp_isSet){
obj->insert("copyAudioUseRTP", QJsonValue(copy_audio_use_rtp));
}
if(udp_address != nullptr && *udp_address != QString("")){
toJsonValue(QString("udpAddress"), udp_address, obj, QString("QString"));
}
@ -387,16 +377,6 @@ SWGNFMDemodSettings::setCopyAudioToUdp(qint32 copy_audio_to_udp) {
this->m_copy_audio_to_udp_isSet = true;
}
qint32
SWGNFMDemodSettings::getCopyAudioUseRtp() {
return copy_audio_use_rtp;
}
void
SWGNFMDemodSettings::setCopyAudioUseRtp(qint32 copy_audio_use_rtp) {
this->copy_audio_use_rtp = copy_audio_use_rtp;
this->m_copy_audio_use_rtp_isSet = true;
}
QString*
SWGNFMDemodSettings::getUdpAddress() {
return udp_address;
@ -455,7 +435,6 @@ SWGNFMDemodSettings::isSet(){
if(m_ctcss_index_isSet){ isObjectUpdated = true; break;}
if(m_audio_sample_rate_isSet){ isObjectUpdated = true; break;}
if(m_copy_audio_to_udp_isSet){ isObjectUpdated = true; break;}
if(m_copy_audio_use_rtp_isSet){ isObjectUpdated = true; break;}
if(udp_address != nullptr && *udp_address != QString("")){ isObjectUpdated = true; break;}
if(m_udp_port_isSet){ isObjectUpdated = true; break;}
if(m_rgb_color_isSet){ isObjectUpdated = true; break;}

View File

@ -81,9 +81,6 @@ public:
qint32 getCopyAudioToUdp();
void setCopyAudioToUdp(qint32 copy_audio_to_udp);
qint32 getCopyAudioUseRtp();
void setCopyAudioUseRtp(qint32 copy_audio_use_rtp);
QString* getUdpAddress();
void setUdpAddress(QString* udp_address);
@ -139,9 +136,6 @@ private:
qint32 copy_audio_to_udp;
bool m_copy_audio_to_udp_isSet;
qint32 copy_audio_use_rtp;
bool m_copy_audio_use_rtp_isSet;
QString* udp_address;
bool m_udp_address_isSet;