diff --git a/plugins/channel/demodnfm/nfmdemod.cpp b/plugins/channel/demodnfm/nfmdemod.cpp index e9dc0d582..9b78629c7 100644 --- a/plugins/channel/demodnfm/nfmdemod.cpp +++ b/plugins/channel/demodnfm/nfmdemod.cpp @@ -48,13 +48,13 @@ NFMDemod::NFMDemod() : m_config.m_inputFrequencyOffset = 0; m_config.m_rfBandwidth = 12500; m_config.m_afBandwidth = 3000; + m_config.m_fmDeviation = 2000; m_config.m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack m_config.m_squelch = -30.0; m_config.m_volume = 1.0; m_config.m_ctcssOn = false; m_config.m_audioMute = false; m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); - m_phaseDiscri.setFMScaling(384000/2400); apply(); @@ -78,6 +78,7 @@ NFMDemod::~NFMDemod() void NFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, + int fmDeviation, Real volume, int squelchGate, Real squelch, @@ -86,6 +87,7 @@ void NFMDemod::configure(MessageQueue* messageQueue, { Message* cmd = MsgConfigureNFMDemod::create(rfBandwidth, afBandwidth, + fmDeviation, volume, squelchGate, squelch, @@ -297,6 +299,7 @@ bool NFMDemod::handleMessage(const Message& cmd) m_config.m_rfBandwidth = cfg.getRFBandwidth(); m_config.m_afBandwidth = cfg.getAFBandwidth(); + m_config.m_fmDeviation = cfg.getFMDeviation(); m_config.m_volume = cfg.getVolume(); m_config.m_squelchGate = cfg.getSquelchGate(); m_config.m_squelch = cfg.getSquelch(); @@ -307,6 +310,7 @@ bool NFMDemod::handleMessage(const Message& cmd) qDebug() << "NFMDemod::handleMessage: MsgConfigureNFMDemod: m_rfBandwidth: " << m_config.m_rfBandwidth << " m_afBandwidth: " << m_config.m_afBandwidth + << " m_fmDeviation: " << m_config.m_fmDeviation << " m_volume: " << m_config.m_volume << " m_squelchGate" << m_config.m_squelchGate << " m_squelch: " << m_config.m_squelch @@ -336,11 +340,15 @@ void NFMDemod::apply() m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2); m_interpolatorDistanceRemain = 0; m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; - m_fmExcursion = m_config.m_rfBandwidth / 2.0f; - m_phaseDiscri.setFMScaling(m_config.m_inputSampleRate / m_fmExcursion); + m_phaseDiscri.setFMScaling(m_config.m_rfBandwidth / (float) m_config.m_fmDeviation); m_settingsMutex.unlock(); } + if (m_config.m_fmDeviation != m_running.m_fmDeviation) + { + m_phaseDiscri.setFMScaling(m_config.m_rfBandwidth / (float) m_config.m_fmDeviation); + } + if ((m_config.m_afBandwidth != m_running.m_afBandwidth) || (m_config.m_audioSampleRate != m_running.m_audioSampleRate)) { @@ -368,6 +376,7 @@ void NFMDemod::apply() m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset; m_running.m_rfBandwidth = m_config.m_rfBandwidth; m_running.m_afBandwidth = m_config.m_afBandwidth; + m_running.m_fmDeviation = m_config.m_fmDeviation; m_running.m_squelchGate = m_config.m_squelchGate; m_running.m_squelch = m_config.m_squelch; m_running.m_volume = m_config.m_volume; diff --git a/plugins/channel/demodnfm/nfmdemod.h b/plugins/channel/demodnfm/nfmdemod.h index 885ed2ba8..38bc44dab 100644 --- a/plugins/channel/demodnfm/nfmdemod.h +++ b/plugins/channel/demodnfm/nfmdemod.h @@ -43,6 +43,7 @@ public: void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, + int fmDeviation, Real volume, int squelchGate, Real squelch, @@ -77,6 +78,7 @@ private: public: Real getRFBandwidth() const { return m_rfBandwidth; } Real getAFBandwidth() const { return m_afBandwidth; } + int getFMDeviation() const { return m_fmDeviation; } Real getVolume() const { return m_volume; }\ int getSquelchGate() const { return m_squelchGate; } Real getSquelch() const { return m_squelch; } @@ -85,18 +87,20 @@ private: static MsgConfigureNFMDemod* create(Real rfBandwidth, Real afBandwidth, + int fmDeviation, Real volume, int squelchGate, Real squelch, bool ctcssOn, bool audioMute) { - return new MsgConfigureNFMDemod(rfBandwidth, afBandwidth, volume, squelchGate, squelch, ctcssOn, audioMute); + return new MsgConfigureNFMDemod(rfBandwidth, afBandwidth, fmDeviation, volume, squelchGate, squelch, ctcssOn, audioMute); } private: Real m_rfBandwidth; Real m_afBandwidth; + int m_fmDeviation; Real m_volume; int m_squelchGate; Real m_squelch; @@ -105,6 +109,7 @@ private: MsgConfigureNFMDemod(Real rfBandwidth, Real afBandwidth, + int fmDeviation, Real volume, int squelchGate, Real squelch, @@ -113,6 +118,7 @@ private: Message(), m_rfBandwidth(rfBandwidth), m_afBandwidth(afBandwidth), + m_fmDeviation(fmDeviation), m_volume(volume), m_squelchGate(squelchGate), m_squelch(squelch), @@ -137,6 +143,7 @@ private: qint64 m_inputFrequencyOffset; Real m_rfBandwidth; Real m_afBandwidth; + int m_fmDeviation; int m_squelchGate; Real m_squelch; Real m_volume; @@ -150,7 +157,8 @@ private: m_inputFrequencyOffset(0), m_rfBandwidth(-1), m_afBandwidth(-1), - m_squelchGate(50), + m_fmDeviation(1), + m_squelchGate(1), m_squelch(0), m_volume(0), m_ctcssOn(false), diff --git a/plugins/channel/demodnfm/nfmdemodgui.cpp b/plugins/channel/demodnfm/nfmdemodgui.cpp index 49b005a09..74fd1fb9f 100644 --- a/plugins/channel/demodnfm/nfmdemodgui.cpp +++ b/plugins/channel/demodnfm/nfmdemodgui.cpp @@ -17,6 +17,9 @@ const int NFMDemodGUI::m_rfBW[] = { 5000, 6250, 8330, 10000, 12500, 15000, 20000, 25000, 40000 }; +const int NFMDemodGUI::m_fmDev[] = { // corresponding FM deviations + 1000, 1500, 2000, 2000, 2000, 2500, 3000, 3500, 5000 +}; const int NFMDemodGUI::m_nbRfBW = 9; NFMDemodGUI* NFMDemodGUI::create(PluginAPI* pluginAPI) @@ -331,6 +334,7 @@ void NFMDemodGUI::applySettings() m_nfmDemod->configure(m_nfmDemod->getInputMessageQueue(), m_rfBW[ui->rfBW->currentIndex()], ui->afBW->value() * 1000.0, + m_fmDev[ui->rfBW->currentIndex()], ui->volume->value() / 10.0, ui->squelchGate->value(), // in 10ths of ms ui->squelch->value(), diff --git a/plugins/channel/demodnfm/nfmdemodgui.h b/plugins/channel/demodnfm/nfmdemodgui.h index bd06db81e..d56cd1eda 100644 --- a/plugins/channel/demodnfm/nfmdemodgui.h +++ b/plugins/channel/demodnfm/nfmdemodgui.h @@ -68,6 +68,7 @@ private: MovingAverage m_channelPowerDbAvg; static const int m_rfBW[]; + static const int m_fmDev[]; static const int m_nbRfBW; explicit NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent = NULL); diff --git a/plugins/channel/udpsrc/udpsrc.cpp b/plugins/channel/udpsrc/udpsrc.cpp index a69503005..0e1d839d5 100644 --- a/plugins/channel/udpsrc/udpsrc.cpp +++ b/plugins/channel/udpsrc/udpsrc.cpp @@ -34,7 +34,8 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, SampleSink* s m_audioFifo(4, 24000), m_audioActive(false), m_audioStereo(false), - m_volume(20) + m_volume(20), + m_fmDeviation(2500) { setObjectName("UDPSrc"); @@ -66,6 +67,8 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, SampleSink* s m_magsq = 0; UDPFilter = new fftfilt(0.3 / 48.0, 16.0 / 48.0, udpBLockSampleSize * sizeof(Sample)); + m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation)); + if (m_audioSocket->bind(QHostAddress::LocalHost, m_audioPort)) { qDebug("UDPSrc::UDPSrc: bind audio socket to port %d", m_audioPort); @@ -91,6 +94,7 @@ void UDPSrc::configure(MessageQueue* messageQueue, SampleFormat sampleFormat, Real outputSampleRate, Real rfBandwidth, + int fmDeviation, QString& udpAddress, int udpPort, int audioPort) @@ -98,6 +102,7 @@ void UDPSrc::configure(MessageQueue* messageQueue, Message* cmd = MsgUDPSrcConfigure::create(sampleFormat, outputSampleRate, rfBandwidth, + fmDeviation, udpAddress, udpPort, audioPort); @@ -162,25 +167,8 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: } else if (m_sampleFormat == FormatNFM) { - int n_out = UDPFilter->runFilt(ci, &sideband); - - if (n_out) - { - Real sum = 1.0; - for (int i = 0; i < n_out; i+=2) - { - l = m_this.real() * (m_last.imag() - sideband[i].imag()) - - m_this.imag() * (m_last.real() - sideband[i].real()); - m_last = sideband[i]; - r = m_last.real() * (m_this.imag() - sideband[i+1].imag()) - - m_last.imag() * (m_this.real() - sideband[i+1].real()); - m_this = sideband[i+1]; - m_udpBuffer->write(Sample(l*m_scale, r*m_scale)); - sum += m_this.real() * m_this.real() + m_this.imag() * m_this.imag(); - } - - m_scale = (24000 * udpBLockSampleSize * sizeof(Sample)) / sum; // TODO: correct levels - } + Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci); + m_udpBuffer->write(Sample(demod, 0.0)); } else // Raw I/Q samples { @@ -189,7 +177,7 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: } } - qDebug() << "UDPSrc::feed: " << m_sampleBuffer.size() * 4; + //qDebug() << "UDPSrc::feed: " << m_sampleBuffer.size() * 4; if((m_spectrum != 0) && (m_spectrumEnabled)) { @@ -201,6 +189,7 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: void UDPSrc::start() { + m_phaseDiscri.reset(); } void UDPSrc::stop() @@ -316,6 +305,12 @@ bool UDPSrc::handleMessage(const Message& cmd) } } + if (cfg.getFMDeviation() != m_fmDeviation) + { + m_fmDeviation = cfg.getFMDeviation(); + m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation)); + } + m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0); m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate; diff --git a/plugins/channel/udpsrc/udpsrc.h b/plugins/channel/udpsrc/udpsrc.h index 888b0d4f7..d3b85c950 100644 --- a/plugins/channel/udpsrc/udpsrc.h +++ b/plugins/channel/udpsrc/udpsrc.h @@ -24,6 +24,7 @@ #include "dsp/nco.h" #include "dsp/fftfilt.h" #include "dsp/interpolator.h" +#include "dsp/phasediscri.h" #include "util/udpsink.h" #include "util/message.h" #include "audio/audiofifo.h" @@ -57,6 +58,7 @@ public: SampleFormat sampleFormat, Real outputSampleRate, Real rfBandwidth, + int fmDeviation, QString& udpAddress, int udpPort, int audioPort); @@ -86,6 +88,7 @@ protected: SampleFormat getSampleFormat() const { return m_sampleFormat; } Real getOutputSampleRate() const { return m_outputSampleRate; } Real getRFBandwidth() const { return m_rfBandwidth; } + int getFMDeviation() const { return m_fmDeviation; } const QString& getUDPAddress() const { return m_udpAddress; } int getUDPPort() const { return m_udpPort; } int getAudioPort() const { return m_audioPort; } @@ -94,6 +97,7 @@ protected: sampleFormat, Real sampleRate, Real rfBandwidth, + int fmDeviation, QString& udpAddress, int udpPort, int audioPort) @@ -101,6 +105,7 @@ protected: return new MsgUDPSrcConfigure(sampleFormat, sampleRate, rfBandwidth, + fmDeviation, udpAddress, udpPort, audioPort); @@ -110,6 +115,7 @@ protected: SampleFormat m_sampleFormat; Real m_outputSampleRate; Real m_rfBandwidth; + int m_fmDeviation; QString m_udpAddress; int m_udpPort; int m_audioPort; @@ -117,6 +123,7 @@ protected: MsgUDPSrcConfigure(SampleFormat sampleFormat, Real outputSampleRate, Real rfBandwidth, + int fmDeviation, QString& udpAddress, int udpPort, int audioPort) : @@ -124,6 +131,7 @@ protected: m_sampleFormat(sampleFormat), m_outputSampleRate(outputSampleRate), m_rfBandwidth(rfBandwidth), + m_fmDeviation(fmDeviation), m_udpAddress(udpAddress), m_udpPort(udpPort), m_audioPort(audioPort) @@ -207,6 +215,7 @@ protected: bool m_audioActive; bool m_audioStereo; int m_volume; + int m_fmDeviation; Real m_magsq; Real m_scale; @@ -230,6 +239,8 @@ protected: quint32 m_nextSSBId; quint32 m_nextS16leId; + PhaseDiscriminators m_phaseDiscri; + QMutex m_settingsMutex; }; diff --git a/plugins/channel/udpsrc/udpsrcgui.cpp b/plugins/channel/udpsrc/udpsrcgui.cpp index 3b5b364a2..619461535 100644 --- a/plugins/channel/udpsrc/udpsrcgui.cpp +++ b/plugins/channel/udpsrc/udpsrcgui.cpp @@ -68,6 +68,7 @@ void UDPSrcGUI::resetToDefaults() ui->sampleFormat->setCurrentIndex(0); ui->sampleRate->setText("48000"); ui->rfBandwidth->setText("32000"); + ui->fmDeviation->setText("2500"); ui->udpAddress->setText("127.0.0.1"); ui->udpPort->setText("9999"); ui->audioPort->setText("9999"); @@ -99,6 +100,7 @@ QByteArray UDPSrcGUI::serialize() const s.writeS32(12, (qint32)m_volume); s.writeS32(13, m_audioPort); s.writeBool(14, m_audioStereo); + s.writeS32(15, m_fmDeviation); return s.final(); } @@ -164,6 +166,8 @@ bool UDPSrcGUI::deserialize(const QByteArray& data) ui->audioPort->setText(QString("%1").arg(s32tmp)); d.readBool(14, &booltmp, false); ui->audioStereo->setChecked(booltmp); + d.readS32(15, &s32tmp, 2500); + ui->fmDeviation->setText(QString("%1").arg(s32tmp)); blockApplySettings(false); m_channelMarker.blockSignals(false); @@ -317,6 +321,13 @@ void UDPSrcGUI::applySettings() audioPort = udpPort - 1; } + int fmDeviation = ui->fmDeviation->text().toInt(&ok); + + if ((!ok) || (fmDeviation < 1)) + { + fmDeviation = 2500; + } + int boost = ui->boost->value(); setTitleColor(m_channelMarker.getColor()); @@ -327,6 +338,7 @@ void UDPSrcGUI::applySettings() //ui->udpAddress->setText(m_udpAddress); ui->udpPort->setText(QString("%1").arg(udpPort)); ui->audioPort->setText(QString("%1").arg(audioPort)); + ui->fmDeviation->setText(QString("%1").arg(fmDeviation)); ui->boost->setValue(boost); m_channelMarker.disconnect(this, SLOT(channelMarkerChanged())); m_channelMarker.setBandwidth((int)rfBandwidth); @@ -358,6 +370,7 @@ void UDPSrcGUI::applySettings() m_sampleFormat = sampleFormat; m_outputSampleRate = outputSampleRate; m_rfBandwidth = rfBandwidth; + m_fmDeviation = fmDeviation; m_udpPort = udpPort; m_audioPort = audioPort; m_boost = boost; @@ -366,6 +379,7 @@ void UDPSrcGUI::applySettings() sampleFormat, outputSampleRate, rfBandwidth, + fmDeviation, m_udpAddress, udpPort, audioPort); @@ -409,6 +423,11 @@ void UDPSrcGUI::on_rfBandwidth_textEdited(const QString& arg1) ui->applyBtn->setEnabled(true); } +void UDPSrcGUI::on_fmDeviation_textEdited(const QString& arg1) +{ + ui->applyBtn->setEnabled(true); +} + void UDPSrcGUI::on_udpAddress_textEdited(const QString& arg1) { ui->applyBtn->setEnabled(true); diff --git a/plugins/channel/udpsrc/udpsrcgui.h b/plugins/channel/udpsrc/udpsrcgui.h index 02cf6b505..7de8ebca1 100644 --- a/plugins/channel/udpsrc/udpsrcgui.h +++ b/plugins/channel/udpsrc/udpsrcgui.h @@ -64,6 +64,7 @@ private slots: void on_udpAddress_textEdited(const QString& arg1); void on_udpPort_textEdited(const QString& arg1); void on_audioPort_textEdited(const QString& arg1); + void on_fmDeviation_textEdited(const QString& arg1); void on_audioActive_toggled(bool active); void on_audioStereo_toggled(bool stereo); void on_applyBtn_clicked(); @@ -84,6 +85,7 @@ private: UDPSrc::SampleFormat m_sampleFormat; Real m_outputSampleRate; Real m_rfBandwidth; + int m_fmDeviation; int m_boost; bool m_audioActive; bool m_audioStereo; diff --git a/plugins/channel/udpsrc/udpsrcgui.ui b/plugins/channel/udpsrc/udpsrcgui.ui index 97f9e7424..fcca36a19 100644 --- a/plugins/channel/udpsrc/udpsrcgui.ui +++ b/plugins/channel/udpsrc/udpsrcgui.ui @@ -6,8 +6,8 @@ 0 0 - 257 - 324 + 290 + 158 @@ -24,10 +24,16 @@ 10 5 - 241 + 270 142 + + + 270 + 0 + + Settings @@ -298,38 +304,55 @@ - Port + D - Destination port + Remote data port 9999 + + + + A + + + + + + + Local audio input port + + + 9998 + + + - + - Audio + FMd (Hz) - + - Audio input port + FM deviation in Hz (for S16LE NFM format) - 9998 + 2500 @@ -448,7 +471,7 @@ - Destination address + Remote address 127.0.0.1 @@ -522,7 +545,6 @@ sampleFormat - udpPort sampleRate rfBandwidth applyBtn diff --git a/sdrbase/dsp/phasediscri.h b/sdrbase/dsp/phasediscri.h index 3530a439a..7078f0859 100644 --- a/sdrbase/dsp/phasediscri.h +++ b/sdrbase/dsp/phasediscri.h @@ -48,7 +48,7 @@ public: { Complex d(std::conj(m_m1Sample) * sample); m_m1Sample = sample; - return (std::atan2(d.imag(), d.real()) / M_PI_2) * m_fmScaling; + return (std::atan2(d.imag(), d.real()) / M_PI) * m_fmScaling; } /** @@ -66,7 +66,8 @@ public: m_m2Sample = m_m1Sample; m_m1Sample = sample; - return ((h1 - h2) / M_PI_2) * m_fmScaling; + //return ((h1 - h2) / M_PI_2) * m_fmScaling; + return (h1 - h2) * m_fmScaling; } private: diff --git a/sdrbase/gui/aboutdialog.ui b/sdrbase/gui/aboutdialog.ui index bee6db737..4df65bbcf 100644 --- a/sdrbase/gui/aboutdialog.ui +++ b/sdrbase/gui/aboutdialog.ui @@ -84,7 +84,7 @@ - <html><head/><body><p>Version 1.1.6 - Copyright (C) 2015-2016 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a> This is a complete redesign from RTL-SDRangelove at <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/hexameron/rtl-sdrangelove</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in RTL-SDRangelove</p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html> + <html><head/><body><p>Version 1.1.7 - Copyright (C) 2015-2016 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a> This is a complete redesign from RTL-SDRangelove at <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/hexameron/rtl-sdrangelove</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in RTL-SDRangelove</p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html> true