From 0d7f73f595bed8f8cf39c1ffe3fa396ea9986b46 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 29 Mar 2018 16:57:42 +0200 Subject: [PATCH] Multiple audio support: SSB modulator --- plugins/channeltx/modssb/CMakeLists.txt | 2 + plugins/channeltx/modssb/ssbmod.cpp | 147 ++++++++++++++++---- plugins/channeltx/modssb/ssbmod.h | 3 + plugins/channeltx/modssb/ssbmodgui.cpp | 29 +++- plugins/channeltx/modssb/ssbmodgui.h | 1 + plugins/channeltx/modssb/ssbmodsettings.cpp | 4 +- plugins/channeltx/modssb/ssbmodsettings.h | 2 +- 7 files changed, 154 insertions(+), 34 deletions(-) diff --git a/plugins/channeltx/modssb/CMakeLists.txt b/plugins/channeltx/modssb/CMakeLists.txt index fc652b3a4..b8650ad5b 100644 --- a/plugins/channeltx/modssb/CMakeLists.txt +++ b/plugins/channeltx/modssb/CMakeLists.txt @@ -1,5 +1,7 @@ project(modssb) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + set(modssb_SOURCES ssbmod.cpp ssbmodgui.cpp diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index 51066ace9..a99bde786 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -70,8 +70,11 @@ SSBMod::SSBMod(DeviceSinkAPI *deviceAPI) : { setObjectName(m_channelId); - m_SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_settings.m_audioSampleRate, m_settings.m_bandwidth / m_settings.m_audioSampleRate, m_ssbFftLen); - m_DSBFilter = new fftfilt((2.0f * m_settings.m_bandwidth) / m_settings.m_audioSampleRate, 2 * m_ssbFftLen); + DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue()); + m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getInputSampleRate(); + + m_SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_audioSampleRate, m_settings.m_bandwidth / m_audioSampleRate, m_ssbFftLen); + m_DSBFilter = new fftfilt((2.0f * m_settings.m_bandwidth) / m_audioSampleRate, 2 * m_ssbFftLen); m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size m_DSBFilterBuffer = new Complex[m_ssbFftLen]; memset(m_SSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen>>1)); @@ -87,11 +90,10 @@ SSBMod::SSBMod(DeviceSinkAPI *deviceAPI) : m_magsq = 0.0; - m_toneNco.setFreq(1000.0, m_settings.m_audioSampleRate); - DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue()); + m_toneNco.setFreq(1000.0, m_audioSampleRate); // CW keyer - m_cwKeyer.setSampleRate(m_settings.m_audioSampleRate); + m_cwKeyer.setSampleRate(48000); m_cwKeyer.setWPM(13); m_cwKeyer.setMode(CWKeyerSettings::CWNone); @@ -175,7 +177,7 @@ void SSBMod::pull(Sample& sample) void SSBMod::pullAudio(int nbSamples) { - unsigned int nbSamplesAudio = nbSamples * ((Real) m_settings.m_audioSampleRate / (Real) m_basebandSampleRate); + unsigned int nbSamplesAudio = nbSamples * ((Real) m_audioSampleRate / (Real) m_basebandSampleRate); if (nbSamplesAudio > m_audioBuffer.size()) { @@ -580,9 +582,26 @@ bool SSBMod::handleMessage(const Message& cmd) samplesCount = m_ifstream.tellg() / sizeof(Real); } - MsgReportFileSourceStreamTiming *report; - report = MsgReportFileSourceStreamTiming::create(samplesCount); - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportFileSourceStreamTiming *report; + report = MsgReportFileSourceStreamTiming::create(samplesCount); + getMessageQueueToGUI()->push(report); + } + + return true; + } + else if (DSPConfigureAudio::match(cmd)) + { + DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd; + uint32_t sampleRate = cfg.getSampleRate(); + + qDebug() << "SSBMod::handleMessage: DSPConfigureAudio:" + << " sampleRate: " << sampleRate; + + if (sampleRate != m_audioSampleRate) { + applyAudioSampleRate(sampleRate); + } return true; } @@ -613,9 +632,12 @@ void SSBMod::openFileStream() << " fileSize: " << m_fileSize << "bytes" << " length: " << m_recordLength << " seconds"; - MsgReportFileSourceStreamData *report; - report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportFileSourceStreamData *report; + report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); + getMessageQueueToGUI()->push(report); + } } void SSBMod::seekFileStream(int seekPercentage) @@ -631,6 +653,68 @@ void SSBMod::seekFileStream(int seekPercentage) } } +void SSBMod::applyAudioSampleRate(int sampleRate) +{ + qDebug("SSBMod::applyAudioSampleRate: %d", sampleRate); + + + MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create( + sampleRate, m_settings.m_inputFrequencyOffset); + m_inputMessageQueue.push(channelConfigMsg); + + m_settingsMutex.lock(); + + m_interpolatorDistanceRemain = 0; + m_interpolatorConsumed = false; + m_interpolatorDistance = (Real) sampleRate / (Real) m_outputSampleRate; + m_interpolator.create(48, sampleRate, m_settings.m_bandwidth, 3.0); + + float band = m_settings.m_bandwidth; + float lowCutoff = m_settings.m_lowCutoff; + bool usb = m_settings.m_usb; + + if (band < 0) // negative means LSB + { + band = -band; // turn to positive + lowCutoff = -lowCutoff; + usb = false; // and take note of side band + } + else + { + usb = true; + } + + if (band < 100.0f) // at least 100 Hz + { + band = 100.0f; + lowCutoff = 0; + } + + if (band - lowCutoff < 100.0f) { + lowCutoff = band - 100.0f; + } + + m_SSBFilter->create_filter(lowCutoff / sampleRate, band / sampleRate); + m_DSBFilter->create_dsb_filter((2.0f * band) / sampleRate); + + m_settings.m_bandwidth = band; + m_settings.m_lowCutoff = lowCutoff; + m_settings.m_usb = usb; + + m_toneNco.setFreq(m_settings.m_toneFrequency, sampleRate); + m_cwKeyer.setSampleRate(sampleRate); + + m_settingsMutex.unlock(); + + m_audioSampleRate = sampleRate; + + if (getMessageQueueToGUI()) + { + DSPConfigureAudio *cfg = new DSPConfigureAudio(m_audioSampleRate); + getMessageQueueToGUI()->push(cfg); + } +} + void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force) { qDebug() << "SSBMod::applyChannelSettings:" @@ -651,8 +735,8 @@ void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, m_settingsMutex.lock(); m_interpolatorDistanceRemain = 0; m_interpolatorConsumed = false; - m_interpolatorDistance = (Real) m_settings.m_audioSampleRate / (Real) outputSampleRate; - m_interpolator.create(48, m_settings.m_audioSampleRate, m_settings.m_bandwidth, 3.0); + m_interpolatorDistance = (Real) m_audioSampleRate / (Real) outputSampleRate; + m_interpolator.create(48, m_audioSampleRate, m_settings.m_bandwidth, 3.0); m_settingsMutex.unlock(); } @@ -668,8 +752,7 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force) bool usb = settings.m_usb; if ((settings.m_bandwidth != m_settings.m_bandwidth) || - (settings.m_lowCutoff != m_settings.m_lowCutoff) || - (settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force) + (settings.m_lowCutoff != m_settings.m_lowCutoff) || force) { if (band < 0) // negative means LSB { @@ -695,25 +778,17 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force) m_settingsMutex.lock(); m_interpolatorDistanceRemain = 0; m_interpolatorConsumed = false; - m_interpolatorDistance = (Real) settings.m_audioSampleRate / (Real) m_outputSampleRate; - m_interpolator.create(48, settings.m_audioSampleRate, band, 3.0); - m_SSBFilter->create_filter(lowCutoff / settings.m_audioSampleRate, band / settings.m_audioSampleRate); - m_DSBFilter->create_dsb_filter((2.0f * band) / settings.m_audioSampleRate); + m_interpolatorDistance = (Real) m_audioSampleRate / (Real) m_outputSampleRate; + m_interpolator.create(48, m_audioSampleRate, band, 3.0); + m_SSBFilter->create_filter(lowCutoff / m_audioSampleRate, band / m_audioSampleRate); + m_DSBFilter->create_dsb_filter((2.0f * band) / m_audioSampleRate); m_settingsMutex.unlock(); } - if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || - (settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force) + if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || force) { m_settingsMutex.lock(); - m_toneNco.setFreq(settings.m_toneFrequency, settings.m_audioSampleRate); - m_settingsMutex.unlock(); - } - - if ((settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force) - { - m_settingsMutex.lock(); - m_cwKeyer.setSampleRate(settings.m_audioSampleRate); + m_toneNco.setFreq(settings.m_toneFrequency, m_audioSampleRate); m_settingsMutex.unlock(); } @@ -759,6 +834,18 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force) m_inAGC.setStepDownDelay(settings.m_agcThresholdDelay); } + if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) + { + AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); + int audioDeviceIndex = audioDeviceManager->getInputDeviceIndex(settings.m_audioDeviceName); + audioDeviceManager->addAudioSource(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex); + uint32_t audioSampleRate = audioDeviceManager->getInputSampleRate(audioDeviceIndex); + + if (m_audioSampleRate != audioSampleRate) { + applyAudioSampleRate(audioSampleRate); + } + } + m_settings = settings; m_settings.m_bandwidth = band; m_settings.m_lowCutoff = lowCutoff; diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index 3929813a7..263420c1e 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -248,6 +248,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; } CWKeyer *getCWKeyer() { return &m_cwKeyer; } @@ -279,6 +280,7 @@ private: int m_outputSampleRate; int m_inputFrequencyOffset; SSBModSettings m_settings; + quint32 m_audioSampleRate; NCOF m_carrierNco; NCOF m_toneNco; @@ -327,6 +329,7 @@ private: static const int m_levelNbSamples; + void applyAudioSampleRate(int sampleRate); void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false); void applySettings(const SSBModSettings& settings, bool force = false); void pullAF(Complex& sample); diff --git a/plugins/channeltx/modssb/ssbmodgui.cpp b/plugins/channeltx/modssb/ssbmodgui.cpp index 2ad877ce9..6f2819034 100644 --- a/plugins/channeltx/modssb/ssbmodgui.cpp +++ b/plugins/channeltx/modssb/ssbmodgui.cpp @@ -30,6 +30,9 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "gui/crightclickenabler.h" +#include "gui/audioselectdialog.h" #include "mainwindow.h" SSBModGUI* SSBModGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx) @@ -108,6 +111,12 @@ bool SSBModGUI::handleMessage(const Message& message) updateWithStreamTime(); return true; } + else if (DSPConfigureAudio::match(message)) + { + qDebug("SSBModGUI::handleMessage: DSPConfigureAudio: %d", m_ssbMod->getAudioSampleRate()); + applyBandwidths(); // will update spectrum details with new sample rate + return true; + } else { return false; @@ -379,6 +388,9 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->mic); + 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); @@ -453,10 +465,10 @@ void SSBModGUI::applyBandwidths(bool force) { bool dsb = ui->dsb->isChecked(); int spanLog2 = ui->spanLog2->value(); - m_spectrumRate = 48000 / (1<getAudioSampleRate() / (1<BW->value(); int lw = ui->lowCut->value(); - int bwMax = 480/(1<getAudioSampleRate() / (100*(1<getAudioDeviceManager(), m_settings.m_audioDeviceName, true); // true for input + audioSelect.exec(); + + if (audioSelect.m_selected) + { + m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName; + applySettings(); + } +} + void SSBModGUI::tick() { double powDb = CalcDb::dbPower(m_ssbMod->getMagSq()); diff --git a/plugins/channeltx/modssb/ssbmodgui.h b/plugins/channeltx/modssb/ssbmodgui.h index 55ba7360c..3ebb0d225 100644 --- a/plugins/channeltx/modssb/ssbmodgui.h +++ b/plugins/channeltx/modssb/ssbmodgui.h @@ -129,6 +129,7 @@ private slots: void onWidgetRolled(QWidget* widget, bool rollDown); void configureFileName(); + void audioSelect(); void tick(); }; diff --git a/plugins/channeltx/modssb/ssbmodsettings.cpp b/plugins/channeltx/modssb/ssbmodsettings.cpp index f84a28b48..09fea178c 100644 --- a/plugins/channeltx/modssb/ssbmodsettings.cpp +++ b/plugins/channeltx/modssb/ssbmodsettings.cpp @@ -51,7 +51,6 @@ void SSBModSettings::resetToDefaults() m_usb = true; m_toneFrequency = 1000.0; m_volumeFactor = 1.0; - m_audioSampleRate = DSPEngine::instance()->getDefaultAudioSampleRate(); m_spanLog2 = 3; m_audioBinaural = false; m_audioFlipChannels = false; @@ -69,6 +68,7 @@ void SSBModSettings::resetToDefaults() m_udpAddress = "127.0.0.1"; m_udpPort = 9999; m_title = "SSB Modulator"; + m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; } QByteArray SSBModSettings::serialize() const @@ -106,6 +106,7 @@ QByteArray SSBModSettings::serialize() const } s.writeString(19, m_title); + s.writeString(20, m_audioDeviceName); return s.final(); } @@ -171,6 +172,7 @@ bool SSBModSettings::deserialize(const QByteArray& data) } d.readString(19, &m_title, "SSB Modulator"); + d.readString(20, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName); return true; } diff --git a/plugins/channeltx/modssb/ssbmodsettings.h b/plugins/channeltx/modssb/ssbmodsettings.h index 2cab6cb18..1266b0edc 100644 --- a/plugins/channeltx/modssb/ssbmodsettings.h +++ b/plugins/channeltx/modssb/ssbmodsettings.h @@ -34,7 +34,6 @@ struct SSBModSettings bool m_usb; float m_toneFrequency; float m_volumeFactor; - quint32 m_audioSampleRate; int m_spanLog2; bool m_audioBinaural; bool m_audioFlipChannels; @@ -54,6 +53,7 @@ struct SSBModSettings uint16_t m_udpPort; QString m_title; + QString m_audioDeviceName; Serializable *m_channelMarker; Serializable *m_spectrumGUI;