diff --git a/plugins/channel/CMakeLists.txt b/plugins/channel/CMakeLists.txt index 1700e8b72..4d6c557ae 100644 --- a/plugins/channel/CMakeLists.txt +++ b/plugins/channel/CMakeLists.txt @@ -5,7 +5,5 @@ add_subdirectory(am) add_subdirectory(nfm) add_subdirectory(ssb) add_subdirectory(tcpsrc) -add_subdirectory(usb) -add_subdirectory(wfm) #add_subdirectory(tetra) diff --git a/plugins/channel/ssb/ssbdemodgui.ui b/plugins/channel/ssb/ssbdemodgui.ui index 45b2c3979..f4429d219 100644 --- a/plugins/channel/ssb/ssbdemodgui.ui +++ b/plugins/channel/ssb/ssbdemodgui.ui @@ -85,7 +85,7 @@ - 3 kHz + 3.0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -202,7 +202,7 @@ - 0.3 kHz + 0.3 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/plugins/channel/wfm/CMakeLists.txt b/plugins/channel/wfm/CMakeLists.txt index 72d173c1b..552a129c4 100644 --- a/plugins/channel/wfm/CMakeLists.txt +++ b/plugins/channel/wfm/CMakeLists.txt @@ -29,7 +29,7 @@ add_definitions(${QT_DEFINITIONS}) add_definitions(-DQT_PLUGIN) add_definitions(-DQT_SHARED) -#qt5_wrap_cpp(wfm_HEADERS_MOC ${wfm_HEADERS}) +#qt5_wrap_cpp(nfm_HEADERS_MOC ${nfm_HEADERS}) qt5_wrap_ui(wfm_FORMS_HEADERS ${wfm_FORMS}) add_library(demodwfm SHARED @@ -44,4 +44,4 @@ target_link_libraries(demodwfm sdrbase ) -qt5_use_modules(demodwfm Core Widgets OpenGL Multimedia) +qt5_use_modules(demodwfm Core Widgets OpenGL Multimedia) \ No newline at end of file diff --git a/plugins/channel/wfm/wfmdemod.cpp b/plugins/channel/wfm/wfmdemod.cpp index c1a386da0..55155a3d8 100644 --- a/plugins/channel/wfm/wfmdemod.cpp +++ b/plugins/channel/wfm/wfmdemod.cpp @@ -1,5 +1,4 @@ /////////////////////////////////////////////////////////////////////////////////// -// (c) 2014 John Greb // // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // written by Christian Daniel // // // @@ -18,9 +17,13 @@ #include #include -#include "wfmdemod.h" +#include #include "audio/audiooutput.h" #include "dsp/dspcommands.h" +#include "dsp/pidcontroller.h" +#include "wfmdemod.h" + +#include MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message) @@ -28,85 +31,197 @@ WFMDemod::WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) : m_sampleSink(sampleSink), m_audioFifo(audioFifo) { - m_volume = 2.0; - m_sampleRate = 250000; - m_frequency = 0; + m_config.m_inputSampleRate = 96000; + m_config.m_inputFrequencyOffset = 0; + m_config.m_rfBandwidth = 180000; + m_config.m_afBandwidth = 15000; + m_config.m_squelch = -60.0; + m_config.m_volume = 2.0; + m_config.m_audioSampleRate = 48000; - m_interpolator.create(16, m_sampleRate, 16000); - m_sampleDistanceRemain = (Real)m_sampleRate / 48000.0; + apply(); - m_audioBuffer.resize(256); + m_audioBuffer.resize(16384); m_audioBufferFill = 0; - m_scale = 0; + m_movingAverage.resize(16, 0); } WFMDemod::~WFMDemod() { } -void WFMDemod::configure(MessageQueue* messageQueue, Real afBandwidth, Real volume) +void WFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch) { - Message* cmd = MsgConfigureWFMDemod::create(afBandwidth, volume); + Message* cmd = MsgConfigureWFMDemod::create(rfBandwidth, afBandwidth, volume, squelch); cmd->submit(messageQueue, this); } -void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) +/* +float arctan2(Real y, Real x) { - qint16 sample; - Real x, y, demod; + Real coeff_1 = M_PI / 4; + Real coeff_2 = 3 * coeff_1; + Real abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition + Real angle; + if( x>= 0) { + Real r = (x - abs_y) / (x + abs_y); + angle = coeff_1 - coeff_1 * r; + } else { + Real r = (x + abs_y) / (abs_y - x); + angle = coeff_2 - coeff_1 * r; + } + if(y < 0) + return(-angle); + else return(angle); +} - for(SampleVector::const_iterator it = begin; it < end; ++it) { - x = it->real() * m_last.real() + it->imag() * m_last.imag(); - y = it->real() * m_last.imag() - it->imag() * m_last.real(); - m_last = Complex(it->real(), it->imag()); - demod = atan2(y, x); +Real angleDist(Real a, Real b) +{ + Real dist = b - a; - Complex e(demod, 0); - Complex c; - if(m_interpolator.interpolate(&m_sampleDistanceRemain, e, &c)) { - sample = (qint16)(c.real() * 100 * m_volume * m_volume); - m_sampleBuffer.push_back(Sample(sample, sample)); - m_audioBuffer[m_audioBufferFill].l = sample; - m_audioBuffer[m_audioBufferFill].r = sample; - ++m_audioBufferFill; - if(m_audioBufferFill >= m_audioBuffer.size()) { - uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1); - if(res != m_audioBufferFill) - qDebug("lost %u samples", m_audioBufferFill - res); - m_audioBufferFill = 0; + while(dist <= M_PI) + dist += 2 * M_PI; + while(dist >= M_PI) + dist -= 2 * M_PI; + + return dist; +} +*/ + +void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst) +{ + Complex ci; + + if(m_audioFifo->size() <= 0) + return; + + for(SampleVector::const_iterator it = begin; it != end; ++it) { + Complex c(it->real() / 32768.0, it->imag() / 32768.0); + c *= m_nco.nextIQ(); + + { + if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci)) + { + m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0)); + + m_movingAverage.feed(ci.real() * ci.real() + ci.imag() * ci.imag()); + if(m_movingAverage.average() >= m_squelchLevel) + m_squelchState = m_running.m_audioSampleRate/ 20; + + qint16 sample; + if(m_squelchState > 0) { + m_squelchState--; + + Real argument = arg(ci); + argument /= M_PI; + Real demod = argument - m_lastArgument; + m_lastArgument = argument; + + + //ci *= 32768.0; + + /* + Complex d = conj(m_lastSample) * ci; + m_lastSample = ci; + Real demod = atan2(d.imag(), d.real()); + */ + + + //m_lastSample = ci; + //std::cerr << "demod=" << demod << std::endl; + + /* + Real argument = atan2(ci.real()*m_lastSample.imag() - m_lastSample.real()*ci.imag(), + ci.real()*m_lastSample.real() + ci.imag()*m_lastSample.imag()); + argument /= M_PI; + Real demod = argument - m_lastArgument; + m_lastArgument = argument; + m_lastSample = ci; + */ + + //Real demod = arctan2(d.imag(), d.real()); +/* + Real argument1 = arg(ci);//atan2(ci.imag(), ci.real()); + Real argument2 = m_lastSample.real(); + Real demod = angleDist(argument2, argument1); + m_lastSample = Complex(argument1, 0); +*/ + //demod /= M_PI; + + demod = m_lowpass.filter(demod); + + /* + if(demod < -1) + demod = -1; + else if(demod > 1) + demod = 1; + */ + + demod *= m_running.m_volume; + sample = demod * 64; + + } else { + sample = 0; + } + + m_audioBuffer[m_audioBufferFill].l = sample; + m_audioBuffer[m_audioBufferFill].r = sample; + ++m_audioBufferFill; + if(m_audioBufferFill >= m_audioBuffer.size()) { + uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1); + if(res != m_audioBufferFill) + qDebug("lost %u audio samples", m_audioBufferFill - res); + m_audioBufferFill = 0; + } + + m_interpolatorDistanceRemain += m_interpolatorDistance; } - m_sampleDistanceRemain += (Real)m_sampleRate / 48000.0; } } - if(m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill) - qDebug("lost samples"); - m_audioBufferFill = 0; + if(m_audioBufferFill > 0) { + uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1); + if(res != m_audioBufferFill) + qDebug("lost %u samples", m_audioBufferFill - res); + m_audioBufferFill = 0; + } if(m_sampleSink != NULL) - m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), true); + m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false); m_sampleBuffer.clear(); } -void WFMDemod::start() {} -void WFMDemod::stop() {} +void WFMDemod::start() +{ + m_squelchState = 0; + m_audioFifo->clear(); + m_interpolatorRegulation = 0.9999; + m_interpolatorDistance = 1.0; + m_interpolatorDistanceRemain = 0.0; + m_lastSample = 0; +} + +void WFMDemod::stop() +{ +} bool WFMDemod::handleMessage(Message* cmd) { if(DSPSignalNotification::match(cmd)) { DSPSignalNotification* signal = (DSPSignalNotification*)cmd; - qDebug("%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset()); - m_sampleRate = signal->getSampleRate(); - m_interpolator.create(16, m_sampleRate, m_afBandwidth); - m_sampleDistanceRemain = m_sampleRate / 48000.0; + + m_config.m_inputSampleRate = signal->getSampleRate(); + m_config.m_inputFrequencyOffset = signal->getFrequencyOffset(); + apply(); cmd->completed(); return true; } else if(MsgConfigureWFMDemod::match(cmd)) { MsgConfigureWFMDemod* cfg = (MsgConfigureWFMDemod*)cmd; - m_afBandwidth = cfg->getAFBandwidth(); - m_interpolator.create(16, m_sampleRate, m_afBandwidth); - m_volume = cfg->getVolume(); - cmd->completed(); + m_config.m_rfBandwidth = cfg->getRFBandwidth(); + m_config.m_afBandwidth = cfg->getAFBandwidth(); + m_config.m_volume = cfg->getVolume(); + m_config.m_squelch = cfg->getSquelch(); + apply(); return true; } else { if(m_sampleSink != NULL) @@ -114,3 +229,37 @@ bool WFMDemod::handleMessage(Message* cmd) else return false; } } + +void WFMDemod::apply() +{ + + if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || + (m_config.m_inputSampleRate != m_running.m_inputSampleRate)) { + m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); + } + + if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || + (m_config.m_rfBandwidth != m_running.m_rfBandwidth)) { + std::cerr << "WFMDemod::apply: in=" << m_config.m_inputSampleRate << ", rf=" << m_config.m_rfBandwidth << std::endl; + m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2); + m_interpolatorDistanceRemain = 0; + m_interpolatorDistance = m_config.m_inputSampleRate / m_config.m_audioSampleRate; + } + + if((m_config.m_afBandwidth != m_running.m_afBandwidth) || + (m_config.m_audioSampleRate != m_running.m_audioSampleRate)) { + m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth); + } + + if(m_config.m_squelch != m_running.m_squelch) { + m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0); + m_squelchLevel *= m_squelchLevel; + } + + m_running.m_inputSampleRate = m_config.m_inputSampleRate; + m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset; + m_running.m_rfBandwidth = m_config.m_rfBandwidth; + m_running.m_squelch = m_config.m_squelch; + m_running.m_volume = m_config.m_volume; + m_running.m_audioSampleRate = m_config.m_audioSampleRate; +} diff --git a/plugins/channel/wfm/wfmdemod.h b/plugins/channel/wfm/wfmdemod.h index caace9a0c..f11e17151 100644 --- a/plugins/channel/wfm/wfmdemod.h +++ b/plugins/channel/wfm/wfmdemod.h @@ -20,7 +20,10 @@ #include #include "dsp/samplesink.h" +#include "dsp/nco.h" #include "dsp/interpolator.h" +#include "dsp/lowpass.h" +#include "dsp/movingaverage.h" #include "audio/audiofifo.h" #include "util/message.h" @@ -31,9 +34,9 @@ public: WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink); ~WFMDemod(); - void configure(MessageQueue* messageQueue, Real afBandwidth, Real volume); + void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch); - void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); + void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po); void start(); void stop(); bool handleMessage(Message* cmd); @@ -43,22 +46,28 @@ private: MESSAGE_CLASS_DECLARATION public: + Real getRFBandwidth() const { return m_rfBandwidth; } Real getAFBandwidth() const { return m_afBandwidth; } Real getVolume() const { return m_volume; } + Real getSquelch() const { return m_squelch; } - static MsgConfigureWFMDemod* create(Real afBandwidth, Real volume) + static MsgConfigureWFMDemod* create(Real rfBandwidth, Real afBandwidth, Real volume, Real squelch) { - return new MsgConfigureWFMDemod(afBandwidth, volume); + return new MsgConfigureWFMDemod(rfBandwidth, afBandwidth, volume, squelch); } private: + Real m_rfBandwidth; Real m_afBandwidth; Real m_volume; + Real m_squelch; - MsgConfigureWFMDemod(Real afBandwidth, Real volume) : + MsgConfigureWFMDemod(Real rfBandwidth, Real afBandwidth, Real volume, Real squelch) : Message(), + m_rfBandwidth(rfBandwidth), m_afBandwidth(afBandwidth), - m_volume(volume) + m_volume(volume), + m_squelch(squelch) { } }; @@ -68,24 +77,56 @@ private: }; typedef std::vector AudioVector; - Real m_afBandwidth; - Real m_volume; - int m_sampleRate; - int m_frequency; + enum RateState { + RSInitialFill, + RSRunning + }; - double m_scale; + struct Config { + int m_inputSampleRate; + qint64 m_inputFrequencyOffset; + Real m_rfBandwidth; + Real m_afBandwidth; + Real m_squelch; + Real m_volume; + quint32 m_audioSampleRate; - Interpolator m_interpolator; - Real m_sampleDistanceRemain; - Complex m_last, m_this; + Config() : + m_inputSampleRate(-1), + m_inputFrequencyOffset(0), + m_rfBandwidth(-1), + m_afBandwidth(-1), + m_squelch(0), + m_volume(0), + m_audioSampleRate(0) + { } + }; + + Config m_config; + Config m_running; + + NCO m_nco; + Real m_interpolatorRegulation; + Interpolator m_interpolator; // Interpolator between sample rate sent from DSP engine and requested RF bandwidth (rational) + Real m_interpolatorDistance; + Real m_interpolatorDistanceRemain; + Lowpass m_lowpass; + + Real m_squelchLevel; + int m_squelchState; + + Real m_lastArgument; + Complex m_lastSample; + MovingAverage m_movingAverage; AudioVector m_audioBuffer; uint m_audioBufferFill; SampleSink* m_sampleSink; + AudioFifo* m_audioFifo; SampleVector m_sampleBuffer; - AudioFifo* m_audioFifo; + void apply(); }; #endif // INCLUDE_WFMDEMOD_H diff --git a/plugins/channel/wfm/wfmdemodgui.cpp b/plugins/channel/wfm/wfmdemodgui.cpp index 0739253e0..cae7c7e4b 100644 --- a/plugins/channel/wfm/wfmdemodgui.cpp +++ b/plugins/channel/wfm/wfmdemodgui.cpp @@ -1,18 +1,22 @@ #include #include -#include "wfmdemodgui.h" -#include "ui_wfmdemodgui.h" -#include "wfmdemodgui.h" #include "ui_wfmdemodgui.h" #include "dsp/threadedsamplesink.h" #include "dsp/channelizer.h" -#include "wfmdemod.h" -#include "dsp/spectrumvis.h" +#include "dsp/nullsink.h" #include "gui/glspectrum.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "gui/basicchannelsettingswidget.h" +#include +#include "wfmdemod.h" +#include "wfmdemodgui.h" + +const int WFMDemodGUI::m_rfBW[] = { + 48000, 80000, 120000, 140000, 160000, 180000, 200000, 220000, 250000 +}; + WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI) { WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI); @@ -31,9 +35,11 @@ void WFMDemodGUI::setName(const QString& name) void WFMDemodGUI::resetToDefaults() { - ui->afBW->setValue(6); + ui->rfBW->setValue(4); + ui->afBW->setValue(3); ui->volume->setValue(20); - ui->spectrumGUI->resetToDefaults(); + ui->squelch->setValue(-40); + ui->deltaFrequency->setValue(0); applySettings(); } @@ -41,10 +47,12 @@ QByteArray WFMDemodGUI::serialize() const { SimpleSerializer s(1); s.writeS32(1, m_channelMarker->getCenterFrequency()); - s.writeS32(2, ui->afBW->value()); - s.writeS32(3, ui->volume->value()); - s.writeBlob(4, ui->spectrumGUI->serialize()); - s.writeU32(5, m_channelMarker->getColor().rgb()); + s.writeS32(2, ui->rfBW->value()); + s.writeS32(3, ui->afBW->value()); + s.writeS32(4, ui->volume->value()); + s.writeS32(5, ui->squelch->value()); + //s.writeBlob(6, ui->spectrumGUI->serialize()); + s.writeU32(7, m_channelMarker->getColor().rgb()); return s.final(); } @@ -63,13 +71,17 @@ bool WFMDemodGUI::deserialize(const QByteArray& data) qint32 tmp; d.readS32(1, &tmp, 0); m_channelMarker->setCenterFrequency(tmp); - d.readS32(2, &tmp, 6); + d.readS32(2, &tmp, 4); + ui->rfBW->setValue(tmp); + d.readS32(3, &tmp, 3); ui->afBW->setValue(tmp); - d.readS32(3, &tmp, 20); + d.readS32(4, &tmp, 20); ui->volume->setValue(tmp); - d.readBlob(4, &bytetmp); - ui->spectrumGUI->deserialize(bytetmp); - if(d.readU32(5, &u32tmp)) + d.readS32(5, &tmp, -40); + ui->squelch->setValue(tmp); + //d.readBlob(6, &bytetmp); + //ui->spectrumGUI->deserialize(bytetmp); + if(d.readU32(7, &u32tmp)) m_channelMarker->setColor(u32tmp); applySettings(); return true; @@ -89,6 +101,33 @@ void WFMDemodGUI::viewChanged() applySettings(); } +void WFMDemodGUI::on_deltaMinus_clicked(bool minus) +{ + int deltaFrequency = m_channelMarker->getCenterFrequency(); + bool minusDelta = (deltaFrequency < 0); + + if (minus ^ minusDelta) // sign change + { + m_channelMarker->setCenterFrequency(-deltaFrequency); + } +} + +void WFMDemodGUI::on_deltaFrequency_changed(quint64 value) +{ + if (ui->deltaMinus->isChecked()) { + m_channelMarker->setCenterFrequency(-value); + } else { + m_channelMarker->setCenterFrequency(value); + } +} + +void WFMDemodGUI::on_rfBW_valueChanged(int value) +{ + ui->rfBWText->setText(QString("%1 kHz").arg(m_rfBW[value] / 1000.0)); + m_channelMarker->setBandwidth(m_rfBW[value]); + applySettings(); +} + void WFMDemodGUI::on_afBW_valueChanged(int value) { ui->afBWText->setText(QString("%1 kHz").arg(value)); @@ -101,12 +140,15 @@ void WFMDemodGUI::on_volume_valueChanged(int value) applySettings(); } +void WFMDemodGUI::on_squelch_valueChanged(int value) +{ + ui->squelchText->setText(QString("%1 dB").arg(value)); + applySettings(); +} + + void WFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) { - /* - if((widget == ui->spectrumContainer) && (m_wfmDemod != NULL)) - m_wfmDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); - */ } void WFMDemodGUI::onMenuDoubleClicked() @@ -129,30 +171,22 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) : connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); - m_audioFifo = new AudioFifo(4, 48000 / 4); - m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_wfmDemod = new WFMDemod(m_audioFifo, m_spectrumVis); + m_audioFifo = new AudioFifo(4, 250000); // TODO: check. Room for 1s FIFO at max rate + m_nullSink = new NullSink(); + m_wfmDemod = new WFMDemod(m_audioFifo, m_nullSink); m_channelizer = new Channelizer(m_wfmDemod); m_threadedSampleSink = new ThreadedSampleSink(m_channelizer); m_pluginAPI->addAudioSource(m_audioFifo); m_pluginAPI->addSampleSink(m_threadedSampleSink); - ui->glSpectrum->setCenterFrequency(12000); - ui->glSpectrum->setSampleRate(24000); - ui->glSpectrum->setDisplayWaterfall(true); - ui->glSpectrum->setDisplayMaxHold(true); - m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); - m_channelMarker = new ChannelMarker(this); m_channelMarker->setColor(Qt::blue); - m_channelMarker->setBandwidth(32000); + m_channelMarker->setBandwidth(12500); m_channelMarker->setCenterFrequency(0); m_channelMarker->setVisible(true); connect(m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); m_pluginAPI->addChannelMarker(m_channelMarker); - ui->spectrumGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_spectrumVis, ui->glSpectrum); - applySettings(); } @@ -164,7 +198,7 @@ WFMDemodGUI::~WFMDemodGUI() delete m_threadedSampleSink; delete m_channelizer; delete m_wfmDemod; - delete m_spectrumVis; + delete m_nullSink; delete m_audioFifo; delete m_channelMarker; delete ui; @@ -174,9 +208,24 @@ void WFMDemodGUI::applySettings() { setTitleColor(m_channelMarker->getColor()); m_channelizer->configure(m_threadedSampleSink->getMessageQueue(), - 48000, + 256000, // TODO: this is where requested sample rate is specified m_channelMarker->getCenterFrequency()); + ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency())); + ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0); m_wfmDemod->configure(m_threadedSampleSink->getMessageQueue(), + m_rfBW[ui->rfBW->value()], ui->afBW->value() * 1000.0, - ui->volume->value() * 0.1); + ui->volume->value() / 10.0, + ui->squelch->value()); } + +void WFMDemodGUI::leaveEvent(QEvent*) +{ + m_channelMarker->setHighlighted(false); +} + +void WFMDemodGUI::enterEvent(QEvent*) +{ + m_channelMarker->setHighlighted(true); +} + diff --git a/plugins/channel/wfm/wfmdemodgui.h b/plugins/channel/wfm/wfmdemodgui.h index bd3c1d482..ec0a96a88 100644 --- a/plugins/channel/wfm/wfmdemodgui.h +++ b/plugins/channel/wfm/wfmdemodgui.h @@ -11,7 +11,7 @@ class AudioFifo; class ThreadedSampleSink; class Channelizer; class WFMDemod; -class SpectrumVis; +class NullSink; namespace Ui { class WFMDemodGUI; @@ -34,8 +34,12 @@ public: private slots: void viewChanged(); + void on_deltaFrequency_changed(quint64 value); + void on_deltaMinus_clicked(bool minus); + void on_rfBW_valueChanged(int value); void on_afBW_valueChanged(int value); void on_volume_valueChanged(int value); + void on_squelch_valueChanged(int value); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDoubleClicked(); @@ -49,12 +53,17 @@ private: ThreadedSampleSink* m_threadedSampleSink; Channelizer* m_channelizer; WFMDemod* m_wfmDemod; - SpectrumVis* m_spectrumVis; + NullSink *m_nullSink; + + static const int m_rfBW[]; explicit WFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent = NULL); ~WFMDemodGUI(); void applySettings(); + + void leaveEvent(QEvent*); + void enterEvent(QEvent*); }; #endif // INCLUDE_WFMDEMODGUI_H diff --git a/plugins/channel/wfm/wfmdemodgui.ui b/plugins/channel/wfm/wfmdemodgui.ui index f5d9d0c2e..8e63dee35 100644 --- a/plugins/channel/wfm/wfmdemodgui.ui +++ b/plugins/channel/wfm/wfmdemodgui.ui @@ -7,11 +7,11 @@ 0 0 302 - 410 + 138 - WBFM Demodulator + WFM Demodulator @@ -26,20 +26,130 @@ Settings - + + 2 + + + 2 + + + 2 + + 2 3 + + + + 100 + + + 20 + + + Qt::Horizontal + + + + + + + 8 + + + 1 + + + 4 + + + Qt::Horizontal + + + + + + Qt::RightToLeft + + + Minus + + + + + + + Squelch + + + + AF Bandwidth - + + + + -100 + + + 0 + + + -40 + + + Qt::Horizontal + + + + + + + + 50 + 0 + + + + 12.5kHz + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + RF Bandwidth + + + + + + + + 50 + 0 + + + + 3 kHz + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + 1 @@ -58,8 +168,8 @@ - - + + 50 @@ -67,34 +177,21 @@ - 6 kHz + -40dB Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + Volume - - - - 100 - - - 20 - - - Qt::Horizontal - - - - + @@ -110,62 +207,60 @@ - - - - - - 40 - 140 - 218 - 184 - - - - Channel Spectrum - - - - 2 - - - 3 - - - + + + + + 0 + 0 + + - 200 - 150 + 32 + 16 + + + Monospace + 12 + + + + SizeVerCursor + + + Qt::StrongFocus + + + Demod shift frequency from center in Hz + - - + + + + Hz + + - - GLSpectrum - QWidget -
gui/glspectrum.h
- 1 -
- - GLSpectrumGUI - QWidget -
gui/glspectrumgui.h
- 1 -
RollupWidget QWidget
gui/rollupwidget.h
1
+ + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
diff --git a/plugins/channel/wfm/wfmplugin.cpp b/plugins/channel/wfm/wfmplugin.cpp index 860b32346..afefa434f 100644 --- a/plugins/channel/wfm/wfmplugin.cpp +++ b/plugins/channel/wfm/wfmplugin.cpp @@ -1,16 +1,17 @@ #include #include #include "plugin/pluginapi.h" -#include "wfmplugin.h" + #include "wfmdemodgui.h" +#include "wfmplugin.h" const PluginDescriptor WFMPlugin::m_pluginDescriptor = { QString("WFM Demodulator"), - QString("1.0"), - QString("(c) 2014 JohnGreb"), - QString("http://www.maintech.de"), + QString("---"), + QString("(c) Edouard Griffiths, F4EXB"), + QString("https://github.com/f4exb/rtl-sdrangelove/tree/f4exb"), true, - QString("github.com/hexameron/rtl-sdrangelove") + QString("https://github.com/f4exb/rtl-sdrangelove/tree/f4exb") }; WFMPlugin::WFMPlugin(QObject* parent) :