SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
wfmdemod.cpp
Go to the documentation of this file.
1 // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
3 // written by Christian Daniel //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 
20 #include <stdio.h>
21 #include <complex.h>
22 
23 #include <QTime>
24 #include <QDebug>
25 #include <QNetworkAccessManager>
26 #include <QNetworkReply>
27 #include <QBuffer>
28 
29 #include "SWGChannelSettings.h"
30 #include "SWGWFMDemodSettings.h"
31 #include "SWGChannelReport.h"
32 #include "SWGWFMDemodReport.h"
33 
34 #include <dsp/downchannelizer.h>
36 #include "device/deviceapi.h"
37 #include "audio/audiooutput.h"
38 #include "dsp/dspengine.h"
39 #include "dsp/dspcommands.h"
40 #include "util/db.h"
41 
42 #include "wfmdemod.h"
43 
46 
47 const QString WFMDemod::m_channelIdURI = "sdrangel.channel.wfmdemod";
48 const QString WFMDemod::m_channelId = "WFMDemod";
49 const int WFMDemod::m_udpBlockSize = 512;
50 
52  ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
53  m_deviceAPI(deviceAPI),
54  m_inputSampleRate(384000),
55  m_inputFrequencyOffset(0),
56  m_squelchOpen(false),
57  m_magsq(0.0f),
58  m_magsqSum(0.0f),
59  m_magsqPeak(0.0f),
60  m_magsqCount(0),
61  m_audioFifo(250000),
62  m_settingsMutex(QMutex::Recursive)
63 {
64  setObjectName(m_channelId);
65 
66  m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, rfFilterFftLength);
67  m_phaseDiscri.setFMScaling(384000/75000);
68 
69  m_audioBuffer.resize(16384);
71 
74 
77 
78  m_channelizer = new DownChannelizer(this);
82 
83  m_networkManager = new QNetworkAccessManager();
84  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
85 }
86 
88 {
89  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
90  delete m_networkManager;
92 
95  delete m_threadedChannelizer;
96  delete m_channelizer;
97  delete m_rfFilter;
98 }
99 
100 void WFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
101 {
102  (void) firstOfBurst;
103  Complex ci;
104  fftfilt::cmplx *rf;
105  int rf_out;
106  Real demod;
107  double msq;
108  float fmDev;
109 
110  m_settingsMutex.lock();
111 
112  for (SampleVector::const_iterator it = begin; it != end; ++it)
113  {
114  Complex c(it->real(), it->imag());
115  c *= m_nco.nextIQ();
116 
117  rf_out = m_rfFilter->runFilt(c, &rf); // filter RF before demod
118 
119  for (int i = 0 ; i < rf_out; i++)
120  {
121  msq = rf[i].real()*rf[i].real() + rf[i].imag()*rf[i].imag();
122  Real magsq = msq / (SDR_RX_SCALED*SDR_RX_SCALED);
123  m_magsqSum += magsq;
124  m_movingAverage(magsq);
125 
126  if (magsq > m_magsqPeak) {
127  m_magsqPeak = magsq;
128  }
129 
130  m_magsqCount++;
131 
132  if (magsq >= m_squelchLevel)
133  {
134  if (m_squelchState < m_settings.m_rfBandwidth / 10) { // twice attack and decay rate
135  m_squelchState++;
136  }
137  }
138  else
139  {
140  if (m_squelchState > 0) {
141  m_squelchState--;
142  }
143  }
144 
146 
147  if (m_squelchOpen && !m_settings.m_audioMute) { // squelch open and not mute
148  demod = m_phaseDiscri.phaseDiscriminatorDelta(rf[i], msq, fmDev);
149  } else {
150  demod = 0;
151  }
152 
153  Complex e(demod, 0);
154 
156  {
157  qint16 sample = (qint16)(ci.real() * 3276.8f * m_settings.m_volume);
158  m_sampleBuffer.push_back(Sample(sample, sample));
159  m_audioBuffer[m_audioBufferFill].l = sample;
160  m_audioBuffer[m_audioBufferFill].r = sample;
161 
163 
164  if(m_audioBufferFill >= m_audioBuffer.size())
165  {
166  uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
167 
168  if (res != m_audioBufferFill) {
169  qDebug("WFMDemod::feed: %u/%u audio samples written", res, m_audioBufferFill);
170  }
171 
172  m_audioBufferFill = 0;
173  }
174 
176  }
177  }
178  }
179 
180  if (m_audioBufferFill > 0)
181  {
182  uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
183 
184  if (res != m_audioBufferFill) {
185  qDebug("WFMDemod::feed: %u/%u tail samples written", res, m_audioBufferFill);
186  }
187 
188  m_audioBufferFill = 0;
189  }
190 
191  m_sampleBuffer.clear();
192 
193  m_settingsMutex.unlock();
194 }
195 
197 {
198  m_squelchState = 0;
199  m_audioFifo.clear();
202 }
203 
205 {
206 }
207 
209 {
211  {
213  qDebug() << "WFMDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << notif.getSampleRate()
214  << " m_inputFrequencyOffset: " << notif.getFrequencyOffset();
215 
217 
218  return true;
219  }
220  else if (MsgConfigureChannelizer::match(cmd))
221  {
223  qDebug() << "WFMDemod::handleMessage: MsgConfigureChannelizer:"
224  << " sampleRate: " << cfg.getSampleRate()
225  << " inputFrequencyOffset: " << cfg.getCenterFrequency();
226 
228  cfg.getSampleRate(),
229  cfg.getCenterFrequency());
230 
231  return true;
232  }
233  else if (MsgConfigureWFMDemod::match(cmd))
234  {
236  qDebug("WFMDemod::handleMessage: MsgConfigureWFMDemod");
237 
238  applySettings(cfg.getSettings(), cfg.getForce());
239 
240  return true;
241  }
243  {
245  const QThread *thread = cfg.getThread();
246  qDebug("WFMDemod::handleMessage: BasebandSampleSink::MsgThreadedSink: %p", thread);
247  return true;
248  }
249  else if (DSPConfigureAudio::match(cmd))
250  {
251  DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
252  uint32_t sampleRate = cfg.getSampleRate();
253 
254  qDebug() << "WFMDemod::handleMessage: DSPConfigureAudio:"
255  << " sampleRate: " << sampleRate;
256 
257  if (sampleRate != m_audioSampleRate) {
258  applyAudioSampleRate(sampleRate);
259  }
260 
261  return true;
262  }
263  else if (DSPSignalNotification::match(cmd))
264  {
265  return true;
266  }
267  else
268  {
269  return false;
270  }
271 }
272 
273 void WFMDemod::applyAudioSampleRate(int sampleRate)
274 {
275  qDebug("WFMDemod::applyAudioSampleRate: %d", sampleRate);
276 
277  m_settingsMutex.lock();
278 
282 
283  m_settingsMutex.unlock();
284 
285  m_audioSampleRate = sampleRate;
286 }
287 
288 void WFMDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force)
289 {
290  qDebug() << "WFMDemod::applyChannelSettings:"
291  << " inputSampleRate: " << inputSampleRate
292  << " inputFrequencyOffset: " << inputFrequencyOffset;
293 
294  if((inputFrequencyOffset != m_inputFrequencyOffset) ||
295  (inputSampleRate != m_inputSampleRate) || force)
296  {
297  m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
298  }
299 
300  if ((inputSampleRate != m_inputSampleRate) || force)
301  {
302  qDebug() << "WFMDemod::applyChannelSettings: m_interpolator.create";
303  m_settingsMutex.lock();
304  m_interpolator.create(16, inputSampleRate, m_settings.m_afBandwidth);
306  m_interpolatorDistance = (Real) inputSampleRate / (Real) m_audioSampleRate;
307  m_settingsMutex.unlock();
308  qDebug() << "WFMDemod::applySettings: m_rfFilter->create_filter";
309  Real lowCut = -(m_settings.m_rfBandwidth / 2.0) / inputSampleRate;
310  Real hiCut = (m_settings.m_rfBandwidth / 2.0) / inputSampleRate;
311  m_rfFilter->create_filter(lowCut, hiCut);
312  m_fmExcursion = m_settings.m_rfBandwidth / (Real) inputSampleRate;
314  qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion);
315  }
316 
317  m_inputSampleRate = inputSampleRate;
318  m_inputFrequencyOffset = inputFrequencyOffset;
319 }
320 
321 void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force)
322 {
323  qDebug() << "WFMDemod::applySettings:"
324  << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
325  << " m_rfBandwidth: " << settings.m_rfBandwidth
326  << " m_afBandwidth: " << settings.m_afBandwidth
327  << " m_volume: " << settings.m_volume
328  << " m_squelch: " << settings.m_squelch
329  << " m_audioDeviceName: " << settings.m_audioDeviceName
330  << " m_audioMute: " << settings.m_audioMute
331  << " m_useReverseAPI: " << settings.m_useReverseAPI
332  << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
333  << " m_reverseAPIPort: " << settings.m_reverseAPIPort
334  << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
335  << " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
336  << " force: " << force;
337 
338  QList<QString> reverseAPIKeys;
339 
340  if((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
341  reverseAPIKeys.append("inputFrequencyOffset");
342  }
343  if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
344  reverseAPIKeys.append("rfBandwidth");
345  }
346  if((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) {
347  reverseAPIKeys.append("afBandwidth");
348  }
349  if((settings.m_volume != m_settings.m_volume) || force) {
350  reverseAPIKeys.append("volume");
351  }
352  if((settings.m_squelch != m_settings.m_squelch) || force) {
353  reverseAPIKeys.append("squelch");
354  }
355  if((settings.m_audioMute != m_settings.m_audioMute) || force) {
356  reverseAPIKeys.append("audioMute");
357  }
358  if((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) {
359  reverseAPIKeys.append("audioDeviceName");
360  }
361  if((settings.m_title != m_settings.m_title) || force) {
362  reverseAPIKeys.append("title");
363  }
364  if((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
365  reverseAPIKeys.append("rgbColor");
366  }
367 
368  if((settings.m_afBandwidth != m_settings.m_afBandwidth) ||
369  (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
370  {
371  m_settingsMutex.lock();
372  qDebug() << "WFMDemod::applySettings: m_interpolator.create";
376  qDebug() << "WFMDemod::applySettings: m_rfFilter->create_filter";
377  Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
378  Real hiCut = (settings.m_rfBandwidth / 2.0) / m_inputSampleRate;
379  m_rfFilter->create_filter(lowCut, hiCut);
382  qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion);
383  m_settingsMutex.unlock();
384  }
385 
386  if ((settings.m_squelch != m_settings.m_squelch) || force)
387  {
388  qDebug() << "WFMDemod::applySettings: set m_squelchLevel";
389  m_squelchLevel = pow(10.0, settings.m_squelch / 10.0);
390  }
391 
392  if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
393  {
395  int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
396  //qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex);
397  audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
398  uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
399 
400  if (m_audioSampleRate != audioSampleRate) {
401  applyAudioSampleRate(audioSampleRate);
402  }
403  }
404 
405  if (settings.m_useReverseAPI)
406  {
407  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
412  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
413  }
414 
415  m_settings = settings;
416 }
417 
418 QByteArray WFMDemod::serialize() const
419 {
420  return m_settings.serialize();
421 }
422 
423 bool WFMDemod::deserialize(const QByteArray& data)
424 {
425  if (m_settings.deserialize(data))
426  {
429  return true;
430  }
431  else
432  {
436  return false;
437  }
438 }
439 
442  QString& errorMessage)
443 {
444  (void) errorMessage;
446  response.getWfmDemodSettings()->init();
448  return 200;
449 }
450 
452  bool force,
453  const QStringList& channelSettingsKeys,
455  QString& errorMessage)
456 {
457  (void) errorMessage;
458  WFMDemodSettings settings = m_settings;
459  bool frequencyOffsetChanged = false;
460 
461  if (channelSettingsKeys.contains("inputFrequencyOffset"))
462  {
464  frequencyOffsetChanged = true;
465  }
466  if (channelSettingsKeys.contains("rfBandwidth")) {
467  settings.m_rfBandwidth = response.getWfmDemodSettings()->getRfBandwidth();
468  }
469  if (channelSettingsKeys.contains("afBandwidth")) {
470  settings.m_afBandwidth = response.getWfmDemodSettings()->getAfBandwidth();
471  }
472  if (channelSettingsKeys.contains("volume")) {
473  settings.m_volume = response.getWfmDemodSettings()->getVolume();
474  }
475  if (channelSettingsKeys.contains("squelch")) {
476  settings.m_squelch = response.getWfmDemodSettings()->getSquelch();
477  }
478  if (channelSettingsKeys.contains("audioMute")) {
479  settings.m_audioMute = response.getWfmDemodSettings()->getAudioMute() != 0;
480  }
481  if (channelSettingsKeys.contains("rgbColor")) {
482  settings.m_rgbColor = response.getWfmDemodSettings()->getRgbColor();
483  }
484  if (channelSettingsKeys.contains("title")) {
485  settings.m_title = *response.getWfmDemodSettings()->getTitle();
486  }
487  if (channelSettingsKeys.contains("audioDeviceName")) {
488  settings.m_audioDeviceName = *response.getWfmDemodSettings()->getAudioDeviceName();
489  }
490  if (channelSettingsKeys.contains("useReverseAPI")) {
491  settings.m_useReverseAPI = response.getWfmDemodSettings()->getUseReverseApi() != 0;
492  }
493  if (channelSettingsKeys.contains("reverseAPIAddress")) {
495  }
496  if (channelSettingsKeys.contains("reverseAPIPort")) {
497  settings.m_reverseAPIPort = response.getWfmDemodSettings()->getReverseApiPort();
498  }
499  if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
501  }
502  if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
504  }
505 
506  if (frequencyOffsetChanged)
507  {
509  requiredBW(settings.m_rfBandwidth), settings.m_inputFrequencyOffset);
510  m_inputMessageQueue.push(channelConfigMsg);
511  }
512 
513  MsgConfigureWFMDemod *msg = MsgConfigureWFMDemod::create(settings, force);
515 
516  qDebug("WFMDemod::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
517  if (m_guiMessageQueue) // forward to GUI if any
518  {
519  MsgConfigureWFMDemod *msgToGUI = MsgConfigureWFMDemod::create(settings, force);
520  m_guiMessageQueue->push(msgToGUI);
521  }
522 
523  webapiFormatChannelSettings(response, settings);
524 
525  return 200;
526 }
527 
530  QString& errorMessage)
531 {
532  (void) errorMessage;
534  response.getWfmDemodReport()->init();
535  webapiFormatChannelReport(response);
536  return 200;
537 }
538 
540 {
542  response.getWfmDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
543  response.getWfmDemodSettings()->setAfBandwidth(settings.m_afBandwidth);
544  response.getWfmDemodSettings()->setVolume(settings.m_volume);
545  response.getWfmDemodSettings()->setSquelch(settings.m_squelch);
546  response.getWfmDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
547  response.getWfmDemodSettings()->setRgbColor(settings.m_rgbColor);
548 
549  if (response.getWfmDemodSettings()->getTitle()) {
550  *response.getWfmDemodSettings()->getTitle() = settings.m_title;
551  } else {
552  response.getWfmDemodSettings()->setTitle(new QString(settings.m_title));
553  }
554 
555  if (response.getWfmDemodSettings()->getAudioDeviceName()) {
556  *response.getWfmDemodSettings()->getAudioDeviceName() = settings.m_audioDeviceName;
557  } else {
558  response.getWfmDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
559  }
560 
561  response.getWfmDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
562 
563  if (response.getWfmDemodSettings()->getReverseApiAddress()) {
565  } else {
566  response.getWfmDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
567  }
568 
572 }
573 
575 {
576  double magsqAvg, magsqPeak;
577  int nbMagsqSamples;
578  getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
579 
580  response.getWfmDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg));
581  response.getWfmDemodReport()->setSquelch(m_squelchState > 0 ? 1 : 0);
584 }
585 
586 void WFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force)
587 {
589  swgChannelSettings->setDirection(0); // single sink (Rx)
590  swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
591  swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
592  swgChannelSettings->setChannelType(new QString("WFMDemod"));
593  swgChannelSettings->setWfmDemodSettings(new SWGSDRangel::SWGWFMDemodSettings());
594  SWGSDRangel::SWGWFMDemodSettings *swgWFMDemodSettings = swgChannelSettings->getWfmDemodSettings();
595 
596  // transfer data that has been modified. When force is on transfer all data except reverse API data
597 
598  if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
599  swgWFMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
600  }
601  if (channelSettingsKeys.contains("rfBandwidth") || force) {
602  swgWFMDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
603  }
604  if (channelSettingsKeys.contains("afBandwidth") || force) {
605  swgWFMDemodSettings->setAfBandwidth(settings.m_afBandwidth);
606  }
607  if (channelSettingsKeys.contains("volume") || force) {
608  swgWFMDemodSettings->setVolume(settings.m_volume);
609  }
610  if (channelSettingsKeys.contains("squelch") || force) {
611  swgWFMDemodSettings->setSquelch(settings.m_squelch);
612  }
613  if (channelSettingsKeys.contains("audioMute") || force) {
614  swgWFMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
615  }
616  if (channelSettingsKeys.contains("rgbColor") || force) {
617  swgWFMDemodSettings->setRgbColor(settings.m_rgbColor);
618  }
619  if (channelSettingsKeys.contains("title") || force) {
620  swgWFMDemodSettings->setTitle(new QString(settings.m_title));
621  }
622  if (channelSettingsKeys.contains("audioDeviceName") || force) {
623  swgWFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
624  }
625 
626  QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
627  .arg(settings.m_reverseAPIAddress)
628  .arg(settings.m_reverseAPIPort)
629  .arg(settings.m_reverseAPIDeviceIndex)
630  .arg(settings.m_reverseAPIChannelIndex);
631  m_networkRequest.setUrl(QUrl(channelSettingsURL));
632  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
633 
634  QBuffer *buffer=new QBuffer();
635  buffer->open((QBuffer::ReadWrite));
636  buffer->write(swgChannelSettings->asJson().toUtf8());
637  buffer->seek(0);
638 
639  // Always use PATCH to avoid passing reverse API settings
640  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
641 
642  delete swgChannelSettings;
643 }
644 
645 void WFMDemod::networkManagerFinished(QNetworkReply *reply)
646 {
647  QNetworkReply::NetworkError replyError = reply->error();
648 
649  if (replyError)
650  {
651  qWarning() << "WFMDemod::networkManagerFinished:"
652  << " error(" << (int) replyError
653  << "): " << replyError
654  << ": " << reply->errorString();
655  return;
656  }
657 
658  QString answer = reply->readAll();
659  answer.chop(1); // remove last \n
660  qDebug("WFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
661 }
void setOriginatorChannelIndex(qint32 originator_channel_index)
void setReverseApiAddress(QString *reverse_api_address)
void addAudioSink(AudioFifo *audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex=-1)
Add the audio sink.
qint64 m_inputFrequencyOffset
void networkManagerFinished(QNetworkReply *reply)
Definition: wfmdemod.cpp:645
int getOutputSampleRate(int outputDeviceIndex=-1)
Complex nextIQ()
Return next complex sample.
Definition: nco.cpp:61
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
void setChannelSampleRate(qint32 channel_sample_rate)
ThreadedBasebandSampleSink * m_threadedChannelizer
Definition: wfmdemod.h:187
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void removeChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:163
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
virtual void start()
Definition: wfmdemod.cpp:196
void addChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:156
void setWfmDemodSettings(SWGWFMDemodSettings *wfm_demod_settings)
virtual QByteArray serialize() const
Definition: wfmdemod.cpp:418
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
WFMDemodSettings m_settings
Definition: wfmdemod.h:192
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setFMScaling(Real fmScaling)
Definition: phasediscri.h:42
uint16_t m_reverseAPIPort
void clear()
Definition: audiofifo.cpp:156
int getDeviceSetIndex() const
Definition: channelapi.h:89
int getOutputDeviceIndex(const QString &deviceName) const
uint16_t m_reverseAPIChannelIndex
int runFilt(const cmplx &in, cmplx **out)
Definition: fftfilt.cpp:260
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
Definition: wfmdemod.cpp:528
void removeAudioSink(AudioFifo *audioFifo)
Remove the audio sink.
int m_inputSampleRate
Definition: wfmdemod.h:190
Real m_fmExcursion
Definition: wfmdemod.h:211
QByteArray serialize() const
virtual ~WFMDemod()
Definition: wfmdemod.cpp:87
DeviceAPI * m_deviceAPI
Definition: wfmdemod.h:186
void setChannelType(QString *channel_type)
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
bool m_squelchOpen
Definition: wfmdemod.h:203
int m_squelchState
Definition: wfmdemod.h:202
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
std::complex< float > cmplx
Definition: fftfilt.h:21
const WFMDemodSettings & getSettings() const
Definition: wfmdemod.h:55
unsigned int uint32_t
Definition: rtptypes_win.h:46
Real m_squelchLevel
Definition: wfmdemod.h:201
bool deserialize(const QByteArray &data)
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: wfmdemod.cpp:451
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
SWGWFMDemodSettings * getWfmDemodSettings()
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
uint16_t m_reverseAPIDeviceIndex
SWGWFMDemodReport * getWfmDemodReport()
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
AudioVector m_audioBuffer
Definition: wfmdemod.h:213
double m_magsqPeak
Definition: wfmdemod.h:206
void create_filter(float f1, float f2)
Definition: fftfilt.cpp:107
static int requiredBW(int rfBW)
Definition: wfmdemod.h:158
int getSampleRate() const
Definition: dspcommands.h:390
static DSPEngine * instance()
Definition: dspengine.cpp:51
void getMagSqLevels(double &avg, double &peak, int &nbSamples)
Definition: wfmdemod.h:126
fftfilt * m_rfFilter
Definition: wfmdemod.h:199
QString m_reverseAPIAddress
QNetworkRequest m_networkRequest
Definition: wfmdemod.h:223
static const int m_udpBlockSize
Definition: wfmdemod.h:225
void setWfmDemodReport(SWGWFMDemodReport *wfm_demod_report)
int32_t i
Definition: decimators.h:244
Real m_interpolatorDistance
Definition: wfmdemod.h:197
void setReverseApiPort(qint32 reverse_api_port)
static bool match(const Message *message)
Definition: message.cpp:45
void setFreq(Real freq, Real sampleRate)
Definition: nco.cpp:49
Interpolator m_interpolator
Interpolator between sample rate sent from DSP engine and requested RF bandwidth (rational) ...
Definition: wfmdemod.h:196
void removeChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Remove a channel sink (Rx)
Definition: deviceapi.cpp:127
void setInputFrequencyOffset(qint64 input_frequency_offset)
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: wfmdemod.h:81
void setAfBandwidth(float af_bandwidth)
quint32 m_audioSampleRate
Definition: wfmdemod.h:193
void applyAudioSampleRate(int sampleRate)
Definition: wfmdemod.cpp:273
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force=false)
Definition: wfmdemod.cpp:288
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool po)
Definition: wfmdemod.cpp:100
QNetworkAccessManager * m_networkManager
Definition: wfmdemod.h:222
virtual QString asJson() override
static const QString m_channelIdURI
Definition: wfmdemod.h:167
void applySettings(const WFMDemodSettings &settings, bool force=false)
Definition: wfmdemod.cpp:321
void setRfBandwidth(float rf_bandwidth)
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const WFMDemodSettings &settings, bool force)
Definition: wfmdemod.cpp:586
MovingAverageUtil< Real, double, 16 > m_movingAverage
Definition: wfmdemod.h:210
static const QString m_channelId
Definition: wfmdemod.h:168
AudioDeviceManager * getAudioDeviceManager()
Definition: dspengine.h:55
void addChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Add a channel sink (Rx)
Definition: deviceapi.cpp:118
static MsgConfigureWFMDemod * create(const WFMDemodSettings &settings, bool force)
Definition: wfmdemod.h:58
WFMDemod(DeviceAPI *deviceAPI)
Definition: wfmdemod.cpp:51
uint m_audioBufferFill
Definition: wfmdemod.h:214
void setAudioSampleRate(qint32 audio_sample_rate)
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
Definition: wfmdemod.cpp:574
QMutex m_settingsMutex
Definition: wfmdemod.h:218
NCO m_nco
Definition: wfmdemod.h:195
SampleVector m_sampleBuffer
Definition: wfmdemod.h:217
int m_inputFrequencyOffset
Definition: wfmdemod.h:191
Real m_interpolatorDistanceRemain
Definition: wfmdemod.h:198
int m_magsqCount
Definition: wfmdemod.h:207
DownChannelizer * m_channelizer
Definition: wfmdemod.h:188
double m_magsqSum
Definition: wfmdemod.h:205
AudioFifo m_audioFifo
Definition: wfmdemod.h:216
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const WFMDemodSettings &settings)
Definition: wfmdemod.cpp:539
virtual void stop()
Definition: wfmdemod.cpp:204
int getIndexInDeviceSet() const
Definition: channelapi.h:87
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: wfmdemod.cpp:440
std::complex< Real > Complex
Definition: dsptypes.h:43
#define rfFilterFftLength
Definition: datvdemod.h:27
Real phaseDiscriminatorDelta(const Complex &sample, double &magsq, Real &fmDev)
Definition: phasediscri.h:62
#define SDR_RX_SCALED
Definition: dsptypes.h:34
float Real
Definition: dsptypes.h:42
PhaseDiscriminators m_phaseDiscri
Definition: wfmdemod.h:220
void setUseReverseApi(qint32 use_reverse_api)
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
Definition: wfmdemod.cpp:208
virtual bool deserialize(const QByteArray &data)
Definition: wfmdemod.cpp:423
uint32_t write(const quint8 *data, uint32_t numSamples)
Definition: audiofifo.cpp:66
void setChannelPowerDb(float channel_power_db)
void setAudioDeviceName(QString *audio_device_name)