diff --git a/Readme.md b/Readme.md index 74a50db21..4f7dd8b3d 100644 --- a/Readme.md +++ b/Readme.md @@ -78,7 +78,8 @@ Done since the fork - SSB bandwidth can now be tuned in steps of 100 Hz - NFM and SSB receiver in focus trigger the display of the central frequency line on the spectrum frequency scale thus facilitating its identification - Added AM demod so now you can listen to air traffic! - - Added the possibility to change the brightness and/or color of the grid. + - Added the possibility to change the brightness and/or color of the grid. + - Make the low cutoff frequency of the SSB filter variable so it can be used for CW also. ===== To Do diff --git a/include-gpl/gui/glspectrum.h b/include-gpl/gui/glspectrum.h index 918cbb642..3f2ac8a60 100644 --- a/include-gpl/gui/glspectrum.h +++ b/include-gpl/gui/glspectrum.h @@ -54,11 +54,13 @@ private: struct ChannelMarkerState { ChannelMarker* m_channelMarker; QRectF m_glRect; + QRectF m_glRectDsb; QRect m_rect; ChannelMarkerState(ChannelMarker* channelMarker) : m_channelMarker(channelMarker), - m_glRect() + m_glRect(), + m_glRectDsb() { } }; QList m_channelMarkerStates; @@ -150,8 +152,6 @@ private: void enterEvent(QEvent* event); void leaveEvent(QEvent* event); - float getCenterFreqLineRelPos(ChannelMarker *channelMarker); - private slots: void tick(); void channelMarkerChanged(); diff --git a/include/dsp/channelmarker.h b/include/dsp/channelmarker.h index d5b43bd4d..d5d9dffc8 100644 --- a/include/dsp/channelmarker.h +++ b/include/dsp/channelmarker.h @@ -27,6 +27,9 @@ public: void setBandwidth(int bandwidth); int getBandwidth() const { return m_bandwidth; } + void setLowCutoff(int lowCutoff); + int getLowCutoff() const { return m_lowCutoff; } + void setSidebands(sidebands_t sidebands); sidebands_t getSidebands() const { return m_sidebands; } @@ -46,6 +49,7 @@ protected: QString m_title; int m_centerFrequency; int m_bandwidth; + int m_lowCutoff; sidebands_t m_sidebands; bool m_visible; bool m_highlighted; diff --git a/plugins/channel/ssb/ssbdemod.cpp b/plugins/channel/ssb/ssbdemod.cpp index 6b53a33af..041c6b35e 100644 --- a/plugins/channel/ssb/ssbdemod.cpp +++ b/plugins/channel/ssb/ssbdemod.cpp @@ -22,6 +22,8 @@ #include "audio/audiooutput.h" #include "dsp/dspcommands.h" +#include + MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) SSBDemod::SSBDemod(AudioFifo* audioFifo, SampleSink* sampleSink) : @@ -29,6 +31,7 @@ SSBDemod::SSBDemod(AudioFifo* audioFifo, SampleSink* sampleSink) : m_audioFifo(audioFifo) { m_Bandwidth = 5000; + m_LowCutoff = 300; m_volume = 2.0; m_sampleRate = 96000; m_frequency = 0; @@ -41,7 +44,7 @@ SSBDemod::SSBDemod(AudioFifo* audioFifo, SampleSink* sampleSink) : m_undersampleCount = 0; m_usb = true; - SSBFilter = new fftfilt(0.01, m_Bandwidth / 48000.0, ssbFftLen); + SSBFilter = new fftfilt(m_LowCutoff / 48000.0, m_Bandwidth / 48000.0, ssbFftLen); // if (!USBFilter) segfault; } @@ -50,9 +53,9 @@ SSBDemod::~SSBDemod() if (SSBFilter) delete SSBFilter; } -void SSBDemod::configure(MessageQueue* messageQueue, Real Bandwidth, Real volume) +void SSBDemod::configure(MessageQueue* messageQueue, Real Bandwidth, Real LowCutoff, Real volume) { - Message* cmd = MsgConfigureSSBDemod::create(Bandwidth, volume); + Message* cmd = MsgConfigureSSBDemod::create(Bandwidth, LowCutoff, volume); cmd->submit(messageQueue, this); } @@ -110,7 +113,7 @@ void SSBDemod::stop() bool SSBDemod::handleMessage(Message* cmd) { - float band; + float band, lowCutoff; if(DSPSignalNotification::match(cmd)) { DSPSignalNotification* signal = (DSPSignalNotification*)cmd; @@ -125,17 +128,26 @@ bool SSBDemod::handleMessage(Message* cmd) MsgConfigureSSBDemod* cfg = (MsgConfigureSSBDemod*)cmd; band = cfg->getBandwidth(); + lowCutoff = cfg->getLoCutoff(); + if (band < 0) { band = -band; + lowCutoff = -lowCutoff; m_usb = false; } else m_usb = true; - if (band < 500.0f) - band = 500.0f; + + if (band < 100.0f) + { + band = 100.0f; + lowCutoff = 0; + } + m_Bandwidth = band; + m_LowCutoff = lowCutoff; m_interpolator.create(16, m_sampleRate, band * 2.0f); - SSBFilter->create_filter(0.3f / 48.0f, m_Bandwidth / 48000.0f); + SSBFilter->create_filter(m_LowCutoff / 48000.0f, m_Bandwidth / 48000.0f); m_volume = cfg->getVolume(); m_volume *= m_volume * 0.1; diff --git a/plugins/channel/ssb/ssbdemod.h b/plugins/channel/ssb/ssbdemod.h index a93a1c44b..59fc56a5f 100644 --- a/plugins/channel/ssb/ssbdemod.h +++ b/plugins/channel/ssb/ssbdemod.h @@ -35,7 +35,7 @@ public: SSBDemod(AudioFifo* audioFifo, SampleSink* sampleSink); ~SSBDemod(); - void configure(MessageQueue* messageQueue, Real Bandwidth, Real volume); + void configure(MessageQueue* messageQueue, Real Bandwidth, Real LowCutoff, Real volume); void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); void start(); @@ -48,20 +48,23 @@ private: public: Real getBandwidth() const { return m_Bandwidth; } + Real getLoCutoff() const { return m_LowCutoff; } Real getVolume() const { return m_volume; } - static MsgConfigureSSBDemod* create(Real Bandwidth, Real volume) + static MsgConfigureSSBDemod* create(Real Bandwidth, Real LowCutoff, Real volume) { - return new MsgConfigureSSBDemod(Bandwidth, volume); + return new MsgConfigureSSBDemod(Bandwidth, LowCutoff, volume); } private: Real m_Bandwidth; + Real m_LowCutoff; Real m_volume; - MsgConfigureSSBDemod(Real Bandwidth, Real volume) : + MsgConfigureSSBDemod(Real Bandwidth, Real LowCutoff, Real volume) : Message(), m_Bandwidth(Bandwidth), + m_LowCutoff(LowCutoff), m_volume(volume) { } }; @@ -73,6 +76,7 @@ private: typedef std::vector AudioVector; Real m_Bandwidth; + Real m_LowCutoff; Real m_volume; int m_undersampleCount; int m_sampleRate; diff --git a/plugins/channel/ssb/ssbdemodgui.cpp b/plugins/channel/ssb/ssbdemodgui.cpp index 8c9840fca..ba72d47b3 100644 --- a/plugins/channel/ssb/ssbdemodgui.cpp +++ b/plugins/channel/ssb/ssbdemodgui.cpp @@ -13,6 +13,8 @@ #include "util/simpleserializer.h" #include "gui/basicchannelsettingswidget.h" +#include + SSBDemodGUI* SSBDemodGUI::create(PluginAPI* pluginAPI) { SSBDemodGUI* gui = new SSBDemodGUI(pluginAPI); @@ -42,6 +44,7 @@ QByteArray SSBDemodGUI::serialize() const SimpleSerializer s(1); s.writeS32(1, m_channelMarker->getCenterFrequency()); s.writeS32(2, ui->BW->value()); + s.writeS32(6, ui->lowCut->value()); s.writeS32(3, ui->volume->value()); s.writeBlob(4, ui->spectrumGUI->serialize()); s.writeU32(5, m_channelMarker->getColor().rgb()); @@ -63,8 +66,10 @@ bool SSBDemodGUI::deserialize(const QByteArray& data) qint32 tmp; d.readS32(1, &tmp, 0); m_channelMarker->setCenterFrequency(tmp); - d.readS32(2, &tmp, 3); + d.readS32(2, &tmp, 30); ui->BW->setValue(tmp); + d.readS32(6, &tmp, 3); + ui->lowCut->setValue(tmp); d.readS32(3, &tmp, 20); ui->volume->setValue(tmp); d.readBlob(4, &bytetmp); @@ -114,11 +119,48 @@ void SSBDemodGUI::on_BW_valueChanged(int value) QString s = QString::number(value/10.0, 'f', 1); ui->BWText->setText(s); m_channelMarker->setBandwidth(value * 100 * 2); + if (value < 0) { m_channelMarker->setSidebands(ChannelMarker::lsb); } else { m_channelMarker->setSidebands(ChannelMarker::usb); } + + on_lowCut_valueChanged(m_channelMarker->getLowCutoff()/100); +} + +int SSBDemodGUI::getEffectiveLowCutoff(int lowCutoff) +{ + int ssbBW = m_channelMarker->getBandwidth() / 2; + int effectiveLowCutoff = lowCutoff; + const int guard = 100; + + if (ssbBW < 0) { + if (effectiveLowCutoff < ssbBW + guard) { + effectiveLowCutoff = ssbBW + guard; + } + if (effectiveLowCutoff > 0) { + effectiveLowCutoff = 0; + } + } else { + if (effectiveLowCutoff > ssbBW - guard) { + effectiveLowCutoff = ssbBW - guard; + } + if (effectiveLowCutoff < 0) { + effectiveLowCutoff = 0; + } + } + + return effectiveLowCutoff; +} + +void SSBDemodGUI::on_lowCut_valueChanged(int value) +{ + int lowCutoff = getEffectiveLowCutoff(value * 100); + m_channelMarker->setLowCutoff(lowCutoff); + QString s = QString::number(lowCutoff/1000.0, 'f', 1); + ui->lowCutText->setText(s); + ui->lowCut->setValue(lowCutoff/100); applySettings(); } @@ -207,6 +249,7 @@ void SSBDemodGUI::applySettings() m_channelMarker->getCenterFrequency()); m_ssbDemod->configure(m_threadedSampleSink->getMessageQueue(), ui->BW->value() * 100.0, + ui->lowCut->value() * 100.0, ui->volume->value() / 10.0 ); } diff --git a/plugins/channel/ssb/ssbdemodgui.h b/plugins/channel/ssb/ssbdemodgui.h index 439acfebc..042e2582b 100644 --- a/plugins/channel/ssb/ssbdemodgui.h +++ b/plugins/channel/ssb/ssbdemodgui.h @@ -37,6 +37,7 @@ private slots: void on_deltaFrequency_changed(quint64 value); void on_deltaMinus_clicked(bool minus); void on_BW_valueChanged(int value); + void on_lowCut_valueChanged(int value); void on_volume_valueChanged(int value); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDoubleClicked(); @@ -56,6 +57,7 @@ private: explicit SSBDemodGUI(PluginAPI* pluginAPI, QWidget* parent = NULL); ~SSBDemodGUI(); + int getEffectiveLowCutoff(int lowCutoff); void applySettings(); void leaveEvent(QEvent*); diff --git a/plugins/channel/ssb/ssbdemodgui.ui b/plugins/channel/ssb/ssbdemodgui.ui index 8dd285975..45b2c3979 100644 --- a/plugins/channel/ssb/ssbdemodgui.ui +++ b/plugins/channel/ssb/ssbdemodgui.ui @@ -41,6 +41,41 @@ 3 + + + + -60 + + + 60 + + + 1 + + + 30 + + + Qt::Horizontal + + + + + + + + 50 + 0 + + + + 2.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + @@ -57,7 +92,7 @@ - + 100 @@ -70,65 +105,6 @@ - - - - -60 - - - 60 - - - 10 - - - 30 - - - Qt::Horizontal - - - - - - - Volume - - - - - - - - 50 - 0 - - - - 2.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Bandwidth - - - - - - - Qt::RightToLeft - - - Minus - - - @@ -160,6 +136,20 @@ + + + + Bandwidth + + + + + + + Volume + + + @@ -167,6 +157,58 @@ + + + + Qt::RightToLeft + + + Minus + + + + + + + Low cutoff + + + + + + + -60 + + + 60 + + + 1 + + + 3 + + + Qt::Horizontal + + + + + + + + 50 + 0 + + + + 0.3 kHz + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + @@ -214,18 +256,6 @@ - - GLSpectrum - QWidget -
gui/glspectrum.h
- 1 -
- - GLSpectrumGUI - QWidget -
gui/glspectrumgui.h
- 1 -
RollupWidget QWidget @@ -238,6 +268,18 @@
gui/valuedial.h
1
+ + GLSpectrum + QWidget +
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
+ 1 +
diff --git a/sdrbase/dsp/channelmarker.cpp b/sdrbase/dsp/channelmarker.cpp index 531c1c268..ed6757086 100644 --- a/sdrbase/dsp/channelmarker.cpp +++ b/sdrbase/dsp/channelmarker.cpp @@ -1,5 +1,7 @@ #include "dsp/channelmarker.h" +#include + QRgb ChannelMarker::m_colorTable[] = { qRgb(0xc0, 0x00, 0x00), qRgb(0x00, 0xc0, 0x00), @@ -29,6 +31,7 @@ ChannelMarker::ChannelMarker(QObject* parent) : QObject(parent), m_centerFrequency(0), m_bandwidth(0), + m_lowCutoff(0), m_sidebands(dsb), m_visible(false), m_highlighted(false), @@ -57,6 +60,12 @@ void ChannelMarker::setBandwidth(int bandwidth) emit changed(); } +void ChannelMarker::setLowCutoff(int lowCutoff) +{ + m_lowCutoff = lowCutoff; + emit changed(); +} + void ChannelMarker::setSidebands(sidebands_t sidebands) { m_sidebands = sidebands; diff --git a/sdrbase/gui/glspectrum.cpp b/sdrbase/gui/glspectrum.cpp index 6d44a594a..3b3e90376 100644 --- a/sdrbase/gui/glspectrum.cpp +++ b/sdrbase/gui/glspectrum.cpp @@ -551,20 +551,10 @@ void GLSpectrum::paintGL() // paint channels if(m_mouseInside) { + // Effective BW overlays for(int i = 0; i < m_channelMarkerStates.size(); ++i) { ChannelMarkerState* dv = m_channelMarkerStates[i]; if(dv->m_channelMarker->getVisible()) { - /* - ChannelMarker::sidebands_t sidebands = dv->m_channelMarker->getSidebands(); - float fcLineRelativePos; - if (sidebands == ChannelMarker::usb) { - fcLineRelativePos = 0.0; - } else if (sidebands == ChannelMarker::lsb) { - fcLineRelativePos = 1.0; - } else { - fcLineRelativePos = 0.5; - } - */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(dv->m_channelMarker->getColor().redF(), dv->m_channelMarker->getColor().greenF(), dv->m_channelMarker->getColor().blueF(), 0.3f); @@ -577,11 +567,22 @@ void GLSpectrum::paintGL() glVertex2f(1, 1); glVertex2f(0, 1); glEnd(); + glPopMatrix(); + } + } + + // Center line overlays based on DSB enveloppe + for(int i = 0; i < m_channelMarkerStates.size(); ++i) { + ChannelMarkerState* dv = m_channelMarkerStates[i]; + if(dv->m_channelMarker->getVisible()) { glDisable(GL_BLEND); glColor3f(0.8f, 0.8f, 0.6f); + glPushMatrix(); + glTranslatef(dv->m_glRectDsb.x(), dv->m_glRectDsb.y(), 0); + glScalef(dv->m_glRectDsb.width(), dv->m_glRectDsb.height(), 1); glBegin(GL_LINE_LOOP); - glVertex2f(getCenterFreqLineRelPos(dv->m_channelMarker), 0); - glVertex2f(getCenterFreqLineRelPos(dv->m_channelMarker), 1); + glVertex2f(0.5, 0); + glVertex2f(0.5, 1); glEnd(); glPopMatrix(); } @@ -662,6 +663,8 @@ void GLSpectrum::paintGL() glPushMatrix(); glTranslatef(m_glWaterfallRect.x(), m_glFrequencyScaleRect.y(), 0); glScalef(m_glWaterfallRect.width(), m_glFrequencyScaleRect.height(), 1); + + // Effective bandwidth overlays for(int i = 0; i < m_channelMarkerStates.size(); ++i) { ChannelMarkerState* dv = m_channelMarkerStates[i]; if(dv->m_channelMarker->getVisible()) { @@ -677,19 +680,29 @@ void GLSpectrum::paintGL() glVertex2f(1, 0.5); glVertex2f(0, 0.5); glEnd(); - - if (dv->m_channelMarker->getHighlighted()) { - glColor3f(0.8f, 0.8f, 0.6f); - glBegin(GL_LINE_LOOP); - glVertex2f(getCenterFreqLineRelPos(dv->m_channelMarker), 0); - glVertex2f(getCenterFreqLineRelPos(dv->m_channelMarker), 1); - glEnd(); - } - glDisable(GL_BLEND); glPopMatrix(); } } + + // Center frequency mark on highlighted channels based on DSB enveloppe + for(int i = 0; i < m_channelMarkerStates.size(); ++i) { + ChannelMarkerState* dv = m_channelMarkerStates[i]; + if(dv->m_channelMarker->getVisible()) { + if (dv->m_channelMarker->getHighlighted()) { + glColor3f(0.8f, 0.8f, 0.6f); + glPushMatrix(); + glTranslatef(dv->m_glRectDsb.x(), dv->m_glRectDsb.y(), 0); + glScalef(dv->m_glRectDsb.width(), dv->m_glRectDsb.height(), 1); + glBegin(GL_LINE_LOOP); + glVertex2f(0.5, 0); + glVertex2f(0.5, 1); + glEnd(); + glPopMatrix(); + } + } + } + glPopMatrix(); } @@ -1026,23 +1039,31 @@ void GLSpectrum::applyChanges() for(int i = 0; i < m_channelMarkerStates.size(); ++i) { ChannelMarkerState* dv = m_channelMarkerStates[i]; - qreal xc, pw, nw; + qreal xc, pw, nw, dsbw; ChannelMarker::sidebands_t sidebands = dv->m_channelMarker->getSidebands(); xc = m_centerFrequency + dv->m_channelMarker->getCenterFrequency(); // marker center frequency + dsbw = dv->m_channelMarker->getBandwidth(); if (sidebands == ChannelMarker::usb) { - nw = 0; // negative bandwidth + nw = dv->m_channelMarker->getLowCutoff(); // negative bandwidth pw = dv->m_channelMarker->getBandwidth() / 2; // positive bandwidth } else if (sidebands == ChannelMarker::lsb) { - pw = 0; + pw = dv->m_channelMarker->getLowCutoff(); nw = dv->m_channelMarker->getBandwidth() / 2; } else { - pw = dv->m_channelMarker->getBandwidth() / 2; + pw = dsbw / 2; nw = -pw; } - //std::cerr << xc << "; " << nw << "; " << pw << std::endl; + // draw the DSB rectangle + dv->m_glRectDsb.setRect( + m_frequencyScale.getPosFromValue(xc - (dsbw/2)) / (float)(width() - leftMargin - rightMargin), + 0, + dsbw / (float)m_sampleRate, + 1); + + // draw the effective BW rectangle dv->m_glRect.setRect( m_frequencyScale.getPosFromValue(xc + nw) / (float)(width() - leftMargin - rightMargin), 0, @@ -1366,16 +1387,3 @@ void GLSpectrum::channelMarkerDestroyed(QObject* object) { removeChannelMarker((ChannelMarker*)object); } - -float GLSpectrum::getCenterFreqLineRelPos(ChannelMarker *channelMarker) -{ - ChannelMarker::sidebands_t sidebands = channelMarker->getSidebands(); - - if (sidebands == ChannelMarker::usb) { - return 0.0; - } else if (sidebands == ChannelMarker::lsb) { - return 1.0; - } else { - return 0.5; - } -}