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.
wfmmodgui.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 <QDockWidget>
19 #include <QMainWindow>
20 #include <QFileDialog>
21 #include <QTime>
22 #include <QDebug>
23 
24 #include "device/deviceuiset.h"
25 #include "dsp/upchannelizer.h"
27 #include "plugin/pluginapi.h"
28 #include "util/simpleserializer.h"
29 #include "util/db.h"
30 #include "dsp/dspengine.h"
31 #include "gui/crightclickenabler.h"
32 #include "gui/audioselectdialog.h"
34 #include "mainwindow.h"
35 
36 #include "ui_wfmmodgui.h"
37 #include "wfmmodgui.h"
38 
40 {
41  WFMModGUI* gui = new WFMModGUI(pluginAPI, deviceUISet, channelTx);
42  return gui;
43 }
44 
46 {
47  delete this;
48 }
49 
50 void WFMModGUI::setName(const QString& name)
51 {
52  setObjectName(name);
53 }
54 
55 QString WFMModGUI::getName() const
56 {
57  return objectName();
58 }
59 
62 }
63 
64 void WFMModGUI::setCenterFrequency(qint64 centerFrequency)
65 {
66  m_channelMarker.setCenterFrequency(centerFrequency);
67  applySettings();
68 }
69 
71 {
74  applySettings(true);
75 }
76 
77 QByteArray WFMModGUI::serialize() const
78 {
79  return m_settings.serialize();
80 }
81 
82 bool WFMModGUI::deserialize(const QByteArray& data)
83 {
84  if(m_settings.deserialize(data)) {
86  applySettings(true);
87  return true;
88  } else {
90  return false;
91  }
92 }
93 
94 bool WFMModGUI::handleMessage(const Message& message)
95 {
97  {
98  m_recordSampleRate = ((WFMMod::MsgReportFileSourceStreamData&)message).getSampleRate();
99  m_recordLength = ((WFMMod::MsgReportFileSourceStreamData&)message).getRecordLength();
100  m_samplesCount = 0;
102  return true;
103  }
105  {
106  m_samplesCount = ((WFMMod::MsgReportFileSourceStreamTiming&)message).getSamplesCount();
108  return true;
109  }
110  else if (WFMMod::MsgConfigureWFMMod::match(message))
111  {
113  m_settings = cfg.getSettings();
114  blockApplySettings(true);
115  displaySettings();
116  blockApplySettings(false);
117  return true;
118  }
119  else if (CWKeyer::MsgConfigureCWKeyer::match(message))
120  {
122  ui->cwKeyerGUI->setSettings(cfg.getSettings());
123  ui->cwKeyerGUI->displaySettings();
124  return true;
125  }
126  else
127  {
128  return false;
129  }
130 }
131 
133 {
134  ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
136  applySettings();
137 }
138 
140 {
141  Message* message;
142 
143  while ((message = getInputMessageQueue()->pop()) != 0)
144  {
145  if (handleMessage(*message))
146  {
147  delete message;
148  }
149  }
150 }
151 
153 {
156  applySettings();
157 }
158 
160 {
161  float rfBW = WFMModSettings::getRFBW(index);
163  m_settings.m_rfBandwidth = rfBW;
164  applySettings();
165 }
166 
168 {
169  ui->afBWText->setText(QString("%1k").arg(value));
170  m_settings.m_afBandwidth = value * 1000.0;
171  applySettings();
172 }
173 
175 {
176  ui->fmDevText->setText(QString("%1k").arg(value));
177  m_settings.m_fmDeviation = value * 1000.0;
178  applySettings();
179 }
180 
182 {
183  ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
184  m_settings.m_volumeFactor = value / 10.0;
185  applySettings();
186 }
187 
189 {
190  ui->toneFrequencyText->setText(QString("%1k").arg(value / 100.0, 0, 'f', 2));
191  m_settings.m_toneFrequency = value * 10.0;
192  applySettings();
193 }
194 
196 {
197  m_settings.m_channelMute = checked;
198  applySettings();
199 }
200 
202 {
203  m_settings.m_playLoop = checked;
204  applySettings();
205 }
206 
207 void WFMModGUI::on_play_toggled(bool checked)
208 {
209  ui->tone->setEnabled(!checked); // release other source inputs
210  ui->mic->setEnabled(!checked);
211  ui->morseKeyer->setEnabled(!checked);
213  applySettings();
214  ui->navTimeSlider->setEnabled(!checked);
215  m_enableNavTime = !checked;
216 }
217 
218 void WFMModGUI::on_tone_toggled(bool checked)
219 {
220  ui->play->setEnabled(!checked); // release other source inputs
221  ui->mic->setEnabled(!checked);
222  ui->morseKeyer->setEnabled(!checked);
224  applySettings();
225 }
226 
228 {
229  ui->tone->setEnabled(!checked); // release other source inputs
230  ui->mic->setEnabled(!checked);
231  ui->play->setEnabled(!checked);
233  applySettings();
234 }
235 
236 void WFMModGUI::on_mic_toggled(bool checked)
237 {
238  ui->play->setEnabled(!checked); // release other source inputs
239  ui->tone->setEnabled(!checked); // release other source inputs
240  ui->morseKeyer->setEnabled(!checked);
242  applySettings();
243 }
244 
246 {
247  if (m_enableNavTime && ((value >= 0) && (value <= 100)))
248  {
249  int t_sec = (m_recordLength * value) / 100;
250  QTime t(0, 0, 0, 0);
251  t = t.addSecs(t_sec);
252 
254  m_wfmMod->getInputMessageQueue()->push(message);
255  }
256 }
257 
259 {
260  (void) checked;
261  QString fileName = QFileDialog::getOpenFileName(this,
262  tr("Open raw audio file"), ".", tr("Raw audio Files (*.raw)"), 0, QFileDialog::DontUseNativeDialog);
263 
264  if (fileName != "")
265  {
266  m_fileName = fileName;
267  ui->recordFileText->setText(m_fileName);
268  ui->play->setEnabled(true);
270  }
271 }
272 
274 {
275  qDebug() << "FileSourceGui::configureFileName: " << m_fileName.toStdString().c_str();
277  m_wfmMod->getInputMessageQueue()->push(message);
278 }
279 
280 void WFMModGUI::onWidgetRolled(QWidget* widget, bool rollDown)
281 {
282  (void) widget;
283  (void) rollDown;
284 }
285 
286 void WFMModGUI::onMenuDialogCalled(const QPoint &p)
287 {
289  {
296 
297  dialog.move(p);
298  dialog.exec();
299 
308 
309  setWindowTitle(m_settings.m_title);
311 
312  applySettings();
313  }
314 
316 }
317 
318 WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent) :
319  RollupWidget(parent),
320  ui(new Ui::WFMModGUI),
321  m_pluginAPI(pluginAPI),
322  m_deviceUISet(deviceUISet),
323  m_channelMarker(this),
324  m_doApplySettings(true),
325  m_recordLength(0),
326  m_recordSampleRate(48000),
327  m_samplesCount(0),
328  m_tickCount(0),
329  m_enableNavTime(false)
330 {
331  ui->setupUi(this);
332  setAttribute(Qt::WA_DeleteOnClose, true);
333 
334  blockApplySettings(true);
335 
336  ui->rfBW->clear();
337  for (int i = 0; i < WFMModSettings::m_nbRfBW; i++) {
338  ui->rfBW->addItem(QString("%1").arg(WFMModSettings::getRFBW(i) / 1000.0, 0, 'f', 2));
339  }
340  ui->rfBW->setCurrentIndex(7);
341 
342  blockApplySettings(false);
343 
344  connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
345  connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
346 
347  m_wfmMod = (WFMMod*) channelTx; //new WFMMod(m_deviceUISet->m_deviceSinkAPI);
349 
350  connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
351 
352  CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->mic);
353  connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
354 
355  ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
356  ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
357  ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
358 
359  m_channelMarker.blockSignals(true);
360  m_channelMarker.setColor(Qt::blue);
363  m_channelMarker.setTitle("WFM Modulator");
365  m_channelMarker.blockSignals(false);
366  m_channelMarker.setVisible(true); // activate signal on the last setting only
367 
371 
372  connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
373 
374  ui->play->setEnabled(false);
375  ui->play->setChecked(false);
376  ui->tone->setChecked(false);
377  ui->mic->setChecked(false);
378 
379  ui->cwKeyerGUI->setCWKeyer(m_wfmMod->getCWKeyer());
380 
382  m_settings.setCWKeyerGUI(ui->cwKeyerGUI);
383 
384  connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
385  connect(m_wfmMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int)));
386 
387  displaySettings();
388  applySettings(true);
389 }
390 
392 {
394  delete m_wfmMod; // TODO: check this: when the GUI closes it has to delete the modulator
395  delete ui;
396 }
397 
399 {
400  m_doApplySettings = !block;
401 }
402 
403 void WFMModGUI::applySettings(bool force)
404 {
405  if (m_doApplySettings)
406  {
408 
410  requiredBW(WFMModSettings::getRFBW(ui->rfBW->currentIndex())),
412  m_wfmMod->getInputMessageQueue()->push(msgChan);
413 
414  ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
415 
417  m_wfmMod->getInputMessageQueue()->push(msgConf);
418  }
419 }
420 
422 {
423  m_channelMarker.blockSignals(true);
427  m_channelMarker.blockSignals(false);
428  m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
429 
431  setWindowTitle(m_channelMarker.getTitle());
432 
433  blockApplySettings(true);
434 
435  ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
436 
437  ui->rfBW->setCurrentIndex(WFMModSettings::getRFBWIndex(m_settings.m_rfBandwidth));
438 
439  ui->afBWText->setText(QString("%1k").arg(m_settings.m_afBandwidth / 1000.0));
440  ui->afBW->setValue(m_settings.m_afBandwidth / 1000.0);
441 
442  ui->fmDevText->setText(QString("%1k").arg(m_settings.m_fmDeviation / 1000.0));
443  ui->fmDev->setValue(m_settings.m_fmDeviation / 1000.0);
444 
445  ui->volumeText->setText(QString("%1").arg(m_settings.m_volumeFactor, 0, 'f', 1));
446  ui->volume->setValue(m_settings.m_volumeFactor * 10.0);
447 
448  ui->toneFrequencyText->setText(QString("%1k").arg(m_settings.m_toneFrequency / 1000.0, 0, 'f', 2));
449  ui->toneFrequency->setValue(m_settings.m_toneFrequency / 10.0);
450 
451  ui->channelMute->setChecked(m_settings.m_channelMute);
452  ui->playLoop->setChecked(m_settings.m_playLoop);
453 
454  ui->tone->setEnabled((m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputTone) || (m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputNone));
455  ui->mic->setEnabled((m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputAudio) || (m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputNone));
456  ui->play->setEnabled((m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputFile) || (m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputNone));
457  ui->morseKeyer->setEnabled((m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputCWTone) || (m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputNone));
458 
459  ui->tone->setChecked(m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputTone);
460  ui->mic->setChecked(m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputAudio);
461  ui->play->setChecked(m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputFile);
462  ui->morseKeyer->setChecked(m_settings.m_modAFInput == WFMModSettings::WFMModInputAF::WFMModInputCWTone);
463 
464  blockApplySettings(false);
465 }
466 
468 {
470 }
471 
473 {
475 }
476 
478 {
479  qDebug("WFMModGUI::audioSelect");
480  AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName, true); // true for input
481  audioSelect.exec();
482 
483  if (audioSelect.m_selected)
484  {
486  applySettings();
487  }
488 }
489 
491 {
492  double powDb = CalcDb::dbPower(m_wfmMod->getMagSq());
493  m_channelPowerDbAvg(powDb);
494  ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.asDouble(), 0, 'f', 1));
495 
497  {
499  m_wfmMod->getInputMessageQueue()->push(message);
500  }
501 }
502 
504 {
505  QTime recordLength(0, 0, 0, 0);
506  recordLength = recordLength.addSecs(m_recordLength);
507  QString s_time = recordLength.toString("HH:mm:ss");
508  ui->recordLengthText->setText(s_time);
510 }
511 
513 {
514  int t_sec = 0;
515  int t_msec = 0;
516 
517  if (m_recordSampleRate > 0)
518  {
519  t_msec = ((m_samplesCount * 1000) / m_recordSampleRate) % 1000;
521  }
522 
523  QTime t(0, 0, 0, 0);
524  t = t.addSecs(t_sec);
525  t = t.addMSecs(t_msec);
526  QString s_timems = t.toString("HH:mm:ss.zzz");
527  QString s_time = t.toString("HH:mm:ss");
528  ui->relTimeText->setText(s_timems);
529 
530  if (!m_enableNavTime)
531  {
532  float posRatio = (float) t_sec / (float) m_recordLength;
533  ui->navTimeSlider->setValue((int) (posRatio * 100.0));
534  }
535 }
void removeTxChannelInstance(PluginInstanceGUI *pluginGUI)
CWKeyer * getCWKeyer()
Definition: wfmmod.h:248
static MainWindow * getInstance()
Definition: mainwindow.h:73
const QString & getReverseAPIAddress() const
static WFMModGUI * create(PluginAPI *pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx)
Definition: wfmmodgui.cpp:39
MovingAverageUtil< double, double, 20 > m_channelPowerDbAvg
Definition: wfmmodgui.h:72
virtual ~WFMModGUI()
Definition: wfmmodgui.cpp:391
int getCenterFrequency() const
Definition: channelmarker.h:42
void registerTxChannelInstance(const QString &channelName, PluginInstanceGUI *pluginGUI)
Definition: deviceuiset.cpp:88
void push(Message *message, bool emitSignal=true)
Push message onto queue.
uint16_t m_reverseAPIChannelIndex
void resetToDefaults()
Definition: wfmmodgui.cpp:70
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
bool m_doApplySettings
Definition: wfmmodgui.h:67
int m_samplesCount
Definition: wfmmodgui.h:77
static const int m_nbRfBW
bool deserialize(const QByteArray &data)
Definition: wfmmodgui.cpp:82
static int getRFBW(int index)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setName(const QString &name)
Definition: wfmmodgui.cpp:50
WFMModInputAF m_modAFInput
void setCWKeyerGUI(Serializable *cwKeyerGUI)
void setReverseAPIChannelIndex(uint16_t channelIndex)
Ui::WFMModGUI * ui
Definition: wfmmodgui.h:62
WFMModSettings m_settings
Definition: wfmmodgui.h:66
void resetContextMenuType()
Definition: rollupwidget.h:50
void addChannelMarker(ChannelMarker *channelMarker)
Add channel marker to spectrum.
Definition: deviceuiset.cpp:72
void on_channelMute_toggled(bool checked)
Definition: wfmmodgui.cpp:195
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: wfmmod.h:82
void leaveEvent(QEvent *)
Definition: wfmmodgui.cpp:467
Definition: wfmmod.h:48
static const QString m_channelIdURI
Definition: wfmmod.h:250
quint32 m_rgbColor
void audioSelect()
Definition: wfmmodgui.cpp:477
static MsgConfigureWFMMod * create(const WFMModSettings &settings, bool force)
Definition: wfmmod.h:59
ContextMenuType m_contextMenuType
Definition: rollupwidget.h:33
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
virtual void setCenterFrequency(qint64 centerFrequency)
Definition: wfmmodgui.cpp:64
void setReverseAPIDeviceIndex(uint16_t deviceIndex)
virtual MessageQueue * getInputMessageQueue()
Definition: wfmmodgui.h:55
void enterEvent(QEvent *)
Definition: wfmmodgui.cpp:472
double getMagSq() const
Definition: wfmmod.h:246
bool deserialize(const QByteArray &data)
void on_morseKeyer_toggled(bool checked)
Definition: wfmmodgui.cpp:227
void applySettings(bool force=false)
Definition: wfmmodgui.cpp:403
void setChannelMarker(Serializable *channelMarker)
static int requiredBW(int rfBW)
Definition: wfmmodgui.h:94
void setSourceOrSinkStream(bool sourceOrSinkStream)
Definition: channelmarker.h:75
static DSPEngine * instance()
Definition: dspengine.cpp:51
void on_mic_toggled(bool checked)
Definition: wfmmodgui.cpp:236
void on_navTimeSlider_valueChanged(int value)
Definition: wfmmodgui.cpp:245
void setTitleColor(const QColor &c)
void on_rfBW_currentIndexChanged(int index)
Definition: wfmmodgui.cpp:159
WFMMod * m_wfmMod
Definition: wfmmodgui.h:71
void setHighlighted(bool highlighted)
DeviceUISet * m_deviceUISet
Definition: wfmmodgui.h:64
PluginAPI * m_pluginAPI
Definition: wfmmodgui.h:63
int32_t i
Definition: decimators.h:244
void addRollupWidget(QWidget *widget)
Add rollup widget to channel window.
Definition: deviceuiset.cpp:77
QString m_audioDeviceName
This is the audio device you get the audio samples from.
virtual void setMessageQueueToGUI(MessageQueue *queue)
int m_recordSampleRate
Definition: wfmmodgui.h:76
const QString & getTitle() const
Definition: channelmarker.h:38
static bool match(const Message *message)
Definition: message.cpp:45
void blockApplySettings(bool block)
Definition: wfmmodgui.cpp:398
bool m_enableNavTime
Definition: wfmmodgui.h:79
QByteArray serialize() const
Definition: wfmmodgui.cpp:77
void handleSourceMessages()
Definition: wfmmodgui.cpp:139
void updateWithStreamData()
Definition: wfmmodgui.cpp:503
virtual qint64 getCenterFrequency() const
Definition: wfmmodgui.cpp:60
void setReverseAPIAddress(const QString &address)
QByteArray serialize() const
QString m_fileName
Definition: wfmmodgui.h:74
uint16_t m_reverseAPIPort
void onWidgetRolled(QWidget *widget, bool rollDown)
Definition: wfmmodgui.cpp:280
void setColor(const QColor &color)
void on_deltaFrequency_changed(qint64 value)
Definition: wfmmodgui.cpp:152
quint32 m_recordLength
Definition: wfmmodgui.h:75
void channelMarkerChangedByCursor()
Definition: wfmmodgui.cpp:132
static MsgConfigureFileSourceStreamTiming * create()
Definition: wfmmod.h:145
void setVisible(bool visible)
QString getName() const
Definition: wfmmodgui.cpp:55
void on_tone_toggled(bool checked)
Definition: wfmmodgui.cpp:218
void displaySettings()
Definition: wfmmodgui.cpp:421
void setBandwidth(int bandwidth)
const QColor & getColor() const
Definition: channelmarker.h:64
void setTitle(const QString &title)
virtual void destroy()
Definition: wfmmodgui.cpp:45
static int getRFBWIndex(int rfbw)
void on_afBW_valueChanged(int value)
Definition: wfmmodgui.cpp:167
void on_playLoop_toggled(bool checked)
Definition: wfmmodgui.cpp:201
void configureFileName()
Definition: wfmmodgui.cpp:273
QString m_reverseAPIAddress
static MsgConfigureFileSourceName * create(const QString &fileName)
Definition: wfmmod.h:105
void on_volume_valueChanged(int value)
Definition: wfmmodgui.cpp:181
void setCenterFrequency(int centerFrequency)
void on_toneFrequency_valueChanged(int value)
Definition: wfmmodgui.cpp:188
void updateWithStreamTime()
Definition: wfmmodgui.cpp:512
const WFMModSettings & getSettings() const
Definition: wfmmod.h:56
virtual bool handleMessage(const Message &message)
Definition: wfmmodgui.cpp:94
void onMenuDialogCalled(const QPoint &p)
Definition: wfmmodgui.cpp:286
void on_showFileDialog_clicked(bool checked)
Definition: wfmmodgui.cpp:258
void widgetRolled(QWidget *widget, bool rollDown)
void on_play_toggled(bool checked)
Definition: wfmmodgui.cpp:207
void tick()
Definition: wfmmodgui.cpp:490
qint64 m_inputFrequencyOffset
void setUseReverseAPI(bool useReverseAPI)
static MsgConfigureFileSourceSeek * create(int seekPercentage)
Definition: wfmmod.h:126
uint16_t m_reverseAPIDeviceIndex
void on_fmDev_valueChanged(int value)
Definition: wfmmodgui.cpp:174
const CWKeyerSettings & getSettings() const
Definition: cwkeyer.h:60
ChannelMarker m_channelMarker
Definition: wfmmodgui.h:65
WFMModGUI(PluginAPI *pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget *parent=0)
Definition: wfmmodgui.cpp:318
std::size_t m_tickCount
Definition: wfmmodgui.h:78