1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-09-27 07:16:48 -04:00

Multiple audio support: SSB modulator

This commit is contained in:
f4exb 2018-03-29 16:57:42 +02:00
parent eb57c1aca6
commit 0d7f73f595
7 changed files with 154 additions and 34 deletions

View File

@ -1,5 +1,7 @@
project(modssb) project(modssb)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(modssb_SOURCES set(modssb_SOURCES
ssbmod.cpp ssbmod.cpp
ssbmodgui.cpp ssbmodgui.cpp

View File

@ -70,8 +70,11 @@ SSBMod::SSBMod(DeviceSinkAPI *deviceAPI) :
{ {
setObjectName(m_channelId); 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); DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
m_DSBFilter = new fftfilt((2.0f * m_settings.m_bandwidth) / m_settings.m_audioSampleRate, 2 * m_ssbFftLen); 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_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size
m_DSBFilterBuffer = new Complex[m_ssbFftLen]; m_DSBFilterBuffer = new Complex[m_ssbFftLen];
memset(m_SSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen>>1)); memset(m_SSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen>>1));
@ -87,11 +90,10 @@ SSBMod::SSBMod(DeviceSinkAPI *deviceAPI) :
m_magsq = 0.0; m_magsq = 0.0;
m_toneNco.setFreq(1000.0, m_settings.m_audioSampleRate); m_toneNco.setFreq(1000.0, m_audioSampleRate);
DSPEngine::instance()->getAudioDeviceManager()->addAudioSource(&m_audioFifo, getInputMessageQueue());
// CW keyer // CW keyer
m_cwKeyer.setSampleRate(m_settings.m_audioSampleRate); m_cwKeyer.setSampleRate(48000);
m_cwKeyer.setWPM(13); m_cwKeyer.setWPM(13);
m_cwKeyer.setMode(CWKeyerSettings::CWNone); m_cwKeyer.setMode(CWKeyerSettings::CWNone);
@ -175,7 +177,7 @@ void SSBMod::pull(Sample& sample)
void SSBMod::pullAudio(int nbSamples) 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()) if (nbSamplesAudio > m_audioBuffer.size())
{ {
@ -580,9 +582,26 @@ bool SSBMod::handleMessage(const Message& cmd)
samplesCount = m_ifstream.tellg() / sizeof(Real); samplesCount = m_ifstream.tellg() / sizeof(Real);
} }
MsgReportFileSourceStreamTiming *report; if (getMessageQueueToGUI())
report = MsgReportFileSourceStreamTiming::create(samplesCount); {
getMessageQueueToGUI()->push(report); 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; return true;
} }
@ -613,9 +632,12 @@ void SSBMod::openFileStream()
<< " fileSize: " << m_fileSize << "bytes" << " fileSize: " << m_fileSize << "bytes"
<< " length: " << m_recordLength << " seconds"; << " length: " << m_recordLength << " seconds";
MsgReportFileSourceStreamData *report; if (getMessageQueueToGUI())
report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); {
getMessageQueueToGUI()->push(report); MsgReportFileSourceStreamData *report;
report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength);
getMessageQueueToGUI()->push(report);
}
} }
void SSBMod::seekFileStream(int seekPercentage) 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) void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
{ {
qDebug() << "SSBMod::applyChannelSettings:" qDebug() << "SSBMod::applyChannelSettings:"
@ -651,8 +735,8 @@ void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate,
m_settingsMutex.lock(); m_settingsMutex.lock();
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorConsumed = false; m_interpolatorConsumed = false;
m_interpolatorDistance = (Real) m_settings.m_audioSampleRate / (Real) outputSampleRate; m_interpolatorDistance = (Real) m_audioSampleRate / (Real) outputSampleRate;
m_interpolator.create(48, m_settings.m_audioSampleRate, m_settings.m_bandwidth, 3.0); m_interpolator.create(48, m_audioSampleRate, m_settings.m_bandwidth, 3.0);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
@ -668,8 +752,7 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force)
bool usb = settings.m_usb; bool usb = settings.m_usb;
if ((settings.m_bandwidth != m_settings.m_bandwidth) || if ((settings.m_bandwidth != m_settings.m_bandwidth) ||
(settings.m_lowCutoff != m_settings.m_lowCutoff) || (settings.m_lowCutoff != m_settings.m_lowCutoff) || force)
(settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force)
{ {
if (band < 0) // negative means LSB if (band < 0) // negative means LSB
{ {
@ -695,25 +778,17 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force)
m_settingsMutex.lock(); m_settingsMutex.lock();
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorConsumed = false; m_interpolatorConsumed = false;
m_interpolatorDistance = (Real) settings.m_audioSampleRate / (Real) m_outputSampleRate; m_interpolatorDistance = (Real) m_audioSampleRate / (Real) m_outputSampleRate;
m_interpolator.create(48, settings.m_audioSampleRate, band, 3.0); m_interpolator.create(48, m_audioSampleRate, band, 3.0);
m_SSBFilter->create_filter(lowCutoff / settings.m_audioSampleRate, band / settings.m_audioSampleRate); m_SSBFilter->create_filter(lowCutoff / m_audioSampleRate, band / m_audioSampleRate);
m_DSBFilter->create_dsb_filter((2.0f * band) / settings.m_audioSampleRate); m_DSBFilter->create_dsb_filter((2.0f * band) / m_audioSampleRate);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || force)
(settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force)
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
m_toneNco.setFreq(settings.m_toneFrequency, settings.m_audioSampleRate); m_toneNco.setFreq(settings.m_toneFrequency, m_audioSampleRate);
m_settingsMutex.unlock();
}
if ((settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force)
{
m_settingsMutex.lock();
m_cwKeyer.setSampleRate(settings.m_audioSampleRate);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
@ -759,6 +834,18 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force)
m_inAGC.setStepDownDelay(settings.m_agcThresholdDelay); 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 = settings;
m_settings.m_bandwidth = band; m_settings.m_bandwidth = band;
m_settings.m_lowCutoff = lowCutoff; m_settings.m_lowCutoff = lowCutoff;

View File

@ -248,6 +248,7 @@ public:
virtual QByteArray serialize() const; virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data); virtual bool deserialize(const QByteArray& data);
uint32_t getAudioSampleRate() const { return m_audioSampleRate; }
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
CWKeyer *getCWKeyer() { return &m_cwKeyer; } CWKeyer *getCWKeyer() { return &m_cwKeyer; }
@ -279,6 +280,7 @@ private:
int m_outputSampleRate; int m_outputSampleRate;
int m_inputFrequencyOffset; int m_inputFrequencyOffset;
SSBModSettings m_settings; SSBModSettings m_settings;
quint32 m_audioSampleRate;
NCOF m_carrierNco; NCOF m_carrierNco;
NCOF m_toneNco; NCOF m_toneNco;
@ -327,6 +329,7 @@ private:
static const int m_levelNbSamples; static const int m_levelNbSamples;
void applyAudioSampleRate(int sampleRate);
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false); void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force = false);
void applySettings(const SSBModSettings& settings, bool force = false); void applySettings(const SSBModSettings& settings, bool force = false);
void pullAF(Complex& sample); void pullAF(Complex& sample);

View File

@ -30,6 +30,9 @@
#include "util/simpleserializer.h" #include "util/simpleserializer.h"
#include "util/db.h" #include "util/db.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "gui/crightclickenabler.h"
#include "gui/audioselectdialog.h"
#include "mainwindow.h" #include "mainwindow.h"
SSBModGUI* SSBModGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx) SSBModGUI* SSBModGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx)
@ -108,6 +111,12 @@ bool SSBModGUI::handleMessage(const Message& message)
updateWithStreamTime(); updateWithStreamTime();
return true; 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 else
{ {
return false; return false;
@ -379,6 +388,9 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); 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->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
@ -453,10 +465,10 @@ void SSBModGUI::applyBandwidths(bool force)
{ {
bool dsb = ui->dsb->isChecked(); bool dsb = ui->dsb->isChecked();
int spanLog2 = ui->spanLog2->value(); int spanLog2 = ui->spanLog2->value();
m_spectrumRate = 48000 / (1<<spanLog2); m_spectrumRate = m_ssbMod->getAudioSampleRate() / (1<<spanLog2);
int bw = ui->BW->value(); int bw = ui->BW->value();
int lw = ui->lowCut->value(); int lw = ui->lowCut->value();
int bwMax = 480/(1<<spanLog2); int bwMax = m_ssbMod->getAudioSampleRate() / (100*(1<<spanLog2));
int tickInterval = m_spectrumRate / 1200; int tickInterval = m_spectrumRate / 1200;
tickInterval = tickInterval == 0 ? 1 : tickInterval; tickInterval = tickInterval == 0 ? 1 : tickInterval;
@ -668,6 +680,19 @@ void SSBModGUI::enterEvent(QEvent*)
m_channelMarker.setHighlighted(true); m_channelMarker.setHighlighted(true);
} }
void SSBModGUI::audioSelect()
{
qDebug("SSBModGUI::audioSelect");
AudioSelectDialog audioSelect(DSPEngine::instance()->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() void SSBModGUI::tick()
{ {
double powDb = CalcDb::dbPower(m_ssbMod->getMagSq()); double powDb = CalcDb::dbPower(m_ssbMod->getMagSq());

View File

@ -129,6 +129,7 @@ private slots:
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void configureFileName(); void configureFileName();
void audioSelect();
void tick(); void tick();
}; };

View File

@ -51,7 +51,6 @@ void SSBModSettings::resetToDefaults()
m_usb = true; m_usb = true;
m_toneFrequency = 1000.0; m_toneFrequency = 1000.0;
m_volumeFactor = 1.0; m_volumeFactor = 1.0;
m_audioSampleRate = DSPEngine::instance()->getDefaultAudioSampleRate();
m_spanLog2 = 3; m_spanLog2 = 3;
m_audioBinaural = false; m_audioBinaural = false;
m_audioFlipChannels = false; m_audioFlipChannels = false;
@ -69,6 +68,7 @@ void SSBModSettings::resetToDefaults()
m_udpAddress = "127.0.0.1"; m_udpAddress = "127.0.0.1";
m_udpPort = 9999; m_udpPort = 9999;
m_title = "SSB Modulator"; m_title = "SSB Modulator";
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
} }
QByteArray SSBModSettings::serialize() const QByteArray SSBModSettings::serialize() const
@ -106,6 +106,7 @@ QByteArray SSBModSettings::serialize() const
} }
s.writeString(19, m_title); s.writeString(19, m_title);
s.writeString(20, m_audioDeviceName);
return s.final(); return s.final();
} }
@ -171,6 +172,7 @@ bool SSBModSettings::deserialize(const QByteArray& data)
} }
d.readString(19, &m_title, "SSB Modulator"); d.readString(19, &m_title, "SSB Modulator");
d.readString(20, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
return true; return true;
} }

View File

@ -34,7 +34,6 @@ struct SSBModSettings
bool m_usb; bool m_usb;
float m_toneFrequency; float m_toneFrequency;
float m_volumeFactor; float m_volumeFactor;
quint32 m_audioSampleRate;
int m_spanLog2; int m_spanLog2;
bool m_audioBinaural; bool m_audioBinaural;
bool m_audioFlipChannels; bool m_audioFlipChannels;
@ -54,6 +53,7 @@ struct SSBModSettings
uint16_t m_udpPort; uint16_t m_udpPort;
QString m_title; QString m_title;
QString m_audioDeviceName;
Serializable *m_channelMarker; Serializable *m_channelMarker;
Serializable *m_spectrumGUI; Serializable *m_spectrumGUI;