1 /* -*- c++ -*- */
2 /*
3 * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
4 * https://gqrx.dk/
5 *
6 * Copyright 2011-2014 Alexandru Csete OZ9AEC.
7 *
8 * Gqrx is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3, or (at your option)
11 * any later version.
12 *
13 * Gqrx is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Gqrx; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street,
21 * Boston, MA 02110-1301, USA.
22 */
23 #include <QDebug>
24 #include <QFile>
25 #include <QPushButton>
26 #include <QRegExp>
27 #include <QSettings>
28 #include <QString>
29 #include <QtGlobal>
30 #include <QVariant>
31
32 #include <osmosdr/device.h>
33 #include <osmosdr/source.h>
34 #include <osmosdr/ranges.h>
35
36 #ifdef WITH_PULSEAUDIO
37 #include "pulseaudio/pa_device_list.h"
38 #elif WITH_PORTAUDIO
39 #include "portaudio/device_list.h"
40 #elif defined(Q_OS_DARWIN)
41 #include "osxaudio/device_list.h"
42 #endif
43
44 #include "qtgui/ioconfig.h"
45 #include "ui_ioconfig.h"
46
47
CIoConfig(QSettings * settings,std::map<QString,QVariant> & devList,QWidget * parent)48 CIoConfig::CIoConfig(QSettings * settings,
49 std::map<QString, QVariant> &devList,
50 QWidget *parent) :
51 QDialog(parent),
52 ui(new Ui::CIoConfig),
53 m_settings(settings),
54 m_devList(&devList)
55 {
56 ui->setupUi(this);
57
58 // update input device list
59 updateInDev(settings, *m_devList);
60
61 // input rate
62 updateInputSampleRates(settings->value("input/sample_rate", 0).toInt());
63
64 // decimation
65 int idx = decim2idx(settings->value("input/decimation", 0).toInt());
66 ui->decimCombo->setCurrentIndex(idx);
67 decimationChanged(idx);
68
69 // Analog bandwidth
70 ui->bwSpinBox->setValue(1.0e-6*settings->value("input/bandwidth", 0.0).toDouble());
71
72 // LNB LO
73 ui->loSpinBox->setValue(1.0e-6 * settings->value("input/lnb_lo", 0.0).toDouble());
74
75 // Output device
76 updateOutDev();
77
78 m_scanButton = new QPushButton("&Device scan", ui->buttonBox);
79 ui->buttonBox->addButton(m_scanButton, QDialogButtonBox::ButtonRole::ActionRole);
80
81 // Signals and slots
82 connect(this, SIGNAL(accepted()), this, SLOT(saveConfig()));
83 connect(ui->inDevCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(inputDeviceSelected(int)));
84 connect(ui->inDevEdit, SIGNAL(textChanged(QString)), this, SLOT(inputDevstrChanged(QString)));
85 connect(ui->inSrCombo, SIGNAL(editTextChanged(QString)), this, SLOT(inputRateChanged(QString)));
86 connect(ui->decimCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(decimationChanged(int)));
87 connect(m_scanButton, SIGNAL(clicked(bool)), this, SLOT(onScanButtonClicked()));
88 }
89
~CIoConfig()90 CIoConfig::~CIoConfig()
91 {
92 delete m_scanButton;
93 delete ui;
94 }
95
96 /**
97 * @brief get the list of devices
98 */
getDeviceList(std::map<QString,QVariant> & devList)99 void CIoConfig::getDeviceList(std::map<QString, QVariant> &devList)
100 {
101 QString devstr;
102 QString devlabel;
103
104 // automatic discovery of FCD does not work on Mac
105 // so we do it ourselves
106 #if defined(Q_OS_DARWIN)
107 #ifdef WITH_PORTAUDIO
108 portaudio_device_list devices;
109 vector<portaudio_device> inDevList = devices.get_input_devices();
110 #else
111 osxaudio_device_list devices;
112 vector<osxaudio_device> inDevList = devices.get_input_devices();
113 #endif
114 string this_dev;
115 for (auto &device : inDevList)
116 {
117 this_dev = device.get_name();
118 if (this_dev.find("FUNcube Dongle V1.0") != string::npos)
119 {
120 devstr = "fcd,type=1,device='FUNcube Dongle V1.0'";
121 devList.insert(std::pair<QString, QVariant>(QString("FUNcube Dongle V1.0"), QVariant(devstr)));
122 }
123 else if (this_dev.find("FUNcube Dongle V1_0") != string::npos) // since OS X 10.11.4
124 {
125 devstr = "fcd,type=1,device='FUNcube Dongle V1_0'";
126 devList.insert(std::pair<QString, QVariant>(QString("FUNcube Dongle V1_0"), QVariant(devstr)));
127 }
128 else if (this_dev.find("FUNcube Dongle V2.0") != string::npos)
129 {
130 devstr = "fcd,type=2,device='FUNcube Dongle V2.0'";
131 devList.insert(std::pair<QString, QVariant>(QString("FUNcube Dongle V2.0"), QVariant(devstr)));
132 }
133 else if (this_dev.find("FUNcube Dongle V2_0") != string::npos) // since OS X 10.11.4
134 {
135 devstr = "fcd,type=2,device='FUNcube Dongle V2_0'";
136 devList.insert(std::pair<QString, QVariant>(QString("FUNcube Dongle V2_0"), QVariant(devstr)));
137 }
138 }
139 #endif
140
141 // Get list of input devices discovered by gr-osmosdr and store them in
142 // the device list together with the device descriptor strings
143 osmosdr::devices_t devs = osmosdr::device::find();
144
145 qDebug() << __FUNCTION__ << ": Available input devices:";
146 for (auto &dev : devs)
147 {
148 if (dev.count("label"))
149 {
150 devlabel = QString(dev["label"].c_str());
151 dev.erase("label");
152 }
153 else
154 {
155 devlabel = "Unknown";
156 }
157
158 devstr = QString(dev.to_string().c_str());
159 devList.insert(std::pair<QString, QVariant>(devlabel, devstr));
160 qDebug() << " " << devlabel;
161 }
162 }
163
164 /** Save configuration. */
saveConfig()165 void CIoConfig::saveConfig()
166 {
167 int idx;
168 int int_val;
169 bool conv_ok;
170
171 qDebug() << __FUNCTION__;
172
173 idx = ui->outDevCombo->currentIndex();
174
175 #if defined(WITH_PULSEAUDIO) || defined(WITH_PORTAUDIO) || defined(Q_OS_DARWIN)
176 if (idx > 0)
177 {
178 qDebug() << "Output device" << idx << ":" << QString(outDevList[idx-1].get_name().c_str());
179 m_settings->setValue("output/device", QString(outDevList[idx-1].get_name().c_str()));
180 }
181 #else
182 if (idx > 0 || ui->outDevCombo->currentText() != "Default")
183 {
184 qDebug() << "Output device:" << ui->outDevCombo->currentText();
185 m_settings->setValue("output/device", ui->outDevCombo->currentText());
186 }
187 #endif
188 else
189 {
190 m_settings->remove("output/device");
191 }
192
193 // input settings
194 m_settings->setValue("input/device", ui->inDevEdit->text()); // "OK" button disabled if empty
195
196 qint64 value = (qint64)(ui->bwSpinBox->value()*1.e6);
197 if (value)
198 m_settings->setValue("input/bandwidth", value);
199 else
200 m_settings->remove("input/bandwidth");
201
202 value = (qint64)(ui->loSpinBox->value()*1.e6);
203 if (value)
204 m_settings->setValue("input/lnb_lo", value);
205 else
206 m_settings->remove("input/lnb_lo");
207
208 int_val = ui->inSrCombo->currentText().toInt(&conv_ok);
209 if (conv_ok)
210 m_settings->setValue("input/sample_rate", int_val);
211 else
212 m_settings->remove("input/sample_rate");
213
214 idx = ui->decimCombo->currentIndex();
215 int_val = idx2decim(idx);
216 if (int_val < 2)
217 m_settings->remove("input/decimation");
218 else
219 m_settings->setValue("input/decimation", int_val);
220 }
221
222
223 /**
224 * @brief Update list of sample rates based on selected device.
225 * @param rate The current sample rate from the configuration.
226 */
updateInputSampleRates(int rate)227 void CIoConfig::updateInputSampleRates(int rate)
228 {
229 ui->inSrCombo->clear();
230
231 if (ui->inDevEdit->text().isEmpty())
232 return;
233
234 if (ui->inDevEdit->text().contains("fcd"))
235 {
236 if (ui->inDevCombo->currentText().contains("V2")) // V2.0 or V2_0
237 {
238 ui->inSrCombo->addItem("192000");
239 }
240 else
241 {
242 ui->inSrCombo->addItem("96000");
243 }
244 }
245 else if (ui->inDevEdit->text().contains("rtl") || ui->inDevEdit->text().contains("rtl_tcp"))
246 {
247 ui->inSrCombo->addItem("240000");
248 ui->inSrCombo->addItem("300000");
249 ui->inSrCombo->addItem("960000");
250 ui->inSrCombo->addItem("1152000");
251 ui->inSrCombo->addItem("1200000");
252 ui->inSrCombo->addItem("1440000");
253 ui->inSrCombo->addItem("1600000");
254 ui->inSrCombo->addItem("1800000");
255 ui->inSrCombo->addItem("1920000");
256 ui->inSrCombo->addItem("2400000");
257 ui->inSrCombo->addItem("2880000");
258 ui->inSrCombo->addItem("3200000");
259 if (rate > 0)
260 {
261 ui->inSrCombo->addItem(QString("%1").arg(rate));
262 ui->inSrCombo->setCurrentIndex(12);
263 }
264 else
265 {
266 ui->inSrCombo->setCurrentIndex(7);
267 }
268 }
269 else if (ui->inDevEdit->text().contains("uhd"))
270 {
271 if (rate > 0)
272 ui->inSrCombo->addItem(QString("%1").arg(rate));
273 ui->inSrCombo->addItem("250000");
274 ui->inSrCombo->addItem("500000");
275 ui->inSrCombo->addItem("2000000");
276 ui->inSrCombo->addItem("4000000");
277 ui->inSrCombo->addItem("8000000");
278 }
279 else if (ui->inDevEdit->text().contains("hackrf"))
280 {
281 if (rate > 0)
282 ui->inSrCombo->addItem(QString("%1").arg(rate));
283 ui->inSrCombo->addItem("8000000");
284 ui->inSrCombo->addItem("10000000");
285 ui->inSrCombo->addItem("12500000");
286 ui->inSrCombo->addItem("16000000");
287 ui->inSrCombo->addItem("20000000");
288 }
289 else if (ui->inDevEdit->text().contains("bladerf"))
290 {
291 if (rate > 0)
292 ui->inSrCombo->addItem(QString("%1").arg(rate));
293 ui->inSrCombo->addItem("5000000");
294 ui->inSrCombo->addItem("8000000");
295 ui->inSrCombo->addItem("10000000");
296 ui->inSrCombo->addItem("15000000");
297 ui->inSrCombo->addItem("20000000");
298 ui->inSrCombo->addItem("25000000");
299 ui->inSrCombo->addItem("30000000");
300 ui->inSrCombo->addItem("35000000");
301 ui->inSrCombo->addItem("40000000");
302 }
303 else if (ui->inDevEdit->text().contains("sdr-iq"))
304 {
305 ui->inSrCombo->addItem("8138");
306 ui->inSrCombo->addItem("16276");
307 ui->inSrCombo->addItem("37793");
308 ui->inSrCombo->addItem("55556");
309 ui->inSrCombo->addItem("111111");
310 ui->inSrCombo->addItem("158730");
311 ui->inSrCombo->addItem("196078");
312 if (rate > 0)
313 {
314 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
315 ui->inSrCombo->setCurrentIndex(0);
316 }
317 else
318 ui->inSrCombo->setCurrentIndex(4); // select 111.111 kHz
319 }
320 else if (ui->inDevEdit->text().contains("sdr-ip"))
321 {
322 ui->inSrCombo->addItem("31250");
323 ui->inSrCombo->addItem("32000");
324 ui->inSrCombo->addItem("40000");
325 ui->inSrCombo->addItem("50000");
326 ui->inSrCombo->addItem("62500");
327 ui->inSrCombo->addItem("64000");
328 ui->inSrCombo->addItem("80000");
329 ui->inSrCombo->addItem("100000");
330 ui->inSrCombo->addItem("125000");
331 ui->inSrCombo->addItem("160000");
332 ui->inSrCombo->addItem("200000");
333 ui->inSrCombo->addItem("250000");
334 ui->inSrCombo->addItem("320000");
335 ui->inSrCombo->addItem("400000");
336 ui->inSrCombo->addItem("500000");
337 ui->inSrCombo->addItem("800000");
338 ui->inSrCombo->addItem("1000000");
339 ui->inSrCombo->addItem("1600000");
340 ui->inSrCombo->addItem("2000000");
341 if (rate > 0)
342 {
343 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
344 ui->inSrCombo->setCurrentIndex(0);
345 }
346 else
347 ui->inSrCombo->setCurrentIndex(11); // select 250 kHz
348 }
349 else if (ui->inDevEdit->text().contains("netsdr"))
350 {
351 ui->inSrCombo->addItem("32000");
352 ui->inSrCombo->addItem("40000");
353 ui->inSrCombo->addItem("50000");
354 ui->inSrCombo->addItem("62500");
355 ui->inSrCombo->addItem("78125");
356 ui->inSrCombo->addItem("80000");
357 ui->inSrCombo->addItem("100000");
358 ui->inSrCombo->addItem("125000");
359 ui->inSrCombo->addItem("156250");
360 ui->inSrCombo->addItem("160000");
361 ui->inSrCombo->addItem("200000");
362 ui->inSrCombo->addItem("250000");
363 ui->inSrCombo->addItem("312500");
364 ui->inSrCombo->addItem("400000");
365 ui->inSrCombo->addItem("500000");
366 ui->inSrCombo->addItem("625000");
367 ui->inSrCombo->addItem("800000");
368 ui->inSrCombo->addItem("1000000");
369 ui->inSrCombo->addItem("1250000");
370 ui->inSrCombo->addItem("2000000");
371 if (rate > 0)
372 {
373 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
374 ui->inSrCombo->setCurrentIndex(0);
375 }
376 else
377 ui->inSrCombo->setCurrentIndex(11); // select 250 kHz
378 }
379 else if (ui->inDevEdit->text().contains("cloudiq"))
380 {
381 ui->inSrCombo->addItem("48000");
382 ui->inSrCombo->addItem("61440");
383 ui->inSrCombo->addItem("96000");
384 ui->inSrCombo->addItem("122880");
385 ui->inSrCombo->addItem("240000");
386 ui->inSrCombo->addItem("256000");
387 ui->inSrCombo->addItem("370120");
388 ui->inSrCombo->addItem("495483");
389 ui->inSrCombo->addItem("512000");
390 ui->inSrCombo->addItem("614400");
391 ui->inSrCombo->addItem("1024000");
392 ui->inSrCombo->addItem("1228800");
393 ui->inSrCombo->addItem("1807058");
394 if (rate > 0)
395 {
396 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
397 ui->inSrCombo->setCurrentIndex(0);
398 }
399 else
400 ui->inSrCombo->setCurrentIndex(4); // select 240 kHz
401 }
402 else if (ui->inDevEdit->text().contains("airspyhf"))
403 {
404 ui->inSrCombo->addItem("192000");
405 ui->inSrCombo->addItem("256000");
406 ui->inSrCombo->addItem("384000");
407 ui->inSrCombo->addItem("456000");
408 ui->inSrCombo->addItem("768000");
409 ui->inSrCombo->addItem("912000");
410
411 if (rate > 0)
412 {
413 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
414 ui->inSrCombo->setCurrentIndex(0);
415 }
416 else
417 ui->inSrCombo->setCurrentIndex(4); // select 768 kHz
418 }
419 // NB: must list airspyhf first
420 else if (ui->inDevEdit->text().contains("airspy"))
421 {
422 if (rate > 0)
423 ui->inSrCombo->addItem(QString("%1").arg(rate));
424
425 ui->inSrCombo->addItem("2500000");
426 ui->inSrCombo->addItem("3000000");
427 ui->inSrCombo->addItem("6000000");
428 ui->inSrCombo->addItem("10000000");
429 }
430 else if (ui->inDevEdit->text().contains("redpitaya"))
431 {
432 ui->inSrCombo->addItem("20000");
433 ui->inSrCombo->addItem("50000");
434 ui->inSrCombo->addItem("100000");
435 ui->inSrCombo->addItem("250000");
436 ui->inSrCombo->addItem("500000");
437 ui->inSrCombo->addItem("1250000");
438 if (rate > 0)
439 {
440 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
441 ui->inSrCombo->setCurrentIndex(0);
442 }
443 else
444 ui->inSrCombo->setCurrentIndex(3); // select 250 kHz
445 }
446 else if (ui->inDevEdit->text().contains("sdrplay"))
447 {
448 ui->inSrCombo->addItem("62500");
449 ui->inSrCombo->addItem("125000");
450 ui->inSrCombo->addItem("250000");
451 ui->inSrCombo->addItem("500000");
452 ui->inSrCombo->addItem("1000000");
453 ui->inSrCombo->addItem("2000000");
454 ui->inSrCombo->addItem("3000000");
455 ui->inSrCombo->addItem("4000000");
456 ui->inSrCombo->addItem("5000000");
457 ui->inSrCombo->addItem("6000000");
458 ui->inSrCombo->addItem("7000000");
459 ui->inSrCombo->addItem("8000000");
460 ui->inSrCombo->addItem("9000000");
461 ui->inSrCombo->addItem("10000000");
462 if (rate > 0)
463 {
464 if (rate < 62500)
465 rate = 62500;
466 if (rate > 10000000)
467 rate = 10000000;
468 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
469 ui->inSrCombo->setCurrentIndex(0);
470 }
471 else
472 ui->inSrCombo->setCurrentIndex(5); // select 2 MHz
473 }
474 else if (ui->inDevEdit->text().contains("lime"))
475 {
476 ui->inSrCombo->addItem("100000");
477 ui->inSrCombo->addItem("500000");
478 ui->inSrCombo->addItem("1000000");
479 ui->inSrCombo->addItem("2500000");
480 ui->inSrCombo->addItem("5000000");
481 ui->inSrCombo->addItem("10000000");
482 ui->inSrCombo->addItem("20000000");
483 ui->inSrCombo->addItem("50000000");
484 if (rate > 0)
485 {
486 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
487 ui->inSrCombo->setCurrentIndex(0);
488 }
489 else
490 ui->inSrCombo->setCurrentIndex(4); // select 5 MHz
491 }
492 else if (ui->inDevEdit->text().contains("plutosdr"))
493 {
494 ui->inSrCombo->addItem("600000");
495 ui->inSrCombo->addItem("1000000");
496 ui->inSrCombo->addItem("1500000");
497 ui->inSrCombo->addItem("2000000");
498 ui->inSrCombo->addItem("3000000");
499 ui->inSrCombo->addItem("6000000");
500 ui->inSrCombo->addItem("16000000");
501 ui->inSrCombo->addItem("20000000");
502 ui->inSrCombo->addItem("56000000");
503 if (rate > 0)
504 {
505 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
506 ui->inSrCombo->setCurrentIndex(0);
507 }
508 else
509 ui->inSrCombo->setCurrentIndex(2); // select 2 MHz
510 }
511 else if (ui->inDevEdit->text().contains("perseus"))
512 {
513 ui->inSrCombo->addItem("48000");
514 ui->inSrCombo->addItem("95000");
515 ui->inSrCombo->addItem("96000");
516 ui->inSrCombo->addItem("125000");
517 ui->inSrCombo->addItem("192000");
518 ui->inSrCombo->addItem("250000");
519 ui->inSrCombo->addItem("500000");
520 ui->inSrCombo->addItem("1000000");
521 ui->inSrCombo->addItem("1600000");
522 ui->inSrCombo->addItem("2000000");
523 if (rate > 0)
524 {
525 ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
526 ui->inSrCombo->setCurrentIndex(0);
527 }
528 else
529 ui->inSrCombo->setCurrentIndex(4); // select 192 kHz
530 }
531 else
532 {
533 if (rate > 0)
534 ui->inSrCombo->addItem(QString("%1").arg(rate));
535 }
536
537 updateDecimations();
538 }
539
540 /**
541 * @brief Update available decimations according to the current sample rate.
542 *
543 * This function will repopulate the decimation selector combo box to only
544 * include decimations up to a meaningful maximum value, so that the quadrature
545 * rate doesn't get below 48 ksps.
546 */
updateDecimations(void)547 void CIoConfig::updateDecimations(void)
548 {
549 bool ok;
550 int rate;
551
552 // get current sample rate from combo box
553 rate= ui->inSrCombo->currentText().toInt(&ok);
554 if (!ok || rate < 0)
555 return;
556
557 ui->decimCombo->clear();
558 ui->decimCombo->addItem("None", 0);
559 if (rate >= 96000)
560 ui->decimCombo->addItem("2", 0);
561 if (rate >= 192000)
562 ui->decimCombo->addItem("4", 0);
563 if (rate >= 384000)
564 ui->decimCombo->addItem("8", 0);
565 if (rate >= 768000)
566 ui->decimCombo->addItem("16", 0);
567 if (rate >= 1536000)
568 ui->decimCombo->addItem("32", 0);
569 if (rate >= 3072000)
570 ui->decimCombo->addItem("64", 0);
571 if (rate >= 6144000)
572 ui->decimCombo->addItem("128", 0);
573 // if (rate >= 12288000)
574 // ui->decimCombo->addItem("256", 0);
575 // if (rate >= 24576000)
576 // ui->decimCombo->addItem("512", 0);
577
578 decimationChanged(0);
579 }
580
updateInDev(const QSettings * settings,const std::map<QString,QVariant> & devList)581 void CIoConfig::updateInDev(const QSettings *settings, const std::map<QString, QVariant> &devList)
582 {
583 QString indev = settings->value("input/device", "").toString();
584 bool cfgmatch = false; //flag to indicate that device from config was found
585
586 // insert the device list in device combo box
587 ui->inDevCombo->clear();
588 int i = 0;
589 for (auto it = devList.cbegin(); it != devList.cend(); it++, i++)
590 {
591 auto devstr = (*it).second.toString();
592 ui->inDevCombo->addItem((*it).first, devstr);
593
594 // is this the device stored in config?
595 if (indev == devstr)
596 {
597 ui->inDevCombo->setCurrentIndex(i);
598 ui->inDevEdit->setText(devstr);
599 cfgmatch = true;
600 }
601 }
602
603 ui->inDevCombo->addItem(tr("Other..."), QVariant(""));
604
605 // If device string from config is not one of the detected devices
606 // it could be that device is not plugged in (in which case we select
607 // other) or that this is the first time (select the first detected device).
608 if (!cfgmatch)
609 {
610 if (indev.isEmpty())
611 {
612 // First time config: select the first detected device
613 ui->inDevCombo->setCurrentIndex(0);
614 ui->inDevEdit->setText(ui->inDevCombo->itemData(0).toString());
615 if (ui->inDevEdit->text().isEmpty())
616 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
617 }
618 else
619 {
620 // Select other
621 ui->inDevCombo->setCurrentIndex(i);
622 ui->inDevEdit->setText(indev);
623 }
624 }
625 }
626
updateOutDev()627 void CIoConfig::updateOutDev()
628 {
629 QString outdev = m_settings->value("output/device", "").toString();
630
631 ui->outDevCombo->clear();
632 ui->outDevCombo->addItem("Default");
633
634 // get list of audio output devices
635 #ifdef WITH_PULSEAUDIO
636 pa_device_list devices;
637 outDevList = devices.get_output_devices();
638
639 qDebug() << __FUNCTION__ << ": Available output devices:";
640 for (size_t i = 0; i < outDevList.size(); i++)
641 {
642 qDebug() << " " << i << ":" << QString(outDevList[i].get_description().c_str());
643 //qDebug() << " " << QString(outDevList[i].get_name().c_str());
644 ui->outDevCombo->addItem(QString(outDevList[i].get_description().c_str()));
645
646 // note that item #i in devlist will be item #(i+1)
647 // in combo box due to "default"
648 if (outdev == QString(outDevList[i].get_name().c_str()))
649 ui->outDevCombo->setCurrentIndex(i+1);
650 }
651 #elif WITH_PORTAUDIO
652 portaudio_device_list devices;
653
654 outDevList = devices.get_output_devices();
655 for (size_t i = 0; i < outDevList.size(); i++)
656 {
657 ui->outDevCombo->addItem(QString(outDevList[i].get_description().c_str()));
658
659 // note that item #i in devlist will be item #(i+1)
660 // in combo box due to "default"
661 if (outdev == QString(outDevList[i].get_name().c_str()))
662 ui->outDevCombo->setCurrentIndex(i+1);
663 }
664 //ui->outDevCombo->setEditable(true);
665
666 #elif defined(Q_OS_DARWIN)
667 osxaudio_device_list devices;
668 outDevList = devices.get_output_devices();
669
670 qDebug() << __FUNCTION__ << ": Available output devices:";
671 for (size_t i = 0; i < outDevList.size(); i++)
672 {
673 qDebug() << " " << i << ":" << QString(outDevList[i].get_name().c_str());
674 ui->outDevCombo->addItem(QString(outDevList[i].get_name().c_str()));
675
676 // note that item #i in devlist will be item #(i+1)
677 // in combo box due to "default"
678 if (outdev == QString(outDevList[i].get_name().c_str()))
679 ui->outDevCombo->setCurrentIndex(i+1);
680 }
681
682 #else
683 ui->outDevCombo->addItem(m_settings->value("output/device", "Default").toString(),
684 m_settings->value("output/device", "Default").toString());
685 ui->outDevCombo->setEditable(true);
686 #endif // WITH_PULSEAUDIO
687 }
688
689 /**
690 * @brief New input device has been selected by the user.
691 * @param index The index of the item that has been selected in the combo box.
692 */
inputDeviceSelected(int index)693 void CIoConfig::inputDeviceSelected(int index)
694 {
695 qDebug() << "New input device selected:" << index;
696 qDebug() << " Label:" << ui->inDevCombo->itemText(index);
697 qDebug() << " Devstr:" << ui->inDevCombo->itemData(index).toString();
698
699 ui->inDevEdit->setText(ui->inDevCombo->itemData(index).toString());
700 updateInputSampleRates(0);
701 }
702
703
704 /**
705 * @brief Input device string has changed
706 * @param text THe new device string
707 *
708 * This slot is activated when the device string in the text edit box has changed
709 * either by the user or programmatically. We use this to enable/disable the OK
710 * button - we allo OK only if there is some text in the text entry.
711 */
inputDevstrChanged(const QString & text)712 void CIoConfig::inputDevstrChanged(const QString &text)
713 {
714 if (text.isEmpty())
715 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
716 else
717 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
718 }
719
720 /**
721 * @brief Sample changed, either by selection of direct entry.
722 * @param text The new sample rate.
723 */
inputRateChanged(const QString & text)724 void CIoConfig::inputRateChanged(const QString &text)
725 {
726 (void) text;
727 updateDecimations();
728 }
729
730 /**
731 * @brief New decimation rate selected.
732 * @param index The index of the selected item in the combo box.
733 *
734 * This function calculates the quadrature rate and updates the sample rate
735 * label just below the decimation combo box.
736 */
decimationChanged(int index)737 void CIoConfig::decimationChanged(int index)
738 {
739 float quad_rate;
740 int input_rate;
741 int decim;
742 bool ok;
743
744 decim = idx2decim(index);
745 input_rate = ui->inSrCombo->currentText().toInt(&ok);
746 if (!ok)
747 return;
748
749 quad_rate = (float)input_rate / (float)decim;
750 if (quad_rate > 1.e6f)
751 ui->sampRateLabel->setText(QString(" %1 Msps").
752 arg(quad_rate * 1.e-6, 0, 'f', 3));
753 else
754 ui->sampRateLabel->setText(QString(" %1 ksps").
755 arg(quad_rate * 1.e-3, 0, 'f', 3));
756 }
757
758 /**
759 * @brief Slot to handle device list updates on m_scanButton clicks
760 */
onScanButtonClicked()761 void CIoConfig::onScanButtonClicked()
762 {
763 m_devList->clear();
764 CIoConfig::getDeviceList(*m_devList);
765 updateInDev(m_settings, *m_devList);
766 updateOutDev();
767 }
768
769 /** Convert a combo box index to decimation. */
idx2decim(int idx) const770 int CIoConfig::idx2decim(int idx) const
771 {
772 if (idx < 1)
773 return 1;
774
775 return (1 << idx);
776 }
777
778 /** Convert a decimation to a combobox index */
decim2idx(int decim) const779 int CIoConfig::decim2idx(int decim) const
780 {
781 int idx;
782
783 if (decim == 0)
784 return 0;
785
786 idx = 0;
787 while (decim >>= 1)
788 ++idx;
789
790 return idx;
791 }
792