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.
ssbmod.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include "ssbmod.h"
19 
20 #include <QTime>
21 #include <QDebug>
22 #include <QMutexLocker>
23 #include <QNetworkAccessManager>
24 #include <QNetworkReply>
25 #include <QBuffer>
26 
27 #include <stdio.h>
28 #include <complex.h>
29 #include <algorithm>
30 
31 #include "SWGChannelSettings.h"
32 #include "SWGChannelReport.h"
33 #include "SWGSSBModReport.h"
34 
35 #include "dsp/upchannelizer.h"
36 #include "dsp/dspengine.h"
38 #include "dsp/dspcommands.h"
39 #include "device/deviceapi.h"
40 #include "util/db.h"
41 
49 
50 const QString SSBMod::m_channelIdURI = "sdrangel.channeltx.modssb";
51 const QString SSBMod::m_channelId = "SSBMod";
52 const int SSBMod::m_levelNbSamples = 480; // every 10ms
53 const int SSBMod::m_ssbFftLen = 1024;
54 
56  ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource),
57  m_deviceAPI(deviceAPI),
58  m_basebandSampleRate(48000),
59  m_outputSampleRate(48000),
60  m_inputFrequencyOffset(0),
61  m_SSBFilter(0),
62  m_DSBFilter(0),
63  m_SSBFilterBuffer(0),
64  m_DSBFilterBuffer(0),
65  m_SSBFilterBufferIndex(0),
66  m_DSBFilterBufferIndex(0),
67  m_sampleSink(0),
68  m_audioFifo(4800),
69  m_feedbackAudioFifo(48000),
70  m_settingsMutex(QMutex::Recursive),
71  m_fileSize(0),
72  m_recordLength(0),
73  m_sampleRate(48000),
74  m_levelCalcCount(0),
75  m_peakLevel(0.0f),
76  m_levelSum(0.0f),
77  m_agcStepLength(2400)
78 {
79  setObjectName(m_channelId);
80 
83 
87 
90  m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size
94 // memset(m_SSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen>>1));
95 // memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen));
96 
97  m_audioBuffer.resize(1<<14);
99 
100  m_feedbackAudioBuffer.resize(1<<14);
102 
103  m_sum.real(0.0f);
104  m_sum.imag(0.0f);
105  m_undersampleCount = 0;
106  m_sumCount = 0;
107 
108  m_magsq = 0.0;
109 
111  m_cwKeyer.setSampleRate(48000);
112  m_cwKeyer.reset();
113 
116  50, // pregain (dB)
117  -30, // threshold (dB)
118  20, // knee (dB)
119  12, // ratio (dB)
120  0.003, // attack (s)
121  0.25 // release (s)
122  );
123 
125  applySettings(m_settings, true);
126 
127  m_channelizer = new UpChannelizer(this);
131 
132  m_networkManager = new QNetworkAccessManager();
133  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
134 }
135 
137 {
138  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
139  delete m_networkManager;
140 
143 
146  delete m_threadedChannelizer;
147  delete m_channelizer;
148 
149  delete m_SSBFilter;
150  delete m_DSBFilter;
151  delete[] m_SSBFilterBuffer;
152  delete[] m_DSBFilterBuffer;
153 }
154 
155 void SSBMod::pull(Sample& sample)
156 {
157  Complex ci;
158 
159  m_settingsMutex.lock();
160 
161  if (m_interpolatorDistance > 1.0f) // decimate
162  {
163  modulateSample();
164 
166  {
167  modulateSample();
168  }
169  }
170  else
171  {
173  {
174  modulateSample();
175  }
176  }
177 
179 
180  ci *= m_carrierNco.nextIQ(); // shift to carrier frequency
181  ci *= 0.891235351562f * SDR_TX_SCALEF; //scaling at -1 dB to account for possible filter overshoot
182 
183  m_settingsMutex.unlock();
184 
185  double magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
186  magsq /= (SDR_TX_SCALED*SDR_TX_SCALED);
187  m_movingAverage(magsq);
189 
190  sample.m_real = (FixReal) ci.real();
191  sample.m_imag = (FixReal) ci.imag();
192 }
193 
194 void SSBMod::pullAudio(int nbSamples)
195 {
196  unsigned int nbSamplesAudio = nbSamples * ((Real) m_audioSampleRate / (Real) m_basebandSampleRate);
197 
198  if (nbSamplesAudio > m_audioBuffer.size())
199  {
200  m_audioBuffer.resize(nbSamplesAudio);
201  }
202 
203  m_audioFifo.read(reinterpret_cast<quint8*>(&m_audioBuffer[0]), nbSamplesAudio);
204  m_audioBufferFill = 0;
205 }
206 
208 {
210 
213  }
214 
217 }
218 
219 void SSBMod::pullAF(Complex& sample)
220 {
222  {
223  sample.real(0.0f);
224  sample.imag(0.0f);
225  return;
226  }
227 
228  Complex ci;
229  fftfilt::cmplx *filtered;
230  int n_out = 0;
231 
232  int decim = 1<<(m_settings.m_spanLog2 - 1);
233  unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
234 
235  switch (m_settings.m_modAFInput)
236  {
238  if (m_settings.m_dsb)
239  {
240  Real t = m_toneNco.next()/1.25;
241  sample.real(t);
242  sample.imag(t);
243  }
244  else
245  {
246  if (m_settings.m_usb) {
247  sample = m_toneNco.nextIQ();
248  } else {
249  sample = m_toneNco.nextQI();
250  }
251  }
252  break;
254  // Monaural (mono):
255  // sox f4exb_call.wav --encoding float --endian little f4exb_call.raw
256  // ffplay -f f32le -ar 48k -ac 1 f4exb_call.raw
257  // Binaural (stereo):
258  // sox f4exb_call.wav --encoding float --endian little f4exb_call.raw
259  // ffplay -f f32le -ar 48k -ac 2 f4exb_call.raw
260  if (m_ifstream.is_open())
261  {
262  if (m_ifstream.eof())
263  {
265  {
266  m_ifstream.clear();
267  m_ifstream.seekg(0, std::ios::beg);
268  }
269  }
270 
271  if (m_ifstream.eof())
272  {
273  ci.real(0.0f);
274  ci.imag(0.0f);
275  }
276  else
277  {
279  {
280  Complex c;
281  m_ifstream.read(reinterpret_cast<char*>(&c), sizeof(Complex));
282 
284  {
285  ci.real(c.imag() * m_settings.m_volumeFactor);
286  ci.imag(c.real() * m_settings.m_volumeFactor);
287  }
288  else
289  {
290  ci = c * m_settings.m_volumeFactor;
291  }
292  }
293  else
294  {
295  Real real;
296  m_ifstream.read(reinterpret_cast<char*>(&real), sizeof(Real));
297 
298  if (m_settings.m_agc)
299  {
300  real = m_audioCompressor.compress(real);
301  ci.real(real);
302  ci.imag(0.0f);
304  }
305  else
306  {
307  ci.real(real * m_settings.m_volumeFactor);
308  ci.imag(0.0f);
309  }
310  }
311  }
312  }
313  else
314  {
315  ci.real(0.0f);
316  ci.imag(0.0f);
317  }
318  break;
321  {
323  {
326  }
327  else
328  {
331  }
332  }
333  else
334  {
335  if (m_settings.m_agc)
336  {
337  ci.real(((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f));
338  ci.real(m_audioCompressor.compress(ci.real()));
339  ci.imag(0.0f);
341  }
342  else
343  {
345  ci.imag(0.0f);
346  }
347  }
348 
349  break;
351  Real fadeFactor;
352 
353  if (m_cwKeyer.getSample())
354  {
355  m_cwKeyer.getCWSmoother().getFadeSample(true, fadeFactor);
356 
357  if (m_settings.m_dsb)
358  {
359  Real t = m_toneNco.next() * fadeFactor;
360  sample.real(t);
361  sample.imag(t);
362  }
363  else
364  {
365  if (m_settings.m_usb) {
366  sample = m_toneNco.nextIQ() * fadeFactor;
367  } else {
368  sample = m_toneNco.nextQI() * fadeFactor;
369  }
370  }
371  }
372  else
373  {
374  if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor))
375  {
376  if (m_settings.m_dsb)
377  {
378  Real t = (m_toneNco.next() * fadeFactor)/1.25;
379  sample.real(t);
380  sample.imag(t);
381  }
382  else
383  {
384  if (m_settings.m_usb) {
385  sample = m_toneNco.nextIQ() * fadeFactor;
386  } else {
387  sample = m_toneNco.nextQI() * fadeFactor;
388  }
389  }
390  }
391  else
392  {
393  sample.real(0.0f);
394  sample.imag(0.0f);
395  m_toneNco.setPhase(0);
396  }
397  }
398 
399  break;
401  default:
402  sample.real(0.0f);
403  sample.imag(0.0f);
404  break;
405  }
406 
409  {
410  if (m_settings.m_dsb)
411  {
412  n_out = m_DSBFilter->runDSB(ci, &filtered);
413 
414  if (n_out > 0)
415  {
416  memcpy((void *) m_DSBFilterBuffer, (const void *) filtered, n_out*sizeof(Complex));
418  }
419 
422  }
423  else
424  {
425  n_out = m_SSBFilter->runSSB(ci, &filtered, m_settings.m_usb);
426 
427  if (n_out > 0)
428  {
429  memcpy((void *) m_SSBFilterBuffer, (const void *) filtered, n_out*sizeof(Complex));
431  }
432 
435  }
436 
437  if (n_out > 0)
438  {
439  for (int i = 0; i < n_out; i++)
440  {
441  // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
442  // smart decimation with bit gain using float arithmetic (23 bits significand)
443 
444  m_sum += filtered[i];
445 
446  if (!(m_undersampleCount++ & decim_mask))
447  {
448  Real avgr = (m_sum.real() / decim) * 0.891235351562f * SDR_TX_SCALEF; //scaling at -1 dB to account for possible filter overshoot
449  Real avgi = (m_sum.imag() / decim) * 0.891235351562f * SDR_TX_SCALEF;
450 
452  { // invert spectrum for LSB
453  m_sampleBuffer.push_back(Sample(avgi, avgr));
454  }
455  else
456  {
457  m_sampleBuffer.push_back(Sample(avgr, avgi));
458  }
459 
460  m_sum.real(0.0);
461  m_sum.imag(0.0);
462  }
463  }
464  }
465  } // Real audio
468  {
469  m_sum += sample;
470 
471  if (!(m_undersampleCount++ & decim_mask))
472  {
473  Real avgr = (m_sum.real() / decim) * 0.891235351562f * SDR_TX_SCALEF; //scaling at -1 dB to account for possible filter overshoot
474  Real avgi = (m_sum.imag() / decim) * 0.891235351562f * SDR_TX_SCALEF;
475 
477  { // invert spectrum for LSB
478  m_sampleBuffer.push_back(Sample(avgi, avgr));
479  }
480  else
481  {
482  m_sampleBuffer.push_back(Sample(avgr, avgi));
483  }
484 
485  m_sum.real(0.0);
486  m_sum.imag(0.0);
487  }
488 
490  {
491  n_out = 0;
492  m_sumCount++;
493  }
494  else
495  {
496  n_out = m_sumCount;
497  m_sumCount = 0;
498  }
499  }
500 
501  if (n_out > 0)
502  {
503  if (m_sampleSink != 0)
504  {
506  }
507 
508  m_sampleBuffer.clear();
509  }
510 }
511 
513 {
514  Complex ci;
515 
516  if (m_feedbackInterpolatorDistance < 1.0f) // interpolate
517  {
519  {
520  processOneSample(ci);
522  }
523  }
524  else // decimate
525  {
527  {
528  processOneSample(ci);
530  }
531  }
532 }
533 
535 {
539 
541  {
543 
544  if (res != m_feedbackAudioBufferFill)
545  {
546  qDebug("AMDemod::pushFeedback: %u/%u audio samples written m_feedbackInterpolatorDistance: %f",
549  }
550 
552  }
553 }
554 
556 {
557  Real t = sample.real(); // TODO: possibly adjust depending on sample type
558 
560  {
561  m_peakLevel = std::max(std::fabs(m_peakLevel), t);
562  m_levelSum += t * t;
564  }
565  else
566  {
567  qreal rmsLevel = sqrt(m_levelSum / m_levelNbSamples);
568  //qDebug("NFMMod::calculateLevel: %f %f", rmsLevel, m_peakLevel);
569  emit levelChanged(rmsLevel, m_peakLevel, m_levelNbSamples);
570  m_peakLevel = 0.0f;
571  m_levelSum = 0.0f;
572  m_levelCalcCount = 0;
573  }
574 }
575 
577 {
578  qDebug() << "SSBMod::start: m_outputSampleRate: " << m_outputSampleRate
579  << " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset;
580 
581  m_audioFifo.clear();
583 }
584 
586 {
587 }
588 
590 {
592  {
594  qDebug() << "SSBMod::handleMessage: MsgChannelizerNotification";
595 
597 
598  return true;
599  }
600  else if (MsgConfigureChannelizer::match(cmd))
601  {
603  qDebug() << "SSBMod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
604  << " centerFrequency: " << cfg.getCenterFrequency();
605 
607  cfg.getSampleRate(),
608  cfg.getCenterFrequency());
609 
610  return true;
611  }
612  else if (MsgConfigureSSBMod::match(cmd))
613  {
615  qDebug() << "SSBMod::handleMessage: MsgConfigureSSBMod";
616 
617  applySettings(cfg.getSettings(), cfg.getForce());
618 
619  return true;
620  }
621  else if (MsgConfigureFileSourceName::match(cmd))
622  {
624  m_fileName = conf.getFileName();
625  openFileStream();
626  return true;
627  }
628  else if (MsgConfigureFileSourceSeek::match(cmd))
629  {
631  int seekPercentage = conf.getPercentage();
632  seekFileStream(seekPercentage);
633 
634  return true;
635  }
637  {
638  std::size_t samplesCount;
639 
640  if (m_ifstream.eof()) {
641  samplesCount = m_fileSize / sizeof(Real);
642  } else {
643  samplesCount = m_ifstream.tellg() / sizeof(Real);
644  }
645 
646  if (getMessageQueueToGUI())
647  {
649  report = MsgReportFileSourceStreamTiming::create(samplesCount);
650  getMessageQueueToGUI()->push(report);
651  }
652 
653  return true;
654  }
656  {
658 
661  }
662 
663  return true;
664  }
665  else if (DSPConfigureAudio::match(cmd))
666  {
667  DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
668  uint32_t sampleRate = cfg.getSampleRate();
669  DSPConfigureAudio::AudioType audioType = cfg.getAudioType();
670 
671  qDebug() << "SSBMod::handleMessage: DSPConfigureAudio:"
672  << " sampleRate: " << sampleRate
673  << " audioType: " << audioType;
674 
675  if (audioType == DSPConfigureAudio::AudioInput)
676  {
677  if (sampleRate != m_audioSampleRate) {
678  applyAudioSampleRate(sampleRate);
679  }
680  }
681  else if (audioType == DSPConfigureAudio::AudioOutput)
682  {
683  if (sampleRate != m_audioSampleRate) {
684  applyFeedbackAudioSampleRate(sampleRate);
685  }
686  }
687 
688  return true;
689  }
690  else if (DSPSignalNotification::match(cmd))
691  {
692  return true;
693  }
694  else
695  {
696  return false;
697  }
698 }
699 
701 {
702  if (m_ifstream.is_open()) {
703  m_ifstream.close();
704  }
705 
706  m_ifstream.open(m_fileName.toStdString().c_str(), std::ios::binary | std::ios::ate);
707  m_fileSize = m_ifstream.tellg();
708  m_ifstream.seekg(0,std::ios_base::beg);
709 
710  m_sampleRate = 48000; // fixed rate
711  m_recordLength = m_fileSize / (sizeof(Real) * m_sampleRate);
712 
713  qDebug() << "SSBMod::openFileStream: " << m_fileName.toStdString().c_str()
714  << " fileSize: " << m_fileSize << "bytes"
715  << " length: " << m_recordLength << " seconds";
716 
717  if (getMessageQueueToGUI())
718  {
720  report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength);
721  getMessageQueueToGUI()->push(report);
722  }
723 }
724 
725 void SSBMod::seekFileStream(int seekPercentage)
726 {
727  QMutexLocker mutexLocker(&m_settingsMutex);
728 
729  if (m_ifstream.is_open())
730  {
731  int seekPoint = ((m_recordLength * seekPercentage) / 100) * m_sampleRate;
732  seekPoint *= sizeof(Real);
733  m_ifstream.clear();
734  m_ifstream.seekg(seekPoint, std::ios::beg);
735  }
736 }
737 
738 void SSBMod::applyAudioSampleRate(int sampleRate)
739 {
740  qDebug("SSBMod::applyAudioSampleRate: %d", sampleRate);
741 
742 
744  sampleRate, m_settings.m_inputFrequencyOffset);
745  m_inputMessageQueue.push(channelConfigMsg);
746 
747  m_settingsMutex.lock();
748 
750  m_interpolatorConsumed = false;
752  m_interpolator.create(48, sampleRate, m_settings.m_bandwidth, 3.0);
753 
754  float band = m_settings.m_bandwidth;
755  float lowCutoff = m_settings.m_lowCutoff;
756  bool usb = m_settings.m_usb;
757 
758  if (band < 100.0f) // at least 100 Hz
759  {
760  band = 100.0f;
761  lowCutoff = 0;
762  }
763 
764  if (band - lowCutoff < 100.0f) {
765  lowCutoff = band - 100.0f;
766  }
767 
768  m_SSBFilter->create_filter(lowCutoff / sampleRate, band / sampleRate);
769  m_DSBFilter->create_dsb_filter((2.0f * band) / sampleRate);
770 
771  m_settings.m_bandwidth = band;
772  m_settings.m_lowCutoff = lowCutoff;
773  m_settings.m_usb = usb;
774 
776  m_cwKeyer.setSampleRate(sampleRate);
777 
778  m_audioCompressor.m_rate = sampleRate;
780 
781  m_settingsMutex.unlock();
782 
783  m_audioSampleRate = sampleRate;
784 
785  if (getMessageQueueToGUI())
786  {
788  getMessageQueueToGUI()->push(cfg);
789  }
790 
792 }
793 
794 void SSBMod::applyFeedbackAudioSampleRate(unsigned int sampleRate)
795 {
796  qDebug("SSBMod::applyFeedbackAudioSampleRate: %u", sampleRate);
797 
798  m_settingsMutex.lock();
799 
803  Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f;
804  m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0);
805 
806  m_settingsMutex.unlock();
807 
808  m_feedbackAudioSampleRate = sampleRate;
809 }
810 
811 void SSBMod::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
812 {
813  qDebug() << "SSBMod::applyChannelSettings:"
814  << " basebandSampleRate: " << basebandSampleRate
815  << " outputSampleRate: " << outputSampleRate
816  << " inputFrequencyOffset: " << inputFrequencyOffset;
817 
818  if ((inputFrequencyOffset != m_inputFrequencyOffset) ||
819  (outputSampleRate != m_outputSampleRate) || force)
820  {
821  m_settingsMutex.lock();
822  m_carrierNco.setFreq(inputFrequencyOffset, outputSampleRate);
823  m_settingsMutex.unlock();
824  }
825 
826  if ((outputSampleRate != m_outputSampleRate) || force)
827  {
828  m_settingsMutex.lock();
830  m_interpolatorConsumed = false;
831  m_interpolatorDistance = (Real) m_audioSampleRate / (Real) outputSampleRate;
833  m_settingsMutex.unlock();
834  }
835 
836  m_basebandSampleRate = basebandSampleRate;
837  m_outputSampleRate = outputSampleRate;
838  m_inputFrequencyOffset = inputFrequencyOffset;
839 }
840 
841 void SSBMod::applySettings(const SSBModSettings& settings, bool force)
842 {
843  float band = settings.m_bandwidth;
844  float lowCutoff = settings.m_lowCutoff;
845  bool usb = settings.m_usb;
846  QList<QString> reverseAPIKeys;
847 
848  if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
849  reverseAPIKeys.append("inputFrequencyOffset");
850  }
851  if ((settings.m_bandwidth != m_settings.m_bandwidth) || force) {
852  reverseAPIKeys.append("bandwidth");
853  }
854  if ((settings.m_lowCutoff != m_settings.m_lowCutoff) || force) {
855  reverseAPIKeys.append("lowCutoff");
856  }
857  if ((settings.m_usb != m_settings.m_usb) || force) {
858  reverseAPIKeys.append("usb");
859  }
860  if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || force) {
861  reverseAPIKeys.append("toneFrequency");
862  }
863  if ((settings.m_volumeFactor != m_settings.m_volumeFactor) || force) {
864  reverseAPIKeys.append("volumeFactor");
865  }
866  if ((settings.m_spanLog2 != m_settings.m_spanLog2) || force) {
867  reverseAPIKeys.append("spanLog2");
868  }
869  if ((settings.m_audioBinaural != m_settings.m_audioBinaural) || force) {
870  reverseAPIKeys.append("audioBinaural");
871  }
872  if ((settings.m_audioFlipChannels != m_settings.m_audioFlipChannels) || force) {
873  reverseAPIKeys.append("audioFlipChannels");
874  }
875  if ((settings.m_dsb != m_settings.m_dsb) || force) {
876  reverseAPIKeys.append("dsb");
877  }
878  if ((settings.m_audioMute != m_settings.m_audioMute) || force) {
879  reverseAPIKeys.append("audioMute");
880  }
881  if ((settings.m_playLoop != m_settings.m_playLoop) || force) {
882  reverseAPIKeys.append("playLoop");
883  }
884  if ((settings.m_agc != m_settings.m_agc) || force) {
885  reverseAPIKeys.append("agc");
886  }
887  if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
888  reverseAPIKeys.append("rgbColor");
889  }
890  if ((settings.m_title != m_settings.m_title) || force) {
891  reverseAPIKeys.append("title");
892  }
893  if ((settings.m_modAFInput != m_settings.m_modAFInput) || force) {
894  reverseAPIKeys.append("modAFInput");
895  }
896  if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) {
897  reverseAPIKeys.append("audioDeviceName");
898  }
899 
900  if ((settings.m_bandwidth != m_settings.m_bandwidth) ||
901  (settings.m_lowCutoff != m_settings.m_lowCutoff) || force)
902  {
903  if (band < 100.0f) // at least 100 Hz
904  {
905  band = 100.0f;
906  lowCutoff = 0;
907  }
908 
909  if (band - lowCutoff < 100.0f) {
910  lowCutoff = band - 100.0f;
911  }
912 
913  m_settingsMutex.lock();
915  m_interpolatorConsumed = false;
917  m_interpolator.create(48, m_audioSampleRate, band, 3.0);
920  m_settingsMutex.unlock();
921  }
922 
923  if ((settings.m_toneFrequency != m_settings.m_toneFrequency) || force)
924  {
925  m_settingsMutex.lock();
927  m_settingsMutex.unlock();
928  }
929 
930  if ((settings.m_dsb != m_settings.m_dsb) || force)
931  {
932  if (settings.m_dsb)
933  {
935  //memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen));
937  }
938  else
939  {
941  //memset(m_SSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen>>1));
943  }
944  }
945 
946  if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
947  {
949  int audioDeviceIndex = audioDeviceManager->getInputDeviceIndex(settings.m_audioDeviceName);
950  audioDeviceManager->addAudioSource(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
951  uint32_t audioSampleRate = audioDeviceManager->getInputSampleRate(audioDeviceIndex);
952 
953  if (m_audioSampleRate != audioSampleRate) {
954  applyAudioSampleRate(audioSampleRate);
955  }
956  }
957 
959  {
960  reverseAPIKeys.append("feedbackAudioDeviceName");
962  int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_feedbackAudioDeviceName);
963  audioDeviceManager->addAudioSink(&m_feedbackAudioFifo, getInputMessageQueue(), audioDeviceIndex);
964  uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
965 
966  if (m_feedbackAudioSampleRate != audioSampleRate) {
967  reverseAPIKeys.append("feedbackAudioSampleRate");
968  applyFeedbackAudioSampleRate(audioSampleRate);
969  }
970  }
971 
972  if (settings.m_useReverseAPI)
973  {
974  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
979  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
980  }
981 
982  m_settings = settings;
983  m_settings.m_bandwidth = band;
984  m_settings.m_lowCutoff = lowCutoff;
985  m_settings.m_usb = usb;
986 }
987 
988 QByteArray SSBMod::serialize() const
989 {
990  return m_settings.serialize();
991 }
992 
993 bool SSBMod::deserialize(const QByteArray& data)
994 {
995  if (m_settings.deserialize(data))
996  {
999  return true;
1000  }
1001  else
1002  {
1006  return false;
1007  }
1008 }
1009 
1012  QString& errorMessage)
1013 {
1014  (void) errorMessage;
1016  response.getSsbModSettings()->init();
1018  return 200;
1019 }
1020 
1022  bool force,
1023  const QStringList& channelSettingsKeys,
1025  QString& errorMessage)
1026 {
1027  (void) errorMessage;
1028  SSBModSettings settings = m_settings;
1029  bool frequencyOffsetChanged = false;
1030 
1031  if (channelSettingsKeys.contains("inputFrequencyOffset"))
1032  {
1034  frequencyOffsetChanged = true;
1035  }
1036  if (channelSettingsKeys.contains("bandwidth")) {
1037  settings.m_bandwidth = response.getSsbModSettings()->getBandwidth();
1038  }
1039  if (channelSettingsKeys.contains("lowCutoff")) {
1040  settings.m_lowCutoff = response.getSsbModSettings()->getLowCutoff();
1041  }
1042  if (channelSettingsKeys.contains("usb")) {
1043  settings.m_usb = response.getSsbModSettings()->getUsb() != 0;
1044  }
1045  if (channelSettingsKeys.contains("toneFrequency")) {
1046  settings.m_toneFrequency = response.getSsbModSettings()->getToneFrequency();
1047  }
1048  if (channelSettingsKeys.contains("volumeFactor")) {
1049  settings.m_volumeFactor = response.getSsbModSettings()->getVolumeFactor();
1050  }
1051  if (channelSettingsKeys.contains("spanLog2")) {
1052  settings.m_spanLog2 = response.getSsbModSettings()->getSpanLog2();
1053  }
1054  if (channelSettingsKeys.contains("audioBinaural")) {
1055  settings.m_audioBinaural = response.getSsbModSettings()->getAudioBinaural() != 0;
1056  }
1057  if (channelSettingsKeys.contains("audioFlipChannels")) {
1058  settings.m_audioFlipChannels = response.getSsbModSettings()->getAudioFlipChannels() != 0;
1059  }
1060  if (channelSettingsKeys.contains("dsb")) {
1061  settings.m_dsb = response.getSsbModSettings()->getDsb() != 0;
1062  }
1063  if (channelSettingsKeys.contains("audioMute")) {
1064  settings.m_audioMute = response.getSsbModSettings()->getAudioMute() != 0;
1065  }
1066  if (channelSettingsKeys.contains("playLoop")) {
1067  settings.m_playLoop = response.getSsbModSettings()->getPlayLoop() != 0;
1068  }
1069  if (channelSettingsKeys.contains("agc")) {
1070  settings.m_agc = response.getSsbModSettings()->getAgc() != 0;
1071  }
1072  if (channelSettingsKeys.contains("rgbColor")) {
1073  settings.m_rgbColor = response.getSsbModSettings()->getRgbColor();
1074  }
1075  if (channelSettingsKeys.contains("title")) {
1076  settings.m_title = *response.getSsbModSettings()->getTitle();
1077  }
1078  if (channelSettingsKeys.contains("modAFInput")) {
1080  }
1081  if (channelSettingsKeys.contains("audioDeviceName")) {
1082  settings.m_audioDeviceName = *response.getSsbModSettings()->getAudioDeviceName();
1083  }
1084  if (channelSettingsKeys.contains("useReverseAPI")) {
1085  settings.m_useReverseAPI = response.getSsbModSettings()->getUseReverseApi() != 0;
1086  }
1087  if (channelSettingsKeys.contains("reverseAPIAddress")) {
1089  }
1090  if (channelSettingsKeys.contains("reverseAPIPort")) {
1091  settings.m_reverseAPIPort = response.getSsbModSettings()->getReverseApiPort();
1092  }
1093  if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
1095  }
1096  if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
1098  }
1099 
1100  if (channelSettingsKeys.contains("cwKeyer"))
1101  {
1102  SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getSsbModSettings()->getCwKeyer();
1103  CWKeyerSettings cwKeyerSettings = m_cwKeyer.getSettings();
1104  m_cwKeyer.webapiSettingsPutPatch(channelSettingsKeys, cwKeyerSettings, apiCwKeyerSettings);
1105 
1106  CWKeyer::MsgConfigureCWKeyer *msgCwKeyer = CWKeyer::MsgConfigureCWKeyer::create(cwKeyerSettings, force);
1107  m_cwKeyer.getInputMessageQueue()->push(msgCwKeyer);
1108 
1109  if (m_guiMessageQueue) // forward to GUI if any
1110  {
1111  CWKeyer::MsgConfigureCWKeyer *msgCwKeyerToGUI = CWKeyer::MsgConfigureCWKeyer::create(cwKeyerSettings, force);
1112  m_guiMessageQueue->push(msgCwKeyerToGUI);
1113  }
1114  }
1115 
1116  if (frequencyOffsetChanged)
1117  {
1120  m_inputMessageQueue.push(msgChan);
1121  }
1122 
1123  MsgConfigureSSBMod *msg = MsgConfigureSSBMod::create(settings, force);
1125 
1126  if (m_guiMessageQueue) // forward to GUI if any
1127  {
1128  MsgConfigureSSBMod *msgToGUI = MsgConfigureSSBMod::create(settings, force);
1129  m_guiMessageQueue->push(msgToGUI);
1130  }
1131 
1132  webapiFormatChannelSettings(response, settings);
1133 
1134  return 200;
1135 }
1136 
1139  QString& errorMessage)
1140 {
1141  (void) errorMessage;
1143  response.getSsbModReport()->init();
1144  webapiFormatChannelReport(response);
1145  return 200;
1146 }
1147 
1149 {
1151  response.getSsbModSettings()->setBandwidth(settings.m_bandwidth);
1152  response.getSsbModSettings()->setLowCutoff(settings.m_lowCutoff);
1153  response.getSsbModSettings()->setUsb(settings.m_usb ? 1 : 0);
1154  response.getSsbModSettings()->setToneFrequency(settings.m_toneFrequency);
1155  response.getSsbModSettings()->setVolumeFactor(settings.m_volumeFactor);
1156  response.getSsbModSettings()->setSpanLog2(settings.m_spanLog2);
1157  response.getSsbModSettings()->setAudioBinaural(settings.m_audioBinaural ? 1 : 0);
1158  response.getSsbModSettings()->setAudioFlipChannels(settings.m_audioFlipChannels ? 1 : 0);
1159  response.getSsbModSettings()->setDsb(settings.m_dsb ? 1 : 0);
1160  response.getSsbModSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
1161  response.getSsbModSettings()->setPlayLoop(settings.m_playLoop ? 1 : 0);
1162  response.getSsbModSettings()->setAgc(settings.m_agc ? 1 : 0);
1163  response.getSsbModSettings()->setRgbColor(settings.m_rgbColor);
1164 
1165  if (response.getSsbModSettings()->getTitle()) {
1166  *response.getSsbModSettings()->getTitle() = settings.m_title;
1167  } else {
1168  response.getSsbModSettings()->setTitle(new QString(settings.m_title));
1169  }
1170 
1171  response.getSsbModSettings()->setModAfInput((int) settings.m_modAFInput);
1172 
1173  if (response.getSsbModSettings()->getAudioDeviceName()) {
1174  *response.getSsbModSettings()->getAudioDeviceName() = settings.m_audioDeviceName;
1175  } else {
1176  response.getSsbModSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
1177  }
1178 
1179  if (!response.getSsbModSettings()->getCwKeyer()) {
1181  }
1182 
1183  SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getSsbModSettings()->getCwKeyer();
1184  const CWKeyerSettings& cwKeyerSettings = m_cwKeyer.getSettings();
1185  m_cwKeyer.webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
1186 
1187  response.getSsbModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
1188 
1189  if (response.getSsbModSettings()->getReverseApiAddress()) {
1191  } else {
1192  response.getSsbModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
1193  }
1194 
1198 }
1199 
1201 {
1205 }
1206 
1207 void SSBMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBModSettings& settings, bool force)
1208 {
1210  swgChannelSettings->setDirection(1); // single source (Tx)
1211  swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
1212  swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
1213  swgChannelSettings->setChannelType(new QString("SSBMod"));
1214  swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings());
1215  SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings();
1216 
1217  // transfer data that has been modified. When force is on transfer all data except reverse API data
1218 
1219  if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
1220  swgSSBModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
1221  }
1222  if (channelSettingsKeys.contains("bandwidth") || force) {
1223  swgSSBModSettings->setBandwidth(settings.m_bandwidth);
1224  }
1225  if (channelSettingsKeys.contains("lowCutoff") || force) {
1226  swgSSBModSettings->setLowCutoff(settings.m_lowCutoff);
1227  }
1228  if (channelSettingsKeys.contains("usb") || force) {
1229  swgSSBModSettings->setUsb(settings.m_usb ? 1 : 0);
1230  }
1231  if (channelSettingsKeys.contains("toneFrequency") || force) {
1232  swgSSBModSettings->setToneFrequency(settings.m_toneFrequency);
1233  }
1234  if (channelSettingsKeys.contains("volumeFactor") || force) {
1235  swgSSBModSettings->setVolumeFactor(settings.m_volumeFactor);
1236  }
1237  if (channelSettingsKeys.contains("spanLog2") || force) {
1238  swgSSBModSettings->setSpanLog2(settings.m_spanLog2);
1239  }
1240  if (channelSettingsKeys.contains("audioBinaural") || force) {
1241  swgSSBModSettings->setAudioBinaural(settings.m_audioBinaural ? 1 : 0);
1242  }
1243  if (channelSettingsKeys.contains("audioFlipChannels") || force) {
1244  swgSSBModSettings->setAudioFlipChannels(settings.m_audioFlipChannels ? 1 : 0);
1245  }
1246  if (channelSettingsKeys.contains("dsb") || force) {
1247  swgSSBModSettings->setDsb(settings.m_dsb ? 1 : 0);
1248  }
1249  if (channelSettingsKeys.contains("audioMute") || force) {
1250  swgSSBModSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
1251  }
1252  if (channelSettingsKeys.contains("playLoop") || force) {
1253  swgSSBModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
1254  }
1255  if (channelSettingsKeys.contains("agc") || force) {
1256  swgSSBModSettings->setAgc(settings.m_agc ? 1 : 0);
1257  }
1258  if (channelSettingsKeys.contains("rgbColor") || force) {
1259  swgSSBModSettings->setRgbColor(settings.m_rgbColor);
1260  }
1261  if (channelSettingsKeys.contains("title") || force) {
1262  swgSSBModSettings->setTitle(new QString(settings.m_title));
1263  }
1264  if (channelSettingsKeys.contains("modAFInput") || force) {
1265  swgSSBModSettings->setModAfInput((int) settings.m_modAFInput);
1266  }
1267  if (channelSettingsKeys.contains("audioDeviceName") || force) {
1268  swgSSBModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
1269  }
1270 
1271  if (force)
1272  {
1273  const CWKeyerSettings& cwKeyerSettings = m_cwKeyer.getSettings();
1274  swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
1275  SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer();
1276  m_cwKeyer.webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
1277  }
1278 
1279  QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
1280  .arg(settings.m_reverseAPIAddress)
1281  .arg(settings.m_reverseAPIPort)
1282  .arg(settings.m_reverseAPIDeviceIndex)
1283  .arg(settings.m_reverseAPIChannelIndex);
1284  m_networkRequest.setUrl(QUrl(channelSettingsURL));
1285  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1286 
1287  QBuffer *buffer=new QBuffer();
1288  buffer->open((QBuffer::ReadWrite));
1289  buffer->write(swgChannelSettings->asJson().toUtf8());
1290  buffer->seek(0);
1291 
1292  // Always use PATCH to avoid passing reverse API settings
1293  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
1294 
1295  delete swgChannelSettings;
1296 }
1297 
1299 {
1301  swgChannelSettings->setDirection(1); // single source (Tx)
1302  swgChannelSettings->setChannelType(new QString("SSBMod"));
1303  swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings());
1304  SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings();
1305 
1306  swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
1307  SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer();
1308  m_cwKeyer.webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
1309 
1310  QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
1315  m_networkRequest.setUrl(QUrl(channelSettingsURL));
1316  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
1317 
1318  QBuffer *buffer=new QBuffer();
1319  buffer->open((QBuffer::ReadWrite));
1320  buffer->write(swgChannelSettings->asJson().toUtf8());
1321  buffer->seek(0);
1322 
1323  // Always use PATCH to avoid passing reverse API settings
1324  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
1325 
1326  delete swgChannelSettings;
1327 }
1328 
1329 void SSBMod::networkManagerFinished(QNetworkReply *reply)
1330 {
1331  QNetworkReply::NetworkError replyError = reply->error();
1332 
1333  if (replyError)
1334  {
1335  qWarning() << "SSBMod::networkManagerFinished:"
1336  << " error(" << (int) replyError
1337  << "): " << replyError
1338  << ": " << reply->errorString();
1339  return;
1340  }
1341 
1342  QString answer = reply->readAll();
1343  answer.chop(1); // remove last \n
1344  qDebug("SSBMod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
1345 }
void setReverseApiAddress(QString *reverse_api_address)
void setOriginatorChannelIndex(qint32 originator_channel_index)
void addAudioSink(AudioFifo *audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex=-1)
Add the audio sink.
quint32 m_levelCalcCount
Definition: ssbmod.h:332
void calculateLevel(Complex &sample)
Definition: ssbmod.cpp:555
int m_outputSampleRate
Definition: ssbmod.h:278
static MsgConfigureSSBMod * create(const SSBModSettings &settings, bool force)
Definition: ssbmod.h:60
int getOutputSampleRate(int outputDeviceIndex=-1)
void setSpanLog2(qint32 span_log2)
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
Definition: ssbmod.cpp:1200
int m_basebandSampleRate
Definition: ssbmod.h:277
void setSsbModReport(SWGSSBModReport *ssb_mod_report)
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
SWGSSBModReport * getSsbModReport()
Complex * m_SSBFilterBuffer
Definition: ssbmod.h:298
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
Interpolator m_interpolator
Definition: ssbmod.h:286
int m_inputFrequencyOffset
Definition: ssbmod.h:279
const QString & getFileName() const
Definition: ssbmod.h:104
void removeChannelSourceAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:181
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const SSBModSettings &settings, bool force)
Definition: ssbmod.cpp:1207
void networkManagerFinished(QNetworkReply *reply)
Definition: ssbmod.cpp:1329
int m_sampleRate
Definition: ssbmod.h:330
void openFileStream()
Definition: ssbmod.cpp:700
void applyFeedbackAudioSampleRate(unsigned int sampleRate)
Definition: ssbmod.cpp:794
DeviceAPI * m_deviceAPI
Definition: ssbmod.h:273
int getInputSampleRate(int inputDeviceIndex=-1)
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
bool interpolate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:53
QMutex m_settingsMutex
Definition: ssbmod.h:324
void clear()
Definition: audiofifo.cpp:156
void pullAF(Complex &sample)
Definition: ssbmod.cpp:219
quint64 m_fileSize
raw file size (bytes)
Definition: ssbmod.h:328
int getDeviceSetIndex() const
Definition: channelapi.h:89
int getOutputDeviceIndex(const QString &deviceName) const
void setAudioBinaural(qint32 audio_binaural)
void initSimple(int rate, float pregain, float threshold, float knee, float ratio, float attack, float release)
quint32 m_audioSampleRate
Definition: ssbmod.h:314
static MsgConfigureCWKeyer * create(const CWKeyerSettings &settings, bool force)
Definition: cwkeyer.h:63
void removeChannelSource(ThreadedBasebandSampleSource *sink, int streamIndex=0)
Remove a channel source (Tx)
Definition: deviceapi.cpp:147
qint64 m_inputFrequencyOffset
Complex * m_DSBFilterBuffer
Definition: ssbmod.h:299
~SSBMod()
Definition: ssbmod.cpp:136
uint16_t m_reverseAPIChannelIndex
bool m_feedbackInterpolatorConsumed
Definition: ssbmod.h:294
void removeAudioSink(AudioFifo *audioFifo)
Remove the audio sink.
void setCwKeyer(SWGCWKeyerSettings *cw_keyer)
void setToneFrequency(float tone_frequency)
void applySettings(const SSBModSettings &settings, bool force=false)
Definition: ssbmod.cpp:841
void seekFileStream(int seekPercentage)
Definition: ssbmod.cpp:725
QString m_feedbackAudioDeviceName
This is the audio device you send the audio samples to for audio feedback.
AudioVector m_audioBuffer
Definition: ssbmod.h:315
MovingAverageUtil< double, double, 16 > m_movingAverage
Definition: ssbmod.h:312
uint m_feedbackAudioBufferFill
Definition: ssbmod.h:321
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
QString m_fileName
Definition: ssbmod.h:327
Real m_levelSum
Definition: ssbmod.h:334
void setVolumeFactor(float volume_factor)
SampleVector m_sampleBuffer
Definition: ssbmod.h:305
AudioFifo m_feedbackAudioFifo
Definition: ssbmod.h:322
void setChannelType(QString *channel_type)
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)=0
void addChannelSource(ThreadedBasebandSampleSource *sink, int streamIndex=0)
Add a channel source (Tx)
Definition: deviceapi.cpp:138
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
fftfilt * m_SSBFilter
Definition: ssbmod.h:296
Interpolator m_feedbackInterpolator
Definition: ssbmod.h:291
std::complex< float > cmplx
Definition: fftfilt.h:21
int m_sumCount
Definition: ssbmod.h:309
Complex nextIQ()
Return next complex sample.
Definition: ncof.cpp:63
virtual QByteArray serialize() const
Definition: ssbmod.cpp:988
const SSBModSettings & getSettings() const
Definition: ssbmod.h:57
unsigned int uint32_t
Definition: rtptypes_win.h:46
void addAudioSource(AudioFifo *audioFifo, MessageQueue *sampleSourceMessageQueue, int inputDeviceIndex=-1)
Add an audio source.
AudioType getAudioType() const
Definition: dspcommands.h:391
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
Definition: cwkeyer.h:104
float m_feedbackVolumeFactor
SWGCWKeyerSettings * getCwKeyer()
void setPhase(Real phase)
Definition: ncof.h:42
#define SDR_TX_SCALEF
Definition: dsptypes.h:39
void setAudioDeviceName(QString *audio_device_name)
void setUseReverseApi(qint32 use_reverse_api)
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: ssbmod.h:83
virtual void pullAudio(int nbSamples)
Definition: ssbmod.cpp:194
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
bool getFadeSample(bool on, float &sample)
Definition: cwkeyer.cpp:487
static const QString m_channelId
Definition: ssbmod.h:255
fftfilt::cmplx m_sum
Definition: ssbmod.h:307
void create_filter(float f1, float f2)
Definition: fftfilt.cpp:107
Real m_interpolatorDistance
Definition: ssbmod.h:287
int getSampleRate() const
Definition: dspcommands.h:390
static DSPEngine * instance()
Definition: dspengine.cpp:51
QString m_audioDeviceName
This is the audio device you get the audio samples from.
SSBModInputAF m_modAFInput
void setInputFrequencyOffset(qint64 input_frequency_offset)
void processOneSample(Complex &ci)
Definition: ssbmod.cpp:534
CWSmoother & getCWSmoother()
Definition: cwkeyer.h:111
double m_magsq
Definition: ssbmod.h:311
uint16_t m_reverseAPIDeviceIndex
void setChannelSampleRate(qint32 channel_sample_rate)
QNetworkRequest m_networkRequest
Definition: ssbmod.h:341
Real m_feedbackInterpolatorDistance
Definition: ssbmod.h:292
FixReal m_real
Definition: dsptypes.h:64
bool m_audioFlipChannels
void setLowCutoff(float low_cutoff)
void setSsbModSettings(SWGSSBModSettings *ssb_mod_settings)
Real m_interpolatorDistanceRemain
Definition: ssbmod.h:288
SSBMod(DeviceAPI *deviceAPI)
Definition: ssbmod.cpp:55
int32_t i
Definition: decimators.h:244
void webapiReverseSendCWSettings(const CWKeyerSettings &settings)
Definition: ssbmod.cpp:1298
void pushFeedback(Complex sample)
Definition: ssbmod.cpp:512
double getMagSq() const
Definition: ssbmod.h:250
AudioVector m_feedbackAudioBuffer
Definition: ssbmod.h:320
std::ifstream m_ifstream
Definition: ssbmod.h:326
static bool match(const Message *message)
Definition: message.cpp:45
CWKeyer m_cwKeyer
Definition: ssbmod.h:335
void setRgbColor(qint32 rgb_color)
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const SSBModSettings &settings)
Definition: ssbmod.cpp:1148
SWGSSBModSettings * getSsbModSettings()
virtual bool deserialize(const QByteArray &data)
Definition: ssbmod.cpp:993
SSBModSettings m_settings
Definition: ssbmod.h:280
QByteArray serialize() const
void setPlayLoop(qint32 play_loop)
Fixed< IntType, IntBits > sqrt(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2283
static MsgReportFileSourceStreamData * create(int sampleRate, quint32 recordLength)
Definition: ssbmod.h:186
quint32 m_recordLength
record length in seconds computed from file size
Definition: ssbmod.h:329
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: ssbmod.cpp:1010
AudioCompressorSnd m_audioCompressor
Definition: ssbmod.h:337
uint32_t read(quint8 *data, uint32_t numSamples)
Definition: audiofifo.cpp:103
NCOF m_carrierNco
Definition: ssbmod.h:282
void modulateSample()
Definition: ssbmod.cpp:207
int m_undersampleCount
Definition: ssbmod.h:308
void setAudioMute(qint32 audio_mute)
uint16_t m_reverseAPIPort
virtual QString asJson() override
void setChannelPowerDb(float channel_power_db)
void applyAudioSampleRate(int sampleRate)
Definition: ssbmod.cpp:738
static void webapiFormatChannelSettings(SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings, const CWKeyerSettings &cwKeyerSettings)
Definition: cwkeyer.cpp:637
int getSample()
Definition: cwkeyer.cpp:194
void setReverseApiPort(qint32 reverse_api_port)
Complex nextQI()
Return next complex sample (reversed)
Definition: ncof.cpp:77
AudioDeviceManager * getAudioDeviceManager()
Definition: dspengine.h:55
void setAudioFlipChannels(qint32 audio_flip_channels)
uint m_audioBufferFill
Definition: ssbmod.h:316
int m_DSBFilterBufferIndex
Definition: ssbmod.h:301
int getCenterFrequency() const
Definition: ssbmod.h:81
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: ssbmod.cpp:1021
static const int m_ssbFftLen
Definition: ssbmod.h:302
bool m_interpolatorConsumed
Definition: ssbmod.h:289
BasebandSampleSink * m_sampleSink
Definition: ssbmod.h:304
MessageQueue * getMessageQueueToGUI()
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
Definition: ssbmod.cpp:589
static void webapiSettingsPutPatch(const QStringList &channelSettingsKeys, CWKeyerSettings &cwKeyerSettings, SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings)
Definition: cwkeyer.cpp:599
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
int runSSB(const cmplx &in, cmplx **out, bool usb, bool getDC=true)
Definition: fftfilt.cpp:284
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
AudioFifo m_audioFifo
Definition: ssbmod.h:317
void setModAfInput(qint32 mod_af_input)
void setFreq(Real freq, Real sampleRate)
Definition: ncof.cpp:51
int m_SSBFilterBufferIndex
Definition: ssbmod.h:300
QString m_reverseAPIAddress
Real m_feedbackInterpolatorDistanceRemain
Definition: ssbmod.h:293
virtual void start()
Definition: ssbmod.cpp:576
FixReal m_imag
Definition: dsptypes.h:65
int getInputDeviceIndex(const QString &deviceName) const
QNetworkAccessManager * m_networkManager
Definition: ssbmod.h:340
static MsgReportFileSourceStreamTiming * create(std::size_t samplesCount)
Definition: ssbmod.h:165
virtual void stop()
Definition: ssbmod.cpp:585
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force=false)
Definition: ssbmod.cpp:811
virtual void pull(Sample &sample)
Definition: ssbmod.cpp:155
void addChannelSourceAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:174
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples)
NCOF m_toneNco
Definition: ssbmod.h:283
bool deserialize(const QByteArray &data)
void reset()
Definition: cwkeyer.h:109
const CWKeyerSettings & getSettings() const
Definition: cwkeyer.h:107
UpChannelizer * m_channelizer
Definition: ssbmod.h:275
float compress(float sample)
int getIndexInDeviceSet() const
Definition: channelapi.h:87
Real next()
Return next real sample.
Definition: ncof.cpp:57
std::complex< Real > Complex
Definition: dsptypes.h:43
void setAudioSampleRate(qint32 audio_sample_rate)
double asDouble() const
Definition: movingaverage.h:57
static const int m_levelNbSamples
Definition: ssbmod.h:343
Complex m_modSample
Definition: ssbmod.h:284
int runDSB(const cmplx &in, cmplx **out, bool getDC=true)
Definition: fftfilt.cpp:327
float Real
Definition: dsptypes.h:42
#define SDR_TX_SCALED
Definition: dsptypes.h:40
quint32 m_rgbColor
void setSampleRate(int sampleRate)
Definition: cwkeyer.cpp:186
bool m_feedbackAudioEnable
qint16 FixReal
Definition: dsptypes.h:35
Real m_peakLevel
Definition: ssbmod.h:333
T max(const T &x, const T &y)
Definition: framework.h:446
uint32_t write(const quint8 *data, uint32_t numSamples)
Definition: audiofifo.cpp:66
const CWKeyerSettings & getSettings() const
Definition: cwkeyer.h:60
void removeAudioSource(AudioFifo *audioFifo)
Remove an audio source.
ThreadedBasebandSampleSource * m_threadedChannelizer
Definition: ssbmod.h:274
quint32 m_feedbackAudioSampleRate
Definition: ssbmod.h:319
void create_dsb_filter(float f2)
Definition: fftfilt.cpp:148
bool getForce() const
Definition: ssbmod.h:58
void setBandwidth(float bandwidth)
static const QString m_channelIdURI
Definition: ssbmod.h:254
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
T min(const T &x, const T &y)
Definition: framework.h:440
fftfilt * m_DSBFilter
Definition: ssbmod.h:297
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
Definition: ssbmod.cpp:1137