From 9cb1a414719bece6f6cac55d87730ff8ea8f12ac Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 5 Apr 2016 17:02:24 +0200 Subject: [PATCH] UDP source plugin: new formats with mono output in particular NFM for mono discriminator type output --- plugins/channel/udpsrc/readme.md | 9 +++- plugins/channel/udpsrc/udpsrc.cpp | 76 ++++++++++++++++++++++------ plugins/channel/udpsrc/udpsrc.h | 10 +++- plugins/channel/udpsrc/udpsrcgui.cpp | 49 +++++++++++++++--- plugins/channel/udpsrc/udpsrcgui.ui | 31 ++++++++++-- 5 files changed, 146 insertions(+), 29 deletions(-) diff --git a/plugins/channel/udpsrc/readme.md b/plugins/channel/udpsrc/readme.md index ea6ec2d39..f33080f57 100644 --- a/plugins/channel/udpsrc/readme.md +++ b/plugins/channel/udpsrc/readme.md @@ -23,8 +23,13 @@ Total power in dB relative to a +/- 1.0 amplitude signal received in the pass ba Combo box to specify the type of samples that are sent over UDP. - `S16LE I/Q`: Raw I/Q samples on signed 16 bits integers with Little Endian layout. Use it with software that accepts I/Q data as input like GNUradio with the `UDP source` block. The output is interleaved I and Q samples - - `S16LE SSB`: AF of SSB demodulated signal as 16 bits signed integers with Little Endian layout. Use it with software that uses a SSB demodulated signal as input i.e. software that is based on the audio output of a SSB radio. The output is interleaved samples of the USB (on real part) and LSB signals (on imaginary part). - - `S16LE NFM`: AF of FM demodulated signal as 16 bits signed integers with Little Endian layout. Use it with software that takes the FM demodulated audio or the discriminator output of a radio as input. Make sure you specify the appropriate signal bandwidth (see 7) according to the AF bandwidth needs. The output is a repetition of NFM samples on real part and on imaginary part this facilitates integration wtih software expecting a mono from stereo like input. With GNURadio just use a complex to real block. + - `S16LE NFM`: AF of FM demodulated signal as 16 bits signed integers with Little Endian layout. Use it with software that takes the FM demodulated audio or the discriminator output of a radio as input. Make sure you specify the appropriate signal bandwidth (see 7) according to the AF bandwidth needs. The output is a repetition of NFM samples on real part and on imaginary part this facilitates integration wtih software expecting a stereo type of input with the same samples on L and R channels. With GNURadio just use a complex to real block. + - `S16LE NFM Mono`: This is the same as above but only one sample is output for one NFM sample. This can be used with software that accept a mono type of input like `dsd`. With GNURadio you can use a short to float block but remember that the UDP payload size is now 1024 bytes so you have to change it in the UDP source block. + - `S16LE USB`: AF of USB demodulated signal as 16 bits signed integers with Little Endian layout. Use it with software that uses a SSB demodulated signal as input i.e. software that is based on the audio output of a SSB radio. The output is the I/Q binaural output of the demodulator. + - `S16LE LSB`: AF of LSB demodulated signal as 16 bits signed integers with Little Endian layout. Use it with software that uses a SSB demodulated signal as input i.e. software that is based on the audio output of a SSB radio. The output is the I/Q binaural output of the demodulator. + - `S16LE LSB Mono`: AF of the LSB part of a SSB demodulated signal as "mono" (I+Q)*0.7 samples that is one sample per demodulator output sample. This can be used with software that accepts mono type of input. Remember that as these are single 16 bits samples the UDP payload size is 1024 bytes (not 2048). + - `S16LE USB Mono`: AF of the USB part of a SSB demodulated signal as "mono" (I+Q)*0.7 samples that is one sample per demodulator output sample. This can be used with software that accepts mono type of input. Remember that as these are single 16 bits samples the UDP payload size is 1024 bytes (not 2048). + - `S16LE AM Mono`: AF of the enveloppe demodulated signal i.e. channel magnitude or sqrt(I² + Q²) as "mono" samples that is one sample per demodulator output sample. This can be used with software that accepts mono type of input. Remember that as these are single 16 bits samples the UDP payload size is 1024 bytes (not 2048)

4: Signal sample rate

diff --git a/plugins/channel/udpsrc/udpsrc.cpp b/plugins/channel/udpsrc/udpsrc.cpp index 1a59a6209..2167f97a1 100644 --- a/plugins/channel/udpsrc/udpsrc.cpp +++ b/plugins/channel/udpsrc/udpsrc.cpp @@ -40,13 +40,14 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, SampleSink* s setObjectName("UDPSrc"); m_udpBuffer = new UDPSink(this, udpBLockSampleSize, m_udpPort); + m_udpBufferMono = new UDPSink(this, udpBLockSampleSize, m_udpPort); m_audioSocket = new QUdpSocket(this); m_audioBuffer.resize(1<<9); m_audioBufferFill = 0; m_inputSampleRate = 96000; - m_sampleFormat = FormatSSB; + m_sampleFormat = FormatS16LE; m_outputSampleRate = 48000; m_rfBandwidth = 32000; m_audioPort = m_udpPort - 1; @@ -65,7 +66,7 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, SampleSink* s m_scale = 0; m_boost = 0; m_magsq = 0; - UDPFilter = new fftfilt(0.3 / 48.0, 16.0 / 48.0, udpBLockSampleSize * sizeof(Sample)); + UDPFilter = new fftfilt(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate, udpBLockSampleSize * sizeof(Sample)); m_phaseDiscri.setFMScaling((float) m_outputSampleRate / (2.0f * m_fmDeviation)); @@ -86,6 +87,7 @@ UDPSrc::~UDPSrc() { delete m_audioSocket; delete m_udpBuffer; + delete m_udpBufferMono; if (UDPFilter) delete UDPFilter; if (m_audioActive) DSPEngine::instance()->removeAudioSink(&m_audioFifo); } @@ -151,16 +153,30 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: m_sampleBuffer.push_back(s); m_sampleDistanceRemain += m_inputSampleRate / m_outputSampleRate; - if (m_sampleFormat == FormatSSB) + if (m_sampleFormat == FormatLSB) + { + int n_out = UDPFilter->runSSB(ci, &sideband, false); + + if (n_out) + { + for (int i = 0; i < n_out; i++) + { + l = sideband[i].real(); + r = sideband[i].imag(); + m_udpBuffer->write(Sample(l, r)); + } + } + } + if (m_sampleFormat == FormatUSB) { int n_out = UDPFilter->runSSB(ci, &sideband, true); if (n_out) { - for (int i = 0; i < n_out; i+=2) + for (int i = 0; i < n_out; i++) { - l = (sideband[i].real() + sideband[i].imag()) * 0.7; - r = (sideband[i+1].real() + sideband[i+1].imag()) * 0.7; + l = sideband[i].real(); + r = sideband[i].imag(); m_udpBuffer->write(Sample(l, r)); } } @@ -170,6 +186,42 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector: Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci); m_udpBuffer->write(Sample(demod, demod)); } + else if (m_sampleFormat == FormatNFMMono) + { + FixReal demod = (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci)); + m_udpBufferMono->write(demod); + } + else if (m_sampleFormat == FormatLSBMono) + { + int n_out = UDPFilter->runSSB(ci, &sideband, false); + + if (n_out) + { + for (int i = 0; i < n_out; i++) + { + l = (sideband[i].real() + sideband[i].imag()) * 0.7; + m_udpBufferMono->write(l); + } + } + } + else if (m_sampleFormat == FormatUSBMono) + { + int n_out = UDPFilter->runSSB(ci, &sideband, true); + + if (n_out) + { + for (int i = 0; i < n_out; i++) + { + l = (sideband[i].real() + sideband[i].imag()) * 0.7; + m_udpBufferMono->write(l); + } + } + } + else if (m_sampleFormat == FormatAMMono) + { + FixReal demod = (FixReal) (32768.0f * sqrt(m_magsq)); + m_udpBufferMono->write(demod); + } else // Raw I/Q samples { m_udpBuffer->write(s); @@ -279,12 +331,14 @@ bool UDPSrc::handleMessage(const Message& cmd) { m_udpAddressStr = cfg.getUDPAddress(); m_udpBuffer->setAddress(m_udpAddressStr); + m_udpBufferMono->setAddress(m_udpAddressStr); } if (cfg.getUDPPort() != m_udpPort) { m_udpPort = cfg.getUDPPort(); m_udpBuffer->setPort(m_udpPort); + m_udpBufferMono->setPort(m_udpPort); } if (cfg.getAudioPort() != m_audioPort) @@ -313,15 +367,7 @@ bool UDPSrc::handleMessage(const Message& cmd) m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0); m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate; - - if (m_sampleFormat == FormatSSB) - { - UDPFilter->create_filter(0.3 / 48.0, m_rfBandwidth / 2.0 / m_outputSampleRate); - } - else - { - UDPFilter->create_filter(0.0, m_rfBandwidth / 2.0 / m_outputSampleRate); - } + UDPFilter->create_filter(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate); m_settingsMutex.unlock(); diff --git a/plugins/channel/udpsrc/udpsrc.h b/plugins/channel/udpsrc/udpsrc.h index d3b85c950..e4ba5afe3 100644 --- a/plugins/channel/udpsrc/udpsrc.h +++ b/plugins/channel/udpsrc/udpsrc.h @@ -38,9 +38,14 @@ class UDPSrc : public SampleSink { public: enum SampleFormat { - FormatSSB, - FormatNFM, FormatS16LE, + FormatNFM, + FormatNFMMono, + FormatLSB, + FormatUSB, + FormatLSBMono, + FormatUSBMono, + FormatAMMono, FormatNone }; @@ -228,6 +233,7 @@ protected: SampleVector m_sampleBuffer; UDPSink *m_udpBuffer; + UDPSink *m_udpBufferMono; AudioVector m_audioBuffer; uint m_audioBufferFill; diff --git a/plugins/channel/udpsrc/udpsrcgui.cpp b/plugins/channel/udpsrc/udpsrcgui.cpp index 0c449ea36..3ca715d82 100644 --- a/plugins/channel/udpsrc/udpsrcgui.cpp +++ b/plugins/channel/udpsrc/udpsrcgui.cpp @@ -129,17 +129,32 @@ bool UDPSrcGUI::deserialize(const QByteArray& data) restoreState(bytetmp); d.readS32(2, &s32tmp, 0); m_channelMarker.setCenterFrequency(s32tmp); - d.readS32(3, &s32tmp, UDPSrc::FormatSSB); + d.readS32(3, &s32tmp, UDPSrc::FormatS16LE); switch(s32tmp) { - case UDPSrc::FormatSSB: + case UDPSrc::FormatS16LE: ui->sampleFormat->setCurrentIndex(0); break; case UDPSrc::FormatNFM: ui->sampleFormat->setCurrentIndex(1); break; - case UDPSrc::FormatS16LE: + case UDPSrc::FormatNFMMono: ui->sampleFormat->setCurrentIndex(2); break; + case UDPSrc::FormatLSB: + ui->sampleFormat->setCurrentIndex(3); + break; + case UDPSrc::FormatUSB: + ui->sampleFormat->setCurrentIndex(4); + break; + case UDPSrc::FormatLSBMono: + ui->sampleFormat->setCurrentIndex(5); + break; + case UDPSrc::FormatUSBMono: + ui->sampleFormat->setCurrentIndex(6); + break; + case UDPSrc::FormatAMMono: + ui->sampleFormat->setCurrentIndex(7); + break; default: ui->sampleFormat->setCurrentIndex(0); break; @@ -356,7 +371,7 @@ void UDPSrcGUI::applySettings() switch(ui->sampleFormat->currentIndex()) { case 0: - sampleFormat = UDPSrc::FormatSSB; + sampleFormat = UDPSrc::FormatS16LE; ui->fmDeviation->setEnabled(false); break; case 1: @@ -364,11 +379,31 @@ void UDPSrcGUI::applySettings() ui->fmDeviation->setEnabled(true); break; case 2: - sampleFormat = UDPSrc::FormatS16LE; + sampleFormat = UDPSrc::FormatNFMMono; + ui->fmDeviation->setEnabled(true); + break; + case 3: + sampleFormat = UDPSrc::FormatLSB; + ui->fmDeviation->setEnabled(false); + break; + case 4: + sampleFormat = UDPSrc::FormatUSB; + ui->fmDeviation->setEnabled(false); + break; + case 5: + sampleFormat = UDPSrc::FormatLSBMono; + ui->fmDeviation->setEnabled(false); + break; + case 6: + sampleFormat = UDPSrc::FormatUSBMono; + ui->fmDeviation->setEnabled(false); + break; + case 7: + sampleFormat = UDPSrc::FormatAMMono; ui->fmDeviation->setEnabled(false); break; default: - sampleFormat = UDPSrc::FormatSSB; + sampleFormat = UDPSrc::FormatS16LE; ui->fmDeviation->setEnabled(false); break; } @@ -416,7 +451,7 @@ void UDPSrcGUI::on_deltaFrequency_changed(quint64 value) void UDPSrcGUI::on_sampleFormat_currentIndexChanged(int index) { - if (index == 1) { + if ((index == 1) || (index == 2)) { ui->fmDeviation->setEnabled(true); } else { ui->fmDeviation->setEnabled(false); diff --git a/plugins/channel/udpsrc/udpsrcgui.ui b/plugins/channel/udpsrc/udpsrcgui.ui index fcca36a19..61fc34f2d 100644 --- a/plugins/channel/udpsrc/udpsrcgui.ui +++ b/plugins/channel/udpsrc/udpsrcgui.ui @@ -440,11 +440,11 @@ Samples format - 2 + 0 - S16LE SSB + S16LE I/Q @@ -454,7 +454,32 @@ - S16LE I/Q + S16LE NFM Mono + + + + + S16LE LSB + + + + + S16LE USB + + + + + S16LE LSB Mono + + + + + S16LE USB Mono + + + + + S16LE AM Mono