From 507d1f2b898451c0ff1d87db5e5080dedee68e62 Mon Sep 17 00:00:00 2001 From: Dave Olsthoorn Date: Thu, 24 Mar 2016 20:04:29 +0100 Subject: [PATCH 001/334] Add dutch translation to desktop file Add dutch translations for the summary and the general name tags in the desktop package --- gqrx.desktop | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gqrx.desktop b/gqrx.desktop index d693e62..7c5807e 100644 --- a/gqrx.desktop +++ b/gqrx.desktop @@ -6,6 +6,8 @@ Comment=Software defined radio receiver implemented using GNU Radio and the Qt G # FIXME add comments in other languages GenericName[ru]=Программно-определённое радио Comment[ru]=Приемник для программно-определенного радио (SDR) использующий GNU Radio и библиотеку Qt. +GenericName[nl]=Software Defined Radio +Comment[nl]=Software defined radio ontvanger geïmplementeerd met GNU Radio en de Qt GUI toolkit Exec=gqrx Terminal=false Icon=gqrx From 7890c8dfaeb0248ab01a329e592c2a29b8437fe0 Mon Sep 17 00:00:00 2001 From: Dave Olsthoorn Date: Thu, 24 Mar 2016 20:24:16 +0100 Subject: [PATCH 002/334] Add appdata file Add an appdata file to get gqrx to show up in softwarecenter(s) --- gqrx.appdata.xml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 gqrx.appdata.xml diff --git a/gqrx.appdata.xml b/gqrx.appdata.xml new file mode 100644 index 0000000..4b4bc7d --- /dev/null +++ b/gqrx.appdata.xml @@ -0,0 +1,32 @@ + + + gqrx.desktop + Gqrx + Software defined radio receiver implemented using GNU Radio and the Qt GUI toolkit + Software defined radio ontvanger geïmplementeerd met GNU Radio en de Qt GUI toolkit + Приемник для программно-определенного радио (SDR) использующий GNU Radio и библиотеку Qt. + Alexandru Csete + +

+ +

+

+ +

+
+ CC-BY-3.0 + GPL-3.0 + https://github.com/csete/gqrx/issues + + + + http://gqrx.dk/ + + + + + https://c2.staticflickr.com/2/1567/23593127703_11fc1ac026_b.jpg + + + daveo@fedoraproject.org +
From 4cd8c561f4aa551a8951db6e6acbf8075c6c7087 Mon Sep 17 00:00:00 2001 From: Wolfgang Fritz Date: Sat, 26 Mar 2016 12:32:42 +0100 Subject: [PATCH 003/334] Add sample rates for SDRPlay. --- src/qtgui/ioconfig.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 7bd6b07..83603ed 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -474,6 +474,36 @@ void CIoConfig::updateInputSampleRates(int rate) else ui->inSrCombo->setCurrentIndex(3); // select 250 kHz } + else if (ui->inDevEdit->text().contains("sdrplay")) + { + if (rate > 0) + ui->inSrCombo->addItem(QString("%1").arg(rate)); + ui->inSrCombo->addItem("222222"); + ui->inSrCombo->addItem("333333"); + ui->inSrCombo->addItem("428571"); + ui->inSrCombo->addItem("500000"); + ui->inSrCombo->addItem("571429"); + ui->inSrCombo->addItem("750000"); + ui->inSrCombo->addItem("875000"); + ui->inSrCombo->addItem("1000000"); + ui->inSrCombo->addItem("1536000"); + ui->inSrCombo->addItem("2048000"); + ui->inSrCombo->addItem("5000000"); + ui->inSrCombo->addItem("6000000"); + ui->inSrCombo->addItem("7000000"); + ui->inSrCombo->addItem("8000000"); + ui->inSrCombo->addItem("9000000"); + ui->inSrCombo->addItem("10000000"); + ui->inSrCombo->addItem("11000000"); + ui->inSrCombo->addItem("12000000"); + if (rate == 0) + ui->inSrCombo->setCurrentIndex(9); // select 2048 kHz + } + else + { + if (rate > 0) + ui->inSrCombo->addItem(QString("%1").arg(rate)); + } updateDecimations(); } From 3e32dfde39e305e0c2b347409c94f0be8105afa3 Mon Sep 17 00:00:00 2001 From: Wolfgang Fritz Date: Sun, 27 Mar 2016 20:00:27 +0200 Subject: [PATCH 004/334] src/qtgui/dockinputctl.cpp: Set gain mode on startup Some drivers don not start with autogain enabled. Make sure that the gain mode is properly restored from config file at start up. --- src/qtgui/dockinputctl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qtgui/dockinputctl.cpp b/src/qtgui/dockinputctl.cpp index 545efec..c80b294 100644 --- a/src/qtgui/dockinputctl.cpp +++ b/src/qtgui/dockinputctl.cpp @@ -69,6 +69,7 @@ void DockInputCtl::readSettings(QSettings *settings) bool_val = settings->value("input/hwagc", false).toBool(); setAgc(bool_val); + emit autoGainChanged(bool_val); // Ignore antenna selection if there is only one option if (ui->antSelector->count() > 1) From 04034816c5d4e591b5f0498ee7010f0db8e17e97 Mon Sep 17 00:00:00 2001 From: Wolfgang Fritz Date: Thu, 31 Mar 2016 18:25:02 +0200 Subject: [PATCH 005/334] Probe SDR devices only at program start The probing of SDR devices is only done once before the first configuration isn done. Later the cached list of devices is used. Reason for this is that some devices (SDRPlay RSP) get reinitialized during device probe and lose their configuration. --- src/applications/gqrx/mainwindow.cpp | 9 +- src/applications/gqrx/mainwindow.h | 2 + src/qtgui/ioconfig.cpp | 134 +++++++++++++++------------ src/qtgui/ioconfig.h | 3 +- 4 files changed, 84 insertions(+), 64 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 3423996..8e81b90 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -279,6 +279,10 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : ui->plotter->setTooltipsEnabled(true); #endif + // Create list of input devices. This must be done before the configuration is + // restored because device probing might change the device configuration + CIoConfig::getDeviceList(devList); + // restore last session if (!loadConfig(cfgfile, true)) { @@ -1715,7 +1719,7 @@ int MainWindow::on_actionIoConfig_triggered() { qDebug() << "Configure I/O devices."; - CIoConfig *ioconf = new CIoConfig(m_settings); + CIoConfig *ioconf = new CIoConfig(m_settings, devList); int confres = ioconf->exec(); if (confres == QDialog::Accepted) @@ -1743,7 +1747,7 @@ int MainWindow::firstTimeConfig() { qDebug() << __func__; - CIoConfig *ioconf = new CIoConfig(m_settings); + CIoConfig *ioconf = new CIoConfig(m_settings, devList); int confres = ioconf->exec(); if (confres == QDialog::Accepted) @@ -2092,6 +2096,7 @@ void MainWindow::showSimpleTextFile(const QString &resource_path, // browser and layout deleted automatically } + /** * @brief Action: About Qthid * diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index f3c702b..2160777 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -116,6 +116,8 @@ public slots: RemoteControl *remote; + std::map devList; + private: void updateHWFrequencyRange(bool ignore_limits); void updateFrequencyRange(); diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 83603ed..7e1b881 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -44,69 +44,26 @@ #include "ui_ioconfig.h" -CIoConfig::CIoConfig(QSettings *settings, QWidget *parent) : +CIoConfig::CIoConfig(QSettings *settings, std::map &devList, QWidget *parent) : QDialog(parent), ui(new Ui::CIoConfig), m_settings(settings) { unsigned int i=0; QString devstr; - QString devlabel; bool cfgmatch=false; //flag to indicate that device from config was found ui->setupUi(this); QString indev = settings->value("input/device", "").toString(); - // automatic discovery of FCD does not work on Mac - // so we do it ourselves -#if defined(GQRX_OS_MACX) - osxaudio_device_list devices; - inDevList = devices.get_input_devices(); - - string this_dev; - for (i = 0; i < inDevList.size(); i++) + // insert the device list in device combo box + std::map::iterator I = devList.begin(); + i = 0; + while (I != devList.end()) { - this_dev = inDevList[i].get_name(); - if (this_dev.find("FUNcube Dongle V1.0") != string::npos) - { - devstr = "fcd,type=1,device='FUNcube Dongle V1.0'"; - ui->inDevCombo->addItem("FUNcube Dongle V1.0", QVariant(devstr)); - } - else if (this_dev.find("FUNcube Dongle V2.0") != string::npos) - { - devstr = "fcd,type=2,device='FUNcube Dongle V2.0'"; - ui->inDevCombo->addItem("FUNcube Dongle V2.0", QVariant(devstr)); - } - - if (indev == QString(inDevList[i].get_name().c_str())) - { - ui->inDevCombo->setCurrentIndex(i); - ui->inDevEdit->setText(devstr); - cfgmatch = true; - } - } -#endif - - // Get list of input devices discovered by gr-osmosdr and store them in - // the input device selector together with the device descriptor strings - osmosdr::devices_t devs = osmosdr::device::find(); - - qDebug() << __FUNCTION__ << ": Available input devices:"; - BOOST_FOREACH(osmosdr::device_t &dev, devs) - { - if (dev.count("label")) - { - devlabel = QString(dev["label"].c_str()); - dev.erase("label"); - } - else - { - devlabel = "Unknown"; - } - - devstr = QString(dev.to_string().c_str()); - ui->inDevCombo->addItem(devlabel, QVariant(devstr)); + devstr = (*I).second.toString(); + ui->inDevCombo->addItem((*I).first, devstr); // is this the device stored in config? if (indev == devstr) @@ -115,20 +72,11 @@ CIoConfig::CIoConfig(QSettings *settings, QWidget *parent) : ui->inDevEdit->setText(devstr); cfgmatch = true; } - - qDebug() << " " << i << ":" << devlabel; + ++I; ++i; - - // Following code could be used for multiple matches - /* QStringList list; - int pos = 0; - while ((pos = rx.indexIn(devstr, pos)) != -1) { - list << rx.cap(1); - pos += rx.matchedLength(); - } */ - } + ui->inDevCombo->addItem(tr("Other..."), QVariant("")); // If device string from config is not one of the detected devices @@ -221,6 +169,70 @@ CIoConfig::~CIoConfig() delete ui; } +/** + * @brief get the list of devices + */ +void CIoConfig::getDeviceList(std::map &devList) +{ + unsigned int i=0; + QString devstr; + QString devlabel; + +#if defined(GQRX_OS_MACX) + // automatic discovery of FCD does not work on Mac + // so we do it ourselves + osxaudio_device_list devices; + inDevList = devices.get_input_devices(); + + string this_dev; + for (i = 0; i < inDevList.size(); i++) + { + this_dev = inDevList[i].get_name(); + if (this_dev.find("FUNcube Dongle V1.0") != string::npos) + { + devstr = "fcd,type=1,device='FUNcube Dongle V1.0'"; + devList.insert(std::pair(QString("FUNcube Dongle V1.0"), QVariant(devstr))); + } + else if (this_dev.find("FUNcube Dongle V2.0") != string::npos) + { + devstr = "fcd,type=2,device='FUNcube Dongle V2.0'"; + devList.insert(std::pair(QString("FUNcube Dongle V2.0"), QVariant(devstr))); + } + } +#endif + + // Get list of input devices discovered by gr-osmosdr and store them in + // the device list together with the device descriptor strings + osmosdr::devices_t devs = osmosdr::device::find(); + + qDebug() << __FUNCTION__ << ": Available input devices:"; + BOOST_FOREACH(osmosdr::device_t &dev, devs) + { + if (dev.count("label")) + { + devlabel = QString(dev["label"].c_str()); + dev.erase("label"); + } + else + { + devlabel = "Unknown"; + } + + devstr = QString(dev.to_string().c_str()); + devList.insert(std::pair(devlabel, devstr)); + + qDebug() << " " << i << ":" << devlabel; + ++i; + + // Following code could be used for multiple matches + /* QStringList list; + int pos = 0; + while ((pos = rx.indexIn(devstr, pos)) != -1) { + list << rx.cap(1); + pos += rx.matchedLength(); + } */ + } +} /** @brief Save configuration. */ void CIoConfig::saveConfig() diff --git a/src/qtgui/ioconfig.h b/src/qtgui/ioconfig.h index 016a15c..cfb75e7 100644 --- a/src/qtgui/ioconfig.h +++ b/src/qtgui/ioconfig.h @@ -44,8 +44,9 @@ class CIoConfig : public QDialog Q_OBJECT public: - explicit CIoConfig(QSettings *settings, QWidget *parent = 0); + explicit CIoConfig(QSettings *settings, std::map &devList, QWidget *parent = 0); virtual ~CIoConfig(); + static void getDeviceList(std::map &devList); private slots: void saveConfig(); From 529fb143fa219423b3d61cee515db14b3c6a772b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 4 Apr 2016 21:22:38 +0200 Subject: [PATCH 006/334] Fixed copy & paste error. --- src/applications/gqrx/mainwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 8e81b90..9bbaf13 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2096,9 +2096,8 @@ void MainWindow::showSimpleTextFile(const QString &resource_path, // browser and layout deleted automatically } - /** - * @brief Action: About Qthid + * @brief Action: About gqrx. * * This slot is called when the user activates the * Help|About menu item (or Gqrx|About on Mac) From 6f36c2bd3029260c208be5c4065686401c877fa5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 4 Apr 2016 21:28:09 +0200 Subject: [PATCH 007/334] Update news and readme files. --- README.md | 5 +++++ resources/news.txt | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 143ede6..fbbebc2 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,11 @@ Vincent Pelletier Will Scales - Bug fixes. +Wolfgang Fritz DK7OB +- SDRPlay integration. +- Various UI improvements. + + Also thanks to Volker Schroer and Alexey Bazhin for bringing Funcube Dongle Pro+ support to GNU Radio and Gqrx. diff --git a/resources/news.txt b/resources/news.txt index cf4dce6..92e7a0f 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,3 +1,9 @@ + 2.6: Released TBD + + FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. + IMPROVED: SDRPlay integration. + IMPROVED: Only probe for devices when the program is satarted. + 2.5.3: Released February 3, 2016. NEW: Set and read squelch via remote control socket. From 317cdaafaef926c02ee6069a1d1f9dabcee2f13a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 4 Apr 2016 21:35:22 +0200 Subject: [PATCH 008/334] Fix FCD Pro/Pro+ detection on Mac OS X 10.11.4 Fixes issue #357. --- src/qtgui/ioconfig.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 7e1b881..e8dd513 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -193,11 +193,21 @@ void CIoConfig::getDeviceList(std::map &devList) devstr = "fcd,type=1,device='FUNcube Dongle V1.0'"; devList.insert(std::pair(QString("FUNcube Dongle V1.0"), QVariant(devstr))); } + else if (this_dev.find("FUNcube Dongle V1_0") != string::npos) // since OS X 10.11.4 + { + devstr = "fcd,type=1,device='FUNcube Dongle V1_0'"; + ui->inDevCombo->addItem("FUNcube Dongle V1_0", QVariant(devstr)); + } else if (this_dev.find("FUNcube Dongle V2.0") != string::npos) { devstr = "fcd,type=2,device='FUNcube Dongle V2.0'"; devList.insert(std::pair(QString("FUNcube Dongle V2.0"), QVariant(devstr))); } + else if (this_dev.find("FUNcube Dongle V2_0") != string::npos) // since OS X 10.11.4 + { + devstr = "fcd,type=2,device='FUNcube Dongle V2_0'"; + ui->inDevCombo->addItem("FUNcube Dongle V2_0", QVariant(devstr)); + } } #endif @@ -309,7 +319,7 @@ void CIoConfig::updateInputSampleRates(int rate) if (ui->inDevEdit->text().contains("fcd")) { - if (ui->inDevCombo->currentText().contains("V2.0")) + if (ui->inDevCombo->currentText().contains("V2")) // V2.0 or V2_0 { ui->inSrCombo->addItem("192000"); } From a4e9e927eca32d2ed7dc7886084bb2d3cbd9c4ca Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 6 Apr 2016 21:52:18 +0200 Subject: [PATCH 009/334] Fix incorrect merge in commit 317cdaa. --- src/qtgui/ioconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index e8dd513..96b3b18 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -196,7 +196,7 @@ void CIoConfig::getDeviceList(std::map &devList) else if (this_dev.find("FUNcube Dongle V1_0") != string::npos) // since OS X 10.11.4 { devstr = "fcd,type=1,device='FUNcube Dongle V1_0'"; - ui->inDevCombo->addItem("FUNcube Dongle V1_0", QVariant(devstr)); + devList.insert(std::pair(QString("FUNcube Dongle V1_0"), QVariant(devstr))); } else if (this_dev.find("FUNcube Dongle V2.0") != string::npos) { @@ -206,7 +206,7 @@ void CIoConfig::getDeviceList(std::map &devList) else if (this_dev.find("FUNcube Dongle V2_0") != string::npos) // since OS X 10.11.4 { devstr = "fcd,type=2,device='FUNcube Dongle V2_0'"; - ui->inDevCombo->addItem("FUNcube Dongle V2_0", QVariant(devstr)); + devList.insert(std::pair(QString("FUNcube Dongle V2_0"), QVariant(devstr))); } } #endif From 600f1913aedfa8459ebb11a46b528c7b9bb20a44 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 11 Apr 2016 12:21:57 +0200 Subject: [PATCH 010/334] Use system font ion plotter. This should fix small font issues with high resolution monitors, e.g. #359 --- src/qtgui/dockaudio.cpp | 5 ----- src/qtgui/plotter.cpp | 18 +++--------------- src/qtgui/plotter.h | 5 ++--- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 94964f9..71833c4 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -66,11 +66,6 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setFilterBoxEnabled(false); ui->audioSpectrum->setCenterLineEnabled(false); ui->audioSpectrum->setMinMaxDB(-110, -20); -#ifdef Q_OS_MAC - ui->audioSpectrum->setFontSize(11); -#else - ui->audioSpectrum->setFontSize(9); -#endif ui->audioSpectrum->setVdivDelta(30); ui->audioSpectrum->setHdivDelta(40); ui->audioSpectrum->setFreqDigits(1); diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index e25d542..3ebe1ac 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -184,12 +184,6 @@ CPlotter::CPlotter(QWidget *parent) : m_Size = QSize(0,0); m_GrabPosition = 0; m_Percent2DScreen = 30; //percent of screen used for 2D display - -#ifdef Q_OS_MAC - m_FontSize = 11; -#else - m_FontSize = 9; -#endif m_VdivDelta = 40; m_HdivDelta = 80; @@ -1321,13 +1315,8 @@ void CPlotter::drawOverlay() painter.drawLine(m_DemodFreqX, 0, m_DemodFreqX, h); } - // create Font to use for scales - QFont Font("Arial"); - Font.setPointSize(m_FontSize); - QFontMetrics metrics(Font); - - Font.setWeight(QFont::Normal); - painter.setFont(Font); + QFontMetrics metrics(m_Font); + painter.setFont(m_Font); // draw vertical grids pixperdiv = (float)w / (float)m_HorDivs; @@ -1425,8 +1414,7 @@ void CPlotter::drawOverlay() // draw amplitude values painter.setPen(QColor(0xD8,0xBA,0xA1,0xFF)); - //Font.setWeight(QFont::Light); - painter.setFont(Font); + int dB = m_MaxdB; m_YAxisWidth = metrics.width("-120 "); for (int i = 1; i < m_VerDivs; i++) diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 22db9ec..d1be4e4 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -3,6 +3,7 @@ #define PLOTTER_H #include +#include #include #include #include @@ -86,8 +87,6 @@ class CPlotter : public QFrame } void setMinMaxDB(float min, float max); - - void setFontSize(int points) { m_FontSize = points; } void setHdivDelta(int delta) { m_HdivDelta = delta; } void setVdivDelta(int delta) { m_VdivDelta = delta; } @@ -239,7 +238,7 @@ public slots: int m_Yzero; /*!< Used to measure mouse drag direction. */ int m_FreqDigits; /*!< Number of decimal digits in frequency strings. */ - int m_FontSize; /*!< Font size in points. */ + QFont m_Font; /*!< Font used for plotter (system font) */ int m_HdivDelta; /*!< Minimum distance in pixels between two horizontal grid lines (vertical division). */ int m_VdivDelta; /*!< Minimum distance in pixels between two vertical grid lines (horizontal division). */ From f1d10b470cd68139b5fd5280dc2460976eae443f Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 11 Apr 2016 12:26:56 +0200 Subject: [PATCH 011/334] Updated news file. --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 92e7a0f..cfed8a5 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,6 @@ 2.6: Released TBD + FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is satarted. From bd269212fec51aa268b079ed0fe2d12ff6029cbf Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 15 Apr 2016 23:33:37 +0200 Subject: [PATCH 012/334] Fix OS X build issues (#361) --- src/qtgui/ioconfig.cpp | 4 ++-- src/qtgui/ioconfig.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 96b3b18..97eae13 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -137,7 +137,7 @@ CIoConfig::CIoConfig(QSettings *settings, std::map &devList, #elif defined(GQRX_OS_MACX) // get list of output devices - // (already defined) osxaudio_device_list devices; + osxaudio_device_list devices; outDevList = devices.get_output_devices(); qDebug() << __FUNCTION__ << ": Available output devices:"; @@ -182,7 +182,7 @@ void CIoConfig::getDeviceList(std::map &devList) // automatic discovery of FCD does not work on Mac // so we do it ourselves osxaudio_device_list devices; - inDevList = devices.get_input_devices(); + vector inDevList = devices.get_input_devices(); string this_dev; for (i = 0; i < inDevList.size(); i++) diff --git a/src/qtgui/ioconfig.h b/src/qtgui/ioconfig.h index cfb75e7..912f0b4 100644 --- a/src/qtgui/ioconfig.h +++ b/src/qtgui/ioconfig.h @@ -70,7 +70,6 @@ private slots: vector outDevList; #elif defined(GQRX_OS_MACX) vector outDevList; - vector inDevList; #endif }; From db58729a3f0c38328f4f6d14f8e0a756c8deaeec Mon Sep 17 00:00:00 2001 From: Andy Sloane Date: Thu, 21 Apr 2016 14:48:40 -0700 Subject: [PATCH 013/334] Prevent IQ panel from crashing on random *.raw If a filename doesn't contain the expected gqrx_yymmdd_hhmmss_freq_samprate_fc.raw pattern, sampleRateFromFileName would crash. --- src/qtgui/iq_tool.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qtgui/iq_tool.cpp b/src/qtgui/iq_tool.cpp index 67b8840..e63f6bd 100644 --- a/src/qtgui/iq_tool.cpp +++ b/src/qtgui/iq_tool.cpp @@ -437,6 +437,9 @@ qint64 CIqTool::sampleRateFromFileName(const QString &filename) QStringList list = filename.split('_'); + if (list.size() < 5) + return sample_rate; + // gqrx_yymmdd_hhmmss_freq_samprate_fc.raw sr = list.at(4).toLongLong(&ok); From 8103ef620099518a9af1761e1610750c10ec0075 Mon Sep 17 00:00:00 2001 From: Andy Sloane Date: Thu, 21 Apr 2016 15:01:52 -0700 Subject: [PATCH 014/334] Set UDP packet size limit to 512 bytes Workaround for #363. Substantially more reliable on OS X with this, though the reason packets are lost remains elusive. --- src/interfaces/udp_sink_f.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/interfaces/udp_sink_f.cpp b/src/interfaces/udp_sink_f.cpp index adda667..4df6305 100644 --- a/src/interfaces/udp_sink_f.cpp +++ b/src/interfaces/udp_sink_f.cpp @@ -50,7 +50,13 @@ udp_sink_f::udp_sink_f() { d_f2s = gr::blocks::float_to_short::make(1, 32767); +#ifdef GQRX_OS_MACX + // There seems to be excessive packet loss (even to localhost) on OS X + // unless the buffer size is limited. + d_sink = gr::blocks::udp_sink::make(sizeof(short), "localhost", 7355, 512); +#else d_sink = gr::blocks::udp_sink::make(sizeof(short), "localhost", 7355); +#endif d_sink->disconnect(); connect(self(), 0, d_f2s, 0); From ba612ea165b0c3a75dc9efc0416806ab64aa21e6 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 23 Apr 2016 17:20:43 +0200 Subject: [PATCH 015/334] Updated readme. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index fbbebc2..caa2cbb 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,9 @@ Following people and organisations have contributed to gqrx: Alex Grinkov: - FM stereo demodulator. +Andy Sloane: +- Bug fixes and improvements. + Andrea Merello: - Cmake build option to build using gr-audio. From 3c7b5330600033c8cee93273582d3c558c1bddeb Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 1 May 2016 01:15:01 +0200 Subject: [PATCH 016/334] Use UTC for waterfall times. --- src/applications/gqrx/mainwindow.cpp | 2 +- src/qtgui/plotter.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 9bbaf13..f5b284f 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1810,7 +1810,7 @@ void MainWindow::on_actionSaveSettings_triggered() void MainWindow::on_actionSaveWaterfall_triggered() { - QDateTime dt(QDateTime::currentDateTime()); + QDateTime dt(QDateTime::currentDateTimeUtc()); QString wffile; QString save_path; diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index 3ebe1ac..6425f13 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -593,6 +593,7 @@ bool CPlotter::saveWaterfall(const QString & filename) const quint64 msec; int tdivs = h / 70 + 1; pixperdiv = (float) h / (float) tdivs; + tt.setOffsetFromUtc(0); // ensure time is in UTC for (i = 1; i < tdivs; i++) { y = (int)((float)i * pixperdiv); From 35eec7e8ed3cd207ebb92a804a65ca7e68da86f2 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 2 May 2016 21:14:02 +0200 Subject: [PATCH 017/334] Use UTC time function available in Qt 4.8 --- src/qtgui/plotter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index 6425f13..cfdbcad 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -593,7 +593,7 @@ bool CPlotter::saveWaterfall(const QString & filename) const quint64 msec; int tdivs = h / 70 + 1; pixperdiv = (float) h / (float) tdivs; - tt.setOffsetFromUtc(0); // ensure time is in UTC + tt.setTimeSpec(Qt::OffsetFromUTC); for (i = 1; i < tdivs; i++) { y = (int)((float)i * pixperdiv); From 78fff0395c7f32ae93c406cb1552c7ea6cf280a7 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 6 May 2016 14:28:45 +0200 Subject: [PATCH 018/334] Increase frequency deviation for APT. --- src/qtgui/demod_options.cpp | 4 ++-- src/qtgui/demod_options.ui | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qtgui/demod_options.cpp b/src/qtgui/demod_options.cpp index be158c4..d693928 100644 --- a/src/qtgui/demod_options.cpp +++ b/src/qtgui/demod_options.cpp @@ -85,8 +85,8 @@ void CDemodOptions::on_maxdevSelector_activated(int index) max_dev = 5000.0; break; case 2: - /* APT 17k */ - max_dev = 17000.0; + /* APT 25k (17k but need some margin for Doppler and freq error) */ + max_dev = 25000.0; break; case 3: /* Broadcast FM 75k */ diff --git a/src/qtgui/demod_options.ui b/src/qtgui/demod_options.ui index 40f9a70..5147b6f 100644 --- a/src/qtgui/demod_options.ui +++ b/src/qtgui/demod_options.ui @@ -100,26 +100,26 @@ this demodulator Maximum FM deviation - 1 + 0 - Voice (2.5k) + Voice (2.5 kHz) - Voice (5k) + Voice (5 kHz) - APT (17k) + APT (25 kHz) - BC (75k) + BC (75 kHz) @@ -227,7 +227,7 @@ For digital modes it is best to switch it off. - + 20 From fb6df7aa0efd644df7a02148b78b13c6902afda9 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 8 May 2016 15:51:26 +0200 Subject: [PATCH 019/334] Fixed typos --- resources/remote-control.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/remote-control.txt b/resources/remote-control.txt index bd4e633..8b2ebdc 100644 --- a/resources/remote-control.txt +++ b/resources/remote-control.txt @@ -1,6 +1,6 @@ Remote control protocol. -Supported command: +Supported commands: f - Get frequency [Hz] F - Set frequency [Hz] m - Get demodulator mode From 30474a1389709d335332262509dbaf21a7ef4196 Mon Sep 17 00:00:00 2001 From: Ludovico Cavedon Date: Wed, 11 May 2016 16:52:29 +0200 Subject: [PATCH 020/334] #374 remote control: reset receiver offset if hw frequency needs to be changed --- src/applications/gqrx/remote_control.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index e587cd9..079a6b0 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -426,6 +426,9 @@ void RemoteControl::setNewRemoteFreq(qint64 freq) { // move rx freqeucy and let MainWindow deal with it // (will usually change hardware PLL) + // reset the filter_offset, otherwise the MainWindo will preserve it + rc_filter_offset = 0; + emit newFilterOffset(rc_filter_offset); emit newFrequency(freq); } From 51a01f5afdf539b963de867edb53696fc210a1c4 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Sat, 21 May 2016 08:59:46 +0200 Subject: [PATCH 021/334] fix wrong filename when decimation is enabled --- src/applications/gqrx/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index f5b284f..f3cbe80 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1412,9 +1412,10 @@ void MainWindow::startIqRecording(const QString recdir) // gqrx_iq_yyyymmdd_hhmmss_freq_bw_fc.raw qint64 freq = (qint64)(rx->get_rf_freq()); qint64 sr = (qint64)(rx->get_input_rate()); + qint32 dec = (quint32)(rx->get_input_decim()); QString lastRec = QDateTime::currentDateTimeUtc(). toString("%1/gqrx_yyyyMMdd_hhmmss_%2_%3_fc.'raw'") - .arg(recdir).arg(freq).arg(sr); + .arg(recdir).arg(freq).arg(sr/dec); // start recorder; fails if recording already in progress if (rx->start_iq_recording(lastRec.toStdString())) From b3ec1524ad996d37fb98aa70f48f27c25ec6300e Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Sat, 21 May 2016 09:34:55 +0200 Subject: [PATCH 022/334] fix integer overflow --- src/qtgui/plotter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index cfdbcad..153b17f 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -1177,7 +1177,7 @@ void CPlotter::getScreenIntegerFFTData(qint32 plotHeight, qint32 plotWidth, { // more FFT points than plot points for (i = minbin; i < maxbin; i++) - m_pTranslateTbl[i] = ((i-m_BinMin)*plotWidth) / (m_BinMax - m_BinMin); + m_pTranslateTbl[i] = ((qint64)(i-m_BinMin)*plotWidth) / (m_BinMax - m_BinMin); *xmin = m_pTranslateTbl[minbin]; *xmax = m_pTranslateTbl[maxbin - 1]; } From 4f7a3657b2428208fc9b7c0d92b6e45fd995dd48 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 22 May 2016 11:42:52 +0200 Subject: [PATCH 023/334] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index caa2cbb..008a8a7 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,9 @@ Following people and organisations have contributed to gqrx: Alex Grinkov: - FM stereo demodulator. +Alexander Fasching: +- Bug fixes. + Andy Sloane: - Bug fixes and improvements. From 4268098879c3f13a3f5646ad6f96cce22475965e Mon Sep 17 00:00:00 2001 From: Wolfgang Fritz Date: Tue, 29 Mar 2016 09:43:03 +0200 Subject: [PATCH 024/334] 1-2-5 scaling for FFT axis Calculate FFT level and frequency axis to 1/2/5 * 10^n steps. This is done in many instruments like spectrum analyzers or oscilloscopes and makes visual interpolation easier. Signed-off-by: Wolfgang Fritz --- src/qtgui/dockaudio.cpp | 2 +- src/qtgui/plotter.cpp | 154 ++++++++++++++++++++++++++++------------ src/qtgui/plotter.h | 7 +- 3 files changed, 115 insertions(+), 48 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 71833c4..093a8bf 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -66,7 +66,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setFilterBoxEnabled(false); ui->audioSpectrum->setCenterLineEnabled(false); ui->audioSpectrum->setMinMaxDB(-110, -20); - ui->audioSpectrum->setVdivDelta(30); + ui->audioSpectrum->setVdivDelta(20); ui->audioSpectrum->setHdivDelta(40); ui->audioSpectrum->setFreqDigits(1); } diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index 153b17f..d97baed 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -172,7 +172,6 @@ CPlotter::CPlotter(QWidget *parent) : m_VerDivs = 6; m_MaxdB = 0; m_MindB = -115; - m_dBStepSize = std::abs(m_MaxdB-m_MindB)/m_VerDivs; m_FreqUnits = 1000000; m_CursorCaptured = NOCAP; @@ -184,8 +183,8 @@ CPlotter::CPlotter(QWidget *parent) : m_Size = QSize(0,0); m_GrabPosition = 0; m_Percent2DScreen = 30; //percent of screen used for 2D display - m_VdivDelta = 40; - m_HdivDelta = 80; + m_VdivDelta = 30; + m_HdivDelta = 70; m_FreqDigits = 3; @@ -1277,16 +1276,13 @@ void CPlotter::drawOverlay() int h = m_OverlayPixmap.height(); int x,y; float pixperdiv; + float adjoffset; + float dbstepsize; + float mindbadj; QRect rect; QPainter painter(&m_OverlayPixmap); painter.initFrom(this); - // horizontal grids (size and grid calcs could be moved to resize) - m_VerDivs = h/m_VdivDelta+1; - m_HorDivs = qMin(w/m_HdivDelta, HORZ_DIVS_MAX); - if (m_HorDivs % 2) - m_HorDivs++; // we want an odd number of divs so that we have a center line - //m_OverlayPixmap.fill(Qt::black); // fill background with gradient QLinearGradient gradient(0, 0, 0 ,h); @@ -1319,15 +1315,11 @@ void CPlotter::drawOverlay() QFontMetrics metrics(m_Font); painter.setFont(m_Font); - // draw vertical grids - pixperdiv = (float)w / (float)m_HorDivs; - y = h - h/m_VerDivs/2; - painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0x30), 1, Qt::DotLine)); - for (int i = 1; i < m_HorDivs; i++) - { - x = (int)((float)i*pixperdiv); - painter.drawLine(x, 0, x, y); - } + // X and Y axis areas + m_YAxisWidth = metrics.width("-120 "); + m_XAxisYCenter = h - metrics.height()/2; + int xAxisHeight = metrics.height() ;// + metrics.height()/2; + int xAxisTop = h - xAxisHeight; //Draw Bookmark Tags m_BookmarkTags.clear(); @@ -1358,7 +1350,7 @@ void CPlotter::drawOverlay() color.setAlpha(0x60); painter.setPen(QPen(color, 1, Qt::DashLine)); - painter.drawLine(x, level*levelHeight+fontHeight+slant, x, y); //Vertical line + painter.drawLine(x, level*levelHeight+fontHeight+slant, x, xAxisTop); //Vertical line painter.setPen(QPen(color, 1, Qt::SolidLine)); painter.drawLine(x+slant, level*levelHeight+fontHeight, x+nameWidth+slant-1, level*levelHeight+fontHeight); //Horizontal line @@ -1388,42 +1380,79 @@ void CPlotter::drawOverlay() if (x > 0 && x < w) { painter.setPen(QPen(QColor(0x78,0x82,0x96,0xFF), 1, Qt::SolidLine)); - painter.drawLine(x, 0, x, y); + painter.drawLine(x, 0, x, xAxisTop); + } + } + + // Frequency grid + qint64 StartFreq = m_CenterFreq + m_FftCenter - m_Span/2; + QString label; + label.setNum(float((StartFreq + m_Span) / m_FreqUnits),'f', m_FreqDigits); + calcDivSize (StartFreq, StartFreq + m_Span, qMin(w/(metrics.width(label)+metrics.width("O")), HORZ_DIVS_MAX), m_StartFreqAdj, m_FreqPerDiv, m_HorDivs); + pixperdiv = (float)w * (float) m_FreqPerDiv / (float) m_Span; + adjoffset = pixperdiv * float (m_StartFreqAdj - StartFreq) / (float) m_FreqPerDiv; + + painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0x30), 1, Qt::DotLine)); + for (int i = 0; i <= m_HorDivs; i++) + { + x = (int)((float)i*pixperdiv + adjoffset); + if (x > m_YAxisWidth) + { + painter.drawLine(x, 0, x, xAxisTop); } } - // draw frequency values + // draw frequency values (x axis) makeFrequencyStrs(); painter.setPen(QColor(0xD8,0xBA,0xA1,0xFF)); - y = h - (h/m_VerDivs); - m_XAxisYCenter = h - metrics.height()/2; - for (int i = 1; i < m_HorDivs; i++) + + for (int i = 0; i <= m_HorDivs; i++) { - x = (int)((float)i*pixperdiv - pixperdiv/2); - rect.setRect(x, y, (int)pixperdiv, h/m_VerDivs); - painter.drawText(rect, Qt::AlignHCenter|Qt::AlignBottom, m_HDivText[i]); + int tw = metrics.width(m_HDivText[i]); + x = (int)((float)i*pixperdiv + adjoffset); + if (x > m_YAxisWidth) + { + rect.setRect(x - tw/2, xAxisTop, tw, metrics.height()); + painter.drawText(rect, Qt::AlignHCenter|Qt::AlignBottom, m_HDivText[i]); + } } - m_dBStepSize = fabs(m_MaxdB - m_MindB)/(float)m_VerDivs; - pixperdiv = (float)h / (float)m_VerDivs; + // Level grid + qint64 mindBAdj64 = 0; + qint64 dbDivSize = 0; + + calcDivSize ((qint64) m_MindB, (qint64) m_MaxdB, qMax(h/m_VdivDelta, VERT_DIVS_MIN), mindBAdj64, dbDivSize, m_VerDivs); + + dbstepsize = (float) dbDivSize; + mindbadj = mindBAdj64; + + pixperdiv = (float) h * (float) dbstepsize / (m_MaxdB - m_MindB); + adjoffset = (float) h * (mindbadj - m_MindB) / (m_MaxdB - m_MindB); + qDebug() << "minDb =" << m_MindB << "maxDb =" << m_MaxdB << "mindbadj =" << mindbadj + << "dbstepsize =" << dbstepsize + << "pixperdiv =" << pixperdiv << "adjoffset =" << adjoffset; painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0x30), 1,Qt::DotLine)); - for (int i = 1; i < m_VerDivs; i++) + for (int i = 0; i <= m_VerDivs; i++) { - y = (int)((float) i*pixperdiv); - painter.drawLine(5*metrics.width("0",-1), y, w, y); + y = h - (int)((float) i*pixperdiv + adjoffset); + if (y < h - xAxisHeight) + painter.drawLine(m_YAxisWidth, y, w, y); } - // draw amplitude values + // draw amplitude values (y axis) painter.setPen(QColor(0xD8,0xBA,0xA1,0xFF)); - int dB = m_MaxdB; m_YAxisWidth = metrics.width("-120 "); - for (int i = 1; i < m_VerDivs; i++) + for (int i = 0; i < m_VerDivs; i++) { - dB -= m_dBStepSize; // move to end if want to include maxdb - y = (int)((float)i*pixperdiv); - rect.setRect(0, y-metrics.height()/2, m_YAxisWidth, metrics.height()); - painter.drawText(rect, Qt::AlignRight|Qt::AlignVCenter, QString::number(dB)); + y = h - (int)((float) i*pixperdiv + adjoffset); + int th = metrics.height(); + if (y < h -xAxisHeight) + { + dB = mindbadj + dbstepsize * i; + rect.setRect(0, y-th/2, m_YAxisWidth, th); + painter.drawText(rect, Qt::AlignRight|Qt::AlignVCenter, QString::number(dB)); + } } if (!m_Running) @@ -1447,8 +1476,7 @@ void CPlotter::drawOverlay() ////////////////////////////////////////////////////////////////////// void CPlotter::makeFrequencyStrs() { - qint64 FreqPerDiv = m_Span/m_HorDivs; - qint64 StartFreq = m_CenterFreq + m_FftCenter - m_Span/2; + qint64 StartFreq = m_StartFreqAdj; float freq; int i,j; @@ -1458,7 +1486,7 @@ void CPlotter::makeFrequencyStrs() { freq = (float)StartFreq/(float)m_FreqUnits; m_HDivText[i].setNum((int)freq); - StartFreq += FreqPerDiv; + StartFreq += m_FreqPerDiv; } return; } @@ -1468,7 +1496,7 @@ void CPlotter::makeFrequencyStrs() { freq = (float)StartFreq/(float)m_FreqUnits; m_HDivText[i].setNum(freq,'f', m_FreqDigits); - StartFreq += FreqPerDiv; + StartFreq += m_FreqPerDiv; } // now find the division text with the longest non-zero digit // to the right of the decimal point. @@ -1486,12 +1514,12 @@ void CPlotter::makeFrequencyStrs() max = j-dp; } // truncate all strings to maximum fractional length - StartFreq = m_CenterFreq + m_FftCenter - m_Span/2; + StartFreq = m_StartFreqAdj; for (i = 0; i <= m_HorDivs; i++) { freq = (float)StartFreq/(float)m_FreqUnits; m_HDivText[i].setNum(freq,'f', max); - StartFreq += FreqPerDiv; + StartFreq += m_FreqPerDiv; } } @@ -1672,3 +1700,39 @@ void CPlotter::setPeakDetection(bool enabled, float c) else m_PeakDetection = c; } + +void CPlotter::calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adjlow, qint64 &step, int& divs) +{ + qDebug() << "low: " << low; + qDebug() << "high: " << high; + qDebug() << "divswanted: " << divswanted; + + if (divswanted == 0) + return; + + static const qint64 stepTable[] = { 1, 2, 5 }; + static const int stepTableSize = sizeof (stepTable) / sizeof (stepTable[0]); + qint64 multiplier = 1; + step = 1; + divs = high - low; + int index = 0; + + while (divs > divswanted) + { + step = stepTable[index] * multiplier; + divs = int ((high - low) / step); + adjlow = (low / step) * step; + index = index + 1; + if (index == stepTableSize) + { + index = 0; + multiplier = multiplier * 10; + } + } + if (adjlow < low) + adjlow += step; + + qDebug() << "adjlow: " << adjlow; + qDebug() << "step: " << step; + qDebug() << "divs: " << divs; +} diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index d1be4e4..e80a803 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -10,6 +10,7 @@ #include #define HORZ_DIVS_MAX 50 //12 +#define VERT_DIVS_MIN 5 #define MAX_SCREENSIZE 16384 #define PEAK_CLICK_MAX_H_DISTANCE 10 //Maximum horizontal distance of clicked point from peak @@ -179,6 +180,7 @@ public slots: qint64 startFreq, qint64 stopFreq, float *inBuf, qint32 *outBuf, qint32 *maxbin, qint32 *minbin); + void calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adjlow, qint64 &step, int& divs); bool m_PeakHoldActive; bool m_PeakHoldValid; @@ -205,6 +207,8 @@ public slots: qint64 m_CenterFreq; qint64 m_FftCenter; qint64 m_DemodCenterFreq; + qint64 m_StartFreqAdj; + qint64 m_FreqPerDiv; bool m_CenterLineEnabled; /*!< Distinguish center line. */ bool m_FilterBoxEnabled; /*!< Draw filter box. */ bool m_TooltipsEnabled; /*!< Tooltips enabled */ @@ -227,8 +231,7 @@ public slots: int m_VerDivs; /*!< Current number of vertical divisions. Calculated from height. */ float m_MaxdB; float m_MindB; - qint32 m_dBStepSize; - qint32 m_Span; + qint64 m_Span; float m_SampleFreq; /*!< Sample rate. */ qint32 m_FreqUnits; int m_ClickResolution; From 0df0c737b6be4e24158cf0a1b82e8449835784d3 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 4 Jul 2016 22:26:28 +0200 Subject: [PATCH 025/334] Update news and readme. --- README.md | 1 + resources/news.txt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 008a8a7..84d62ed 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,7 @@ Will Scales Wolfgang Fritz DK7OB - SDRPlay integration. +- 1-2-5 scaling on FFT plot. - Various UI improvements. diff --git a/resources/news.txt b/resources/news.txt index cfed8a5..8aa9cdb 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -3,7 +3,8 @@ FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. IMPROVED: SDRPlay integration. - IMPROVED: Only probe for devices when the program is satarted. + IMPROVED: Only probe for devices when the program is started. + IMPROVED: 1-2-5 scaling on FFT axis. 2.5.3: Released February 3, 2016. From 0d3639ea7779c5b73f1dc9b421f9dbb6561164d7 Mon Sep 17 00:00:00 2001 From: Valentin Ochs Date: Tue, 5 Jul 2016 17:41:04 +0200 Subject: [PATCH 026/334] [alsa-devices] Let ALSA users pick a sound card --- src/qtgui/ioconfig.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 97eae13..f793420 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -153,6 +153,8 @@ CIoConfig::CIoConfig(QSettings *settings, std::map &devList, } #else + ui->outDevCombo->addItem(settings->value("output/device", "Default").toString(), + settings->value("output/device", "Default").toString()); ui->outDevCombo->setEditable(true); #endif // WITH_PULSEAUDIO @@ -254,12 +256,20 @@ void CIoConfig::saveConfig() idx = ui->outDevCombo->currentIndex(); - if (idx > 0) + if (idx > 0 + #if !defined(WITH_PULSEAUDIO) && !defined(GQRX_OS_MACX) + || ui->outDevCombo->currentText() != "Default" + #endif + ) { #if defined(WITH_PULSEAUDIO) || defined(GQRX_OS_MACX) qDebug() << "Output device" << idx << ":" << QString(outDevList[idx-1].get_name().c_str()); m_settings->setValue("output/device", QString(outDevList[idx-1].get_name().c_str())); +#else + qDebug() << "Output device:" << ui->outDevCombo->currentText(); + m_settings->setValue("output/device", ui->outDevCombo->currentText()); #endif + } else { From 42a3bf425f5f7469a70c75905e2e8db7df5ae8c0 Mon Sep 17 00:00:00 2001 From: Valentin Ochs Date: Tue, 5 Jul 2016 22:20:59 +0200 Subject: [PATCH 027/334] [alsa-devices] Remove ifdef from expression that checks if a non-default output device is selected --- src/qtgui/ioconfig.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index f793420..5eb1eba 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -256,21 +256,19 @@ void CIoConfig::saveConfig() idx = ui->outDevCombo->currentIndex(); - if (idx > 0 - #if !defined(WITH_PULSEAUDIO) && !defined(GQRX_OS_MACX) - || ui->outDevCombo->currentText() != "Default" - #endif - ) - { #if defined(WITH_PULSEAUDIO) || defined(GQRX_OS_MACX) - qDebug() << "Output device" << idx << ":" << QString(outDevList[idx-1].get_name().c_str()); - m_settings->setValue("output/device", QString(outDevList[idx-1].get_name().c_str())); + if (idx > 0) + { + qDebug() << "Output device" << idx << ":" << QString(outDevList[idx-1].get_name().c_str()); + m_settings->setValue("output/device", QString(outDevList[idx-1].get_name().c_str())); + } #else + if (idx > 0 || ui->outDevCombo->currentText() != "Default") + { qDebug() << "Output device:" << ui->outDevCombo->currentText(); m_settings->setValue("output/device", ui->outDevCombo->currentText()); -#endif - } +#endif else { m_settings->remove("output/device"); From f34b161c3759218f6e28712197ce87fcd7b12742 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 5 Jul 2016 23:15:52 +0200 Subject: [PATCH 028/334] Disable plotter debug messages by default. Enable it with PLOTTER_DEBUG. --- src/qtgui/plotter.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index d97baed..4718648 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -64,6 +64,9 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) #include "plotter.h" #include "bookmarks.h" +// Comment out to enable plotter debug messages +//#define PLOTTER_DEBUG + ////////////////////////////////////////////////////////////////////// // Local defines ////////////////////////////////////////////////////////////////////// @@ -1428,9 +1431,11 @@ void CPlotter::drawOverlay() pixperdiv = (float) h * (float) dbstepsize / (m_MaxdB - m_MindB); adjoffset = (float) h * (mindbadj - m_MindB) / (m_MaxdB - m_MindB); +#ifdef PLOTTER_DEBUG qDebug() << "minDb =" << m_MindB << "maxDb =" << m_MaxdB << "mindbadj =" << mindbadj << "dbstepsize =" << dbstepsize << "pixperdiv =" << pixperdiv << "adjoffset =" << adjoffset; +#endif painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0x30), 1,Qt::DotLine)); for (int i = 0; i <= m_VerDivs; i++) { @@ -1703,9 +1708,11 @@ void CPlotter::setPeakDetection(bool enabled, float c) void CPlotter::calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adjlow, qint64 &step, int& divs) { +#ifdef PLOTTER_DEBUG qDebug() << "low: " << low; qDebug() << "high: " << high; qDebug() << "divswanted: " << divswanted; +#endif if (divswanted == 0) return; @@ -1732,7 +1739,9 @@ void CPlotter::calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adj if (adjlow < low) adjlow += step; +#ifdef PLOTTER_DEBUG qDebug() << "adjlow: " << adjlow; qDebug() << "step: " << step; qDebug() << "divs: " << divs; +#endif } From 4026c6f2cf8c20e99dbf1d1758853b84f48b38c1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 5 Jul 2016 23:39:12 +0200 Subject: [PATCH 029/334] Add 3 and 6 Msps option for Airspy. --- src/qtgui/ioconfig.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 5eb1eba..a147b7c 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -489,6 +489,8 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->addItem(QString("%1").arg(rate)); ui->inSrCombo->addItem("2500000"); + ui->inSrCombo->addItem("3000000"); + ui->inSrCombo->addItem("6000000"); ui->inSrCombo->addItem("10000000"); } else if (ui->inDevEdit->text().contains("redpitaya")) From 78e6cd62ba676c7853f01089146b1435e4485fe0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 5 Jul 2016 23:44:21 +0200 Subject: [PATCH 030/334] Update news and readme file. --- README.md | 3 +++ resources/news.txt | 1 + 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 84d62ed..638a472 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,9 @@ Timothy Reaves: - UI layout fixes for Mac. - cmake build files +Valentin Ochs: +- ALSA support improvement. + Vesa Solonen: - DC removal in AM demodulator. diff --git a/resources/news.txt b/resources/news.txt index 8aa9cdb..560effe 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -5,6 +5,7 @@ IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. IMPROVED: 1-2-5 scaling on FFT axis. + IMPROVED: Allow user to enter ALSA device name. 2.5.3: Released February 3, 2016. From 451554eec0adbc4d146c474b1d6a2743dc147835 Mon Sep 17 00:00:00 2001 From: Valentin Ochs Date: Wed, 6 Jul 2016 00:26:43 +0200 Subject: [PATCH 031/334] [fix-iq-bandwidth] Get input rate from the input device after setting a new device. Fixes issue #389 --- src/applications/gqrx/receiver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 84149ee..7e29410 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -226,6 +226,7 @@ void receiver::set_input_device(const std::string device) src.reset(); src = osmosdr::source::make(device); + set_input_rate(src->get_sample_rate()); if (d_decim >= 2) { From 1111c4542d37332e282e065eb7eb52cd64573a7b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 8 Jul 2016 23:27:00 +0200 Subject: [PATCH 032/334] Update readme. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 638a472..485ade9 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,7 @@ Timothy Reaves: Valentin Ochs: - ALSA support improvement. +- Various bugfixes. Vesa Solonen: - DC removal in AM demodulator. From 86439028f6b1593d6247a0e9fbf4bc5bfee656d3 Mon Sep 17 00:00:00 2001 From: Valentin Ochs Date: Wed, 6 Jul 2016 13:33:45 +0200 Subject: [PATCH 033/334] Draw correct frequencies between -1 and 0 kHz. --- src/qtgui/freqctrl.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index cbf1403..b28259d 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -261,10 +261,17 @@ void CFreqCtrl::setFrequency(qint64 freq) m_LeadZeroPos = i; } } + + // If the sign changed and the frequency is less than 1 unit, + // redraw the leading zero to get the correct sign. + if(m_Oldfreq ^ m_freq < 0 && m_DigitInfo[m_LeadZeroPos-1].val == 0) + m_DigitInfo[m_LeadZeroPos-1].modified = true; + // When frequency is negative all non-zero digits that // have changed will have a negative sign. This loop will // change all digits back to positive, except the one at - // position m_leadZeroPos-1 + // position m_leadZeroPos-1. If that position is zero, + // it will be checked in the drawing method, drawDigits(). /** TBC if this works for all configurations */ if (m_freq < 0) { @@ -707,8 +714,12 @@ void CFreqCtrl::drawDigits(QPainter &Painter) else Painter.setPen(m_DigitColor); - Painter.drawText(m_DigitInfo[i].dQRect, Qt::AlignHCenter|Qt::AlignVCenter, - QString().number(m_DigitInfo[i].val)); + if (m_freq < 0 && i == m_LeadZeroPos - 1 && m_DigitInfo[i].val == 0) + Painter.drawText(m_DigitInfo[i].dQRect, Qt::AlignHCenter|Qt::AlignVCenter, + QString("-0")); + else + Painter.drawText(m_DigitInfo[i].dQRect, Qt::AlignHCenter|Qt::AlignVCenter, + QString().number(m_DigitInfo[i].val)); m_DigitInfo[i].modified = false; } } From a452af86e1e9238125ccfc5304eddeafe213cdcd Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 9 Jul 2016 00:39:43 +0200 Subject: [PATCH 034/334] Fix compiler warning. --- src/qtgui/freqctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index b28259d..d6cd4a6 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -264,8 +264,8 @@ void CFreqCtrl::setFrequency(qint64 freq) // If the sign changed and the frequency is less than 1 unit, // redraw the leading zero to get the correct sign. - if(m_Oldfreq ^ m_freq < 0 && m_DigitInfo[m_LeadZeroPos-1].val == 0) - m_DigitInfo[m_LeadZeroPos-1].modified = true; + if ((m_Oldfreq ^ m_freq) < 0 && m_DigitInfo[m_LeadZeroPos - 1].val == 0) + m_DigitInfo[m_LeadZeroPos - 1].modified = true; // When frequency is negative all non-zero digits that // have changed will have a negative sign. This loop will From bf2f5f84b61cb5b0db1240f73c43d97ce626f5b7 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 10 Jul 2016 22:28:40 +0200 Subject: [PATCH 035/334] Update news.txt --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 560effe..1fd82f8 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,6 +2,7 @@ FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. + FIXED: Correct display of negative offsets between -1 and 0 kHz IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. IMPROVED: 1-2-5 scaling on FFT axis. From b89371c3ba20dbab07e9a64df810ee16fde4f983 Mon Sep 17 00:00:00 2001 From: Valentin Ochs Date: Tue, 12 Jul 2016 09:30:35 +0200 Subject: [PATCH 036/334] [fix/samplerate] Don't set rate if input reports 0 --- src/applications/gqrx/receiver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 7e29410..c5d254f 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -226,7 +226,8 @@ void receiver::set_input_device(const std::string device) src.reset(); src = osmosdr::source::make(device); - set_input_rate(src->get_sample_rate()); + if(src->get_sample_rate() != 0) + set_input_rate(src->get_sample_rate()); if (d_decim >= 2) { From 252088a74edea983d7297c8ff360fc000073fcf5 Mon Sep 17 00:00:00 2001 From: Tasnad Kernetzky Date: Thu, 21 Jul 2016 18:23:02 +0200 Subject: [PATCH 037/334] converted tabs to spaces to fix compiler warning (there were only sporadic tabs) --- src/dsp/filter/decimator.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/dsp/filter/decimator.cpp b/src/dsp/filter/decimator.cpp index c491c43..683ae4e 100644 --- a/src/dsp/filter/decimator.cpp +++ b/src/dsp/filter/decimator.cpp @@ -73,7 +73,7 @@ int Decimator::process(int samples, gr_complex * pin, gr_complex * pout) while (filter_table[i]) n = filter_table[i++]->DecBy2(n, pin, pin); - for(i = 0; i < n; i++) + for(i = 0; i < n; i++) pout[i] = pin[i]; return n; @@ -84,13 +84,13 @@ void Decimator::delete_filters() int i; for(i = 0; i < MAX_STAGES; i++) - { - if (filter_table[i]) - { - delete filter_table[i]; - filter_table[i] = 0; - } - } + { + if (filter_table[i]) + { + delete filter_table[i]; + filter_table[i] = 0; + } + } } int Decimator::init_filters_70(unsigned int decimation) @@ -178,14 +178,14 @@ int Decimator::init_filters_140(unsigned int decimation) } Decimator::CHalfBandDecimateBy2::CHalfBandDecimateBy2(int len, const float * pCoef) - : m_FirLength(len), m_pCoef(pCoef) + : m_FirLength(len), m_pCoef(pCoef) { gr_complex CPXZERO(0.0,0.0); // create buffer for FIR implementation m_pHBFirBuf = new gr_complex[MAX_HALF_BAND_BUFSIZE]; for (int i = 0; i < MAX_HALF_BAND_BUFSIZE; i++) - m_pHBFirBuf[i] = CPXZERO; + m_pHBFirBuf[i] = CPXZERO; } /* @@ -306,11 +306,11 @@ int Decimator::CHalfBand11TapDecimateBy2::DecBy2(int InLength, int i; for(i = 0; i < (InLength - 11 - 6) / 2; i++) - { - *pOut++ = (H0 * pIn[0]) + (H2 * pIn[2]) + (H4 * pIn[4]) + - (H5 * pIn[5]) + (H6 * pIn[6]) + (H8 * pIn[8]) + (H10 * pIn[10]); - pIn += 2; - } + { + *pOut++ = (H0 * pIn[0]) + (H2 * pIn[2]) + (H4 * pIn[4]) + + (H5 * pIn[5]) + (H6 * pIn[6]) + (H8 * pIn[8]) + (H10 * pIn[10]); + pIn += 2; + } // copy first outputs back into output array so outbuf can be same as inbuf pOutData[0] = tmpout[0]; @@ -321,7 +321,7 @@ int Decimator::CHalfBand11TapDecimateBy2::DecBy2(int InLength, pOutData[5] = tmpout[5]; pOutData[6] = tmpout[6]; pOutData[7] = tmpout[7]; - pOutData[8] = tmpout[8]; + pOutData[8] = tmpout[8]; // copy last 10 input samples into delay buffer for next time pIn = &pInData[InLength-1]; From bef19564fcdaf4aa84455441dc49b083ed22561a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 22 Jul 2016 23:05:32 +0200 Subject: [PATCH 038/334] More space between frequency and controls. --- src/qtgui/dockrxopt.ui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index 95e81d7..6a36422 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -128,8 +128,11 @@ This is an offset from the hardware RF frequency.</p></body></htm + + 10 + - 4 + 5 From cab0622f6cfe0a64da296041f8069fc7c0d52a39 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 26 Jul 2016 22:59:40 +0200 Subject: [PATCH 039/334] Update Qt dependencies. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 485ade9..33fe86a 100644 --- a/README.md +++ b/README.md @@ -102,13 +102,13 @@ To compile gqrx from source you need the following dependencies: - HackRF Jawbreaker driver from http://greatscottgadgets.com/hackrf/ - gnuradio-osmosdr from http://cgit.osmocom.org/cgit/gr-osmosdr/ - pulseaudio (Linux only and optional) -- Qt 4.7 or later with the following components: +- Qt 4.8 or later with the following components: - Core - GUI - Network - Widgets (Qt 5 only) - Svg (runtime only) -- cmake version >= 3.2.0 if you wish to build using cmake. +- cmake version >= 3.2.0 if you wish to build using cmake. Note that cmake builds require Qt 5. To build using qmake, you can either open the gqrx.pro file in Qt Creator and build, or on the command line: From 7349eb9c1f4708dfe121be1d3adba7743e2c84c9 Mon Sep 17 00:00:00 2001 From: Wolfgang Fritz Date: Sun, 31 Jul 2016 19:18:07 +0200 Subject: [PATCH 040/334] loadconfig: Restore main window only at program start Restore the main window only at program start, not at each loadconfig(). This prevents a moved window jumping back to the old position after a change in device configuration. Signed-off-by: Wolfgang Fritz --- src/applications/gqrx/mainwindow.cpp | 19 +++++++++++-------- src/applications/gqrx/mainwindow.h | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index f3cbe80..7f0839c 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -284,7 +284,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : CIoConfig::getDeviceList(devList); // restore last session - if (!loadConfig(cfgfile, true)) + if (!loadConfig(cfgfile, true, true)) { // first time config @@ -382,7 +382,7 @@ MainWindow::~MainWindow() * * FIXME: Refactor. */ -bool MainWindow::loadConfig(const QString cfgfile, bool check_crash) +bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restore_mainwindow) { double actual_rate; qint64 int64_val; @@ -442,8 +442,11 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash) ui->mainToolBar->hide(); // main window settings - restoreGeometry(m_settings->value("gui/geometry", saveGeometry()).toByteArray()); - restoreState(m_settings->value("gui/state", saveState()).toByteArray()); + if (restore_mainwindow) + { + restoreGeometry(m_settings->value("gui/geometry", saveGeometry()).toByteArray()); + restoreState(m_settings->value("gui/state", saveState()).toByteArray()); + } QString indev = m_settings->value("input/device", "").toString(); if (!indev.isEmpty()) @@ -626,7 +629,7 @@ bool MainWindow::saveConfig(const QString cfgfile) m_settings->setValue("crashed", false); m_settings->sync(); - loadConfig(cfgfile, false); + loadConfig(cfgfile, false, false); return true; } else @@ -1730,7 +1733,7 @@ int MainWindow::on_actionIoConfig_triggered() on_actionDSP_triggered(false); storeSession(); - loadConfig(m_settings->fileName(), false); + loadConfig(m_settings->fileName(), false, false); if (ui->actionDSP->isChecked()) // restsart DSP @@ -1752,7 +1755,7 @@ int MainWindow::firstTimeConfig() int confres = ioconf->exec(); if (confres == QDialog::Accepted) - loadConfig(m_settings->fileName(), false); + loadConfig(m_settings->fileName(), false, false); delete ioconf; @@ -1776,7 +1779,7 @@ void MainWindow::on_actionLoadSettings_triggered() if (!cfgfile.endsWith(".conf", Qt::CaseSensitive)) cfgfile.append(".conf"); - loadConfig(cfgfile, cfgfile != m_settings->fileName()); + loadConfig(cfgfile, cfgfile != m_settings->fileName(), cfgfile != m_settings->fileName()); // store last dir QFileInfo fi(cfgfile); diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index 2160777..04b7a66 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -60,7 +60,7 @@ class MainWindow : public QMainWindow explicit MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent = 0); ~MainWindow(); - bool loadConfig(const QString cfgfile, bool check_crash); + bool loadConfig(const QString cfgfile, bool check_crash, bool restore_mainwindow); bool saveConfig(const QString cfgfile); void storeSession(); From 42a6ec6d41680cc9bae0f980688c091f439acaf7 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 7 Aug 2016 00:34:45 +0200 Subject: [PATCH 041/334] Add option to disable painrting bookmarks on spectrum. Fixes issue #399. --- src/qtgui/dockaudio.cpp | 1 + src/qtgui/plotter.cpp | 91 ++++++++++++++++++++--------------------- src/qtgui/plotter.h | 2 + 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 093a8bf..1ce9b6e 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -65,6 +65,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setDemodCenterFreq(0); ui->audioSpectrum->setFilterBoxEnabled(false); ui->audioSpectrum->setCenterLineEnabled(false); + ui->audioSpectrum->setBookmarksEnabled(false); ui->audioSpectrum->setMinMaxDB(-110, -20); ui->audioSpectrum->setVdivDelta(20); ui->audioSpectrum->setHdivDelta(40); diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index 4718648..aaf47c9 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -167,6 +167,7 @@ CPlotter::CPlotter(QWidget *parent) : m_FilterBoxEnabled = true; m_CenterLineEnabled = true; + m_BookmarksEnabled = true; m_Span = 96000; m_SampleFreq = 96000; @@ -1324,58 +1325,54 @@ void CPlotter::drawOverlay() int xAxisHeight = metrics.height() ;// + metrics.height()/2; int xAxisTop = h - xAxisHeight; - //Draw Bookmark Tags - m_BookmarkTags.clear(); - static const QFontMetrics fm(painter.font()); - static const int fontHeight = fm.ascent()+1; // height(); - static const int slant = 5; - static const int levelHeight = fontHeight+5; - static const int nLevels = 10; - QList bookmarks = Bookmarks::Get().getBookmarksInRange(m_CenterFreq+m_FftCenter-m_Span/2, m_CenterFreq+m_FftCenter+m_Span/2); - int tagEnd[nLevels] = {0}; - for(int i=0; i bookmarks = Bookmarks::Get().getBookmarksInRange(m_CenterFreq+m_FftCenter-m_Span/2, m_CenterFreq+m_FftCenter+m_Span/2); + int tagEnd[nLevels] = {0}; + for(int i = 0; i < bookmarks.size(); i++) + { + x=xFromFreq(bookmarks[i].frequency); #if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) - int nameWidth= fm.width(bookmarks[i].name); + int nameWidth = fm.width(bookmarks[i].name); #else - int nameWidth= fm.boundingRect(bookmarks[i].name).width(); + int nameWidth = fm.boundingRect(bookmarks[i].name).width(); #endif - - int level = 0; - for(; levelx; level++); - level%=nLevels; - - tagEnd[level]=x+nameWidth+slant-1; - m_BookmarkTags.append(qMakePair(QRect(x, level*levelHeight, nameWidth+slant, fontHeight), bookmarks[i].frequency)); - - QColor color = QColor(bookmarks[i].GetColor()); - color.setAlpha(0x60); - - painter.setPen(QPen(color, 1, Qt::DashLine)); - painter.drawLine(x, level*levelHeight+fontHeight+slant, x, xAxisTop); //Vertical line - - painter.setPen(QPen(color, 1, Qt::SolidLine)); - painter.drawLine(x+slant, level*levelHeight+fontHeight, x+nameWidth+slant-1, level*levelHeight+fontHeight); //Horizontal line - painter.drawLine(x+1,level*levelHeight+fontHeight+slant-1, x+slant-1, level*levelHeight+fontHeight+1); //Diagonal line -/* - painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0xB0), 1, Qt::SolidLine)); - QPolygon polygon(6); - polygon.setPoint(0, 0, 10); - polygon.setPoint(1, 5, 15); - polygon.setPoint(2, 5+nameWidth, 15); - polygon.setPoint(3, 5+nameWidth, 0); - polygon.setPoint(4, 5, 0); - polygon.setPoint(5, 0, 5); - polygon.translate(x, level*18); - painter.drawPolygon(polygon); -*/ - - color.setAlpha(0xFF); - painter.setPen(QPen(color, 2, Qt::SolidLine)); - painter.drawText(x+slant,level*levelHeight, nameWidth, fontHeight, Qt::AlignVCenter | Qt::AlignHCenter, bookmarks[i].name); + int level = 0; + for (; level < nLevels && tagEnd[level] > x; level++); + level %= nLevels; + + tagEnd[level] = x + nameWidth + slant - 1; + m_BookmarkTags.append(qMakePair(QRect(x, level*levelHeight, nameWidth+slant, fontHeight), bookmarks[i].frequency)); + + QColor color = QColor(bookmarks[i].GetColor()); + color.setAlpha(0x60); + // Vertical line + painter.setPen(QPen(color, 1, Qt::DashLine)); + painter.drawLine(x, level*levelHeight+fontHeight+slant, x, xAxisTop); + + // Horizontal line + painter.setPen(QPen(color, 1, Qt::SolidLine)); + painter.drawLine(x + slant, level * levelHeight + fontHeight, + x + nameWidth + slant - 1, + level * levelHeight + fontHeight); + // Diagonal line + painter.drawLine(x + 1, level * levelHeight + fontHeight + slant - 1, + x + slant - 1, level * levelHeight + fontHeight + 1); + + color.setAlpha(0xFF); + painter.setPen(QPen(color, 2, Qt::SolidLine)); + painter.drawText(x + slant, level * levelHeight, nameWidth, + fontHeight, Qt::AlignVCenter | Qt::AlignHCenter, + bookmarks[i].name); + } } - if (m_CenterLineEnabled) { // center line diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index e80a803..5361b4f 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -37,6 +37,7 @@ class CPlotter : public QFrame void setFilterBoxEnabled(bool enabled) { m_FilterBoxEnabled = enabled; } void setCenterLineEnabled(bool enabled) { m_CenterLineEnabled = enabled; } void setTooltipsEnabled(bool enabled) { m_TooltipsEnabled = enabled; } + void setBookmarksEnabled(bool enabled) { m_BookmarksEnabled = enabled; } void setPercent2DScreen(int percent) { m_Percent2DScreen = percent; @@ -212,6 +213,7 @@ public slots: bool m_CenterLineEnabled; /*!< Distinguish center line. */ bool m_FilterBoxEnabled; /*!< Draw filter box. */ bool m_TooltipsEnabled; /*!< Tooltips enabled */ + bool m_BookmarksEnabled; /*!< Show/hide bookmarks on spectrum */ int m_DemodHiCutFreq; int m_DemodLowCutFreq; int m_DemodFreqX; //screen coordinate x position From 5f7c0177f4d8084a1700284443f3bfd05cc92678 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 7 Aug 2016 17:42:55 +0200 Subject: [PATCH 042/334] Reset frequency digits below the one being changed. --- src/qtgui/freqctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index d6cd4a6..c7c4269 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -77,7 +77,7 @@ CFreqCtrl::CFreqCtrl(QWidget *parent) : m_LastLeadZeroPos = 0; m_LRMouseFreqSel = false; m_ActiveEditDigit = -1; - m_ResetLowerDigits = false; + m_ResetLowerDigits = true; m_UnitsFont = QFont("Arial", 12, QFont::Normal); m_DigitFont = QFont("Arial", 12, QFont::Normal); From 336a11eab6416a28e5811f6adf62228cb1051bbe Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 8 Aug 2016 11:09:07 +0200 Subject: [PATCH 043/334] Update news file. --- resources/news.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 1fd82f8..e185179 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,7 +2,8 @@ FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. - FIXED: Correct display of negative offsets between -1 and 0 kHz + FIXED: Correct display of negative offsets between -1 and 0 kHz. + FIXED: Reset frequency digits below the one that is being changed. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. IMPROVED: 1-2-5 scaling on FFT axis. From 7120189177822ad8d5a07a91c46ca8f54cca6ad0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 8 Aug 2016 11:14:17 +0200 Subject: [PATCH 044/334] Set default audio FFT range to -70...0 dB. --- resources/news.txt | 3 ++- src/qtgui/dockaudio.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index e185179..0b1018e 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -8,7 +8,8 @@ IMPROVED: Only probe for devices when the program is started. IMPROVED: 1-2-5 scaling on FFT axis. IMPROVED: Allow user to enter ALSA device name. - + IMPROVED: Set default audio FFT range to -70...0 dB. + 2.5.3: Released February 3, 2016. NEW: Set and read squelch via remote control socket. diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 1ce9b6e..66775a8 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -66,7 +66,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setFilterBoxEnabled(false); ui->audioSpectrum->setCenterLineEnabled(false); ui->audioSpectrum->setBookmarksEnabled(false); - ui->audioSpectrum->setMinMaxDB(-110, -20); + ui->audioSpectrum->setMinMaxDB(-70, 0); ui->audioSpectrum->setVdivDelta(20); ui->audioSpectrum->setHdivDelta(40); ui->audioSpectrum->setFreqDigits(1); From 1e92bc625c480c16452b0299d910f79980edde42 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 8 Aug 2016 13:07:56 +0200 Subject: [PATCH 045/334] Make setPercent2DScreen() a slot. --- src/qtgui/plotter.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 5361b4f..942cc6c 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -38,12 +38,6 @@ class CPlotter : public QFrame void setCenterLineEnabled(bool enabled) { m_CenterLineEnabled = enabled; } void setTooltipsEnabled(bool enabled) { m_TooltipsEnabled = enabled; } void setBookmarksEnabled(bool enabled) { m_BookmarksEnabled = enabled; } - void setPercent2DScreen(int percent) - { - m_Percent2DScreen = percent; - m_Size = QSize(0,0); - resizeEvent(NULL); - } void setNewFttData(float *fftData, int size); void setNewFttData(float *fftData, float *wfData, int size); @@ -144,6 +138,13 @@ public slots: void setPeakDetection(bool enabled, float c); void updateOverlay(); + void setPercent2DScreen(int percent) + { + m_Percent2DScreen = percent; + m_Size = QSize(0,0); + resizeEvent(NULL); + } + protected: //re-implemented widget event handlers void paintEvent(QPaintEvent *event); From 8fa85cc6ce8a2698dda0fec9e67c3e58773f4bb6 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 8 Aug 2016 14:13:31 +0200 Subject: [PATCH 046/334] Audio FFT improvements. Enable waterfall on audio FFT (closes issue #355). Restore dB range between sessions (ref. level fixed at 0). New options tab to set FFT split and dB range using spin buttons. --- resources/news.txt | 3 ++ src/qtgui/audio_options.cpp | 31 +++++++++++++ src/qtgui/audio_options.h | 11 +++++ src/qtgui/audio_options.ui | 90 ++++++++++++++++++++++++++++++++++++- src/qtgui/dockaudio.cpp | 37 +++++++++++++-- src/qtgui/dockaudio.h | 1 + 6 files changed, 168 insertions(+), 5 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index 0b1018e..eb2a388 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,7 @@ 2.6: Released TBD + NEW: 1-2-5 scaling on FFT axis. + NEW: Audio waterfall. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. FIXED: Correct display of negative offsets between -1 and 0 kHz. @@ -9,6 +11,7 @@ IMPROVED: 1-2-5 scaling on FFT axis. IMPROVED: Allow user to enter ALSA device name. IMPROVED: Set default audio FFT range to -70...0 dB. + IMPROVED: Restore audio FFT dB scaling between sessions. 2.5.3: Released February 3, 2016. diff --git a/src/qtgui/audio_options.cpp b/src/qtgui/audio_options.cpp index 0940206..aa08812 100644 --- a/src/qtgui/audio_options.cpp +++ b/src/qtgui/audio_options.cpp @@ -90,6 +90,37 @@ void CAudioOptions::setUdpPort(int port) ui->udpPort->setValue(port); } + +void CAudioOptions::setFftSplit(int pct_2d) +{ + ui->splitSpinBox->setValue(100 - pct_2d); +} + +int CAudioOptions::getFftSplit(void) const +{ + return 100 - ui->splitSpinBox->value(); +} + +void CAudioOptions::on_splitSpinBox_valueChanged(int value) +{ + emit newFftSplit(100 - value); +} + +void CAudioOptions::setFftMin(int min_db) +{ + ui->scaleSpinBox->setValue(min_db); +} + +int CAudioOptions::getFftMin(void) const +{ + return ui->scaleSpinBox->value(); +} + +void CAudioOptions::on_scaleSpinBox_valueChanged(int value) +{ + emit newFftMin(value); +} + /** * Slot called when the recordings directory has changed either * because of user input or programmatically. diff --git a/src/qtgui/audio_options.h b/src/qtgui/audio_options.h index 489d06f..d12b861 100644 --- a/src/qtgui/audio_options.h +++ b/src/qtgui/audio_options.h @@ -47,7 +47,16 @@ class CAudioOptions : public QDialog void setUdpHost(const QString &host); void setUdpPort(int port); + void setFftSplit(int pct_2d); + int getFftSplit(void) const; + + void setFftMin(int min_db); + int getFftMin(void) const; + signals: + void newFftSplit(int pct_2d); + void newFftMin(int min_db); + /*! \brief Signal emitted when a new valid directory has been selected. */ void newRecDirSelected(const QString &dir); @@ -55,6 +64,8 @@ class CAudioOptions : public QDialog void newUdpPort(int port); private slots: + void on_splitSpinBox_valueChanged(int value); + void on_scaleSpinBox_valueChanged(int value); void on_recDirEdit_textChanged(const QString &text); void on_recDirButton_clicked(); void on_udpHost_textChanged(const QString &text); diff --git a/src/qtgui/audio_options.ui b/src/qtgui/audio_options.ui index c06f55c..b8cea7c 100644 --- a/src/qtgui/audio_options.ui +++ b/src/qtgui/audio_options.ui @@ -7,7 +7,7 @@ 0 0 350 - 144 + 170 @@ -23,6 +23,94 @@ 0 + + + FFT + + + Audio FFT settings + + + + + + Waterfall + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + % + + + 100 + + + + + + + Qt::Horizontal + + + + 166 + 20 + + + + + + + + Range + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + dB + + + -150 + + + -20 + + + -70 + + + + + + + Qt::Horizontal + + + + 166 + 20 + + + + + + Recording diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 66775a8..0852889 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -52,11 +52,12 @@ DockAudio::DockAudio(QWidget *parent) : audioOptions = new CAudioOptions(this); + connect(audioOptions, SIGNAL(newFftSplit(int)), ui->audioSpectrum, SLOT(setPercent2DScreen(int))); + connect(audioOptions, SIGNAL(newFftMin(int)), this, SLOT(setNewFftMin(int))); connect(audioOptions, SIGNAL(newRecDirSelected(QString)), this, SLOT(setNewRecDir(QString))); connect(audioOptions, SIGNAL(newUdpHost(QString)), this, SLOT(setNewUdpHost(QString))); connect(audioOptions, SIGNAL(newUdpPort(int)), this, SLOT(setNewUdpPort(int))); - ui->audioSpectrum->setPercent2DScreen(100); ui->audioSpectrum->setFreqUnits(1000); ui->audioSpectrum->setSampleRate(48000); // Full bandwidth ui->audioSpectrum->setSpanFreq(12000); @@ -276,11 +277,25 @@ void DockAudio::setAudioPlayButtonState(bool checked) void DockAudio::saveSettings(QSettings *settings) { + int ival; + if (!settings) return; settings->setValue("audio/gain", audioGain()); + ival = audioOptions->getFftSplit(); + if (ival >= 0 && ival < 100) + settings->setValue("audio/fft_split", ival); + else + settings->remove("audio/fft_split"); + + ival = audioOptions->getFftMin(); + if (ival != -70) + settings->setValue("audio/fft_min_db", ival); + else + settings->remove("audio/fft_min_db"); + if (rec_dir != QDir::homePath()) settings->setValue("audio/rec_dir", rec_dir); else @@ -299,14 +314,23 @@ void DockAudio::saveSettings(QSettings *settings) void DockAudio::readSettings(QSettings *settings) { + int ival; + bool conv_ok = false; + if (!settings) return; - bool conv_ok = false; + ival = settings->value("audio/gain", QVariant(-200)).toInt(&conv_ok); + if (conv_ok) + setAudioGain(ival); + + ival = settings->value("audio/fft_split", QVariant(100)).toInt(&conv_ok); + if (conv_ok) + audioOptions->setFftSplit(ival); - int gain = settings->value("audio/gain", QVariant(-200)).toInt(&conv_ok); + ival = settings->value("audio/fft_min_db", QVariant(-70)).toInt(&conv_ok); if (conv_ok) - setAudioGain(gain); + audioOptions->setFftMin(ival); // Location of audio recordings rec_dir = settings->value("audio/rec_dir", QDir::homePath()).toString(); @@ -322,6 +346,11 @@ void DockAudio::readSettings(QSettings *settings) audioOptions->setUdpPort(udp_port); } +void DockAudio::setNewFftMin(int min_db) +{ + ui->audioSpectrum->setMinMaxDB(min_db, 0.f); +} + /*! \brief Slot called when a new valid recording directory has been selected * in the audio conf dialog. */ diff --git a/src/qtgui/dockaudio.h b/src/qtgui/dockaudio.h index 835c961..a9cbdf1 100644 --- a/src/qtgui/dockaudio.h +++ b/src/qtgui/dockaudio.h @@ -102,6 +102,7 @@ private slots: void on_audioRecButton_clicked(bool checked); void on_audioPlayButton_clicked(bool checked); void on_audioConfButton_clicked(); + void setNewFftMin(int min_db); void setNewRecDir(const QString &dir); void setNewUdpHost(const QString &host); void setNewUdpPort(int port); From b51cbbcd3f38377580b813cfa047056a03bac4f4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 8 Aug 2016 14:46:26 +0200 Subject: [PATCH 047/334] Use u8 instead of int32 for waterfall buffer. Fixes #372. --- src/qtgui/plotter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 942cc6c..29113be 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -187,7 +187,7 @@ public slots: bool m_PeakHoldActive; bool m_PeakHoldValid; qint32 m_fftbuf[MAX_SCREENSIZE]; - qint32 m_wfbuf[MAX_SCREENSIZE]; // used for accumulating waterfall data at high time spans + quint8 m_wfbuf[MAX_SCREENSIZE]; // used for accumulating waterfall data at high time spans qint32 m_fftPeakHoldBuf[MAX_SCREENSIZE]; float *m_fftData; /*! pointer to incoming FFT data */ float *m_wfData; From ca3621d7c88a975f7d309d603ea906bf502b3a32 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 8 Aug 2016 17:07:17 +0200 Subject: [PATCH 048/334] Ensure audio FFT split is 0 by default. --- src/qtgui/dockaudio.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 0852889..d96aa08 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -62,6 +62,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setSampleRate(48000); // Full bandwidth ui->audioSpectrum->setSpanFreq(12000); ui->audioSpectrum->setCenterFreq(0); + ui->audioSpectrum->setPercent2DScreen(100); ui->audioSpectrum->setFftCenterFreq(6000); ui->audioSpectrum->setDemodCenterFreq(0); ui->audioSpectrum->setFilterBoxEnabled(false); From b39d65f0fef5fdbf5a6d157353fdef0174a98b7b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 10 Aug 2016 20:41:47 +0200 Subject: [PATCH 049/334] Let audio spectrum expand without upper limit. --- src/qtgui/dockaudio.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/dockaudio.ui b/src/qtgui/dockaudio.ui index de6768c..66b71e5 100644 --- a/src/qtgui/dockaudio.ui +++ b/src/qtgui/dockaudio.ui @@ -57,7 +57,7 @@ 16777215 - 300 + 16777215 From 0cddaca00a0ccb015d28afd3d784a32d1694c009 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 11 Aug 2016 20:37:22 +0200 Subject: [PATCH 050/334] Use default Pulseaudio buffer attributes. Fixes all audio crackling issues that I have been able to reproduce. Probably also fixes issue #378. --- src/pulseaudio/pa_sink.cc | 9 +-------- src/pulseaudio/pa_sink.h | 1 - src/pulseaudio/pa_source.cc | 9 ++------- src/pulseaudio/pa_source.h | 1 - 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/pulseaudio/pa_sink.cc b/src/pulseaudio/pa_sink.cc index 805d688..408ec4b 100644 --- a/src/pulseaudio/pa_sink.cc +++ b/src/pulseaudio/pa_sink.cc @@ -62,13 +62,6 @@ pa_sink::pa_sink(const string device_name, int audio_rate, d_ss.format = PA_SAMPLE_FLOAT32LE; d_ss.rate = audio_rate; d_ss.channels = 2; - - /* Buffer attributes tuned for low latency, see Documentation/Developer/Clients/LactencyControl */ - size_t latency = pa_usec_to_bytes(10000, &d_ss); - d_attr.maxlength = d_attr.minreq = d_attr.prebuf = (uint32_t)-1; - d_attr.fragsize = latency; - d_attr.tlength = latency; - d_pasink = pa_simple_new(NULL, d_app_name.c_str(), PA_STREAM_PLAYBACK, @@ -76,7 +69,7 @@ pa_sink::pa_sink(const string device_name, int audio_rate, d_stream_name.c_str(), &d_ss, NULL, - &d_attr, + NULL, &error); if (!d_pasink) { diff --git a/src/pulseaudio/pa_sink.h b/src/pulseaudio/pa_sink.h index 02f400d..eac4627 100644 --- a/src/pulseaudio/pa_sink.h +++ b/src/pulseaudio/pa_sink.h @@ -69,7 +69,6 @@ class pa_sink : public gr::sync_block string d_stream_name; /*! Descriptive name of the stream. */ string d_app_name; /*! Descriptive name of the applcation. */ pa_sample_spec d_ss; /*! pulseaudio sample specification. */ - pa_buffer_attr d_attr; /*! Buffer attributes. */ // FIXME // periodic flushing of audio buffer (until we have soundcard calibration) diff --git a/src/pulseaudio/pa_source.cc b/src/pulseaudio/pa_source.cc index 213fbb4..1378700 100644 --- a/src/pulseaudio/pa_source.cc +++ b/src/pulseaudio/pa_source.cc @@ -72,11 +72,6 @@ pa_source::pa_source (const string device_name, int sample_rate, int num_chan, d_ss.rate = sample_rate; d_ss.channels = num_chan; - /* Buffer attributes. Inspired by ghpsdr2-alex/softrockio */ - d_attr.maxlength = d_attr.minreq = d_attr.prebuf = (uint32_t)-1; - d_attr.fragsize = SAMPLES_PER_BUFFER*2 * sizeof(float); - d_attr.tlength = SAMPLES_PER_BUFFER*2 * sizeof(float); - d_pasrc = pa_simple_new(NULL, d_app_name.c_str(), PA_STREAM_RECORD, @@ -84,7 +79,7 @@ pa_source::pa_source (const string device_name, int sample_rate, int num_chan, d_stream_name.c_str(), &d_ss, NULL, - &d_attr, + NULL, &error); if (!d_pasrc) { @@ -118,7 +113,7 @@ void pa_source::select_device(string device_name) d_stream_name.c_str(), &d_ss, NULL, - &d_attr, + NULL, &error); if (!d_pasrc) { diff --git a/src/pulseaudio/pa_source.h b/src/pulseaudio/pa_source.h index 9663d39..8b66dae 100644 --- a/src/pulseaudio/pa_source.h +++ b/src/pulseaudio/pa_source.h @@ -62,7 +62,6 @@ class pa_source : public gr::sync_block private: pa_sample_spec d_ss; /*! Sample specification. */ - pa_buffer_attr d_attr; /*! Buffer attributes. */ string d_stream_name; /*! Descriptive name of the stream. */ string d_app_name; /*! Descriptive name of the applcation. */ pa_simple *d_pasrc; /*! The pulseaudio object. */ From 37400c0b598011fcec355af1e8d014a150ea6da8 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 11 Aug 2016 21:43:08 +0200 Subject: [PATCH 051/334] Remove auto-flushing of pulseaudio buffers. There is no idication that it has had any effect at all. --- src/pulseaudio/pa_sink.cc | 28 ++++------------------------ src/pulseaudio/pa_sink.h | 8 +------- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/pulseaudio/pa_sink.cc b/src/pulseaudio/pa_sink.cc index 408ec4b..bef73f8 100644 --- a/src/pulseaudio/pa_sink.cc +++ b/src/pulseaudio/pa_sink.cc @@ -20,15 +20,13 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#include "pa_sink.h" #include -#include -#include -//#include - #include #include #include +#include + +#include "pa_sink.h" /*! \brief Create a new pulseaudio sink object. @@ -52,9 +50,7 @@ pa_sink::pa_sink(const string device_name, int audio_rate, gr::io_signature::make (1, 2, sizeof(float)), gr::io_signature::make (0, 0, 0)), d_stream_name(stream_name), - d_app_name(app_name), - d_auto_flush(300), - d_last_flush(0) + d_app_name(app_name) { int error; @@ -89,8 +85,6 @@ pa_sink::~pa_sink() bool pa_sink::start() { - d_last_flush = gr::high_res_timer_now(); - return true; } @@ -141,20 +135,6 @@ int pa_sink::work (int noutput_items, if (noutput_items > BUFFER_SIZE/2) noutput_items = BUFFER_SIZE/2; - if (d_auto_flush > 0) - { - gr::high_res_timer_type tnow = gr::high_res_timer_now(); - if ((tnow-d_last_flush)/gr::high_res_timer_tps() > d_auto_flush) - { - pa_simple_flush(d_pasink, 0); - d_last_flush = tnow; - -#ifndef QT_NO_DEBUG_OUTPUT - fprintf(stderr, "Flushing pa_sink\n"); -#endif - } - } - if (input_items.size() == 2) { // two channels (stereo) diff --git a/src/pulseaudio/pa_sink.h b/src/pulseaudio/pa_sink.h index eac4627..b13405c 100644 --- a/src/pulseaudio/pa_sink.h +++ b/src/pulseaudio/pa_sink.h @@ -23,10 +23,9 @@ #ifndef PA_SINK_H #define PA_SINK_H -#include #include -#include #include +#include using namespace std; @@ -69,11 +68,6 @@ class pa_sink : public gr::sync_block string d_stream_name; /*! Descriptive name of the stream. */ string d_app_name; /*! Descriptive name of the applcation. */ pa_sample_spec d_ss; /*! pulseaudio sample specification. */ - - // FIXME - // periodic flushing of audio buffer (until we have soundcard calibration) - int d_auto_flush; // flush interval in seconds (negative means off) - gr::high_res_timer_type d_last_flush; }; #endif /* PA_SINK_H */ From b7b3a8d7c8fadc8917c4fedad88459919b1455f9 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 11 Aug 2016 21:55:56 +0200 Subject: [PATCH 052/334] Change audio FFT range to 80 dB. --- src/qtgui/audio_options.ui | 2 +- src/qtgui/dockaudio.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qtgui/audio_options.ui b/src/qtgui/audio_options.ui index b8cea7c..a2b5f14 100644 --- a/src/qtgui/audio_options.ui +++ b/src/qtgui/audio_options.ui @@ -92,7 +92,7 @@ -20 - -70 + -80 diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index d96aa08..f16bd06 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -68,7 +68,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setFilterBoxEnabled(false); ui->audioSpectrum->setCenterLineEnabled(false); ui->audioSpectrum->setBookmarksEnabled(false); - ui->audioSpectrum->setMinMaxDB(-70, 0); + ui->audioSpectrum->setMinMaxDB(-80, 0); ui->audioSpectrum->setVdivDelta(20); ui->audioSpectrum->setHdivDelta(40); ui->audioSpectrum->setFreqDigits(1); @@ -292,7 +292,7 @@ void DockAudio::saveSettings(QSettings *settings) settings->remove("audio/fft_split"); ival = audioOptions->getFftMin(); - if (ival != -70) + if (ival != -80) settings->setValue("audio/fft_min_db", ival); else settings->remove("audio/fft_min_db"); @@ -329,7 +329,7 @@ void DockAudio::readSettings(QSettings *settings) if (conv_ok) audioOptions->setFftSplit(ival); - ival = settings->value("audio/fft_min_db", QVariant(-70)).toInt(&conv_ok); + ival = settings->value("audio/fft_min_db", QVariant(-80)).toInt(&conv_ok); if (conv_ok) audioOptions->setFftMin(ival); From 5b1e32dfc4939889e8681e84ca0ef2e0364c7138 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 11 Aug 2016 21:56:08 +0200 Subject: [PATCH 053/334] Update news file. --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index eb2a388..d30d4eb 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,6 +2,7 @@ NEW: 1-2-5 scaling on FFT axis. NEW: Audio waterfall. + FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. FIXED: Correct display of negative offsets between -1 and 0 kHz. From 31a2289f5775e5b09d7f954ee1ece3f581050c2c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 12 Aug 2016 00:30:04 +0200 Subject: [PATCH 054/334] Tweaks to plotter theme. --- src/qtgui/dockaudio.cpp | 2 +- src/qtgui/plotter.cpp | 100 ++++++++++++++++++++-------------------- src/qtgui/plotter.h | 2 +- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index f16bd06..24276d9 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -69,7 +69,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setCenterLineEnabled(false); ui->audioSpectrum->setBookmarksEnabled(false); ui->audioSpectrum->setMinMaxDB(-80, 0); - ui->audioSpectrum->setVdivDelta(20); + ui->audioSpectrum->setVdivDelta(40); ui->audioSpectrum->setHdivDelta(40); ui->audioSpectrum->setFreqDigits(1); } diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index aaf47c9..c0aff37 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -28,10 +28,10 @@ * or implied, of Moe Wheatley. */ #include + #ifndef _MSC_VER #include #else - #include #include @@ -55,6 +55,8 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) } #endif + +#include #include #include #include @@ -78,6 +80,14 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) #define FFT_RANGE_MIN 10.f #define FFT_RANGE_MAX 200.f +// Colors of type QRgb in 0xAARRGGBB format (unsigned int) +#define PLOTTER_BGD_COLOR 0xFF1F1D1D +#define PLOTTER_GRID_COLOR 0xFF444242 +#define PLOTTER_TEXT_COLOR 0xFFDADADA +#define PLOTTER_CENTER_LINE_COLOR 0xFF788296 +#define PLOTTER_FILTER_LINE_COLOR 0xFFFF7171 +#define PLOTTER_FILTER_BOX_COLOR 0xFFA0A0A4 +// FIXME: Should cache the QColors also static inline bool val_is_out_of_range(float val, float min, float max) { @@ -1284,50 +1294,23 @@ void CPlotter::drawOverlay() float dbstepsize; float mindbadj; QRect rect; + QFontMetrics metrics(m_Font); QPainter painter(&m_OverlayPixmap); painter.initFrom(this); - - //m_OverlayPixmap.fill(Qt::black); - // fill background with gradient - QLinearGradient gradient(0, 0, 0 ,h); - gradient.setColorAt(0, QColor(0x2F,0x2F,0x2F,0xFF)); - gradient.setColorAt(1, QColor(0x00,0x00,0x00,0xFF)); - painter.setBrush(gradient); - painter.drawRect(0, 0, w, h); - - // Draw demod filter box - if (m_FilterBoxEnabled) - { - // Clamping no longer necessary as we do it in mouseMove() - //ClampDemodParameters(); - - m_DemodFreqX = xFromFreq(m_DemodCenterFreq); - m_DemodLowCutFreqX = xFromFreq(m_DemodCenterFreq + m_DemodLowCutFreq); - m_DemodHiCutFreqX = xFromFreq(m_DemodCenterFreq + m_DemodHiCutFreq); - - int dw = m_DemodHiCutFreqX - m_DemodLowCutFreqX; - - painter.setBrush(Qt::SolidPattern); - painter.setOpacity(0.3); - painter.fillRect(m_DemodLowCutFreqX, 0, dw, h, Qt::gray); - - painter.setOpacity(1.0); - painter.setPen(QPen(QColor(0xFF,0x71,0x71,0xFF), 1, Qt::SolidLine)); - painter.drawLine(m_DemodFreqX, 0, m_DemodFreqX, h); - } - - QFontMetrics metrics(m_Font); painter.setFont(m_Font); + // solid background + painter.setBrush(Qt::SolidPattern); + painter.fillRect(0, 0, w, h, QColor(PLOTTER_BGD_COLOR)); + // X and Y axis areas m_YAxisWidth = metrics.width("-120 "); m_XAxisYCenter = h - metrics.height()/2; - int xAxisHeight = metrics.height() ;// + metrics.height()/2; + int xAxisHeight = metrics.height(); int xAxisTop = h - xAxisHeight; if (m_BookmarksEnabled) { - // Draw Bookmark Tags m_BookmarkTags.clear(); static const QFontMetrics fm(painter.font()); static const int fontHeight = fm.ascent() + 1; @@ -1373,39 +1356,38 @@ void CPlotter::drawOverlay() bookmarks[i].name); } } + if (m_CenterLineEnabled) { - // center line x = xFromFreq(m_CenterFreq); if (x > 0 && x < w) { - painter.setPen(QPen(QColor(0x78,0x82,0x96,0xFF), 1, Qt::SolidLine)); + painter.setPen(QColor(PLOTTER_CENTER_LINE_COLOR)); painter.drawLine(x, 0, x, xAxisTop); } } // Frequency grid - qint64 StartFreq = m_CenterFreq + m_FftCenter - m_Span/2; + qint64 StartFreq = m_CenterFreq + m_FftCenter - m_Span / 2; QString label; - label.setNum(float((StartFreq + m_Span) / m_FreqUnits),'f', m_FreqDigits); - calcDivSize (StartFreq, StartFreq + m_Span, qMin(w/(metrics.width(label)+metrics.width("O")), HORZ_DIVS_MAX), m_StartFreqAdj, m_FreqPerDiv, m_HorDivs); + label.setNum(float((StartFreq + m_Span) / m_FreqUnits), 'f', m_FreqDigits); + calcDivSize(StartFreq, StartFreq + m_Span, + qMin(w/(metrics.width(label) + metrics.width("O")), HORZ_DIVS_MAX), + m_StartFreqAdj, m_FreqPerDiv, m_HorDivs); pixperdiv = (float)w * (float) m_FreqPerDiv / (float) m_Span; adjoffset = pixperdiv * float (m_StartFreqAdj - StartFreq) / (float) m_FreqPerDiv; - painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0x30), 1, Qt::DotLine)); + painter.setPen(QColor(PLOTTER_GRID_COLOR)); for (int i = 0; i <= m_HorDivs; i++) { - x = (int)((float)i*pixperdiv + adjoffset); + x = (int)((float)i * pixperdiv + adjoffset); if (x > m_YAxisWidth) - { painter.drawLine(x, 0, x, xAxisTop); - } } // draw frequency values (x axis) makeFrequencyStrs(); - painter.setPen(QColor(0xD8,0xBA,0xA1,0xFF)); - + painter.setPen(QColor(PLOTTER_TEXT_COLOR)); for (int i = 0; i <= m_HorDivs; i++) { int tw = metrics.width(m_HDivText[i]); @@ -1428,12 +1410,14 @@ void CPlotter::drawOverlay() pixperdiv = (float) h * (float) dbstepsize / (m_MaxdB - m_MindB); adjoffset = (float) h * (mindbadj - m_MindB) / (m_MaxdB - m_MindB); + #ifdef PLOTTER_DEBUG qDebug() << "minDb =" << m_MindB << "maxDb =" << m_MaxdB << "mindbadj =" << mindbadj << "dbstepsize =" << dbstepsize << "pixperdiv =" << pixperdiv << "adjoffset =" << adjoffset; #endif - painter.setPen(QPen(QColor(0xF0,0xF0,0xF0,0x30), 1,Qt::DotLine)); + + painter.setPen(QColor(PLOTTER_GRID_COLOR)); for (int i = 0; i <= m_VerDivs; i++) { y = h - (int)((float) i*pixperdiv + adjoffset); @@ -1442,21 +1426,39 @@ void CPlotter::drawOverlay() } // draw amplitude values (y axis) - painter.setPen(QColor(0xD8,0xBA,0xA1,0xFF)); int dB = m_MaxdB; m_YAxisWidth = metrics.width("-120 "); + painter.setPen(QColor(PLOTTER_TEXT_COLOR)); for (int i = 0; i < m_VerDivs; i++) { - y = h - (int)((float) i*pixperdiv + adjoffset); + y = h - (int)((float) i * pixperdiv + adjoffset); int th = metrics.height(); if (y < h -xAxisHeight) { dB = mindbadj + dbstepsize * i; - rect.setRect(0, y-th/2, m_YAxisWidth, th); + rect.setRect(0, y - th / 2, m_YAxisWidth, th); painter.drawText(rect, Qt::AlignRight|Qt::AlignVCenter, QString::number(dB)); } } + // Draw demod filter box + if (m_FilterBoxEnabled) + { + m_DemodFreqX = xFromFreq(m_DemodCenterFreq); + m_DemodLowCutFreqX = xFromFreq(m_DemodCenterFreq + m_DemodLowCutFreq); + m_DemodHiCutFreqX = xFromFreq(m_DemodCenterFreq + m_DemodHiCutFreq); + + int dw = m_DemodHiCutFreqX - m_DemodLowCutFreqX; + + painter.setOpacity(0.3); + painter.fillRect(m_DemodLowCutFreqX, 0, dw, h, + QColor(PLOTTER_FILTER_BOX_COLOR)); + + painter.setOpacity(1.0); + painter.setPen(QColor(PLOTTER_FILTER_LINE_COLOR)); + painter.drawLine(m_DemodFreqX, 0, m_DemodFreqX, h); + } + if (!m_Running) { // if not running so is no data updates to draw to screen diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 29113be..1a9c082 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -9,7 +9,7 @@ #include #include -#define HORZ_DIVS_MAX 50 //12 +#define HORZ_DIVS_MAX 12 //50 #define VERT_DIVS_MIN 5 #define MAX_SCREENSIZE 16384 From 44f61bece9350a9d5471ba88e1eecdf65d24a56b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 12 Aug 2016 23:29:14 +0200 Subject: [PATCH 055/334] Switch back to dotted lines on plotter. --- src/qtgui/plotter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index c0aff37..cb3af5e 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -1377,7 +1377,7 @@ void CPlotter::drawOverlay() pixperdiv = (float)w * (float) m_FreqPerDiv / (float) m_Span; adjoffset = pixperdiv * float (m_StartFreqAdj - StartFreq) / (float) m_FreqPerDiv; - painter.setPen(QColor(PLOTTER_GRID_COLOR)); + painter.setPen(QPen(QColor(PLOTTER_GRID_COLOR), 1, Qt::DotLine)); for (int i = 0; i <= m_HorDivs; i++) { x = (int)((float)i * pixperdiv + adjoffset); @@ -1417,7 +1417,7 @@ void CPlotter::drawOverlay() << "pixperdiv =" << pixperdiv << "adjoffset =" << adjoffset; #endif - painter.setPen(QColor(PLOTTER_GRID_COLOR)); + painter.setPen(QPen(QColor(PLOTTER_GRID_COLOR), 1, Qt::DotLine)); for (int i = 0; i <= m_VerDivs; i++) { y = h - (int)((float) i*pixperdiv + adjoffset); From e55b056900ac999264c791922adebfd7dcc711ad Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 13 Aug 2016 00:06:17 +0200 Subject: [PATCH 056/334] Use solid fill instead of gradient. --- src/qtgui/plotter.cpp | 11 +++-------- src/qtgui/plotter.h | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index cb3af5e..a356dc1 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -1025,10 +1025,7 @@ void CPlotter::draw() if (m_FftFill) { - QLinearGradient linGrad(QPointF(xmin, h), QPointF(xmin, 0)); - linGrad.setColorAt(0.0, m_FftCol0); - linGrad.setColorAt(1.0, m_FftCol1); - painter2.setBrush(QBrush(QGradient(linGrad))); + painter2.setBrush(QBrush(m_FftFillCol, Qt::SolidPattern)); if (n < MAX_SCREENSIZE-2) { LineBuf[n].setX(xmax-1); @@ -1670,10 +1667,8 @@ void CPlotter::moveToDemodFreq(void) void CPlotter::setFftPlotColor(const QColor color) { m_FftColor = color; - m_FftCol0 = color; - m_FftCol0.setAlpha(0x00); - m_FftCol1 = color; - m_FftCol1.setAlpha(0xA0); + m_FftFillCol = color; + m_FftFillCol.setAlpha(0x1A); m_PeakHoldColor = color; m_PeakHoldColor.setAlpha(60); } diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 1a9c082..03a6fa5 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -250,7 +250,7 @@ public slots: quint32 m_LastSampleRate; - QColor m_FftColor, m_FftCol0, m_FftCol1, m_PeakHoldColor; + QColor m_FftColor, m_FftFillCol, m_PeakHoldColor; bool m_FftFill; float m_PeakDetection; From a64cc6b8d2b0202cdeea6644955f5232cafe5036 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 13 Aug 2016 23:59:34 +0200 Subject: [PATCH 057/334] Adjust frequency controller colors. --- src/qtgui/freqctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index c7c4269..980f2d1 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -67,8 +67,8 @@ CFreqCtrl::CFreqCtrl(QWidget *parent) : setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); - m_BkColor = QColor(0x20,0x20,0x20,0xFF); - m_DigitColor = QColor(0xFF, 0xE6, 0xC8, 0xFF); + m_BkColor = QColor(0x1F, 0x1D, 0x1D, 0xFF); + m_DigitColor = QColor(0xFF, 0xFF, 0xFF, 0xFF); m_HighlightColor = QColor(0x5A, 0x5A, 0x5A, 0xFF); m_UnitsColor = Qt::gray; m_freq = 146123456; From de8a794d10ed226eb6c6a66cac9f7f1f3fa508c9 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 14 Aug 2016 00:18:08 +0200 Subject: [PATCH 058/334] Indent and cleanup. --- src/qtgui/meter.cpp | 190 +++++++++++++++++--------------------------- src/qtgui/meter.h | 159 ++++++++++++++++++------------------ 2 files changed, 154 insertions(+), 195 deletions(-) diff --git a/src/qtgui/meter.cpp b/src/qtgui/meter.cpp index f5249c3..e9c82b6 100644 --- a/src/qtgui/meter.cpp +++ b/src/qtgui/meter.cpp @@ -1,48 +1,49 @@ /* -*- c++ -*- */ /* + + + This Software is released under the "Simplified BSD License" + + + + * * Copyright 2010 Moe Wheatley. All rights reserved. * Copyright 2011-2013 Alexandru Csete OZ9AEC. * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Moe Wheatley OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of Moe Wheatley. + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Moe Wheatley. */ + #include #include #include "meter.h" - -//ratio to total control width or height -#define CTRL_MARGIN 0.07 //left/right margin -#define CTRL_MAJOR_START 0.3 //top of major tic line -#define CTRL_MINOR_START 0.3 //top of minor tic line -#define CTRL_XAXIS_HEGHT 0.4 //vert position of horizontal axis -#define CTRL_NEEDLE_TOP 0.4 //vert position of top of needle triangle +// ratio to total control width or height +#define CTRL_MARGIN 0.07 // left/right margin +#define CTRL_MAJOR_START 0.3 // top of major tic line +#define CTRL_MINOR_START 0.3 // top of minor tic line +#define CTRL_XAXIS_HEGHT 0.4 // vertical position of horizontal axis +#define CTRL_NEEDLE_TOP 0.4 // vertical position of top of needle triangle #define MIN_DB -100.0 #define MAX_DB +0.0 - CMeter::CMeter(QWidget *parent) : QFrame(parent) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -64,12 +65,8 @@ CMeter::CMeter(QWidget *parent) : QFrame(parent) CMeter::~CMeter() { - } -////////////////////////////////////////////////////////////////////// -// Sizing interface -////////////////////////////////////////////////////////////////////// QSize CMeter::minimumSizeHint() const { return QSize(20, 10); @@ -80,16 +77,14 @@ QSize CMeter::sizeHint() const return QSize(100, 30); } - -////////////////////////////////////////////////////////////////////// -// Called when screen size changes so must recalculate bitmaps -////////////////////////////////////////////////////////////////////// void CMeter::resizeEvent(QResizeEvent* ) { if (!size().isValid()) return; - if (m_Size != size()) { //if size changed, resize pixmaps to new screensize + if (m_Size != size()) + { + // if size changed, resize pixmaps to new screensize m_Size = size(); m_OverlayPixmap = QPixmap(m_Size.width(), m_Size.height()); m_OverlayPixmap.fill(Qt::black); @@ -101,10 +96,6 @@ void CMeter::resizeEvent(QResizeEvent* ) draw(); } - -////////////////////////////////////////////////////////////////////// -// Slot called to update meter level position -////////////////////////////////////////////////////////////////////// void CMeter::setLevel(float dbfs) { if(dbfs < MIN_DB) @@ -115,40 +106,33 @@ void CMeter::setLevel(float dbfs) // decay delay float level = (float)m_dBm; - if (dbfs < level) { - level = level*(1-d_alpha_decay) + dbfs*d_alpha_decay; - } - else { - level = level*(1-d_alpha_rise) + dbfs*d_alpha_rise; - } + if (dbfs < level) + level = level * (1.f - d_alpha_decay) + dbfs * d_alpha_decay; + else + level = level * (1.f - d_alpha_rise) + dbfs * d_alpha_rise; m_dBm = (int)level; qreal w = (qreal)m_2DPixmap.width(); - w = w - 2.0*CTRL_MARGIN*w; // width of meter scale in pixels + w -= 2 * CTRL_MARGIN * w; // width of meter scale in pixels // pixels / dB qreal pixperdb = w / fabs(MAX_DB - MIN_DB); - m_Slevel = (int)(-(MIN_DB-level)*pixperdb); + m_Slevel = (int)(-(MIN_DB - level) * pixperdb); draw(); } -////////////////////////////////////////////////////////////////////// // Called by QT when screen needs to be redrawn -////////////////////////////////////////////////////////////////////// void CMeter::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.drawPixmap(0,0,m_2DPixmap); + painter.drawPixmap(0, 0, m_2DPixmap); return; } - -////////////////////////////////////////////////////////////////////// // Called to update s-meter data for displaying on the screen -////////////////////////////////////////////////////////////////////// void CMeter::draw() { int w; @@ -162,52 +146,50 @@ void CMeter::draw() h = m_2DPixmap.height(); // first copy into 2Dbitmap the overlay bitmap. - m_2DPixmap = m_OverlayPixmap.copy(0,0,w,h); + m_2DPixmap = m_OverlayPixmap.copy(0, 0, w, h); QPainter painter(&m_2DPixmap); // DrawCurrent position indicator - qreal hline = (qreal)h*CTRL_XAXIS_HEGHT; - qreal marg = (qreal)w*CTRL_MARGIN; - qreal ht = (qreal)h*CTRL_NEEDLE_TOP; + qreal hline = (qreal) h * CTRL_XAXIS_HEGHT; + qreal marg = (qreal) w * CTRL_MARGIN; + qreal ht = (qreal) h * CTRL_NEEDLE_TOP; qreal x = marg + m_Slevel; QPoint pts[3]; - pts[0].setX(x); pts[0].setY(ht+2); - pts[1].setX(x-6); pts[1].setY(hline+8); - pts[2].setX(x+6); pts[2].setY(hline+8); - + pts[0].setX(x); + pts[0].setY(ht + 2); + pts[1].setX(x - 6); + pts[1].setY(hline + 8); + pts[2].setX(x + 6); + pts[2].setY(hline + 8); - //painter.setBrush(QBrush(Qt::green)); painter.setBrush(QBrush(QColor(0, 190, 0, 255))); painter.setOpacity(1.0); -// Qt 4.8+ has a 1-pixel error (or they fixed line drawing) -// see http://stackoverflow.com/questions/16990326 + // Qt 4.8+ has a 1-pixel error (or they fixed line drawing) + // see http://stackoverflow.com/questions/16990326 #if QT_VERSION >= 0x040800 - painter.drawRect(marg-1, ht+1, x-marg, 6); + painter.drawRect(marg - 1, ht + 1, x - marg, 6); #else - painter.drawRect(marg, ht+2, x-marg, 6); + painter.drawRect(marg, ht + 2, x - marg, 6); #endif // create Font to use for scales QFont Font("Arial"); - QFontMetrics metrics(Font); - int y = (h)/4; + int y = (h) / 4; Font.setPixelSize(y); Font.setWeight(QFont::Normal); painter.setFont(Font); - painter.setPen(QColor(0xEF,0xEF,0xEF,0xFF)); + painter.setPen(QColor(0xEF, 0xEF, 0xEF, 0xFF)); painter.setOpacity(1.0); m_Str.setNum(m_dBm); - painter.drawText(marg, h-2, m_Str+" dBFS" ); + painter.drawText(marg, h - 2, m_Str + " dBFS" ); update(); } -////////////////////////////////////////////////////////////////////// // Called to draw an overlay bitmap containing items that // does not need to be recreated every fft data update. -////////////////////////////////////////////////////////////////////// void CMeter::DrawOverlay() { if(m_OverlayPixmap.isNull()) @@ -219,45 +201,37 @@ void CMeter::DrawOverlay() QRect rect; QPainter painter(&m_OverlayPixmap); - m_OverlayPixmap.fill(QColor(0x20,0x20,0x20,0xFF)); -#if 0 - //fill background with gradient - QLinearGradient gradient(0, 0, 0 ,h); - gradient.setColorAt(1, Qt::black); - gradient.setColorAt(0, Qt::black); - painter.setBrush(gradient); - painter.drawRect(0, 0, w, h); -#endif + m_OverlayPixmap.fill(QColor(0x20, 0x20, 0x20, 0xFF)); - //Draw scale lines - qreal marg = (qreal)w*CTRL_MARGIN; - qreal hline = (qreal)h*CTRL_XAXIS_HEGHT; - qreal magstart = (qreal)h*CTRL_MAJOR_START; - qreal minstart = (qreal)h*CTRL_MINOR_START; - qreal hstop = (qreal)w-marg; + // Draw scale lines + qreal marg = (qreal) w * CTRL_MARGIN; + qreal hline = (qreal)h * CTRL_XAXIS_HEGHT; + qreal magstart = (qreal) h * CTRL_MAJOR_START; + qreal minstart = (qreal) h * CTRL_MINOR_START; + qreal hstop = (qreal) w - marg; painter.setPen(QPen(Qt::white, 1, Qt::SolidLine)); - painter.drawLine(QLineF(marg, hline, hstop, hline)); // top line with ticks - painter.drawLine(QLineF(marg, hline+8, hstop, hline+8)); // bottom line + painter.drawLine(QLineF(marg, hline, hstop, hline)); // top line + painter.drawLine(QLineF(marg, hline+8, hstop, hline+8)); // bottom line qreal xpos = marg; - for(x=0; x<11; x++) { - if(x&1) //minor tics - painter.drawLine( QLineF(xpos, minstart, xpos, hline) ); + for (x = 0; x < 11; x++) { + if (x & 1) + //minor tics + painter.drawLine(QLineF(xpos, minstart, xpos, hline)); else - painter.drawLine( QLineF(xpos, magstart, xpos, hline) ); - xpos += (hstop-marg)/10.0; + painter.drawLine(QLineF(xpos, magstart, xpos, hline)); + xpos += (hstop-marg) / 10.0; } - //draw scale text - //create Font to use for scales + // draw scale text + // create Font to use for scales QFont Font("Arial"); - QFontMetrics metrics(Font); - y = h/4; + y = h / 4; Font.setPixelSize(y); Font.setWeight(QFont::Normal); painter.setFont(Font); - int rwidth = (int)((hstop-marg)/5.0); + int rwidth = (int)((hstop - marg) / 5.0); m_Str = "-100"; - rect.setRect(marg/2-5, 0, rwidth, magstart); + rect.setRect(marg / 2 - 5, 0, rwidth, magstart); for (x = MIN_DB; x <= MAX_DB; x += 20) { @@ -265,19 +239,5 @@ void CMeter::DrawOverlay() painter.drawText(rect, Qt::AlignHCenter|Qt::AlignVCenter, m_Str); rect.translate(rwidth, 0); } - - /* - for(x=1; x<=9; x+=2) { - m_Str.setNum(x); - painter.drawText(rect, Qt::AlignHCenter|Qt::AlignVCenter, m_Str); - rect.translate( rwidth,0); - } - painter.setPen(QPen(Qt::red, 1,Qt::SolidLine)); - for(x=20; x<=60; x+=20) { - m_Str = "+" + m_Str.setNum(x); - painter.drawText(rect, Qt::AlignHCenter|Qt::AlignVCenter, m_Str); - rect.translate( rwidth,0); - } - */ } diff --git a/src/qtgui/meter.h b/src/qtgui/meter.h index 287ced2..3877d53 100644 --- a/src/qtgui/meter.h +++ b/src/qtgui/meter.h @@ -1,80 +1,79 @@ -/* -*- c++ -*- */ -/* + + + This Software is released under the "Simplified BSD License" + + + - * Copyright 2010 Moe Wheatley. All rights reserved. - * Copyright 2011-2013 Alexandru Csete OZ9AEC. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of Moe Wheatley. - */ -#ifndef METER_H -#define METER_H - -#include -#include -#include - - -class CMeter : public QFrame -{ - Q_OBJECT - -public: - explicit CMeter(QWidget *parent = 0); - explicit CMeter(float min_level = -100.0, float max_level = 10.0, QWidget *parent = 0); - ~CMeter(); - - QSize minimumSizeHint() const; - QSize sizeHint() const; - - void setMin(float min_level); - void setMax(float max_level); - void setRange(float min_level, float max_level); - - void draw(); - void UpdateOverlay(){DrawOverlay();} - -signals: - -public slots: - void setLevel(float dbfs); - -protected: - //re-implemented widget event handlers - void paintEvent(QPaintEvent *event); - void resizeEvent(QResizeEvent* event); - -private: - void DrawOverlay(); - QPixmap m_2DPixmap; - QPixmap m_OverlayPixmap; - QSize m_Size; - QString m_Str; - int m_Slevel; - int m_dBm; - - float d_alpha_decay; - float d_alpha_rise; -}; - -#endif // METER_H +/* -*- c++ -*- */ +/* + + + This Software is released under the "Simplified BSD License" + + + + * + * Copyright 2010 Moe Wheatley. All rights reserved. + * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Moe Wheatley OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Moe Wheatley. + */ +#ifndef METER_H +#define METER_H + +#include +#include +#include + +class CMeter : public QFrame +{ + Q_OBJECT + +public: + explicit CMeter(QWidget *parent = 0); + explicit CMeter(float min_level = -100.0, float max_level = 10.0, + QWidget *parent = 0); + ~CMeter(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + void setMin(float min_level); + void setMax(float max_level); + void setRange(float min_level, float max_level); + + void draw(); + void UpdateOverlay(){DrawOverlay();} + +public slots: + void setLevel(float dbfs); + +protected: + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent* event); + +private: + void DrawOverlay(); + QPixmap m_2DPixmap; + QPixmap m_OverlayPixmap; + QSize m_Size; + QString m_Str; + int m_Slevel; + int m_dBm; + + float d_alpha_decay; + float d_alpha_rise; +}; + +#endif // METER_H From e540e2c6044042ffb987065a84cc739653604225 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 14 Aug 2016 00:38:20 +0200 Subject: [PATCH 059/334] Adjust meter colors to fit with other widgets. --- src/qtgui/meter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/meter.cpp b/src/qtgui/meter.cpp index e9c82b6..9cdd6dc 100644 --- a/src/qtgui/meter.cpp +++ b/src/qtgui/meter.cpp @@ -180,7 +180,7 @@ void CMeter::draw() Font.setWeight(QFont::Normal); painter.setFont(Font); - painter.setPen(QColor(0xEF, 0xEF, 0xEF, 0xFF)); + painter.setPen(QColor(0xDA, 0xDA, 0xDA, 0xFF)); painter.setOpacity(1.0); m_Str.setNum(m_dBm); painter.drawText(marg, h - 2, m_Str + " dBFS" ); @@ -201,7 +201,7 @@ void CMeter::DrawOverlay() QRect rect; QPainter painter(&m_OverlayPixmap); - m_OverlayPixmap.fill(QColor(0x20, 0x20, 0x20, 0xFF)); + m_OverlayPixmap.fill(QColor(0x1F, 0x1D, 0x1D, 0xFF)); // Draw scale lines qreal marg = (qreal) w * CTRL_MARGIN; From 53b3dcb20bb9653741e7298f3c79ceb28f67e140 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 14 Aug 2016 00:50:43 +0200 Subject: [PATCH 060/334] Indent and cleanup. --- src/applications/gqrx/mainwindow.cpp | 89 ++++++++++------------------ src/applications/gqrx/mainwindow.h | 3 - 2 files changed, 32 insertions(+), 60 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 7f0839c..77c4414 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -135,10 +135,10 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : uiDockAudio->toggleViewAction()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A)); uiDockBookmarks->toggleViewAction()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); - setCorner( Qt::TopLeftCorner, Qt::LeftDockWidgetArea ); - setCorner( Qt::TopRightCorner, Qt::RightDockWidgetArea ); - setCorner( Qt::BottomLeftCorner, Qt::BottomDockWidgetArea ); - setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea ); + setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); + setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea); + setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); /* Add dock widgets to main window. This should be done even for dock widgets that are going to be hidden, otherwise they will @@ -160,16 +160,9 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : addDockWidget(Qt::BottomDockWidgetArea, uiDockBookmarks); /* hide docks that we don't want to show initially */ - /** FIXME: Hide them initially but store layout in config **/ - // uiDockInputCtl->hide(); - // uiDockFft->hide(); - uiDockBookmarks->hide(); uiDockRDS->hide(); - /* misc configurations */ - //uiDockAudio->setFftRange(0, 8000); // FM - /* Add dock widget actions to View menu. By doing it this way all signal/slot connections will be established automagially. */ @@ -372,17 +365,18 @@ MainWindow::~MainWindow() * @param cfgfile * @returns True if config is OK, False if not (e.g. no input device specified). * - * If cfgfile is an absolute path it will be used as is, otherwise it is assumed to be the - * name of a file under m_cfg_dir. + * If cfgfile is an absolute path it will be used as is, otherwise it is assumed + * to be the name of a file under m_cfg_dir. * * If cfgfile does not exist it will be created. * - * If no input device is specified, we return false to signal that the I/O configuration - * dialog should be run. + * If no input device is specified, we return false to signal that the I/O + * configuration dialog should be run. * * FIXME: Refactor. */ -bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restore_mainwindow) +bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, + bool restore_mainwindow) { double actual_rate; qint64 int64_val; @@ -400,7 +394,8 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor if (QDir::isAbsolutePath(cfgfile)) m_settings = new QSettings(cfgfile, QSettings::IniFormat); else - m_settings = new QSettings(QString("%1/%2").arg(m_cfg_dir).arg(cfgfile), QSettings::IniFormat); + m_settings = new QSettings(QString("%1/%2").arg(m_cfg_dir).arg(cfgfile), + QSettings::IniFormat); qDebug() << "Configuration file:" << m_settings->fileName(); @@ -444,7 +439,8 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor // main window settings if (restore_mainwindow) { - restoreGeometry(m_settings->value("gui/geometry", saveGeometry()).toByteArray()); + restoreGeometry(m_settings->value("gui/geometry", + saveGeometry()).toByteArray()); restoreState(m_settings->value("gui/state", saveState()).toByteArray()); } @@ -479,9 +475,7 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor updateGainStages(false); } else - { updateGainStages(true); - } } QString outdev = m_settings->value("output/device", "").toString(); @@ -513,9 +507,7 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor qDebug() << "Actual sample rate :" << QString("%1").arg(actual_rate, 0, 'f', 6); } else - { actual_rate = rx->get_input_rate(); - } if (actual_rate > 0.) { @@ -536,9 +528,8 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor } } else - { rx->set_input_decim(1); - } + // update various widgets that need a sample rate uiDockRxOpt->setFilterOffsetRange((qint64)(actual_rate)); uiDockFft->setSampleRate(actual_rate); @@ -548,9 +539,7 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor iq_tool->setSampleRate((qint64)actual_rate); } else - { qDebug() << "Error: Actual sample rate is" << actual_rate; - } int64_val = m_settings->value("input/bandwidth", 0).toInt(&conv_ok); if (conv_ok) @@ -592,11 +581,11 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash, bool restor * @param cfgfile * @returns True if the operation was successful. * - * If cfgfile is an absolute path it will be used as is, otherwise it is assumed to be the - * name of a file under m_cfg_dir. + * If cfgfile is an absolute path it will be used as is, otherwise it is + * assumed to be the name of a file under m_cfg_dir. * - * If cfgfile already exists it will be overwritten (we assume that a file selection dialog - * has already asked for confirmation of overwrite. + * If cfgfile already exists it will be overwritten (we assume that a file + * selection dialog has already asked for confirmation of overwrite. * * Since QSettings does not support "save as" we do this by copying the current * settings to a new file. @@ -754,7 +743,7 @@ void MainWindow::updateGainStages(bool read_from_device) */ void MainWindow::setNewFrequency(qint64 rx_freq) { - double hw_freq = (double)(rx_freq-d_lnb_lo) - rx->get_filter_offset(); + double hw_freq = (double)(rx_freq - d_lnb_lo) - rx->get_filter_offset(); qint64 center_freq = rx_freq - (qint64)rx->get_filter_offset(); d_hw_freq = (qint64)hw_freq; @@ -849,9 +838,9 @@ void MainWindow::setAutoGain(bool enabled) void MainWindow::setFreqCorr(double ppm) { if (ppm < -200.0) - ppm = -200.0; + ppm = -200.0; else if (ppm > 200.0) - ppm = 200.0; + ppm = 200.0; qDebug() << __FUNCTION__ << ":" << ppm << "ppm"; rx->set_freq_corr(ppm); @@ -941,9 +930,8 @@ void MainWindow::selectDemod(int mode_idx) d_filter_shape = (receiver::filter_shape)uiDockRxOpt->currentFilterShape(); if (rx->is_rds_decoder_active()) - { setRdsDecoder(false); - } + uiDockRDS->setDisabled(); switch (mode_idx) { @@ -1062,7 +1050,8 @@ void MainWindow::selectDemod(int mode_idx) rx->set_filter((double)flo, (double)fhi, d_filter_shape); rx->set_cw_offset(cwofs); - d_have_audio = ((mode_idx != DockRxOpt::MODE_OFF) && (mode_idx != DockRxOpt::MODE_RAW)); + d_have_audio = ((mode_idx != DockRxOpt::MODE_OFF) && + (mode_idx != DockRxOpt::MODE_RAW)); uiDockRxOpt->setCurrentDemod(mode_idx); } @@ -1647,11 +1636,11 @@ void MainWindow::setPeakDetection(bool enabled) * started. The jerkyness disappears when trhe receiver is reconfigured * by selecting a new demodulator. */ -void MainWindow::forceRxReconf() +/*void MainWindow::forceRxReconf() { qDebug() << "Force RX reconf (jerky dongle workarond)..."; selectDemod(uiDockRxOpt->currentDemod()); -} +}*/ /** * @brief Start/Stop DSP processing. @@ -1858,9 +1847,8 @@ void MainWindow::on_plotter_newDemodFreq(qint64 freq, qint64 delta) uiDockRxOpt->setFilterOffset(delta); ui->freqCtrl->setFrequency(freq); - if (rx->is_rds_decoder_active()) { + if (rx->is_rds_decoder_active()) rx->reset_rds_parser(); - } } /* CPlotter::NewfilterFreq() is emitted */ @@ -1872,9 +1860,7 @@ void MainWindow::on_plotter_newFilterFreq(int low, int high) retcode = rx->set_filter((double) low, (double) high, d_filter_shape); if (retcode == receiver::STATUS_OK) - { uiDockRxOpt->setFilterParam(low, high); - } } void MainWindow::on_plotter_newCenterFreq(qint64 f) @@ -1956,12 +1942,10 @@ void MainWindow::on_actionAFSK1200_triggered() dec_timer->start(100); } else - { QMessageBox::warning(this, tr("Gqrx error"), tr("Error starting sample sniffer.\n" "Close all data decoders and try again."), QMessageBox::Ok, QMessageBox::Ok); - } } } @@ -1994,14 +1978,9 @@ void MainWindow::decoderTimeout() float buffer[DATA_BUFFER_SIZE]; unsigned int num; - //qDebug() << "Process decoder"; - rx->get_sniffer_data(&buffer[0], num); if (dec_afsk1200) - { dec_afsk1200->process_samples(&buffer[0], num); - } - /* else stop timeout and sniffer? */ } void MainWindow::setRdsDecoder(bool checked) @@ -2029,12 +2008,10 @@ void MainWindow::on_actionUserGroup_triggered() bool res = QDesktopServices::openUrl(QUrl("https://groups.google.com/forum/#!forum/gqrx", QUrl::TolerantMode)); if (!res) - { QMessageBox::warning(this, tr("Error"), tr("Failed to open website:\n" "https://groups.google.com/forum/#!forum/gqrx"), QMessageBox::Close); - } } /** @@ -2209,17 +2186,15 @@ void MainWindow::on_actionAddBookmark_triggered() QStringList listTags = tags.split(",",QString::SkipEmptyParts); info.tags.clear(); if (listTags.size() == 0) - { info.tags.append(&Bookmarks::Get().findOrAddTag("")); - } - for(i = 0; i < listTags.size(); ++i) - { + + + for (i = 0; i < listTags.size(); ++i) info.tags.append(&Bookmarks::Get().findOrAddTag(listTags[i])); - } + Bookmarks::Get().add(info); uiDockBookmarks->updateTags(); uiDockBookmarks->updateBookmarks(); ui->plotter->updateOverlay(); } - } diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index 04b7a66..47c4ef6 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -213,9 +213,6 @@ private slots: /* window close signals */ void afsk1200win_closed(); - - void forceRxReconf(); - int firstTimeConfig(); /* cyclic processing */ From bf1443a85308e8a700ca357eecfab10092fb81ee Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 14 Aug 2016 00:53:45 +0200 Subject: [PATCH 061/334] Add keyboard shortcut for 'View toolbar' action. --- src/applications/gqrx/mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 77c4414..97d30f5 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -134,6 +134,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : uiDockFft->toggleViewAction()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F)); uiDockAudio->toggleViewAction()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A)); uiDockBookmarks->toggleViewAction()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); + ui->mainToolBar->toggleViewAction()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_T)); setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); From 0cecd874006abbc05a35eedf8971d281ce95874b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 14 Aug 2016 19:05:33 +0200 Subject: [PATCH 062/334] Add keyboard shortcut for 'Add bookmark'. Fixes issue #385. Note that the shortcut only works as long as either the toolbar or the menubar is visible. --- src/applications/gqrx/mainwindow.ui | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index 0b4eaf9..7c34930 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -131,7 +131,7 @@ 0 0 950 - 22 + 20 @@ -172,9 +172,12 @@ + + + @@ -379,10 +382,13 @@ :/icons/icons/bookmark-new.svg:/icons/icons/bookmark-new.svg - AddBookmark + Add bookmark - Bookmark the current frequency and mode + Bookmark the current frequency and mode (Ctrl+Shift+B) + + + Ctrl+Shift+B From d0f26a63c8092091a8157b91f516de236f6f1429 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 15 Aug 2016 00:31:21 +0200 Subject: [PATCH 063/334] Adjust central widget background and margins. --- src/applications/gqrx/mainwindow.ui | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index 7c34930..d1c22c4 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -17,6 +17,9 @@ :/icons/icons/gqrx.svg:/icons/icons/gqrx.svg + + + QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks @@ -24,15 +27,18 @@ true + + background-color: rgb(31, 29, 29); + - 2 + 10 0 - 2 + 10 0 @@ -43,7 +49,13 @@ - 2 + 30 + + + 20 + + + 10 From ce0cf76e39c4e4dcd53b2ef15260f2e75df3f77b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 17 Aug 2016 11:16:53 +0200 Subject: [PATCH 064/334] Add spacers around frequency control and s-meter widgets. --- src/applications/gqrx/mainwindow.ui | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index d1c22c4..98e7417 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -49,7 +49,7 @@ - 30 + 10 20 @@ -57,6 +57,19 @@ 10 + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -82,6 +95,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + From 9984b10d517f0aa08fa33a57edb902416f1949c8 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 20 Aug 2016 00:05:26 +0200 Subject: [PATCH 065/334] Update icon credits. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 33fe86a..b792a33 100644 --- a/README.md +++ b/README.md @@ -270,14 +270,14 @@ Wolfgang Fritz DK7OB - 1-2-5 scaling on FFT plot. - Various UI improvements. +Some of the icons are from: +- The GNOME icon theme CC-SA 3.0 by GNOME icon artists +- Tango icon theme, Public Domain by The people from the Tango! project +- Mint-X icon theme, GPL by Clement Lefebvre Also thanks to Volker Schroer and Alexey Bazhin for bringing Funcube Dongle Pro+ support to GNU Radio and Gqrx. -Some of the icons are from the GNOME and Tango icon themes. The scope.svg icon -is based on the utilities-system-monitor.svg icon from the Mint-X icon theme -licensed under GNU GPL. - Let me know if somebody or someting is missing from the list! Alex OZ9AEC From 5cab5c79ec8765e2bee9259e1e27175eaf6ef377 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 20 Aug 2016 00:42:53 +0200 Subject: [PATCH 066/334] Update start/stop DSP icon. --- src/applications/gqrx/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index 98e7417..66f077e 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -286,7 +286,7 @@ - :/icons/icons/power-off.svg:/icons/icons/power-off.svg + :/icons/icons/play.svg:/icons/icons/play.svg Start DSP From 1076ed6b14dc158d9152828125f37184b6f5a4d3 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 20 Aug 2016 15:41:25 +0200 Subject: [PATCH 067/334] Reduce HBF attenuation to 100 dB. --- src/dsp/hbf_decim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsp/hbf_decim.cpp b/src/dsp/hbf_decim.cpp index 555f08f..00244d5 100644 --- a/src/dsp/hbf_decim.cpp +++ b/src/dsp/hbf_decim.cpp @@ -43,7 +43,7 @@ hbf_decim::hbf_decim(unsigned int decim) { decimation = decim; dec = new Decimator(); - if (dec->init(decim, 120) != decim) + if (dec->init(decim, 100) != decim) throw std::range_error("Decimation not supported"); std::cout << "New decimator: " << decimation << std::endl; From 3840a7011e9badb2ccb74e5d285a16a48adc1231 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 20 Aug 2016 20:51:52 +0200 Subject: [PATCH 068/334] Use medium AGC as default. --- src/dsp/rx_agc_xx.cpp | 50 ++++++++++++++++++--------------- src/dsp/rx_agc_xx.h | 60 +++++++++++++++++----------------------- src/qtgui/agc_options.ui | 15 ++++++---- src/qtgui/dockrxopt.ui | 3 ++ src/receivers/nbrx.cpp | 2 +- 5 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/dsp/rx_agc_xx.cpp b/src/dsp/rx_agc_xx.cpp index cb1f157..900abb2 100644 --- a/src/dsp/rx_agc_xx.cpp +++ b/src/dsp/rx_agc_xx.cpp @@ -33,8 +33,8 @@ rx_agc_cc_sptr make_rx_agc_cc(double sample_rate, bool agc_on, int threshold, use_hang)); } - -/*! \brief Create receiver AGC object. +/** + * \brief Create receiver AGC object. * * Use make_rx_agc_cc() instead. */ @@ -61,11 +61,11 @@ rx_agc_cc::~rx_agc_cc() delete d_agc; } - -/*! \brief Receiver AGC work method. - * \param mooutput_items - * \param input_items - * \param output_items +/** + * \brief Receiver AGC work method. + * \param mooutput_items + * \param input_items + * \param output_items */ int rx_agc_cc::work(int noutput_items, gr_vector_const_void_star &input_items, @@ -80,9 +80,9 @@ int rx_agc_cc::work(int noutput_items, return noutput_items; } - -/*! \brief Enable or disable AGC. - * \param agc_on Whether AGC should be endabled. +/** + * \brief Enable or disable AGC. + * \param agc_on Whether AGC should be endabled. * * When AGC is disabled a fixed gain is used. * @@ -98,8 +98,9 @@ void rx_agc_cc::set_agc_on(bool agc_on) } } -/*! \brief Set AGC sample rate. - * \param sample_rate The sample rate. +/** + * \brief Set AGC sample rate. + * \param sample_rate The sample rate. * * The AGC uses knowledge about the sample rate to calculate various delays and * time constants. @@ -114,8 +115,9 @@ void rx_agc_cc::set_sample_rate(double sample_rate) } } -/*! \brief Set new AGC threshold. - * \param threshold The new threshold between -160 and 0dB. +/** + * \brief Set new AGC threshold. + * \param threshold The new threshold between -160 and 0dB. * * The threshold specifies AGC "knee" in dB when the AGC is active. */ @@ -129,8 +131,9 @@ void rx_agc_cc::set_threshold(int threshold) } } -/*! \brief Set new manual gain. - * \param gain The new manual gain between 0 and 100dB. +/** + * \brief Set new manual gain. + * \param gain The new manual gain between 0 and 100dB. * * The manual gain is used when AGC is switched off. * @@ -146,8 +149,9 @@ void rx_agc_cc::set_manual_gain(int gain) } } -/*! \brief Set AGC slope factor. - * \param slope The new slope factor between 0 and 10dB. +/** + * \brief Set AGC slope factor. + * \param slope The new slope factor between 0 and 10dB. * * The slope factor specifies dB reduction in output at knee from maximum output level */ @@ -161,8 +165,9 @@ void rx_agc_cc::set_slope(int slope) } } -/*! \brief Set AGC decay time. - * \param decay The new AGC decay time between 20 to 5000 ms. +/** + * \brief Set AGC decay time. + * \param decay The new AGC decay time between 20 to 5000 ms. */ void rx_agc_cc::set_decay(int decay) { @@ -174,8 +179,9 @@ void rx_agc_cc::set_decay(int decay) } } -/*! \brief Enable/disable AGC hang. - * \param use_hang Whether to use hang or not. +/** + * \brief Enable/disable AGC hang. + * \param use_hang Whether to use hang or not. */ void rx_agc_cc::set_use_hang(bool use_hang) { diff --git a/src/dsp/rx_agc_xx.h b/src/dsp/rx_agc_xx.h index a2c2faf..4b6c71a 100644 --- a/src/dsp/rx_agc_xx.h +++ b/src/dsp/rx_agc_xx.h @@ -33,39 +33,32 @@ class rx_agc_cc; typedef boost::shared_ptr rx_agc_cc_sptr; -/*! \brief Return a shared_ptr to a new instance of rx_agc_cc. - * \param sample_rate The samle rate (default = 96000). - * \param agc_on Whether AGC should be ON (default = true). - * \param threshold AGC Knee in dB if AGC is active. Range -160 to 0dB - * (default = -100dB). - * \param manual_gain Manual gain when AGC is OFF. Range 0 to 100dB - * (default = 0dB). - * \param slope AGC slope factor. Specifies dB reduction in output at - * knee from maximum output level. Range 0 to 10dB - * (default = 2dB TBC). - * \param decay AGC decay time in milliseconds. Range 20 to 5000. This - * parameter determines whether AGC is fast/slow/medium. - * The default value is 100ms (fast AGC). - * \param use_hang Whether AGC should "hang" before starting to decay. - * The default is false. +/** + * \brief Return a shared_ptr to a new instance of rx_agc_cc. + * \param sample_rate The samle rate (default = 96000). + * \param agc_on Whether AGC should be ON (default = true). + * \param threshold AGC Knee in dB if AGC is active. Range -160 to 0 dB. + * \param manual_gain Manual gain when AGC is OFF. Range 0 to 100 dB. + * \param slope AGC slope factor. Specifies dB reduction in output at + * knee from maximum output level. Range 0 to 10 dB + * \param decay AGC decay time in milliseconds. Range 20 to 5000. This + * parameter determines whether AGC is fast, slow or medium. + * \param use_hang Whether AGC should "hang" before starting to decay. * * This is effectively the public constructor for a new AGC block. * To avoid accidental use of raw pointers, the rx_agc_cc constructor is private. * make_rx_agc_cc is the public interface for creating new instances. */ -rx_agc_cc_sptr make_rx_agc_cc(double sample_rate = 96000.0, bool agc_on = true, - int threshold = -100, int manual_gain = 0, - int slope = 2, int decay = 100, - bool use_hang = false); +rx_agc_cc_sptr make_rx_agc_cc(double sample_rate, bool agc_on, int threshold, + int manual_gain, int slope, int decay, + bool use_hang); - -/*! \brief Experimental AGC block for analog voice modes (AM, SSB, CW). - * \ingroup DSP +/** + * \brief Experimental AGC block for analog voice modes (AM, SSB, CW). + * \ingroup DSP * * This block performs automatic gain control. * To be written... - * - * \todo rx_agc_ff */ class rx_agc_cc : public gr::sync_block { @@ -93,17 +86,16 @@ class rx_agc_cc : public gr::sync_block void set_use_hang(bool use_hang); private: - CAgc *d_agc; - boost::mutex d_mutex; /*! Used to lock internal data while processing or setting parameters. */ + CAgc *d_agc; + boost::mutex d_mutex; /*! Used to lock internal data while processing or setting parameters. */ - bool d_agc_on; /*! Current AGC status (true/false). */ - double d_sample_rate; /*! Current sample rate. */ - int d_threshold; /*! Current AGC threshold (-160...0 dB). */ - int d_manual_gain; /*! Current gain when AGC is OFF. */ - int d_slope; /*! Current AGC slope (0...10 dB). */ - int d_decay; /*! Current AGC decay (20...5000 ms). */ - bool d_use_hang; /*! Current AGC hang status (true/false). */ + bool d_agc_on; /*! Current AGC status (true/false). */ + double d_sample_rate; /*! Current sample rate. */ + int d_threshold; /*! Current AGC threshold (-160...0 dB). */ + int d_manual_gain; /*! Current gain when AGC is OFF. */ + int d_slope; /*! Current AGC slope (0...10 dB). */ + int d_decay; /*! Current AGC decay (20...5000 ms). */ + bool d_use_hang; /*! Current AGC hang status (true/false). */ }; - #endif /* RX_AGC_XX_H */ diff --git a/src/qtgui/agc_options.ui b/src/qtgui/agc_options.ui index 11ede75..737eb65 100644 --- a/src/qtgui/agc_options.ui +++ b/src/qtgui/agc_options.ui @@ -74,7 +74,7 @@ 1 - 2 + 0 Qt::Horizontal @@ -84,7 +84,7 @@ - -120 dB + -100 dB Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -163,7 +163,10 @@ 50 - 100 + 500 + + + 500 Qt::Horizontal @@ -176,7 +179,7 @@ false - 100 ms + 500 ms Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -221,7 +224,7 @@ false - 2 dB + 0 dB Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -253,7 +256,7 @@ 0 - -120 + -100 Qt::Horizontal diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index 6a36422..cb77da9 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -347,6 +347,9 @@ This is an offset from the hardware RF frequency.</p></body></htm AGC presets + + 1 + Fast diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index b14073c..98415ee 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -43,7 +43,7 @@ nbrx::nbrx(float quad_rate, float audio_rate) nb = make_rx_nb_cc(PREF_QUAD_RATE, 3.3, 2.5); filter = make_rx_filter(PREF_QUAD_RATE, -5000.0, 5000.0, 1000.0); - agc = make_rx_agc_cc(PREF_QUAD_RATE, true, -120, 50, 2, 100, false); + agc = make_rx_agc_cc(PREF_QUAD_RATE, true, -100, 0, 0, 500, false); sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001); meter = make_rx_meter_c(DETECTOR_TYPE_RMS); demod_ssb = gr::blocks::complex_to_real::make(1); From 670ec76e9c2fb5007b96c0491387527c1681423d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 21 Aug 2016 00:11:17 +0200 Subject: [PATCH 069/334] Restore AGC settings between sessions. --- src/qtgui/agc_options.cpp | 8 +-- src/qtgui/dockrxopt.cpp | 110 ++++++++++++++++++++++++++++---------- src/qtgui/dockrxopt.h | 3 +- 3 files changed, 88 insertions(+), 33 deletions(-) diff --git a/src/qtgui/agc_options.cpp b/src/qtgui/agc_options.cpp index 0ebcfe9..4a1af5c 100644 --- a/src/qtgui/agc_options.cpp +++ b/src/qtgui/agc_options.cpp @@ -63,15 +63,15 @@ void CAgcOptions::setPreset(agc_preset_e preset) case AGC_FAST: setDecay(100); enableDecay(false); - setSlope(2); + setSlope(0); enableSlope(false); enableGain(false); break; case AGC_MEDIUM: - setDecay(1000); + setDecay(500); enableDecay(false); - setSlope(2); + setSlope(0); enableSlope(false); enableGain(false); break; @@ -79,7 +79,7 @@ void CAgcOptions::setPreset(agc_preset_e preset) case AGC_SLOW: setDecay(2000); enableDecay(false); - setSlope(2); + setSlope(0); enableSlope(false); enableGain(false); break; diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index fd5d6af..6fb1eb2 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -269,7 +269,7 @@ QString DockRxOpt::currentDemodAsString() float DockRxOpt::currentMaxdev() { - qDebug() << __FILE__ << __FUNCTION__ << "FIXME"; + qInfo() << __FILE__ << __FUNCTION__ << "FIXME"; return 5000.0; } @@ -289,12 +289,12 @@ void DockRxOpt::getFilterPreset(int mode, int preset, int * lo, int * hi) const { if (mode < 0 || mode >= MODE_LAST) { - qDebug() << __func__ << ": Invalid mode:" << mode; + qInfo() << __func__ << ": Invalid mode:" << mode; mode = MODE_AM; } else if (preset < 0 || preset > 2) { - qDebug() << __func__ << ": Invalid preset:" << preset; + qInfo() << __func__ << ": Invalid preset:" << preset; preset = FILTER_PRESET_NORMAL; } *lo = filter_preset_table[mode][preset][0]; @@ -309,22 +309,20 @@ int DockRxOpt::getCwOffset() const /** Read receiver configuration from settings data. */ void DockRxOpt::readSettings(QSettings *settings) { - bool conv_ok; - int intVal; + bool conv_ok; + int int_val; + double dbl_val; - intVal = settings->value("receiver/demod", 0).toInt(&conv_ok); - if (intVal >= 0) + int_val = settings->value("receiver/demod", 0).toInt(&conv_ok); + if (int_val >= 0) { - setCurrentDemod(intVal); - emit demodSelected(intVal); + setCurrentDemod(int_val); + emit demodSelected(int_val); } - intVal = settings->value("receiver/cwoffset", 700).toInt(&conv_ok); + int_val = settings->value("receiver/cwoffset", 700).toInt(&conv_ok); if (conv_ok) - { - demodOpt->setCwOffset(intVal); - //demodOpt_cwOffsetChanged(intVal); - } + demodOpt->setCwOffset(int_val); qint64 offs = settings->value("receiver/offset", 0).toInt(&conv_ok); if (offs) @@ -333,17 +331,48 @@ void DockRxOpt::readSettings(QSettings *settings) emit filterOffsetChanged(offs); } - double dblVal = settings->value("receiver/sql_level", 1.0).toDouble(&conv_ok); - if (conv_ok && dblVal < 1.0) + dbl_val = settings->value("receiver/sql_level", 1.0).toDouble(&conv_ok); + if (conv_ok && dbl_val < 1.0) + ui->sqlSpinBox->setValue(dbl_val); + + // AGC settings + int_val = settings->value("receiver/agc_threshold", -100).toInt(&conv_ok); + if (conv_ok) + agcOpt->setThreshold(int_val); + + int_val = settings->value("receiver/agc_decay", 500).toInt(&conv_ok); + if (conv_ok) { - //ui->sqlSlider->setValue(intVal); // signal emitted automatically - ui->sqlSpinBox->setValue(dblVal); + agcOpt->setDecay(int_val); + if (int_val == 100) + ui->agcPresetCombo->setCurrentIndex(0); + else if (int_val == 500) + ui->agcPresetCombo->setCurrentIndex(1); + else if (int_val == 2000) + ui->agcPresetCombo->setCurrentIndex(2); + else + ui->agcPresetCombo->setCurrentIndex(3); } + + int_val = settings->value("receiver/agc_slope", 0).toInt(&conv_ok); + if (conv_ok) + agcOpt->setSlope(int_val); + + int_val = settings->value("receiver/agc_gain", 0).toInt(&conv_ok); + if (conv_ok) + agcOpt->setGain(int_val); + + agcOpt->setHang(settings->value("receiver/agc_usehang", false).toBool()); + + if (settings->value("receiver/agc_off", false).toBool()) + ui->agcPresetCombo->setCurrentIndex(4); } /** Save receiver configuration to settings. */ void DockRxOpt::saveSettings(QSettings *settings) { + int int_val; + settings->setValue("receiver/demod", ui->modeSelector->currentIndex()); int cwofs = demodOpt->getCwOffset(); @@ -365,6 +394,40 @@ void DockRxOpt::saveSettings(QSettings *settings) settings->setValue("receiver/sql_level", sql_lvl); else settings->remove("receiver/sql_level"); + + // AGC settings + int_val = agcOpt->threshold(); + if (int_val != -100) + settings->setValue("receiver/agc_threshold", int_val); + else + settings->remove("receiver/agc_threshold"); + + int_val = agcOpt->decay(); + if (int_val != 500) + settings->setValue("receiver/agc_decay", int_val); + else + settings->remove("receiver/agc_decay"); + + int_val = agcOpt->slope(); + if (int_val != 0) + settings->setValue("receiver/agc_slope", int_val); + else + settings->remove("receiver/agc_slope"); + + int_val = agcOpt->gain(); + if (int_val != 0) + settings->setValue("receiver/agc_gain", int_val); + else + settings->remove("receiver/agc_gain"); + + if (agcOpt->hang()) + settings->setValue("receiver/agc_usehang", true); + else + settings->remove("receiver/agc_usehang"); + + // AGC Off + if (ui->agcPresetCombo->currentIndex() == 4) + settings->setValue("receiver/agc_off", true); } /** @@ -376,7 +439,6 @@ void DockRxOpt::saveSettings(QSettings *settings) */ void DockRxOpt::on_filterFreq_newFrequency(qint64 freq) { - qDebug() << "New filter offset:" << freq << "Hz"; updateHwFreq(); emit filterOffsetChanged(freq); @@ -410,8 +472,6 @@ void DockRxOpt::on_filterCombo_activated(int index) */ void DockRxOpt::on_modeSelector_activated(int index) { - qDebug() << "New mode: " << index; - if (index == MODE_RAW) { qDebug() << "Raw I/Q not implemented (fallback to FM-N)"; @@ -457,13 +517,12 @@ void DockRxOpt::on_agcButton_clicked() */ void DockRxOpt::on_autoSquelchButton_clicked() { - // Emit signal double newval = sqlAutoClicked(); // FIXME: We rely on signal only being connected to one slot ui->sqlSpinBox->setValue(newval); } /** AGC preset has changed. */ -void DockRxOpt::on_agcPresetCombo_activated(int index) +void DockRxOpt::on_agcPresetCombo_currentIndexChanged(int index) { CAgcOptions::agc_preset_e preset = (CAgcOptions::agc_preset_e) index; @@ -497,7 +556,6 @@ void DockRxOpt::on_agcPresetCombo_activated(int index) void DockRxOpt::agcOpt_hangToggled(bool checked) { - qDebug() << "AGC hang" << (checked ? "ON" : "OFF"); emit agcHangToggled(checked); } @@ -507,7 +565,6 @@ void DockRxOpt::agcOpt_hangToggled(bool checked) */ void DockRxOpt::agcOpt_thresholdChanged(int value) { - qDebug() << "AGC threshold:" << value; emit agcThresholdChanged(value); } @@ -517,7 +574,6 @@ void DockRxOpt::agcOpt_thresholdChanged(int value) */ void DockRxOpt::agcOpt_slopeChanged(int value) { - qDebug() << "AGC slope:" << value; emit agcSlopeChanged(value); } @@ -527,7 +583,6 @@ void DockRxOpt::agcOpt_slopeChanged(int value) */ void DockRxOpt::agcOpt_decayChanged(int value) { - qDebug() << "AGC decay:" << value; emit agcDecayChanged(value); } @@ -537,7 +592,6 @@ void DockRxOpt::agcOpt_decayChanged(int value) */ void DockRxOpt::agcOpt_gainChanged(int gain) { - qDebug() << "AGC manual gain:" << gain; emit agcGainChanged(gain); } diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h index d061a07..1175b2f 100644 --- a/src/qtgui/dockrxopt.h +++ b/src/qtgui/dockrxopt.h @@ -177,7 +177,8 @@ private slots: void on_modeButton_clicked(); void on_agcButton_clicked(); void on_autoSquelchButton_clicked(); - void on_agcPresetCombo_activated(int index); + //void on_agcPresetCombo_activated(int index); + void on_agcPresetCombo_currentIndexChanged(int index); void on_sqlSpinBox_valueChanged(double value); void on_nb1Button_toggled(bool checked); void on_nb2Button_toggled(bool checked); From 8b6ea4a338ef1af46f28d103226fde08265aaae1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 21 Aug 2016 00:12:46 +0200 Subject: [PATCH 070/334] Update news file. --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index d30d4eb..e9ba75c 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,6 +2,7 @@ NEW: 1-2-5 scaling on FFT axis. NEW: Audio waterfall. + NEW: Remember AGC settings between sessions. FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. From d2bcf19d05aec4e3c6993a59a7cf62dc8eec87a4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 21 Aug 2016 01:04:51 +0200 Subject: [PATCH 071/334] Synchronise LNB LO when using I/O config dialog. Fixes bug #123. --- resources/news.txt | 1 + src/applications/gqrx/mainwindow.cpp | 2 + src/qtgui/dockinputctl.cpp | 136 +++++++++++++++++---------- src/qtgui/dockinputctl.h | 51 +++++----- src/qtgui/ioconfig.cpp | 14 ++- 5 files changed, 122 insertions(+), 82 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index e9ba75c..674be59 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -8,6 +8,7 @@ FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. FIXED: Correct display of negative offsets between -1 and 0 kHz. FIXED: Reset frequency digits below the one that is being changed. + FIXED: LNB LO could not be set from I/O confugration dialog. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. IMPROVED: 1-2-5 scaling on FFT axis. diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 97d30f5..51363a4 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1722,6 +1722,8 @@ int MainWindow::on_actionIoConfig_triggered() // suspend DSP while we reload settings on_actionDSP_triggered(false); + // Refresh LNB LO in dock widget, otherwise changes will be lost + uiDockInputCtl->readLnbLoFromSettings(m_settings); storeSession(); loadConfig(m_settings->fileName(), false, false); diff --git a/src/qtgui/dockinputctl.cpp b/src/qtgui/dockinputctl.cpp index c80b294..149033d 100644 --- a/src/qtgui/dockinputctl.cpp +++ b/src/qtgui/dockinputctl.cpp @@ -24,7 +24,7 @@ #include "dockinputctl.h" #include "ui_dockinputctl.h" -DockInputCtl::DockInputCtl(QWidget *parent) : +DockInputCtl::DockInputCtl(QWidget * parent) : QDockWidget(parent), ui(new Ui::DockInputCtl) { @@ -42,9 +42,11 @@ DockInputCtl::~DockInputCtl() delete gainLayout; } -void DockInputCtl::readSettings(QSettings *settings) +void DockInputCtl::readSettings(QSettings * settings) { - bool conv_ok; + qint64 lnb_lo; + bool conv_ok; + bool bool_val; qint64 ppm_corr = settings->value("input/corr_freq", 0).toLongLong(&conv_ok); setFreqCorr(((double)ppm_corr)/1.0e6); @@ -59,11 +61,14 @@ void DockInputCtl::readSettings(QSettings *settings) setIqBalance(settings->value("input/iq_balance", false).toBool()); emit iqBalanceChanged(ui->iqBalanceButton->isChecked()); - qint64 lnb_lo = settings->value("input/lnb_lo", 0).toLongLong(&conv_ok); - setLnbLo(((double)lnb_lo)/1.0e6); - emit lnbLoChanged(ui->lnbSpinBox->value()); + lnb_lo = settings->value("input/lnb_lo", 0).toLongLong(&conv_ok); + if (conv_ok) + { + setLnbLo(((double)lnb_lo)/1.0e6); + emit lnbLoChanged(ui->lnbSpinBox->value()); + } - bool bool_val = settings->value("input/ignore_limits", false).toBool(); + bool_val = settings->value("input/ignore_limits", false).toBool(); setIgnoreLimits(bool_val); emit ignoreLimitsChanged(bool_val); @@ -101,7 +106,7 @@ void DockInputCtl::readSettings(QSettings *settings) } -void DockInputCtl::saveSettings(QSettings *settings) +void DockInputCtl::saveSettings(QSettings * settings) { qint64 lnb_lo = (qint64)(ui->lnbSpinBox->value()*1.e6); if (lnb_lo) @@ -156,6 +161,19 @@ void DockInputCtl::saveSettings(QSettings *settings) settings->remove("input/antenna"); } +void DockInputCtl::readLnbLoFromSettings(QSettings * settings) +{ + qint64 lnb_lo; + bool conv_ok; + + lnb_lo = settings->value("input/lnb_lo", 0).toLongLong(&conv_ok); + if (conv_ok) + { + setLnbLo(((double)lnb_lo) / 1.0e6); + emit lnbLoChanged(ui->lnbSpinBox->value()); + } +} + void DockInputCtl::setLnbLo(double freq_mhz) { ui->lnbSpinBox->setValue(freq_mhz); @@ -166,9 +184,10 @@ double DockInputCtl::lnbLo() return ui->lnbSpinBox->value(); } -/*! \brief Set new value of a specific gain. - * \param name The name of the gain to change. - * \param value The new value. +/** + * @brief Set new value of a specific gain. + * @param name The name of the gain to change. + * @param value The new value. */ void DockInputCtl::setGain(QString &name, double value) { @@ -185,8 +204,9 @@ void DockInputCtl::setGain(QString &name, double value) } } -/*! \brief Get current gain. - * \returns The relative gain between 0.0 and 1.0 or -1 if HW AGC is enabled. +/** + * @brief Get current gain. + * @returns The relative gain between 0.0 and 1.0 or -1 if HW AGC is enabled. */ double DockInputCtl::gain(QString &name) { @@ -204,16 +224,18 @@ double DockInputCtl::gain(QString &name) return gain; } -/*! \brief Set status of hardware AGC button. - * \param enabled Whether hardware AGC is enabled or not. +/** + * Set status of hardware AGC button. + * @param enabled Whether hardware AGC is enabled or not. */ void DockInputCtl::setAgc(bool enabled) { ui->agcButton->setChecked(enabled); } -/*! \brief Get status of hardware AGC button. - * \return Whether hardware AGC is enabled or not. +/** + * @brief Get status of hardware AGC button. + * @return Whether hardware AGC is enabled or not. */ bool DockInputCtl::agc() { @@ -221,8 +243,9 @@ bool DockInputCtl::agc() } -/*! \brief Set new frequency correction. - * \param corr The new frequency correction in PPM. +/** + * Set new frequency correction. + * @param corr The new frequency correction in PPM. */ void DockInputCtl::setFreqCorr(double corr) { @@ -230,61 +253,61 @@ void DockInputCtl::setFreqCorr(double corr) } -/*! \brief Get current frequency correction. */ +/** Get current frequency correction. */ double DockInputCtl::freqCorr() { return ui->freqCorrSpinBox->value(); } -/*! \brief Enasble/disable I/Q swapping. */ +/** Enasble/disable I/Q swapping. */ void DockInputCtl::setIqSwap(bool reversed) { ui->iqSwapButton->setChecked(reversed); } -/*! \brief Get current I/Q swapping. */ +/** Get current I/Q swapping. */ bool DockInputCtl::iqSwap(void) { return ui->iqSwapButton->isChecked(); } -/*! \brief Enable automatic DC removal. */ +/** Enable automatic DC removal. */ void DockInputCtl::setDcCancel(bool enabled) { ui->dcCancelButton->setChecked(enabled); } -/*! \brief Get current DC remove status. */ +/** Get current DC remove status. */ bool DockInputCtl::dcCancel(void) { return ui->dcCancelButton->isChecked(); } -/*! \brief Enable automatic IQ balance. */ +/** Enable automatic IQ balance. */ void DockInputCtl::setIqBalance(bool enabled) { ui->iqBalanceButton->setChecked(enabled); } -/*! \brief Get current IQ balance status. */ +/** Get current IQ balance status. */ bool DockInputCtl::iqBalance(void) { return ui->iqBalanceButton->isChecked(); } -/*! \brief Enasble/disable ignoring hardware limits. */ +/** Enasble/disable ignoring hardware limits. */ void DockInputCtl::setIgnoreLimits(bool reversed) { ui->ignoreButton->setChecked(reversed); } -/*! \brief Get current status of whether limits should be ignored or not. */ +/** Get current status of whether limits should be ignored or not. */ bool DockInputCtl::ignoreLimits(void) { return ui->ignoreButton->isChecked(); } -/*! \brief Populate antenna selector combo box with strings. */ +/** Populate antenna selector combo box with strings. */ void DockInputCtl::setAntennas(std::vector &antennas) { ui->antSelector->clear(); @@ -294,7 +317,7 @@ void DockInputCtl::setAntennas(std::vector &antennas) } } -/*! \brief Select antenna. */ +/** Select antenna. */ void DockInputCtl::setAntenna(const QString &antenna) { int index = ui->antSelector->findText(antenna, Qt::MatchExactly); @@ -302,8 +325,9 @@ void DockInputCtl::setAntenna(const QString &antenna) ui->antSelector->setCurrentIndex(index); } -/*! \brief Set gain stages. - * \param gain_list A list containing the gain stages for this device. +/** + * Set gain stages. + * @param gain_list A list containing the gain stages for this device. */ void DockInputCtl::setGainStages(gain_list_t &gain_list) { @@ -361,7 +385,8 @@ void DockInputCtl::setGainStages(gain_list_t &gain_list) } -/*! \brief Load all gains from the settings. +/** + * Load all gains from the settings. * * Can be used for restoring the manual gains after auto-gain has been * disabled. @@ -390,13 +415,13 @@ void DockInputCtl::restoreManualGains(QSettings *settings) } } -/*! \brief LNB LO value has changed. */ +/** LNB LO value has changed. */ void DockInputCtl::on_lnbSpinBox_valueChanged(double value) { emit lnbLoChanged(value); } -/*! \brief Automatic gain control button has been toggled. */ +/** Automatic gain control button has been toggled. */ void DockInputCtl::on_agcButton_toggled(bool checked) { for (int i = 0; i < gain_sliders.length(); ++i) @@ -407,32 +432,36 @@ void DockInputCtl::on_agcButton_toggled(bool checked) emit autoGainChanged(checked); } -/*! \brief Frequency correction changed. - * \param value The new frequency correction in ppm. +/** + * Frequency correction changed. + * @param value The new frequency correction in ppm. */ void DockInputCtl::on_freqCorrSpinBox_valueChanged(double value) { emit freqCorrChanged(value); } -/*! \brief I/Q swapping checkbox changed. - * \param checked True if I/Q swapping is enabled, false otherwise +/** + * I/Q swapping checkbox changed. + * @param checked True if I/Q swapping is enabled, false otherwise */ void DockInputCtl::on_iqSwapButton_toggled(bool checked) { emit iqSwapChanged(checked); } -/*! \brief DC removal checkbox changed. - * \param checked True if DC removal is enabled, false otherwise +/** + * DC removal checkbox changed. + * @param checked True if DC removal is enabled, false otherwise */ void DockInputCtl::on_dcCancelButton_toggled(bool checked) { emit dcCancelChanged(checked); } -/*! \brief IQ balance checkbox changed. - * \param checked True if automatic IQ balance is enabled, false otherwise +/** + * IQ balance checkbox changed. + * @param checked True if automatic IQ balance is enabled, false otherwise */ void DockInputCtl::on_iqBalanceButton_toggled(bool checked) { @@ -449,13 +478,13 @@ void DockInputCtl::on_ignoreButton_toggled(bool checked) emit ignoreLimitsChanged(checked); } -/*! \brief Antenna selection has changed. */ +/** Antenna selection has changed. */ void DockInputCtl::on_antSelector_currentIndexChanged(const QString &antenna) { emit antennaSelected(antenna); } -/*! \brief Remove all widgets from the lists. */ +/** Remove all widgets from the lists. */ void DockInputCtl::clearWidgets() { QWidget *widget; @@ -485,8 +514,9 @@ void DockInputCtl::clearWidgets() } } -/*! \brief Slot for managing slider value changed signals. - * \param value The value of the slider. +/** + * Slot for managing slider value changed signals. + * @param value The value of the slider. * * Note. We use the sender() function to find out which slider has emitted the signal. */ @@ -507,9 +537,10 @@ void DockInputCtl::sliderValueChanged(int value) emit gainChanged(slider->property("name").toString(), gain); } -/*! \brief Update value label - * \param idx The index of the gain - * \param value The new value +/** + * Update value label + * @param idx The index of the gain + * @param value The new value */ void DockInputCtl::updateLabel(int idx, double value) { @@ -518,8 +549,9 @@ void DockInputCtl::updateLabel(int idx, double value) label->setText(QString("%1 dB").arg(value, 0, 'f', 1)); } -/*! \brief Get all gains. - * \param gains Pointer to a map where the gains and their names are stored. +/** + * Get all gains. + * @param gains Pointer to a map where the gains and their names are stored. * * This is a private utility function used when storing the settings. */ diff --git a/src/qtgui/dockinputctl.h b/src/qtgui/dockinputctl.h index 2c8aaaa..945f7d9 100644 --- a/src/qtgui/dockinputctl.h +++ b/src/qtgui/dockinputctl.h @@ -64,41 +64,42 @@ class DockInputCtl : public QDockWidget Q_OBJECT public: - explicit DockInputCtl(QWidget *parent = 0); + explicit DockInputCtl(QWidget * parent = 0); ~DockInputCtl(); - void readSettings(QSettings *settings); - void saveSettings(QSettings *settings); + void readSettings(QSettings * settings); + void saveSettings(QSettings * settings); - void setLnbLo(double freq_mhz); - double lnbLo(); + void setLnbLo(double freq_mhz); + double lnbLo(); + void readLnbLoFromSettings(QSettings * settings); - void setGain(QString &name, double value); - double gain(QString &name); + void setGain(QString &name, double value); + double gain(QString &name); - void setAgc(bool enabled); - bool agc(); + void setAgc(bool enabled); + bool agc(); - void setFreqCorr(double corr); - double freqCorr(); + void setFreqCorr(double corr); + double freqCorr(); - void setIqSwap(bool reversed); - bool iqSwap(void); + void setIqSwap(bool reversed); + bool iqSwap(void); - void setDcCancel(bool enabled); - bool dcCancel(void); + void setDcCancel(bool enabled); + bool dcCancel(void); - void setIqBalance(bool enabled); - bool iqBalance(void); + void setIqBalance(bool enabled); + bool iqBalance(void); - void setIgnoreLimits(bool reversed); - bool ignoreLimits(void); + void setIgnoreLimits(bool reversed); + bool ignoreLimits(void); - void setAntennas(std::vector &antennas); - void setAntenna(const QString &antenna); + void setAntennas(std::vector &antennas); + void setAntenna(const QString &antenna); - void setGainStages(gain_list_t &gain_list); - void restoreManualGains(QSettings *settings); + void setGainStages(gain_list_t &gain_list); + void restoreManualGains(QSettings *settings); signals: void gainChanged(QString name, double value); @@ -126,8 +127,8 @@ private slots: private: void clearWidgets(); void updateLabel(int idx, double value); - void getGains(QMap *gains); - void setGains(QMap *gains); + void getGains(QMap * gains); + void setGains(QMap * gains); private: QList gain_sliders; /*!< A list containing the gain sliders. */ diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index a147b7c..56c7b49 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -44,7 +44,9 @@ #include "ui_ioconfig.h" -CIoConfig::CIoConfig(QSettings *settings, std::map &devList, QWidget *parent) : +CIoConfig::CIoConfig(QSettings * settings, + std::map &devList, + QWidget *parent) : QDialog(parent), ui(new Ui::CIoConfig), m_settings(settings) @@ -112,7 +114,7 @@ CIoConfig::CIoConfig(QSettings *settings, std::map &devList, ui->bwSpinBox->setValue(1.0e-6*settings->value("input/bandwidth", 0.0).toDouble()); // LNB LO - ui->loSpinBox->setValue(1.0e-6*settings->value("input/lnb_lo", 0.0).toDouble()); + ui->loSpinBox->setValue(1.0e-6 * settings->value("input/lnb_lo", 0.0).toDouble()); // Output device QString outdev = settings->value("output/device", "").toString(); @@ -251,6 +253,7 @@ void CIoConfig::saveConfig() { int idx; int int_val; + bool conv_ok; qDebug() << __FUNCTION__; @@ -286,10 +289,11 @@ void CIoConfig::saveConfig() value = (qint64)(ui->loSpinBox->value()*1.e6); if (value) m_settings->setValue("input/lnb_lo", value); + else + m_settings->remove("input/lnb_lo"); - bool ok=false; - int_val = ui->inSrCombo->currentText().toInt(&ok); - if (ok) + int_val = ui->inSrCombo->currentText().toInt(&conv_ok); + if (conv_ok) m_settings->setValue("input/sample_rate", int_val); else m_settings->remove("input/sample_rate"); From 3556cbf79cfd5e024a391dd766735328e25b8371 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 28 Aug 2016 11:44:45 +0200 Subject: [PATCH 072/334] Don't use qInfo() since it's not avaialble in Qt 5.2. Fixes #404. --- src/qtgui/dockrxopt.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 6fb1eb2..37464f0 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -269,7 +269,7 @@ QString DockRxOpt::currentDemodAsString() float DockRxOpt::currentMaxdev() { - qInfo() << __FILE__ << __FUNCTION__ << "FIXME"; + qDebug() << __FILE__ << __FUNCTION__ << "FIXME"; return 5000.0; } @@ -289,12 +289,12 @@ void DockRxOpt::getFilterPreset(int mode, int preset, int * lo, int * hi) const { if (mode < 0 || mode >= MODE_LAST) { - qInfo() << __func__ << ": Invalid mode:" << mode; + qDebug() << __func__ << ": Invalid mode:" << mode; mode = MODE_AM; } else if (preset < 0 || preset > 2) { - qInfo() << __func__ << ": Invalid preset:" << preset; + qDebug() << __func__ << ": Invalid preset:" << preset; preset = FILTER_PRESET_NORMAL; } *lo = filter_preset_table[mode][preset][0]; From 7f98552701ec6fb27fa5d5a6ba1273c000761c5a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 27 Aug 2016 17:34:22 +0200 Subject: [PATCH 073/334] Replace half-band decimator with optimal FIR sequence. Replaces the half-band input decimation filters with and optimal sequence of FIR filters. The filter specs were created using a test version of FIRCalc by Youssef Touil. The filter taps were then generated using Matlab for 90-100 dB stop band attenuation and 0.5 dB passband ripple. The optimized FIR sequence and the vectorized FIR implementation in GNU Radio give a significant performance improvement over the previous half band implementation. --- README.md | 3 + gqrx.pro | 10 +- resources/news.txt | 1 + src/applications/gqrx/receiver.cpp | 7 +- src/applications/gqrx/receiver.h | 4 +- src/dsp/CMakeLists.txt | 12 +- src/dsp/filter/fir_decim.cpp | 160 +++++++++++++ src/dsp/filter/fir_decim.h | 48 ++++ src/dsp/filter/fir_decim_coef.h | 353 +++++++++++++++++++++++++++++ src/qtgui/ioconfig.cpp | 8 +- 10 files changed, 582 insertions(+), 24 deletions(-) create mode 100644 src/dsp/filter/fir_decim.cpp create mode 100644 src/dsp/filter/fir_decim.h create mode 100644 src/dsp/filter/fir_decim_coef.h diff --git a/README.md b/README.md index b792a33..50368df 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,9 @@ Wolfgang Fritz DK7OB - 1-2-5 scaling on FFT plot. - Various UI improvements. +Youssef Touil +- FIRCalc design tool for optimizing input decimator. + Some of the icons are from: - The GNOME icon theme CC-SA 3.0 by GNOME icon artists - Tango icon theme, Public Domain by The people from the Tango! project diff --git a/gqrx.pro b/gqrx.pro index 6376d7b..c93169a 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -89,8 +89,7 @@ SOURCES += \ src/dsp/afsk1200/costabf.c \ src/dsp/agc_impl.cpp \ src/dsp/correct_iq_cc.cpp \ - src/dsp/filter/decimator.cpp \ - src/dsp/hbf_decim.cpp \ + src/dsp/filter/fir_decim.cpp \ src/dsp/lpf.cpp \ src/dsp/rds/decoder_impl.cc \ src/dsp/rds/parser_impl.cc \ @@ -141,11 +140,8 @@ HEADERS += \ src/dsp/afsk1200/filter-i386.h \ src/dsp/agc_impl.h \ src/dsp/correct_iq_cc.h \ - src/dsp/filter/decimator.h \ - src/dsp/filter/filtercoef_hbf_70.h \ - src/dsp/filter/filtercoef_hbf_100.h \ - src/dsp/filter/filtercoef_hbf_140.h \ - src/dsp/hbf_decim.h \ + src/dsp/filter/fir_decim.h \ + src/dsp/filter/fir_decim_coef.h \ src/dsp/lpf.h \ src/dsp/rds/api.h \ src/dsp/rds/parser.h \ diff --git a/resources/news.txt b/resources/news.txt index 674be59..3f5e9b3 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -9,6 +9,7 @@ FIXED: Correct display of negative offsets between -1 and 0 kHz. FIXED: Reset frequency digits below the one that is being changed. FIXED: LNB LO could not be set from I/O confugration dialog. + IMPROVED: Input decimator performance. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. IMPROVED: 1-2-5 scaling on FFT axis. diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index c5d254f..208119a 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -36,7 +36,8 @@ #include "applications/gqrx/receiver.h" #include "dsp/correct_iq_cc.h" -#include "dsp/hbf_decim.h" +//#include "dsp/hbf_decim.h" +#include "dsp/filter/fir_decim.h" #include "dsp/rx_fft.h" #include "receivers/nbrx.h" #include "receivers/wfmrx.h" @@ -90,7 +91,7 @@ receiver::receiver(const std::string input_device, { try { - input_decim = make_hbf_decim(d_decim); + input_decim = make_fir_decim_cc(d_decim); } catch (std::range_error &e) { @@ -376,7 +377,7 @@ unsigned int receiver::set_input_decim(unsigned int decim) { try { - input_decim = make_hbf_decim(d_decim); + input_decim = make_fir_decim_cc(d_decim); } catch (std::range_error &e) { diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index 1c24ae6..a9e7d80 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -35,7 +35,7 @@ #include #include "dsp/correct_iq_cc.h" -#include "dsp/hbf_decim.h" +#include "dsp/filter/fir_decim.h" #include "dsp/rx_noise_blanker_cc.h" #include "dsp/rx_filter.h" #include "dsp/rx_meter.h" @@ -241,7 +241,7 @@ class receiver gr::top_block_sptr tb; /*!< The GNU Radio top block. */ osmosdr::source::sptr src; /*!< Real time I/Q source. */ - hbf_decim_sptr input_decim; /*!< Input decimator. */ + fir_decim_cc_sptr input_decim; /*!< Input decimator. */ receiver_base_cf_sptr rx; /*!< receiver. */ dc_corr_cc_sptr dc_corr; /*!< DC corrector block. */ diff --git a/src/dsp/CMakeLists.txt b/src/dsp/CMakeLists.txt index 87eaad9..daae9fc 100644 --- a/src/dsp/CMakeLists.txt +++ b/src/dsp/CMakeLists.txt @@ -1,4 +1,4 @@ -####################################################################################################################### + # Add the source files to SRCS_LIST add_source_files(SRCS_LIST afsk1200/cafsk12.cpp @@ -6,13 +6,9 @@ add_source_files(SRCS_LIST afsk1200/costabf.c afsk1200/filter-i386.h afsk1200/filter.h - filter/decimator.cpp - filter/decimator.h - filter/filtercoef_hbf_70.h - filter/filtercoef_hbf_100.h - filter/filtercoef_hbf_140.h - hbf_decim.cpp - hbf_decim.h + filter/fir_decim.cpp + filter/fir_decim.h + filter/fir_decim_coef.h rds/api.h rds/constants.h rds/decoder_impl.cc diff --git a/src/dsp/filter/fir_decim.cpp b/src/dsp/filter/fir_decim.cpp new file mode 100644 index 0000000..192c63e --- /dev/null +++ b/src/dsp/filter/fir_decim.cpp @@ -0,0 +1,160 @@ +/* -*- c++ -*- */ +/* + * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt + * http://gqrx.dk/ + * + * Copyright 2016 Alexandru Csete OZ9AEC. + * + * Gqrx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Gqrx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Gqrx; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include +#include + +#include "fir_decim.h" +#include "fir_decim_coef.h" + + +fir_decim_cc_sptr make_fir_decim_cc(unsigned int decim) +{ + return gnuradio::get_initial_sptr(new fir_decim_cc(decim)); +} + +fir_decim_cc::fir_decim_cc(unsigned int decim) + : gr::hier_block2("fir_decim_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))) +{ + std::vector taps; + + switch (decim) + { + default: + std::cout << "Invalid decimation: " << decim + << " (falling back to 2)." << std::endl; + // fallthrough + case 2: + // Stage Passband Stopband Decimation + // FIR1 0.4500000000 0.5500000000 2 + taps.assign(FIR_2_1_TAPS, FIR_2_1_TAPS + FIR_2_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, self(), 0); + break; + + case 4: + // Stage Passband Stopband Decimation + // FIR1 0.2250000000 0.7750000000 2 + // FIR2 0.4500000000 0.5500000000 2 + taps.assign(FIR_4_1_TAPS, FIR_4_1_TAPS + FIR_4_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(2, taps); + taps.assign(FIR_4_2_TAPS, FIR_4_2_TAPS + FIR_4_2_LEN); + fir2 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, fir2, 0); + connect(fir2, 0, self(), 0); + break; + + case 8: + // Stage Passband Stopband Decimation + // FIR1 0.1125000000 0.3875000000 4 + // FIR2 0.4500000000 0.5500000000 2 + taps.assign(FIR_8_1_TAPS, FIR_8_1_TAPS + FIR_8_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(4, taps); + taps.assign(FIR_8_2_TAPS, FIR_8_2_TAPS + FIR_8_2_LEN); + fir2 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, fir2, 0); + connect(fir2, 0, self(), 0); + break; + + case 16: + // Stage Passband Stopband Decimation + // FIR1 0.0562500000 0.4437500000 4 + // FIR2 0.2250000000 0.7750000000 2 + // FIR3 0.4500000000 0.5500000000 2 + taps.assign(FIR_16_1_TAPS, FIR_16_1_TAPS + FIR_16_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(4, taps); + taps.assign(FIR_16_2_TAPS, FIR_16_2_TAPS + FIR_16_2_LEN); + fir2 = gr::filter::fir_filter_ccf::make(2, taps); + taps.assign(FIR_16_3_TAPS, FIR_16_3_TAPS + FIR_16_3_LEN); + fir3 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, fir2, 0); + connect(fir2, 0, fir3, 0); + connect(fir3, 0, self(), 0); + break; + + case 32: + // Stage Passband Stopband Decimation + // FIR1 0.0281250000 0.2218750000 8 + // FIR2 0.2250000000 0.7750000000 2 + // FIR3 0.4500000000 0.5500000000 2 + taps.assign(FIR_32_1_TAPS, FIR_32_1_TAPS + FIR_32_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(8, taps); + taps.assign(FIR_32_2_TAPS, FIR_32_2_TAPS + FIR_32_2_LEN); + fir2 = gr::filter::fir_filter_ccf::make(2, taps); + taps.assign(FIR_32_3_TAPS, FIR_32_3_TAPS + FIR_32_3_LEN); + fir3 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, fir2, 0); + connect(fir2, 0, fir3, 0); + connect(fir3, 0, self(), 0); + break; + + case 64: + // Stage Passband Stopband Decimation + // FIR1 0.0140625000 0.2359375000 8 + // FIR2 0.1125000000 0.3875000000 4 + // FIR3 0.4500000000 0.5500000000 2 + taps.assign(FIR_64_1_TAPS, FIR_64_1_TAPS + FIR_64_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(8, taps); + taps.assign(FIR_64_2_TAPS, FIR_64_2_TAPS + FIR_64_2_LEN); + fir2 = gr::filter::fir_filter_ccf::make(4, taps); + taps.assign(FIR_64_3_TAPS, FIR_64_3_TAPS + FIR_64_3_LEN); + fir3 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, fir2, 0); + connect(fir2, 0, fir3, 0); + connect(fir3, 0, self(), 0); + break; + + case 128: + // Stage Passband Stopband Decimation + // FIR1 0.0070312500 0.1179688000 16 + // FIR2 0.1125000000 0.3875000000 4 + // FIR3 0.4500000000 0.5500000000 2 + taps.assign(FIR_128_1_TAPS, FIR_128_1_TAPS + FIR_128_1_LEN); + fir1 = gr::filter::fir_filter_ccf::make(16, taps); + taps.assign(FIR_128_2_TAPS, FIR_128_2_TAPS + FIR_128_2_LEN); + fir2 = gr::filter::fir_filter_ccf::make(4, taps); + taps.assign(FIR_128_3_TAPS, FIR_128_3_TAPS + FIR_128_3_LEN); + fir3 = gr::filter::fir_filter_ccf::make(2, taps); + connect(self(), 0, fir1, 0); + connect(fir1, 0, fir2, 0); + connect(fir2, 0, fir3, 0); + connect(fir3, 0, self(), 0); + break; + } +} + +fir_decim_cc::~fir_decim_cc() +{ + +} diff --git a/src/dsp/filter/fir_decim.h b/src/dsp/filter/fir_decim.h new file mode 100644 index 0000000..9c026f4 --- /dev/null +++ b/src/dsp/filter/fir_decim.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt + * http://gqrx.dk/ + * + * Copyright 2016 Alexandru Csete OZ9AEC. + * + * Gqrx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Gqrx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Gqrx; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#pragma once + +#include +#include + +class fir_decim_cc; + +typedef boost::shared_ptr fir_decim_cc_sptr; +fir_decim_cc_sptr make_fir_decim_cc(unsigned int decim); + +class fir_decim_cc : public gr::hier_block2 +{ + friend fir_decim_cc_sptr make_fir_decim_cc(unsigned int decim); + +//protected: +public: + fir_decim_cc(unsigned int decim); + +public: + ~fir_decim_cc(); + +private: + gr::filter::fir_filter_ccf::sptr fir1; + gr::filter::fir_filter_ccf::sptr fir2; + gr::filter::fir_filter_ccf::sptr fir3; +}; diff --git a/src/dsp/filter/fir_decim_coef.h b/src/dsp/filter/fir_decim_coef.h new file mode 100644 index 0000000..d32cecc --- /dev/null +++ b/src/dsp/filter/fir_decim_coef.h @@ -0,0 +1,353 @@ +/* -*- c++ -*- */ +/* + * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt + * http://gqrx.dk/ + * + * Copyright 2016 Alexandru Csete OZ9AEC. + * + * Gqrx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Gqrx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Gqrx; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#pragma once + +/* Filter taps generated by matlab. + * All filters are designed for 0.5 dB passband ripple and 90-100 dB stop-band + * attenuation. + * Optimal FIR sequence generated using FIRCalc 1.0 by Youssef Touil + */ + +// 0.4500000000 0.5500000000 2 +#define FIR_2_1_LEN 65 +const float FIR_2_1_TAPS[FIR_2_1_LEN] = { + -0.0003278252261, + -0.002040079795, + -0.005349315703, + -0.007344492245, + -0.004085056018, + 0.002583198482, + 0.004540402908, + -0.001126032323, + -0.005173824262, + 0.0001933958993, + 0.006274622399, + 0.0009823472938, + -0.007659214549, + -0.002643365879, + 0.009217977524, + 0.004966503475, + -0.01085040253, + -0.008121663705, + 0.01248027012, + 0.01234706212, + -0.01405533589, + -0.01806676947, + 0.01550395414, + 0.02604486234, + -0.01677149534, + -0.03794026747, + 0.0178176146, + 0.05812988058, + -0.01859222725, + -0.1027237624, + 0.01906614564, + 0.3171727061, + 0.4807731807, + 0.3171727061, + 0.01906614564, + -0.1027237624, + -0.01859222725, + 0.05812988058, + 0.0178176146, + -0.03794026747, + -0.01677149534, + 0.02604486234, + 0.01550395414, + -0.01806676947, + -0.01405533589, + 0.01234706212, + 0.01248027012, + -0.008121663705, + -0.01085040253, + 0.004966503475, + 0.009217977524, + -0.002643365879, + -0.007659214549, + 0.0009823472938, + 0.006274622399, + 0.0001933958993, + -0.005173824262, + -0.001126032323, + 0.004540402908, + 0.002583198482, + -0.004085056018, + -0.007344492245, + -0.005349315703, + -0.002040079795, + -0.0003278252261 +}; + +// 0.2250000000 0.7750000000 2 +#define FIR_4_1_LEN 11 +const float FIR_4_1_TAPS[FIR_4_1_LEN] = { + -0.005957326386, + -0.02477577329, + -0.01910482161, + 0.09140145779, + 0.2892911136, + 0.3952179253, + 0.2892911136, + 0.09140145779, + -0.01910482161, + -0.02477577329, + -0.005957326386 +}; + +// 0.4500000000 0.5500000000 2 +#define FIR_4_2_LEN FIR_2_1_LEN +const float *FIR_4_2_TAPS = FIR_2_1_TAPS; + +// 0.1125000000 0.3875000000 4 +#define FIR_8_1_LEN 24 +const float FIR_8_1_TAPS[FIR_8_1_LEN] = { + -0.0003039507719, + -0.00151092303, + -0.004308381584, + -0.008604046889, + -0.0124123916, + -0.01131789293, + 0.0005229047383, + 0.02762223035, + 0.06973481923, + 0.1198379695, + 0.1653192043, + 0.1925006062, + 0.1925006062, + 0.1653192043, + 0.1198379695, + 0.06973481923, + 0.02762223035, + 0.0005229047383, + -0.01131789293, + -0.0124123916, + -0.008604046889, + -0.004308381584, + -0.00151092303, + -0.0003039507719 +}; + +// 0.4500000000 0.5500000000 2 +#define FIR_8_2_LEN FIR_2_1_LEN +const float *FIR_8_2_TAPS = FIR_2_1_TAPS; + +// 0.0562500000 0.4437500000 4 +#define FIR_16_1_LEN 16 +const float FIR_16_1_TAPS[FIR_16_1_LEN] = { + 0.0005477772793, + 0.003594921902, + 0.01279040519, + 0.03234443441, + 0.06392806023, + 0.103605859, + 0.141295597, + 0.1644843221, + 0.1644843221, + 0.141295597, + 0.103605859, + 0.06392806023, + 0.03234443441, + 0.01279040519, + 0.003594921902, + 0.0005477772793 +}; + +// 0.2250000000 0.7750000000 2 +#define FIR_16_2_LEN FIR_4_1_LEN +const float *FIR_16_2_TAPS = FIR_4_1_TAPS; + +// 0.4500000000 0.5500000000 2 +#define FIR_16_3_LEN FIR_2_1_LEN +const float *FIR_16_3_TAPS = FIR_2_1_TAPS; + +// 0.0281250000 0.2218750000 8 +#define FIR_32_1_LEN 42 +const float FIR_32_1_TAPS[FIR_32_1_LEN] = { + -4.750685548e-5, + -0.0001519439538, + -0.0003587162937, + -0.0006931721, + -0.001151426113, + -0.001673014951, + -0.002116090851, + -0.002241667826, + -0.001715262071, + -0.0001324449986, + 0.002929489361, + 0.007837772369, + 0.01481874287, + 0.02387691103, + 0.03473669663, + 0.0468236953, + 0.05929613858, + 0.07112794369, + 0.08123386651, + 0.08861737698, + 0.09251579642, + 0.09251579642, + 0.08861737698, + 0.08123386651, + 0.07112794369, + 0.05929613858, + 0.0468236953, + 0.03473669663, + 0.02387691103, + 0.01481874287, + 0.007837772369, + 0.002929489361, + -0.0001324449986, + -0.001715262071, + -0.002241667826, + -0.002116090851, + -0.001673014951, + -0.001151426113, + -0.0006931721, + -0.0003587162937, + -0.0001519439538, + -4.750685548e-5 +}; + +// 0.2250000000 0.7750000000 2 +#define FIR_32_2_LEN FIR_4_1_LEN +const float *FIR_32_2_TAPS = FIR_4_1_TAPS; + +// 0.4500000000 0.5500000000 2 +#define FIR_32_3_LEN FIR_2_1_LEN +const float *FIR_32_3_TAPS = FIR_2_1_TAPS; + +// 0.0140625000 0.2359375000 8 +#define FIR_64_1_LEN 30 +const float FIR_64_1_TAPS[FIR_64_1_LEN] = { + 0.0001188354872, + 0.0004522371455, + 0.001223598025, + 0.002714014845, + 0.005253443029, + 0.009166177362, + 0.0146980416, + 0.02193524688, + 0.03073395602, + 0.04068056494, + 0.05109928548, + 0.06111412868, + 0.06976035982, + 0.07612732053, + 0.07950519025, + 0.07950519025, + 0.07612732053, + 0.06976035982, + 0.06111412868, + 0.05109928548, + 0.04068056494, + 0.03073395602, + 0.02193524688, + 0.0146980416, + 0.009166177362, + 0.005253443029, + 0.002714014845, + 0.001223598025, + 0.0004522371455, + 0.0001188354872 +}; + +// 0.1125000000 0.3875000000 4 +#define FIR_64_2_LEN FIR_8_1_LEN +const float *FIR_64_2_TAPS = FIR_8_1_TAPS; + +// 0.4500000000 0.5500000000 2 +#define FIR_64_3_LEN FIR_2_1_LEN +const float *FIR_64_3_TAPS = FIR_2_1_TAPS; + +// 0.0070312500 0.1179688000 16 +#define FIR_128_1_LEN 61 +const float FIR_128_1_TAPS[FIR_128_1_LEN] = { + 3.695723717e-5, + 7.529251889e-5, + 0.0001481503132, + 0.000263013033, + 0.0004344411718, + 0.0006792644854, + 0.001016279799, + 0.001465716981, + 0.002048497088, + 0.002785283606, + 0.003695455613, + 0.004795861896, + 0.006099532824, + 0.007614453789, + 0.00934238825, + 0.01127781812, + 0.01340724807, + 0.01570868306, + 0.01815159246, + 0.02069726959, + 0.02329952456, + 0.02590598352, + 0.02845956571, + 0.03090048954, + 0.03316837549, + 0.03520460054, + 0.03695458919, + 0.03837010637, + 0.03941125423, + 0.04004824534, + 0.0402626507, + 0.04004824534, + 0.03941125423, + 0.03837010637, + 0.03695458919, + 0.03520460054, + 0.03316837549, + 0.03090048954, + 0.02845956571, + 0.02590598352, + 0.02329952456, + 0.02069726959, + 0.01815159246, + 0.01570868306, + 0.01340724807, + 0.01127781812, + 0.00934238825, + 0.007614453789, + 0.006099532824, + 0.004795861896, + 0.003695455613, + 0.002785283606, + 0.002048497088, + 0.001465716981, + 0.001016279799, + 0.0006792644854, + 0.0004344411718, + 0.000263013033, + 0.0001481503132, + 7.529251889e-5, + 3.695723717e-5 +}; + +// 0.1125000000 0.3875000000 4 +#define FIR_128_2_LEN FIR_8_1_LEN +const float *FIR_128_2_TAPS = FIR_8_1_TAPS; + +// 0.4500000000 0.5500000000 2 +#define FIR_128_3_LEN FIR_2_1_LEN +const float *FIR_128_3_TAPS = FIR_2_1_TAPS; diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 56c7b49..2930c8b 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -577,10 +577,10 @@ void CIoConfig::updateDecimations(void) ui->decimCombo->addItem("64", 0); if (rate >= 6144000) ui->decimCombo->addItem("128", 0); - if (rate >= 12288000) - ui->decimCombo->addItem("256", 0); - if (rate >= 24576000) - ui->decimCombo->addItem("512", 0); +// if (rate >= 12288000) +// ui->decimCombo->addItem("256", 0); +// if (rate >= 24576000) +// ui->decimCombo->addItem("512", 0); decimationChanged(0); } From 9dc71e5aace1ac769a5e2ee22bfc61342418ebbd Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 3 Sep 2016 23:06:53 +0200 Subject: [PATCH 074/334] Minor code clean-up. --- src/qtgui/plotter.cpp | 124 ++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index a356dc1..0e5a629 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -641,9 +641,7 @@ void CPlotter::setFftRate(int rate_hz) clearWaterfall(); } -////////////////////////////////////////////////////////////////////// // Called when a mouse button is pressed -////////////////////////////////////////////////////////////////////// void CPlotter::mousePressEvent(QMouseEvent * event) { QPoint pt = event->pos(); @@ -651,41 +649,43 @@ void CPlotter::mousePressEvent(QMouseEvent * event) if (NOCAP == m_CursorCaptured) { if (isPointCloseTo(pt.x(), m_DemodFreqX, m_CursorCaptureDelta)) - { //in move demod box center frequency region + { + // move demod box center frequency region m_CursorCaptured = CENTER; - m_GrabPosition = pt.x()-m_DemodFreqX; + m_GrabPosition = pt.x() - m_DemodFreqX; } else if (isPointCloseTo(pt.x(), m_DemodLowCutFreqX, m_CursorCaptureDelta)) - { // filter low cut + { + // filter low cut m_CursorCaptured = LEFT; - m_GrabPosition = pt.x()-m_DemodLowCutFreqX; + m_GrabPosition = pt.x() - m_DemodLowCutFreqX; } else if (isPointCloseTo(pt.x(), m_DemodHiCutFreqX, m_CursorCaptureDelta)) - { // filter high cut + { + // filter high cut m_CursorCaptured = RIGHT; - m_GrabPosition = pt.x()-m_DemodHiCutFreqX; + m_GrabPosition = pt.x() - m_DemodHiCutFreqX; } else { if (event->buttons() == Qt::LeftButton) { - int best=-1; - if(m_PeakDetection>0) - best = getNearestPeak(pt); + int best = -1; - if(best!=-1) + if (m_PeakDetection > 0) + best = getNearestPeak(pt); + if (best != -1) m_DemodCenterFreq = freqFromX(best); else - m_DemodCenterFreq = roundFreq(freqFromX(pt.x()),m_ClickResolution ); + m_DemodCenterFreq = roundFreq(freqFromX(pt.x()), m_ClickResolution); - //if cursor not captured set demod frequency and start demod box capture - emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); + // if cursor not captured set demod frequency and start demod box capture + emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq - m_CenterFreq); - //save initial grab postion from m_DemodFreqX - //setCursor(QCursor(Qt::CrossCursor)); + // save initial grab postion from m_DemodFreqX + // setCursor(QCursor(Qt::CrossCursor)); m_CursorCaptured = CENTER; m_GrabPosition = 1; - //m_GrabPosition = pt.x()-m_DemodFreqX; drawOverlay(); } else if (event->buttons() == Qt::MidButton) @@ -694,7 +694,7 @@ void CPlotter::mousePressEvent(QMouseEvent * event) m_CenterFreq = roundFreq(freqFromX(pt.x()), m_ClickResolution); m_DemodCenterFreq = m_CenterFreq; emit newCenterFreq(m_CenterFreq); - emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); + emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq - m_CenterFreq); } } } @@ -705,14 +705,15 @@ void CPlotter::mousePressEvent(QMouseEvent * event) m_Yzero = pt.y(); else if (m_CursorCaptured == XAXIS) m_Xzero = pt.x(); - else if(m_CursorCaptured==BOOKMARK) + else if(m_CursorCaptured == BOOKMARK) { - for(int i=0; ipos())) + if (m_BookmarkTags[i].first.contains(event->pos())) { m_DemodCenterFreq = m_BookmarkTags[i].second; - emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); + emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq - m_CenterFreq); break; } } @@ -720,15 +721,14 @@ void CPlotter::mousePressEvent(QMouseEvent * event) } } -////////////////////////////////////////////////////////////////////// // Called when a mouse button is released -////////////////////////////////////////////////////////////////////// void CPlotter::mouseReleaseEvent(QMouseEvent * event) { QPoint pt = event->pos(); if (!m_OverlayPixmap.rect().contains(pt)) - { //not in Overlay region + { + // not in Overlay region if (NOCAP != m_CursorCaptured) setCursor(QCursor(Qt::ArrowCursor)); @@ -784,9 +784,7 @@ void CPlotter::zoomOnXAxis(float level) zoomStepX(current_level / level, xFromFreq(m_DemodCenterFreq)); } -////////////////////////////////////////////////////////////////////// // Called when a mouse wheel is turned -////////////////////////////////////////////////////////////////////// void CPlotter::wheelEvent(QWheelEvent * event) { QPoint pt = event->pos(); @@ -822,8 +820,8 @@ void CPlotter::wheelEvent(QWheelEvent * event) else if (event->modifiers() & Qt::ControlModifier) { // filter width - m_DemodLowCutFreq -= numSteps*m_ClickResolution; - m_DemodHiCutFreq += numSteps*m_ClickResolution; + m_DemodLowCutFreq -= numSteps * m_ClickResolution; + m_DemodHiCutFreq += numSteps * m_ClickResolution; clampDemodParameters(); emit newFilterFreq(m_DemodLowCutFreq, m_DemodHiCutFreq); } @@ -831,15 +829,15 @@ void CPlotter::wheelEvent(QWheelEvent * event) else if (event->modifiers() & Qt::ShiftModifier) { // filter shift - m_DemodLowCutFreq += numSteps*m_ClickResolution; - m_DemodHiCutFreq += numSteps*m_ClickResolution; + m_DemodLowCutFreq += numSteps * m_ClickResolution; + m_DemodHiCutFreq += numSteps * m_ClickResolution; clampDemodParameters(); emit newFilterFreq(m_DemodLowCutFreq, m_DemodHiCutFreq); } else { // inc/dec demod frequency - m_DemodCenterFreq += (numSteps*m_ClickResolution); + m_DemodCenterFreq += (numSteps * m_ClickResolution); m_DemodCenterFreq = roundFreq(m_DemodCenterFreq, m_ClickResolution ); emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); } @@ -850,27 +848,32 @@ void CPlotter::wheelEvent(QWheelEvent * event) drawOverlay(); } -////////////////////////////////////////////////////////////////////// // Called when screen size changes so must recalculate bitmaps -////////////////////////////////////////////////////////////////////// void CPlotter::resizeEvent(QResizeEvent* ) { if (!size().isValid()) return; if (m_Size != size()) - { //if changed, resize pixmaps to new screensize + { + // if changed, resize pixmaps to new screensize + int fft_plot_height; + m_Size = size(); - m_OverlayPixmap = QPixmap(m_Size.width(), m_Percent2DScreen * m_Size.height() / 100); + fft_plot_height = m_Percent2DScreen * m_Size.height() / 100; + m_OverlayPixmap = QPixmap(m_Size.width(), fft_plot_height); m_OverlayPixmap.fill(Qt::black); - m_2DPixmap = QPixmap(m_Size.width(), m_Percent2DScreen * m_Size.height() / 100); + m_2DPixmap = QPixmap(m_Size.width(), fft_plot_height); m_2DPixmap.fill(Qt::black); int height = (100 - m_Percent2DScreen) * m_Size.height() / 100; - if (m_WaterfallPixmap.isNull()) { + if (m_WaterfallPixmap.isNull()) + { m_WaterfallPixmap = QPixmap(m_Size.width(), height); m_WaterfallPixmap.fill(Qt::black); - } else { + } + else + { m_WaterfallPixmap = m_WaterfallPixmap.scaled(m_Size.width(), height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); @@ -886,9 +889,7 @@ void CPlotter::resizeEvent(QResizeEvent* ) drawOverlay(); } -////////////////////////////////////////////////////////////////////// // Called by QT when screen needs to be redrawn -////////////////////////////////////////////////////////////////////// void CPlotter::paintEvent(QPaintEvent *) { QPainter painter(this); @@ -898,16 +899,13 @@ void CPlotter::paintEvent(QPaintEvent *) m_WaterfallPixmap); } - -////////////////////////////////////////////////////////////////////// // Called to update spectrum data for displaying on the screen -////////////////////////////////////////////////////////////////////// void CPlotter::draw() { - int i, n; - int w; - int h; - int xmin, xmax; + int i, n; + int w; + int h; + int xmin, xmax; if (m_DrawOverlay) { @@ -1048,7 +1046,7 @@ void CPlotter::draw() painter2.drawPolyline(LineBuf, n); } - //Peak detection + // Peak detection if (m_PeakDetection > 0) { m_Peaks.clear(); @@ -1061,28 +1059,30 @@ void CPlotter::draw() sum_of_sq += m_fftbuf[i + xmin] * m_fftbuf[i + xmin]; } mean /= n; - float stdev= sqrt( sum_of_sq/n-mean*mean ); + float stdev= sqrt(sum_of_sq / n - mean * mean ); - int lastPeak=-1; + int lastPeak = -1; for (i = 0; i < n; i++) { //m_PeakDetection times the std over the mean or better than current peak - float d = (lastPeak==-1) ? (mean - m_PeakDetection * stdev) : - m_fftbuf[lastPeak+xmin]; + float d = (lastPeak == -1) ? (mean - m_PeakDetection * stdev) : + m_fftbuf[lastPeak + xmin]; if (m_fftbuf[i + xmin] < d) lastPeak=i; - if (lastPeak != -1 && (i - lastPeak > PEAK_H_TOLERANCE || i == n-1)) + if (lastPeak != -1 && + (i - lastPeak > PEAK_H_TOLERANCE || i == n-1)) { - m_Peaks.insert(lastPeak+xmin, m_fftbuf[lastPeak + xmin]); - painter2.drawEllipse(lastPeak+xmin-5, m_fftbuf[lastPeak + xmin]-5, 10, 10); - lastPeak=-1; + m_Peaks.insert(lastPeak + xmin, m_fftbuf[lastPeak + xmin]); + painter2.drawEllipse(lastPeak + xmin - 5, + m_fftbuf[lastPeak + xmin] - 5, 10, 10); + lastPeak = -1; } } } - //Peak hold + // Peak hold if (m_PeakHoldActive) { for (i = 0; i < n; i++) @@ -1096,7 +1096,7 @@ void CPlotter::draw() painter2.setPen(m_PeakHoldColor); painter2.drawPolyline(LineBuf, n); - m_PeakHoldValid=true; + m_PeakHoldValid = true; } painter2.end(); @@ -1116,7 +1116,6 @@ void CPlotter::draw() */ void CPlotter::setNewFttData(float *fftData, int size) { - /** FIXME **/ if (!m_Running) m_Running = true; @@ -1139,7 +1138,6 @@ void CPlotter::setNewFttData(float *fftData, int size) void CPlotter::setNewFttData(float *fftData, float *wfData, int size) { - /** FIXME **/ if (!m_Running) m_Running = true; @@ -1274,10 +1272,8 @@ void CPlotter::setFftRange(float reflevel, float range) } -////////////////////////////////////////////////////////////////////// // Called to draw an overlay bitmap containing grid and text that // does not need to be recreated every fft data update. -////////////////////////////////////////////////////////////////////// void CPlotter::drawOverlay() { if (m_OverlayPixmap.isNull()) From 353c9d1c4246329675fbb959cb856f030fbc2cd7 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 4 Sep 2016 01:01:06 +0200 Subject: [PATCH 075/334] Right click on FFT resets frequency zoom. --- resources/news.txt | 3 ++- src/qtgui/plotter.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 3f5e9b3..ec88306 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -3,12 +3,13 @@ NEW: 1-2-5 scaling on FFT axis. NEW: Audio waterfall. NEW: Remember AGC settings between sessions. + NEW: Right-click on FFT resets frequency zoom. FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. FIXED: Correct display of negative offsets between -1 and 0 kHz. FIXED: Reset frequency digits below the one that is being changed. - FIXED: LNB LO could not be set from I/O confugration dialog. + FIXED: LNB LO could not be set from I/O configuration dialog. IMPROVED: Input decimator performance. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index 0e5a629..7b5e154 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -696,6 +696,11 @@ void CPlotter::mousePressEvent(QMouseEvent * event) emit newCenterFreq(m_CenterFreq); emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq - m_CenterFreq); } + else if (event->buttons() == Qt::RightButton) + { + // reset frequency zoom + resetHorizontalZoom(); + } } } else @@ -704,7 +709,14 @@ void CPlotter::mousePressEvent(QMouseEvent * event) // get ready for moving Y axis m_Yzero = pt.y(); else if (m_CursorCaptured == XAXIS) + { m_Xzero = pt.x(); + if (event->buttons() == Qt::RightButton) + { + // reset frequency zoom + resetHorizontalZoom(); + } + } else if(m_CursorCaptured == BOOKMARK) { int i; From 537f2c7e05a82017ab62cf21ed471a3d37efc836 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 4 Sep 2016 23:30:06 +0200 Subject: [PATCH 076/334] Add support for Portaudio backend. Allow using portaudio as backend on Linux. Enabled using: qmake AUDIO_BACKEND=portaudio cmake -DLINUX_AUDIO_BACKEND:STRING=Portaudio Enverything else should be as before. This first implementation ignores audio device settings and uses the default audio output at 48 kHz. --- CMakeLists.txt | 16 ++- gqrx.pro | 42 ++++-- src/CMakeLists.txt | 9 +- src/applications/gqrx/main.cpp | 37 +++--- src/applications/gqrx/mainwindow.cpp | 1 + src/applications/gqrx/receiver.cpp | 6 + src/applications/gqrx/receiver.h | 7 +- src/portaudio/CMakeLists.txt | 7 + src/portaudio/device_list.cpp | 5 - src/portaudio/device_list.h | 5 +- src/portaudio/portaudio_sink.cpp | 184 +++++++++++++++++++++++++++ src/portaudio/portaudio_sink.h | 67 ++++++++++ src/pulseaudio/CMakeLists.txt | 13 +- src/qtgui/ioconfig.cpp | 19 ++- src/qtgui/ioconfig.h | 13 +- 15 files changed, 376 insertions(+), 55 deletions(-) create mode 100644 src/portaudio/CMakeLists.txt create mode 100644 src/portaudio/portaudio_sink.cpp create mode 100644 src/portaudio/portaudio_sink.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8903aac..413357c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,18 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") # there is a defect in the pulse audio cmake file that does not include this library. So we add it here. find_library(PULSE-SIMPLE NAMES pulse-simple REQUIRED) add_definitions(-DWITH_PULSEAUDIO) + unset(PORTAUDIO_INCLUDE_DIRS CACHE) + unset(PORTAUDIO_LIBRARIES CACHE) + elseif(${LINUX_AUDIO_BACKEND} MATCHES "Portaudio") + find_package(Portaudio REQUIRED) + add_definitions(-DWITH_PORTAUDIO) + unset(PULSEAUDIO_FOUND CACHE) + unset(PULSEAUDIO_INCLUDE_DIR CACHE) + unset(PULSEAUDIO_LIBRARY CACHE) + unset(PulseAudio_DIR CACHE) + unset(PULSE-SIMPLE CACHE) + unset(PULSEAUDIO_INCLUDE_DIR CACHE) + unset(PULSEAUDIO_MAINLOOP_LIBRARY CACHE) elseif(${LINUX_AUDIO_BACKEND} MATCHES "Gr-audio") unset(PULSEAUDIO_FOUND CACHE) unset(PULSEAUDIO_INCLUDE_DIR CACHE) @@ -129,8 +141,10 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") unset(PULSE-SIMPLE CACHE) unset(PULSEAUDIO_INCLUDE_DIR CACHE) unset(PULSEAUDIO_MAINLOOP_LIBRARY CACHE) + unset(PORTAUDIO_INCLUDE_DIRS CACHE) + unset(PORTAUDIO_LIBRARIES CACHE) else() - message(FATAL_ERROR "Invalid audio backend: should be either Pulseaudio or Gr-audio") + message(FATAL_ERROR "Invalid audio backend: should be either Pulseaudio, Portaudio or Gr-audio") endif() endif() diff --git a/gqrx.pro b/gqrx.pro index c93169a..5711e43 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -28,10 +28,16 @@ macx { CONFIG += link_pkgconfig unix:!macx { - packagesExist(libpulse libpulse-simple) { - # Comment out to use gr-audio (not recommended with ALSA and Funcube Dongle Pro) - AUDIO_BACKEND = pulse - message("Gqrx configured with pulseaudio backend") + equals(AUDIO_BACKEND, "portaudio") { + !packagesExist(portaudio-2.0) { + error(Portaudio backend requires portaudio19-dev package.) + } + } + isEmpty(AUDIO_BACKEND) { + packagesExist(libpulse libpulse-simple) { + # Comment out to use gr-audio + AUDIO_BACKEND = pulseaudio + } } } @@ -203,7 +209,10 @@ FORMS += \ src/qtgui/nb_options.ui # Use pulseaudio (ps: could use equals? undocumented) -contains(AUDIO_BACKEND, pulse): { +equals(AUDIO_BACKEND, "pulseaudio"): { + message("Gqrx configured with pulseaudio backend.") + PKGCONFIG += libpulse libpulse-simple + DEFINES += WITH_PULSEAUDIO HEADERS += \ src/pulseaudio/pa_device_list.h \ src/pulseaudio/pa_sink.h \ @@ -212,20 +221,29 @@ contains(AUDIO_BACKEND, pulse): { src/pulseaudio/pa_device_list.cc \ src/pulseaudio/pa_sink.cc \ src/pulseaudio/pa_source.cc - DEFINES += WITH_PULSEAUDIO +} else { + equals(AUDIO_BACKEND, "portaudio"): { + message("Gqrx configured with portaudio backend.") + PKGCONFIG += portaudio-2.0 + DEFINES += WITH_PORTAUDIO + HEADERS += \ + src/portaudio/device_list.h \ + src/portaudio/portaudio_sink.h + SOURCES += \ + src/portaudio/device_list.cpp \ + src/portaudio/portaudio_sink.cpp + } else { + message("Gqrx configured with gnuradio-audio backend.") + PKGCONFIG += gnuradio-audio + } } macx { + # FIXME: Merge into previous one HEADERS += src/osxaudio/device_list.h SOURCES += src/osxaudio/device_list.cpp } -contains(AUDIO_BACKEND, pulse): { - PKGCONFIG += libpulse libpulse-simple -} else { - PKGCONFIG += gnuradio-audio -} - PKGCONFIG += gnuradio-analog \ gnuradio-blocks \ gnuradio-digital \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 54fd285..c707f11 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,8 +10,12 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") add_subdirectory(osxaudio) add_definitions(-DGQRX_OS_MACX) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9) -elseif((${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (${LINUX_AUDIO_BACKEND} MATCHES "Pulseaudio")) - add_subdirectory(pulseaudio) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + if(${LINUX_AUDIO_BACKEND} MATCHES "Pulseaudio") + add_subdirectory(pulseaudio) + elseif(${LINUX_AUDIO_BACKEND} MATCHES "Portaudio") + add_subdirectory(portaudio) + endif() elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") endif() @@ -59,6 +63,7 @@ target_link_libraries(${PROJECT_NAME} ${GNURADIO_OSMOSDR_LIBRARIES} ${PULSEAUDIO_LIBRARY} ${PULSE-SIMPLE} + ${PORTAUDIO_LIBRARIES} ) #build a win32 app, not a console app diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index bbe2e41..6e466ae 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -29,6 +29,10 @@ #include #include +#ifdef WITH_PORTAUDIO +#include +#endif + #include "mainwindow.h" #include "gqrx.h" @@ -41,10 +45,11 @@ static void list_conf(void); int main(int argc, char *argv[]) { - QString cfg_file; - std::string conf; - bool clierr=false; - bool edit_conf = false; + QString cfg_file; + std::string conf; + bool clierr = false; + bool edit_conf = false; + int return_code; QApplication a(argc, argv); QCoreApplication::setOrganizationName(GQRX_ORG_NAME); @@ -60,15 +65,11 @@ int main(int argc, char *argv[]) else qDebug() << "Failed to disable controlport"; -#if 0 -//#ifdef WITH_PORTAUDIO - // FIXME: This should be user configurable although for now - // the audio-osx-source is useless and the only way to use the - // Funcube Dongle Pro and Pro+ is via portaudio. - if (qputenv("GR_CONF_AUDIO_AUDIO_MODULE", "portaudio")) - qDebug() << "GR_CONF_AUDIO_AUDIO_MODULE set to portaudio"; - else - qDebug() << "Failed to set GR_CONF_AUDIO_AUDIO_MODULE=portaudio"; +#ifdef WITH_PORTAUDIO + PaError err = Pa_Initialize(); + if (err != paNoError) + qCritical() << "Failed to initialize Portaudio backend:" + << Pa_GetErrorText(err); #endif // setup the program options @@ -137,12 +138,18 @@ int main(int argc, char *argv[]) if (w.configOk) { w.show(); - return a.exec(); + return_code = a.exec(); } else { - return 1; + return_code = 1; } + +#ifdef WITH_PORTAUDIO + Pa_Terminate(); +#endif + + return return_code; } /*! \brief Reset configuration file specified by file_name. */ diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 51363a4..f50238a 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include "qtgui/ioconfig.h" diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 208119a..4ca7336 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -44,6 +44,8 @@ #ifdef WITH_PULSEAUDIO #include "pulseaudio/pa_sink.h" +#elif WITH_PORTAUDIO +#include "portaudio/portaudio_sink.h" #else #include #endif @@ -135,6 +137,8 @@ receiver::receiver(const std::string input_device, #ifdef WITH_PULSEAUDIO audio_snk = make_pa_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); +#elif WITH_PORTAUDIO + audio_snk = make_portaudio_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); #else audio_snk = gr::audio::sink::make(d_audio_rate, audio_device, true); #endif @@ -274,6 +278,8 @@ void receiver::set_output_device(const std::string device) #ifdef WITH_PULSEAUDIO audio_snk = make_pa_sink(device, d_audio_rate, "GQRX", "Audio output"); +#elif WITH_PORTAUDIO + audio_snk = make_portaudio_sink(device, d_audio_rate, "GQRX", "Audio output"); #else audio_snk = gr::audio::sink::make(d_audio_rate, device, true); #endif diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index a9e7d80..0df430d 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -49,7 +49,9 @@ #include "receivers/receiver_base.h" #ifdef WITH_PULSEAUDIO -#include +#include "pulseaudio/pa_sink.h" +#elif WITH_PORTAUDIO +#include "portaudio/portaudio_sink.h" #else #include #endif @@ -58,7 +60,6 @@ * @defgroup DSP Digital signal processing library based on GNU Radio */ - /** * @brief Top-level receiver class. * @ingroup DSP @@ -269,6 +270,8 @@ class receiver #ifdef WITH_PULSEAUDIO pa_sink_sptr audio_snk; /*!< Pulse audio sink. */ +#elif WITH_PORTAUDIO + portaudio_sink_sptr audio_snk; /*!< portaudio sink */ #else gr::audio::sink::sptr audio_snk; /*!< gr audio sink */ #endif diff --git a/src/portaudio/CMakeLists.txt b/src/portaudio/CMakeLists.txt new file mode 100644 index 0000000..0914164 --- /dev/null +++ b/src/portaudio/CMakeLists.txt @@ -0,0 +1,7 @@ +# Add the source files to SRCS_LIST +add_source_files(SRCS_LIST + device_list.cpp + device_list.h + portaudio_sink.cpp + portaudio_sink.h +) diff --git a/src/portaudio/device_list.cpp b/src/portaudio/device_list.cpp index 5437177..70978da 100644 --- a/src/portaudio/device_list.cpp +++ b/src/portaudio/device_list.cpp @@ -58,8 +58,6 @@ int portaudio_device_list::populate_device_list() const PaDeviceInfo *dev_info; PaError err; - Pa_Initialize(); - std::cout << Pa_GetVersionText() << " (version " << Pa_GetVersion() << ")" << std::endl; num_dev = Pa_GetDeviceCount(); @@ -92,16 +90,13 @@ int portaudio_device_list::populate_device_list() } } - Pa_Terminate(); return 0; error: - Pa_Terminate(); std::cerr << "An error occured while using the portaudio stream" << std::endl; std::cerr << "Error number: " << err << std::endl; std::cerr << "Error message: " << Pa_GetErrorText(err) << std::endl; return err; - } diff --git a/src/portaudio/device_list.h b/src/portaudio/device_list.h index 1539e92..328990c 100644 --- a/src/portaudio/device_list.h +++ b/src/portaudio/device_list.h @@ -20,8 +20,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#ifndef PORTAUDIO_DEVICE_LIST_H -#define PORTAUDIO_DEVICE_LIST_H +#pragma once #include #include #include @@ -72,5 +71,3 @@ class portaudio_device_list void add_sink(unsigned int idx, string name, string desc); void add_source(unsigned int idx, string name, string desc); }; - -#endif // PORTAUDIO_DEVICE_LIST_H diff --git a/src/portaudio/portaudio_sink.cpp b/src/portaudio/portaudio_sink.cpp new file mode 100644 index 0000000..6f3f2ce --- /dev/null +++ b/src/portaudio/portaudio_sink.cpp @@ -0,0 +1,184 @@ +/* -*- c++ -*- */ +/* + * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt + * http://gqrx.dk/ + * + * Copyright 2016 Alexandru Csete OZ9AEC. + * + * Gqrx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Gqrx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Gqrx; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "portaudio_sink.h" + +/** + * Create a new portaudio sink object. + * @param device_name The name of the audio device, or NULL for default. + * @param audio_rate The sample rate of the audio stream. + * @param app_name Application name. + * @param stream_name The audio stream name. + */ +portaudio_sink_sptr make_portaudio_sink(const string device_name, int audio_rate, + const string app_name, + const string stream_name) +{ + return gnuradio::get_initial_sptr(new portaudio_sink(device_name, audio_rate, + app_name, stream_name)); +} + +portaudio_sink::portaudio_sink(const string device_name, int audio_rate, + const string app_name, const string stream_name) + : gr::sync_block ("portaudio_sink", + gr::io_signature::make (1, 2, sizeof(float)), + gr::io_signature::make (0, 0, 0)), + d_stream_name(stream_name), + d_app_name(app_name), + d_audio_rate(audio_rate) +{ + // FIXME: find device index based on device_name + fprintf(stderr, + "*** FIXME: %s: Requested audio device is %s but we are using default\n", + __func__, device_name.data()); + + // Initialize stream parmaeters + d_out_params.device = Pa_GetDefaultOutputDevice(); + d_out_params.channelCount = 2; + d_out_params.sampleFormat = paFloat32; + d_out_params.suggestedLatency = + Pa_GetDeviceInfo(d_out_params.device)->defaultHighOutputLatency; + d_out_params.hostApiSpecificStreamInfo = NULL; + + if (Pa_IsFormatSupported(NULL, &d_out_params, d_audio_rate) != paFormatIsSupported) + fprintf(stderr, + "%s: Audio output device does not support requested format.\n", + __func__); + else + fprintf(stderr, "HELLO WORKLD\n"); +} + +portaudio_sink::~portaudio_sink() +{ + // nothing to do +} + +/* open and start audio stream */ +bool portaudio_sink::start() +{ + PaError err; + + err = Pa_OpenStream(&d_stream, + NULL, // inputParameters + &d_out_params, + d_audio_rate, + paFramesPerBufferUnspecified, + paClipOff, + NULL, // no callback, use blocking API + NULL); + + if (err != paNoError) + { + fprintf(stderr, "%s: Failed to open audio stream: %s\n", __FILE__, + Pa_GetErrorText(err)); + return false; + } + + err = Pa_StartStream(d_stream); + if (err != paNoError) + { + fprintf(stderr, "%s: Failed to start audio stream: %s\n", __FILE__, + Pa_GetErrorText(err)); + return false; + } + + return true; +} + +/* Stop and close audio stream */ +bool portaudio_sink::stop() +{ + PaError err; + bool retval = true; + + err = Pa_StopStream(d_stream); + if (err != paNoError) + { + retval = false; + fprintf(stderr, "%s: Error stopping audio stream: %s\n", __FILE__, + Pa_GetErrorText(err)); + } + + err = Pa_CloseStream(d_stream); + if (err != paNoError) + { + retval = false; + fprintf(stderr, "%s: Error closing audio stream: %s\n", __FILE__, + Pa_GetErrorText(err)); + } + + return retval; +} + +void portaudio_sink::select_device(string device_name) +{ + +} + +#define BUFFER_SIZE 100000 +int portaudio_sink::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + PaError err; + + static float audio_buffer[BUFFER_SIZE]; + float *ptr = &audio_buffer[0]; + int i; + + (void) output_items; + + if (noutput_items > BUFFER_SIZE/2) + noutput_items = BUFFER_SIZE/2; + + if (input_items.size() == 2) + { + // two channels (stereo) + const float *data_l = (const float*) input_items[0]; // left channel + const float *data_r = (const float*) input_items[1]; // right channel + for (i = noutput_items; i > 0; i--) + { + *ptr++ = *data_l++; + *ptr++ = *data_r++; + } + } + else + { + // assume 1 channel (mono) + const float *data = (const float*) input_items[0]; + for (i = noutput_items; i > 0; i--) + { + float a = *data++; + *ptr++ = a; // same data in left and right channel + *ptr++ = a; + } + } + + err = Pa_WriteStream(d_stream, audio_buffer, noutput_items); + if (err) + fprintf(stderr, "Error writing to audio device: %s\n", Pa_GetErrorText(err)); + + return noutput_items; +} diff --git a/src/portaudio/portaudio_sink.h b/src/portaudio/portaudio_sink.h new file mode 100644 index 0000000..bf7b83b --- /dev/null +++ b/src/portaudio/portaudio_sink.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt + * http://gqrx.dk/ + * + * Copyright 2016 Alexandru Csete OZ9AEC. + * + * Gqrx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Gqrx is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Gqrx; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#pragma once + +#include +#include +#include + +using namespace std; + +class portaudio_sink; + +typedef boost::shared_ptr portaudio_sink_sptr; + +portaudio_sink_sptr make_portaudio_sink(const string device_name, int audio_rate, + const string app_name, + const string stream_name); + +/** Two-channel portaudio sink */ +class portaudio_sink : public gr::sync_block +{ + friend portaudio_sink_sptr make_portaudio_sink(const string device_name, + int audio_rate, + const string app_name, + const string stream_name); + +public: + portaudio_sink(const string device_name, int audio_rate, + const string app_name, const string stream_name); + ~portaudio_sink(); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + bool start(); + bool stop(); + + void select_device(string device_name); + +private: + PaStream *d_stream; + PaStreamParameters d_out_params; + string d_stream_name; // Descriptive name of the stream. + string d_app_name; // Descriptive name of the applcation. + int d_audio_rate; +}; diff --git a/src/pulseaudio/CMakeLists.txt b/src/pulseaudio/CMakeLists.txt index d129ecd..7025b18 100644 --- a/src/pulseaudio/CMakeLists.txt +++ b/src/pulseaudio/CMakeLists.txt @@ -1,10 +1,9 @@ -####################################################################################################################### # Add the source files to SRCS_LIST add_source_files(SRCS_LIST - pa_device_list.cc - pa_device_list.h - pa_sink.cc - pa_sink.h - pa_source.cc - pa_source.h + pa_device_list.cc + pa_device_list.h + pa_sink.cc + pa_sink.h + pa_source.cc + pa_source.h ) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 2930c8b..4d825bc 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -36,6 +36,8 @@ #ifdef WITH_PULSEAUDIO #include "pulseaudio/pa_device_list.h" +#elif WITH_PORTAUDIO +#include "portaudio/device_list.h" #elif defined(GQRX_OS_MACX) #include "osxaudio/device_list.h" #endif @@ -119,8 +121,8 @@ CIoConfig::CIoConfig(QSettings * settings, // Output device QString outdev = settings->value("output/device", "").toString(); + // get list of audio output devices #ifdef WITH_PULSEAUDIO - // get list of output devices pa_device_list devices; outDevList = devices.get_output_devices(); @@ -136,9 +138,22 @@ CIoConfig::CIoConfig(QSettings * settings, if (outdev == QString(outDevList[i].get_name().c_str())) ui->outDevCombo->setCurrentIndex(i+1); } +#elif WITH_PORTAUDIO + portaudio_device_list devices; + + outDevList = devices.get_output_devices(); + for (i = 0; i < outDevList.size(); i++) + { + ui->outDevCombo->addItem(QString(outDevList[i].get_description().c_str())); + + // note that item #i in devlist will be item #(i+1) + // in combo box due to "default" + if (outdev == QString(outDevList[i].get_name().c_str())) + ui->outDevCombo->setCurrentIndex(i+1); + } + //ui->outDevCombo->setEditable(true); #elif defined(GQRX_OS_MACX) - // get list of output devices osxaudio_device_list devices; outDevList = devices.get_output_devices(); diff --git a/src/qtgui/ioconfig.h b/src/qtgui/ioconfig.h index 912f0b4..004dd28 100644 --- a/src/qtgui/ioconfig.h +++ b/src/qtgui/ioconfig.h @@ -29,6 +29,8 @@ #ifdef WITH_PULSEAUDIO #include "pulseaudio/pa_device_list.h" +#elif WITH_PORTAUDIO +#include "portaudio/device_list.h" #elif defined(GQRX_OS_MACX) #include "osxaudio/device_list.h" #endif @@ -62,14 +64,15 @@ private slots: int decim2idx(int decim) const; private: - Ui::CIoConfig *ui; - - QSettings *m_settings; + Ui::CIoConfig *ui; + QSettings *m_settings; #ifdef WITH_PULSEAUDIO - vector outDevList; + vector outDevList; +#elif WITH_PORTAUDIO + vector outDevList; #elif defined(GQRX_OS_MACX) - vector outDevList; + vector outDevList; #endif }; From 03caf6553a39e703344dfd5c62d3ad4e8aad0c10 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 6 Sep 2016 23:05:09 +0200 Subject: [PATCH 077/334] Make RDS enable/disable widget more clear. --- src/qtgui/dockrds.cpp | 2 -- src/qtgui/dockrds.ui | 61 +++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/qtgui/dockrds.cpp b/src/qtgui/dockrds.cpp index 8aeaf52..eaf4a76 100644 --- a/src/qtgui/dockrds.cpp +++ b/src/qtgui/dockrds.cpp @@ -81,12 +81,10 @@ void DockRDS::updateRDS(QString text, int type) void DockRDS::showEnabled() { - ui->rdsCheckbox->setText("Enabled"); } void DockRDS::showDisabled() { - ui->rdsCheckbox->setText("Disabled"); ui->program_information->setText(""); ui->station_name->setText(""); ui->program_type->setText(""); diff --git a/src/qtgui/dockrds.ui b/src/qtgui/dockrds.ui index 7e0a531..1a2e4ff 100644 --- a/src/qtgui/dockrds.ui +++ b/src/qtgui/dockrds.ui @@ -59,7 +59,7 @@ 0 0 205 - 195 + 201 @@ -70,46 +70,17 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - 0 + 5 - 0 + 5 - 0 + 5 - 0 + 5 - - - - RDS Status: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - true - - - Qt::StrongFocus - - - Disabled - - - @@ -319,6 +290,28 @@ + + + + + 0 + 0 + + + + true + + + Qt::StrongFocus + + + Enable or disable decoding of RDS data + + + Enable RDS + + + From d6a1dc69cc8ad3d9f97423dd8d19dc36baf70579 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 6 Sep 2016 23:18:44 +0200 Subject: [PATCH 078/334] Coding style clean-up. --- src/qtgui/dockrds.cpp | 69 +++++++++++++++++++++++++------------------ src/qtgui/dockrds.h | 12 ++++---- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/qtgui/dockrds.cpp b/src/qtgui/dockrds.cpp index eaf4a76..aacbe0c 100644 --- a/src/qtgui/dockrds.cpp +++ b/src/qtgui/dockrds.cpp @@ -34,7 +34,7 @@ DockRDS::DockRDS(QWidget *parent) : #if QT_VERSION >= 0x050200 ui->scrollArea->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow); #endif - } +} DockRDS::~DockRDS() { @@ -43,39 +43,53 @@ DockRDS::~DockRDS() void DockRDS::updateRDS(QString text, int type) { + std::string str, out; + /* type 0 = PI * type 1 = PS * type 2 = PTY * type 3 = flagstring: TP, TA, MuSp, MoSt, AH, CMP, stPTY * type 4 = RadioText * type 5 = ClockTime - * type 6 = Alternative Frequencies */ - - if (type==0) { + * type 6 = Alternative Frequencies + */ + switch (type) + { + case 0: ui->program_information->setText(text); - } else if (type==1) { + break; + case 1: ui->station_name->setText(text); - } else if (type==2) { + break; + case 2: ui->program_type->setText(text); - } else if (type==3) { - std::string str = text.toStdString(); - std::string out=""; - if (str.at(0)=='1') out.append("TP "); - if (str.at(1)=='1') out.append("TA "); - if (str.at(2)=='0') out.append("Speech "); - if (str.at(2)=='1') out.append("Music "); - if (str.at(3)=='0') out.append("Stereo "); - if (str.at(3)=='1') out.append("Mono "); - if (str.at(4)=='1') out.append("AH "); - if (str.at(5)=='1') out.append("CMP "); - if (str.at(6)=='1') out.append("stPTY "); + break; + case 3: + str = text.toStdString(); + out = ""; + if (str.at(0) == '1') out.append("TP "); + if (str.at(1) == '1') out.append("TA "); + if (str.at(2) == '0') out.append("Speech "); + if (str.at(2) == '1') out.append("Music "); + if (str.at(3) == '0') out.append("Stereo "); + if (str.at(3) == '1') out.append("Mono "); + if (str.at(4) == '1') out.append("AH "); + if (str.at(5) == '1') out.append("CMP "); + if (str.at(6) == '1') out.append("stPTY "); ui->flags->setText(QString::fromStdString(out)); - } else if (type==4) { + break; + case 4: ui->radiotext->setText(text); - } else if (type==5) { + break; + case 5: ui->clocktime->setText(text); - } else if (type==6) { + break; + case 6: ui->alt_freq->setText(text); + break; + default: + // nothing to do + break; } } @@ -96,19 +110,18 @@ void DockRDS::showDisabled() void DockRDS::setDisabled() { - ui->rdsCheckbox->setDisabled(true); - - ui->rdsCheckbox->blockSignals(true); - ui->rdsCheckbox->setChecked(false); - ui->rdsCheckbox->blockSignals(false); + ui->rdsCheckbox->setDisabled(true); + ui->rdsCheckbox->blockSignals(true); + ui->rdsCheckbox->setChecked(false); + ui->rdsCheckbox->blockSignals(false); } void DockRDS::setEnabled() { - ui->rdsCheckbox->setDisabled(false); + ui->rdsCheckbox->setDisabled(false); } -/*! \brief Enable/disable RDS decoder */ +/** Enable/disable RDS decoder */ void DockRDS::on_rdsCheckbox_toggled(bool checked) { emit rdsDecoderToggled(checked); diff --git a/src/qtgui/dockrds.h b/src/qtgui/dockrds.h index b7bbd86..fc67c70 100644 --- a/src/qtgui/dockrds.h +++ b/src/qtgui/dockrds.h @@ -17,11 +17,11 @@ class DockRDS : public QDockWidget ~DockRDS(); public slots: - void updateRDS(QString text, int type); - void showEnabled(); - void showDisabled(); - void setEnabled(); - void setDisabled(); + void updateRDS(QString text, int type); + void showEnabled(); + void showDisabled(); + void setEnabled(); + void setDisabled(); private: @@ -29,7 +29,7 @@ public slots: void rdsDecoderToggled(bool); private slots: - void on_rdsCheckbox_toggled(bool checked); + void on_rdsCheckbox_toggled(bool checked); private: Ui::DockRDS *ui; /*! The Qt designer UI file. */ From cb683ccf30a033e877a6ccea1f85d8cf95db1407 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 6 Sep 2016 23:42:23 +0200 Subject: [PATCH 079/334] Add info about using portaudi backend with qmake. --- gqrx.pro | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gqrx.pro b/gqrx.pro index 5711e43..ede4467 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -4,9 +4,10 @@ # # Common options you may want to passs to qmake: # -# CONFIG+=debug Enable debug mode -# PREFIX=/some/prefix Installation prefix -# BOOST_SUFFIX=-mt To link against libboost-xyz-mt (needed for pybombs) +# AUDIO_BACKEND=portaudio Use portaudio backend +# CONFIG+=debug Enable debug mode +# PREFIX=/some/prefix Installation prefix +# BOOST_SUFFIX=-mt To link against libboost-xyz-mt (needed for pybombs) #-------------------------------------------------------------------------------- QT += core gui network From e6baca04a918d1ac178d94ec044fa8694a327f63 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 6 Sep 2016 23:56:08 +0200 Subject: [PATCH 080/334] Disable single channel audio sink code. We only use 2 channel audio streams at the moment. --- src/portaudio/portaudio_sink.cpp | 36 +++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/portaudio/portaudio_sink.cpp b/src/portaudio/portaudio_sink.cpp index 6f3f2ce..522fde9 100644 --- a/src/portaudio/portaudio_sink.cpp +++ b/src/portaudio/portaudio_sink.cpp @@ -32,12 +32,15 @@ * @param app_name Application name. * @param stream_name The audio stream name. */ -portaudio_sink_sptr make_portaudio_sink(const string device_name, int audio_rate, - const string app_name, - const string stream_name) +portaudio_sink_sptr make_portaudio_sink(const string device_name, + int audio_rate, + const string app_name, + const string stream_name) { - return gnuradio::get_initial_sptr(new portaudio_sink(device_name, audio_rate, - app_name, stream_name)); + return gnuradio::get_initial_sptr(new portaudio_sink(device_name, + audio_rate, + app_name, + stream_name)); } portaudio_sink::portaudio_sink(const string device_name, int audio_rate, @@ -153,6 +156,23 @@ int portaudio_sink::work(int noutput_items, if (noutput_items > BUFFER_SIZE/2) noutput_items = BUFFER_SIZE/2; + // two channels (stereo) + const float *data_l = (const float*) input_items[0]; + const float *data_r = (const float*) input_items[1]; + for (i = noutput_items; i > 0; i--) + { + *ptr++ = *data_l++; + *ptr++ = *data_r++; + } + + err = Pa_WriteStream(d_stream, audio_buffer, noutput_items); + if (err) + fprintf(stderr, "Error writing to audio device: %s\n", Pa_GetErrorText(err)); + + return noutput_items; + +// code below supports 1 or 2 channels +#if 0 if (input_items.size() == 2) { // two channels (stereo) @@ -175,10 +195,6 @@ int portaudio_sink::work(int noutput_items, *ptr++ = a; } } +#endif - err = Pa_WriteStream(d_stream, audio_buffer, noutput_items); - if (err) - fprintf(stderr, "Error writing to audio device: %s\n", Pa_GetErrorText(err)); - - return noutput_items; } From 4900479161c7b06a71e4ac41f63b15fb69b04577 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 7 Sep 2016 00:03:16 +0200 Subject: [PATCH 081/334] Ensure frequency axis is redrawn when using mid button click. --- src/qtgui/plotter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index 7b5e154..a116605 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -695,6 +695,7 @@ void CPlotter::mousePressEvent(QMouseEvent * event) m_DemodCenterFreq = m_CenterFreq; emit newCenterFreq(m_CenterFreq); emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq - m_CenterFreq); + drawOverlay(); } else if (event->buttons() == Qt::RightButton) { From 2ea2ba925a79fffd5a077bb961e0bf24f00f0102 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 7 Sep 2016 00:19:04 +0200 Subject: [PATCH 082/334] Code clean-up in plotter widget. --- src/qtgui/plotter.cpp | 42 ++++++++---------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index a116605..b6d43ce 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -401,10 +401,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) { setFftCenterFreq(m_FftCenter + delta_hz); } - if (m_Running) - m_DrawOverlay = true; - else - drawOverlay(); + updateOverlay(); m_PeakHoldValid = false; @@ -459,10 +456,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) clampDemodParameters(); emit newFilterFreq(m_DemodLowCutFreq, m_DemodHiCutFreq); - if (m_Running) - m_DrawOverlay = true; // schedule update of overlay during draw() - else - drawOverlay(); // not running so update oiverlay now + updateOverlay(); } else { //save initial grab postion from m_DemodFreqX @@ -483,12 +477,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) { m_DemodCenterFreq = roundFreq(freqFromX(pt.x()-m_GrabPosition), m_ClickResolution ); emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); - - if (m_Running) - m_DrawOverlay = true; // schedule update of overlay during draw() - else - drawOverlay(); // not running so update oiverlay now - + updateOverlay(); m_PeakHoldValid = false; } else @@ -855,10 +844,7 @@ void CPlotter::wheelEvent(QWheelEvent * event) emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); } - if (m_Running) - m_DrawOverlay = true; - else - drawOverlay(); + updateOverlay(); } // Called when screen size changes so must recalculate bitmaps @@ -1267,12 +1253,7 @@ void CPlotter::setMinMaxDB(float min, float max) { m_MaxdB = max; m_MindB = min; - - if (m_Running) - m_DrawOverlay = true; - else - drawOverlay(); - + updateOverlay(); m_PeakHoldValid = false; } @@ -1284,7 +1265,6 @@ void CPlotter::setFftRange(float reflevel, float range) setMinMaxDB(reflevel - range, reflevel); } - // Called to draw an overlay bitmap containing grid and text that // does not need to be recreated every fft data update. void CPlotter::drawOverlay() @@ -1611,11 +1591,7 @@ void CPlotter::setDemodRanges(int FLowCmin, int FLowCmax, int FHiCmin, int FHiCm m_FHiCmax=FHiCmax; m_symetric=symetric; clampDemodParameters(); - - if (m_Running) - m_DrawOverlay = true; - else - drawOverlay(); + updateOverlay(); } void CPlotter::setCenterFreq(quint64 f) @@ -1633,6 +1609,7 @@ void CPlotter::setCenterFreq(quint64 f) m_PeakHoldValid = false; } +// Ensure overlay is updated by either scheduling or forcing a redraw void CPlotter::updateOverlay() { if (m_Running) @@ -1664,10 +1641,7 @@ void CPlotter::moveToCenterFreq(void) void CPlotter::moveToDemodFreq(void) { setFftCenterFreq(m_DemodCenterFreq-m_CenterFreq); - if (m_Running) - m_DrawOverlay = true; - else - drawOverlay(); + updateOverlay(); m_PeakHoldValid = false; } From b40b2dfbb20335216795d7f759ceb70c835ff78c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 11 Sep 2016 15:29:21 +0200 Subject: [PATCH 083/334] Build option to use custom FIR kernels in Airspy. --- CMakeLists.txt | 19 ++++++++----------- src/applications/gqrx/receiver.cpp | 5 +++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 413357c..3a12f56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 2.8.0) -####################################################################################################################### # Project name project(gqrx) set(${PROJECT_NAME}_MAJOR "2") @@ -74,7 +73,6 @@ if(MSVC) endif() endif() -####################################################################################################################### # Functions & macros. These must be defined before including subdirectories. # function to collect all the sources from sub-directories @@ -99,7 +97,6 @@ function(add_source_files list) endfunction(add_source_files) -####################################################################################################################### # 3rd Party Dependency Stuff find_package(Qt5 COMPONENTS Core Network Widgets REQUIRED) find_package(Boost COMPONENTS system program_options REQUIRED) @@ -148,12 +145,19 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif() endif() + +# Airspy optimizations that require modified gr-osmosdr +option(CUSTOM_AIRSPY_KERNELS "Enable non-standard Airspy optimizations" OFF) +if(CUSTOM_AIRSPY_KERNELS) + add_definitions(-DCUSTOM_AIRSPY_KERNELS) +endif(CUSTOM_AIRSPY_KERNELS) + + # Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) -####################################################################################################################### # Finish configuring compiler / linker settings & flags include_directories( ${CMAKE_SOURCE_DIR}/include @@ -167,16 +171,9 @@ link_directories( ) - -####################################################################################################################### # Add subdirectories add_subdirectory(src) -####################################################################################################################### -# enable testing - must be in the top level CMakeLists.txt file -# enable_testing() - - # uninstall target # https://cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F configure_file( diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 4ca7336..f703f50 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -415,6 +415,11 @@ unsigned int receiver::set_input_decim(unsigned int decim) tb->connect(src, 0, iq_swap, 0); } +#ifdef CUSTOM_AIRSPY_KERNELS + if (input_devstr.find("airspy") != string::npos) + src->set_bandwidth(d_quad_rate); +#endif + if (d_running) tb->start(); From 24b6a7cf691b85af87ddfdcaec53cc4f9839eeb0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 11 Sep 2016 17:30:24 +0200 Subject: [PATCH 084/334] Remove old debug print. --- src/portaudio/portaudio_sink.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/portaudio/portaudio_sink.cpp b/src/portaudio/portaudio_sink.cpp index 522fde9..8c1b9a3 100644 --- a/src/portaudio/portaudio_sink.cpp +++ b/src/portaudio/portaudio_sink.cpp @@ -69,8 +69,6 @@ portaudio_sink::portaudio_sink(const string device_name, int audio_rate, fprintf(stderr, "%s: Audio output device does not support requested format.\n", __func__); - else - fprintf(stderr, "HELLO WORKLD\n"); } portaudio_sink::~portaudio_sink() From 12c5f977df5a78b2f0ee8bb6c54bf4598524b575 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 11 Sep 2016 18:22:45 +0200 Subject: [PATCH 085/334] Improve layout of audio gain label. --- src/qtgui/dockaudio.cpp | 2 +- src/qtgui/dockaudio.ui | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 24276d9..700f20d 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -168,7 +168,7 @@ void DockAudio::on_audioGainSlider_valueChanged(int value) float gain = float(value) / 10.0; // update dB label - ui->audioGainDbLabel->setText(QString("%1 dB").arg(gain)); + ui->audioGainDbLabel->setText(QString("%1 dB").arg(gain, 5, 'f', 1)); emit audioGainChanged(gain); } diff --git a/src/qtgui/dockaudio.ui b/src/qtgui/dockaudio.ui index 66b71e5..52af0b6 100644 --- a/src/qtgui/dockaudio.ui +++ b/src/qtgui/dockaudio.ui @@ -79,7 +79,7 @@ - + 0 0 @@ -95,7 +95,7 @@ - + 0 0 @@ -135,7 +135,7 @@ - -20 dB + -20.0 dB Qt::AlignCenter From 3c819a15607dd0fcf7ba83e76810059539d2d287 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 11 Sep 2016 21:59:03 +0200 Subject: [PATCH 086/334] Don't update plotter if width or height is zero. --- src/qtgui/plotter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index b6d43ce..f162709 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -922,7 +922,7 @@ void CPlotter::draw() h = m_WaterfallPixmap.height(); // no need to draw if pixmap is invisible - if ((w != 0) || (h != 0)) + if (w != 0 && h != 0) { quint64 tnow_ms = time_ms(); @@ -990,7 +990,7 @@ void CPlotter::draw() w = m_2DPixmap.width(); h = m_2DPixmap.height(); - if ((w != 0) || (h != 0)) + if (w != 0 && h != 0) { // first copy into 2Dbitmap the overlay bitmap. m_2DPixmap = m_OverlayPixmap.copy(0,0,w,h); From ec3520622d27f347cb6fb19fe056492bc09c7e1a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 11 Sep 2016 22:10:32 +0200 Subject: [PATCH 087/334] Only update audio FFT if widget is visible. --- src/applications/gqrx/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index f50238a..6b829b8 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1259,7 +1259,7 @@ void MainWindow::audioFftTimeout() float pwr_scale; std::complex pt; /* a single FFT point used in calculations */ - if (!d_have_audio) + if (!d_have_audio || !uiDockAudio->isVisible()) return; rx->get_audio_fft_data(d_fftData, fftsize); From 2d5f6b822876d1ffa7fd0b33780d18b611a3bf2b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 12 Sep 2016 00:24:21 +0200 Subject: [PATCH 088/334] Audio resampler optimizations. Only create audio resampler if the audio rate and the output rate are different. --- src/receivers/nbrx.cpp | 76 +++++++++++++++++++++++++++------ src/receivers/nbrx.h | 4 +- src/receivers/receiver_base.cpp | 1 - src/receivers/receiver_base.h | 2 +- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index 98415ee..c698744 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -24,8 +24,8 @@ #include #include "receivers/nbrx.h" -#define PREF_QUAD_RATE 48000.0 -#define PREF_AUDIO_RATE 48000.0 +#define PREF_QUAD_RATE 48000.f +#define PREF_AUDIO_RATE 48000.f nbrx_sptr make_nbrx(float quad_rate, float audio_rate) { @@ -49,24 +49,35 @@ nbrx::nbrx(float quad_rate, float audio_rate) demod_ssb = gr::blocks::complex_to_real::make(1); demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, PREF_AUDIO_RATE, 5000.0, 75.0e-6); demod_am = make_rx_demod_am(PREF_QUAD_RATE, PREF_AUDIO_RATE, true); - audio_rr = make_resampler_ff(d_audio_rate/PREF_AUDIO_RATE); + audio_rr = 0; + if (d_audio_rate != PREF_AUDIO_RATE) + { + std::cout << "Resampling audio " << PREF_AUDIO_RATE << " -> " + << d_audio_rate << std::endl; + audio_rr = make_resampler_ff(d_audio_rate/PREF_AUDIO_RATE); + } + + demod = demod_fm; connect(self(), 0, iq_resamp, 0); connect(iq_resamp, 0, nb, 0); connect(nb, 0, filter, 0); connect(filter, 0, meter, 0); connect(filter, 0, sql, 0); connect(sql, 0, agc, 0); - connect(agc, 0, demod_fm, 0); - connect(demod_fm, 0, audio_rr, 0); - connect(audio_rr, 0, self(), 0); // left channel - connect(audio_rr, 0, self(), 1); // right channel - // FIXME: we only need audio_rr when audio_rate != PREF_AUDIO_RATE - -} + connect(agc, 0, demod, 0); -nbrx::~nbrx() -{ + if (audio_rr) + { + connect(demod, 0, audio_rr, 0); + connect(audio_rr, 0, self(), 0); // left channel + connect(audio_rr, 0, self(), 1); // right channel + } + else + { + connect(demod, 0, self(), 0); + connect(demod, 0, self(), 1); + } } @@ -194,7 +205,7 @@ void nbrx::set_demod(int rx_demod) // for now we must depend on top level stop/lock // because of https://github.com/csete/gqrx/issues/120 //lock(); - +#if 0 /* disconnect current demodulator */ switch (current_demod) { @@ -244,6 +255,45 @@ void nbrx::set_demod(int rx_demod) connect(demod_fm, 0, audio_rr, 0); break; } +#endif + + disconnect(agc, 0, demod, 0); + if (audio_rr) + disconnect(demod, 0, audio_rr, 0); + else + { + disconnect(demod, 0, self(), 0); + disconnect(demod, 0, self(), 1); + } + + switch (rx_demod) { + + case NBRX_DEMOD_NONE: /** FIXME! **/ + case NBRX_DEMOD_SSB: + d_demod = NBRX_DEMOD_SSB; + demod = demod_ssb; + break; + + case NBRX_DEMOD_AM: + d_demod = NBRX_DEMOD_AM; + demod = demod_am; + break; + + case NBRX_DEMOD_FM: + default: + d_demod = NBRX_DEMOD_FM; + demod = demod_fm; + break; + } + + connect(agc, 0, demod, 0); + if (audio_rr) + connect(demod, 0, audio_rr, 0); + else + { + connect(demod, 0, self(), 0); + connect(demod, 0, self(), 1); + } /* continue processing */ //unlock(); diff --git a/src/receivers/nbrx.h b/src/receivers/nbrx.h index 47fb7f3..0efe882 100644 --- a/src/receivers/nbrx.h +++ b/src/receivers/nbrx.h @@ -24,6 +24,7 @@ #define NBRX_H #include +#include #include #include "receivers/receiver_base.h" #include "dsp/rx_noise_blanker_cc.h" @@ -61,7 +62,7 @@ class nbrx : public receiver_base_cf public: nbrx(float quad_rate, float audio_rate); - ~nbrx(); + virtual ~nbrx() { }; bool start(); bool stop(); @@ -123,6 +124,7 @@ class nbrx : public receiver_base_cf rx_demod_am_sptr demod_am; /*!< AM demodulator. */ resampler_ff_sptr audio_rr; /*!< Audio resampler. */ + gr::basic_block_sptr demod; // dummy pointer used for simplifying reconf }; #endif // NBRX_H diff --git a/src/receivers/receiver_base.cpp b/src/receivers/receiver_base.cpp index 35bc4ae..411ce3b 100644 --- a/src/receivers/receiver_base.cpp +++ b/src/receivers/receiver_base.cpp @@ -42,7 +42,6 @@ receiver_base_cf::~receiver_base_cf() } - bool receiver_base_cf::has_nb() { return false; diff --git a/src/receivers/receiver_base.h b/src/receivers/receiver_base.h index e50eaad..4e24698 100644 --- a/src/receivers/receiver_base.h +++ b/src/receivers/receiver_base.h @@ -46,7 +46,7 @@ class receiver_base_cf : public gr::hier_block2 * \param src_name Descriptive name used in the contructor of gr::hier_block2 */ receiver_base_cf(std::string src_name); - ~receiver_base_cf(); + virtual ~receiver_base_cf(); virtual bool start() = 0; virtual bool stop() = 0; From c89a5afb08faeffaf08d167e41825faab9d39e8c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 13 Sep 2016 00:03:17 +0200 Subject: [PATCH 089/334] Use reset() on boost shared_ptr. Hopefully fixes issue #407. --- src/receivers/nbrx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index c698744..6e768f6 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -50,7 +50,7 @@ nbrx::nbrx(float quad_rate, float audio_rate) demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, PREF_AUDIO_RATE, 5000.0, 75.0e-6); demod_am = make_rx_demod_am(PREF_QUAD_RATE, PREF_AUDIO_RATE, true); - audio_rr = 0; + audio_rr.reset(); if (d_audio_rate != PREF_AUDIO_RATE) { std::cout << "Resampling audio " << PREF_AUDIO_RATE << " -> " From 3732bb50f54dc16f1cd35f8a93f342ae0cc42da5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 14 Sep 2016 23:27:20 +0200 Subject: [PATCH 090/334] Use class and method name in debug output. --- src/portaudio/portaudio_sink.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/portaudio/portaudio_sink.cpp b/src/portaudio/portaudio_sink.cpp index 8c1b9a3..39413e2 100644 --- a/src/portaudio/portaudio_sink.cpp +++ b/src/portaudio/portaudio_sink.cpp @@ -54,8 +54,8 @@ portaudio_sink::portaudio_sink(const string device_name, int audio_rate, { // FIXME: find device index based on device_name fprintf(stderr, - "*** FIXME: %s: Requested audio device is %s but we are using default\n", - __func__, device_name.data()); + "*** FIXME: portaudio_sink(): Requested audio device is %s but we are using default\n", + device_name.data()); // Initialize stream parmaeters d_out_params.device = Pa_GetDefaultOutputDevice(); @@ -66,9 +66,7 @@ portaudio_sink::portaudio_sink(const string device_name, int audio_rate, d_out_params.hostApiSpecificStreamInfo = NULL; if (Pa_IsFormatSupported(NULL, &d_out_params, d_audio_rate) != paFormatIsSupported) - fprintf(stderr, - "%s: Audio output device does not support requested format.\n", - __func__); + fprintf(stderr, "portaudio_sink(): Audio output device does not support requested format.\n"); } portaudio_sink::~portaudio_sink() @@ -92,7 +90,8 @@ bool portaudio_sink::start() if (err != paNoError) { - fprintf(stderr, "%s: Failed to open audio stream: %s\n", __FILE__, + fprintf(stderr, + "portaudio_sink::start(): Failed to open audio stream: %s\n", Pa_GetErrorText(err)); return false; } @@ -100,7 +99,8 @@ bool portaudio_sink::start() err = Pa_StartStream(d_stream); if (err != paNoError) { - fprintf(stderr, "%s: Failed to start audio stream: %s\n", __FILE__, + fprintf(stderr, + "portaudio_sink::start(): Failed to start audio stream: %s\n", Pa_GetErrorText(err)); return false; } @@ -118,7 +118,8 @@ bool portaudio_sink::stop() if (err != paNoError) { retval = false; - fprintf(stderr, "%s: Error stopping audio stream: %s\n", __FILE__, + fprintf(stderr, + "portaudio_sink::stop(): Error stopping audio stream: %s\n", Pa_GetErrorText(err)); } @@ -126,7 +127,8 @@ bool portaudio_sink::stop() if (err != paNoError) { retval = false; - fprintf(stderr, "%s: Error closing audio stream: %s\n", __FILE__, + fprintf(stderr, + "portaudio_sink::stop(): Error closing audio stream: %s\n", Pa_GetErrorText(err)); } @@ -165,7 +167,9 @@ int portaudio_sink::work(int noutput_items, err = Pa_WriteStream(d_stream, audio_buffer, noutput_items); if (err) - fprintf(stderr, "Error writing to audio device: %s\n", Pa_GetErrorText(err)); + fprintf(stderr, + "portaudio_sink::work(): Error writing to audio device: %s\n", + Pa_GetErrorText(err)); return noutput_items; From b643a9bb43eb8fac3baf9f641401ce6e07aa3df3 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 15 Sep 2016 00:43:37 +0200 Subject: [PATCH 091/334] Add function to find Portaudio device index from name. --- src/portaudio/device_list.cpp | 20 ++++++++++++++++++++ src/portaudio/device_list.h | 9 ++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/portaudio/device_list.cpp b/src/portaudio/device_list.cpp index 70978da..8417e04 100644 --- a/src/portaudio/device_list.cpp +++ b/src/portaudio/device_list.cpp @@ -22,8 +22,12 @@ */ #include #include +#include +#include + #include "device_list.h" +using namespace std; portaudio_device::portaudio_device(unsigned int idx, string name, string desc) : d_index(idx), d_name(name), d_description(desc) @@ -110,3 +114,19 @@ void portaudio_device_list::add_source(unsigned int idx, string name, string des { d_sources.push_back(portaudio_device(idx, name, desc)); } + +PaDeviceIndex portaudio_device_list::get_output_device_index(const string name) const +{ + vector::const_iterator it; + + if (name.empty()) + return -1; + + for (it = d_sinks.begin(); it < d_sinks.end(); it++) + { + if (it->get_name() == name) + return it->get_index(); + } + + return -1; +} diff --git a/src/portaudio/device_list.h b/src/portaudio/device_list.h index 328990c..4feca5a 100644 --- a/src/portaudio/device_list.h +++ b/src/portaudio/device_list.h @@ -42,9 +42,9 @@ class portaudio_device void set_name(string name) { d_name = name; } void set_description(string desc) { d_description = desc; } - unsigned int get_index() { return d_index; } - string get_name() { return d_name; } - string get_description() { return d_description; } + unsigned int get_index() const { return d_index; } + string get_name() const { return d_name; } + string get_description() const { return d_description; } private: unsigned int d_index; /*! The index of the audio device (unique for each source/sink). */ @@ -63,6 +63,9 @@ class portaudio_device_list vector get_input_devices() { return d_sources; } vector get_output_devices() {return d_sinks; } + /** Get output device index. Returns -1 if not found */ + PaDeviceIndex get_output_device_index(const string name) const; + private: vector d_sources; /*! List of pulseaudio sources. */ vector d_sinks; /*! List of pulseaudio sinks. */ From 6c81b3c9f2fbda185481fa0213de04bfcf4de584 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 15 Sep 2016 00:44:01 +0200 Subject: [PATCH 092/334] Allow using any portaudio output device. --- src/portaudio/portaudio_sink.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/portaudio/portaudio_sink.cpp b/src/portaudio/portaudio_sink.cpp index 39413e2..9693178 100644 --- a/src/portaudio/portaudio_sink.cpp +++ b/src/portaudio/portaudio_sink.cpp @@ -23,6 +23,7 @@ #include #include +#include "device_list.h" #include "portaudio_sink.h" /** @@ -52,13 +53,25 @@ portaudio_sink::portaudio_sink(const string device_name, int audio_rate, d_app_name(app_name), d_audio_rate(audio_rate) { - // FIXME: find device index based on device_name - fprintf(stderr, - "*** FIXME: portaudio_sink(): Requested audio device is %s but we are using default\n", - device_name.data()); + + // find device index + PaDeviceIndex idx; + portaudio_device_list devices; + + idx = devices.get_output_device_index(device_name); + if (idx == -1) + { + fprintf(stderr, "Using default audio device\n"); + idx = Pa_GetDefaultOutputDevice(); + } + else + { + fprintf(stderr, "Audio device '%s' has index %d\n", + device_name.data(), idx); + } // Initialize stream parmaeters - d_out_params.device = Pa_GetDefaultOutputDevice(); + d_out_params.device = idx; d_out_params.channelCount = 2; d_out_params.sampleFormat = paFloat32; d_out_params.suggestedLatency = From 5b65296bd6517fa0504d2d66f671e8b13b502dea Mon Sep 17 00:00:00 2001 From: Dominic Chen Date: Fri, 16 Sep 2016 18:17:58 -0400 Subject: [PATCH 093/334] Fix memory leak --- src/applications/gqrx/mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 6b829b8..4eb8d8e 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -351,6 +351,7 @@ MainWindow::~MainWindow() delete ui; delete uiDockRxOpt; delete uiDockAudio; + delete uiDockBookmarks; delete uiDockFft; delete uiDockInputCtl; delete uiDockRDS; From fa5d0ed3b6b31ff2c7161dad88df0048367ba5ee Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Sep 2016 09:08:41 +0200 Subject: [PATCH 094/334] Use std::string. Fixes compile error with latest Apple Clang. --- src/applications/gqrx/receiver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index f703f50..0cddce8 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -416,7 +416,7 @@ unsigned int receiver::set_input_decim(unsigned int decim) } #ifdef CUSTOM_AIRSPY_KERNELS - if (input_devstr.find("airspy") != string::npos) + if (input_devstr.find("airspy") != std::string::npos) src->set_bandwidth(d_quad_rate); #endif From 0de6590efd3f94714fb24cad23029b93a4b79817 Mon Sep 17 00:00:00 2001 From: Phil Vachon Date: Sat, 17 Sep 2016 17:01:21 -0400 Subject: [PATCH 095/334] When resetting FFT Zoom, reset slider too Make sure that when the FFT zoom is reset using the reset button, that the slider UI element (and associated label) are also reset simultaneously. --- src/qtgui/dockfft.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index 22c07fc..0e66f98 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -383,6 +383,8 @@ void DockFft::on_rangeSlider_valueChanged(int value) void DockFft::on_resetButton_clicked(void) { + ui->zoomLevelLabel->setText(QString("1x")); + ui->fftZoomSlider->setValue(0); emit resetFftZoom(); } From fda5a80793ed40a64e1a6f012c33de9e9bcdd733 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 18 Sep 2016 12:44:32 +0200 Subject: [PATCH 096/334] Update README.md. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 50368df..5119b2f 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,9 @@ Stefano Leucci: Daniil Cherednik: - FM OIRT stereo. +Dominic Chen: +- Bug fixes. + Elias Önal: - Building Gqrx on Mac OS X. - Crash recovery dialog. @@ -242,6 +245,9 @@ Nadeem Hasan: Nokia: - QtColorPicker widget. +Phil Vachon: +- Bug fixes. + Rob Frohne: - Initial Qt5 support. From 7cc3c5c4d290f61d543848e496d2749c76a2dd47 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 19 Sep 2016 01:31:36 +0200 Subject: [PATCH 097/334] Add margin around axis labels. --- src/qtgui/plotter.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index f162709..a65c390 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -1289,11 +1289,15 @@ void CPlotter::drawOverlay() painter.setBrush(Qt::SolidPattern); painter.fillRect(0, 0, w, h, QColor(PLOTTER_BGD_COLOR)); +#define HOR_MARGIN 5 +#define VER_MARGIN 5 + // X and Y axis areas - m_YAxisWidth = metrics.width("-120 "); + m_YAxisWidth = metrics.width("XXXX") + 2 * HOR_MARGIN; m_XAxisYCenter = h - metrics.height()/2; - int xAxisHeight = metrics.height(); + int xAxisHeight = metrics.height() + 2 * VER_MARGIN; int xAxisTop = h - xAxisHeight; + int fLabelTop = xAxisTop + VER_MARGIN; if (m_BookmarksEnabled) { @@ -1380,7 +1384,7 @@ void CPlotter::drawOverlay() x = (int)((float)i*pixperdiv + adjoffset); if (x > m_YAxisWidth) { - rect.setRect(x - tw/2, xAxisTop, tw, metrics.height()); + rect.setRect(x - tw/2, fLabelTop, tw, metrics.height()); painter.drawText(rect, Qt::AlignHCenter|Qt::AlignBottom, m_HDivText[i]); } } @@ -1422,7 +1426,7 @@ void CPlotter::drawOverlay() if (y < h -xAxisHeight) { dB = mindbadj + dbstepsize * i; - rect.setRect(0, y - th / 2, m_YAxisWidth, th); + rect.setRect(HOR_MARGIN, y - th / 2, m_YAxisWidth, th); painter.drawText(rect, Qt::AlignRight|Qt::AlignVCenter, QString::number(dB)); } } From ff19e591e7f8eebedf6d1662d895c5bee11e72d5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Sep 2016 11:33:01 +0200 Subject: [PATCH 098/334] Explicitly set Fusion style. This prevents the default "windows 3.1" style to be used on linux and is necessary with Qt 5.7 since the removal of Gtk Style. --- src/applications/gqrx/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index 6e466ae..bf8c094 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef WITH_PORTAUDIO @@ -52,6 +53,7 @@ int main(int argc, char *argv[]) int return_code; QApplication a(argc, argv); + QApplication::setStyle(QStyleFactory::create("Fusion")); QCoreApplication::setOrganizationName(GQRX_ORG_NAME); QCoreApplication::setOrganizationDomain(GQRX_ORG_DOMAIN); QCoreApplication::setApplicationName(GQRX_APP_NAME); From 6f5a32e1002bfddd483fa965bf2fca128d95ffd4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Sep 2016 11:48:11 +0200 Subject: [PATCH 099/334] Code clean-up. --- src/applications/gqrx/main.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index bf8c094..c540d0d 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -46,13 +46,13 @@ static void list_conf(void); int main(int argc, char *argv[]) { - QString cfg_file; + QString cfg_file; std::string conf; - bool clierr = false; - bool edit_conf = false; - int return_code; + bool clierr = false; + bool edit_conf = false; + int return_code; - QApplication a(argc, argv); + QApplication app(argc, argv); QApplication::setStyle(QStyleFactory::create("Fusion")); QCoreApplication::setOrganizationName(GQRX_ORG_NAME); QCoreApplication::setOrganizationDomain(GQRX_ORG_DOMAIN); @@ -140,7 +140,7 @@ int main(int argc, char *argv[]) if (w.configOk) { w.show(); - return_code = a.exec(); + return_code = app.exec(); } else { @@ -154,11 +154,11 @@ int main(int argc, char *argv[]) return return_code; } -/*! \brief Reset configuration file specified by file_name. */ +/** Reset configuration file specified by file_name. */ static void reset_conf(const QString &file_name) { - QString cfg_file; - QByteArray xdg_dir = qgetenv("XDG_CONFIG_HOME"); + QString cfg_file; + QByteArray xdg_dir = qgetenv("XDG_CONFIG_HOME"); if (xdg_dir.isEmpty()) cfg_file = QString("%1/.config/gqrx/%2").arg(QDir::homePath()).arg(file_name); @@ -178,11 +178,11 @@ static void reset_conf(const QString &file_name) } } -/*! \brief List avaialble configurations. */ +/** List available configurations. */ static void list_conf(void) { - QString conf_path; - QByteArray xdg_dir = qgetenv("XDG_CONFIG_HOME"); + QString conf_path; + QByteArray xdg_dir = qgetenv("XDG_CONFIG_HOME"); if (xdg_dir.isEmpty()) conf_path = QString("%1/.config/gqrx/").arg(QDir::homePath()); From 40abdecca3f71dc45c7642b7f67c809a0d6d6d6d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Sep 2016 12:17:50 +0200 Subject: [PATCH 100/334] Indent and code clean-up. --- src/qtgui/plotter.cpp | 275 ++++++++++++++++++++---------------------- src/qtgui/plotter.h | 4 +- 2 files changed, 136 insertions(+), 143 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index a65c390..c49eaf6 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -69,9 +69,7 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) // Comment out to enable plotter debug messages //#define PLOTTER_DEBUG -////////////////////////////////////////////////////////////////////// -// Local defines -////////////////////////////////////////////////////////////////////// + #define CUR_CUT_DELTA 5 //cursor capture delta in pixels // dB-axis constraints @@ -115,13 +113,8 @@ static inline quint64 time_ms(void) "Drag and scroll X and Y axes for pan and zoom. " \ "Drag filter edges to adjust filter." -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// -CPlotter::CPlotter(QWidget *parent) : - QFrame(parent) +CPlotter::CPlotter(QWidget *parent) : QFrame(parent) { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setFocusPolicy(Qt::StrongFocus); setAttribute(Qt::WA_PaintOnScreen,false); @@ -156,8 +149,8 @@ CPlotter::CPlotter(QWidget *parent) : m_ColorTbl[i].setRgb(255, 255*(i-250)/5, 255*(i-250)/5); } - m_PeakHoldActive=false; - m_PeakHoldValid=false; + m_PeakHoldActive = false; + m_PeakHoldValid = false; m_FftCenter = 0; m_CenterFreq = 144500000; @@ -221,9 +214,6 @@ CPlotter::~CPlotter() { } -////////////////////////////////////////////////////////////////////// -// Sizing interface -////////////////////////////////////////////////////////////////////// QSize CPlotter::minimumSizeHint() const { return QSize(50, 50); @@ -234,12 +224,6 @@ QSize CPlotter::sizeHint() const return QSize(180, 180); } - -////////////////////////////////////////////////////////////////////// -// Called when mouse moves and does different things depending -//on the state of the mouse buttons for dragging the demod bar or -// filter edges. -////////////////////////////////////////////////////////////////////// void CPlotter::mouseMoveEvent(QMouseEvent* event) { @@ -247,26 +231,28 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) /* mouse enter / mouse leave events */ if (m_OverlayPixmap.rect().contains(pt)) - { //is in Overlay bitmap region + { + //is in Overlay bitmap region if (event->buttons() == Qt::NoButton) { - bool onTag=false; - if(pt.y()<15*10) //FIXME + bool onTag = false; + if(pt.y() < 15 * 10) // FIXME { - for(int i=0; ipos())) - onTag=true; + if (m_BookmarkTags[i].first.contains(event->pos())) + onTag = true; } } - //if no mouse button monitor grab regions and change cursor icon - if(onTag) + // if no mouse button monitor grab regions and change cursor icon + if (onTag) { setCursor(QCursor(Qt::PointingHandCursor)); - m_CursorCaptured=BOOKMARK; + m_CursorCaptured = BOOKMARK; } else if (isPointCloseTo(pt.x(), m_DemodFreqX, m_CursorCaptureDelta)) - { //in move demod box center frequency region + { + // in move demod box center frequency region if (CENTER != m_CursorCaptured) setCursor(QCursor(Qt::SizeHorCursor)); m_CursorCaptured = CENTER; @@ -277,7 +263,8 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) this, rect()); } else if (isPointCloseTo(pt.x(), m_DemodHiCutFreqX, m_CursorCaptureDelta)) - { //in move demod hicut region + { + // in move demod hicut region if (RIGHT != m_CursorCaptured) setCursor(QCursor(Qt::SizeFDiagCursor)); m_CursorCaptured = RIGHT; @@ -288,7 +275,8 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) this, rect()); } else if (isPointCloseTo(pt.x(), m_DemodLowCutFreqX, m_CursorCaptureDelta)) - { //in move demod lowcut region + { + // in move demod lowcut region if (LEFT != m_CursorCaptured) setCursor(QCursor(Qt::SizeBDiagCursor)); m_CursorCaptured = LEFT; @@ -331,7 +319,8 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) } } else - { //not in Overlay region + { + // not in Overlay region if (event->buttons() == Qt::NoButton) { if (NOCAP != m_CursorCaptured) @@ -360,7 +349,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) setCursor(QCursor(Qt::ClosedHandCursor)); // move Y scale up/down float delta_px = m_Yzero - pt.y(); - float delta_db = delta_px * fabs(m_MindB-m_MaxdB)/(float)m_OverlayPixmap.height(); + float delta_db = delta_px * fabs(m_MindB-m_MaxdB) / (float)m_OverlayPixmap.height(); m_MindB -= delta_db; m_MaxdB -= delta_db; if (out_of_range(m_MaxdB, m_MaxdB - m_MindB)) @@ -409,12 +398,14 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) } } else if (LEFT == m_CursorCaptured) - { // moving in demod lowcut region - if (event->buttons() & (Qt::LeftButton|Qt::RightButton)) - { //moving in demod lowcut region with left button held + { + // moving in demod lowcut region + if (event->buttons() & (Qt::LeftButton | Qt::RightButton)) + { + // moving in demod lowcut region with left button held if (m_GrabPosition != 0) { - m_DemodLowCutFreq = freqFromX(pt.x()-m_GrabPosition ) - m_DemodCenterFreq; + m_DemodLowCutFreq = freqFromX(pt.x() - m_GrabPosition ) - m_DemodCenterFreq; m_DemodLowCutFreq = roundFreq(m_DemodLowCutFreq, m_FilterClickResolution); if (m_symetric && (event->buttons() & Qt::LeftButton)) // symetric adjustment @@ -425,12 +416,13 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) emit newFilterFreq(m_DemodLowCutFreq, m_DemodHiCutFreq); if (m_Running) - m_DrawOverlay = true; // schedule update of overlay during draw() + m_DrawOverlay = true; else - drawOverlay(); // not running so update overlay now + drawOverlay(); } else - { //save initial grab postion from m_DemodFreqX + { + // save initial grab postion from m_DemodFreqX m_GrabPosition = pt.x()-m_DemodLowCutFreqX; } } @@ -441,9 +433,11 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) } } else if (RIGHT == m_CursorCaptured) - { // moving in demod highcut region - if (event->buttons() & (Qt::LeftButton|Qt::RightButton)) - { // moving in demod highcut region with right button held + { + // moving in demod highcut region + if (event->buttons() & (Qt::LeftButton | Qt::RightButton)) + { + // moving in demod highcut region with right button held if (m_GrabPosition != 0) { m_DemodHiCutFreq = freqFromX( pt.x()-m_GrabPosition ) - m_DemodCenterFreq; @@ -459,8 +453,9 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) updateOverlay(); } else - { //save initial grab postion from m_DemodFreqX - m_GrabPosition = pt.x()-m_DemodHiCutFreqX; + { + // save initial grab postion from m_DemodFreqX + m_GrabPosition = pt.x() - m_DemodHiCutFreqX; } } else if (event->buttons() & ~Qt::NoButton) @@ -470,19 +465,23 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) } } else if (CENTER == m_CursorCaptured) - { // moving inbetween demod lowcut and highcut region + { + // moving inbetween demod lowcut and highcut region if (event->buttons() & Qt::LeftButton) { // moving inbetween demod lowcut and highcut region with left button held if (m_GrabPosition != 0) { - m_DemodCenterFreq = roundFreq(freqFromX(pt.x()-m_GrabPosition), m_ClickResolution ); - emit newDemodFreq(m_DemodCenterFreq, m_DemodCenterFreq-m_CenterFreq); + m_DemodCenterFreq = roundFreq(freqFromX(pt.x() - m_GrabPosition), + m_ClickResolution ); + emit newDemodFreq(m_DemodCenterFreq, + m_DemodCenterFreq - m_CenterFreq); updateOverlay(); m_PeakHoldValid = false; } else - { //save initial grab postion from m_DemodFreqX - m_GrabPosition = pt.x()-m_DemodFreqX; + { + // save initial grab postion from m_DemodFreqX + m_GrabPosition = pt.x() - m_DemodFreqX; } } else if (event->buttons() & ~Qt::NoButton) @@ -491,13 +490,14 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) m_CursorCaptured = NOCAP; } } - else //if cursor not captured + else { + // cursor not captured m_GrabPosition = 0; } if (!this->rect().contains(pt)) { - if(NOCAP != m_CursorCaptured) + if (NOCAP != m_CursorCaptured) setCursor(QCursor(Qt::ArrowCursor)); m_CursorCaptured = NOCAP; } @@ -506,11 +506,12 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) int CPlotter::getNearestPeak(QPoint pt) { - QMap::const_iterator i = m_Peaks.lowerBound(pt.x()-PEAK_CLICK_MAX_H_DISTANCE); - QMap::const_iterator upperBound = m_Peaks.upperBound(pt.x()+PEAK_CLICK_MAX_H_DISTANCE); + QMap::const_iterator i = m_Peaks.lowerBound(pt.x() - PEAK_CLICK_MAX_H_DISTANCE); + QMap::const_iterator upperBound = m_Peaks.upperBound(pt.x() + PEAK_CLICK_MAX_H_DISTANCE); float dist = 1.0e10; int best = -1; - for( ; i != upperBound; i++) + + for ( ; i != upperBound; i++) { int x = i.key(); int y = i.value(); @@ -552,17 +553,17 @@ void CPlotter::clearWaterfall() */ bool CPlotter::saveWaterfall(const QString & filename) const { - QBrush axis_brush(QColor(0x00, 0x00, 0x00, 0x70), Qt::SolidPattern); - QPixmap pixmap(m_WaterfallPixmap); - QPainter painter(&pixmap); - QRect rect; - QDateTime tt; - QFont font("sans-serif"); + QBrush axis_brush(QColor(0x00, 0x00, 0x00, 0x70), Qt::SolidPattern); + QPixmap pixmap(m_WaterfallPixmap); + QPainter painter(&pixmap); + QRect rect; + QDateTime tt; + QFont font("sans-serif"); QFontMetrics font_metrics(font); - float pixperdiv; - int x, y, w, h; - int hxa, wya = 85; - int i; + float pixperdiv; + int x, y, w, h; + int hxa, wya = 85; + int i; w = pixmap.width(); h = pixmap.height(); @@ -707,10 +708,9 @@ void CPlotter::mousePressEvent(QMouseEvent * event) resetHorizontalZoom(); } } - else if(m_CursorCaptured == BOOKMARK) + else if (m_CursorCaptured == BOOKMARK) { - int i; - for (i = 0; i < m_BookmarkTags.size(); i++) + for (int i = 0; i < m_BookmarkTags.size(); i++) { if (m_BookmarkTags[i].first.contains(event->pos())) { @@ -723,7 +723,6 @@ void CPlotter::mousePressEvent(QMouseEvent * event) } } -// Called when a mouse button is released void CPlotter::mouseReleaseEvent(QMouseEvent * event) { QPoint pt = event->pos(); @@ -1106,9 +1105,10 @@ void CPlotter::draw() update(); } -/*! \brief Set new FFT data. - * \param fftData Pointer to the new FFT data (same data for pandapter and waterfall). - * \param size The FFT size. +/** + * Set new FFT data. + * @param fftData Pointer to the new FFT data (same data for pandapter and waterfall). + * @param size The FFT size. * * When FFT data is set using this method, the same data will be used for both the * pandapter and the waterfall. @@ -1126,10 +1126,11 @@ void CPlotter::setNewFttData(float *fftData, int size) draw(); } -/*! \brief Set new FFT data. - * \param fftData Pointer to the new FFT data used on the pandapter. - * \param wfData Pointer to the FFT data used in the waterfall. - * \param size The FFT size. +/** + * Set new FFT data. + * @param fftData Pointer to the new FFT data used on the pandapter. + * @param wfData Pointer to the FFT data used in the waterfall. + * @param size The FFT size. * * This method can be used to set different FFT data set for the pandapter and the * waterfall. @@ -1248,7 +1249,7 @@ void CPlotter::getScreenIntegerFFTData(qint32 plotHeight, qint32 plotWidth, delete [] m_pTranslateTbl; } -/*! \brief Set limits of dB scale. */ +/** Set limits of dB scale. */ void CPlotter::setMinMaxDB(float min, float max) { m_MaxdB = max; @@ -1272,16 +1273,17 @@ void CPlotter::drawOverlay() if (m_OverlayPixmap.isNull()) return; - int w = m_OverlayPixmap.width(); - int h = m_OverlayPixmap.height(); - int x,y; - float pixperdiv; - float adjoffset; - float dbstepsize; - float mindbadj; - QRect rect; - QFontMetrics metrics(m_Font); - QPainter painter(&m_OverlayPixmap); + int w = m_OverlayPixmap.width(); + int h = m_OverlayPixmap.height(); + int x,y; + float pixperdiv; + float adjoffset; + float dbstepsize; + float mindbadj; + QRect rect; + QFontMetrics metrics(m_Font); + QPainter painter(&m_OverlayPixmap); + painter.initFrom(this); painter.setFont(m_Font); @@ -1307,28 +1309,31 @@ void CPlotter::drawOverlay() static const int slant = 5; static const int levelHeight = fontHeight + 5; static const int nLevels = 10; - QList bookmarks = Bookmarks::Get().getBookmarksInRange(m_CenterFreq+m_FftCenter-m_Span/2, m_CenterFreq+m_FftCenter+m_Span/2); + QList bookmarks = Bookmarks::Get().getBookmarksInRange(m_CenterFreq + m_FftCenter - m_Span / 2, + m_CenterFreq + m_FftCenter + m_Span / 2); int tagEnd[nLevels] = {0}; - for(int i = 0; i < bookmarks.size(); i++) + for (int i = 0; i < bookmarks.size(); i++) { - x=xFromFreq(bookmarks[i].frequency); + x = xFromFreq(bookmarks[i].frequency); + #if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) int nameWidth = fm.width(bookmarks[i].name); #else int nameWidth = fm.boundingRect(bookmarks[i].name).width(); #endif + int level = 0; for (; level < nLevels && tagEnd[level] > x; level++); level %= nLevels; tagEnd[level] = x + nameWidth + slant - 1; - m_BookmarkTags.append(qMakePair(QRect(x, level*levelHeight, nameWidth+slant, fontHeight), bookmarks[i].frequency)); + m_BookmarkTags.append(qMakePair(QRect(x, level * levelHeight, nameWidth + slant, fontHeight), bookmarks[i].frequency)); QColor color = QColor(bookmarks[i].GetColor()); color.setAlpha(0x60); // Vertical line painter.setPen(QPen(color, 1, Qt::DashLine)); - painter.drawLine(x, level*levelHeight+fontHeight+slant, x, xAxisTop); + painter.drawLine(x, level * levelHeight + fontHeight + slant, x, xAxisTop); // Horizontal line painter.setPen(QPen(color, 1, Qt::SolidLine)); @@ -1462,20 +1467,19 @@ void CPlotter::drawOverlay() painter.end(); } -////////////////////////////////////////////////////////////////////// -// Helper function Called to create all the frequency division text -//strings based on start frequency, span frequency, frequency units. -//Places in QString array m_HDivText -//Keeps all strings the same fractional length -////////////////////////////////////////////////////////////////////// +// Create frequency division strings based on start frequency, span frequency, +// and frequency units. +// Places in QString array m_HDivText +// Keeps all strings the same fractional length void CPlotter::makeFrequencyStrs() { - qint64 StartFreq = m_StartFreqAdj; - float freq; - int i,j; + qint64 StartFreq = m_StartFreqAdj; + float freq; + int i,j; if ((1 == m_FreqUnits) || (m_FreqDigits == 0)) - { //if units is Hz then just output integer freq + { + // if units is Hz then just output integer freq for (int i = 0; i <= m_HorDivs; i++) { freq = (float)StartFreq/(float)m_FreqUnits; @@ -1488,7 +1492,7 @@ void CPlotter::makeFrequencyStrs() // so create max sized text based on frequency units for (int i = 0; i <= m_HorDivs; i++) { - freq = (float)StartFreq/(float)m_FreqUnits; + freq = (float)StartFreq / (float)m_FreqUnits; m_HDivText[i].setNum(freq,'f', m_FreqDigits); StartFreq += m_FreqPerDiv; } @@ -1504,8 +1508,8 @@ void CPlotter::makeFrequencyStrs() if (m_HDivText[i][j] != '0') break; } - if ((j-dp) > max) - max = j-dp; + if ((j - dp) > max) + max = j - dp; } // truncate all strings to maximum fractional length StartFreq = m_StartFreqAdj; @@ -1517,9 +1521,7 @@ void CPlotter::makeFrequencyStrs() } } -////////////////////////////////////////////////////////////////////// -// Helper functions to convert to/from screen coordinates to frequency -////////////////////////////////////////////////////////////////////// +// Convert from screen coordinate to frequency int CPlotter::xFromFreq(qint64 freq) { int w = m_OverlayPixmap.width(); @@ -1532,11 +1534,12 @@ int CPlotter::xFromFreq(qint64 freq) return x; } +// Convert from frequency to screen coordinate qint64 CPlotter::freqFromX(int x) { int w = m_OverlayPixmap.width(); - qint64 StartFreq = m_CenterFreq + m_FftCenter - m_Span/2; - qint64 f = (qint64)(StartFreq + (float)m_Span * (float)x/(float)w ); + qint64 StartFreq = m_CenterFreq + m_FftCenter - m_Span / 2; + qint64 f = (qint64)(StartFreq + (float)m_Span * (float)x / (float)w); return f; } @@ -1555,26 +1558,20 @@ quint64 CPlotter::msecFromY(int y) return tlast_wf_ms - dy * 1000 / fft_rate; } -////////////////////////////////////////////////////////////////////// -// Helper function to round frequency to click resolution value -////////////////////////////////////////////////////////////////////// +// Round frequency to click resolution value qint64 CPlotter::roundFreq(qint64 freq, int resolution) { qint64 delta = resolution; - qint64 delta_2 = delta/2; + qint64 delta_2 = delta / 2; if (freq >= 0) - return ( freq - (freq+delta_2)%delta + delta_2); + return (freq - (freq + delta_2) % delta + delta_2); else - return ( freq - (freq+delta_2)%delta - delta_2); + return (freq - (freq + delta_2) % delta - delta_2); } -////////////////////////////////////////////////////////////////////// -// Helper function clamps demod freqeuency limits of -// m_DemodCenterFreq -////////////////////////////////////////////////////////////////////// +// Clamp demod freqeuency limits of m_DemodCenterFreq void CPlotter::clampDemodParameters() { - if(m_DemodLowCutFreq < m_FLowCmin) m_DemodLowCutFreq = m_FLowCmin; if(m_DemodLowCutFreq > m_FLowCmax) @@ -1584,10 +1581,11 @@ void CPlotter::clampDemodParameters() m_DemodHiCutFreq = m_FHiCmin; if(m_DemodHiCutFreq > m_FHiCmax) m_DemodHiCutFreq = m_FHiCmax; - } -void CPlotter::setDemodRanges(int FLowCmin, int FLowCmax, int FHiCmin, int FHiCmax, bool symetric) +void CPlotter::setDemodRanges(int FLowCmin, int FLowCmax, + int FHiCmin, int FHiCmax, + bool symetric) { m_FLowCmin=FLowCmin; m_FLowCmax=FLowCmax; @@ -1600,7 +1598,7 @@ void CPlotter::setDemodRanges(int FLowCmin, int FLowCmax, int FHiCmin, int FHiCm void CPlotter::setCenterFreq(quint64 f) { - if((quint64)m_CenterFreq==f) + if((quint64)m_CenterFreq == f) return; qint64 offset = m_CenterFreq - m_DemodCenterFreq; @@ -1622,26 +1620,22 @@ void CPlotter::updateOverlay() drawOverlay(); } -/*! \brief Reset horizontal zoom to 100% and centered around 0. */ +/** Reset horizontal zoom to 100% and centered around 0. */ void CPlotter::resetHorizontalZoom(void) { setFftCenterFreq(0); setSpanFreq((qint32)m_SampleFreq); } -/*! \brief Center FFT plot around 0 (corresponds to center freq). */ +/** Center FFT plot around 0 (corresponds to center freq). */ void CPlotter::moveToCenterFreq(void) { setFftCenterFreq(0); - if (m_Running) - m_DrawOverlay = true; - else - drawOverlay(); - + updateOverlay(); m_PeakHoldValid = false; } -/*! \brief Center FFT plot around the demodulator frequency. */ +/** Center FFT plot around the demodulator frequency. */ void CPlotter::moveToDemodFreq(void) { setFftCenterFreq(m_DemodCenterFreq-m_CenterFreq); @@ -1650,7 +1644,7 @@ void CPlotter::moveToDemodFreq(void) m_PeakHoldValid = false; } -/*! Set FFT plot color. */ +/** Set FFT plot color. */ void CPlotter::setFftPlotColor(const QColor color) { m_FftColor = color; @@ -1660,24 +1654,23 @@ void CPlotter::setFftPlotColor(const QColor color) m_PeakHoldColor.setAlpha(60); } -/*! Enable/disable filling the area below the FFT plot. */ +/** Enable/disable filling the area below the FFT plot. */ void CPlotter::setFftFill(bool enabled) { m_FftFill = enabled; } -/*! \brief Set peak hold on or off. - * \param enabled The new state of peak hold. - */ +/** Set peak hold on or off. */ void CPlotter::setPeakHold(bool enabled) { m_PeakHoldActive = enabled; m_PeakHoldValid = false; } -/*! \brief Set peak detection on or off. - * \param enabled The new state of peak detection. - * \param c Minimum distance of peaks from mean, in multiples of standard deviation. +/** + * Set peak detection on or off. + * @param enabled The new state of peak detection. + * @param c Minimum distance of peaks from mean, in multiples of standard deviation. */ void CPlotter::setPeakDetection(bool enabled, float c) { diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 03a6fa5..2ef4126 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -206,8 +206,8 @@ public slots: QString m_HDivText[HORZ_DIVS_MAX+1]; bool m_Running; bool m_DrawOverlay; - qint64 m_CenterFreq; - qint64 m_FftCenter; + qint64 m_CenterFreq; // The HW frequency + qint64 m_FftCenter; // Center freq in the -span ... +span range qint64 m_DemodCenterFreq; qint64 m_StartFreqAdj; qint64 m_FreqPerDiv; From 50e4b9679c4cd873ac1181ffff03c02ebe1acb44 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Sep 2016 22:13:55 +0200 Subject: [PATCH 101/334] Add ctkRangeSlider widget from CTK project. --- LICENSE-CTK | 203 ++++++++ README.md | 3 + gqrx.pro | 3 + src/qtgui/CMakeLists.txt | 3 + src/qtgui/ctk/ctkPimpl.h | 197 +++++++ src/qtgui/ctk/ctkRangeSlider.cpp | 859 +++++++++++++++++++++++++++++++ src/qtgui/ctk/ctkRangeSlider.h | 210 ++++++++ 7 files changed, 1478 insertions(+) create mode 100644 LICENSE-CTK create mode 100644 src/qtgui/ctk/ctkPimpl.h create mode 100644 src/qtgui/ctk/ctkRangeSlider.cpp create mode 100644 src/qtgui/ctk/ctkRangeSlider.h diff --git a/LICENSE-CTK b/LICENSE-CTK new file mode 100644 index 0000000..3501b9f --- /dev/null +++ b/LICENSE-CTK @@ -0,0 +1,203 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the + purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control + systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITION OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index 5119b2f..ead243e 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,9 @@ Josh Blum Kate Adams: - Auto squelch. +Kitware Inc.: +- Widgets from the CTK library (http://commontk.org/). + Michael Dickens: - Bugfixes and audio on OSX. diff --git a/gqrx.pro b/gqrx.pro index ede4467..9f6e999 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -118,6 +118,7 @@ SOURCES += \ src/qtgui/bookmarks.cpp \ src/qtgui/bookmarkstablemodel.cpp \ src/qtgui/bookmarkstaglist.cpp \ + src/qtgui/ctk/ctkRangeSlider.cpp \ src/qtgui/demod_options.cpp \ src/qtgui/dockaudio.cpp \ src/qtgui/dockbookmarks.cpp \ @@ -174,6 +175,8 @@ HEADERS += \ src/qtgui/bookmarks.h \ src/qtgui/bookmarkstablemodel.h \ src/qtgui/bookmarkstaglist.h \ + src/qtgui/ctk/ctkPimpl.h \ + src/qtgui/ctk/ctkRangeSlider.h \ src/qtgui/demod_options.h \ src/qtgui/dockaudio.h \ src/qtgui/dockbookmarks.h \ diff --git a/src/qtgui/CMakeLists.txt b/src/qtgui/CMakeLists.txt index c024b9e..38db002 100644 --- a/src/qtgui/CMakeLists.txt +++ b/src/qtgui/CMakeLists.txt @@ -13,6 +13,9 @@ add_source_files(SRCS_LIST bookmarkstablemodel.h bookmarkstaglist.cpp bookmarkstaglist.h + ctk/ctkPimpl.h + ctk/ctkRangeSlider.cpp + ctk/ctkRangeSlider.h demod_options.cpp demod_options.h dockaudio.cpp diff --git a/src/qtgui/ctk/ctkPimpl.h b/src/qtgui/ctk/ctkPimpl.h new file mode 100644 index 0000000..4633727 --- /dev/null +++ b/src/qtgui/ctk/ctkPimpl.h @@ -0,0 +1,197 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +/** +\page CorePimpl CTK Pimpl Macros + +\brief Utility macros for handling private implementations. It is in addition + to QtGlobal: Q_DECLARE_PRIVATE, Q_DECLARE_PUBLIC, + Q_D and Q_Q. + +Application code generally doesn't have to be concerned about hiding its +implementation details, but when writing library code it is important to +maintain a constant interface, both source and binary. Maintaining a constant +source interface is easy enough, but keeping the binary interface constant +means moving implementation details into a private class. The PIMPL, or +d-pointer, idiom is a common method of implementing this separation. ctkPimpl +offers a convenient way to connect the public and private sides of your class. + +\section start Getting Started +Before you declare the public class, you need to make a forward declaration +of the private class. The private class must have the same name as the public +class, followed by the word Private. + +\subsection pub The Public Class +Generally, you shouldn't keep any data members in the public class without a +good reason. Functions that are part of the public interface should be declared +in the public class, and functions that need to be available to subclasses (for +calling or overriding) should be in the protected section of the public class. +To connect the private class to the public class, include the +Q_DECLARE_PRIVATE macro in the private section of the public class. + +Additionally, you must construct the d_ptr pointer in the constructor of the + public class. + +\subsection priv The Private Class +As mentioned above, data members should usually be kept in the private class. +This allows the memory layout of the private class to change without breaking +binary compatibility for the public class. Functions that exist only as +implementation details, or functions that need access to private data members, +should be implemented here. + +To define the private class, nothing special needs to be done, except if you +want the private class to have access to the public class. Then use +Q_DECLARE_PUBLIC and create a public class pointer member. The constructor of +the private class should take a public class reference as a parameter. + +\section cross Accessing Private Members +Use the Q_D() macros from functions in +the public class to access the private class. Similarly, functions in the +private class can invoke functions in the public class by using the Q_Q() +macro. +\section example Example +Header file (ctkFooObject.h): +\code +// Qt includes +#include + +// CTK includes +#include "ctkCoreExport.h" +class ctkFooObjectPrivate; + +class CTK_CORE_EXPORT ctkFooObject: public QObject +{ +public: + ctkFooObject(QObject* parent = 0); + virtual ~ctkFooObject(); + + void setProperty(double property); + double property()const; + +protected: + QScopedPointer d_ptr; + +private: + Q_DECLARE_PRIVATE(ctkFooObject); + Q_DISABLE_COPY(ctkFooObject); +}; +\endcode +Implementation file (ctkFooObject.cpp): +\code +// CTK includes +#include "ctkFooObject.h" + +class ctkFooObjectPrivate +{ +public: + void processSomething(); + + double MyProperty; +}; + +ctkFooObject::ctkFooObject(QObject* parentObject) + : d_ptr(new ctkFooObjectPrivate) +{ + Q_D(ctkFooObject); + d->MyProperty = 10.; +} + +void ctkFooObject::setProperty(double newProperty) +{ + Q_D(ctkFooObject); + d->MyProperty = newProperty; +} + +double ctkFooObject::property()const +{ + Q_D(const ctkFooObject); + return d->MyProperty; +} +\endcode +*/ + +#ifndef __ctkPimpl_h +#define __ctkPimpl_h + +// Qt includes +#include + +/*! + * \ingroup Core + * @{ + */ + +/*! + * Define a public class constructor with no argument + * + * Also make sure the Pimpl is initalized + * \see \ref CorePimpl + */ +#define CTK_CONSTRUCTOR_NO_ARG_CPP(PUB) \ + PUB::PUB(): d_ptr(new PUB##Private) \ + { \ + } + +/*! + * Define a public class constructor with one argument + * + * Also make sure the Pimpl is initalized + * \see \ref CorePimpl + */ +#define CTK_CONSTRUCTOR_1_ARG_CPP(PUB, _ARG1) \ + PUB::PUB(_ARG1 _parent) \ + : Superclass( _parent ) \ + , d_ptr(new PUB##Private) \ + { \ + } + +/*! + * Define the setter in the public class. + * + * This should be put in the .cxx file of the public class. The parameter are + * the name of the public class (PUB), the type of the argument to return (_TYPE), + * the name of the getter(_NAME) and the name of the variable in the Private class(_VARNAME). + * \see \ref CorePimpl + */ +#define CTK_SET_CPP(PUB, _TYPE, _NAME, _VARNAME) \ + void PUB::_NAME(_TYPE var) \ + { \ + Q_D(PUB); \ + d->_VARNAME = var; \ + } + +/*! + * Define the setter in the public class. + * + * This should be put in the .cxx file of the public class. The parameter are + * the name of the public class (PUB), the type of the argument to return (_TYPE), + * the name of the setter(_NAME) and the name of the variable in the Private class(_VARNAME). + * \see \ref CorePimpl + */ +#define CTK_GET_CPP(PUB, _TYPE, _NAME, _VARNAME) \ + _TYPE PUB::_NAME()const \ + { \ + Q_D(const PUB); \ + return d->_VARNAME; \ + } + +/**@}*/ + +#endif diff --git a/src/qtgui/ctk/ctkRangeSlider.cpp b/src/qtgui/ctk/ctkRangeSlider.cpp new file mode 100644 index 0000000..17927c5 --- /dev/null +++ b/src/qtgui/ctk/ctkRangeSlider.cpp @@ -0,0 +1,859 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include + +// CTK includes +#include "ctkRangeSlider.h" + +class ctkRangeSliderPrivate +{ + Q_DECLARE_PUBLIC(ctkRangeSlider); +protected: + ctkRangeSlider* const q_ptr; +public: + /// Boolean indicates the selected handle + /// True for the minimum range handle, false for the maximum range handle + enum Handle { + NoHandle = 0x0, + MinimumHandle = 0x1, + MaximumHandle = 0x2 + }; + Q_DECLARE_FLAGS(Handles, Handle); + + ctkRangeSliderPrivate(ctkRangeSlider& object); + void init(); + + /// Return the handle at the given pos, or none if no handle is at the pos. + /// If a handle is selected, handleRect is set to the handle rect. + /// otherwise return NoHandle and handleRect is set to the combined rect of + /// the min and max handles + Handle handleAtPos(const QPoint& pos, QRect& handleRect)const; + + /// Copied verbatim from QSliderPrivate class (see QSlider.cpp) + int pixelPosToRangeValue(int pos) const; + int pixelPosFromRangeValue(int val) const; + + /// Draw the bottom and top sliders. + void drawMinimumSlider( QStylePainter* painter ) const; + void drawMaximumSlider( QStylePainter* painter ) const; + + /// End points of the range on the Model + int m_MaximumValue; + int m_MinimumValue; + + /// End points of the range on the GUI. This is synced with the model. + int m_MaximumPosition; + int m_MinimumPosition; + + /// Controls selected ? + QStyle::SubControl m_MinimumSliderSelected; + QStyle::SubControl m_MaximumSliderSelected; + + /// See QSliderPrivate::clickOffset. + /// Overrides this ivar + int m_SubclassClickOffset; + + /// See QSliderPrivate::position + /// Overrides this ivar. + int m_SubclassPosition; + + /// Original width between the 2 bounds before any moves + float m_SubclassWidth; + + ctkRangeSliderPrivate::Handles m_SelectedHandles; + + /// When symmetricMoves is true, moving a handle will move the other handle + /// symmetrically, otherwise the handles are independent. + bool m_SymmetricMoves; + + QString m_HandleToolTip; + +private: + Q_DISABLE_COPY(ctkRangeSliderPrivate); +}; + +// -------------------------------------------------------------------------- +ctkRangeSliderPrivate::ctkRangeSliderPrivate(ctkRangeSlider& object) + :q_ptr(&object) +{ + this->m_MinimumValue = 0; + this->m_MaximumValue = 100; + this->m_MinimumPosition = 0; + this->m_MaximumPosition = 100; + this->m_MinimumSliderSelected = QStyle::SC_None; + this->m_MaximumSliderSelected = QStyle::SC_None; + this->m_SubclassClickOffset = 0; + this->m_SubclassPosition = 0; + this->m_SubclassWidth = 0.0; + this->m_SelectedHandles = 0; + this->m_SymmetricMoves = false; +} + +// -------------------------------------------------------------------------- +void ctkRangeSliderPrivate::init() +{ + Q_Q(ctkRangeSlider); + this->m_MinimumValue = q->minimum(); + this->m_MaximumValue = q->maximum(); + this->m_MinimumPosition = q->minimum(); + this->m_MaximumPosition = q->maximum(); + q->connect(q, SIGNAL(rangeChanged(int,int)), q, SLOT(onRangeChanged(int,int))); +} + +// -------------------------------------------------------------------------- +ctkRangeSliderPrivate::Handle ctkRangeSliderPrivate::handleAtPos(const QPoint& pos, QRect& handleRect)const +{ + Q_Q(const ctkRangeSlider); + + QStyleOptionSlider option; + q->initStyleOption( &option ); + + // The functinos hitTestComplexControl only know about 1 handle. As we have + // 2, we change the position of the handle and test if the pos correspond to + // any of the 2 positions. + + // Test the MinimumHandle + option.sliderPosition = this->m_MinimumPosition; + option.sliderValue = this->m_MinimumValue; + + QStyle::SubControl minimumControl = q->style()->hitTestComplexControl( + QStyle::CC_Slider, &option, pos, q); + QRect minimumHandleRect = q->style()->subControlRect( + QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q); + + // Test if the pos is under the Maximum handle + option.sliderPosition = this->m_MaximumPosition; + option.sliderValue = this->m_MaximumValue; + + QStyle::SubControl maximumControl = q->style()->hitTestComplexControl( + QStyle::CC_Slider, &option, pos, q); + QRect maximumHandleRect = q->style()->subControlRect( + QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q); + + // The pos is above both handles, select the closest handle + if (minimumControl == QStyle::SC_SliderHandle && + maximumControl == QStyle::SC_SliderHandle) + { + int minDist = 0; + int maxDist = 0; + if (q->orientation() == Qt::Horizontal) + { + minDist = pos.x() - minimumHandleRect.left(); + maxDist = maximumHandleRect.right() - pos.x(); + } + else //if (q->orientation() == Qt::Vertical) + { + minDist = minimumHandleRect.bottom() - pos.y(); + maxDist = pos.y() - maximumHandleRect.top(); + } + Q_ASSERT( minDist >= 0 && maxDist >= 0); + minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None; + } + + if (minimumControl == QStyle::SC_SliderHandle) + { + handleRect = minimumHandleRect; + return MinimumHandle; + } + else if (maximumControl == QStyle::SC_SliderHandle) + { + handleRect = maximumHandleRect; + return MaximumHandle; + } + handleRect = minimumHandleRect.united(maximumHandleRect); + return NoHandle; +} + +// -------------------------------------------------------------------------- +// Copied verbatim from QSliderPrivate::pixelPosToRangeValue. See QSlider.cpp +// +int ctkRangeSliderPrivate::pixelPosToRangeValue( int pos ) const +{ + Q_Q(const ctkRangeSlider); + QStyleOptionSlider option; + q->initStyleOption( &option ); + + QRect gr = q->style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderGroove, + q ); + QRect sr = q->style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderHandle, + q ); + int sliderMin, sliderMax, sliderLength; + if (option.orientation == Qt::Horizontal) + { + sliderLength = sr.width(); + sliderMin = gr.x(); + sliderMax = gr.right() - sliderLength + 1; + } + else + { + sliderLength = sr.height(); + sliderMin = gr.y(); + sliderMax = gr.bottom() - sliderLength + 1; + } + + return QStyle::sliderValueFromPosition( q->minimum(), + q->maximum(), + pos - sliderMin, + sliderMax - sliderMin, + option.upsideDown ); +} + +//--------------------------------------------------------------------------- +int ctkRangeSliderPrivate::pixelPosFromRangeValue( int val ) const +{ + Q_Q(const ctkRangeSlider); + QStyleOptionSlider option; + q->initStyleOption( &option ); + + QRect gr = q->style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderGroove, + q ); + QRect sr = q->style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderHandle, + q ); + int sliderMin, sliderMax, sliderLength; + if (option.orientation == Qt::Horizontal) + { + sliderLength = sr.width(); + sliderMin = gr.x(); + sliderMax = gr.right() - sliderLength + 1; + } + else + { + sliderLength = sr.height(); + sliderMin = gr.y(); + sliderMax = gr.bottom() - sliderLength + 1; + } + + return QStyle::sliderPositionFromValue( q->minimum(), + q->maximum(), + val, + sliderMax - sliderMin, + option.upsideDown ) + sliderMin; +} + +//--------------------------------------------------------------------------- +// Draw slider at the bottom end of the range +void ctkRangeSliderPrivate::drawMinimumSlider( QStylePainter* painter ) const +{ + Q_Q(const ctkRangeSlider); + QStyleOptionSlider option; + q->initMinimumSliderStyleOption( &option ); + + option.subControls = QStyle::SC_SliderHandle; + option.sliderValue = m_MinimumValue; + option.sliderPosition = m_MinimumPosition; + if (q->isMinimumSliderDown()) + { + option.activeSubControls = QStyle::SC_SliderHandle; + option.state |= QStyle::State_Sunken; + } +#ifdef Q_OS_MAC + // On mac style, drawing just the handle actually draws also the groove. + QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option, + QStyle::SC_SliderHandle, q); + painter->setClipRect(clip); +#endif + painter->drawComplexControl(QStyle::CC_Slider, option); +} + +//--------------------------------------------------------------------------- +// Draw slider at the top end of the range +void ctkRangeSliderPrivate::drawMaximumSlider( QStylePainter* painter ) const +{ + Q_Q(const ctkRangeSlider); + QStyleOptionSlider option; + q->initMaximumSliderStyleOption( &option ); + + option.subControls = QStyle::SC_SliderHandle; + option.sliderValue = m_MaximumValue; + option.sliderPosition = m_MaximumPosition; + if (q->isMaximumSliderDown()) + { + option.activeSubControls = QStyle::SC_SliderHandle; + option.state |= QStyle::State_Sunken; + } +#ifdef Q_OS_MAC + // On mac style, drawing just the handle actually draws also the groove. + QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option, + QStyle::SC_SliderHandle, q); + painter->setClipRect(clip); +#endif + painter->drawComplexControl(QStyle::CC_Slider, option); +} + +// -------------------------------------------------------------------------- +ctkRangeSlider::ctkRangeSlider(QWidget* _parent) + : QSlider(_parent) + , d_ptr(new ctkRangeSliderPrivate(*this)) +{ + Q_D(ctkRangeSlider); + d->init(); +} + +// -------------------------------------------------------------------------- +ctkRangeSlider::ctkRangeSlider( Qt::Orientation o, + QWidget* parentObject ) + :QSlider(o, parentObject) + , d_ptr(new ctkRangeSliderPrivate(*this)) +{ + Q_D(ctkRangeSlider); + d->init(); +} + +// -------------------------------------------------------------------------- +ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate* impl, QWidget* _parent) + : QSlider(_parent) + , d_ptr(impl) +{ + Q_D(ctkRangeSlider); + d->init(); +} + +// -------------------------------------------------------------------------- +ctkRangeSlider::ctkRangeSlider( ctkRangeSliderPrivate* impl, Qt::Orientation o, + QWidget* parentObject ) + :QSlider(o, parentObject) + , d_ptr(impl) +{ + Q_D(ctkRangeSlider); + d->init(); +} + +// -------------------------------------------------------------------------- +ctkRangeSlider::~ctkRangeSlider() +{ +} + +// -------------------------------------------------------------------------- +int ctkRangeSlider::minimumValue() const +{ + Q_D(const ctkRangeSlider); + return d->m_MinimumValue; +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setMinimumValue( int min ) +{ + Q_D(ctkRangeSlider); + this->setValues( min, qMax(d->m_MaximumValue,min) ); +} + +// -------------------------------------------------------------------------- +int ctkRangeSlider::maximumValue() const +{ + Q_D(const ctkRangeSlider); + return d->m_MaximumValue; +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setMaximumValue( int max ) +{ + Q_D(ctkRangeSlider); + this->setValues( qMin(d->m_MinimumValue, max), max ); +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setValues(int l, int u) +{ + Q_D(ctkRangeSlider); + const int minValue = + qBound(this->minimum(), qMin(l,u), this->maximum()); + const int maxValue = + qBound(this->minimum(), qMax(l,u), this->maximum()); + bool emitMinValChanged = (minValue != d->m_MinimumValue); + bool emitMaxValChanged = (maxValue != d->m_MaximumValue); + + d->m_MinimumValue = minValue; + d->m_MaximumValue = maxValue; + + bool emitMinPosChanged = + (minValue != d->m_MinimumPosition); + bool emitMaxPosChanged = + (maxValue != d->m_MaximumPosition); + d->m_MinimumPosition = minValue; + d->m_MaximumPosition = maxValue; + + if (isSliderDown()) + { + if (emitMinPosChanged || emitMaxPosChanged) + { + emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition); + } + if (emitMinPosChanged) + { + emit minimumPositionChanged(d->m_MinimumPosition); + } + if (emitMaxPosChanged) + { + emit maximumPositionChanged(d->m_MaximumPosition); + } + } + if (emitMinValChanged || emitMaxValChanged) + { + emit valuesChanged(d->m_MinimumValue, + d->m_MaximumValue); + } + if (emitMinValChanged) + { + emit minimumValueChanged(d->m_MinimumValue); + } + if (emitMaxValChanged) + { + emit maximumValueChanged(d->m_MaximumValue); + } + if (emitMinPosChanged || emitMaxPosChanged || + emitMinValChanged || emitMaxValChanged) + { + this->update(); + } +} + +// -------------------------------------------------------------------------- +int ctkRangeSlider::minimumPosition() const +{ + Q_D(const ctkRangeSlider); + return d->m_MinimumPosition; +} + +// -------------------------------------------------------------------------- +int ctkRangeSlider::maximumPosition() const +{ + Q_D(const ctkRangeSlider); + return d->m_MaximumPosition; +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setMinimumPosition(int l) +{ + Q_D(const ctkRangeSlider); + this->setPositions(l, qMax(l, d->m_MaximumPosition)); +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setMaximumPosition(int u) +{ + Q_D(const ctkRangeSlider); + this->setPositions(qMin(d->m_MinimumPosition, u), u); +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setPositions(int min, int max) +{ + Q_D(ctkRangeSlider); + const int minPosition = + qBound(this->minimum(), qMin(min, max), this->maximum()); + const int maxPosition = + qBound(this->minimum(), qMax(min, max), this->maximum()); + + bool emitMinPosChanged = (minPosition != d->m_MinimumPosition); + bool emitMaxPosChanged = (maxPosition != d->m_MaximumPosition); + + if (!emitMinPosChanged && !emitMaxPosChanged) + { + return; + } + + d->m_MinimumPosition = minPosition; + d->m_MaximumPosition = maxPosition; + + if (!this->hasTracking()) + { + this->update(); + } + if (isSliderDown()) + { + if (emitMinPosChanged) + { + emit minimumPositionChanged(d->m_MinimumPosition); + } + if (emitMaxPosChanged) + { + emit maximumPositionChanged(d->m_MaximumPosition); + } + if (emitMinPosChanged || emitMaxPosChanged) + { + emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition); + } + } + if (this->hasTracking()) + { + this->triggerAction(SliderMove); + this->setValues(d->m_MinimumPosition, d->m_MaximumPosition); + } +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setSymmetricMoves(bool symmetry) +{ + Q_D(ctkRangeSlider); + d->m_SymmetricMoves = symmetry; +} + +// -------------------------------------------------------------------------- +bool ctkRangeSlider::symmetricMoves()const +{ + Q_D(const ctkRangeSlider); + return d->m_SymmetricMoves; +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::onRangeChanged(int _minimum, int _maximum) +{ + Q_UNUSED(_minimum); + Q_UNUSED(_maximum); + Q_D(ctkRangeSlider); + this->setValues(d->m_MinimumValue, d->m_MaximumValue); +} + +// -------------------------------------------------------------------------- +// Render +void ctkRangeSlider::paintEvent( QPaintEvent* ) +{ + Q_D(ctkRangeSlider); + QStyleOptionSlider option; + this->initStyleOption(&option); + + QStylePainter painter(this); + option.subControls = QStyle::SC_SliderGroove; + // Move to minimum to not highlight the SliderGroove. + // On mac style, drawing just the slider groove also draws the handles, + // therefore we give a negative (outside of view) position. + option.sliderValue = this->minimum() - this->maximum(); + option.sliderPosition = this->minimum() - this->maximum(); + painter.drawComplexControl(QStyle::CC_Slider, option); + + option.sliderPosition = d->m_MinimumPosition; + const QRect lr = style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderHandle, + this); + option.sliderPosition = d->m_MaximumPosition; + + const QRect ur = style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderHandle, + this); + + QRect sr = style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderGroove, + this); + QRect rangeBox; + if (option.orientation == Qt::Horizontal) + { + rangeBox = QRect( + QPoint(qMin( lr.center().x(), ur.center().x() ), sr.center().y() - 2), + QPoint(qMax( lr.center().x(), ur.center().x() ), sr.center().y() + 1)); + } + else + { + rangeBox = QRect( + QPoint(sr.center().x() - 2, qMin( lr.center().y(), ur.center().y() )), + QPoint(sr.center().x() + 1, qMax( lr.center().y(), ur.center().y() ))); + } + + // ----------------------------- + // Render the range + // + QRect groove = this->style()->subControlRect( QStyle::CC_Slider, + &option, + QStyle::SC_SliderGroove, + this ); + groove.adjust(0, 0, -1, 0); + + // Create default colors based on the transfer function. + // + QColor highlight = this->palette().color(QPalette::Normal, QPalette::Highlight); + QLinearGradient gradient; + if (option.orientation == Qt::Horizontal) + { + gradient = QLinearGradient( groove.center().x(), groove.top(), + groove.center().x(), groove.bottom()); + } + else + { + gradient = QLinearGradient( groove.left(), groove.center().y(), + groove.right(), groove.center().y()); + } + + // TODO: Set this based on the supplied transfer function + //QColor l = Qt::darkGray; + //QColor u = Qt::black; + + gradient.setColorAt(0, highlight.darker(120)); + gradient.setColorAt(1, highlight.lighter(160)); + + painter.setPen(QPen(highlight.darker(150), 0)); + painter.setBrush(gradient); + painter.drawRect( rangeBox.intersected(groove) ); + + // ----------------------------------- + // Render the sliders + // + if (this->isMinimumSliderDown()) + { + d->drawMaximumSlider( &painter ); + d->drawMinimumSlider( &painter ); + } + else + { + d->drawMinimumSlider( &painter ); + d->drawMaximumSlider( &painter ); + } +} + +// -------------------------------------------------------------------------- +// Standard Qt UI events +void ctkRangeSlider::mousePressEvent(QMouseEvent* mouseEvent) +{ + Q_D(ctkRangeSlider); + if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button())) + { + mouseEvent->ignore(); + return; + } + int mepos = this->orientation() == Qt::Horizontal ? + mouseEvent->pos().x() : mouseEvent->pos().y(); + + QStyleOptionSlider option; + this->initStyleOption( &option ); + + QRect handleRect; + ctkRangeSliderPrivate::Handle handle_ = d->handleAtPos(mouseEvent->pos(), handleRect); + + if (handle_ != ctkRangeSliderPrivate::NoHandle) + { + d->m_SubclassPosition = (handle_ == ctkRangeSliderPrivate::MinimumHandle)? + d->m_MinimumPosition : d->m_MaximumPosition; + + // save the position of the mouse inside the handle for later + d->m_SubclassClickOffset = mepos - (this->orientation() == Qt::Horizontal ? + handleRect.left() : handleRect.top()); + + this->setSliderDown(true); + + if (d->m_SelectedHandles != handle_) + { + d->m_SelectedHandles = handle_; + this->update(handleRect); + } + // Accept the mouseEvent + mouseEvent->accept(); + return; + } + + // if we are here, no handles have been pressed + // Check if we pressed on the groove between the 2 handles + + QStyle::SubControl control = this->style()->hitTestComplexControl( + QStyle::CC_Slider, &option, mouseEvent->pos(), this); + QRect sr = style()->subControlRect( + QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this); + int minCenter = (this->orientation() == Qt::Horizontal ? + handleRect.left() : handleRect.top()); + int maxCenter = (this->orientation() == Qt::Horizontal ? + handleRect.right() : handleRect.bottom()); + if (control == QStyle::SC_SliderGroove && + mepos > minCenter && mepos < maxCenter) + { + // warning lost of precision it might be fatal + d->m_SubclassPosition = (d->m_MinimumPosition + d->m_MaximumPosition) / 2.; + d->m_SubclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_SubclassPosition); + d->m_SubclassWidth = (d->m_MaximumPosition - d->m_MinimumPosition) / 2.; + qMax(d->m_SubclassPosition - d->m_MinimumPosition, d->m_MaximumPosition - d->m_SubclassPosition); + this->setSliderDown(true); + if (!this->isMinimumSliderDown() || !this->isMaximumSliderDown()) + { + d->m_SelectedHandles = + QFlags(ctkRangeSliderPrivate::MinimumHandle) | + QFlags(ctkRangeSliderPrivate::MaximumHandle); + this->update(handleRect.united(sr)); + } + mouseEvent->accept(); + return; + } + mouseEvent->ignore(); +} + +// -------------------------------------------------------------------------- +// Standard Qt UI events +void ctkRangeSlider::mouseMoveEvent(QMouseEvent* mouseEvent) +{ + Q_D(ctkRangeSlider); + if (!d->m_SelectedHandles) + { + mouseEvent->ignore(); + return; + } + int mepos = this->orientation() == Qt::Horizontal ? + mouseEvent->pos().x() : mouseEvent->pos().y(); + + QStyleOptionSlider option; + this->initStyleOption(&option); + + const int m = style()->pixelMetric( QStyle::PM_MaximumDragDistance, &option, this ); + + int newPosition = d->pixelPosToRangeValue(mepos - d->m_SubclassClickOffset); + + if (m >= 0) + { + const QRect r = rect().adjusted(-m, -m, m, m); + if (!r.contains(mouseEvent->pos())) + { + newPosition = d->m_SubclassPosition; + } + } + + // Only the lower/left slider is down + if (this->isMinimumSliderDown() && !this->isMaximumSliderDown()) + { + double newMinPos = qMin(newPosition,d->m_MaximumPosition); + this->setPositions(newMinPos, d->m_MaximumPosition + + (d->m_SymmetricMoves ? d->m_MinimumPosition - newMinPos : 0)); + } + // Only the upper/right slider is down + else if (this->isMaximumSliderDown() && !this->isMinimumSliderDown()) + { + double newMaxPos = qMax(d->m_MinimumPosition, newPosition); + this->setPositions(d->m_MinimumPosition - + (d->m_SymmetricMoves ? newMaxPos - d->m_MaximumPosition: 0), + newMaxPos); + } + // Both handles are down (the user clicked in between the handles) + else if (this->isMinimumSliderDown() && this->isMaximumSliderDown()) + { + this->setPositions(newPosition - static_cast(d->m_SubclassWidth), + newPosition + static_cast(d->m_SubclassWidth + .5)); + } + mouseEvent->accept(); +} + +// -------------------------------------------------------------------------- +// Standard Qt UI mouseEvents +void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent) +{ + Q_D(ctkRangeSlider); + this->QSlider::mouseReleaseEvent(mouseEvent); + + setSliderDown(false); + d->m_SelectedHandles = 0; + + this->update(); +} + +// -------------------------------------------------------------------------- +bool ctkRangeSlider::isMinimumSliderDown()const +{ + Q_D(const ctkRangeSlider); + return d->m_SelectedHandles & ctkRangeSliderPrivate::MinimumHandle; +} + +// -------------------------------------------------------------------------- +bool ctkRangeSlider::isMaximumSliderDown()const +{ + Q_D(const ctkRangeSlider); + return d->m_SelectedHandles & ctkRangeSliderPrivate::MaximumHandle; +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const +{ + this->initStyleOption(option); +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider* option) const +{ + this->initStyleOption(option); +} + +// -------------------------------------------------------------------------- +QString ctkRangeSlider::handleToolTip()const +{ + Q_D(const ctkRangeSlider); + return d->m_HandleToolTip; +} + +// -------------------------------------------------------------------------- +void ctkRangeSlider::setHandleToolTip(const QString& _toolTip) +{ + Q_D(ctkRangeSlider); + d->m_HandleToolTip = _toolTip; +} + +// -------------------------------------------------------------------------- +bool ctkRangeSlider::event(QEvent* _event) +{ + Q_D(ctkRangeSlider); + switch(_event->type()) + { + case QEvent::ToolTip: + { + QHelpEvent* helpEvent = static_cast(_event); + QStyleOptionSlider opt; + // Test the MinimumHandle + opt.sliderPosition = d->m_MinimumPosition; + opt.sliderValue = d->m_MinimumValue; + this->initStyleOption(&opt); + QStyle::SubControl hoveredControl = + this->style()->hitTestComplexControl( + QStyle::CC_Slider, &opt, helpEvent->pos(), this); + if (!d->m_HandleToolTip.isEmpty() && + hoveredControl == QStyle::SC_SliderHandle) + { + QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->minimumValue())); + _event->accept(); + return true; + } + // Test the MaximumHandle + opt.sliderPosition = d->m_MaximumPosition; + opt.sliderValue = d->m_MaximumValue; + this->initStyleOption(&opt); + hoveredControl = this->style()->hitTestComplexControl( + QStyle::CC_Slider, &opt, helpEvent->pos(), this); + if (!d->m_HandleToolTip.isEmpty() && + hoveredControl == QStyle::SC_SliderHandle) + { + QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->maximumValue())); + _event->accept(); + return true; + } + } + default: + break; + } + return this->Superclass::event(_event); +} diff --git a/src/qtgui/ctk/ctkRangeSlider.h b/src/qtgui/ctk/ctkRangeSlider.h new file mode 100644 index 0000000..dea72b7 --- /dev/null +++ b/src/qtgui/ctk/ctkRangeSlider.h @@ -0,0 +1,210 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef __ctkRangeSlider_h +#define __ctkRangeSlider_h + +// Qt includes +#include + +// CTK includes +#include "ctkPimpl.h" + +class QStylePainter; +class ctkRangeSliderPrivate; + +/// \ingroup Widgets +/// +/// A ctkRangeSlider is a slider that lets you input 2 values instead of one +/// (see QSlider). These values are typically a lower and upper bound. +/// Values are comprised between the range of the slider. See setRange(), +/// minimum() and maximum(). The upper bound can't be smaller than the +/// lower bound and vice-versa. +/// When setting new values (setMinimumValue(), setMaximumValue() or +/// setValues()), make sure they lie between the range (minimum(), maximum()) +/// of the slider, they would be forced otherwised. If it is not the behavior +/// you desire, you can set the range first (setRange(), setMinimum(), +/// setMaximum()) +/// TODO: support triggerAction(QAbstractSlider::SliderSingleStepSub) that +/// moves both values at a time. +/// \sa ctkDoubleRangeSlider, ctkDoubleSlider, ctkRangeWidget +class ctkRangeSlider : public QSlider +{ + Q_OBJECT + Q_PROPERTY(int minimumValue READ minimumValue WRITE setMinimumValue) + Q_PROPERTY(int maximumValue READ maximumValue WRITE setMaximumValue) + Q_PROPERTY(int minimumPosition READ minimumPosition WRITE setMinimumPosition) + Q_PROPERTY(int maximumPosition READ maximumPosition WRITE setMaximumPosition) + Q_PROPERTY(bool symmetricMoves READ symmetricMoves WRITE setSymmetricMoves) + Q_PROPERTY(QString handleToolTip READ handleToolTip WRITE setHandleToolTip) + +public: + // Superclass typedef + typedef QSlider Superclass; + /// Constructor, builds a ctkRangeSlider that ranges from 0 to 100 and has + /// a lower and upper values of 0 and 100 respectively, other properties + /// are set the QSlider default properties. + explicit ctkRangeSlider( Qt::Orientation o, QWidget* par= 0 ); + explicit ctkRangeSlider( QWidget* par = 0 ); + virtual ~ctkRangeSlider(); + + /// + /// This property holds the slider's current minimum value. + /// The slider silently forces minimumValue to be within the legal range: + /// minimum() <= minimumValue() <= maximumValue() <= maximum(). + /// Changing the minimumValue also changes the minimumPosition. + int minimumValue() const; + + /// + /// This property holds the slider's current maximum value. + /// The slider forces the maximum value to be within the legal range: + /// The slider silently forces maximumValue to be within the legal range: + /// Changing the maximumValue also changes the maximumPosition. + int maximumValue() const; + + /// + /// This property holds the current slider minimum position. + /// If tracking is enabled (the default), this is identical to minimumValue. + int minimumPosition() const; + void setMinimumPosition(int min); + + /// + /// This property holds the current slider maximum position. + /// If tracking is enabled (the default), this is identical to maximumValue. + int maximumPosition() const; + void setMaximumPosition(int max); + + /// + /// Utility function that set the minimum position and + /// maximum position at once. + void setPositions(int min, int max); + + /// + /// When symmetricMoves is true, moving a handle will move the other handle + /// symmetrically, otherwise the handles are independent. False by default + bool symmetricMoves()const; + void setSymmetricMoves(bool symmetry); + + /// + /// Controls the text to display for the handle tooltip. It is in addition + /// to the widget tooltip. + /// "%1" is replaced by the current value of the slider. + /// Empty string (by default) means no tooltip. + QString handleToolTip()const; + void setHandleToolTip(const QString& toolTip); + + /// Returns true if the minimum value handle is down, false if it is up. + /// \sa isMaximumSliderDown() + bool isMinimumSliderDown()const; + /// Returns true if the maximum value handle is down, false if it is up. + /// \sa isMinimumSliderDown() + bool isMaximumSliderDown()const; + +Q_SIGNALS: + /// + /// This signal is emitted when the slider minimum value has changed, + /// with the new slider value as argument. + void minimumValueChanged(int min); + /// + /// This signal is emitted when the slider maximum value has changed, + /// with the new slider value as argument. + void maximumValueChanged(int max); + /// + /// Utility signal that is fired when minimum or maximum values have changed. + void valuesChanged(int min, int max); + + /// + /// This signal is emitted when sliderDown is true and the slider moves. + /// This usually happens when the user is dragging the minimum slider. + /// The value is the new slider minimum position. + /// This signal is emitted even when tracking is turned off. + void minimumPositionChanged(int min); + + /// + /// This signal is emitted when sliderDown is true and the slider moves. + /// This usually happens when the user is dragging the maximum slider. + /// The value is the new slider maximum position. + /// This signal is emitted even when tracking is turned off. + void maximumPositionChanged(int max); + + /// + /// Utility signal that is fired when minimum or maximum positions + /// have changed. + void positionsChanged(int min, int max); + +public Q_SLOTS: + /// + /// This property holds the slider's current minimum value. + /// The slider silently forces min to be within the legal range: + /// minimum() <= min <= maximumValue() <= maximum(). + /// Note: Changing the minimumValue also changes the minimumPosition. + /// \sa stMaximumValue, setValues, setMinimum, setMaximum, setRange + void setMinimumValue(int min); + + /// + /// This property holds the slider's current maximum value. + /// The slider silently forces max to be within the legal range: + /// minimum() <= minimumValue() <= max <= maximum(). + /// Note: Changing the maximumValue also changes the maximumPosition. + /// \sa stMinimumValue, setValues, setMinimum, setMaximum, setRange + void setMaximumValue(int max); + + /// + /// Utility function that set the minimum value and maximum value at once. + /// The slider silently forces min and max to be within the legal range: + /// minimum() <= min <= max <= maximum(). + /// Note: Changing the minimumValue and maximumValue also changes the + /// minimumPosition and maximumPosition. + /// \sa setMinimumValue, setMaximumValue, setMinimum, setMaximum, setRange + void setValues(int min, int max); + +protected Q_SLOTS: + void onRangeChanged(int minimum, int maximum); + +protected: + ctkRangeSlider( ctkRangeSliderPrivate* impl, Qt::Orientation o, QWidget* par= 0 ); + ctkRangeSlider( ctkRangeSliderPrivate* impl, QWidget* par = 0 ); + + // Description: + // Standard Qt UI events + virtual void mousePressEvent(QMouseEvent* ev); + virtual void mouseMoveEvent(QMouseEvent* ev); + virtual void mouseReleaseEvent(QMouseEvent* ev); + + // Description: + // Rendering is done here. + virtual void paintEvent(QPaintEvent* ev); + virtual void initMinimumSliderStyleOption(QStyleOptionSlider* option) const; + virtual void initMaximumSliderStyleOption(QStyleOptionSlider* option) const; + + // Description: + // Reimplemented for the tooltips + virtual bool event(QEvent* event); + +protected: + QScopedPointer d_ptr; + +private: + Q_DECLARE_PRIVATE(ctkRangeSlider); + Q_DISABLE_COPY(ctkRangeSlider); +}; + +#endif + From 50f3e4660566288e907b55032bafa8587661711c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 01:27:58 +0200 Subject: [PATCH 102/334] Separate dB ranges for pandapter and waterfall. Also use new CTK sliders for setting the dB ranges. --- resources/news.txt | 1 + src/applications/gqrx/mainwindow.cpp | 8 +- src/qtgui/dockaudio.cpp | 4 +- src/qtgui/dockfft.cpp | 103 +-- src/qtgui/dockfft.h | 14 +- src/qtgui/dockfft.ui | 935 +++++++++++++-------------- src/qtgui/plotter.cpp | 97 +-- src/qtgui/plotter.h | 15 +- 8 files changed, 601 insertions(+), 576 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index ec88306..84ab118 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -4,6 +4,7 @@ NEW: Audio waterfall. NEW: Remember AGC settings between sessions. NEW: Right-click on FFT resets frequency zoom. + NEW: Separate dB ranges for pandapter and waterfall. FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 4eb8d8e..62daa14 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -229,8 +229,12 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : connect(uiDockFft, SIGNAL(gotoFftCenter()), ui->plotter, SLOT(moveToCenterFreq())); connect(uiDockFft, SIGNAL(gotoDemodFreq()), ui->plotter, SLOT(moveToDemodFreq())); - connect(uiDockFft, SIGNAL(fftRangeChanged(float,float)), ui->plotter, SLOT(setFftRange(float,float))); - connect(ui->plotter, SIGNAL(fftRangeChanged(float,float)), uiDockFft, SLOT(setFftRange(float,float))); + connect(uiDockFft, SIGNAL(pandapterRangeChanged(float,float)), + ui->plotter, SLOT(setPandapterRange(float,float))); + connect(uiDockFft, SIGNAL(waterfallRangeChanged(float,float)), + ui->plotter, SLOT(setWaterfallRange(float,float))); + connect(ui->plotter, SIGNAL(pandapterRangeChanged(float,float)), + uiDockFft, SLOT(setPandapterRange(float,float))); connect(uiDockFft, SIGNAL(fftColorChanged(QColor)), this, SLOT(setFftColor(QColor))); connect(uiDockFft, SIGNAL(fftFillToggled(bool)), this, SLOT(setFftFill(bool))); diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 700f20d..1b7bbfa 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -68,7 +68,7 @@ DockAudio::DockAudio(QWidget *parent) : ui->audioSpectrum->setFilterBoxEnabled(false); ui->audioSpectrum->setCenterLineEnabled(false); ui->audioSpectrum->setBookmarksEnabled(false); - ui->audioSpectrum->setMinMaxDB(-80, 0); + ui->audioSpectrum->setFftRange(-80., 0.); ui->audioSpectrum->setVdivDelta(40); ui->audioSpectrum->setHdivDelta(40); ui->audioSpectrum->setFreqDigits(1); @@ -349,7 +349,7 @@ void DockAudio::readSettings(QSettings *settings) void DockAudio::setNewFftMin(int min_db) { - ui->audioSpectrum->setMinMaxDB(min_db, 0.f); + ui->audioSpectrum->setFftRange(min_db, 0.f); } /*! \brief Slot called when a new valid recording directory has been selected diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index 0e66f98..416795b 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -27,14 +27,12 @@ #include "dockfft.h" #include "ui_dockfft.h" -#define DEFAULT_FFT_MAXIMUM_DB -0.0 -#define DEFAULT_FFT_MINIMUM_DB -135.0 -#define DEFAULT_FFT_RATE 25 -#define DEFAULT_FFT_SIZE 8192 -#define DEFAULT_FFT_SPLIT 35 -#define DEFAULT_FFT_AVG 75 -#define DEFAULT_FFT_REF_LEVEL 0 -#define DEFAULT_FFT_RANGE 130 +#define DEFAULT_FFT_MAX_DB -0 +#define DEFAULT_FFT_MIN_DB -135 +#define DEFAULT_FFT_RATE 25 +#define DEFAULT_FFT_SIZE 8192 +#define DEFAULT_FFT_SPLIT 35 +#define DEFAULT_FFT_AVG 75 DockFft::DockFft(QWidget *parent) : QDockWidget(parent), @@ -221,15 +219,30 @@ void DockFft::saveSettings(QSettings *settings) else settings->remove("pandapter_fill"); - if (ui->reflevelSlider->value() != DEFAULT_FFT_REF_LEVEL) - settings->setValue("reference_level", ui->reflevelSlider->value()); + // dB ranges + intval = ui->pandRangeSlider->minimumValue(); + if (intval == DEFAULT_FFT_MIN_DB) + settings->remove("pandapter_min_db"); else - settings->remove("reference_level"); + settings->setValue("pandapter_min_db", intval); - if (ui->rangeSlider->value() != DEFAULT_FFT_RANGE) - settings->setValue("fft_range", ui->rangeSlider->value()); + intval = ui->pandRangeSlider->maximumValue(); + if (intval == DEFAULT_FFT_MAX_DB) + settings->remove("pandapter_max_db"); else - settings->remove("fft_range"); + settings->setValue("pandapter_max_db", intval); + + intval = ui->wfRangeSlider->minimumValue(); + if (intval == DEFAULT_FFT_MIN_DB) + settings->remove("waterfall_min_db"); + else + settings->setValue("waterfall_min_db", intval); + + intval = ui->wfRangeSlider->maximumValue(); + if (intval == DEFAULT_FFT_MAX_DB) + settings->remove("waterfall_max_db"); + else + settings->setValue("waterfall_max_db", intval); settings->endGroup(); } @@ -237,10 +250,11 @@ void DockFft::saveSettings(QSettings *settings) /** Read FFT settings. */ void DockFft::readSettings(QSettings *settings) { - int intval; - bool bool_val = false; - bool conv_ok = false; - QColor color; + int intval; + int fft_min, fft_max; + bool bool_val = false; + bool conv_ok = false; + QColor color; if (!settings) return; @@ -269,25 +283,38 @@ void DockFft::readSettings(QSettings *settings) bool_val = settings->value("pandapter_fill", false).toBool(); ui->fillButton->setChecked(bool_val); - int ref = settings->value("reference_level", DEFAULT_FFT_REF_LEVEL).toInt(&conv_ok); - int range = settings->value("fft_range", DEFAULT_FFT_RANGE).toInt(&conv_ok); - setFftRange(ref, range); - emit fftRangeChanged(ui->reflevelSlider->value(), ui->rangeSlider->value()); + // delete old dB settings from config + if (settings->contains("reference_level")) + settings->remove("reference_level"); + + if (settings->contains("fft_range")) + settings->remove("fft_range"); + + fft_max = settings->value("pandapter_max_db", DEFAULT_FFT_MAX_DB).toInt(); + fft_min = settings->value("pandapter_min_db", DEFAULT_FFT_MIN_DB).toInt(); + setPandapterRange(fft_min, fft_max); + emit pandapterRangeChanged((float) fft_min, (float) fft_max); + + fft_max = settings->value("waterfall_max_db", DEFAULT_FFT_MAX_DB).toInt(); + fft_min = settings->value("waterfall_min_db", DEFAULT_FFT_MIN_DB).toInt(); + setWaterfallRange(fft_min, fft_max); + emit waterfallRangeChanged((float) fft_min, (float) fft_max); settings->endGroup(); } -void DockFft::setFftRange(float reflevel, float range) +void DockFft::setPandapterRange(float min, float max) +{ + ui->pandRangeSlider->blockSignals(true); + ui->pandRangeSlider->setValues((int) min, (int) max); + ui->pandRangeSlider->blockSignals(false); +} + +void DockFft::setWaterfallRange(float min, float max) { - ui->reflevelSlider->blockSignals(true); - ui->reflevelSlider->setValue((int)reflevel); - ui->reflevelSlider->blockSignals(false); - ui->reflevelLabel->setText(QString("%1 dB").arg((int)reflevel)); - - ui->rangeSlider->blockSignals(true); - ui->rangeSlider->setValue((int)range); - ui->rangeSlider->blockSignals(false); - ui->rangeLabel->setText(QString("%1 dB").arg((int)range)); + ui->wfRangeSlider->blockSignals(true); + ui->wfRangeSlider->setValues((int) min, (int) max); + ui->wfRangeSlider->blockSignals(false); } /** FFT size changed. */ @@ -367,18 +394,14 @@ void DockFft::on_fftZoomSlider_valueChanged(int level) emit fftZoomChanged((float)level); } -/** Reference level changed */ -void DockFft::on_reflevelSlider_valueChanged(int value) +void DockFft::on_pandRangeSlider_valuesChanged(int min, int max) { - ui->reflevelLabel->setText(QString("%1 dB").arg(value)); - emit fftRangeChanged(value, ui->rangeSlider->value()); + emit pandapterRangeChanged((float) min, (float) max); } -/** FFT plot range changed */ -void DockFft::on_rangeSlider_valueChanged(int value) +void DockFft::on_wfRangeSlider_valuesChanged(int min, int max) { - ui->rangeLabel->setText(QString("%1 dB").arg(value)); - emit fftRangeChanged(ui->reflevelSlider->value(), value); + emit waterfallRangeChanged((float) min, (float) max); } void DockFft::on_resetButton_clicked(void) diff --git a/src/qtgui/dockfft.h b/src/qtgui/dockfft.h index c9e724a..ba6458c 100644 --- a/src/qtgui/dockfft.h +++ b/src/qtgui/dockfft.h @@ -57,7 +57,8 @@ class DockFft : public QDockWidget void fftSplitChanged(int pct); /*! Split between pandapter and waterfall changed. */ void fftZoomChanged(float level); /*! Zoom level slider changed. */ void fftAvgChanged(float gain); /*! FFT video filter gain has changed. */ - void fftRangeChanged(float reflevel, float range); + void pandapterRangeChanged(float min, float max); + void waterfallRangeChanged(float min, float max); void resetFftZoom(void); /*! FFT zoom reset. */ void gotoFftCenter(void); /*! Go to FFT center. */ void gotoDemodFreq(void); /*! Center FFT around demodulator frequency. */ @@ -67,7 +68,8 @@ class DockFft : public QDockWidget void peakDetectionToggled(bool enabled); /*! Enable peak detection in FFT plot */ public slots: - void setFftRange(float reflevel, float range); + void setPandapterRange(float min, float max); + void setWaterfallRange(float min, float max); void setWfResolution(quint64 msec_per_line); private slots: @@ -77,8 +79,8 @@ private slots: void on_fftSplitSlider_valueChanged(int value); void on_fftAvgSlider_valueChanged(int value); void on_fftZoomSlider_valueChanged(int level); - void on_reflevelSlider_valueChanged(int value); - void on_rangeSlider_valueChanged(int value); + void on_pandRangeSlider_valuesChanged(int min, int max); + void on_wfRangeSlider_valuesChanged(int min, int max); void on_resetButton_clicked(void); void on_centerButton_clicked(void); void on_demodButton_clicked(void); @@ -92,8 +94,8 @@ private slots: private: Ui::DockFft * ui; - float m_maximumFftDb; - float m_minimumFftDb; +// float m_maximumFftDb; +// float m_minimumFftDb; float m_sample_rate; }; diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index 71f159f..212aef5 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -6,8 +6,8 @@ 0 0 - 260 - 229 + 275 + 245 @@ -18,7 +18,7 @@ - 260 + 275 200 @@ -44,19 +44,19 @@ - 2 + 5 - 2 + 5 - 2 + 5 - 2 + 5 - 2 + 5 @@ -77,31 +77,116 @@ 0 0 - 252 - 367 + 251 + 319 + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + 5 - - + + + + Set pandapter dB range + + + Set pandapter dB range + + + -160 + + + 0 + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Current zoom level on the frequency axis + + + Current zoom level on the frequency axis + - FFT size + 1x + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Peak Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - true + + + + Set zoom level on the frequency axis + + Set zoom level on the frequency axis + + + Freq zoom + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Set waterfall dB range + + + Set waterfall dB range + + + Wf. dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 0 @@ -111,104 +196,39 @@ 0 - 0 + 22 - <html>Number of FFT points to calculate. Higher values will require more CPU time. This will not influence the number of points on the display since that parameter is adjusted automatically according to the display size. -</html> + Spatial distribution between pandapter and waterfall - - false + + 0 - - 7 + + 100 - - 15 + + 50 - - QComboBox::InsertAlphabetically + + Qt::Horizontal - - - 1048576 - - - - - 524288 - - - - - 262144 - - - - - 131072 - - - - - 65536 - - - - - 32768 - - - - - 16384 - - - - - 8192 - - - - - 4096 - - - - - 3840 - - - - - 2048 - - - - - 1024 - - - - - 768 - - - - - 512 - - - - + + - Resolution bandwidth + The vertical time span on the waterfall. + + + - RBW: 0 kHz + Time span + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -222,244 +242,201 @@ - - + + + + Set waterfall dB range + + + Set waterfall dB range + + + -160 + + + 0 + + + Qt::Horizontal + + + + + + + Set pandapter dB range + + + Set pandapter dB range + + + Pand. dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + - + 0 0 - - - 0 - 0 - - - FFT refresh rate + FFT averaging gain - - 3 + + Averaging + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 60 fps - - - - - 50 fps - - - - - 30 fps - - - - - 25 fps - - - - - 20 fps - - - - - 17 fps - - - - - 15 fps - - - - - 10 fps - - - - - 5 fps - - - - - 1 fps - - - - - 0 fps - - - - + + - FFT buffer overlap between two consecutive FFT calculations. + Resolution bandwidth - Overlap: 0% + RBW: 0 kHz - - + + - The vertical time span on the waterfall. - - - + Color for the FFT plot - Time span + Color Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - The vertical time span on the waterfall. + + + + + + true + + + + 0 + 0 + + + + + 0 + 0 + + + + <html>Number of FFT points to calculate. Higher values will require more CPU time. This will not influence the number of points on the display since that parameter is adjusted automatically according to the display size. +</html> + + + false + + + 7 + + + 15 + + + QComboBox::InsertAlphabetically - Auto + 1048576 - 5 min + 524288 - 10 min + 262144 - 15 min + 131072 - 20 min + 65536 - 30 min + 32768 - 1 hour + 16384 - 2 hours + 8192 - 5 hours + 4096 - 10 hours + 3840 - 16 hours + 2048 - 24 hours + 1024 - 48 hours + 768 + + + + + 512 - - - - Waterfall time resolution. - - - - - - Res: - s - - - - - + + - + 0 0 - - FFT averaging gain - - Averaging + Waterfall - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 22 - - - - FFT averaging gain - - - 100 - - - 50 - - - Qt::Horizontal - - - false - - - false + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -479,8 +456,8 @@ - - + + 0 @@ -489,50 +466,21 @@ - 0 - 22 + 50 + 32 - Spatial distribution between pandapter and waterfall - - - 0 - - - 100 - - - 50 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - WF + Click to select color for the FFT plot - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + Click to select color for the FFT plot - - - - - Peak + - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + true @@ -608,147 +556,14 @@ Hold - true - - - - - - - - - The reference level is the level at the top of the FFT plot - - - Ref. level - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 22 - - - - The reference level is the level at the top of the FFT plot - - - -100 - - - 0 - - - 0 - - - 0 - - - Qt::Horizontal - - - false - - - - - - - The reference level is the level at the top of the FFT plot - - - - - - 0 dB - - - - - - - The range of the FFT plot - - - dB range - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 22 - - - - The range of the FFT plot - - - 10 - - - 200 - - - 130 - - - 130 - - - Qt::Horizontal - - - - - - - The range of the FFT plot - - - 130 dB - - - - - - - Zooming shortcuts - - - Zoom - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + true + + + + - - + + 0 @@ -762,16 +577,13 @@ - Zoom level for zooming in on the frequency axis. - - - 1 + FFT averaging gain - 50 + 100 - - 5 + + 50 Qt::Horizontal @@ -782,27 +594,90 @@ false - - QSlider::NoTicks - - - - - - 0 - 0 - + + + + The vertical time span on the waterfall. + + + Auto + + + + + 5 min + + + + + 10 min + + + + + 15 min + + + + + 20 min + + + + + 30 min + + + + + 1 hour + + + + + 2 hours + + + + + 5 hours + + + + + 10 hours + + + + + 16 hours + + + + + 24 hours + + + + + 48 hours + + + + + + - Current zoom level + Waterfall time resolution. - - 1x + + - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + Res: - s @@ -897,21 +772,8 @@ - - - - Color for the FFT plot - - - Color - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - + + 0 @@ -920,21 +782,46 @@ - 50 - 32 + 0 + 22 - Click to select color for the FFT plot + Set zoom level on the frequency axis - Click to select color for the FFT plot + Set zoom level on the frequency axis - - + + 1 - - true + + 50 + + + 5 + + + Qt::Horizontal + + + false + + + false + + + QSlider::NoTicks + + + + + + + FFT buffer overlap between two consecutive FFT calculations. + + + Overlap: 0% @@ -972,6 +859,93 @@ + + + + FFT size + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + FFT refresh rate + + + 3 + + + + 60 fps + + + + + 50 fps + + + + + 30 fps + + + + + 25 fps + + + + + 20 fps + + + + + 17 fps + + + + + 15 fps + + + + + 10 fps + + + + + 5 fps + + + + + 1 fps + + + + + 0 fps + + + + @@ -1000,6 +974,11 @@ QPushButton
qtgui/qtcolorpicker.h
+ + ctkRangeSlider + QSlider +
qtgui/ctk/ctkRangeSlider.h
+
diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index c49eaf6..f978953 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -72,11 +72,8 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) #define CUR_CUT_DELTA 5 //cursor capture delta in pixels -// dB-axis constraints -#define REF_LEVEL_MAX 0.f -#define REF_LEVEL_MIN -100.f -#define FFT_RANGE_MIN 10.f -#define FFT_RANGE_MAX 200.f +#define FFT_MIN_DB -160.f +#define FFT_MAX_DB 0.f // Colors of type QRgb in 0xAARRGGBB format (unsigned int) #define PLOTTER_BGD_COLOR 0xFF1F1D1D @@ -89,13 +86,14 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) static inline bool val_is_out_of_range(float val, float min, float max) { - return ((val < min) || (val > max)); + return (val < min || val > max); } -static inline bool out_of_range(float ref, float range) +static inline bool out_of_range(float min, float max) { - return (val_is_out_of_range(ref, REF_LEVEL_MIN, REF_LEVEL_MAX) || - val_is_out_of_range(range, FFT_RANGE_MIN, FFT_RANGE_MAX)); + return (val_is_out_of_range(min, FFT_MIN_DB, FFT_MAX_DB) || + val_is_out_of_range(max, FFT_MIN_DB, FFT_MAX_DB) || + max < min + 10.f); } /** Current time in milliseconds since Epoch */ @@ -177,8 +175,8 @@ CPlotter::CPlotter(QWidget *parent) : QFrame(parent) m_HorDivs = 12; m_VerDivs = 6; - m_MaxdB = 0; - m_MindB = -115; + m_PandMaxdB = m_WfMaxdB = 0.f; + m_PandMindB = m_WfMindB = -150.f; m_FreqUnits = 1000000; m_CursorCaptured = NOCAP; @@ -349,17 +347,18 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) setCursor(QCursor(Qt::ClosedHandCursor)); // move Y scale up/down float delta_px = m_Yzero - pt.y(); - float delta_db = delta_px * fabs(m_MindB-m_MaxdB) / (float)m_OverlayPixmap.height(); - m_MindB -= delta_db; - m_MaxdB -= delta_db; - if (out_of_range(m_MaxdB, m_MaxdB - m_MindB)) + float delta_db = delta_px * fabs(m_PandMindB - m_PandMaxdB) / + (float)m_OverlayPixmap.height(); + m_PandMindB -= delta_db; + m_PandMaxdB -= delta_db; + if (out_of_range(m_PandMindB, m_PandMaxdB)) { - m_MindB += delta_db; - m_MaxdB += delta_db; + m_PandMindB += delta_db; + m_PandMaxdB += delta_db; } else { - emit fftRangeChanged(m_MaxdB, m_MaxdB - m_MindB); + emit pandapterRangeChanged(m_PandMindB, m_PandMaxdB); if (m_Running) m_DrawOverlay = true; @@ -799,20 +798,20 @@ void CPlotter::wheelEvent(QWheelEvent * event) // During zoom we try to keep the point (dB or kHz) under the cursor fixed float zoom_fac = event->delta() < 0 ? 1.1 : 0.9; float ratio = (float)pt.y() / (float)m_OverlayPixmap.height(); - float db_range = (float)(m_MaxdB - m_MindB); + float db_range = m_PandMaxdB - m_PandMindB; float y_range = (float)m_OverlayPixmap.height(); float db_per_pix = db_range / y_range; - float fixed_db = m_MaxdB - pt.y() * db_per_pix; + float fixed_db = m_PandMaxdB - pt.y() * db_per_pix; - db_range = qBound(FFT_RANGE_MIN, db_range * zoom_fac, FFT_RANGE_MAX); - m_MaxdB = fixed_db + ratio*db_range; - if (m_MaxdB > REF_LEVEL_MAX) - m_MaxdB = REF_LEVEL_MAX; + db_range = qBound(10.f, db_range * zoom_fac, FFT_MAX_DB - FFT_MIN_DB); + m_PandMaxdB = fixed_db + ratio * db_range; + if (m_PandMaxdB > FFT_MAX_DB) + m_PandMaxdB = FFT_MAX_DB; - m_MindB = m_MaxdB - db_range; + m_PandMindB = m_PandMaxdB - db_range; m_PeakHoldValid = false; - emit fftRangeChanged(m_MaxdB, db_range); + emit pandapterRangeChanged(m_PandMindB, m_PandMaxdB); } else if (m_CursorCaptured == XAXIS) { @@ -927,7 +926,7 @@ void CPlotter::draw() // get scaled FFT data n = qMin(w, MAX_SCREENSIZE); - getScreenIntegerFFTData(255, n, m_MaxdB, m_MindB, + getScreenIntegerFFTData(255, n, m_WfMaxdB, m_WfMindB, m_FftCenter - (qint64)m_Span / 2, m_FftCenter + (qint64)m_Span / 2, m_wfData, m_fftbuf, @@ -1004,7 +1003,7 @@ void CPlotter::draw() // get new scaled fft data getScreenIntegerFFTData(h, qMin(w, MAX_SCREENSIZE), - m_MaxdB, m_MindB, + m_PandMaxdB, m_PandMindB, m_FftCenter - (qint64)m_Span/2, m_FftCenter + (qint64)m_Span/2, m_fftData, m_fftbuf, @@ -1249,21 +1248,31 @@ void CPlotter::getScreenIntegerFFTData(qint32 plotHeight, qint32 plotWidth, delete [] m_pTranslateTbl; } -/** Set limits of dB scale. */ -void CPlotter::setMinMaxDB(float min, float max) +void CPlotter::setFftRange(float min, float max) { - m_MaxdB = max; - m_MindB = min; + setWaterfallRange(min, max); + setPandapterRange(min, max); +} + +void CPlotter::setPandapterRange(float min, float max) +{ + if (out_of_range(min, max)) + return; + + m_PandMindB = min; + m_PandMaxdB = max; updateOverlay(); m_PeakHoldValid = false; } -void CPlotter::setFftRange(float reflevel, float range) +void CPlotter::setWaterfallRange(float min, float max) { - if (out_of_range(reflevel, range)) + if (out_of_range(min, max)) return; - setMinMaxDB(reflevel - range, reflevel); + m_WfMindB = min; + m_WfMaxdB = max; + // no overlay change is necessary } // Called to draw an overlay bitmap containing grid and text that @@ -1398,30 +1407,32 @@ void CPlotter::drawOverlay() qint64 mindBAdj64 = 0; qint64 dbDivSize = 0; - calcDivSize ((qint64) m_MindB, (qint64) m_MaxdB, qMax(h/m_VdivDelta, VERT_DIVS_MIN), mindBAdj64, dbDivSize, m_VerDivs); + calcDivSize((qint64) m_PandMindB, (qint64) m_PandMaxdB, + qMax(h/m_VdivDelta, VERT_DIVS_MIN), mindBAdj64, dbDivSize, + m_VerDivs); dbstepsize = (float) dbDivSize; mindbadj = mindBAdj64; - pixperdiv = (float) h * (float) dbstepsize / (m_MaxdB - m_MindB); - adjoffset = (float) h * (mindbadj - m_MindB) / (m_MaxdB - m_MindB); + pixperdiv = (float) h * (float) dbstepsize / (m_PandMaxdB - m_PandMindB); + adjoffset = (float) h * (mindbadj - m_PandMindB) / (m_PandMaxdB - m_PandMindB); #ifdef PLOTTER_DEBUG - qDebug() << "minDb =" << m_MindB << "maxDb =" << m_MaxdB << "mindbadj =" << mindbadj - << "dbstepsize =" << dbstepsize - << "pixperdiv =" << pixperdiv << "adjoffset =" << adjoffset; + qDebug() << "minDb =" << m_PandMindB << "maxDb =" << m_PandMaxdB + << "mindbadj =" << mindbadj << "dbstepsize =" << dbstepsize + << "pixperdiv =" << pixperdiv << "adjoffset =" << adjoffset; #endif painter.setPen(QPen(QColor(PLOTTER_GRID_COLOR), 1, Qt::DotLine)); for (int i = 0; i <= m_VerDivs; i++) { - y = h - (int)((float) i*pixperdiv + adjoffset); + y = h - (int)((float) i * pixperdiv + adjoffset); if (y < h - xAxisHeight) painter.drawLine(m_YAxisWidth, y, w, y); } // draw amplitude values (y axis) - int dB = m_MaxdB; + int dB = m_PandMaxdB; m_YAxisWidth = metrics.width("-120 "); painter.setPen(QColor(PLOTTER_TEXT_COLOR)); for (int i = 0; i < m_VerDivs; i++) diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 2ef4126..d8b58bd 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -82,7 +82,6 @@ class CPlotter : public QFrame drawOverlay(); } - void setMinMaxDB(float min, float max); void setHdivDelta(int delta) { m_HdivDelta = delta; } void setVdivDelta(int delta) { m_VdivDelta = delta; } @@ -121,7 +120,7 @@ class CPlotter : public QFrame void newLowCutFreq(int f); void newHighCutFreq(int f); void newFilterFreq(int low, int high); /* substitute for NewLow / NewHigh */ - void fftRangeChanged(float reflevel, float range); + void pandapterRangeChanged(float min, float max); public slots: // zoom functions @@ -134,7 +133,9 @@ public slots: void setFftPlotColor(const QColor color); void setFftFill(bool enabled); void setPeakHold(bool enabled); - void setFftRange(float reflevel, float range); + void setFftRange(float min, float max); + void setPandapterRange(float min, float max); + void setWaterfallRange(float min, float max); void setPeakDetection(bool enabled, float c); void updateOverlay(); @@ -232,8 +233,12 @@ public slots: int m_HorDivs; /*!< Current number of horizontal divisions. Calculated from width. */ int m_VerDivs; /*!< Current number of vertical divisions. Calculated from height. */ - float m_MaxdB; - float m_MindB; + + float m_PandMindB; + float m_PandMaxdB; + float m_WfMindB; + float m_WfMaxdB; + qint64 m_Span; float m_SampleFreq; /*!< Sample rate. */ qint32 m_FreqUnits; From 4bd1bb9f862ed830328102f071dcaf72545c561f Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 13:50:22 +0200 Subject: [PATCH 103/334] Adjust window size and copyright. --- src/qtgui/dockfft.cpp | 2 +- src/qtgui/dockfft.h | 2 +- src/qtgui/dockfft.ui | 38 +++++++++++++++++++++++++------------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index 416795b..d8a5ced 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * Copyright 2011-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/qtgui/dockfft.h b/src/qtgui/dockfft.h index ba6458c..d85531e 100644 --- a/src/qtgui/dockfft.h +++ b/src/qtgui/dockfft.h @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * Copyright 2011-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index 212aef5..f07d757 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -7,7 +7,7 @@ 0 0 275 - 245 + 218 @@ -44,19 +44,19 @@ - 5 + 0 - 5 + 0 - 5 + 0 - 5 + 0 - 5 + 0 @@ -77,8 +77,8 @@ 0 0 - 251 - 319 + 261 + 327 @@ -99,6 +99,18 @@ + + 5 + + + 5 + + + 5 + + + 5 + 5 @@ -969,16 +981,16 @@
- - QtColorPicker - QPushButton -
qtgui/qtcolorpicker.h
-
ctkRangeSlider QSlider
qtgui/ctk/ctkRangeSlider.h
+ + QtColorPicker + QPushButton +
qtgui/qtcolorpicker.h
+
From 38e0e792e5de6ef3a8f8b76f844956500dd346fc Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 13:51:04 +0200 Subject: [PATCH 104/334] Use CTK slider for audio FFT. --- src/qtgui/audio_options.cpp | 40 ++++++-- src/qtgui/audio_options.h | 17 ++-- src/qtgui/audio_options.ui | 192 +++++++++++++++++++++--------------- src/qtgui/dockaudio.cpp | 94 +++++++++++++----- src/qtgui/dockaudio.h | 5 +- 5 files changed, 224 insertions(+), 124 deletions(-) diff --git a/src/qtgui/audio_options.cpp b/src/qtgui/audio_options.cpp index aa08812..7581d9d 100644 --- a/src/qtgui/audio_options.cpp +++ b/src/qtgui/audio_options.cpp @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2013 Alexandru Csete OZ9AEC. + * Copyright 2013-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -93,34 +93,54 @@ void CAudioOptions::setUdpPort(int port) void CAudioOptions::setFftSplit(int pct_2d) { - ui->splitSpinBox->setValue(100 - pct_2d); + ui->fftSplitSlider->setValue(100 - pct_2d); } int CAudioOptions::getFftSplit(void) const { - return 100 - ui->splitSpinBox->value(); + return 100 - ui->fftSplitSlider->value(); } -void CAudioOptions::on_splitSpinBox_valueChanged(int value) +void CAudioOptions::on_fftSplitSlider_valueChanged(int value) { emit newFftSplit(100 - value); } -void CAudioOptions::setFftMin(int min_db) +void CAudioOptions::setPandapterRange(int min, int max) { - ui->scaleSpinBox->setValue(min_db); + if (min < max && max <= 0) + ui->pandRangeSlider->setValues(min, max); } -int CAudioOptions::getFftMin(void) const +void CAudioOptions::getPandapterRange(int * min, int * max) const { - return ui->scaleSpinBox->value(); + *min = ui->pandRangeSlider->minimumValue(); + *max = ui->pandRangeSlider->maximumValue(); } -void CAudioOptions::on_scaleSpinBox_valueChanged(int value) +void CAudioOptions::on_pandRangeSlider_valuesChanged(int min, int max) { - emit newFftMin(value); + emit newPandapterRange(min, max); } +void CAudioOptions::setWaterfallRange(int min, int max) +{ + if (min < max && max <= 0) + ui->wfRangeSlider->setValues(min, max); +} + +void CAudioOptions::getWaterfallRange(int * min, int * max) const +{ + *min = ui->wfRangeSlider->minimumValue(); + *max = ui->wfRangeSlider->maximumValue(); +} + +void CAudioOptions::on_wfRangeSlider_valuesChanged(int min, int max) +{ + emit newWaterfallRange(min, max); +} + + /** * Slot called when the recordings directory has changed either * because of user input or programmatically. diff --git a/src/qtgui/audio_options.h b/src/qtgui/audio_options.h index d12b861..b938658 100644 --- a/src/qtgui/audio_options.h +++ b/src/qtgui/audio_options.h @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2013 Alexandru Csete OZ9AEC. + * Copyright 2013-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,12 +50,16 @@ class CAudioOptions : public QDialog void setFftSplit(int pct_2d); int getFftSplit(void) const; - void setFftMin(int min_db); - int getFftMin(void) const; + void setPandapterRange(int min, int max); + void getPandapterRange(int * min, int * max) const; + + void setWaterfallRange(int min, int max); + void getWaterfallRange(int * min, int * max) const; signals: void newFftSplit(int pct_2d); - void newFftMin(int min_db); + void newPandapterRange(int min, int max); + void newWaterfallRange(int min, int max); /*! \brief Signal emitted when a new valid directory has been selected. */ void newRecDirSelected(const QString &dir); @@ -64,8 +68,9 @@ class CAudioOptions : public QDialog void newUdpPort(int port); private slots: - void on_splitSpinBox_valueChanged(int value); - void on_scaleSpinBox_valueChanged(int value); + void on_fftSplitSlider_valueChanged(int value); + void on_pandRangeSlider_valuesChanged(int min, int max); + void on_wfRangeSlider_valuesChanged(int min, int max); void on_recDirEdit_textChanged(const QString &text); void on_recDirButton_clicked(); void on_udpHost_textChanged(const QString &text); diff --git a/src/qtgui/audio_options.ui b/src/qtgui/audio_options.ui index a2b5f14..4d6947c 100644 --- a/src/qtgui/audio_options.ui +++ b/src/qtgui/audio_options.ui @@ -6,8 +6,8 @@ 0 0 - 350 - 170 + 315 + 169 @@ -30,84 +30,111 @@ Audio FFT settings - - - - - Waterfall - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - % - - - 100 - - - - - - - Qt::Horizontal - - - - 166 - 20 - - - - - - - - Range - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - dB - - - -150 - - - -20 - - - -80 - - + + + + + + + Adjust split between pandapter and waterfall + + + Pandapter + + + + + + + Adjust split between pandapter and waterfall + + + 100 + + + Qt::Horizontal + + + + + + + Adjust split between pandapter and waterfall + + + Waterfall + + + + - - - - Qt::Horizontal - - - - 166 - 20 - - - + + + + + + Adjust dB range on the pandapter + + + Pandapter dB range + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Adjust dB range on the pandapter + + + -120 + + + 0 + + + -80 + + + Qt::Horizontal + + + + + + + Adjust dB range on the waterfall + + + Waterfall dB range + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Adjust dB range on the waterfall + + + -120 + + + 0 + + + -80 + + + Qt::Horizontal + + + +
@@ -251,6 +278,13 @@ + + + ctkRangeSlider + QSlider +
qtgui/ctk/ctkRangeSlider.h
+
+
diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 1b7bbfa..c99a342 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * Copyright 2011-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,7 +53,8 @@ DockAudio::DockAudio(QWidget *parent) : audioOptions = new CAudioOptions(this); connect(audioOptions, SIGNAL(newFftSplit(int)), ui->audioSpectrum, SLOT(setPercent2DScreen(int))); - connect(audioOptions, SIGNAL(newFftMin(int)), this, SLOT(setNewFftMin(int))); + connect(audioOptions, SIGNAL(newPandapterRange(int,int)), this, SLOT(setNewPandapterRange(int,int))); + connect(audioOptions, SIGNAL(newWaterfallRange(int,int)), this, SLOT(setNewWaterfallRange(int,int))); connect(audioOptions, SIGNAL(newRecDirSelected(QString)), this, SLOT(setNewRecDir(QString))); connect(audioOptions, SIGNAL(newUdpHost(QString)), this, SLOT(setNewUdpHost(QString))); connect(audioOptions, SIGNAL(newUdpPort(int)), this, SLOT(setNewUdpPort(int))); @@ -278,78 +279,117 @@ void DockAudio::setAudioPlayButtonState(bool checked) void DockAudio::saveSettings(QSettings *settings) { - int ival; + int ival, fft_min, fft_max; if (!settings) return; - settings->setValue("audio/gain", audioGain()); + settings->beginGroup("audio"); + + settings->setValue("gain", audioGain()); ival = audioOptions->getFftSplit(); if (ival >= 0 && ival < 100) - settings->setValue("audio/fft_split", ival); + settings->setValue("fft_split", ival); else - settings->remove("audio/fft_split"); + settings->remove("fft_split"); - ival = audioOptions->getFftMin(); - if (ival != -80) - settings->setValue("audio/fft_min_db", ival); + audioOptions->getPandapterRange(&fft_min, &fft_max); + if (fft_min != -80) + settings->setValue("pandapter_min_db", fft_min); + else + settings->remove("pandapter_min_db"); + if (fft_max != 0) + settings->setValue("pandapter_max_db", fft_max); + else + settings->remove("pandapter_max_db"); + + audioOptions->getWaterfallRange(&fft_min, &fft_max); + if (fft_min != -80) + settings->setValue("waterfall_min_db", fft_min); + else + settings->remove("waterfall_min_db"); + if (fft_max != 0) + settings->setValue("waterfall_max_db", fft_max); else - settings->remove("audio/fft_min_db"); + settings->remove("waterfall_max_db"); if (rec_dir != QDir::homePath()) - settings->setValue("audio/rec_dir", rec_dir); + settings->setValue("rec_dir", rec_dir); else - settings->remove("audio/rec_dir"); + settings->remove("rec_dir"); if ((udp_host != "localhost") && (udp_host != "127.0.0.1")) - settings->setValue("audio/udp_host", udp_host); + settings->setValue("udp_host", udp_host); else - settings->remove("audio/udp_host"); + settings->remove("udp_host"); if (udp_port != 7355) - settings->setValue("audio/udp_port", udp_port); + settings->setValue("udp_port", udp_port); else - settings->remove("audio/udp_port"); + settings->remove("udp_port"); + + settings->endGroup(); } void DockAudio::readSettings(QSettings *settings) { - int ival; + int ival, fft_min, fft_max; bool conv_ok = false; if (!settings) return; - ival = settings->value("audio/gain", QVariant(-200)).toInt(&conv_ok); + settings->beginGroup("audio"); + + ival = settings->value("gain", QVariant(-200)).toInt(&conv_ok); if (conv_ok) setAudioGain(ival); - ival = settings->value("audio/fft_split", QVariant(100)).toInt(&conv_ok); + ival = settings->value("fft_split", QVariant(100)).toInt(&conv_ok); if (conv_ok) audioOptions->setFftSplit(ival); - ival = settings->value("audio/fft_min_db", QVariant(-80)).toInt(&conv_ok); - if (conv_ok) - audioOptions->setFftMin(ival); + fft_min = settings->value("pandapter_min_db", QVariant(-80)).toInt(&conv_ok); + if (!conv_ok) + fft_min = -80; + fft_max = settings->value("pandapter_max_db", QVariant(0)).toInt(&conv_ok); + if (!conv_ok) + fft_max = 0; + audioOptions->setPandapterRange(fft_min, fft_max); + + fft_min = settings->value("waterfall_min_db", QVariant(-80)).toInt(&conv_ok); + if (!conv_ok) + fft_min = -80; + fft_max = settings->value("waterfall_max_db", QVariant(0)).toInt(&conv_ok); + if (!conv_ok) + fft_max = 0; + audioOptions->setWaterfallRange(fft_min, fft_max); // Location of audio recordings - rec_dir = settings->value("audio/rec_dir", QDir::homePath()).toString(); + rec_dir = settings->value("rec_dir", QDir::homePath()).toString(); audioOptions->setRecDir(rec_dir); // Audio streaming host and port - udp_host = settings->value("audio/udp_host", "localhost").toString(); - udp_port = settings->value("audio/udp_port", 7355).toInt(&conv_ok); + udp_host = settings->value("udp_host", "localhost").toString(); + udp_port = settings->value("udp_port", 7355).toInt(&conv_ok); if (!conv_ok) udp_port = 7355; audioOptions->setUdpHost(udp_host); audioOptions->setUdpPort(udp_port); + + settings->endGroup(); +} + +void DockAudio::setNewPandapterRange(int min, int max) +{ + ui->audioSpectrum->setPandapterRange(min, max); } -void DockAudio::setNewFftMin(int min_db) +void DockAudio::setNewWaterfallRange(int min, int max) { - ui->audioSpectrum->setFftRange(min_db, 0.f); + ui->audioSpectrum->setWaterfallRange(min, max); } /*! \brief Slot called when a new valid recording directory has been selected diff --git a/src/qtgui/dockaudio.h b/src/qtgui/dockaudio.h index a9cbdf1..c1f84f4 100644 --- a/src/qtgui/dockaudio.h +++ b/src/qtgui/dockaudio.h @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * Copyright 2011-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -102,7 +102,8 @@ private slots: void on_audioRecButton_clicked(bool checked); void on_audioPlayButton_clicked(bool checked); void on_audioConfButton_clicked(); - void setNewFftMin(int min_db); + void setNewPandapterRange(int min, int max); + void setNewWaterfallRange(int min, int max); void setNewRecDir(const QString &dir); void setNewUdpHost(const QString &host); void setNewUdpPort(int port); From 851368f3fafc67ad23e652a5a06fcc55786f21d6 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 15:18:52 +0200 Subject: [PATCH 105/334] Reduce RX options dock widget height. --- src/qtgui/dockrxopt.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index cb77da9..b66265a 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -7,7 +7,7 @@ 0 0 266 - 310 + 300 @@ -19,7 +19,7 @@ 266 - 310 + 300 From 1422cf91af557773166fb8989d0eabe1af2b49a7 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 16:39:16 +0200 Subject: [PATCH 106/334] First stab at raw I/Q mode. --- resources/news.txt | 1 + src/qtgui/dockrxopt.cpp | 11 +---------- src/receivers/nbrx.cpp | 15 ++++++++++++++- src/receivers/nbrx.h | 2 ++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index 84ab118..c70f4d7 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -5,6 +5,7 @@ NEW: Remember AGC settings between sessions. NEW: Right-click on FFT resets frequency zoom. NEW: Separate dB ranges for pandapter and waterfall. + NEW: Raw I/Q mode. FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 37464f0..083c611 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -32,7 +32,7 @@ QStringList DockRxOpt::ModulationStrings; static const int filter_preset_table[DockRxOpt::MODE_LAST][3][2] = { // WIDE NORMAL NARROW {{ 0, 0}, { 0, 0}, { 0, 0}}, // MODE_OFF - {{ -25000, 25000}, {-10000, 10000}, { -1000, 1000}}, // MODE_RAW + {{ -15000, 15000}, { -5000, 5000}, { -1000, 1000}}, // MODE_RAW {{ -10000, 10000}, { -5000, 5000}, { -2500, 2500}}, // MODE_AM {{ -10000, 10000}, { -5000, 5000}, { -2500, 2500}}, // MODE_NFM {{-100000, 100000}, {-80000, 80000}, {-60000, 60000}}, // MODE_WFM_MONO @@ -472,16 +472,7 @@ void DockRxOpt::on_filterCombo_activated(int index) */ void DockRxOpt::on_modeSelector_activated(int index) { - if (index == MODE_RAW) - { - qDebug() << "Raw I/Q not implemented (fallback to FM-N)"; - ui->modeSelector->setCurrentIndex(MODE_NFM); - emit demodSelected(MODE_NFM); - return; - } - updateDemodOptPage(index); - emit demodSelected(index); } diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index 6e768f6..1fd0782 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -46,6 +46,7 @@ nbrx::nbrx(float quad_rate, float audio_rate) agc = make_rx_agc_cc(PREF_QUAD_RATE, true, -100, 0, 0, 500, false); sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001); meter = make_rx_meter_c(DETECTOR_TYPE_RMS); + demod_raw = gr::blocks::complex_to_float::make(1); demod_ssb = gr::blocks::complex_to_real::make(1); demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, PREF_AUDIO_RATE, 5000.0, 75.0e-6); demod_am = make_rx_demod_am(PREF_QUAD_RATE, PREF_AUDIO_RATE, true); @@ -268,7 +269,11 @@ void nbrx::set_demod(int rx_demod) switch (rx_demod) { - case NBRX_DEMOD_NONE: /** FIXME! **/ + case NBRX_DEMOD_NONE: + d_demod = NBRX_DEMOD_NONE; + demod = demod_raw; + break; + case NBRX_DEMOD_SSB: d_demod = NBRX_DEMOD_SSB; demod = demod_ssb; @@ -288,7 +293,15 @@ void nbrx::set_demod(int rx_demod) connect(agc, 0, demod, 0); if (audio_rr) + { + // FIXME: DEMOD_NONE has two outputs. connect(demod, 0, audio_rr, 0); + } + else if (d_demod == NBRX_DEMOD_NONE) + { + connect(demod, 0, self(), 0); + connect(demod, 1, self(), 1); + } else { connect(demod, 0, self(), 0); diff --git a/src/receivers/nbrx.h b/src/receivers/nbrx.h index 0efe882..8504a36 100644 --- a/src/receivers/nbrx.h +++ b/src/receivers/nbrx.h @@ -25,6 +25,7 @@ #include #include +#include #include #include "receivers/receiver_base.h" #include "dsp/rx_noise_blanker_cc.h" @@ -119,6 +120,7 @@ class nbrx : public receiver_base_cf rx_meter_c_sptr meter; /*!< Signal strength. */ rx_agc_cc_sptr agc; /*!< Receiver AGC. */ gr::analog::simple_squelch_cc::sptr sql; /*!< Squelch. */ + gr::blocks::complex_to_float::sptr demod_raw; /*!< Raw I/Q passthrough. */ gr::blocks::complex_to_real::sptr demod_ssb; /*!< SSB demodulator. */ rx_demod_fm_sptr demod_fm; /*!< FM demodulator. */ rx_demod_am_sptr demod_am; /*!< AM demodulator. */ From 0981c471fdfaeee8b32dfa4a2ed5883c46cae744 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 16:40:50 +0200 Subject: [PATCH 107/334] Remove unused code and update copyright. --- src/receivers/nbrx.cpp | 59 +----------------------------------------- src/receivers/nbrx.h | 2 +- 2 files changed, 2 insertions(+), 59 deletions(-) diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index 1fd0782..ae73ae1 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * Copyright 2011-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -203,61 +203,6 @@ void nbrx::set_demod(int rx_demod) return; } - // for now we must depend on top level stop/lock - // because of https://github.com/csete/gqrx/issues/120 - //lock(); -#if 0 - /* disconnect current demodulator */ - switch (current_demod) { - - default: - case NBRX_DEMOD_NONE: /** FIXME! **/ - case NBRX_DEMOD_SSB: - disconnect(agc, 0, demod_ssb, 0); - disconnect(demod_ssb, 0, audio_rr, 0); - break; - - case NBRX_DEMOD_AM: - disconnect(agc, 0, demod_am, 0); - disconnect(demod_am, 0, audio_rr, 0); - break; - - case NBRX_DEMOD_FM: - disconnect(agc, 0, demod_fm, 0); - disconnect(demod_fm, 0, audio_rr, 0); - break; - } - - switch (rx_demod) { - - case NBRX_DEMOD_NONE: /** FIXME! **/ - case NBRX_DEMOD_SSB: - d_demod = NBRX_DEMOD_SSB; - connect(agc, 0, demod_ssb, 0); - connect(demod_ssb, 0, audio_rr, 0); - break; - - case NBRX_DEMOD_AM: - d_demod = NBRX_DEMOD_AM; - connect(agc, 0, demod_am, 0); - connect(demod_am, 0, audio_rr, 0); - break; - - case NBRX_DEMOD_FM: - d_demod = NBRX_DEMOD_FM; - connect(agc, 0, demod_fm, 0); - connect(demod_fm, 0, audio_rr, 0); - break; - - default: - /* use FMN */ - d_demod = NBRX_DEMOD_FM; - connect(agc, 0, demod_fm, 0); - connect(demod_fm, 0, audio_rr, 0); - break; - } -#endif - disconnect(agc, 0, demod, 0); if (audio_rr) disconnect(demod, 0, audio_rr, 0); @@ -308,8 +253,6 @@ void nbrx::set_demod(int rx_demod) connect(demod, 0, self(), 1); } - /* continue processing */ - //unlock(); } void nbrx::set_fm_maxdev(float maxdev_hz) diff --git a/src/receivers/nbrx.h b/src/receivers/nbrx.h index 8504a36..1a631a0 100644 --- a/src/receivers/nbrx.h +++ b/src/receivers/nbrx.h @@ -3,7 +3,7 @@ * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt * http://gqrx.dk/ * - * Copyright 2011-2013 Alexandru Csete OZ9AEC. + * Copyright 2011-2016 Alexandru Csete OZ9AEC. * * Gqrx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 34b222e422511799efdcc4e2bd1322535ab1170d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Sep 2016 23:09:40 +0200 Subject: [PATCH 108/334] Add missing filter configuration for raw I/Q mode. --- src/applications/gqrx/mainwindow.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 62daa14..5a42c06 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -957,10 +957,12 @@ void MainWindow::selectDemod(int mode_idx) case DockRxOpt::MODE_RAW: /* Raw I/Q */ - qDebug() << "RAW I/Q mode not implemented!"; + rx->set_demod(receiver::RX_DEMOD_NONE); + ui->plotter->setDemodRanges(-45000, -200, 200, 45000, true); + uiDockAudio->setFftRange(0,24000); + click_res = 100; break; - /* AM */ case DockRxOpt::MODE_AM: rx->set_demod(receiver::RX_DEMOD_AM); ui->plotter->setDemodRanges(-45000, -200, 200, 45000, true); @@ -968,7 +970,6 @@ void MainWindow::selectDemod(int mode_idx) click_res = 100; break; - /* Narrow FM */ case DockRxOpt::MODE_NFM: rx->set_demod(receiver::RX_DEMOD_NFM); click_res = 100; @@ -985,10 +986,10 @@ void MainWindow::selectDemod(int mode_idx) } break; - /* Broadcast FM */ case DockRxOpt::MODE_WFM_MONO: case DockRxOpt::MODE_WFM_STEREO: case DockRxOpt::MODE_WFM_STEREO_OIRT: + /* Broadcast FM */ quad_rate = rx->get_input_rate(); if (quad_rate < 500.0e3) ui->plotter->setDemodRanges(-quad_rate/2.0, -10000, @@ -1008,24 +1009,24 @@ void MainWindow::selectDemod(int mode_idx) uiDockRDS->setEnabled(); break; - /* LSB */ case DockRxOpt::MODE_LSB: + /* LSB */ rx->set_demod(receiver::RX_DEMOD_SSB); ui->plotter->setDemodRanges(-40000, -100, -5000, 0, false); uiDockAudio->setFftRange(0,3000); click_res = 100; break; - /* USB */ case DockRxOpt::MODE_USB: + /* USB */ rx->set_demod(receiver::RX_DEMOD_SSB); ui->plotter->setDemodRanges(0, 5000, 100, 40000, false); uiDockAudio->setFftRange(0,3000); click_res = 100; break; - /* CW-L */ case DockRxOpt::MODE_CWL: + /* CW-L */ rx->set_demod(receiver::RX_DEMOD_SSB); cwofs = -uiDockRxOpt->getCwOffset(); ui->plotter->setDemodRanges(-5000, -100, 100, 5000, true); @@ -1033,8 +1034,8 @@ void MainWindow::selectDemod(int mode_idx) click_res = 10; break; - /* CW-U */ case DockRxOpt::MODE_CWU: + /* CW-U */ rx->set_demod(receiver::RX_DEMOD_SSB); cwofs = uiDockRxOpt->getCwOffset(); ui->plotter->setDemodRanges(-5000, -100, 100, 5000, true); From 210d326ab9d96910056160de62cf4d3122bdb612 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Mon, 26 Sep 2016 18:06:27 +0200 Subject: [PATCH 109/334] Update squelch level when demodulator has changed --- src/applications/gqrx/mainwindow.cpp | 1 + src/qtgui/dockrxopt.cpp | 9 +++++++++ src/qtgui/dockrxopt.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 5a42c06..8030c06 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1057,6 +1057,7 @@ void MainWindow::selectDemod(int mode_idx) ui->plotter->setFilterClickResolution(click_res); rx->set_filter((double)flo, (double)fhi, d_filter_shape); rx->set_cw_offset(cwofs); + rx->set_sql_level(uiDockRxOpt->currentSquelchLevel()); d_have_audio = ((mode_idx != DockRxOpt::MODE_OFF) && (mode_idx != DockRxOpt::MODE_RAW)); diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 083c611..75be118 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -283,6 +283,15 @@ void DockRxOpt::setSquelchLevel(double level) ui->sqlSpinBox->setValue(level); } +/** + * @brief Get the current squelch level + * @returns The current squelch setting in dBFS + */ +double DockRxOpt::currentSquelchLevel() +{ + return ui->sqlSpinBox->value(); +} + /** Get filter lo/hi for a given mode and preset */ void DockRxOpt::getFilterPreset(int mode, int preset, int * lo, int * hi) const diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h index 1175b2f..787dd3b 100644 --- a/src/qtgui/dockrxopt.h +++ b/src/qtgui/dockrxopt.h @@ -100,6 +100,8 @@ class DockRxOpt : public QDockWidget float currentMaxdev(); + double currentSquelchLevel(); + void getFilterPreset(int mode, int preset, int * lo, int * hi) const; int getCwOffset() const; From e2ae620ed66edfc2b65e3904f98ceb3d5440528c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 26 Sep 2016 20:16:03 +0200 Subject: [PATCH 110/334] Update news.txt --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index c70f4d7..529e2ae 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -12,6 +12,7 @@ FIXED: Correct display of negative offsets between -1 and 0 kHz. FIXED: Reset frequency digits below the one that is being changed. FIXED: LNB LO could not be set from I/O configuration dialog. + FIXED: Update squelch level when switching between demodulators. IMPROVED: Input decimator performance. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. From 1274a6bce79e5e74699de6f5a0b21033574859e9 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Mon, 26 Sep 2016 19:13:07 +0200 Subject: [PATCH 111/334] Set correct filter range when loading bookmark * Display the correct filter width on plotter * Calculate the correct taps for RX filter --- src/applications/gqrx/mainwindow.cpp | 38 +++++++++++++++++++++++++--- src/applications/gqrx/mainwindow.h | 3 +++ src/qtgui/dockbookmarks.cpp | 6 +---- src/qtgui/dockbookmarks.h | 4 +-- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 5a42c06..4a11dda 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -243,9 +243,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : connect(uiDockRDS, SIGNAL(rdsDecoderToggled(bool)), this, SLOT(setRdsDecoder(bool))); // Bookmarks - connect(uiDockBookmarks, SIGNAL(newFrequency(qint64)), this, SLOT(setNewFrequency(qint64))); - connect(uiDockBookmarks, SIGNAL(newDemodulation(QString)), this, SLOT(selectDemod(QString))); - connect(uiDockBookmarks, SIGNAL(newFilterBandwidth(int, int)), this, SLOT(on_plotter_newFilterFreq(int, int))); + connect(uiDockBookmarks, SIGNAL(newBookmarkActivated(qint64, QString, int)), this, SLOT(onBookmarkActivated(qint64, QString, int))); connect(uiDockBookmarks->actionAddBookmark, SIGNAL(triggered()), this, SLOT(on_actionAddBookmark_triggered())); @@ -1869,6 +1867,10 @@ void MainWindow::on_plotter_newFilterFreq(int low, int high) /* parameter correctness will be checked in receiver class */ retcode = rx->set_filter((double) low, (double) high, d_filter_shape); + /* Update filter range of plotter, in case this slot is triggered by + * switching to a bookmark */ + ui->plotter->setHiLowCutFrequencies(low, high); + if (retcode == receiver::STATUS_OK) uiDockRxOpt->setFilterParam(low, high); } @@ -2012,6 +2014,36 @@ void MainWindow::setRdsDecoder(bool checked) } } +void MainWindow::onBookmarkActivated(qint64 freq, QString demod, int bandwidth) +{ + setNewFrequency(freq); + selectDemod(demod); + + /* Check if filter is symmetric or not by checking the presets */ + int mode = uiDockRxOpt->currentDemod(); + int preset = uiDockRxOpt->currentFilterShape(); + + int lo, hi; + uiDockRxOpt->getFilterPreset(mode, preset, &lo, &hi); + + if(lo + hi == 0) + { + lo = -bandwidth / 2; + hi = bandwidth / 2; + } + else if(lo >= 0 && hi >= 0) + { + hi = lo + bandwidth; + } + else if(lo <= 0 && hi <= 0) + { + lo = hi - bandwidth; + } + + on_plotter_newFilterFreq(lo, hi); + ui->plotter->setHiLowCutFrequencies(lo, hi); +} + /** Launch Gqrx google group website. */ void MainWindow::on_actionUserGroup_triggered() { diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index 47c4ef6..1b1e4e2 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -192,6 +192,9 @@ private slots: /* RDS */ void setRdsDecoder(bool checked); + /* Bookmarks */ + void onBookmarkActivated(qint64 freq, QString demod, int bandwidth); + /* menu and toolbar actions */ void on_actionDSP_triggered(bool checked); int on_actionIoConfig_triggered(); diff --git a/src/qtgui/dockbookmarks.cpp b/src/qtgui/dockbookmarks.cpp index a7cd00e..8c6bb43 100644 --- a/src/qtgui/dockbookmarks.cpp +++ b/src/qtgui/dockbookmarks.cpp @@ -104,11 +104,7 @@ DockBookmarks::~DockBookmarks() void DockBookmarks::activated(const QModelIndex & index ) { BookmarkInfo *info = bookmarksTableModel->getBookmarkAtRow(index.row()); - //printf("Emit newFrequency(%d)\n", (int)info->frequency); - emit newFrequency(info->frequency); - //printf("Emit newDemodulation(%s)\n", info->modulation.toStdString().c_str()); - emit newDemodulation(info->modulation); - emit newFilterBandwidth(-1*info->bandwidth/2, info->bandwidth/2); + emit newBookmarkActivated(info->frequency, info->modulation, info->bandwidth); } void DockBookmarks::setNewFrequency(qint64 rx_freq) diff --git a/src/qtgui/dockbookmarks.h b/src/qtgui/dockbookmarks.h index 125720f..a1a6c72 100644 --- a/src/qtgui/dockbookmarks.h +++ b/src/qtgui/dockbookmarks.h @@ -80,9 +80,7 @@ class DockBookmarks : public QDockWidget void changeBookmarkTags(int row, int /*column*/); signals: - void newFrequency(qint64); - void newDemodulation(QString); - void newFilterBandwidth(int, int); + void newBookmarkActivated(qint64, QString, int); public slots: void setNewFrequency(qint64 rx_freq); From fbba9db6722d24c85b04c6b9c04bdce3a02e9a61 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 26 Sep 2016 21:31:44 +0200 Subject: [PATCH 112/334] Update news.txt --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 529e2ae..afcdebd 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -13,6 +13,7 @@ FIXED: Reset frequency digits below the one that is being changed. FIXED: LNB LO could not be set from I/O configuration dialog. FIXED: Update squelch level when switching between demodulators. + FIXED: Set correct filter range when loading bookmark. IMPROVED: Input decimator performance. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. From 4ce7ccfc2f28b8e0b20b26297ceb2ff159d1c2c7 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Mon, 26 Sep 2016 22:43:55 +0200 Subject: [PATCH 113/334] Check if FFT buffer index is valid --- src/qtgui/plotter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index f978953..d860049 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -1234,7 +1234,10 @@ void CPlotter::getScreenIntegerFFTData(qint32 plotHeight, qint32 plotWidth, for (x = 0; x < plotWidth; x++ ) { i = m_pTranslateTbl[x]; // get plot to fft bin coordinate transform - y = (qint32)(dBGainFactor*(maxdB-m_pFFTAveBuf[i])); + if(i < 0 || i >= m_FFTSize) + y = plotHeight; + else + y = (qint32)(dBGainFactor*(maxdB-m_pFFTAveBuf[i])); if (y > plotHeight) y = plotHeight; From 2ca5471c0af21686cb8529fa29cf40a8d6cfcac9 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 26 Sep 2016 23:48:57 +0200 Subject: [PATCH 114/334] Adjust dock widget sizes and margins. --- src/qtgui/dockfft.ui | 24 ++++++++++++------------ src/qtgui/dockinputctl.ui | 18 +++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index f07d757..6a2d8a9 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -7,7 +7,7 @@ 0 0 275 - 218 + 242 @@ -44,19 +44,19 @@ - 0 + 6 - 0 + 5 - 0 + 5 - 0 + 5 - 0 + 5 @@ -77,8 +77,8 @@ 0 0 - 261 - 327 + 252 + 340 @@ -86,16 +86,16 @@ 5 - 0 + 5 - 0 + 5 - 0 + 5 - 0 + 5 diff --git a/src/qtgui/dockinputctl.ui b/src/qtgui/dockinputctl.ui index e639a14..fac3443 100644 --- a/src/qtgui/dockinputctl.ui +++ b/src/qtgui/dockinputctl.ui @@ -6,14 +6,14 @@ 0 0 - 234 - 224 + 240 + 240 - 234 - 224 + 240 + 240 @@ -35,16 +35,16 @@ 6 - 4 + 5 - 4 + 5 - 4 + 5 - 4 + 5 @@ -221,7 +221,7 @@ - 20 + 5 0 From 463e1cd023ec1eb51d58f7ea873ed2184bc51424 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Tue, 27 Sep 2016 08:48:36 +0200 Subject: [PATCH 115/334] Add button to lock pandapter and waterfall ranges --- src/qtgui/dockfft.cpp | 18 + src/qtgui/dockfft.h | 1 + src/qtgui/dockfft.ui | 978 ++++++++++++++++++++++-------------------- 3 files changed, 536 insertions(+), 461 deletions(-) diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index d8a5ced..3427a5f 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -396,11 +396,17 @@ void DockFft::on_fftZoomSlider_valueChanged(int level) void DockFft::on_pandRangeSlider_valuesChanged(int min, int max) { + if (ui->lockButton->isChecked()) + ui->wfRangeSlider->setValues(min, max); + emit pandapterRangeChanged((float) min, (float) max); } void DockFft::on_wfRangeSlider_valuesChanged(int min, int max) { + if (ui->lockButton->isChecked()) + ui->pandRangeSlider->setValues(min, max); + emit waterfallRangeChanged((float) min, (float) max); } @@ -445,6 +451,18 @@ void DockFft::on_peakDetectionButton_toggled(bool checked) emit peakDetectionToggled(checked); } +/** lock button toggled */ +void DockFft::on_lockButton_toggled(bool checked) +{ + if (checked) + { + int min = ui->pandRangeSlider->minimumValue(); + int max = ui->pandRangeSlider->maximumValue(); + + ui->wfRangeSlider->setPositions(min, max); + } +} + /** Update RBW and FFT overlab labels */ void DockFft::updateInfoLabels(void) { diff --git a/src/qtgui/dockfft.h b/src/qtgui/dockfft.h index d85531e..63c7b98 100644 --- a/src/qtgui/dockfft.h +++ b/src/qtgui/dockfft.h @@ -88,6 +88,7 @@ private slots: void on_fillButton_toggled(bool checked); void on_peakHoldButton_toggled(bool checked); void on_peakDetectionButton_toggled(bool checked); + void on_lockButton_toggled(bool checked); private: void updateInfoLabels(void); diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index 6a2d8a9..02b600a 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -78,7 +78,7 @@ 0 0 252 - 340 + 339 @@ -114,73 +114,6 @@ 5 - - - - Set pandapter dB range - - - Set pandapter dB range - - - -160 - - - 0 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - Current zoom level on the frequency axis - - - Current zoom level on the frequency axis - - - 1x - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Peak - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Set zoom level on the frequency axis - - - Set zoom level on the frequency axis - - - Freq zoom - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -197,8 +130,86 @@ - - + + + + 2 + + + QLayout::SetDefaultConstraint + + + 1 + + + 0 + + + + + + 0 + 0 + + + + + 50 + 32 + + + + + 16777215 + 16777215 + + + + Enable peak detection in FFT + + + Detect + + + true + + + + + + + + 0 + 0 + + + + + 50 + 32 + + + + + 16777215 + 16777215 + + + + Toggle peak hold in FFT + + + Hold + + + true + + + + + + + 0 @@ -212,10 +223,7 @@ - Spatial distribution between pandapter and waterfall - - - 0 + FFT averaging gain 100 @@ -226,292 +234,134 @@ Qt::Horizontal - - - - - - The vertical time span on the waterfall. - - - - - - Time span - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Rate - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Set waterfall dB range - - - Set waterfall dB range - - - -160 - - - 0 - - - Qt::Horizontal - - - - - - - Set pandapter dB range - - - Set pandapter dB range - - - Pand. dB - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - FFT averaging gain - - - Averaging - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Resolution bandwidth - - - RBW: 0 kHz - - - - - - - Color for the FFT plot - - - Color + + false - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + false - - - - true - - - - 0 - 0 - - - - - 0 - 0 - - + + - <html>Number of FFT points to calculate. Higher values will require more CPU time. This will not influence the number of points on the display since that parameter is adjusted automatically according to the display size. -</html> - - - false - - - 7 - - - 15 - - - QComboBox::InsertAlphabetically + The vertical time span on the waterfall. - 1048576 - - - - - 524288 + Auto - 262144 + 5 min - 131072 + 10 min - 65536 + 15 min - 32768 + 20 min - 16384 + 30 min - 8192 + 1 hour - 4096 + 2 hours - 3840 + 5 hours - 2048 + 10 hours - 1024 + 16 hours - 768 + 24 hours - 512 + 48 hours - - - - - 0 - 0 - - - - Waterfall - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - Pandapter - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 50 - 32 - - + + - Click to select color for the FFT plot + Waterfall time resolution. - Click to select color for the FFT plot - - - - true + + Res: - s - - + + 2 - - QLayout::SetDefaultConstraint - - - 1 - - - 0 - - + + + + 0 + 0 + + + + + 50 + 32 + + + + + 16777215 + 16777215 + + + + Reset zoom level to 1x + + + R + + + + + 0 @@ -531,18 +381,15 @@ - Enable peak detection in FFT + Center FFT around original center frequency - Detect - - - true + C - + 0 @@ -562,20 +409,17 @@ - Toggle peak hold in FFT + Center FFT around demodulator frequency - Hold - - - true + D - - + + 0 @@ -589,14 +433,20 @@ - FFT averaging gain + Set zoom level on the frequency axis - - 100 + + Set zoom level on the frequency axis - + + 1 + + 50 + + 5 + Qt::Horizontal @@ -606,224 +456,272 @@ false + + QSlider::NoTicks + - - + + + + + 0 + 0 + + + + + 0 + 22 + + + + Spatial distribution between pandapter and waterfall + + + 0 + + + 100 + + + 50 + + + Qt::Horizontal + + + + + The vertical time span on the waterfall. + + + + + Time span + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Rate + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + FFT averaging gain + + + Averaging + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Resolution bandwidth + + + RBW: 0 kHz + + + + + + + Color for the FFT plot + + + Color + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + + 0 + 0 + + + + + 0 + 0 + + + + <html>Number of FFT points to calculate. Higher values will require more CPU time. This will not influence the number of points on the display since that parameter is adjusted automatically according to the display size. +</html> + + + false + + + 7 + + + 15 + + + QComboBox::InsertAlphabetically + - Auto - - - - - 5 min - - - - - 10 min - - - - - 15 min - - - - - 20 min + 1048576 - 30 min + 524288 - 1 hour + 262144 - 2 hours + 131072 - 5 hours + 65536 - 10 hours + 32768 - 16 hours + 16384 - 24 hours + 8192 - 48 hours + 4096 - - - - - - Waterfall time resolution. - - - - - - Res: - s - - - - - - - 2 - - - - - 0 - 0 - - - - - 50 - 32 - - - - - 16777215 - 16777215 - - - - Reset zoom level to 1x - - - R - - + + 3840 + - - - - 0 - 0 - - - - - 50 - 32 - - - - - 16777215 - 16777215 - - - - Center FFT around original center frequency - - - C - - + + 2048 + - - - - 0 - 0 - - - - - 50 - 32 - - - - - 16777215 - 16777215 - - - - Center FFT around demodulator frequency - - - D - - + + 1024 + - + + + 768 + + + + + 512 + + + - - + + 0 0 - - - 0 - 22 - + + Waterfall - - Set zoom level on the frequency axis + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - Set zoom level on the frequency axis + + + + + + + 0 + 0 + - - 1 + + Pandapter - - 50 + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - 5 + + + + + + + 0 + 0 + - - Qt::Horizontal + + + 50 + 32 + - - false + + Click to select color for the FFT plot - - false + + Click to select color for the FFT plot - - QSlider::NoTicks + + + + + true @@ -837,7 +735,7 @@ - + @@ -958,6 +856,164 @@ + + + + + 0 + 0 + + + + Current zoom level on the frequency axis + + + Current zoom level on the frequency axis + + + 1x + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Peak + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Set zoom level on the frequency axis + + + Set zoom level on the frequency axis + + + Freq zoom + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Set pandapter dB range + + + Set pandapter dB range + + + Pand. dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 5 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Set pandapter dB range + + + Set pandapter dB range + + + -160 + + + 0 + + + Qt::Horizontal + + + + + + + Set waterfall dB range + + + Set waterfall dB range + + + -160 + + + 0 + + + Qt::Horizontal + + + + + + + true + + + + 0 + 0 + + + + + 0 + 0 + + + + + 40 + 16777215 + + + + Lock panadapter and waterfall sliders together + + + Lock panadapter and waterfall sliders together + + + Lock + + + true + + + + + From 7fab20e183f99e7b00ccb9a27a851a08c734b864 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Tue, 27 Sep 2016 09:04:47 +0200 Subject: [PATCH 116/334] Remember which slider was set last --- src/qtgui/dockfft.cpp | 25 +++++++++++++++++++++---- src/qtgui/dockfft.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index 3427a5f..1c55e11 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -64,6 +64,7 @@ DockFft::DockFft(QWidget *parent) : #endif m_sample_rate = 0.f; + m_pand_last_modified = false; // Add predefined gqrx colors to chooser. ui->colorPicker->insertColor(QColor(0xFF,0xFF,0xFF,0xFF), "White"); @@ -307,6 +308,9 @@ void DockFft::setPandapterRange(float min, float max) { ui->pandRangeSlider->blockSignals(true); ui->pandRangeSlider->setValues((int) min, (int) max); + if (ui->lockButton->isChecked()) + ui->wfRangeSlider->setValues((int) min, (int) max); + m_pand_last_modified = true; ui->pandRangeSlider->blockSignals(false); } @@ -314,6 +318,9 @@ void DockFft::setWaterfallRange(float min, float max) { ui->wfRangeSlider->blockSignals(true); ui->wfRangeSlider->setValues((int) min, (int) max); + if (ui->lockButton->isChecked()) + ui->pandRangeSlider->setValues((int) min, (int) max); + m_pand_last_modified = false; ui->wfRangeSlider->blockSignals(false); } @@ -399,6 +406,7 @@ void DockFft::on_pandRangeSlider_valuesChanged(int min, int max) if (ui->lockButton->isChecked()) ui->wfRangeSlider->setValues(min, max); + m_pand_last_modified = true; emit pandapterRangeChanged((float) min, (float) max); } @@ -407,6 +415,7 @@ void DockFft::on_wfRangeSlider_valuesChanged(int min, int max) if (ui->lockButton->isChecked()) ui->pandRangeSlider->setValues(min, max); + m_pand_last_modified = false; emit waterfallRangeChanged((float) min, (float) max); } @@ -456,10 +465,18 @@ void DockFft::on_lockButton_toggled(bool checked) { if (checked) { - int min = ui->pandRangeSlider->minimumValue(); - int max = ui->pandRangeSlider->maximumValue(); - - ui->wfRangeSlider->setPositions(min, max); + if (m_pand_last_modified) + { + int min = ui->pandRangeSlider->minimumValue(); + int max = ui->pandRangeSlider->maximumValue(); + ui->wfRangeSlider->setPositions(min, max); + } + else + { + int min = ui->wfRangeSlider->minimumValue(); + int max = ui->wfRangeSlider->maximumValue(); + ui->pandRangeSlider->setPositions(min, max); + } } } diff --git a/src/qtgui/dockfft.h b/src/qtgui/dockfft.h index 63c7b98..67832cc 100644 --- a/src/qtgui/dockfft.h +++ b/src/qtgui/dockfft.h @@ -98,6 +98,7 @@ private slots: // float m_maximumFftDb; // float m_minimumFftDb; float m_sample_rate; + bool m_pand_last_modified; /* Flag to indicate which slider was changed last */ }; #endif // DOCKFFT_H From 9a790dac1a40f2808c6723e6365ae8d064bcbb29 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Tue, 27 Sep 2016 09:09:29 +0200 Subject: [PATCH 117/334] Add state of lockButton to settings --- src/qtgui/dockfft.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index 1c55e11..0e25841 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -245,6 +245,12 @@ void DockFft::saveSettings(QSettings *settings) else settings->setValue("waterfall_max_db", intval); + // pandapter and waterfall locked together + if (ui->lockButton->isChecked()) + settings->setValue("pand_wf_locked", true); + else + settings->remove("pand_wf_locked"); + settings->endGroup(); } @@ -301,6 +307,9 @@ void DockFft::readSettings(QSettings *settings) setWaterfallRange(fft_min, fft_max); emit waterfallRangeChanged((float) fft_min, (float) fft_max); + bool_val = settings->value("pand_wf_locked", false).toBool(); + ui->lockButton->setChecked(bool_val); + settings->endGroup(); } From ad5e17d68ef4360952e80e72ebd1b8f2b5ea022b Mon Sep 17 00:00:00 2001 From: Michael Tatarinov Date: Wed, 28 Sep 2016 07:32:53 +0400 Subject: [PATCH 118/334] qSort() is obsoleted. See http://doc.qt.io/qt-5/qtalgorithms-obsolete.html. Also uses std::stable_sort() instead of std::sort() to prevent reorders bookmarks with the some frequency. --- src/qtgui/bookmarks.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qtgui/bookmarks.cpp b/src/qtgui/bookmarks.cpp index c827e11..5eb3f2a 100644 --- a/src/qtgui/bookmarks.cpp +++ b/src/qtgui/bookmarks.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "bookmarks.h" #include #include @@ -59,7 +60,7 @@ void Bookmarks::setConfigDir(const QString& cfg_dir) void Bookmarks::add(BookmarkInfo &info) { m_BookmarkList.append(info); - qSort(m_BookmarkList); + std::stable_sort(m_BookmarkList.begin(),m_BookmarkList.end()); save(); emit( BookmarksChanged() ); } @@ -136,7 +137,7 @@ bool Bookmarks::load() } } file.close(); - qSort(m_BookmarkList); + std::stable_sort(m_BookmarkList.begin(),m_BookmarkList.end()); emit BookmarksChanged(); return true; From 3fa6219e149d634e79ef0f23138f9d49df68bc81 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 28 Sep 2016 16:33:33 +0200 Subject: [PATCH 119/334] Update readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ead243e..392cc1d 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ Michael Lass: - Improved tuning ranges at hardware limits. Michael Tatarinov: -- Documentation. +- Documentation and bugfixes. Moe Weatley: - FFT plotter and waterfall. From 57e79d5b14327879a157c1c683e52fcadc8ad0a1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 28 Sep 2016 17:21:14 +0200 Subject: [PATCH 120/334] Update news file. --- resources/news.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index afcdebd..775c5fa 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -6,6 +6,7 @@ NEW: Right-click on FFT resets frequency zoom. NEW: Separate dB ranges for pandapter and waterfall. NEW: Raw I/Q mode. + NEW: Portaudio support. FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. @@ -14,6 +15,7 @@ FIXED: LNB LO could not be set from I/O configuration dialog. FIXED: Update squelch level when switching between demodulators. FIXED: Set correct filter range when loading bookmark. + FIXED: White area on waterfall. IMPROVED: Input decimator performance. IMPROVED: SDRPlay integration. IMPROVED: Only probe for devices when the program is started. From 5ddecef12d4c54ac21dae765f192cd068888028f Mon Sep 17 00:00:00 2001 From: Michael Tatarinov Date: Thu, 29 Sep 2016 10:09:39 +0400 Subject: [PATCH 121/334] Bookmarks: sort tags too. --- src/qtgui/bookmarks.cpp | 2 ++ src/qtgui/bookmarks.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/qtgui/bookmarks.cpp b/src/qtgui/bookmarks.cpp index 5eb3f2a..b4e90d1 100644 --- a/src/qtgui/bookmarks.cpp +++ b/src/qtgui/bookmarks.cpp @@ -137,6 +137,7 @@ bool Bookmarks::load() } } file.close(); + std::sort(m_TagList.begin(),m_TagList.end()); std::stable_sort(m_BookmarkList.begin(),m_BookmarkList.end()); emit BookmarksChanged(); @@ -246,6 +247,7 @@ TagInfo &Bookmarks::findOrAddTag(QString tagName) TagInfo info; info.name=tagName; m_TagList.append(info); + std::sort(m_TagList.begin(),m_TagList.end()); emit TagListChanged(); return m_TagList.last(); } diff --git a/src/qtgui/bookmarks.h b/src/qtgui/bookmarks.h index b82bbda..411f5ca 100644 --- a/src/qtgui/bookmarks.h +++ b/src/qtgui/bookmarks.h @@ -51,6 +51,10 @@ struct TagInfo this->color=DefaultColor; this->name = name; } + bool operator<(const TagInfo &other) const + { + return name < other.name; + } }; struct BookmarkInfo From ed22a3eb673aae199bbc002510ab35c5d0d15cca Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 29 Sep 2016 22:34:48 +0200 Subject: [PATCH 122/334] Use implicit rect() for plotter tooltips. --- src/qtgui/plotter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index d860049..1a2750c 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -258,7 +258,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) QToolTip::showText(event->globalPos(), QString("Demod: %1 kHz") .arg(m_DemodCenterFreq/1.e3f, 0, 'f', 3), - this, rect()); + this); } else if (isPointCloseTo(pt.x(), m_DemodHiCutFreqX, m_CursorCaptureDelta)) { @@ -270,7 +270,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) QToolTip::showText(event->globalPos(), QString("High cut: %1 Hz") .arg(m_DemodHiCutFreq), - this, rect()); + this); } else if (isPointCloseTo(pt.x(), m_DemodLowCutFreqX, m_CursorCaptureDelta)) { @@ -282,7 +282,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) QToolTip::showText(event->globalPos(), QString("Low cut: %1 Hz") .arg(m_DemodLowCutFreq), - this, rect()); + this); } else if (isPointCloseTo(pt.x(), m_YAxisWidth/2, m_YAxisWidth/2)) { @@ -311,7 +311,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) QToolTip::showText(event->globalPos(), QString("F: %1 kHz") .arg(freqFromX(pt.x())/1.e3f, 0, 'f', 3), - this, rect()); + this); } m_GrabPosition = 0; } @@ -336,7 +336,7 @@ void CPlotter::mouseMoveEvent(QMouseEvent* event) QString("%1\n%2 kHz") .arg(tt.toString("yyyy.MM.dd hh:mm:ss.zzz")) .arg(freqFromX(pt.x())/1.e3f, 0, 'f', 3), - this, rect()); + this); } } // process mouse moves while in cursor capture modes From cef748bc66490ce88c3fe7e590a35bf4f680e811 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 29 Sep 2016 22:35:33 +0200 Subject: [PATCH 123/334] Make fusion or other styles optional (command line). --- src/applications/gqrx/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index c540d0d..1c1ec36 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -48,12 +48,12 @@ int main(int argc, char *argv[]) { QString cfg_file; std::string conf; + std::string style; bool clierr = false; bool edit_conf = false; int return_code; QApplication app(argc, argv); - QApplication::setStyle(QStyleFactory::create("Fusion")); QCoreApplication::setOrganizationName(GQRX_ORG_NAME); QCoreApplication::setOrganizationDomain(GQRX_ORG_DOMAIN); QCoreApplication::setApplicationName(GQRX_APP_NAME); @@ -78,6 +78,7 @@ int main(int argc, char *argv[]) po::options_description desc("Command line options"); desc.add_options() ("help,h", "This help message") + ("style,s", po::value(&style), "Use the give style (fusion, windows)") ("list,l", "List existing configurations") ("conf,c", po::value(&conf), "Start with this config file") ("edit,e", "Edit the config file before using it") @@ -110,6 +111,9 @@ int main(int argc, char *argv[]) return 1; } + if (vm.count("style")) + QApplication::setStyle(QString::fromStdString(style)); + if (vm.count("list")) { list_conf(); From 6caa4ea58cb0f49a6d1b869e1c8a270591db3352 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 29 Sep 2016 22:48:53 +0200 Subject: [PATCH 124/334] Indent. --- src/applications/gqrx/main.cpp | 12 ++++---- src/applications/gqrx/mainwindow.cpp | 42 ++++++++++++++-------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index 1c1ec36..d10477c 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -77,12 +77,12 @@ int main(int argc, char *argv[]) // setup the program options po::options_description desc("Command line options"); desc.add_options() - ("help,h", "This help message") - ("style,s", po::value(&style), "Use the give style (fusion, windows)") - ("list,l", "List existing configurations") - ("conf,c", po::value(&conf), "Start with this config file") - ("edit,e", "Edit the config file before using it") - ("reset,r", "Reset configuration file") + ("help,h", "This help message") + ("style,s", po::value(&style), "Use the give style (fusion, windows)") + ("list,l", "List existing configurations") + ("conf,c", po::value(&conf), "Start with this config file") + ("edit,e", "Edit the config file before using it") + ("reset,r", "Reset configuration file") ; po::variables_map vm; diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index a0026ae..7f0dc56 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2130,27 +2130,27 @@ void MainWindow::on_actionAbout_triggered() { QMessageBox::about(this, tr("About Gqrx"), tr("

This is Gqrx %1

" - "

Copyright (C) 2011-2016 Alexandru Csete & contributors.

" - "

Gqrx is a software defined radio receiver powered by " - "GNU Radio and the Qt toolkit. " - "

Gqrx uses the GrOsmoSDR " - "input source block and and works with any input device supported by it including:" - "

" - "

You can download the latest version from the " - "Gqrx website." - "

" - "

" - "Gqrx is licensed under the GNU General Public License." - "

").arg(VERSION)); + "

Copyright (C) 2011-2016 Alexandru Csete & contributors.

" + "

Gqrx is a software defined radio receiver powered by " + "GNU Radio and the Qt toolkit. " + "

Gqrx uses the GrOsmoSDR " + "input source block and and works with any input device supported by it including:" + "

" + "

You can download the latest version from the " + "Gqrx website." + "

" + "

" + "Gqrx is licensed under the GNU General Public License." + "

").arg(VERSION)); } /** From d77b682122f6f9c1b6d926d86a76f842f09c1ead Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 29 Sep 2016 22:51:48 +0200 Subject: [PATCH 125/334] Update news. --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 775c5fa..4cf0688 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -7,6 +7,7 @@ NEW: Separate dB ranges for pandapter and waterfall. NEW: Raw I/Q mode. NEW: Portaudio support. + NEW: Command line option to set Qt style (fusion, windows, ...) FIXED: Stuttering audio with Pulseaudio backend. FIXED: Use system font on FFT plot (too small font on high res displays). FIXED: Broken FUNcube Dongle Pro+ support on Mac OS X 10.11.4. From c14c9c4bedc25dbf0b45850179cdb5f2bc6c38bc Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 29 Sep 2016 22:52:10 +0200 Subject: [PATCH 126/334] Update text in about dialog. --- src/applications/gqrx/mainwindow.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 7f0dc56..0c2acdf 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2131,20 +2131,12 @@ void MainWindow::on_actionAbout_triggered() QMessageBox::about(this, tr("About Gqrx"), tr("

This is Gqrx %1

" "

Copyright (C) 2011-2016 Alexandru Csete & contributors.

" - "

Gqrx is a software defined radio receiver powered by " + "

Gqrx is a software defined radio (SDR) receiver powered by " "GNU Radio and the Qt toolkit. " "

Gqrx uses the GrOsmoSDR " - "input source block and and works with any input device supported by it including:" - "

" + "input source block and and works with any input device supported by it, including " + "Funcube Dongles, RTL-SDR, Airspy, HackRF, RFSpace, BladeRF and USRP receivers." + "

" "

You can download the latest version from the " "Gqrx website." "

" From ce3272fcc476f286dae43b6257a6a29609ff770f Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 29 Sep 2016 23:32:15 +0200 Subject: [PATCH 127/334] Readme tweaks. --- README.md | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 392cc1d..b0746cb 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,9 @@ Gqrx ==== Gqrx is an experimental software defined radio receiver implemented using GNU -Radio and the Qt GUI toolkit. Currently it works on Linux and Mac and supports -the following devices: -- Funcube Dongle Pro and Pro+ -- RTL2832U-based DVB-T dongles (rtlsdr via USB and TCP) -- OsmoSDR -- USRP -- HackRF -- Nuand bladeRF -- RFspace SDR-IQ, SDR-IP, NetSDR and Cloud-IQ -- Airspy -- any other device supported by the gr-osmosdr library +Radio and the Qt GUI toolkit. Currently it works on Linux and Mac with hardware +supported by gr-osmosdr, including Funcube Dongle, RTL-SDR, Airspy, HackRF, +BladeRF, RFSpace, USRP and even SoapySDR. Gqrx can operate as a traditional AM/FM/SSB receiver with audio output or as an FFT-only instrument. There are also various hooks for interacting with external @@ -22,9 +14,10 @@ application using nertwork sockets. Download -------- -Gqrx is distributed as source code package and binaries for Linux. Mac support -is avaialble through macports. Please see http://gqrx.dk/download for a list of -official and third party download resources. +Gqrx is distributed as source code package and binaries for Linux and Mac. +Alternate Mac support is available through macports and homebrew. + +Please see http://gqrx.dk/download for a list of official download resources. Usage @@ -93,23 +86,28 @@ To compile gqrx from source you need the following dependencies: - gnuradio-audio - gnuradio-pmt - The gr-iqbalance library (optional) -- At least one of: - - Funcube Dongle Pro driver via gnuradio-fcd - - UHD driver via gnuradio-uhd +- Drivers for the hardware you want to have support for: + - Funcube Dongle Pro driver via gr-fcd + - UHD driver via gr-uhd - Funcube Dongle Pro+ driver from https://github.com/dl1ksv/gr-fcdproplus - RTL-SDR driver from http://cgit.osmocom.org/cgit/rtl-sdr/ - OsmoSDR driver from http://cgit.osmocom.org/cgit/osmo-sdr/ - HackRF Jawbreaker driver from http://greatscottgadgets.com/hackrf/ + - Airspy driver from https://github.com/airspy/host + - SoapySDR from https://github.com/pothosware/SoapySDR + - RFSpace driver is bult in - gnuradio-osmosdr from http://cgit.osmocom.org/cgit/gr-osmosdr/ -- pulseaudio (Linux only and optional) -- Qt 4.8 or later with the following components: +- pulseaudio or portaudio (Linux only and optional) +- Qt 5 with the following components: - Core - GUI - Network - - Widgets (Qt 5 only) + - Widgets - Svg (runtime only) - cmake version >= 3.2.0 if you wish to build using cmake. Note that cmake builds require Qt 5. +Qt 4.8 may also work but no longer guaranteed. + To build using qmake, you can either open the gqrx.pro file in Qt Creator and build, or on the command line:

From 65dc5ede0cea70a6102a2d07d408ab9fe12c5959 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 30 Sep 2016 00:29:36 +0200
Subject: [PATCH 128/334] Use more descriptive name for config record.

---
 src/qtgui/dockfft.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp
index 0e25841..c952ac3 100644
--- a/src/qtgui/dockfft.cpp
+++ b/src/qtgui/dockfft.cpp
@@ -245,11 +245,11 @@ void DockFft::saveSettings(QSettings *settings)
     else
         settings->setValue("waterfall_max_db", intval);
 
-    // pandapter and waterfall locked together
+    // pandapter and waterfall ranges locked together
     if (ui->lockButton->isChecked())
-        settings->setValue("pand_wf_locked", true);
+        settings->setValue("db_ranges_locked", true);
     else
-        settings->remove("pand_wf_locked");
+        settings->remove("db_ranges_locked");
 
     settings->endGroup();
 }
@@ -307,7 +307,7 @@ void DockFft::readSettings(QSettings *settings)
     setWaterfallRange(fft_min, fft_max);
     emit waterfallRangeChanged((float) fft_min, (float) fft_max);
 
-    bool_val = settings->value("pand_wf_locked", false).toBool();
+    bool_val = settings->value("db_ranges_locked", false).toBool();
     ui->lockButton->setChecked(bool_val);
 
     settings->endGroup();

From ea15a92632d497c053b4863b1b1a68e234a575d8 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 30 Sep 2016 00:29:57 +0200
Subject: [PATCH 129/334] FFT layout tweaks.

---
 src/qtgui/dockfft.cpp |    1 +
 src/qtgui/dockfft.ui  | 1015 +++++++++++++++++++++--------------------
 2 files changed, 511 insertions(+), 505 deletions(-)

diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp
index c952ac3..b5ecc7c 100644
--- a/src/qtgui/dockfft.cpp
+++ b/src/qtgui/dockfft.cpp
@@ -56,6 +56,7 @@ DockFft::DockFft(QWidget *parent) :
     // buttons can be smaller than 50x32
     ui->peakDetectionButton->setMinimumSize(48, 24);
     ui->peakHoldButton->setMinimumSize(48, 24);
+    ui->lockButton->setMinimumSize(48, 24);
     ui->resetButton->setMinimumSize(48, 24);
     ui->centerButton->setMinimumSize(48, 24);
     ui->demodButton->setMinimumSize(48, 24);
diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui
index 02b600a..3609249 100644
--- a/src/qtgui/dockfft.ui
+++ b/src/qtgui/dockfft.ui
@@ -6,8 +6,8 @@
    
     0
     0
-    275
-    242
+    312
+    368
    
   
   
@@ -18,7 +18,7 @@
   
   
    
-    275
+    200
     200
    
   
@@ -43,9 +43,6 @@
   
   
    
-    
-     6
-    
     
      5
     
@@ -60,6 +57,12 @@
     
     
      
+      
+       
+        0
+        0
+       
+      
       
        QFrame::NoFrame
       
@@ -67,7 +70,10 @@
        QFrame::Sunken
       
       
-       Qt::ScrollBarAlwaysOff
+       Qt::ScrollBarAsNeeded
+      
+      
+       QAbstractScrollArea::AdjustToContentsOnFirstShow
       
       
        true
@@ -77,60 +83,100 @@
         
          0
          0
-         252
+         302
          339
         
        
        
         
-         5
+         0
         
         
-         5
+         0
         
         
-         5
+         0
         
         
-         5
+         0
         
         
-         5
+         0
         
         
          
+          
+           QLayout::SetDefaultConstraint
+          
           
-           5
+           0
           
           
-           5
+           0
           
           
-           5
+           0
           
           
-           5
+           0
           
           
-           5
+           6
           
-          
-           
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             
+              0
+              0
+             
+            
             
-             Set waterfall dB range
+             Set pandapter dB range
             
             
-             Set waterfall dB range
+             Set pandapter dB range
+            
+            
+             -160
+            
+            
+             0
+            
+            
+             Qt::Horizontal
+            
+           
+          
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             Current zoom level on the frequency axis
+            
+            
+             Current zoom level on the frequency axis
             
             
-             Wf. dB
+             1x
             
             
-             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+             Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
             
            
           
-          
+          
            
             
              2
@@ -208,7 +254,105 @@
             
            
           
-          
+          
+           
+            
+             FFT size
+            
+            
+             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+            
+           
+          
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             Waterfall
+            
+            
+             Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+            
+           
+          
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             
+              0
+              22
+             
+            
+            
+             Set zoom level on the frequency axis
+            
+            
+             Set zoom level on the frequency axis
+            
+            
+             1
+            
+            
+             50
+            
+            
+             5
+            
+            
+             Qt::Horizontal
+            
+            
+             false
+            
+            
+             false
+            
+            
+             QSlider::NoTicks
+            
+           
+          
+          
+           
+            
+             Waterfall time resolution.
+            
+            
+             
+            
+            
+             Res: - s
+            
+           
+          
+          
+           
+            
+             Set zoom level on the frequency axis
+            
+            
+             Set zoom level on the frequency axis
+            
+            
+             Freq zoom
+            
+            
+             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+            
+           
+          
+          
            
             
              
@@ -242,276 +386,178 @@
             
            
           
-          
-           
+          
+           
             
-             The vertical time span on the waterfall.
+             Color for the FFT plot
+            
+            
+             Color
+            
+            
+             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+            
+           
+          
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             
+              50
+              32
+             
+            
+            
+             Click to select color for the FFT plot
+            
+            
+             Click to select color for the FFT plot
+            
+            
+             
+            
+            
+             true
+            
+           
+          
+          
+           
+            
+             true
+            
+            
+             
+              0
+              0
+             
+            
+            
+             
+              0
+              0
+             
+            
+            
+             <html>Number of FFT points to calculate. Higher values will require more CPU time. This will not influence the number of points on the display since that parameter is adjusted automatically according to the display size.
+</html>
+            
+            
+             false
+            
+            
+             7
+            
+            
+             15
+            
+            
+             QComboBox::InsertAlphabetically
             
             
              
-              Auto
+              1048576
              
             
             
              
-              5 min
+              524288
              
             
             
              
-              10 min
+              262144
              
             
             
              
-              15 min
+              131072
              
             
             
              
-              20 min
+              65536
              
             
             
              
-              30 min
+              32768
              
             
             
              
-              1 hour
+              16384
              
             
             
              
-              2 hours
+              8192
              
             
             
              
-              5 hours
+              4096
              
             
             
              
-              10 hours
+              3840
              
             
             
              
-              16 hours
+              2048
              
             
             
              
-              24 hours
+              1024
              
             
             
              
-              48 hours
+              768
+             
+            
+            
+             
+              512
              
             
            
           
-          
-           
+          
+           
             
-             Waterfall time resolution.
+             Set pandapter dB range
             
             
-             
+             Set pandapter dB range
             
             
-             Res: - s
-            
-           
-          
-          
-           
-            
-             2
-            
-            
-             
-              
-               
-                0
-                0
-               
-              
-              
-               
-                50
-                32
-               
-              
-              
-               
-                16777215
-                16777215
-               
-              
-              
-               Reset zoom level to 1x
-              
-              
-               R
-              
-             
-            
-            
-             
-              
-               
-                0
-                0
-               
-              
-              
-               
-                50
-                32
-               
-              
-              
-               
-                16777215
-                16777215
-               
-              
-              
-               Center FFT around original center frequency
-              
-              
-               C
-              
-             
-            
-            
-             
-              
-               
-                0
-                0
-               
-              
-              
-               
-                50
-                32
-               
-              
-              
-               
-                16777215
-                16777215
-               
-              
-              
-               Center FFT around demodulator frequency
-              
-              
-               D
-              
-             
-            
-           
-          
-          
-           
-            
-             
-              0
-              0
-             
-            
-            
-             
-              0
-              22
-             
-            
-            
-             Set zoom level on the frequency axis
-            
-            
-             Set zoom level on the frequency axis
-            
-            
-             1
-            
-            
-             50
-            
-            
-             5
-            
-            
-             Qt::Horizontal
-            
-            
-             false
-            
-            
-             false
+             Pand. dB
             
-            
-             QSlider::NoTicks
+            
+             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
             
            
           
-          
-           
+          
+           
             
-             
+             
               0
               0
              
             
-            
-             
-              0
-              22
-             
-            
-            
-             Spatial distribution between pandapter and waterfall
-            
-            
-             0
-            
-            
-             100
-            
-            
-             50
-            
-            
-             Qt::Horizontal
-            
-           
-          
-          
-           
-            
-             The vertical time span on the waterfall.
-            
-            
-             
-            
-            
-             Time span
-            
-            
-             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-            
-           
-          
-          
-           
             
-             Rate
+             Pandapter
             
             
              Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
@@ -537,246 +583,111 @@
             
            
           
-          
-           
+          
+           
             
-             Resolution bandwidth
+             FFT buffer overlap between two consecutive FFT calculations.
             
             
-             RBW: 0 kHz
+             Overlap: 0%
+            
+            
+             0
             
            
           
-          
-           
+          
+           
             
-             Color for the FFT plot
+             Set waterfall dB range
+            
+            
+             Set waterfall dB range
             
             
-             Color
+             Wf. dB
             
             
              Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
             
            
           
-          
-           
-            
-             true
-            
+          
+           
             
              
               0
               0
              
             
-            
-             
-              0
-              0
-             
-            
             
-             <html>Number of FFT points to calculate. Higher values will require more CPU time. This will not influence the number of points on the display since that parameter is adjusted automatically according to the display size.
-</html>
-            
-            
-             false
-            
-            
-             7
-            
-            
-             15
-            
-            
-             QComboBox::InsertAlphabetically
+             The vertical time span on the waterfall.
             
             
              
-              1048576
+              Auto
              
             
             
              
-              524288
+              5 min
              
             
             
              
-              262144
+              10 min
              
             
             
              
-              131072
+              15 min
              
             
             
              
-              65536
+              20 min
              
             
             
              
-              32768
+              30 min
              
             
             
              
-              16384
+              1 hour
              
             
             
              
-              8192
+              2 hours
              
             
             
              
-              4096
+              5 hours
              
             
             
              
-              3840
+              10 hours
              
             
             
              
-              2048
+              16 hours
              
             
             
              
-              1024
+              24 hours
              
             
             
              
-              768
+              48 hours
              
             
-            
-             
-              512
-             
-            
-           
-          
-          
-           
-            
-             
-              0
-              0
-             
-            
-            
-             Waterfall
-            
-            
-             Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-            
-           
-          
-          
-           
-            
-             
-              0
-              0
-             
-            
-            
-             Pandapter
-            
-            
-             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-            
-           
-          
-          
-           
-            
-             
-              0
-              0
-             
-            
-            
-             
-              50
-              32
-             
-            
-            
-             Click to select color for the FFT plot
-            
-            
-             Click to select color for the FFT plot
-            
-            
-             
-            
-            
-             true
-            
-           
-          
-          
-           
-            
-             FFT buffer overlap between two consecutive FFT calculations.
-            
-            
-             Overlap: 0%
-            
-           
-          
-          
-           
-            
-             
-              0
-              0
-             
-            
-            
-             
-              50
-              32
-             
-            
-            
-             
-              16777215
-              16777215
-             
-            
-            
-             Fill the area below the FFT plot with a gradient
-            
-            
-             Fill the area below the FFT plot with a gradient
-            
-            
-             Fill
-            
-            
-             true
-            
-           
-          
-          
-           
-            
-             FFT size
-            
-            
-             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-            
            
           
           
@@ -856,179 +767,273 @@
             
            
           
-          
-           
-            
-             
-              0
-              0
-             
-            
-            
-             Current zoom level on the frequency axis
-            
-            
-             Current zoom level on the frequency axis
-            
-            
-             1x
-            
-            
-             Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-            
-           
-          
-          
-           
-            
-             Peak
-            
-            
-             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-            
-           
-          
-          
-           
-            
-             Set zoom level on the frequency axis
-            
-            
-             Set zoom level on the frequency axis
-            
-            
-             Freq zoom
-            
-            
-             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-            
-           
-          
-          
-           
+          
+           
             
-             Set pandapter dB range
+             The vertical time span on the waterfall.
             
             
-             Set pandapter dB range
+             
             
             
-             Pand. dB
+             Time span
             
             
              Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
             
            
           
-          
-           
+          
+           
             
-             5
+             2
             
-            
-             
+            
+             
               
-               
+               
                 0
                 0
                
               
               
                
-                0
-                0
+                50
+                32
                
               
-              
-               Set pandapter dB range
-              
-              
-               Set pandapter dB range
-              
-              
-               -160
+              
+               
+                16777215
+                16777215
+               
               
-              
-               0
+              
+               Reset zoom level to 1x
               
-              
-               Qt::Horizontal
+              
+               R
               
              
             
-            
-             
-              
-               Set waterfall dB range
+            
+             
+              
+               
+                0
+                0
+               
               
-              
-               Set waterfall dB range
+              
+               
+                50
+                32
+               
               
-              
-               -160
+              
+               
+                16777215
+                16777215
+               
               
-              
-               0
+              
+               Center FFT around original center frequency
               
-              
-               Qt::Horizontal
+              
+               C
               
              
             
-            
-             
-              
-               true
-              
+            
+             
               
-               
+               
                 0
                 0
                
               
               
                
-                0
-                0
+                50
+                32
                
               
               
                
-                40
+                16777215
                 16777215
                
               
               
-               Lock panadapter and waterfall sliders together
-              
-              
-               Lock panadapter and waterfall sliders together
+               Center FFT around demodulator frequency
               
               
-               Lock
-              
-              
-               true
+               D
               
              
             
            
           
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             
+              50
+              32
+             
+            
+            
+             
+              16777215
+              16777215
+             
+            
+            
+             Fill the area below the FFT plot with a gradient
+            
+            
+             Fill the area below the FFT plot with a gradient
+            
+            
+             Fill
+            
+            
+             true
+            
+           
+          
+          
+           
+            
+             Peak
+            
+            
+             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+            
+           
+          
+          
+           
+            
+             Rate
+            
+            
+             Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+            
+           
+          
+          
+           
+            
+             Set waterfall dB range
+            
+            
+             Set waterfall dB range
+            
+            
+             -160
+            
+            
+             0
+            
+            
+             Qt::Horizontal
+            
+           
+          
+          
+           
+            
+             Resolution bandwidth
+            
+            
+             RBW: 0 kHz
+            
+           
+          
+          
+           
+            
+             true
+            
+            
+             
+              0
+              0
+             
+            
+            
+             
+              50
+              32
+             
+            
+            
+             Lock panadapter and waterfall sliders together
+            
+            
+             Lock panadapter and waterfall sliders together
+            
+            
+             Lock
+            
+            
+             true
+            
+           
+          
+          
+           
+            
+             
+              0
+              0
+             
+            
+            
+             
+              0
+              22
+             
+            
+            
+             Spatial distribution between pandapter and waterfall
+            
+            
+             0
+            
+            
+             100
+            
+            
+             50
+            
+            
+             Qt::Horizontal
+            
+           
+          
+          
+           
+            
+             Qt::Vertical
+            
+            
+             
+              253
+              68
+             
+            
+           
+          
          
         
-        
-         
-          
-           Qt::Vertical
-          
-          
-           
-            20
-            8
-           
-          
-         
-        
        
       
      

From d5e632d15e1b38e5dd7679fdf4722d99627028e9 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 30 Sep 2016 00:40:23 +0200
Subject: [PATCH 130/334] Use full text on buttons.

Now thatbuttons have minimum size we may as well use full text on
buttons instead of just their capital letters.
---
 src/qtgui/dockfft.ui | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui
index 3609249..2c60b7c 100644
--- a/src/qtgui/dockfft.ui
+++ b/src/qtgui/dockfft.ui
@@ -812,7 +812,7 @@
                Reset zoom level to 1x
               
               
-               R
+               Reset
               
              
             
@@ -840,7 +840,7 @@
                Center FFT around original center frequency
               
               
-               C
+               Center
               
              
             
@@ -868,7 +868,7 @@
                Center FFT around demodulator frequency
               
               
-               D
+               Demod
               
              
             

From 3460aa7ff8d8e79ad37fa594467f038c60266ea3 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 30 Sep 2016 00:59:40 +0200
Subject: [PATCH 131/334] LEt Lock button occupy a single cell only.

This make the button have a more native feel and leaves an empty cell
for a future auto-scale button.
---
 src/qtgui/dockfft.ui | 70 ++++++++++++++++++++++----------------------
 1 file changed, 35 insertions(+), 35 deletions(-)

diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui
index 2c60b7c..6742884 100644
--- a/src/qtgui/dockfft.ui
+++ b/src/qtgui/dockfft.ui
@@ -6,8 +6,8 @@
    
     0
     0
-    312
-    368
+    320
+    386
    
   
   
@@ -83,8 +83,8 @@
         
          0
          0
-         302
-         339
+         310
+         357
         
        
        
@@ -957,37 +957,6 @@
             
            
           
-          
-           
-            
-             true
-            
-            
-             
-              0
-              0
-             
-            
-            
-             
-              50
-              32
-             
-            
-            
-             Lock panadapter and waterfall sliders together
-            
-            
-             Lock panadapter and waterfall sliders together
-            
-            
-             Lock
-            
-            
-             true
-            
-           
-          
           
            
             
@@ -1032,6 +1001,37 @@
             
            
           
+          
+           
+            
+             true
+            
+            
+             
+              0
+              0
+             
+            
+            
+             
+              50
+              32
+             
+            
+            
+             Lock panadapter and waterfall sliders together
+            
+            
+             Lock panadapter and waterfall sliders together
+            
+            
+             Lock
+            
+            
+             true
+            
+           
+          
          
         
        

From 5dd3978fd87910e3b5f4965b447cd28336a0ef31 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Fri, 30 Sep 2016 11:19:08 +0400
Subject: [PATCH 132/334] Bookmarks: sort tags only in load before bookmarks.

The code uses tag index for coupling between bookmark and tag.
Reorder tags breaks it.
---
 src/qtgui/bookmarks.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/qtgui/bookmarks.cpp b/src/qtgui/bookmarks.cpp
index b4e90d1..7ec7bda 100644
--- a/src/qtgui/bookmarks.cpp
+++ b/src/qtgui/bookmarks.cpp
@@ -105,6 +105,7 @@ bool Bookmarks::load()
                 printf("\nBookmarks: Ignoring Line:\n  %s\n", line.toLatin1().data());
             }
         }
+        std::sort(m_TagList.begin(),m_TagList.end());
 
         // Read Bookmarks, after first empty line.
         while (!file.atEnd())
@@ -137,7 +138,6 @@ bool Bookmarks::load()
             }
         }
         file.close();
-        std::sort(m_TagList.begin(),m_TagList.end());
         std::stable_sort(m_BookmarkList.begin(),m_BookmarkList.end());
 
         emit BookmarksChanged();
@@ -247,7 +247,6 @@ TagInfo &Bookmarks::findOrAddTag(QString tagName)
     TagInfo info;
     info.name=tagName;
     m_TagList.append(info);
-    std::sort(m_TagList.begin(),m_TagList.end());
     emit TagListChanged();
     return m_TagList.last();
 }

From 4e438cdf2996d8f53edc54664be7c22cdb203614 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 1 Oct 2016 19:58:44 +0200
Subject: [PATCH 133/334] Allow audio recording in Raw I/Q mode.

---
 src/applications/gqrx/mainwindow.cpp     | 3 +--
 src/applications/gqrx/remote_control.cpp | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 0c2acdf..c6e6bd3 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -1057,8 +1057,7 @@ void MainWindow::selectDemod(int mode_idx)
     rx->set_cw_offset(cwofs);
     rx->set_sql_level(uiDockRxOpt->currentSquelchLevel());
 
-    d_have_audio = ((mode_idx != DockRxOpt::MODE_OFF) &&
-                    (mode_idx != DockRxOpt::MODE_RAW));
+    d_have_audio = (mode_idx != DockRxOpt::MODE_OFF);
 
     uiDockRxOpt->setCurrentDemod(mode_idx);
 }
diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 079a6b0..1477563 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -444,7 +444,7 @@ void RemoteControl::setSquelchLevel(double level)
 /*! \brief Start audio recorder (from mainwindow). */
 void RemoteControl::startAudioRecorder(QString unused)
 {
-    if (rc_mode >= 2)
+    if (rc_mode > 0)
         audio_recorder_status = true;
 }
 

From 96cecb8e1801cb426e4d328676c453757effb8a2 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 1 Oct 2016 20:09:46 +0200
Subject: [PATCH 134/334] Fix raw I/Q audio recording in remote controller.

---
 src/applications/gqrx/remote_control.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 1477563..7738448 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -254,7 +254,7 @@ void RemoteControl::startRead()
             rc_socket->write("RPRT 0\n");
             rc_mode = mode;
 
-            if (rc_mode < 2)
+            if (rc_mode == 0)
                 audio_recorder_status = false;
 
             emit newMode(rc_mode);
@@ -280,7 +280,7 @@ void RemoteControl::startRead()
         }
         else if (func.compare("RECORD", Qt::CaseInsensitive) == 0)
         {
-            if (rc_mode < 2 || !receiver_running)
+            if (rc_mode == 0 || !receiver_running)
             {
                 rc_socket->write("RPRT 1\n");
             }
@@ -317,7 +317,7 @@ void RemoteControl::startRead()
     //   LOS  - satellite LOS event
     else if (cmdlist[0] == "AOS")
     {
-        if (rc_mode >= 2 && receiver_running)
+        if (rc_mode > 0 && receiver_running)
         {
             emit startAudioRecorderEvent();
             audio_recorder_status = true;
@@ -407,7 +407,7 @@ void RemoteControl::setMode(int mode)
 {
     rc_mode = mode;
 
-    if (rc_mode < 2)
+    if (rc_mode == 0)
         audio_recorder_status = false;
 }
 

From 902ba8cf6a63c33939193116d624f82034e7a3f5 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 1 Oct 2016 23:53:28 +0200
Subject: [PATCH 135/334] Minor improvements to the sample rate selector.

---
 src/qtgui/ioconfig.cpp | 78 ++++++++++++++++++++----------------------
 1 file changed, 38 insertions(+), 40 deletions(-)

diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp
index 4d825bc..557cdf6 100644
--- a/src/qtgui/ioconfig.cpp
+++ b/src/qtgui/ioconfig.cpp
@@ -252,18 +252,10 @@ void CIoConfig::getDeviceList(std::map &devList)
 
         qDebug() << "   " << i << ":"  << devlabel;
         ++i;
-
-        // Following code could be used for multiple matches
-        /* QStringList list;
-        int pos = 0;
-        while ((pos = rx.indexIn(devstr, pos)) != -1) {
-            list << rx.cap(1);
-            pos += rx.matchedLength();
-        } */
     }
 }
 
-/** @brief Save configuration. */
+/** Save configuration. */
 void CIoConfig::saveConfig()
 {
     int         idx;
@@ -331,18 +323,7 @@ void CIoConfig::updateInputSampleRates(int rate)
     ui->inSrCombo->clear();
 
     if (ui->inDevEdit->text().isEmpty())
-    {
         return;
-    }
-
-    /** FIXME: this code crashes on RTL device so we use fixed rates **/
-    //osmosdr_source_c_sptr src = osmosdr_make_source_c(ui->inDevEdit->text().toStdString());
-    //osmosdr::meta_range_t rates = src->get_sample_rates();
-    //BOOST_FOREACH(osmosdr::range_t &rate, rates)
-    //{
-    //    ui->inSrCombo->addItem(QString("%1 kHz").arg(rate.start()/1000, 0, 'f', 0));
-    //}
-    //src.reset();
 
     if (ui->inDevEdit->text().contains("fcd"))
     {
@@ -420,9 +401,6 @@ void CIoConfig::updateInputSampleRates(int rate)
     }
     else if (ui->inDevEdit->text().contains("sdr-iq"))
     {
-        if (rate > 0)
-            ui->inSrCombo->addItem(QString("%1").arg(rate));
-
         ui->inSrCombo->addItem("8138");
         ui->inSrCombo->addItem("16276");
         ui->inSrCombo->addItem("37793");
@@ -430,12 +408,16 @@ void CIoConfig::updateInputSampleRates(int rate)
         ui->inSrCombo->addItem("111111");
         ui->inSrCombo->addItem("158730");
         ui->inSrCombo->addItem("196078");
+        if (rate > 0)
+        {
+            ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
+        else
+            ui->inSrCombo->setCurrentIndex(4); // select 111.111 kHz
     }
     else if (ui->inDevEdit->text().contains("sdr-ip"))
     {
-        if (rate > 0)
-            ui->inSrCombo->addItem(QString("%1").arg(rate));
-
         ui->inSrCombo->addItem("31250");
         ui->inSrCombo->addItem("32000");
         ui->inSrCombo->addItem("40000");
@@ -455,12 +437,16 @@ void CIoConfig::updateInputSampleRates(int rate)
         ui->inSrCombo->addItem("1000000");
         ui->inSrCombo->addItem("1600000");
         ui->inSrCombo->addItem("2000000");
+        if (rate > 0)
+        {
+            ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
+        else
+            ui->inSrCombo->setCurrentIndex(11); // select 250 kHz
     }
     else if (ui->inDevEdit->text().contains("netsdr"))
     {
-        if (rate > 0)
-            ui->inSrCombo->addItem(QString("%1").arg(rate));
-
         ui->inSrCombo->addItem("32000");
         ui->inSrCombo->addItem("40000");
         ui->inSrCombo->addItem("50000");
@@ -481,6 +467,13 @@ void CIoConfig::updateInputSampleRates(int rate)
         ui->inSrCombo->addItem("1000000");
         ui->inSrCombo->addItem("1250000");
         ui->inSrCombo->addItem("2000000");
+        if (rate > 0)
+        {
+            ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
+        else
+            ui->inSrCombo->setCurrentIndex(11); // select 250 kHz
     }
     else if (ui->inDevEdit->text().contains("cloudiq"))
     {
@@ -498,9 +491,12 @@ void CIoConfig::updateInputSampleRates(int rate)
         ui->inSrCombo->addItem("1228800");
         ui->inSrCombo->addItem("1807058");
         if (rate > 0)
+        {
             ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
         else
-            ui->inSrCombo->setCurrentIndex(4); // select 370 kHz
+            ui->inSrCombo->setCurrentIndex(4); // select 240 kHz
     }
     else if (ui->inDevEdit->text().contains("airspy"))
     {
@@ -521,14 +517,15 @@ void CIoConfig::updateInputSampleRates(int rate)
         ui->inSrCombo->addItem("500000");
         ui->inSrCombo->addItem("1250000");
         if (rate > 0)
-            ui->inSrCombo->addItem(QString("%1").arg(rate));
+        {
+            ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
         else
             ui->inSrCombo->setCurrentIndex(3); // select 250 kHz
     }
     else if (ui->inDevEdit->text().contains("sdrplay"))
     {
-        if (rate > 0)
-            ui->inSrCombo->addItem(QString("%1").arg(rate));
         ui->inSrCombo->addItem("222222");
         ui->inSrCombo->addItem("333333");
         ui->inSrCombo->addItem("428571");
@@ -547,7 +544,12 @@ void CIoConfig::updateInputSampleRates(int rate)
         ui->inSrCombo->addItem("10000000");
         ui->inSrCombo->addItem("11000000");
         ui->inSrCombo->addItem("12000000");
-        if (rate == 0)
+        if (rate > 0)
+        {
+            ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
+        else
             ui->inSrCombo->setCurrentIndex(9); // select 2048 kHz
     }
     else
@@ -669,9 +671,7 @@ void CIoConfig::decimationChanged(int index)
                                    arg(quad_rate * 1.e-3, 0, 'f', 3));
 }
 
-/**
- * @brief Convert a combo box index to decimation.
- */
+/** Convert a combo box index to decimation. */
 int CIoConfig::idx2decim(int idx) const
 {
     if (idx < 1)
@@ -680,9 +680,7 @@ int CIoConfig::idx2decim(int idx) const
     return (1 << idx);
 }
 
-/**
- * @brief Convert a decimation to a combobox index
- */
+/** Convert a decimation to a combobox index */
 int CIoConfig::decim2idx(int decim) const
 {
     int         idx;

From 0582f1f751406d7d15cc178edcb930275c10e880 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 2 Oct 2016 19:33:05 +0200
Subject: [PATCH 136/334] Require Qt 5.

Maintaing Qt 4 compatibility becomes increasingly painful. Even small
changes in designer forms can have side effects that break copatibility
with Qt 4. So lets just stop spending time on this.
---
 README.md | 4 +---
 gqrx.pro  | 7 ++++---
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index b0746cb..ee9ef6e 100644
--- a/README.md
+++ b/README.md
@@ -104,9 +104,7 @@ To compile gqrx from source you need the following dependencies:
     - Network
     - Widgets
     - Svg (runtime only)
-- cmake version >= 3.2.0 if you wish to build using cmake. Note that cmake builds require Qt 5.
-
-Qt 4.8 may also work but no longer guaranteed.
+- cmake version >= 3.2.0 if you wish to build using cmake.
 
 To build using qmake, you can either open the gqrx.pro file in Qt Creator and
 build, or on the command line:
diff --git a/gqrx.pro b/gqrx.pro
index 9f6e999..e932f63 100644
--- a/gqrx.pro
+++ b/gqrx.pro
@@ -10,9 +10,10 @@
 #   BOOST_SUFFIX=-mt       To link against libboost-xyz-mt (needed for pybombs)
 #--------------------------------------------------------------------------------
 
-QT       += core gui network
-contains(QT_MAJOR_VERSION,5) {
-    QT += widgets
+QT       += core gui network widgets
+
+lessThan(QT_MAJOR_VERSION,5) {
+    error("Gqrx requires Qt 5.")
 }
 
 TEMPLATE = app

From b067c09866b8ee2138870654a587b1fee8c871f4 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 2 Oct 2016 19:35:39 +0200
Subject: [PATCH 137/334] Always quote strings.

---
 gqrx.pro | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gqrx.pro b/gqrx.pro
index e932f63..6f42def 100644
--- a/gqrx.pro
+++ b/gqrx.pro
@@ -32,7 +32,7 @@ CONFIG += link_pkgconfig
 unix:!macx {
     equals(AUDIO_BACKEND, "portaudio") {
         !packagesExist(portaudio-2.0) {
-            error(Portaudio backend requires portaudio19-dev package.)
+            error("Portaudio backend requires portaudio19-dev package.")
         }
     }
     isEmpty(AUDIO_BACKEND) {
@@ -52,7 +52,7 @@ QMAKE_CLEAN += gqrx
 
 # make install target
 isEmpty(PREFIX) {
-    message(No prefix given. Using /usr/local)
+    message("No prefix given. Using /usr/local")
     PREFIX=/usr/local
 }
 

From 65f0602b14aa055ccfd4f34523082379488b3c40 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 2 Oct 2016 21:02:41 +0200
Subject: [PATCH 138/334] Limit the scope of local variables.

---
 src/qtgui/dockinputctl.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/qtgui/dockinputctl.cpp b/src/qtgui/dockinputctl.cpp
index 149033d..033d8d7 100644
--- a/src/qtgui/dockinputctl.cpp
+++ b/src/qtgui/dockinputctl.cpp
@@ -85,11 +85,12 @@ void DockInputCtl::readSettings(QSettings * settings)
 
     // gains are stored as a QMap
     // note that we store the integer values, i.e. dB*10
-    QMap  allgains;
-    QString gain_name;
-    double gain_value;
     if (settings->contains("input/gains"))
     {
+        QMap     allgains;
+        QString     gain_name;
+        double      gain_value;
+
         allgains = settings->value("input/gains").toMap();
         QMapIterator  gain_iter(allgains);
 
@@ -103,7 +104,6 @@ void DockInputCtl::readSettings(QSettings * settings)
             emit gainChanged(gain_name, gain_value);
         }
     }
-
 }
 
 void DockInputCtl::saveSettings(QSettings * settings)

From 2034b335afc41044762c4c2e37cc9cdf1d6ceb33 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 2 Oct 2016 22:35:15 +0200
Subject: [PATCH 139/334] Update news and readme.

---
 README.md          | 14 +++++++-------
 resources/news.txt |  3 ++-
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index ee9ef6e..35e13b8 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
 Gqrx
 ====
 
-Gqrx is an experimental software defined radio receiver implemented using GNU
-Radio and the Qt GUI toolkit. Currently it works on Linux and Mac with hardware
-supported by gr-osmosdr, including Funcube Dongle, RTL-SDR, Airspy, HackRF,
-BladeRF, RFSpace, USRP and even SoapySDR.
+Gqrx is an open source software defined radio (SDR) receiver implemented using
+GNU Radio and the Qt GUI toolkit. Currently it works on Linux and Mac with
+hardware supported by gr-osmosdr, including Funcube Dongle, RTL-SDR, Airspy,
+HackRF, BladeRF, RFSpace, USRP and SoapySDR.
 
-Gqrx can operate as a traditional AM/FM/SSB receiver with audio output or as an
-FFT-only instrument. There are also various hooks for interacting with external
+Gqrx can operate as an AM/FM/SSB receiver with audio output or as an FFT-only
+instrument. There are also various hooks for interacting with external
 application using nertwork sockets.
 
 
@@ -17,7 +17,7 @@ Download
 Gqrx is distributed as source code package and binaries for Linux and Mac.
 Alternate Mac support is available through macports and homebrew.
 
-Please see http://gqrx.dk/download for a list of official download resources.
+Please see http://gqrx.dk/download for a list of download resources.
 
 
 Usage
diff --git a/resources/news.txt b/resources/news.txt
index 4cf0688..ae53d58 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -1,4 +1,4 @@
-       2.6: Released TBD
+       2.6: Released October 3, 2016
 
        NEW: 1-2-5 scaling on FFT axis.
        NEW: Audio waterfall.
@@ -17,6 +17,7 @@
      FIXED: Update squelch level when switching between demodulators.
      FIXED: Set correct filter range when loading bookmark.
      FIXED: White area on waterfall.
+     FIXED: RFSpace Cloud-IQ support on Mac OS X and in PPA
   IMPROVED: Input decimator performance.
   IMPROVED: SDRPlay integration.
   IMPROVED: Only probe for devices when the program is started.

From 79560565d9f36b17bc01130c49b2f69350ede2ee Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 2 Oct 2016 22:55:02 +0200
Subject: [PATCH 140/334] Update version strings to 2.6

---
 CMakeLists.txt | 22 +++++++++++-----------
 gqrx.pro       |  8 ++++----
 2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3a12f56..fcc33bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,20 +3,20 @@ cmake_minimum_required(VERSION 2.8.0)
 # Project name
 project(gqrx)
 set(${PROJECT_NAME}_MAJOR "2")
-set(${PROJECT_NAME}_MINOR "5")
-set(${PROJECT_NAME}_PATCH "3")
+set(${PROJECT_NAME}_MINOR "6")
+set(${PROJECT_NAME}_PATCH "0")
 ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}")
-##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}")
-##add_definitions(-DVERSION="${VERSION}")
+set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}")
+add_definitions(-DVERSION="${VERSION}")
 
 # development version
-execute_process(
-    COMMAND git describe --long --dirty
-    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-    OUTPUT_VARIABLE GITVERSION
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-)
-add_definitions(-DVERSION="${GITVERSION}")
+#execute_process(
+#    COMMAND git describe --long --dirty
+#    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+#    OUTPUT_VARIABLE GITVERSION
+#    OUTPUT_STRIP_TRAILING_WHITESPACE
+#)
+#add_definitions(-DVERSION="${GITVERSION}")
 
 set(PACKAGE ${PROJECT_NAME})
 
diff --git a/gqrx.pro b/gqrx.pro
index 6f42def..7431435 100644
--- a/gqrx.pro
+++ b/gqrx.pro
@@ -67,14 +67,14 @@ CONFIG(debug, debug|release) {
     #QMAKE_CFLAGS_DEBUG += '-g -O0'
 
     # Define version string (see below for releases)
-    VER = $$system(git describe --abbrev=8)
-    ##VER = 2.5.3
+    ##VER = $$system(git describe --abbrev=8)
+    VER = 2.6
 
 } else {
     DEFINES += QT_NO_DEBUG
     DEFINES += QT_NO_DEBUG_OUTPUT
-    VER = $$system(git describe --abbrev=1)
-    ##VER = 2.5.3
+    ##VER = $$system(git describe --abbrev=1)
+    VER = 2.6
 
     # Release binaries with gr bundled
     # QMAKE_RPATH & co won't work with origin

From d3324e342ab31809f7965384bc5250a845c55dbf Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Fri, 30 Sep 2016 09:53:47 +0400
Subject: [PATCH 141/334] Remote control: Refactoring the load()/save() code.

Initialization the rc_freq/rc_filter_offset is unnecessary when the
remote control server running we get the current value from main code.
---
 src/applications/gqrx/remote_control.cpp | 31 +++++++++++++++---------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 7738448..ea2ee9a 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -74,35 +74,44 @@ void RemoteControl::stop_server()
 /*! \brief Read settings. */
 void RemoteControl::readSettings(QSettings *settings)
 {
-    bool conv_ok;
+    if (!settings)
+        return;
 
-    rc_freq = settings->value("input/frequency", 144500000).toLongLong(&conv_ok);
-    rc_filter_offset = settings->value("receiver/offset", 0).toInt(&conv_ok);
+    settings->beginGroup("remote_control");
 
     // Get port number; restart server if running
-    rc_port = settings->value("remote_control/port", 7356).toInt(&conv_ok);
+    rc_port = settings->value("port", 7356).toInt();
     if (rc_server.isListening())
     {
         rc_server.close();
         rc_server.listen(QHostAddress::Any, rc_port);
     }
 
-    // get list of allowed hosts
-    if (settings->contains("remote_control/allowed_hosts"))
-        rc_allowed_hosts = settings->value("remote_control/allowed_hosts").toStringList();
+    // Get list of allowed hosts
+    if (settings->contains("allowed_hosts"))
+        rc_allowed_hosts = settings->value("allowed_hosts").toStringList();
+
+    settings->endGroup();
 }
 
 void RemoteControl::saveSettings(QSettings *settings) const
 {
+    if (!settings)
+        return;
+
+    settings->beginGroup("remote_control");
+
     if (rc_port != 7356)
-        settings->setValue("remote_control/port", rc_port);
+        settings->setValue("port", rc_port);
     else
-        settings->remove("remote_control/port");
+        settings->remove("port");
 
     if ((rc_allowed_hosts.count() != 1) || (rc_allowed_hosts.at(0) != "::ffff:127.0.0.1"))
-        settings->setValue("remote_control/allowed_hosts", rc_allowed_hosts);
+        settings->setValue("allowed_hosts", rc_allowed_hosts);
     else
-        settings->remove("remote_control/allowed_hosts");
+        settings->remove("allowed_hosts");
+
+    settings->endGroup();
 }
 
 /*! \brief Set new network port.

From ebb9a756c513811608ff76b1089ea40841f870df Mon Sep 17 00:00:00 2001
From: Alexander Fasching 
Date: Mon, 3 Oct 2016 20:41:24 +0200
Subject: [PATCH 142/334] Keep zoom-slider and waterfall zoom synchronized

---
 src/applications/gqrx/mainwindow.cpp | 2 ++
 src/qtgui/dockfft.cpp                | 8 ++++++++
 src/qtgui/dockfft.h                  | 1 +
 src/qtgui/plotter.cpp                | 1 +
 src/qtgui/plotter.h                  | 1 +
 5 files changed, 13 insertions(+)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index c6e6bd3..0efb8cf 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -235,6 +235,8 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
             ui->plotter, SLOT(setWaterfallRange(float,float)));
     connect(ui->plotter, SIGNAL(pandapterRangeChanged(float,float)),
             uiDockFft, SLOT(setPandapterRange(float,float)));
+    connect(ui->plotter, SIGNAL(newZoomLevel(float)),
+            uiDockFft, SLOT(setZoomLevel(float)));
 
     connect(uiDockFft, SIGNAL(fftColorChanged(QColor)), this, SLOT(setFftColor(QColor)));
     connect(uiDockFft, SIGNAL(fftFillToggled(bool)), this, SLOT(setFftFill(bool)));
diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp
index b5ecc7c..5056eca 100644
--- a/src/qtgui/dockfft.cpp
+++ b/src/qtgui/dockfft.cpp
@@ -334,6 +334,14 @@ void DockFft::setWaterfallRange(float min, float max)
     ui->wfRangeSlider->blockSignals(false);
 }
 
+void DockFft::setZoomLevel(float level)
+{
+    ui->fftZoomSlider->blockSignals(true);
+    ui->fftZoomSlider->setValue((int) level);
+    ui->zoomLevelLabel->setText(QString("%1x").arg((int) level));
+    ui->fftZoomSlider->blockSignals(false);
+}
+
 /** FFT size changed. */
 void DockFft::on_fftSizeComboBox_currentIndexChanged(const QString &text)
 {
diff --git a/src/qtgui/dockfft.h b/src/qtgui/dockfft.h
index 67832cc..37b49bc 100644
--- a/src/qtgui/dockfft.h
+++ b/src/qtgui/dockfft.h
@@ -71,6 +71,7 @@ public slots:
     void setPandapterRange(float min, float max);
     void setWaterfallRange(float min, float max);
     void setWfResolution(quint64 msec_per_line);
+    void setZoomLevel(float level);
 
 private slots:
     void on_fftSizeComboBox_currentIndexChanged(const QString & text);
diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp
index 1a2750c..e491632 100644
--- a/src/qtgui/plotter.cpp
+++ b/src/qtgui/plotter.cpp
@@ -771,6 +771,7 @@ void CPlotter::zoomStepX(float step, int x)
     setSpanFreq((quint32)new_range);
 
     float factor = (float)m_SampleFreq / (float)m_Span;
+    emit newZoomLevel(factor);
     qDebug() << QString("Spectrum zoom: %1x").arg(factor, 0, 'f', 1);
 
     m_PeakHoldValid = false;
diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h
index d8b58bd..33708dd 100644
--- a/src/qtgui/plotter.h
+++ b/src/qtgui/plotter.h
@@ -121,6 +121,7 @@ class CPlotter : public QFrame
     void newHighCutFreq(int f);
     void newFilterFreq(int low, int high);  /* substitute for NewLow / NewHigh */
     void pandapterRangeChanged(float min, float max);
+    void newZoomLevel(float level);
 
 public slots:
     // zoom functions

From c05258b65fd194ab33e4f22ccd11db2095f8923b Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 3 Oct 2016 10:23:13 +0400
Subject: [PATCH 143/334] Remote control: state is saved now.

Fixes #219.
---
 src/applications/gqrx/mainwindow.cpp     | 13 ++++++++++++-
 src/applications/gqrx/remote_control.cpp |  8 +++++++-
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index c6e6bd3..f4d72a1 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -575,9 +575,20 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash,
         setNewFrequency(ui->freqCtrl->getFrequency()); // ensure all GUI and RF is updated
     }
 
-    remote->readSettings(m_settings);
     iq_tool->readSettings(m_settings);
 
+    /*
+     * Initialization the remote control at the end.
+     * We must be sure that all variables initialized before starting RC server.
+     */
+    remote->readSettings(m_settings);
+    bool_val = m_settings->value("remote_control/enabled", false).toBool();
+    if (bool_val)
+    {
+       remote->start_server();
+       ui->actionRemoteControl->setChecked(true);
+    }
+
     return conf_ok;
 }
 
diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index ea2ee9a..466c0cc 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -57,7 +57,8 @@ RemoteControl::~RemoteControl()
 /*! \brief Start the server. */
 void RemoteControl::start_server()
 {
-    rc_server.listen(QHostAddress::Any, rc_port);
+    if (!rc_server.isListening())
+        rc_server.listen(QHostAddress::Any, rc_port);
 }
 
 /*! \brief Stop the server. */
@@ -101,6 +102,11 @@ void RemoteControl::saveSettings(QSettings *settings) const
 
     settings->beginGroup("remote_control");
 
+    if (rc_server.isListening())
+        settings->setValue("enabled", true);
+    else
+        settings->remove("enabled");
+
     if (rc_port != 7356)
         settings->setValue("port", rc_port);
     else

From 22fc13a0ff344fb16757266a08aa6dbd9d42a1c9 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 6 Oct 2016 22:35:01 +0200
Subject: [PATCH 144/334] Continue with devel versioning.

---
 CMakeLists.txt | 18 +++++++++---------
 gqrx.pro       |  8 ++++----
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index fcc33bd..b73dc31 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,17 +6,17 @@ set(${PROJECT_NAME}_MAJOR "2")
 set(${PROJECT_NAME}_MINOR "6")
 set(${PROJECT_NAME}_PATCH "0")
 ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}")
-set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}")
-add_definitions(-DVERSION="${VERSION}")
+##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}")
+##add_definitions(-DVERSION="${VERSION}")
 
 # development version
-#execute_process(
-#    COMMAND git describe --long --dirty
-#    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-#    OUTPUT_VARIABLE GITVERSION
-#    OUTPUT_STRIP_TRAILING_WHITESPACE
-#)
-#add_definitions(-DVERSION="${GITVERSION}")
+execute_process(
+    COMMAND git describe --long --dirty
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+    OUTPUT_VARIABLE GITVERSION
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+add_definitions(-DVERSION="${GITVERSION}")
 
 set(PACKAGE ${PROJECT_NAME})
 
diff --git a/gqrx.pro b/gqrx.pro
index 7431435..897e91d 100644
--- a/gqrx.pro
+++ b/gqrx.pro
@@ -67,14 +67,14 @@ CONFIG(debug, debug|release) {
     #QMAKE_CFLAGS_DEBUG += '-g -O0'
 
     # Define version string (see below for releases)
-    ##VER = $$system(git describe --abbrev=8)
-    VER = 2.6
+    VER = $$system(git describe --abbrev=8)
+    ##VER = 2.6
 
 } else {
     DEFINES += QT_NO_DEBUG
     DEFINES += QT_NO_DEBUG_OUTPUT
-    ##VER = $$system(git describe --abbrev=1)
-    VER = 2.6
+    VER = $$system(git describe --abbrev=1)
+    ##VER = 2.6
 
     # Release binaries with gr bundled
     # QMAKE_RPATH & co won't work with origin

From 82dafcccd3c7330b97064052c3b825a138666a08 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 7 Oct 2016 00:45:10 +0200
Subject: [PATCH 145/334] Update news file.

---
 resources/news.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/resources/news.txt b/resources/news.txt
index ae53d58..a1e9eea 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -1,3 +1,9 @@
+       2.7: TBD...
+
+       NEW: Save remote control state between sessions.
+     FIXED: Keep waterfall zoom level and zoom slider synchronised.
+
+
        2.6: Released October 3, 2016
 
        NEW: 1-2-5 scaling on FFT axis.

From 61521554cb235dda8ea5daf2f8e6cb3e775abce9 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Thu, 6 Oct 2016 08:53:36 +0400
Subject: [PATCH 146/334] Remove duplicate code and magic numbers in remote
 control

---
 src/applications/gqrx/remote_control.cpp      | 26 ++++++++-----------
 src/applications/gqrx/remote_control.h        |  1 -
 .../gqrx/remote_control_settings.ui           |  8 ------
 3 files changed, 11 insertions(+), 24 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 466c0cc..c942f14 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -27,6 +27,9 @@
 #include 
 #include "remote_control.h"
 
+#define DEFAULT_RC_PORT            7356
+#define DEFAULT_RC_ALLOWED_HOSTS   "::ffff:127.0.0.1"
+
 RemoteControl::RemoteControl(QObject *parent) :
     QObject(parent)
 {
@@ -40,8 +43,8 @@ RemoteControl::RemoteControl(QObject *parent) :
     audio_recorder_status = false;
     receiver_running = false;
 
-    rc_port = 7356;
-    rc_allowed_hosts.append("::ffff:127.0.0.1");
+    rc_port = DEFAULT_RC_PORT;
+    rc_allowed_hosts.append(DEFAULT_RC_ALLOWED_HOSTS);
 
     rc_socket = 0;
 
@@ -81,16 +84,12 @@ void RemoteControl::readSettings(QSettings *settings)
     settings->beginGroup("remote_control");
 
     // Get port number; restart server if running
-    rc_port = settings->value("port", 7356).toInt();
-    if (rc_server.isListening())
-    {
-        rc_server.close();
-        rc_server.listen(QHostAddress::Any, rc_port);
-    }
+    if (settings->contains("port"))
+        setPort(settings->value("port").toInt());
 
     // Get list of allowed hosts
     if (settings->contains("allowed_hosts"))
-        rc_allowed_hosts = settings->value("allowed_hosts").toStringList();
+        setHosts(settings->value("allowed_hosts").toStringList());
 
     settings->endGroup();
 }
@@ -107,12 +106,12 @@ void RemoteControl::saveSettings(QSettings *settings) const
     else
         settings->remove("enabled");
 
-    if (rc_port != 7356)
+    if (rc_port != DEFAULT_RC_PORT)
         settings->setValue("port", rc_port);
     else
         settings->remove("port");
 
-    if ((rc_allowed_hosts.count() != 1) || (rc_allowed_hosts.at(0) != "::ffff:127.0.0.1"))
+    if ((rc_allowed_hosts.count() != 1) || (rc_allowed_hosts.at(0) != DEFAULT_RC_ALLOWED_HOSTS))
         settings->setValue("allowed_hosts", rc_allowed_hosts);
     else
         settings->remove("allowed_hosts");
@@ -141,10 +140,7 @@ void RemoteControl::setPort(int port)
 
 void RemoteControl::setHosts(QStringList hosts)
 {
-    rc_allowed_hosts.clear();
-
-    for (int i = 0; i < hosts.count(); i++)
-        rc_allowed_hosts << hosts.at(i);
+    rc_allowed_hosts = hosts;
 }
 
 
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index 8f6e715..0e8233a 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -31,7 +31,6 @@
 #include 
 #include 
 
-
 /*! \brief Simple TCP server for remote control.
  *
  * The TCP interface is compatible with the hamlib rigtctld so that applications
diff --git a/src/applications/gqrx/remote_control_settings.ui b/src/applications/gqrx/remote_control_settings.ui
index de77235..7e545dc 100644
--- a/src/applications/gqrx/remote_control_settings.ui
+++ b/src/applications/gqrx/remote_control_settings.ui
@@ -86,14 +86,6 @@
        
         QListView::Fixed
        
-       
-        
-         ::ffff:127.0.0.1
-        
-        
-         ItemIsSelectable|ItemIsEditable|ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled
-        
-       
       
      
      

From 6520a22cf26ad25eeededa9a6a25e6a8248138f5 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Thu, 6 Oct 2016 09:29:44 +0400
Subject: [PATCH 147/334] Implement 'M ?' in the remote control interface.

---
 resources/remote-control.txt             |  3 ++-
 src/applications/gqrx/remote_control.cpp | 28 ++++++++++++++----------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/resources/remote-control.txt b/resources/remote-control.txt
index 8b2ebdc..a07532d 100644
--- a/resources/remote-control.txt
+++ b/resources/remote-control.txt
@@ -4,7 +4,8 @@ Supported commands:
  f - Get frequency [Hz]
  F - Set frequency [Hz]
  m - Get demodulator mode
- M - Set demodulator mode (OFF, RAW, AM, FM, WFM, WFM_ST, WFM_ST_OIRT, LSB, USB, CW, CWL, CWU)
+ M - Set demodulator mode. Passing a '?' as the first argument instead of 'mode'
+     will return a space separated list of radio backend supported modes.
  l STRENGTH - Get signal strength [dBFS]
  l SQL   - Get squelch threshold [dBFS]
  L SQL  - Set squelch threshold to  [dBFS]
diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index c942f14..e3759ed 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -254,21 +254,27 @@ void RemoteControl::startRead()
     // Mode and filter
     else if (cmdlist[0] == "M")
     {
-        int mode = modeStrToInt(cmdlist.value(1, ""));
-        if (mode == -1)
-        {
-            // invalid string
-            rc_socket->write("RPRT 1\n");
-        }
+        QString cmd_arg = cmdlist.value(1, "");
+        if (cmd_arg == "?")
+            rc_socket->write("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWU\n");
         else
         {
-            rc_socket->write("RPRT 0\n");
-            rc_mode = mode;
+            int mode = modeStrToInt(cmd_arg);
+            if (mode == -1)
+            {
+                // invalid string
+                rc_socket->write("RPRT 1\n");
+            }
+            else
+            {
+                rc_socket->write("RPRT 0\n");
+                rc_mode = mode;
 
-            if (rc_mode == 0)
-                audio_recorder_status = false;
+                if (rc_mode == 0)
+                    audio_recorder_status = false;
 
-            emit newMode(rc_mode);
+                emit newMode(rc_mode);
+            }
         }
     }
     else if (cmdlist[0] == "m")

From b441cb3b9029712b5a5db272fb8f5ce5b3b9b190 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 10 Oct 2016 06:57:05 +0400
Subject: [PATCH 148/334] Reformat remote control help text

---
 resources/remote-control.txt | 48 ++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/resources/remote-control.txt b/resources/remote-control.txt
index a07532d..2012a20 100644
--- a/resources/remote-control.txt
+++ b/resources/remote-control.txt
@@ -1,22 +1,38 @@
 Remote control protocol.
 
 Supported commands:
- f - Get frequency [Hz]
- F - Set frequency [Hz]
- m - Get demodulator mode
- M - Set demodulator mode. Passing a '?' as the first argument instead of 'mode'
-     will return a space separated list of radio backend supported modes.
- l STRENGTH - Get signal strength [dBFS]
- l SQL   - Get squelch threshold [dBFS]
- L SQL  - Set squelch threshold to  [dBFS]
- u RECORD - Get status of audio recorder
- U RECORD  - Set status of audio recorder to 
- c - Close connection
- AOS - Acquisition of signal (AOS) event, start audio recording
- LOS - Loss of signal (LOS) event, stop audio recording
- \dump_state - Dump state (only usable for compatibility)
+ f
+    Get frequency [Hz]
+ F 
+    Set frequency [Hz]
+ m
+    Get demodulator mode
+ M 
+    Set demodulator mode
+    Passing a '?' as the first argument instead of 'mode' will return
+    a space separated list of radio backend supported modes.
+ l STRENGTH
+    Get signal strength [dBFS]
+ l SQL
+    Get squelch threshold [dBFS]
+ L SQL 
+    Set squelch threshold to  [dBFS]
+ u RECORD
+    Get status of audio recorder
+ U RECORD 
+    Set status of audio recorder to 
+ c
+    Close connection
+ AOS
+    Acquisition of signal (AOS) event, start audio recording
+ LOS
+    Loss of signal (LOS) event, stop audio recording
+ \dump_state
+    Dump state (only usable for compatibility)
 
 
 Reply:
- RPRT 0 - Command successful
- RPRT 1 - Command failed
+ RPRT 0
+    Command successful
+ RPRT 1
+    Command failed

From 9a574d05a47fef83f4d87db288434cf2aff7c550 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 10 Oct 2016 09:01:37 +0400
Subject: [PATCH 149/334] Remove duplicate code

ui->plotter->setHiLowCutFrequencies is also called from
on_plotter_newFilterFreq().
---
 src/applications/gqrx/mainwindow.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 3107bb1..3413011 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -2054,7 +2054,6 @@ void MainWindow::onBookmarkActivated(qint64 freq, QString demod, int bandwidth)
     }
 
     on_plotter_newFilterFreq(lo, hi);
-    ui->plotter->setHiLowCutFrequencies(lo, hi);
 }
 
 /** Launch Gqrx google group website. */

From 398036d4c611931d0fd7909a9fc898cafd23f472 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Tue, 11 Oct 2016 08:18:14 +0400
Subject: [PATCH 150/334] Remote control: use a hamlib command 'q|Q' to close
 connection.

The 'c' command is get 'CTCSS Tone' as say manual.
---
 resources/remote-control.txt             | 2 +-
 src/applications/gqrx/remote_control.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/resources/remote-control.txt b/resources/remote-control.txt
index 2012a20..c956a0a 100644
--- a/resources/remote-control.txt
+++ b/resources/remote-control.txt
@@ -21,7 +21,7 @@ Supported commands:
     Get status of audio recorder
  U RECORD 
     Set status of audio recorder to 
- c
+ q|Q
     Close connection
  AOS
     Acquisition of signal (AOS) event, start audio recording
diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index e3759ed..b5c3a3b 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -206,7 +206,7 @@ void RemoteControl::startRead()
     {
         rc_socket->write(QString("%1\n").arg(rc_freq).toLatin1());
     }
-    else if (cmdlist[0] == "c")
+    else if (cmdlist[0] == "q" || cmdlist[0] == "Q")
     {
         // FIXME: for now we assume 'close' command
         rc_socket->close();

From 1b43d33754b63aaf409090d26751719903c4d63a Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Wed, 12 Oct 2016 06:55:59 +0400
Subject: [PATCH 151/334] Added a compatibility mode with hamlib specification
 in remote control.

---
 src/applications/gqrx/remote_control.cpp | 15 ++++++++++++---
 src/applications/gqrx/remote_control.h   |  2 ++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index b5c3a3b..e2a4645 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -42,6 +42,7 @@ RemoteControl::RemoteControl(QObject *parent) :
     squelch_level = -150.0;
     audio_recorder_status = false;
     receiver_running = false;
+    hamlib_compatible = false;
 
     rc_port = DEFAULT_RC_PORT;
     rc_allowed_hosts.append(DEFAULT_RC_ALLOWED_HOSTS);
@@ -256,7 +257,7 @@ void RemoteControl::startRead()
     {
         QString cmd_arg = cmdlist.value(1, "");
         if (cmd_arg == "?")
-            rc_socket->write("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWU\n");
+            rc_socket->write("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWR CWU\n");
         else
         {
             int mode = modeStrToInt(cmd_arg);
@@ -524,14 +525,22 @@ int RemoteControl::modeStrToInt(QString mode_str)
     else if (mode_str.compare("CW", Qt::CaseInsensitive) == 0)
     {
         mode_int = 8;
+        hamlib_compatible = true;
     }
     else if (mode_str.compare("CWL", Qt::CaseInsensitive) == 0)
     {
         mode_int = 8;
+        hamlib_compatible = false;
+    }
+    else if (mode_str.compare("CWR", Qt::CaseInsensitive) == 0)
+    {
+        mode_int = 9;
+        hamlib_compatible = true;
     }
     else if (mode_str.compare("CWU", Qt::CaseInsensitive) == 0)
     {
         mode_int = 9;
+        hamlib_compatible = false;
     }
     else if (mode_str.compare("WFM_ST_OIRT", Qt::CaseInsensitive) == 0)
     {
@@ -584,11 +593,11 @@ QString RemoteControl::intToModeStr(int mode)
         break;
 
     case 8:
-        mode_str = "CWL";
+        mode_str = (hamlib_compatible) ? "CW" : "CWL";
         break;
 
     case 9:
-        mode_str = "CWU";
+        mode_str = (hamlib_compatible) ? "CWR" : "CWU";
         break;
 
     case 10:
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index 0e8233a..910c680 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -121,6 +121,8 @@ private slots:
     void        setNewRemoteFreq(qint64 freq);
     int         modeStrToInt(QString mode_str);
     QString     intToModeStr(int mode);
+
+    bool        hamlib_compatible;
 };
 
 #endif // REMOTE_CONTROL_H

From 38f06530b58a6cdf7976cb13cdaba4d6f7c6309a Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 10 Oct 2016 08:34:42 +0400
Subject: [PATCH 152/334] Add passband parameter to 'M/m' remote command

Fixes #218.
---
 resources/remote-control.txt             |  6 ++---
 src/applications/gqrx/mainwindow.cpp     | 32 ++++++++++++++++++++++++
 src/applications/gqrx/mainwindow.h       |  1 +
 src/applications/gqrx/remote_control.cpp | 20 ++++++++++++---
 src/applications/gqrx/remote_control.h   |  4 +++
 5 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/resources/remote-control.txt b/resources/remote-control.txt
index c956a0a..e8dae22 100644
--- a/resources/remote-control.txt
+++ b/resources/remote-control.txt
@@ -6,9 +6,9 @@ Supported commands:
  F 
     Set frequency [Hz]
  m
-    Get demodulator mode
- M 
-    Set demodulator mode
+    Get demodulator mode and passband
+ M  [passband]
+    Set demodulator mode and passband [Hz]
     Passing a '?' as the first argument instead of 'mode' will return
     a space separated list of radio backend supported modes.
  l STRENGTH
diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 3413011..2fda764 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -267,6 +267,8 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
     connect(uiDockRxOpt, SIGNAL(sqlLevelChanged(double)), remote, SLOT(setSquelchLevel(double)));
     connect(remote, SIGNAL(startAudioRecorderEvent()), uiDockAudio, SLOT(startAudioRecorder()));
     connect(remote, SIGNAL(stopAudioRecorderEvent()), uiDockAudio, SLOT(stopAudioRecorder()));
+    connect(ui->plotter, SIGNAL(newFilterFreq(int, int)), remote, SLOT(setPassband(int, int)));
+    connect(remote, SIGNAL(newPassband(int)), this, SLOT(setPassband(int)));
 
     rds_timer = new QTimer(this);
     connect(rds_timer, SIGNAL(timeout()), this, SLOT(rdsTimeout()));
@@ -1070,6 +1072,8 @@ void MainWindow::selectDemod(int mode_idx)
     rx->set_cw_offset(cwofs);
     rx->set_sql_level(uiDockRxOpt->currentSquelchLevel());
 
+    remote->setPassband(flo, fhi);
+
     d_have_audio = (mode_idx != DockRxOpt::MODE_OFF);
 
     uiDockRxOpt->setCurrentDemod(mode_idx);
@@ -2056,6 +2060,34 @@ void MainWindow::onBookmarkActivated(qint64 freq, QString demod, int bandwidth)
     on_plotter_newFilterFreq(lo, hi);
 }
 
+void MainWindow::setPassband(int bandwidth)
+{
+    /* Check if filter is symmetric or not by checking the presets */
+    int mode = uiDockRxOpt->currentDemod();
+    int preset = uiDockRxOpt->currentFilterShape();
+
+    int lo, hi;
+    uiDockRxOpt->getFilterPreset(mode, preset, &lo, &hi);
+
+    if(lo + hi == 0)
+    {
+        lo = -bandwidth / 2;
+        hi =  bandwidth / 2;
+    }
+    else if(lo >= 0 && hi >= 0)
+    {
+        hi = lo + bandwidth;
+    }
+    else if(lo <= 0 && hi <= 0)
+    {
+        lo = hi - bandwidth;
+    }
+
+    remote->setPassband(lo, hi);
+
+    on_plotter_newFilterFreq(lo, hi);
+}
+
 /** Launch Gqrx google group website. */
 void MainWindow::on_actionUserGroup_triggered()
 {
diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h
index 1b1e4e2..01b23b0 100644
--- a/src/applications/gqrx/mainwindow.h
+++ b/src/applications/gqrx/mainwindow.h
@@ -155,6 +155,7 @@ private slots:
     void setSqlLevel(double level_db);
     double setSqlLevelAuto();
     void setAudioGain(float gain);
+    void setPassband(int bandwidth);
 
     /* audio recording and playback */
     void startAudioRec(const QString filename);
diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index e2a4645..a5731f2 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -268,19 +268,26 @@ void RemoteControl::startRead()
             }
             else
             {
-                rc_socket->write("RPRT 0\n");
                 rc_mode = mode;
+                emit newMode(rc_mode);
+
+                int passband = cmdlist.value(2, "0").toInt();
+                if ( passband != 0 )
+                    emit newPassband(passband);
 
                 if (rc_mode == 0)
                     audio_recorder_status = false;
 
-                emit newMode(rc_mode);
+                rc_socket->write("RPRT 0\n");
             }
         }
     }
     else if (cmdlist[0] == "m")
     {
-        rc_socket->write(QString("%1\n").arg(intToModeStr(rc_mode)).toLatin1());
+        QString msg = QString("%1 %2\n")
+                              .arg(intToModeStr(rc_mode))
+                              .arg(rc_passband_hi - rc_passband_lo);
+        rc_socket->write(msg.toLatin1());
     }
     else if (cmdlist[0] == "U")
     {
@@ -429,6 +436,13 @@ void RemoteControl::setMode(int mode)
         audio_recorder_status = false;
 }
 
+/*! \brief Set passband (from mainwindow). */
+void RemoteControl::setPassband(int passband_lo, int passband_hi)
+{
+    rc_passband_lo = passband_lo;
+    rc_passband_hi = passband_hi;
+}
+
 /*! \brief New remote frequency received. */
 void RemoteControl::setNewRemoteFreq(qint64 freq)
 {
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index 910c680..d82eefd 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -85,6 +85,7 @@ public slots:
     void setBandwidth(qint64 bw);
     void setSignalLevel(float level);
     void setMode(int mode);
+    void setPassband(int passband_lo, int passband_hi);
     void setSquelchLevel(double level);
     void startAudioRecorder(QString unused);
     void stopAudioRecorder();
@@ -93,6 +94,7 @@ public slots:
     void newFrequency(qint64 freq);
     void newFilterOffset(qint64 offset);
     void newMode(int mode);
+    void newPassband(int passband);
     void newSquelchLevel(double level);
     void startAudioRecorderEvent();
     void stopAudioRecorderEvent();
@@ -113,6 +115,8 @@ private slots:
     qint64      bw_half;
 
     int         rc_mode;           /*!< Current mode. */
+    int         rc_passband_lo;    /*!< Current low cutoff. */
+    int         rc_passband_hi;    /*!< Current high cutoff. */
     float       signal_level;      /*!< Signal level in dBFS */
     double      squelch_level;     /*!< Squelch level in dBFS */
     bool        audio_recorder_status; /*!< Recording enabled */

From 66dfaf605fccc9ccfbcf5da8bdbad7372f12be44 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 10 Oct 2016 08:54:36 +0400
Subject: [PATCH 153/334] Avoid setting filter offset to 0 when HW freq is
 changed

Setting filter offset to 0 should be avoided because:
 1. Central frequency may be contain DC spike.
 2. In some cases we have to set HW frequency when it can be avoided.
---
 src/applications/gqrx/remote_control.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index a5731f2..9aaf41d 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -448,18 +448,22 @@ void RemoteControl::setNewRemoteFreq(qint64 freq)
 {
     qint64 delta = freq - rc_freq;
 
-    if (std::abs(rc_filter_offset + delta) < bw_half)
+    rc_filter_offset += delta;
+    if (((rc_filter_offset > 0) && ((rc_filter_offset + rc_passband_hi) < bw_half))
+        || ((rc_filter_offset < 0) && ((rc_filter_offset + rc_passband_lo) > -bw_half)))
     {
         // move filter offset
-        rc_filter_offset += delta;
         emit newFilterOffset(rc_filter_offset);
     }
     else
     {
         // move rx freqeucy and let MainWindow deal with it
         // (will usually change hardware PLL)
-        // reset the filter_offset, otherwise the MainWindo will preserve it
-        rc_filter_offset = 0;
+        // reset the filter_offset, otherwise the MainWindow will preserve it
+        if (rc_filter_offset < 0)
+            rc_filter_offset = bw_half - rc_passband_hi;
+        else
+            rc_filter_offset = -bw_half - rc_passband_lo;
         emit newFilterOffset(rc_filter_offset);
         emit newFrequency(freq);
     }

From 734550d30a6f9a4e2ea87d0779747aa2882c6ef0 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 10 Oct 2016 08:43:02 +0400
Subject: [PATCH 154/334] Set remote mode in selectDemod()

Fixes #433.
---
 src/applications/gqrx/mainwindow.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 2fda764..6d265e7 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -1072,6 +1072,7 @@ void MainWindow::selectDemod(int mode_idx)
     rx->set_cw_offset(cwofs);
     rx->set_sql_level(uiDockRxOpt->currentSquelchLevel());
 
+    remote->setMode(mode_idx);
     remote->setPassband(flo, fhi);
 
     d_have_audio = (mode_idx != DockRxOpt::MODE_OFF);

From d2ca23fbfc0380bfc375e74b85c44af5dd70ce13 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Wed, 19 Oct 2016 23:30:53 +0200
Subject: [PATCH 155/334] Update news.txt

---
 resources/news.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/resources/news.txt b/resources/news.txt
index a1e9eea..8fdba76 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -1,7 +1,9 @@
        2.7: TBD...
 
        NEW: Save remote control state between sessions.
+       NEW: Support for passband when setting mode through remote.
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
+  IMPROVED: Tuning through the remote control interface.
 
 
        2.6: Released October 3, 2016

From 4415307f0d66063ee7e0489420c82cdc30ff5adf Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Thu, 20 Oct 2016 07:07:54 +0400
Subject: [PATCH 156/334] Kept the RDS status if mode WFM.

Fixes #310.
---
 src/applications/gqrx/mainwindow.cpp |  7 +++++--
 src/qtgui/dockrds.cpp                | 14 ++++++++++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 6d265e7..e48954e 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -937,6 +937,7 @@ void MainWindow::selectDemod(int mode_idx)
     float maxdev;
     int filter_preset = uiDockRxOpt->currentFilter();
     int flo=0, fhi=0, click_res=100;
+    bool rds_enabled;
 
     // validate mode_idx
     if (mode_idx < DockRxOpt::MODE_OFF || mode_idx >= DockRxOpt::MODE_LAST)
@@ -949,9 +950,9 @@ void MainWindow::selectDemod(int mode_idx)
     uiDockRxOpt->getFilterPreset(mode_idx, filter_preset, &flo, &fhi);
     d_filter_shape = (receiver::filter_shape)uiDockRxOpt->currentFilterShape();
 
-    if (rx->is_rds_decoder_active())
+    rds_enabled = rx->is_rds_decoder_active();
+    if (rds_enabled)
         setRdsDecoder(false);
-
     uiDockRDS->setDisabled();
 
     switch (mode_idx) {
@@ -1020,6 +1021,8 @@ void MainWindow::selectDemod(int mode_idx)
             rx->set_demod(receiver::RX_DEMOD_WFM_S);
 
         uiDockRDS->setEnabled();
+        if (rds_enabled)
+            setRdsDecoder(true);
         break;
 
     case DockRxOpt::MODE_LSB:
diff --git a/src/qtgui/dockrds.cpp b/src/qtgui/dockrds.cpp
index aacbe0c..797c02a 100644
--- a/src/qtgui/dockrds.cpp
+++ b/src/qtgui/dockrds.cpp
@@ -95,6 +95,20 @@ void DockRDS::updateRDS(QString text, int type)
 
 void DockRDS::showEnabled()
 {
+    ui->program_information->setText("");
+    ui->station_name->setText("");
+    ui->program_type->setText("");
+    ui->flags->setText("");
+    ui->radiotext->setText("");
+    ui->clocktime->setText("");
+    ui->alt_freq->setText("");
+
+    if (!ui->rdsCheckbox->isChecked())
+    {
+        ui->rdsCheckbox->blockSignals(true);
+        ui->rdsCheckbox->setChecked(true);
+        ui->rdsCheckbox->blockSignals(false);
+    }
 }
 
 void DockRDS::showDisabled()

From e0de0da4a0b57b8074c20e4c899dee8d51c1e8e0 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Thu, 20 Oct 2016 09:29:29 +0400
Subject: [PATCH 157/334] Remove duplicate code.

---
 src/qtgui/dockrds.cpp | 14 ++++++--------
 src/qtgui/dockrds.h   |  1 +
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/qtgui/dockrds.cpp b/src/qtgui/dockrds.cpp
index 797c02a..1751bb8 100644
--- a/src/qtgui/dockrds.cpp
+++ b/src/qtgui/dockrds.cpp
@@ -93,7 +93,7 @@ void DockRDS::updateRDS(QString text, int type)
     }
 }
 
-void DockRDS::showEnabled()
+void DockRDS::ClearTextFields()
 {
     ui->program_information->setText("");
     ui->station_name->setText("");
@@ -102,7 +102,11 @@ void DockRDS::showEnabled()
     ui->radiotext->setText("");
     ui->clocktime->setText("");
     ui->alt_freq->setText("");
+}
 
+void DockRDS::showEnabled()
+{
+    ClearTextFields();
     if (!ui->rdsCheckbox->isChecked())
     {
         ui->rdsCheckbox->blockSignals(true);
@@ -113,13 +117,7 @@ void DockRDS::showEnabled()
 
 void DockRDS::showDisabled()
 {
-    ui->program_information->setText("");
-    ui->station_name->setText("");
-    ui->program_type->setText("");
-    ui->flags->setText("");
-    ui->radiotext->setText("");
-    ui->clocktime->setText("");
-    ui->alt_freq->setText("");
+    ClearTextFields();
 }
 
 void DockRDS::setDisabled()
diff --git a/src/qtgui/dockrds.h b/src/qtgui/dockrds.h
index fc67c70..b06f7ee 100644
--- a/src/qtgui/dockrds.h
+++ b/src/qtgui/dockrds.h
@@ -24,6 +24,7 @@ public slots:
     void setDisabled();
 
 private:
+    void ClearTextFields();
 
 signals:
     void rdsDecoderToggled(bool);

From 9bdbaf0e216371a14b5cc3aaa22dac6d435079a5 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Oct 2016 13:17:28 +0200
Subject: [PATCH 158/334] Update news.txt

---
 resources/news.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/news.txt b/resources/news.txt
index 8fdba76..4ef2686 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -3,6 +3,7 @@
        NEW: Save remote control state between sessions.
        NEW: Support for passband when setting mode through remote.
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
+     FIXED: RDS status is not kept while jumping through bookmark,
   IMPROVED: Tuning through the remote control interface.
 
 

From debc33a8ea5b87ee910a7101deeb434ea10e7793 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Oct 2016 13:17:55 +0200
Subject: [PATCH 159/334] Fix typo in news.txt

---
 resources/news.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/resources/news.txt b/resources/news.txt
index 4ef2686..a21597e 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -3,7 +3,7 @@
        NEW: Save remote control state between sessions.
        NEW: Support for passband when setting mode through remote.
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
-     FIXED: RDS status is not kept while jumping through bookmark,
+     FIXED: RDS status is not kept while jumping through bookmark.
   IMPROVED: Tuning through the remote control interface.
 
 

From e6baaee4968345a53e977f593362267a91041cff Mon Sep 17 00:00:00 2001
From: Valentin Ochs 
Date: Fri, 21 Oct 2016 20:12:50 +0200
Subject: [PATCH 160/334] Cosmetic & readability changes

---
 src/qtgui/plotter.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp
index e491632..b877546 100644
--- a/src/qtgui/plotter.cpp
+++ b/src/qtgui/plotter.cpp
@@ -1336,8 +1336,11 @@ void CPlotter::drawOverlay()
 #endif
 
             int level = 0;
-            for (; level < nLevels && tagEnd[level] > x; level++);
-                level %= nLevels;
+            while(level < nLevels && tagEnd[level] > x)
+                level++;
+            
+            if(level == nLevels)
+                level = 0;
 
             tagEnd[level] = x + nameWidth + slant - 1;
             m_BookmarkTags.append(qMakePair(QRect(x, level * levelHeight, nameWidth + slant, fontHeight), bookmarks[i].frequency));

From d803ac646b78d9cce8dcbf6325e5f02c3216cd23 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Mon, 24 Oct 2016 09:08:48 +0400
Subject: [PATCH 161/334] The 'm' command must returns a passband on new line.

Fixes: 38f0653 (Add passband parameter to 'M/m' remote command)
---
 src/applications/gqrx/remote_control.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 9aaf41d..863f120 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -284,7 +284,7 @@ void RemoteControl::startRead()
     }
     else if (cmdlist[0] == "m")
     {
-        QString msg = QString("%1 %2\n")
+        QString msg = QString("%1\n%2\n")
                               .arg(intToModeStr(rc_mode))
                               .arg(rc_passband_hi - rc_passband_lo);
         rc_socket->write(msg.toLatin1());

From 64e35a30d711eeac69774548d61b55346323e88f Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Tue, 25 Oct 2016 10:14:01 +0400
Subject: [PATCH 162/334] Improved '\dump_state' command.

The hamlib uses '\dump_state' to determine the capabilities of the
clients. These changes are necessary for the correct work of hamlib
stuff such as rigctl, fldigi and etc.

Fixes: 5e28ad0 (Add (fake) support for dump_state remote control
command.)
---
 src/applications/gqrx/remote_control.cpp | 108 +++++++++++++++++------
 src/applications/gqrx/remote_control.h   |   4 +-
 2 files changed, 83 insertions(+), 29 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 863f120..efae7ca 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -357,36 +357,10 @@ void RemoteControl::startRead()
         rc_socket->write("RPRT 0\n");
 
     }
-
-    /* dump_state used by some clients, e.g. xdx
-     * For now just some quick hack that works taken from
-     * https://github.com/hexameron/rtl-sdrangelove/blob/master/plugins/channel/tcpsrc/rigctl.cpp
-     *
-     * More info in tests/rigctl_parse.c
-     */
     else if (cmdlist[0] == "\\dump_state")
     {
-        rc_socket->write("0\n"
-                         "2\n"
-                         "1\n"
-                         "150000.000000 30000000.000000  0x900af -1 -1 0x10000003 0x3\n"
-                         "0 0 0 0 0 0 0\n"
-                         "150000.000000 30000000.000000  0x900af -1 -1 0x10000003 0x3\n"
-                         "0 0 0 0 0 0 0\n"
-                         "0 0\n"
-                         "0 0\n"
-                         "0\n"
-                         "0\n"
-                         "0\n"
-                         "0\n"
-                         "\n"
-                         "\n"
-                         "0x0\n"
-                         "0x0\n"
-                         "0x0\n"
-                         "0x0\n"
-                         "0x0\n"
-                         "0\n");
+        QString answer = cmd_dump_state();
+        rc_socket->write(answer.toLatin1());
     }
 
     else
@@ -629,3 +603,81 @@ QString RemoteControl::intToModeStr(int mode)
 
     return mode_str;
 }
+
+/*
+ * '\dump_state' used by hamlib clients, e.g. xdx, fldigi, rigctl and etc
+ * More info:
+ *  https://github.com/N0NB/hamlib/blob/master/include/hamlib/rig.h (bit fields)
+ *  https://github.com/N0NB/hamlib/blob/master/dummy/netrigctl.c
+ */
+QString RemoteControl::cmd_dump_state()
+{
+    return QString(
+        /* rigctl protocol version */
+        "0\n"
+        /* rigctl model */
+        "2\n"
+        /* ITU region */
+        "1\n"
+        /* RX/TX frequency ranges
+         * start, end, modes, low_power, high_power, vfo, ant
+         *  start/end - Start/End frequency [Hz]
+         *  modes - Bit field of RIG_MODE's (AM|CW|CWR|USB|LSB|FM|WFM)
+         *  low_power/high_power - Lower/Higher RF power in mW,
+         *                         -1 for no power (ie. rx list)
+         *  vfo - VFO list equipped with this range (RIG_VFO_A)
+         *  ant - Antenna list equipped with this range, 0 means all
+         *  FIXME: limits can be gets from receiver::get_rf_range()
+         */
+        "0.000000 10000000000.000000 0xef -1 -1 0x1 0x0\n"
+        /* End of RX frequency ranges. */
+        "0 0 0 0 0 0 0\n"
+        /* End of TX frequency ranges. The Gqrx is reciver only. */
+        "0 0 0 0 0 0 0\n"
+        /* Tuning steps: modes, tuning_step */
+        "0xef 1\n"
+        "0xef 0\n"
+        /* End of tuning steps */
+        "0 0\n"
+        /* Filter sizes: modes, width
+         * FIXME: filter can be gets from filter_preset_table
+         */
+        "0x82 500\n"    /* CW | CWR normal */
+        "0x82 200\n"    /* CW | CWR narrow */
+        "0x82 2000\n"   /* CW | CWR wide */
+        "0x21 10000\n"  /* AM | FM normal */
+        "0x21 5000\n"   /* AM | FM narrow */
+        "0x21 20000\n"  /* AM | FM wide */
+        "0x0c 2700\n"   /* SSB normal */
+        "0x0c 1400\n"   /* SSB narrow */
+        "0x0c 3900\n"   /* SSB wide */
+        "0x40 160000\n" /* WFM normal */
+        "0x40 120000\n" /* WFM narrow */
+        "0x40 200000\n" /* WFM wide */
+        /* End of filter sizes  */
+        "0 0\n"
+        /* max_rit  */
+        "0\n"
+        /* max_xit */
+        "0\n"
+        /* max_ifshift */
+        "0\n"
+        /* Announces (bit field list) */
+        "0\n" /* RIG_ANN_NONE */
+        /* Preamp list in dB, 0 terminated */
+        "0\n"
+        /* Attenuator list in dB, 0 terminated */
+        "0\n"
+        /* Bit field list of get functions */
+        "0\n" /* RIG_FUNC_NONE */
+        /* Bit field list of set functions */
+        "0\n" /* RIG_FUNC_NONE */
+        /* Bit field list of get level */
+        "0x40000020\n" /* RIG_LEVEL_SQL | RIG_LEVEL_STRENGTH */
+        /* Bit field list of set level */
+        "0x20\n"       /* RIG_LEVEL_SQL */
+        /* Bit field list of get parm */
+        "0\n" /* RIG_PARM_NONE */
+        /* Bit field list of set parm */
+        "0\n" /* RIG_PARM_NONE */);
+}
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index d82eefd..d482a2b 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -121,12 +121,14 @@ private slots:
     double      squelch_level;     /*!< Squelch level in dBFS */
     bool        audio_recorder_status; /*!< Recording enabled */
     bool        receiver_running;  /*!< Wether the receiver is running or not */
+    bool        hamlib_compatible;
 
     void        setNewRemoteFreq(qint64 freq);
     int         modeStrToInt(QString mode_str);
     QString     intToModeStr(int mode);
 
-    bool        hamlib_compatible;
+    /* RC commands */
+    QString     cmd_dump_state();
 };
 
 #endif // REMOTE_CONTROL_H

From 13970fcc1a613c3a328896a1e72dc8753b1d15f0 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Fri, 28 Oct 2016 07:51:05 +0400
Subject: [PATCH 163/334] Refactoring RemoteControl::startRead().

This function is very large and unclean.
Now one command - one function.
---
 src/applications/gqrx/remote_control.cpp | 389 +++++++++++++----------
 src/applications/gqrx/remote_control.h   |  10 +
 2 files changed, 223 insertions(+), 176 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index efae7ca..68986f7 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -176,8 +176,7 @@ void RemoteControl::startRead()
 {
     char    buffer[1024] = {0};
     int     bytes_read;
-
-    bool ok = true;
+    QString answer = "";
 
     bytes_read = rc_socket->readLine(buffer, 1024);
     if (bytes_read < 2)  // command + '\n'
@@ -188,188 +187,43 @@ void RemoteControl::startRead()
     if (cmdlist.size() == 0)
         return;
 
-    // Set new frequency
-    if (cmdlist[0] == "F")
-    {
-        double freq = cmdlist.value(1, "ERR").toDouble(&ok);
-        if (ok)
-        {
-            setNewRemoteFreq((qint64)freq);
-            rc_socket->write("RPRT 0\n");
-        }
-        else
-        {
-            rc_socket->write("RPRT 1\n");
-        }
-    }
-    // Get frequency
-    else if (cmdlist[0] == "f")
-    {
-        rc_socket->write(QString("%1\n").arg(rc_freq).toLatin1());
-    }
-    else if (cmdlist[0] == "q" || cmdlist[0] == "Q")
+    QString cmd = cmdlist[0];
+    if (cmd == "f")
+        answer = cmd_get_freq();
+    else if (cmd == "F")
+        answer = cmd_set_freq(cmdlist);
+    else if (cmd == "m")
+        answer = cmd_get_mode();
+    else if (cmd == "M")
+        answer = cmd_set_mode(cmdlist);
+    else if (cmd == "l")
+        answer = cmd_get_level(cmdlist);
+    else if (cmd == "L")
+        answer = cmd_set_level(cmdlist);
+    else if (cmd == "u")
+        answer = cmd_get_func(cmdlist);
+    else if (cmd == "U")
+        answer = cmd_set_func(cmdlist);
+    else if (cmd == "AOS")
+        answer = cmd_AOS();
+    else if (cmd == "LOS")
+        answer = cmd_LOS();
+    else if (cmd == "\\dump_state")
+        answer = cmd_dump_state();
+    else if (cmd == "q" || cmd == "Q")
     {
         // FIXME: for now we assume 'close' command
         rc_socket->close();
+        return;
     }
-    // Set level
-    else if (cmdlist[0] == "L")
-    {
-        QString lvl = cmdlist.value(1, "");
-        if (lvl == "?")
-        {
-            rc_socket->write("SQL\n");
-        }
-        else if (lvl.compare("SQL", Qt::CaseInsensitive) == 0)
-        {
-            double squelch = cmdlist.value(2, "ERR").toDouble(&ok);
-            if (ok)
-            {
-                rc_socket->write("RPRT 0\n");
-                squelch_level = std::max(-150, std::min(0, squelch));
-                emit newSquelchLevel(squelch_level);
-            }
-            else
-            {
-                rc_socket->write("RPRT 1\n");
-            }
-        }
-        else
-        {
-            rc_socket->write("RPRT 1\n");
-        }
-    }
-    // Get level
-    else if (cmdlist[0] == "l")
-    {
-        QString lvl = cmdlist.value(1, "");
-        if (lvl == "?")
-            rc_socket->write("SQL STRENGTH\n");
-        else if (lvl.compare("STRENGTH", Qt::CaseInsensitive) == 0 || lvl.isEmpty())
-            rc_socket->write(QString("%1\n").arg(signal_level, 0, 'f', 1).toLatin1());
-        else if (lvl.compare("SQL", Qt::CaseInsensitive) == 0)
-            rc_socket->write(QString("%1\n").arg(squelch_level, 0, 'f', 1).toLatin1());
-        else
-            rc_socket->write("RPRT 1\n");
-    }
-    // Mode and filter
-    else if (cmdlist[0] == "M")
-    {
-        QString cmd_arg = cmdlist.value(1, "");
-        if (cmd_arg == "?")
-            rc_socket->write("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWR CWU\n");
-        else
-        {
-            int mode = modeStrToInt(cmd_arg);
-            if (mode == -1)
-            {
-                // invalid string
-                rc_socket->write("RPRT 1\n");
-            }
-            else
-            {
-                rc_mode = mode;
-                emit newMode(rc_mode);
-
-                int passband = cmdlist.value(2, "0").toInt();
-                if ( passband != 0 )
-                    emit newPassband(passband);
-
-                if (rc_mode == 0)
-                    audio_recorder_status = false;
-
-                rc_socket->write("RPRT 0\n");
-            }
-        }
-    }
-    else if (cmdlist[0] == "m")
-    {
-        QString msg = QString("%1\n%2\n")
-                              .arg(intToModeStr(rc_mode))
-                              .arg(rc_passband_hi - rc_passband_lo);
-        rc_socket->write(msg.toLatin1());
-    }
-    else if (cmdlist[0] == "U")
-    {
-        QString func = cmdlist.value(1, "");
-        bool ok;
-        int status = cmdlist.value(2, "").toInt(&ok);
-
-        if (func == "?")
-        {
-            rc_socket->write("RECORD\n");
-        }
-        else if (func == "" || !ok)
-        {
-            rc_socket->write("RPRT 1\n");
-        }
-        else if (func.compare("RECORD", Qt::CaseInsensitive) == 0)
-        {
-            if (rc_mode == 0 || !receiver_running)
-            {
-                rc_socket->write("RPRT 1\n");
-            }
-            else
-            {
-                rc_socket->write("RPRT 0\n");
-                audio_recorder_status = status;
-                if (status)
-                    emit startAudioRecorderEvent();
-                else
-                    emit stopAudioRecorderEvent();
-            }
-        }
-        else
-        {
-            rc_socket->write("RPRT 1\n");
-        }
-    }
-    else if (cmdlist[0] == "u")
-    {
-        QString func = cmdlist.value(1, "");
-
-        if (func == "?")
-            rc_socket->write("RECORD\n");
-        else if (func.compare("RECORD", Qt::CaseInsensitive) == 0)
-            rc_socket->write(QString("%1\n").arg(audio_recorder_status).toLatin1());
-        else
-            rc_socket->write("RPRT 1\n");
-    }
-
-
-    // Gpredict / Gqrx specific commands:
-    //   AOS  - satellite AOS event
-    //   LOS  - satellite LOS event
-    else if (cmdlist[0] == "AOS")
-    {
-        if (rc_mode > 0 && receiver_running)
-        {
-            emit startAudioRecorderEvent();
-            audio_recorder_status = true;
-        }
-        rc_socket->write("RPRT 0\n");
-
-    }
-    else if (cmdlist[0] == "LOS")
-    {
-        emit stopAudioRecorderEvent();
-        audio_recorder_status = false;
-        rc_socket->write("RPRT 0\n");
-
-    }
-    else if (cmdlist[0] == "\\dump_state")
-    {
-        QString answer = cmd_dump_state();
-        rc_socket->write(answer.toLatin1());
-    }
-
     else
     {
         // print unknown command and respond with an error
-        qWarning() << "Unknown remote command:"
-                << cmdlist;
-        rc_socket->write("RPRT 1\n");
+        qWarning() << "Unknown remote command:" << cmdlist;
+        answer = QString("RPRT 1\n");
     }
+
+    rc_socket->write(answer.toLatin1());
 }
 
 /*! \brief Slot called when the receiver is tuned to a new frequency.
@@ -604,6 +458,189 @@ QString RemoteControl::intToModeStr(int mode)
     return mode_str;
 }
 
+/* Get frequency */
+QString RemoteControl::cmd_get_freq()
+{
+    return QString("%1\n").arg(rc_freq);
+}
+
+/* Set new frequency */
+QString RemoteControl::cmd_set_freq(QStringList cmdlist)
+{
+    bool ok;
+    double freq = cmdlist.value(1, "ERR").toDouble(&ok);
+
+    if (ok)
+    {
+        setNewRemoteFreq((qint64)freq);
+        return QString("RPRT 0\n");
+    }
+
+    return QString("RPRT 1\n");
+}
+
+/* Get mode and passband */
+QString RemoteControl::cmd_get_mode()
+{
+    return QString("%1\n%2\n")
+                   .arg(intToModeStr(rc_mode))
+                   .arg(rc_passband_hi - rc_passband_lo);
+}
+
+/* Set mode and passband */
+QString RemoteControl::cmd_set_mode(QStringList cmdlist)
+{
+    QString answer;
+    QString cmd_arg = cmdlist.value(1, "");
+
+    if (cmd_arg == "?")
+        answer = QString("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWR CWU\n");
+    else
+    {
+        int mode = modeStrToInt(cmd_arg);
+        if (mode == -1)
+        {
+            // invalid mode string
+            answer = QString("RPRT 1\n");
+        }
+        else
+        {
+            rc_mode = mode;
+            emit newMode(rc_mode);
+
+            int passband = cmdlist.value(2, "0").toInt();
+            if ( passband != 0 )
+                emit newPassband(passband);
+
+            if (rc_mode == 0)
+                audio_recorder_status = false;
+
+            answer = QString("RPRT 0\n");
+        }
+    }
+    return answer;
+}
+
+/* Get level */
+QString RemoteControl::cmd_get_level(QStringList cmdlist)
+{
+    QString answer;
+    QString lvl = cmdlist.value(1, "");
+
+    if (lvl == "?")
+       answer = QString("SQL STRENGTH\n");
+    else if (lvl.compare("STRENGTH", Qt::CaseInsensitive) == 0 || lvl.isEmpty())
+       answer = QString("%1\n").arg(signal_level, 0, 'f', 1);
+    else if (lvl.compare("SQL", Qt::CaseInsensitive) == 0)
+       answer = QString("%1\n").arg(squelch_level, 0, 'f', 1);
+    else
+       answer = QString("RPRT 1\n");
+
+    return answer;
+}
+
+/* Set level */
+QString RemoteControl::cmd_set_level(QStringList cmdlist)
+{
+    QString answer;
+    QString lvl = cmdlist.value(1, "");
+
+    if (lvl == "?")
+        answer = QString("SQL\n");
+    else if (lvl.compare("SQL", Qt::CaseInsensitive) == 0)
+    {
+        bool ok;
+        double squelch = cmdlist.value(2, "ERR").toDouble(&ok);
+        if (ok)
+        {
+            answer = QString("RPRT 0\n");
+            squelch_level = std::max(-150, std::min(0, squelch));
+            emit newSquelchLevel(squelch_level);
+        }
+        else
+        {
+            answer = QString("RPRT 1\n");
+        }
+    }
+    else
+    {
+        answer = QString("RPRT 1\n");
+    }
+
+    return answer;
+}
+
+/* Get function */
+QString RemoteControl::cmd_get_func(QStringList cmdlist)
+{
+    QString answer;
+    QString func = cmdlist.value(1, "");
+
+    if (func == "?")
+        answer = QString("RECORD\n");
+    else if (func.compare("RECORD", Qt::CaseInsensitive) == 0)
+        answer = QString("%1\n").arg(audio_recorder_status);
+    else
+        answer = QString("RPRT 1\n");
+
+    return answer;
+}
+
+/* Set function */
+QString RemoteControl::cmd_set_func(QStringList cmdlist)
+{
+    bool ok;
+    QString answer;
+    QString func = cmdlist.value(1, "");
+    int     status = cmdlist.value(2, "ERR").toInt(&ok);
+
+    if (func == "?")
+    {
+        answer = QString("RECORD\n");
+    }
+    else if ((func.compare("RECORD", Qt::CaseInsensitive) == 0) && ok)
+    {
+        if (rc_mode == 0 || !receiver_running)
+        {
+            answer = QString("RPRT 1\n");
+        }
+        else
+        {
+            answer = QString("RPRT 0\n");
+            audio_recorder_status = status;
+            if (status)
+                emit startAudioRecorderEvent();
+            else
+                emit stopAudioRecorderEvent();
+        }
+    }
+    else
+    {
+        answer = QString("RPRT 1\n");
+    }
+
+    return answer;
+}
+
+/* Gpredict / Gqrx specific command: AOS - satellite AOS event */
+QString RemoteControl::cmd_AOS()
+{
+    if (rc_mode > 0 && receiver_running)
+    {
+        emit startAudioRecorderEvent();
+        audio_recorder_status = true;
+    }
+    return QString("RPRT 0\n");
+}
+
+/* Gpredict / Gqrx specific command: LOS - satellite LOS event */
+QString RemoteControl::cmd_LOS()
+{
+    emit stopAudioRecorderEvent();
+    audio_recorder_status = false;
+    return QString("RPRT 0\n");
+}
+
 /*
  * '\dump_state' used by hamlib clients, e.g. xdx, fldigi, rigctl and etc
  * More info:
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index d482a2b..5b875d6 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -128,6 +128,16 @@ private slots:
     QString     intToModeStr(int mode);
 
     /* RC commands */
+    QString     cmd_get_freq();
+    QString     cmd_set_freq(QStringList cmdlist);
+    QString     cmd_get_mode();
+    QString     cmd_set_mode(QStringList cmdlist);
+    QString     cmd_get_level(QStringList cmdlist);
+    QString     cmd_set_level(QStringList cmdlist);
+    QString     cmd_get_func(QStringList cmdlist);
+    QString     cmd_set_func(QStringList cmdlist);
+    QString     cmd_AOS();
+    QString     cmd_LOS();
     QString     cmd_dump_state();
 };
 

From 97db8e41cd0cc8b793af7775a03872cca4be7aed Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Fri, 18 Nov 2016 10:14:11 +0400
Subject: [PATCH 164/334] Add .travis.yml for Travis CI
 (http://travis-ci.org/).

Fixes #451.
---
 .travis.yml | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 .travis.yml

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..13c3718
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,28 @@
+sudo: required
+
+dist: trusty
+
+language: cpp
+
+compiler:
+  - gcc
+  - clang
+
+env:
+  - AUDIO_BACKEND="Pulseaudio"
+  - AUDIO_BACKEND="Portaudio"
+  - AUDIO_BACKEND="Gr-audio"
+
+before_install:
+  - sudo add-apt-repository -y ppa:bladerf/bladerf
+  - sudo add-apt-repository -y ppa:ettusresearch/uhd
+  - sudo add-apt-repository -y ppa:myriadrf/drivers
+  - sudo add-apt-repository -y ppa:myriadrf/gnuradio
+  - sudo apt-get update -qq
+  - sudo apt-get install -y cmake qt5-default libqt5svg5-dev libboost-dev libpulse-dev portaudio19-dev liblog4cpp5-dev gnuradio-dev gr-osmosdr gr-fcdproplus
+
+script:
+  - mkdir build
+  - cd build
+  - cmake -DLINUX_AUDIO_BACKEND:STRING=$AUDIO_BACKEND ..
+  - make

From 8d28a1645526afc2f326ab1185f1a39279179b66 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Tue, 22 Nov 2016 16:10:01 +0100
Subject: [PATCH 165/334] Add links to GNU Radio qnd Qt websites

---
 README.md | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 35e13b8..48b3003 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,10 @@ Gqrx
 ====
 
 Gqrx is an open source software defined radio (SDR) receiver implemented using
-GNU Radio and the Qt GUI toolkit. Currently it works on Linux and Mac with
-hardware supported by gr-osmosdr, including Funcube Dongle, RTL-SDR, Airspy,
-HackRF, BladeRF, RFSpace, USRP and SoapySDR.
+[GNU Radio](http://gnuradio.org) and the [Qt GUI toolkit](https://www.qt.io/).
+Currently it works on Linux and Mac with hardware supported by gr-osmosdr,
+including Funcube Dongle, RTL-SDR, Airspy, HackRF, BladeRF, RFSpace, USRP and
+SoapySDR.
 
 Gqrx can operate as an AM/FM/SSB receiver with audio output or as an FFT-only
 instrument. There are also various hooks for interacting with external

From 53e5269cb7999ac38d5a488c598f8a5a9597f981 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Pinkava?= 
Date: Wed, 28 Dec 2016 02:31:33 +0100
Subject: [PATCH 166/334] Replace deprecated mpsk_receiver by
 constellation_receiver

---
 src/dsp/rx_rds.cpp | 21 ++++++++-------------
 src/dsp/rx_rds.h   |  9 ++-------
 2 files changed, 10 insertions(+), 20 deletions(-)

diff --git a/src/dsp/rx_rds.cpp b/src/dsp/rx_rds.cpp
index c18e4fd..895ab93 100644
--- a/src/dsp/rx_rds.cpp
+++ b/src/dsp/rx_rds.cpp
@@ -25,8 +25,7 @@
 #include 
 #include 
 #include 
-#include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -57,19 +56,17 @@ rx_rds::rx_rds(double sample_rate)
                       gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (char))),
       d_sample_rate(sample_rate)
 {
+    const int decimation = d_sample_rate / 2375;
+
     d_taps2 = gr::filter::firdes::low_pass(2500.0, d_sample_rate, 2400, 2000);
 
-    f_fxff = gr::filter::freq_xlating_fir_filter_fcf::make(5.0, d_taps2, 57000, d_sample_rate);
+    f_fxff = gr::filter::freq_xlating_fir_filter_fcf::make(decimation, d_taps2, 57000, d_sample_rate);
 
-    f_rrcf = gr::filter::firdes::root_raised_cosine(1, sample_rate/5, 2375, 1, 100);
+    f_rrcf = gr::filter::firdes::root_raised_cosine(1, sample_rate/decimation, 2375, 1, 100);
     d_bpf2 = gr::filter::fir_filter_ccf::make(1, f_rrcf);
 
-    d_mpsk = gr::digital::mpsk_receiver_cc::make(2, 0, 1*M_PI/100.0, -0.06, 0.06, 0.5, 0.05, sample_rate/5/2375.0, 0.001, 0.005);
-
-
-    b_ctr = gr::blocks::complex_to_real::make(1);
-
-    d_bs = gr::digital::binary_slicer_fb::make();
+    gr::digital::constellation_sptr p_c = gr::digital::constellation_bpsk::make()->base();
+    d_mpsk = gr::digital::constellation_receiver_cb::make(p_c, 1*M_PI/100.0, -0.06, 0.06);
 
     b_koin = gr::blocks::keep_one_in_n::make(sizeof(unsigned char), 2);
 
@@ -82,9 +79,7 @@ rx_rds::rx_rds(double sample_rate)
     connect(self(), 0, f_fxff, 0);
     connect(f_fxff, 0, d_bpf2, 0);
     connect(d_bpf2, 0, d_mpsk, 0);
-    connect(d_mpsk, 0, b_ctr, 0);
-    connect(b_ctr, 0, d_bs, 0);
-    connect(d_bs, 0, b_koin, 0);
+    connect(d_mpsk, 0, b_koin, 0);
     connect(b_koin, 0, d_ddbb, 0);
     connect(d_ddbb, 0, self(), 0);
 }
diff --git a/src/dsp/rx_rds.h b/src/dsp/rx_rds.h
index 219453e..17e406a 100644
--- a/src/dsp/rx_rds.h
+++ b/src/dsp/rx_rds.h
@@ -28,12 +28,9 @@
 #include 
 #include 
 #include 
-#include 
 #include 
-#include 
-#include 
+#include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -86,9 +83,7 @@ class rx_rds : public gr::hier_block2
     gr::filter::freq_xlating_fir_filter_fcf::sptr f_fxff;
     gr::filter::freq_xlating_fir_filter_ccf::sptr f_fxff_ccf;
     std::vector f_rrcf;
-    gr::digital::mpsk_receiver_cc::sptr d_mpsk;
-    gr::blocks::complex_to_real::sptr b_ctr;
-    gr::digital::binary_slicer_fb::sptr d_bs;
+    gr::digital::constellation_receiver_cb::sptr d_mpsk;
     gr::blocks::keep_one_in_n::sptr b_koin;
     gr::digital::diff_decoder_bb::sptr d_ddbb;
     gr::rds::decoder::sptr rds_decoder;

From 5a9e04d432f0c9c34424fc0cb553749a4dbfcb7d Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 5 Jan 2017 22:23:59 +0100
Subject: [PATCH 167/334] Restore FM max deviation between sessions

---
 src/qtgui/demod_options.cpp | 77 ++++++++++++++++++++++++-------------
 src/qtgui/demod_options.h   |  3 ++
 src/qtgui/dockrxopt.cpp     | 17 +++++---
 3 files changed, 65 insertions(+), 32 deletions(-)

diff --git a/src/qtgui/demod_options.cpp b/src/qtgui/demod_options.cpp
index d693928..c454d04 100644
--- a/src/qtgui/demod_options.cpp
+++ b/src/qtgui/demod_options.cpp
@@ -24,6 +24,46 @@
 #include "demod_options.h"
 #include "ui_demod_options.h"
 
+
+float maxdev_from_index(int index)
+{
+    switch(index)
+    {
+    case 0:
+        /* Voice 2.5k */
+        return 2500.0;
+    case 1:
+        /* Voice 5k */
+        return 5000.0;
+    case 2:
+        /* APT 25k (17k but need some margin for Doppler and freq error) */
+        return 25000.0;
+    case 3:
+        /* Broadcast FM 75k */
+        return 75000.0;
+    default:
+        /* Voice 5k */
+        qDebug() << "Invalid max_dev index: " << index;
+        return 5000.0;
+    }
+}
+
+int maxdev_to_index(float max_dev)
+{
+    if (max_dev < 3000.0)
+        /* Voice 2.5k */
+        return 0;
+    else if (max_dev < 10000.0)
+        /* Voice 5k */
+        return 1;
+    else if (max_dev < 40000.0)
+        /* APT 25k (17k nominally) */
+        return 2;
+    else
+        /* Broadcast FM 75k */
+        return 3;
+}
+
 CDemodOptions::CDemodOptions(QWidget *parent) :
     QDialog(parent),
     ui(new Ui::CDemodOptions)
@@ -70,36 +110,19 @@ int  CDemodOptions::getCwOffset(void) const
     return ui->cwOffsetSpin->value();
 }
 
-void CDemodOptions::on_maxdevSelector_activated(int index)
+void CDemodOptions::setMaxDev(float max_dev)
 {
-    float max_dev;
+    ui->maxdevSelector->setCurrentIndex(maxdev_to_index(max_dev));
+}
 
-    switch(index)
-    {
-    case 0:
-        /* Voice 2.5k */
-        max_dev = 2500.0;
-        break;
-    case 1:
-        /* Voice 5k */
-        max_dev = 5000.0;
-        break;
-    case 2:
-        /* APT 25k (17k but need some margin for Doppler and freq error) */
-        max_dev = 25000.0;
-        break;
-    case 3:
-        /* Broadcast FM 75k */
-        max_dev = 75000.0;
-        break;
-    default:
-        /* Voice 5k */
-        qDebug() << "Invalid max_dev index: " << index;
-        max_dev = 5000.0;
-        break;
-    }
+float CDemodOptions::getMaxDev(void) const
+{
+    return maxdev_from_index(ui->maxdevSelector->currentIndex());
+}
 
-    emit fmMaxdevSelected(max_dev);
+void CDemodOptions::on_maxdevSelector_activated(int index)
+{
+    emit fmMaxdevSelected(maxdev_from_index(index));
 }
 
 void CDemodOptions::on_emphSelector_activated(int index)
diff --git a/src/qtgui/demod_options.h b/src/qtgui/demod_options.h
index 8376d1c..f1cf74e 100644
--- a/src/qtgui/demod_options.h
+++ b/src/qtgui/demod_options.h
@@ -60,6 +60,9 @@ class CDemodOptions : public QDialog
     void setCwOffset(int offset);
     int  getCwOffset(void) const;
 
+    void setMaxDev(float max_dev);
+    float getMaxDev(void) const;
+
 signals:
     /*! \brief Signal emitted when new FM deviation is selected. */
     void fmMaxdevSelected(float max_dev);
diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 75be118..5f646d8 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -238,7 +238,6 @@ int  DockRxOpt::currentFilterShape()
     return ui->filterShapeCombo->currentIndex();
 }
 
-
 /**
  * @brief Select new demodulator.
  * @param demod Demodulator index corresponding to receiver::demod.
@@ -252,7 +251,6 @@ void DockRxOpt::setCurrentDemod(int demod)
     }
 }
 
-
 /**
  * @brief Get current demodulator selection.
  * @return The current demodulator corresponding to receiver::demod.
@@ -269,11 +267,9 @@ QString DockRxOpt::currentDemodAsString()
 
 float DockRxOpt::currentMaxdev()
 {
-    qDebug() << __FILE__ << __FUNCTION__ << "FIXME";
-    return 5000.0;
+    return demodOpt->getMaxDev();
 }
 
-
 /**
  * @brief Set squelch level.
  * @param level Squelch level in dBFS
@@ -333,6 +329,10 @@ void DockRxOpt::readSettings(QSettings *settings)
     if (conv_ok)
         demodOpt->setCwOffset(int_val);
 
+    int_val = settings->value("receiver/fm_maxdev", 2500).toInt(&conv_ok);
+    if (conv_ok)
+        demodOpt->setMaxDev(int_val);
+
     qint64 offs = settings->value("receiver/offset", 0).toInt(&conv_ok);
     if (offs)
     {
@@ -390,6 +390,13 @@ void DockRxOpt::saveSettings(QSettings *settings)
     else
         settings->setValue("receiver/cwoffset", cwofs);
 
+    // currently we do not need the decimal
+    int_val = (int)demodOpt->getMaxDev();
+    if (int_val == 2500)
+        settings->remove("receiver/fm_maxdev");
+    else
+        settings->setValue("receiver/fm_maxdev", int_val);
+
     qint64 offs = ui->filterFreq->getFrequency();
     if (offs)
         settings->setValue("receiver/offset", offs);

From e7b7fe00ce62f1b6edb7507edd3acd0439531400 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 5 Jan 2017 22:26:11 +0100
Subject: [PATCH 168/334] Defer reading receiver/demod till the end

This ensures that any demod options that may be read when the
demodulator is changed are already initialized to their stored value.
---
 src/qtgui/dockrxopt.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 5f646d8..2c09971 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -318,13 +318,6 @@ void DockRxOpt::readSettings(QSettings *settings)
     int     int_val;
     double  dbl_val;
 
-    int_val = settings->value("receiver/demod", 0).toInt(&conv_ok);
-    if (int_val >= 0)
-    {
-        setCurrentDemod(int_val);
-        emit demodSelected(int_val);
-    }
-
     int_val = settings->value("receiver/cwoffset", 700).toInt(&conv_ok);
     if (conv_ok)
         demodOpt->setCwOffset(int_val);
@@ -375,6 +368,13 @@ void DockRxOpt::readSettings(QSettings *settings)
 
     if (settings->value("receiver/agc_off", false).toBool())
         ui->agcPresetCombo->setCurrentIndex(4);
+
+    int_val = settings->value("receiver/demod", 0).toInt(&conv_ok);
+    if (int_val >= 0)
+    {
+        setCurrentDemod(int_val);
+        emit demodSelected(int_val);
+    }
 }
 
 /** Save receiver configuration to settings. */

From afb146986037a5f82bf2fc211f342bbb72f1af28 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 00:13:54 +0100
Subject: [PATCH 169/334] Ensure maxdev is applied when NFM is selected

---
 src/applications/gqrx/mainwindow.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index e48954e..ecf9549 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -998,6 +998,7 @@ void MainWindow::selectDemod(int mode_idx)
             ui->plotter->setDemodRanges(-45000, -1000, 1000, 45000, true);
             uiDockAudio->setFftRange(0,24000);
         }
+        rx->set_fm_maxdev(maxdev);
         break;
 
     case DockRxOpt::MODE_WFM_MONO:

From d9b25f889592717739443a5a2e960cdf05f0975c Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 00:22:38 +0100
Subject: [PATCH 170/334] Use const getters where possible

---
 src/qtgui/dockrxopt.cpp | 10 +++++-----
 src/qtgui/dockrxopt.h   | 10 +++++-----
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 2c09971..3f69ce9 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -222,7 +222,7 @@ void DockRxOpt::setCurrentFilter(int index)
  * @brief Get current filter preset.
  * @param The current filter preset (0=wide, 1=normal, 2=narrow).
  */
-int  DockRxOpt::currentFilter()
+int  DockRxOpt::currentFilter() const
 {
     return ui->filterCombo->currentIndex();
 }
@@ -233,7 +233,7 @@ void DockRxOpt::setCurrentFilterShape(int index)
     ui->filterShapeCombo->setCurrentIndex(index);
 }
 
-int  DockRxOpt::currentFilterShape()
+int  DockRxOpt::currentFilterShape() const
 {
     return ui->filterShapeCombo->currentIndex();
 }
@@ -255,7 +255,7 @@ void DockRxOpt::setCurrentDemod(int demod)
  * @brief Get current demodulator selection.
  * @return The current demodulator corresponding to receiver::demod.
  */
-int  DockRxOpt::currentDemod()
+int  DockRxOpt::currentDemod() const
 {
     return ui->modeSelector->currentIndex();
 }
@@ -265,7 +265,7 @@ QString DockRxOpt::currentDemodAsString()
     return GetStringForModulationIndex(currentDemod());
 }
 
-float DockRxOpt::currentMaxdev()
+float DockRxOpt::currentMaxdev() const
 {
     return demodOpt->getMaxDev();
 }
@@ -283,7 +283,7 @@ void DockRxOpt::setSquelchLevel(double level)
  * @brief Get the current squelch level
  * @returns The current squelch setting in dBFS
  */
-double DockRxOpt::currentSquelchLevel()
+double DockRxOpt::currentSquelchLevel() const
 {
     return ui->sqlSpinBox->value();
 }
diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h
index 787dd3b..7a26013 100644
--- a/src/qtgui/dockrxopt.h
+++ b/src/qtgui/dockrxopt.h
@@ -88,19 +88,19 @@ class DockRxOpt : public QDockWidget
 
     void setFilterParam(int lo, int hi);
     void setCurrentFilter(int index);
-    int  currentFilter();
+    int  currentFilter() const;
 
     void setCurrentFilterShape(int index);
-    int  currentFilterShape();
+    int  currentFilterShape() const;
 
     void setHwFreq(qint64 freq_hz);
 
-    int  currentDemod();
+    int  currentDemod() const;
     QString currentDemodAsString();
 
-    float currentMaxdev();
+    float currentMaxdev() const;
 
-    double currentSquelchLevel();
+    double currentSquelchLevel() const;
 
     void    getFilterPreset(int mode, int preset, int * lo, int * hi) const;
     int     getCwOffset() const;

From 86147c5d3bdff50ca964783e71dd9371873fff4b Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 00:25:49 +0100
Subject: [PATCH 171/334] Ensure de-emphasis is applied when NFM is selected

---
 src/applications/gqrx/mainwindow.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index ecf9549..7a021eb 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -999,6 +999,7 @@ void MainWindow::selectDemod(int mode_idx)
             uiDockAudio->setFftRange(0,24000);
         }
         rx->set_fm_maxdev(maxdev);
+        rx->set_fm_deemph(uiDockRxOpt->currentEmph());
         break;
 
     case DockRxOpt::MODE_WFM_MONO:

From 52dd3daac558598d60e1d1e1640449bd17823504 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 00:54:07 +0100
Subject: [PATCH 172/334] Restore FM de-emphasis between sessions

---
 src/qtgui/demod_options.cpp | 47 +++++++++++++++++++++++++++++--------
 src/qtgui/demod_options.h   |  3 +++
 src/qtgui/dockrxopt.cpp     | 16 +++++++++++++
 src/qtgui/dockrxopt.h       |  2 +-
 4 files changed, 57 insertions(+), 11 deletions(-)

diff --git a/src/qtgui/demod_options.cpp b/src/qtgui/demod_options.cpp
index c454d04..2992c32 100644
--- a/src/qtgui/demod_options.cpp
+++ b/src/qtgui/demod_options.cpp
@@ -25,6 +25,32 @@
 #include "ui_demod_options.h"
 
 
+/* convert between deemphasis time constant and combo-index */
+const double tau_tbl[] = {
+    0.0, 25.0e-6, 50.0e-6, 75.0e-6, 100.0e-6, 250.0e-6, 530.0e-6, 1.0e-3
+};
+const int tau_tbl_maxidx = 7;
+
+double tau_from_index(int index)
+{
+    if (index < 0 or index > tau_tbl_maxidx)
+        return 0.0;
+
+    return tau_tbl[index];
+}
+
+int tau_to_index(double tau)
+{
+    int i;
+    for (i = 0; i < tau_tbl_maxidx; i++)
+    {
+        if (tau < (tau_tbl[i] + 0.5 * (tau_tbl[i+1] - tau_tbl[i])))
+            return i;
+    }
+    return 0;
+}
+
+/* convert betweenFM max dev and combo index */
 float maxdev_from_index(int index)
 {
     switch(index)
@@ -120,6 +146,16 @@ float CDemodOptions::getMaxDev(void) const
     return maxdev_from_index(ui->maxdevSelector->currentIndex());
 }
 
+void CDemodOptions::setEmph(double tau)
+{
+    ui->emphSelector->setCurrentIndex((tau_to_index(tau)));
+}
+
+double CDemodOptions::getEmph(void) const
+{
+    return tau_from_index(ui->emphSelector->currentIndex());
+}
+
 void CDemodOptions::on_maxdevSelector_activated(int index)
 {
     emit fmMaxdevSelected(maxdev_from_index(index));
@@ -127,16 +163,7 @@ void CDemodOptions::on_maxdevSelector_activated(int index)
 
 void CDemodOptions::on_emphSelector_activated(int index)
 {
-    double tau_tbl[] = {0.0, 25.0, 50.0, 75.0, 100.0, 250.0, 530.0, 1000.0};
-    double tau;
-
-    if ((index < 0) || (index > 7)) {
-        qDebug() << "Invalid tau selection index: " << index;
-        return;
-    }
-
-    tau = tau_tbl[index] * 1.0e-6;
-    emit fmEmphSelected(tau);
+    emit fmEmphSelected(tau_from_index(index));
 }
 
 void CDemodOptions::on_dcrCheckBox_toggled(bool checked)
diff --git a/src/qtgui/demod_options.h b/src/qtgui/demod_options.h
index f1cf74e..d9324db 100644
--- a/src/qtgui/demod_options.h
+++ b/src/qtgui/demod_options.h
@@ -63,6 +63,9 @@ class CDemodOptions : public QDialog
     void setMaxDev(float max_dev);
     float getMaxDev(void) const;
 
+    void setEmph(double tau);
+    double getEmph(void) const;
+
 signals:
     /*! \brief Signal emitted when new FM deviation is selected. */
     void fmMaxdevSelected(float max_dev);
diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 3f69ce9..75fe3f8 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -270,6 +270,11 @@ float DockRxOpt::currentMaxdev() const
     return demodOpt->getMaxDev();
 }
 
+double DockRxOpt::currentEmph() const
+{
+    return demodOpt->getEmph();
+}
+
 /**
  * @brief Set squelch level.
  * @param level Squelch level in dBFS
@@ -326,6 +331,10 @@ void DockRxOpt::readSettings(QSettings *settings)
     if (conv_ok)
         demodOpt->setMaxDev(int_val);
 
+    dbl_val = settings->value("receiver/fm_deemph", 75).toDouble(&conv_ok);
+    if (conv_ok && dbl_val >= 0)
+        demodOpt->setEmph(1.0e-6 * dbl_val); // was stored as usec
+
     qint64 offs = settings->value("receiver/offset", 0).toInt(&conv_ok);
     if (offs)
     {
@@ -397,6 +406,13 @@ void DockRxOpt::saveSettings(QSettings *settings)
     else
         settings->setValue("receiver/fm_maxdev", int_val);
 
+    // save as usec
+    int_val = (int)(1.0e6 * demodOpt->getEmph());
+    if (int_val == 75)
+        settings->remove("receiver/fm_deemph");
+    else
+        settings->setValue("receiver/fm_deemph", int_val);
+
     qint64 offs = ui->filterFreq->getFrequency();
     if (offs)
         settings->setValue("receiver/offset", offs);
diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h
index 7a26013..3564992 100644
--- a/src/qtgui/dockrxopt.h
+++ b/src/qtgui/dockrxopt.h
@@ -99,7 +99,7 @@ class DockRxOpt : public QDockWidget
     QString currentDemodAsString();
 
     float currentMaxdev() const;
-
+    double currentEmph() const;
     double currentSquelchLevel() const;
 
     void    getFilterPreset(int mode, int preset, int * lo, int * hi) const;

From 63f6e526198c7161ba1e4f4fe3f7a5b22a448e37 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 07:48:32 +0100
Subject: [PATCH 173/334] Add both 17 and 25 kHz deviations for APT use

Issue #459.
---
 src/qtgui/demod_options.cpp | 14 ++++++++++----
 src/qtgui/demod_options.ui  |  7 ++++++-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/qtgui/demod_options.cpp b/src/qtgui/demod_options.cpp
index 2992c32..f831f4a 100644
--- a/src/qtgui/demod_options.cpp
+++ b/src/qtgui/demod_options.cpp
@@ -62,9 +62,12 @@ float maxdev_from_index(int index)
         /* Voice 5k */
         return 5000.0;
     case 2:
+        /* APT 17k */
+        return 17000.0;
+    case 3:
         /* APT 25k (17k but need some margin for Doppler and freq error) */
         return 25000.0;
-    case 3:
+    case 4:
         /* Broadcast FM 75k */
         return 75000.0;
     default:
@@ -82,12 +85,15 @@ int maxdev_to_index(float max_dev)
     else if (max_dev < 10000.0)
         /* Voice 5k */
         return 1;
-    else if (max_dev < 40000.0)
-        /* APT 25k (17k nominally) */
+    else if (max_dev < 20000.0)
+        /* APT 17k */
         return 2;
+    else if (max_dev < 40000.0)
+        /* APT 25k */
+        return 3;
     else
         /* Broadcast FM 75k */
-        return 3;
+        return 4;
 }
 
 CDemodOptions::CDemodOptions(QWidget *parent) :
diff --git a/src/qtgui/demod_options.ui b/src/qtgui/demod_options.ui
index 5147b6f..8551310 100644
--- a/src/qtgui/demod_options.ui
+++ b/src/qtgui/demod_options.ui
@@ -6,7 +6,7 @@
    
     0
     0
-    223
+    228
     110
    
   
@@ -112,6 +112,11 @@ this demodulator
              Voice (5 kHz)
             
            
+           
+            
+             APT (17 kHz)
+            
+           
            
             
              APT (25 kHz)

From d842ad821559d54245d7e619bdeaabe867e2a369 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 18:22:12 +0100
Subject: [PATCH 174/334] Remove unused class member

---
 src/dsp/rx_demod_fm.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/dsp/rx_demod_fm.h b/src/dsp/rx_demod_fm.h
index 0d0211e..0cc9c4f 100644
--- a/src/dsp/rx_demod_fm.h
+++ b/src/dsp/rx_demod_fm.h
@@ -26,7 +26,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 
 class rx_demod_fm;
@@ -65,7 +64,6 @@ class rx_demod_fm : public gr::hier_block2
     /* GR blocks */
     gr::analog::quadrature_demod_cf::sptr   d_quad;      /*! The quadrature demodulator block. */
     gr::filter::iir_filter_ffd::sptr        d_deemph;    /*! De-emphasis IIR filter. */
-    gr::filter::pfb_arb_resampler_ccf::sptr d_resampler; /*! PFB resampler. */
     std::vector            d_taps;      /*! Taps for the PFB resampler. */
 
     /* other parameters */

From 09101bdb177e03bf473d400ae4c96e6aedabad29 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 6 Jan 2017 21:52:28 +0100
Subject: [PATCH 175/334] Minor style cleanup

---
 src/dsp/rx_demod_fm.cpp | 33 ++++++++++++++++++++-------------
 src/dsp/rx_demod_fm.h   | 15 ++++++---------
 2 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/src/dsp/rx_demod_fm.cpp b/src/dsp/rx_demod_fm.cpp
index 507e356..ae7ce3b 100644
--- a/src/dsp/rx_demod_fm.cpp
+++ b/src/dsp/rx_demod_fm.cpp
@@ -20,11 +20,12 @@
  * the Free Software Foundation, Inc., 51 Franklin Street,
  * Boston, MA 02110-1301, USA.
  */
-#include 
 #include 
-#include 
-#include 
+#include 
 #include 
+#include 
+
+#include "dsp/rx_demod_fm.h"
 
 
 /* Create a new instance of rx_demod_fm and return a boost shared_ptr. */
@@ -67,11 +68,13 @@ rx_demod_fm::rx_demod_fm(float quad_rate, float audio_rate, float max_dev, doubl
 
     /* connect block */
     connect(self(), 0, d_quad, 0);
-    if (d_tau > 1.0e-9) {
+    if (d_tau > 1.0e-9)
+    {
         connect(d_quad, 0, d_deemph, 0);
         connect(d_deemph, 0, self(), 0);
     }
-    else {
+    else
+    {
         connect(d_quad, 0, self(), 0);
     }
 
@@ -93,7 +96,8 @@ void rx_demod_fm::set_max_dev(float max_dev)
 {
     float gain;
 
-    if ((max_dev < 500.0) || (max_dev > d_quad_rate/2.0)) {
+    if ((max_dev < 500.0) || (max_dev > d_quad_rate/2.0))
+    {
         return;
     }
 
@@ -111,17 +115,20 @@ void rx_demod_fm::set_max_dev(float max_dev)
  */
 void rx_demod_fm::set_tau(double tau)
 {
-    if (fabs(tau - d_tau) < 1.0e-9) {
+    if (fabs(tau - d_tau) < 1.0e-9)
+    {
         /* no change */
         return;
     }
 
-    if (tau > 1.0e-9) {
+    if (tau > 1.0e-9)
+    {
         calculate_iir_taps(tau);
         d_deemph->set_taps(d_fftaps, d_fbtaps);
 
         /* check to see if we need to rewire flow graph */
-        if (d_tau <= 1.0e-9) {
+        if (d_tau <= 1.0e-9)
+        {
             /* need to put deemph into the flowgraph */
             lock();
             disconnect(d_quad, 0, self(), 0);
@@ -132,12 +139,14 @@ void rx_demod_fm::set_tau(double tau)
 
         d_tau = tau;
     }
-    else {
+    else
+    {
 #ifndef QT_NO_DEBUG_OUTPUT
         std::cerr << "FM de-emphasis tau is 0: " << tau << std::endl;
 #endif
         /* diable de-emph if conencted */
-        if (d_tau > 1.0e-9) {
+        if (d_tau > 1.0e-9)
+        {
 #ifndef QT_NO_DEBUG_OUTPUT
             std::cout << "  Disable de-emphasis" << std::endl;
 #endif
@@ -150,10 +159,8 @@ void rx_demod_fm::set_tau(double tau)
 
         d_tau = 0.0;
     }
-
 }
 
-
 /*! \brief Calculate taps for FM de-emph IIR filter. */
 void rx_demod_fm::calculate_iir_taps(double tau)
 {
diff --git a/src/dsp/rx_demod_fm.h b/src/dsp/rx_demod_fm.h
index 0cc9c4f..ac22602 100644
--- a/src/dsp/rx_demod_fm.h
+++ b/src/dsp/rx_demod_fm.h
@@ -20,12 +20,11 @@
  * the Free Software Foundation, Inc., 51 Franklin Street,
  * Boston, MA 02110-1301, USA.
  */
-#ifndef RX_DEMOD_FM_H
-#define RX_DEMOD_FM_H
+#pragma once
 
-#include 
 #include 
 #include 
+#include 
 #include 
 
 class rx_demod_fm;
@@ -67,10 +66,10 @@ class rx_demod_fm : public gr::hier_block2
     std::vector            d_taps;      /*! Taps for the PFB resampler. */
 
     /* other parameters */
-    float  d_quad_rate;     /*! Quadrature rate. */
-    float  d_audio_rate;    /*! Audio rate. */
-    float  d_max_dev;       /*! Max deviation. */
-    double d_tau;           /*! De-emphasis time constant. */
+    float       d_quad_rate;     /*! Quadrature rate. */
+    float       d_audio_rate;    /*! Audio rate. */
+    float       d_max_dev;       /*! Max deviation. */
+    double      d_tau;           /*! De-emphasis time constant. */
 
     /* De-emph IIR filter taps */
     std::vector d_fftaps;  /*! Feed forward taps. */
@@ -79,5 +78,3 @@ class rx_demod_fm : public gr::hier_block2
     void calculate_iir_taps(double tau);
 
 };
-
-#endif // RX_DEMOD_FM_H

From d9c96454009f51b30555107ac6f21c4a1efe8dcb Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 11:01:31 +0100
Subject: [PATCH 176/334] Use standard filter presets for APT submode

Using wide filter preset for NFM modes with high deviation causes more
trouble than it's worth, at least once we can properly restore the
channel filter settings between sessions.
---
 src/applications/gqrx/mainwindow.cpp | 53 ++++++----------------------
 1 file changed, 11 insertions(+), 42 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 7a021eb..972e293 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -932,12 +932,11 @@ void MainWindow::selectDemod(QString strModulation)
  */
 void MainWindow::selectDemod(int mode_idx)
 {
-    double quad_rate;
-    double cwofs = 0.0;
-    float maxdev;
-    int filter_preset = uiDockRxOpt->currentFilter();
-    int flo=0, fhi=0, click_res=100;
-    bool rds_enabled;
+    double  cwofs = 0.0;
+    double  fw_half = 0.45 * rx->get_quad_rate(); // max filter width half (90% BW)
+    int     filter_preset = uiDockRxOpt->currentFilter();
+    int     flo=0, fhi=0, click_res=100;
+    bool    rds_enabled;
 
     // validate mode_idx
     if (mode_idx < DockRxOpt::MODE_OFF || mode_idx >= DockRxOpt::MODE_LAST)
@@ -964,7 +963,6 @@ void MainWindow::selectDemod(int mode_idx)
             stopAudioRec();
             uiDockAudio->setAudioRecButtonState(false);
         }
-
         rx->set_demod(receiver::RX_DEMOD_OFF);
         click_res = 1000;
         break;
@@ -972,7 +970,7 @@ void MainWindow::selectDemod(int mode_idx)
     case DockRxOpt::MODE_RAW:
         /* Raw I/Q */
         rx->set_demod(receiver::RX_DEMOD_NONE);
-        ui->plotter->setDemodRanges(-45000, -200, 200, 45000, true);
+        ui->plotter->setDemodRanges(-fw_half, -200, 200, fw_half, true);
         uiDockAudio->setFftRange(0,24000);
         click_res = 100;
         break;
@@ -985,34 +983,19 @@ void MainWindow::selectDemod(int mode_idx)
         break;
 
     case DockRxOpt::MODE_NFM:
+        ui->plotter->setDemodRanges(-fw_half, -1000, 1000, fw_half, true);
+        uiDockAudio->setFftRange(0, 5000);
         rx->set_demod(receiver::RX_DEMOD_NFM);
-        click_res = 100;
-        maxdev = uiDockRxOpt->currentMaxdev();
-        if (maxdev < 20000.0)
-        {   /** FIXME **/
-            ui->plotter->setDemodRanges(-45000, -250, 250, 45000, true);
-            uiDockAudio->setFftRange(0,6000);
-        }
-        else
-        {
-            ui->plotter->setDemodRanges(-45000, -1000, 1000, 45000, true);
-            uiDockAudio->setFftRange(0,24000);
-        }
-        rx->set_fm_maxdev(maxdev);
+        rx->set_fm_maxdev(uiDockRxOpt->currentMaxdev());
         rx->set_fm_deemph(uiDockRxOpt->currentEmph());
+        click_res = 100;
         break;
 
     case DockRxOpt::MODE_WFM_MONO:
     case DockRxOpt::MODE_WFM_STEREO:
     case DockRxOpt::MODE_WFM_STEREO_OIRT:
         /* Broadcast FM */
-        quad_rate = rx->get_input_rate();
-        if (quad_rate < 500.0e3)
-            ui->plotter->setDemodRanges(-quad_rate/2.0, -10000,
-                                        10000, quad_rate/2.0,
-                                        true);
-        else
-            ui->plotter->setDemodRanges(-250000, -10000, 10000, 250000, true);
+        ui->plotter->setDemodRanges(-fw_half, -10000, 10000, fw_half, true);
         uiDockAudio->setFftRange(0,24000);  /** FIXME: get audio rate from rx **/
         click_res = 1000;
         if (mode_idx == DockRxOpt::MODE_WFM_MONO)
@@ -1096,20 +1079,6 @@ void MainWindow::setFmMaxdev(float max_dev)
 
     /* receiver will check range */
     rx->set_fm_maxdev(max_dev);
-
-    /* update filter */
-    if (max_dev < 20000.0)
-    {
-        ui->plotter->setDemodRanges(-25000, -1000, 1000, 25000, true);
-        ui->plotter->setHiLowCutFrequencies(-5000, 5000);
-        rx->set_filter(-5000.0, 5000.0, d_filter_shape);
-    }
-    else
-    {
-        ui->plotter->setDemodRanges(-45000, -10000, 10000, 45000, true);
-        ui->plotter->setHiLowCutFrequencies(-35000, 35000);
-        rx->set_filter(-35000.0, 35000.0, d_filter_shape);
-    }
 }
 
 

From b27221a2f5e47382cf85479d5865c21c6a6e2f85 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 11:41:14 +0100
Subject: [PATCH 177/334] Add interface for reading quad_rate from receiver

Also move implementation of get_input_rate to header.
---
 src/applications/gqrx/receiver.cpp | 7 -------
 src/applications/gqrx/receiver.h   | 6 +++++-
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp
index 0cddce8..59017a6 100644
--- a/src/applications/gqrx/receiver.cpp
+++ b/src/applications/gqrx/receiver.cpp
@@ -348,13 +348,6 @@ double receiver::set_input_rate(double rate)
     return d_input_rate;
 }
 
-
-/** Get current input sample rate. */
-double receiver::get_input_rate(void) const
-{
-    return d_input_rate;
-}
-
 /** Set input decimation */
 unsigned int receiver::set_input_decim(unsigned int decim)
 {
diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h
index 0df430d..a95af5c 100644
--- a/src/applications/gqrx/receiver.h
+++ b/src/applications/gqrx/receiver.h
@@ -119,11 +119,15 @@ class receiver
     void        set_antenna(const std::string &antenna);
 
     double      set_input_rate(double rate);
-    double      get_input_rate(void) const;
+    double      get_input_rate(void) const { return d_input_rate; }
 
     unsigned int    set_input_decim(unsigned int decim);
     unsigned int    get_input_decim(void) const { return d_decim; }
 
+    double      get_quad_rate(void) const {
+        return d_input_rate / (double)d_decim;
+    }
+
     double      set_analog_bandwidth(double bw);
     double      get_analog_bandwidth(void) const;
 

From b56bc28ec2388d7256033536c5f85b86157b9f88 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 12:25:19 +0100
Subject: [PATCH 178/334] Remove unused audio rate from FM and AM demods

---
 src/dsp/rx_demod_am.cpp | 7 +++----
 src/dsp/rx_demod_am.h   | 8 +++-----
 src/dsp/rx_demod_fm.cpp | 7 +++----
 src/dsp/rx_demod_fm.h   | 6 ++----
 src/receivers/nbrx.cpp  | 4 ++--
 src/receivers/wfmrx.cpp | 2 +-
 6 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/src/dsp/rx_demod_am.cpp b/src/dsp/rx_demod_am.cpp
index d294062..e97bf53 100644
--- a/src/dsp/rx_demod_am.cpp
+++ b/src/dsp/rx_demod_am.cpp
@@ -26,9 +26,9 @@
 
 
 /* Create a new instance of rx_demod_am and return a boost shared_ptr. */
-rx_demod_am_sptr make_rx_demod_am(float quad_rate, float audio_rate, bool dcr)
+rx_demod_am_sptr make_rx_demod_am(float quad_rate, bool dcr)
 {
-    return gnuradio::get_initial_sptr(new rx_demod_am(quad_rate, audio_rate, dcr));
+    return gnuradio::get_initial_sptr(new rx_demod_am(quad_rate, dcr));
 }
 
 static const int MIN_IN = 1;  /* Mininum number of input streams. */
@@ -36,14 +36,13 @@ static const int MAX_IN = 1;  /* Maximum number of input streams. */
 static const int MIN_OUT = 1; /* Minimum number of output streams. */
 static const int MAX_OUT = 1; /* Maximum number of output streams. */
 
-rx_demod_am::rx_demod_am(float quad_rate, float audio_rate, bool dcr)
+rx_demod_am::rx_demod_am(float quad_rate, bool dcr)
     : gr::hier_block2 ("rx_demod_am",
                       gr::io_signature::make (MIN_IN, MAX_IN, sizeof (gr_complex)),
                       gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (float))),
     d_dcr_enabled(dcr)
 {
     (void) quad_rate;
-    (void) audio_rate;
 
     /* demodulator */
     d_demod = gr::blocks::complex_to_mag::make(1);
diff --git a/src/dsp/rx_demod_am.h b/src/dsp/rx_demod_am.h
index da8ab7d..7809d6c 100644
--- a/src/dsp/rx_demod_am.h
+++ b/src/dsp/rx_demod_am.h
@@ -36,13 +36,11 @@ typedef boost::shared_ptr rx_demod_am_sptr;
 
 /*! \brief Return a shared_ptr to a new instance of rx_demod_am.
  *  \param quad_rate The input sample rate.
- *  \param audio_rate The audio rate.
  *  \param dcr Enable DCR
  *
  * This is effectively the public constructor.
  */
-rx_demod_am_sptr make_rx_demod_am(float quad_rate, float audio_rate, bool dcr=true);
-
+rx_demod_am_sptr make_rx_demod_am(float quad_rate, bool dcr=true);
 
 /*! \brief AM demodulator.
  *  \ingroup DSP
@@ -56,7 +54,7 @@ class rx_demod_am : public gr::hier_block2
 {
 
 public:
-    rx_demod_am(float quad_rate=48000.0, float audio_rate=48000.0, bool dcr=true); // FIXME: could be private
+    rx_demod_am(float quad_rate, bool dcr=true); // FIXME: could be private
     ~rx_demod_am();
 
     void set_dcr(bool dcr);
@@ -64,7 +62,7 @@ class rx_demod_am : public gr::hier_block2
 
 private:
     /* GR blocks */
-    gr::blocks::complex_to_mag::sptr  d_demod;    /*! AM demodulation (complex to magnitude). */
+    gr::blocks::complex_to_mag::sptr    d_demod;  /*! AM demodulation (complex to magnitude). */
     gr::filter::iir_filter_ffd::sptr    d_dcr;    /*! DC removal (IIR high pass). */
 
     /* other parameters */
diff --git a/src/dsp/rx_demod_fm.cpp b/src/dsp/rx_demod_fm.cpp
index ae7ce3b..382060f 100644
--- a/src/dsp/rx_demod_fm.cpp
+++ b/src/dsp/rx_demod_fm.cpp
@@ -29,9 +29,9 @@
 
 
 /* Create a new instance of rx_demod_fm and return a boost shared_ptr. */
-rx_demod_fm_sptr make_rx_demod_fm(float quad_rate, float audio_rate, float max_dev, double tau)
+rx_demod_fm_sptr make_rx_demod_fm(float quad_rate, float max_dev, double tau)
 {
-    return gnuradio::get_initial_sptr(new rx_demod_fm(quad_rate, audio_rate, max_dev, tau));
+    return gnuradio::get_initial_sptr(new rx_demod_fm(quad_rate, max_dev, tau));
 }
 
 static const int MIN_IN = 1;  /* Mininum number of input streams. */
@@ -39,12 +39,11 @@ static const int MAX_IN = 1;  /* Maximum number of input streams. */
 static const int MIN_OUT = 1; /* Minimum number of output streams. */
 static const int MAX_OUT = 1; /* Maximum number of output streams. */
 
-rx_demod_fm::rx_demod_fm(float quad_rate, float audio_rate, float max_dev, double tau)
+rx_demod_fm::rx_demod_fm(float quad_rate, float max_dev, double tau)
     : gr::hier_block2 ("rx_demod_fm",
                       gr::io_signature::make (MIN_IN, MAX_IN, sizeof (gr_complex)),
                       gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (float))),
     d_quad_rate(quad_rate),
-    d_audio_rate(audio_rate),
     d_max_dev(max_dev),
     d_tau(tau)
 {
diff --git a/src/dsp/rx_demod_fm.h b/src/dsp/rx_demod_fm.h
index ac22602..1aac163 100644
--- a/src/dsp/rx_demod_fm.h
+++ b/src/dsp/rx_demod_fm.h
@@ -32,7 +32,6 @@ typedef boost::shared_ptr rx_demod_fm_sptr;
 
 /*! \brief Return a shared_ptr to a new instance of rx_demod_fm.
  *  \param quad_rate The input sample rate.
- *  \param audio_rate The audio rate.
  *  \param max_dev Maximum deviation in Hz
  *  \param tau De-emphasis time constant in seconds (75us in US, 50us in EUR, 0.0 disables).
  *
@@ -40,7 +39,7 @@ typedef boost::shared_ptr rx_demod_fm_sptr;
  * of raw pointers, rx_demod_fm's constructor is private.
  * make_rx_dmod_fm is the public interface for creating new instances.
  */
-rx_demod_fm_sptr make_rx_demod_fm(float quad_rate, float audio_rate, float max_dev=5000.0, double tau=50.0e-6);
+rx_demod_fm_sptr make_rx_demod_fm(float quad_rate, float max_dev=5000.0, double tau=50.0e-6);
 
 /*! \brief FM demodulator.
  *  \ingroup DSP
@@ -53,7 +52,7 @@ class rx_demod_fm : public gr::hier_block2
 {
 
 public:
-    rx_demod_fm(float quad_rate=48000.0, float audio_rate=48000.0, float max_dev=5000.0, double tau=50.0e-6); // FIXME: should be private
+    rx_demod_fm(float quad_rate, float max_dev, double tau); // FIXME: should be private
     ~rx_demod_fm();
 
     void set_max_dev(float max_dev);
@@ -67,7 +66,6 @@ class rx_demod_fm : public gr::hier_block2
 
     /* other parameters */
     float       d_quad_rate;     /*! Quadrature rate. */
-    float       d_audio_rate;    /*! Audio rate. */
     float       d_max_dev;       /*! Max deviation. */
     double      d_tau;           /*! De-emphasis time constant. */
 
diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp
index ae73ae1..b6b9f01 100644
--- a/src/receivers/nbrx.cpp
+++ b/src/receivers/nbrx.cpp
@@ -48,8 +48,8 @@ nbrx::nbrx(float quad_rate, float audio_rate)
     meter = make_rx_meter_c(DETECTOR_TYPE_RMS);
     demod_raw = gr::blocks::complex_to_float::make(1);
     demod_ssb = gr::blocks::complex_to_real::make(1);
-    demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, PREF_AUDIO_RATE, 5000.0, 75.0e-6);
-    demod_am = make_rx_demod_am(PREF_QUAD_RATE, PREF_AUDIO_RATE, true);
+    demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, 5000.0, 75.0e-6);
+    demod_am = make_rx_demod_am(PREF_QUAD_RATE, true);
 
     audio_rr.reset();
     if (d_audio_rate != PREF_AUDIO_RATE)
diff --git a/src/receivers/wfmrx.cpp b/src/receivers/wfmrx.cpp
index a6321fa..1c9f804 100644
--- a/src/receivers/wfmrx.cpp
+++ b/src/receivers/wfmrx.cpp
@@ -45,7 +45,7 @@ wfmrx::wfmrx(float quad_rate, float audio_rate)
     filter = make_rx_filter(PREF_QUAD_RATE, -80000.0, 80000.0, 20000.0);
     sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001);
     meter = make_rx_meter_c(DETECTOR_TYPE_RMS);
-    demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, PREF_MIDLE_RATE, 75000.0, 50.0e-6);
+    demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, 75000.0, 50.0e-6);
     midle_rr = make_resampler_ff(PREF_MIDLE_RATE/PREF_QUAD_RATE);
     stereo = make_stereo_demod(PREF_MIDLE_RATE, d_audio_rate, true);
     stereo_oirt = make_stereo_demod(PREF_MIDLE_RATE, d_audio_rate, true, true);

From 392dd4206a7e745c8ea047f5312664e8dfeaacbf Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 12:37:29 +0100
Subject: [PATCH 179/334] Increase quadrature rate for narrow band receiver

Reducing the quadrature rate to 48 kHz was probably done while
optimizing for embedded devices; however, 48 kHz is just too narrow if
we want to do things like NOAA APT using the narrow band receiver.

See also issue #459.
---
 src/receivers/nbrx.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp
index b6b9f01..c323d34 100644
--- a/src/receivers/nbrx.cpp
+++ b/src/receivers/nbrx.cpp
@@ -24,8 +24,8 @@
 #include 
 #include "receivers/nbrx.h"
 
-#define PREF_QUAD_RATE  48000.f
-#define PREF_AUDIO_RATE 48000.f
+// NB: Remeber to adjust filter ranges in MainWindow
+#define PREF_QUAD_RATE  96000.f
 
 nbrx_sptr make_nbrx(float quad_rate, float audio_rate)
 {
@@ -52,11 +52,11 @@ nbrx::nbrx(float quad_rate, float audio_rate)
     demod_am = make_rx_demod_am(PREF_QUAD_RATE, true);
 
     audio_rr.reset();
-    if (d_audio_rate != PREF_AUDIO_RATE)
+    if (d_audio_rate != PREF_QUAD_RATE)
     {
-        std::cout << "Resampling audio " << PREF_AUDIO_RATE << " -> "
+        std::cout << "Resampling audio " << PREF_QUAD_RATE << " -> "
                   << d_audio_rate << std::endl;
-        audio_rr = make_resampler_ff(d_audio_rate/PREF_AUDIO_RATE);
+        audio_rr = make_resampler_ff(d_audio_rate/PREF_QUAD_RATE);
     }
 
     demod = demod_fm;
@@ -113,6 +113,7 @@ void nbrx::set_quad_rate(float quad_rate)
 void nbrx::set_audio_rate(float audio_rate)
 {
     (void) audio_rate;
+    std::cout << "**** FIXME: nbrx::set_audio_rate() not implemented" << std::endl;
 }
 
 void nbrx::set_filter(double low, double high, double tw)

From 3b2859a0bc2aab89772a4880a4454a28a1b8109d Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 12:44:51 +0100
Subject: [PATCH 180/334] Adjust filter ranges according to quadrature rate

---
 src/applications/gqrx/mainwindow.cpp | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 972e293..35fd7c6 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -933,7 +933,6 @@ void MainWindow::selectDemod(QString strModulation)
 void MainWindow::selectDemod(int mode_idx)
 {
     double  cwofs = 0.0;
-    double  fw_half = 0.45 * rx->get_quad_rate(); // max filter width half (90% BW)
     int     filter_preset = uiDockRxOpt->currentFilter();
     int     flo=0, fhi=0, click_res=100;
     bool    rds_enabled;
@@ -968,22 +967,22 @@ void MainWindow::selectDemod(int mode_idx)
         break;
 
     case DockRxOpt::MODE_RAW:
-        /* Raw I/Q */
+        /* Raw I/Q; max 96 ksps*/
         rx->set_demod(receiver::RX_DEMOD_NONE);
-        ui->plotter->setDemodRanges(-fw_half, -200, 200, fw_half, true);
+        ui->plotter->setDemodRanges(-40000, -200, 200, 40000, true);
         uiDockAudio->setFftRange(0,24000);
         click_res = 100;
         break;
 
     case DockRxOpt::MODE_AM:
         rx->set_demod(receiver::RX_DEMOD_AM);
-        ui->plotter->setDemodRanges(-45000, -200, 200, 45000, true);
+        ui->plotter->setDemodRanges(-40000, -200, 200, 40000, true);
         uiDockAudio->setFftRange(0,6000);
         click_res = 100;
         break;
 
     case DockRxOpt::MODE_NFM:
-        ui->plotter->setDemodRanges(-fw_half, -1000, 1000, fw_half, true);
+        ui->plotter->setDemodRanges(-40000, -1000, 1000, 40000, true);
         uiDockAudio->setFftRange(0, 5000);
         rx->set_demod(receiver::RX_DEMOD_NFM);
         rx->set_fm_maxdev(uiDockRxOpt->currentMaxdev());
@@ -995,7 +994,7 @@ void MainWindow::selectDemod(int mode_idx)
     case DockRxOpt::MODE_WFM_STEREO:
     case DockRxOpt::MODE_WFM_STEREO_OIRT:
         /* Broadcast FM */
-        ui->plotter->setDemodRanges(-fw_half, -10000, 10000, fw_half, true);
+        ui->plotter->setDemodRanges(-120e3, -10000, 10000, 120e3, true);
         uiDockAudio->setFftRange(0,24000);  /** FIXME: get audio rate from rx **/
         click_res = 1000;
         if (mode_idx == DockRxOpt::MODE_WFM_MONO)

From 54960c3db5e67f0cb2ae0cd227784d09dcc181b5 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 13:00:43 +0100
Subject: [PATCH 181/334] Remove 75k deviation from narrow band RX

---
 src/qtgui/demod_options.cpp | 8 +-------
 src/qtgui/demod_options.ui  | 5 -----
 2 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/src/qtgui/demod_options.cpp b/src/qtgui/demod_options.cpp
index f831f4a..2359279 100644
--- a/src/qtgui/demod_options.cpp
+++ b/src/qtgui/demod_options.cpp
@@ -67,9 +67,6 @@ float maxdev_from_index(int index)
     case 3:
         /* APT 25k (17k but need some margin for Doppler and freq error) */
         return 25000.0;
-    case 4:
-        /* Broadcast FM 75k */
-        return 75000.0;
     default:
         /* Voice 5k */
         qDebug() << "Invalid max_dev index: " << index;
@@ -88,12 +85,9 @@ int maxdev_to_index(float max_dev)
     else if (max_dev < 20000.0)
         /* APT 17k */
         return 2;
-    else if (max_dev < 40000.0)
+    else
         /* APT 25k */
         return 3;
-    else
-        /* Broadcast FM 75k */
-        return 4;
 }
 
 CDemodOptions::CDemodOptions(QWidget *parent) :
diff --git a/src/qtgui/demod_options.ui b/src/qtgui/demod_options.ui
index 8551310..a2c1539 100644
--- a/src/qtgui/demod_options.ui
+++ b/src/qtgui/demod_options.ui
@@ -122,11 +122,6 @@ this demodulator
              APT (25 kHz)
             
            
-           
-            
-             BC (75 kHz)
-            
-           
           
          
          

From 05e45a05e4a77b865153610961a518792919f0fe Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 18:43:02 +0100
Subject: [PATCH 182/334] Add interface to retrieve filter low/high cut

---
 src/qtgui/plotter.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h
index 33708dd..f1421a6 100644
--- a/src/qtgui/plotter.h
+++ b/src/qtgui/plotter.h
@@ -70,6 +70,12 @@ class CPlotter : public QFrame
         drawOverlay();
     }
 
+    void getHiLowCutFrequencies(int *LowCut, int *HiCut)
+    {
+        *LowCut = m_DemodLowCutFreq;
+        *HiCut = m_DemodHiCutFreq;
+    }
+
     void setDemodRanges(int FLowCmin, int FLowCmax, int FHiCmin, int FHiCmax, bool symetric);
 
     /* Shown bandwidth around SetCenterFreq() */

From a55eabd60737e665a51a2504133515d5715a1272 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 18:43:45 +0100
Subject: [PATCH 183/334] Restore filter width between sessions

Issue #473.
---
 src/applications/gqrx/mainwindow.cpp | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 35fd7c6..4601ba2 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -579,6 +579,16 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash,
         setNewFrequency(ui->freqCtrl->getFrequency()); // ensure all GUI and RF is updated
     }
 
+    {
+        int flo = m_settings->value("receiver/filter_low_cut", 0).toInt(&conv_ok);
+        int fhi = m_settings->value("receiver/filter_high_cut", 0).toInt(&conv_ok);
+
+        if (conv_ok && flo != fhi)
+        {
+            on_plotter_newFilterFreq(flo, fhi);
+        }
+    }
+
     iq_tool->readSettings(m_settings);
 
     /*
@@ -667,6 +677,16 @@ void MainWindow::storeSession()
 
         remote->saveSettings(m_settings);
         iq_tool->saveSettings(m_settings);
+
+        {
+            int     flo, fhi;
+            ui->plotter->getHiLowCutFrequencies(&flo, &fhi);
+            if (flo != fhi)
+            {
+                m_settings->setValue("receiver/filter_low_cut", flo);
+                m_settings->setValue("receiver/filter_high_cut", fhi);
+            }
+        }
     }
 }
 
@@ -1850,7 +1870,7 @@ void MainWindow::on_plotter_newDemodFreq(qint64 freq, qint64 delta)
         rx->reset_rds_parser();
 }
 
-/* CPlotter::NewfilterFreq() is emitted */
+/* CPlotter::NewfilterFreq() is emitted or bookmark activated */
 void MainWindow::on_plotter_newFilterFreq(int low, int high)
 {
     receiver::status retcode;

From 175f3352f7c77b777f95e5432341659047449e3f Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 18:51:21 +0100
Subject: [PATCH 184/334] Update news file

---
 resources/news.txt | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/resources/news.txt b/resources/news.txt
index a21597e..04c67aa 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -1,10 +1,13 @@
        2.7: TBD...
 
-       NEW: Save remote control state between sessions.
+       NEW: Restore filter low cut and high cut between sessions.
+       NEW: Restore FM parameters between sessions.
+       NEW: Restore remote control state between sessions.
        NEW: Support for passband when setting mode through remote.
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
      FIXED: RDS status is not kept while jumping through bookmark.
   IMPROVED: Tuning through the remote control interface.
+  IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
 
 
        2.6: Released October 3, 2016

From 970591e1b44c3817c96eba6ec6ce2fcc59d8102e Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 7 Jan 2017 23:16:24 +0100
Subject: [PATCH 185/334] Update FM de-emphasis filter to match fm_emph.py

---
 src/dsp/rx_demod_fm.cpp | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/src/dsp/rx_demod_fm.cpp b/src/dsp/rx_demod_fm.cpp
index 382060f..2835609 100644
--- a/src/dsp/rx_demod_fm.cpp
+++ b/src/dsp/rx_demod_fm.cpp
@@ -163,15 +163,25 @@ void rx_demod_fm::set_tau(double tau)
 /*! \brief Calculate taps for FM de-emph IIR filter. */
 void rx_demod_fm::calculate_iir_taps(double tau)
 {
-    /* copied from fm_emph.py in gnuradio-core */
-    double w_p, w_pp;
-
-    w_p = 1.0/tau;
-    w_pp = tan(w_p / (d_quad_rate * 2.0)); /* prewarped analog freq */
-
-    d_fftaps[0] = w_pp/(1 + w_pp);
-    d_fftaps[1] = d_fftaps[0];
-
+    // copied from fm_emph.py in gr-analog
+    double  w_c;    // Digital corner frequency
+    double  w_ca;   // Prewarped analog corner frequency
+    double  k, z1, p1, b0;
+    double  fs = d_quad_rate;
+
+    w_c = 1.0 / tau;
+    w_ca = 2.0 * fs * tan(w_c / (2.0 * fs));
+
+    // Resulting digital pole, zero, and gain term from the bilinear
+    // transformation of H(s) = w_ca / (s + w_ca) to
+    // H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1)
+    k = -w_ca / (2.0 * fs);
+    z1 = -1.0;
+    p1 = (1.0 + k) / (1.0 - k);
+    b0 = -k / (1.0 - k);
+
+    d_fftaps[0] = b0;
+    d_fftaps[1] = -z1 * b0;
     d_fbtaps[0] = 1.0;
-    d_fbtaps[1] = (w_pp - 1)/(w_pp + 1);
+    d_fbtaps[1] = -p1;
 }

From 6a13e4eb5bd372da879d54f545aaf0147a94d2d1 Mon Sep 17 00:00:00 2001
From: Michael Tatarinov 
Date: Thu, 27 Oct 2016 13:53:10 +0400
Subject: [PATCH 186/334] Added a few fake command for better hamlib
 compatible.

---
 resources/remote-control.txt             | 12 +++++-
 src/applications/gqrx/remote_control.cpp | 50 ++++++++++++++++++++++++
 src/applications/gqrx/remote_control.h   |  5 +++
 3 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/resources/remote-control.txt b/resources/remote-control.txt
index e8dae22..0927644 100644
--- a/resources/remote-control.txt
+++ b/resources/remote-control.txt
@@ -28,7 +28,17 @@ Supported commands:
  LOS
     Loss of signal (LOS) event, stop audio recording
  \dump_state
-    Dump state (only usable for compatibility)
+    Dump state (only usable for hamlib compatibility)
+ v
+    Get 'VFO' (only usable for hamlib compatibility)
+ V
+    Set 'VFO' (only usable for hamlib compatibility)
+ s
+    Get 'Split' mode (only usable for hamlib compatibility)
+ S
+    Set 'Split' mode (only usable for hamlib compatibility)
+ _
+    Get version
 
 
 Reply:
diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 68986f7..c77a70c 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -204,6 +204,16 @@ void RemoteControl::startRead()
         answer = cmd_get_func(cmdlist);
     else if (cmd == "U")
         answer = cmd_set_func(cmdlist);
+    else if (cmd == "v")
+        answer = cmd_get_vfo();
+    else if (cmd == "V")
+        answer = cmd_set_vfo(cmdlist);
+    else if (cmd == "s")
+        answer = cmd_get_split_vfo();
+    else if (cmd == "S")
+        answer = cmd_set_split_vfo();
+    else if (cmd == "_")
+        answer = cmd_get_info();
     else if (cmd == "AOS")
         answer = cmd_AOS();
     else if (cmd == "LOS")
@@ -622,6 +632,46 @@ QString RemoteControl::cmd_set_func(QStringList cmdlist)
     return answer;
 }
 
+/* Get current 'VFO' (fake, only for hamlib) */
+QString RemoteControl::cmd_get_vfo()
+{
+    return QString("VFOA\n");
+};
+
+/* Set 'VFO' (fake, only for hamlib) */
+QString RemoteControl::cmd_set_vfo(QStringList cmdlist)
+{
+    QString cmd_arg = cmdlist.value(1, "");
+    QString answer;
+
+    if (cmd_arg == "?")
+        answer = QString("VFOA\n");
+    else if (cmd_arg == "VFOA")
+        answer = QString("RPRT 0\n");
+    else
+        answer = QString("RPRT 1\n");
+
+    return answer;
+};
+
+/* Get 'Split' mode (fake, only for hamlib) */
+QString RemoteControl::cmd_get_split_vfo()
+{
+    return QString("0\nVFOA\n");
+};
+
+/* Set 'Split' mode (fake, only for hamlib) */
+QString RemoteControl::cmd_set_split_vfo()
+{
+    return QString("RPRT 1\n");
+}
+
+/* Get info */
+QString RemoteControl::cmd_get_info()
+{
+    return QString("Gqrx %1\n").arg(VERSION);
+};
+
 /* Gpredict / Gqrx specific command: AOS - satellite AOS event */
 QString RemoteControl::cmd_AOS()
 {
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index 5b875d6..88effc2 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -136,6 +136,11 @@ private slots:
     QString     cmd_set_level(QStringList cmdlist);
     QString     cmd_get_func(QStringList cmdlist);
     QString     cmd_set_func(QStringList cmdlist);
+    QString     cmd_get_vfo();
+    QString     cmd_set_vfo(QStringList cmdlist);
+    QString     cmd_get_split_vfo();
+    QString     cmd_set_split_vfo();
+    QString     cmd_get_info();
     QString     cmd_AOS();
     QString     cmd_LOS();
     QString     cmd_dump_state();

From e7f3c94cda57296c1c8784d261588c5e160e0903 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Mon, 9 Jan 2017 22:32:18 +0100
Subject: [PATCH 187/334] Add config record for resetting the digits in
 FreqCtrl

Replaces pull request #477 and fixes issue #445.
---
 resources/news.txt                   | 1 +
 src/applications/gqrx/mainwindow.cpp | 4 ++++
 src/qtgui/dockrxopt.cpp              | 3 +++
 src/qtgui/freqctrl.h                 | 4 ++++
 4 files changed, 12 insertions(+)

diff --git a/resources/news.txt b/resources/news.txt
index 04c67aa..d885f34 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -8,6 +8,7 @@
      FIXED: RDS status is not kept while jumping through bookmark.
   IMPROVED: Tuning through the remote control interface.
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
+  IMPROVED: Config record for reverting the behavior of the freq. controller
 
 
        2.6: Released October 3, 2016
diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 4601ba2..1654867 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -453,6 +453,10 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash,
         restoreState(m_settings->value("gui/state", saveState()).toByteArray());
     }
 
+    // misc GUI settings
+    bool_val = m_settings->value("gui/fctl_reset_digits", true).toBool();
+    ui->freqCtrl->setResetLowerDigits(bool_val);
+
     QString indev = m_settings->value("input/device", "").toString();
     if (!indev.isEmpty())
     {
diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 75fe3f8..92ac051 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -323,6 +323,9 @@ void DockRxOpt::readSettings(QSettings *settings)
     int     int_val;
     double  dbl_val;
 
+    bool bool_val = settings->value("gui/fctl_reset_digits", true).toBool();
+    ui->filterFreq->setResetLowerDigits(bool_val);
+
     int_val = settings->value("receiver/cwoffset", 700).toInt(&conv_ok);
     if (conv_ok)
         demodOpt->setCwOffset(int_val);
diff --git a/src/qtgui/freqctrl.h b/src/qtgui/freqctrl.h
index 5f7493c..cafcd3c 100644
--- a/src/qtgui/freqctrl.h
+++ b/src/qtgui/freqctrl.h
@@ -59,6 +59,10 @@ class CFreqCtrl : public QFrame
     void setHighlightColor(QColor cr);
     qint64 getFrequency() { return m_freq; }
 
+    void setResetLowerDigits(bool reset) {
+        m_ResetLowerDigits = reset;
+    }
+
 signals:
     void newFrequency(qint64 freq); //emitted when frequency has changed
 

From 487a8ffd5bd207be5ec92fdccdd81b60371ba1d3 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 12 Jan 2017 00:10:46 +0100
Subject: [PATCH 188/334] Make some members const

---
 src/applications/gqrx/remote_control.cpp | 10 +++++-----
 src/applications/gqrx/remote_control.h   | 10 +++++-----
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index c77a70c..51d06d2 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -469,7 +469,7 @@ QString RemoteControl::intToModeStr(int mode)
 }
 
 /* Get frequency */
-QString RemoteControl::cmd_get_freq()
+QString RemoteControl::cmd_get_freq() const
 {
     return QString("%1\n").arg(rc_freq);
 }
@@ -633,7 +633,7 @@ QString RemoteControl::cmd_set_func(QStringList cmdlist)
 }
 
 /* Get current 'VFO' (fake, only for hamlib) */
-QString RemoteControl::cmd_get_vfo()
+QString RemoteControl::cmd_get_vfo() const
 {
     return QString("VFOA\n");
 };
@@ -655,7 +655,7 @@ QString RemoteControl::cmd_set_vfo(QStringList cmdlist)
 };
 
 /* Get 'Split' mode (fake, only for hamlib) */
-QString RemoteControl::cmd_get_split_vfo()
+QString RemoteControl::cmd_get_split_vfo() const
 {
     return QString("0\nVFOA\n");
 };
@@ -667,7 +667,7 @@ QString RemoteControl::cmd_set_split_vfo()
 }
 
 /* Get info */
-QString RemoteControl::cmd_get_info()
+QString RemoteControl::cmd_get_info() const
 {
     return QString("Gqrx %1\n").arg(VERSION);
 };
@@ -697,7 +697,7 @@ QString RemoteControl::cmd_LOS()
  *  https://github.com/N0NB/hamlib/blob/master/include/hamlib/rig.h (bit fields)
  *  https://github.com/N0NB/hamlib/blob/master/dummy/netrigctl.c
  */
-QString RemoteControl::cmd_dump_state()
+QString RemoteControl::cmd_dump_state() const
 {
     return QString(
         /* rigctl protocol version */
diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h
index 88effc2..1050f8d 100644
--- a/src/applications/gqrx/remote_control.h
+++ b/src/applications/gqrx/remote_control.h
@@ -128,7 +128,7 @@ private slots:
     QString     intToModeStr(int mode);
 
     /* RC commands */
-    QString     cmd_get_freq();
+    QString     cmd_get_freq() const;
     QString     cmd_set_freq(QStringList cmdlist);
     QString     cmd_get_mode();
     QString     cmd_set_mode(QStringList cmdlist);
@@ -136,14 +136,14 @@ private slots:
     QString     cmd_set_level(QStringList cmdlist);
     QString     cmd_get_func(QStringList cmdlist);
     QString     cmd_set_func(QStringList cmdlist);
-    QString     cmd_get_vfo();
+    QString     cmd_get_vfo() const;
     QString     cmd_set_vfo(QStringList cmdlist);
-    QString     cmd_get_split_vfo();
+    QString     cmd_get_split_vfo() const;
     QString     cmd_set_split_vfo();
-    QString     cmd_get_info();
+    QString     cmd_get_info() const;
     QString     cmd_AOS();
     QString     cmd_LOS();
-    QString     cmd_dump_state();
+    QString     cmd_dump_state() const;
 };
 
 #endif // REMOTE_CONTROL_H

From 0634769f3cdf0eab1406ab95f6227435f450fe94 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Wed, 18 Jan 2017 15:35:19 +0100
Subject: [PATCH 189/334] Use || for logical or

---
 src/qtgui/demod_options.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/qtgui/demod_options.cpp b/src/qtgui/demod_options.cpp
index 2359279..349bfb6 100644
--- a/src/qtgui/demod_options.cpp
+++ b/src/qtgui/demod_options.cpp
@@ -33,7 +33,7 @@ const int tau_tbl_maxidx = 7;
 
 double tau_from_index(int index)
 {
-    if (index < 0 or index > tau_tbl_maxidx)
+    if (index < 0 || index > tau_tbl_maxidx)
         return 0.0;
 
     return tau_tbl[index];

From 0f0830975d7d5759bb9b297078c0f94375f97408 Mon Sep 17 00:00:00 2001
From: dadosch 
Date: Sat, 28 Jan 2017 21:20:18 +0100
Subject: [PATCH 190/334] German translation for dekstop file

---
 gqrx.desktop | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gqrx.desktop b/gqrx.desktop
index 7c5807e..3814644 100644
--- a/gqrx.desktop
+++ b/gqrx.desktop
@@ -8,6 +8,7 @@ GenericName[ru]=Программно-определённое радио
 Comment[ru]=Приемник для программно-определенного радио (SDR) использующий GNU Radio и библиотеку Qt.
 GenericName[nl]=Software Defined Radio
 Comment[nl]=Software defined radio ontvanger geïmplementeerd met GNU Radio en de Qt GUI toolkit
+Commenr[de]=Software defined Radio implementiert durch GNU Radio und das Qt GUI Toolkit
 Exec=gqrx
 Terminal=false
 Icon=gqrx

From 79f781ee0c0524bc40d02076339aaf81f654d947 Mon Sep 17 00:00:00 2001
From: dadosch 
Date: Sat, 28 Jan 2017 21:30:42 +0100
Subject: [PATCH 191/334] improved naturality

---
 gqrx.desktop | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gqrx.desktop b/gqrx.desktop
index 3814644..f9a9182 100644
--- a/gqrx.desktop
+++ b/gqrx.desktop
@@ -8,7 +8,7 @@ GenericName[ru]=Программно-определённое радио
 Comment[ru]=Приемник для программно-определенного радио (SDR) использующий GNU Radio и библиотеку Qt.
 GenericName[nl]=Software Defined Radio
 Comment[nl]=Software defined radio ontvanger geïmplementeerd met GNU Radio en de Qt GUI toolkit
-Commenr[de]=Software defined Radio implementiert durch GNU Radio und das Qt GUI Toolkit
+Commenr[de]=Software defined Radio auf Basis von GNU Radio und dem Qt GUI Toolkit
 Exec=gqrx
 Terminal=false
 Icon=gqrx

From 96fc99d4a53ce64234b67be63173e55ee4b1759b Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sat, 28 Jan 2017 21:51:50 +0100
Subject: [PATCH 192/334] Fix typo

---
 gqrx.desktop | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gqrx.desktop b/gqrx.desktop
index f9a9182..021a206 100644
--- a/gqrx.desktop
+++ b/gqrx.desktop
@@ -8,7 +8,7 @@ GenericName[ru]=Программно-определённое радио
 Comment[ru]=Приемник для программно-определенного радио (SDR) использующий GNU Radio и библиотеку Qt.
 GenericName[nl]=Software Defined Radio
 Comment[nl]=Software defined radio ontvanger geïmplementeerd met GNU Radio en de Qt GUI toolkit
-Commenr[de]=Software defined Radio auf Basis von GNU Radio und dem Qt GUI Toolkit
+Comment[de]=Software defined Radio auf Basis von GNU Radio und dem Qt GUI Toolkit
 Exec=gqrx
 Terminal=false
 Icon=gqrx

From f0078b19f363c5c5eef2b3c5be45789df2c469fe Mon Sep 17 00:00:00 2001
From: Alexander Fasching 
Date: Fri, 10 Feb 2017 17:43:00 +0100
Subject: [PATCH 193/334] Check if audio sink is connected before disconnecting

---
 src/applications/gqrx/receiver.cpp | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp
index 59017a6..4c5fcbb 100644
--- a/src/applications/gqrx/receiver.cpp
+++ b/src/applications/gqrx/receiver.cpp
@@ -272,8 +272,11 @@ void receiver::set_output_device(const std::string device)
 
     tb->lock();
 
-    tb->disconnect(audio_gain0, 0, audio_snk, 0);
-    tb->disconnect(audio_gain1, 0, audio_snk, 1);
+    if (d_demod != RX_DEMOD_OFF)
+    {
+        tb->disconnect(audio_gain0, 0, audio_snk, 0);
+        tb->disconnect(audio_gain1, 0, audio_snk, 1);
+    }
     audio_snk.reset();
 
 #ifdef WITH_PULSEAUDIO
@@ -284,8 +287,11 @@ void receiver::set_output_device(const std::string device)
     audio_snk = gr::audio::sink::make(d_audio_rate, device, true);
 #endif
 
-    tb->connect(audio_gain0, 0, audio_snk, 0);
-    tb->connect(audio_gain1, 0, audio_snk, 1);
+    if (d_demod != RX_DEMOD_OFF)
+    {
+        tb->connect(audio_gain0, 0, audio_snk, 0);
+        tb->connect(audio_gain1, 0, audio_snk, 1);
+    }
 
     tb->unlock();
 }

From a038f897fc168ce981ab56a2ba0f41518ba6f7ce Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 12 Feb 2017 17:13:35 +0100
Subject: [PATCH 194/334] Properly restore AGC on/off setting

---
 src/qtgui/dockrxopt.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 92ac051..1f234c7 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -463,6 +463,8 @@ void DockRxOpt::saveSettings(QSettings *settings)
     // AGC Off
     if (ui->agcPresetCombo->currentIndex() == 4)
         settings->setValue("receiver/agc_off", true);
+    else
+        settings->remove("receiver/agc_off");
 }
 
 /**

From f5fec3d9adf13a6a23816d5558f333ba434863c2 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 12 Feb 2017 17:20:53 +0100
Subject: [PATCH 195/334] Use convention CW=USB and CWR=LSB

---
 src/applications/gqrx/remote_control.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index 51d06d2..c7707b4 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -380,7 +380,7 @@ int RemoteControl::modeStrToInt(QString mode_str)
     }
     else if (mode_str.compare("CW", Qt::CaseInsensitive) == 0)
     {
-        mode_int = 8;
+        mode_int = 9;
         hamlib_compatible = true;
     }
     else if (mode_str.compare("CWL", Qt::CaseInsensitive) == 0)
@@ -390,7 +390,7 @@ int RemoteControl::modeStrToInt(QString mode_str)
     }
     else if (mode_str.compare("CWR", Qt::CaseInsensitive) == 0)
     {
-        mode_int = 9;
+        mode_int = 8;
         hamlib_compatible = true;
     }
     else if (mode_str.compare("CWU", Qt::CaseInsensitive) == 0)
@@ -449,11 +449,11 @@ QString RemoteControl::intToModeStr(int mode)
         break;
 
     case 8:
-        mode_str = (hamlib_compatible) ? "CW" : "CWL";
+        mode_str = (hamlib_compatible) ? "CWR" : "CWL";
         break;
 
     case 9:
-        mode_str = (hamlib_compatible) ? "CWR" : "CWU";
+        mode_str = (hamlib_compatible) ? "CW" : "CWU";
         break;
 
     case 10:
@@ -504,7 +504,7 @@ QString RemoteControl::cmd_set_mode(QStringList cmdlist)
     QString cmd_arg = cmdlist.value(1, "");
 
     if (cmd_arg == "?")
-        answer = QString("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWL CWR CWU\n");
+        answer = QString("OFF RAW AM FM WFM WFM_ST WFM_ST_OIRT LSB USB CW CWU CWR CWL\n");
     else
     {
         int mode = modeStrToInt(cmd_arg);

From c705aff8c9876108952a543d4ff03e81bd20f2e8 Mon Sep 17 00:00:00 2001
From: Alexander Fasching 
Date: Thu, 16 Feb 2017 15:49:30 +0100
Subject: [PATCH 196/334] Add checkbox to select freqCtrl reset behavior

* Button is added to input-control widget
* Reset enabled by default
---
 src/applications/gqrx/mainwindow.cpp | 12 ++++++++----
 src/applications/gqrx/mainwindow.h   |  1 +
 src/qtgui/dockinputctl.cpp           | 23 +++++++++++++++++++++++
 src/qtgui/dockinputctl.h             |  4 ++++
 src/qtgui/dockinputctl.ui            | 10 ++++++++++
 5 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 1654867..f9309d0 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -192,6 +192,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
     connect(uiDockInputCtl, SIGNAL(iqBalanceChanged(bool)), this, SLOT(setIqBalance(bool)));
     connect(uiDockInputCtl, SIGNAL(ignoreLimitsChanged(bool)), this, SLOT(setIgnoreLimits(bool)));
     connect(uiDockInputCtl, SIGNAL(antennaSelected(QString)), this, SLOT(setAntenna(QString)));
+    connect(uiDockInputCtl, SIGNAL(freqCtrlResetChanged(bool)), this, SLOT(setFreqCtrlReset(bool)));
     connect(uiDockRxOpt, SIGNAL(filterOffsetChanged(qint64)), this, SLOT(setFilterOffset(qint64)));
     connect(uiDockRxOpt, SIGNAL(filterOffsetChanged(qint64)), remote, SLOT(setFilterOffset(qint64)));
     connect(uiDockRxOpt, SIGNAL(demodSelected(int)), this, SLOT(selectDemod(int)));
@@ -453,10 +454,6 @@ bool MainWindow::loadConfig(const QString cfgfile, bool check_crash,
         restoreState(m_settings->value("gui/state", saveState()).toByteArray());
     }
 
-    // misc GUI settings
-    bool_val = m_settings->value("gui/fctl_reset_digits", true).toBool();
-    ui->freqCtrl->setResetLowerDigits(bool_val);
-
     QString indev = m_settings->value("input/device", "").toString();
     if (!indev.isEmpty())
     {
@@ -932,6 +929,13 @@ void MainWindow::setIgnoreLimits(bool ignore_limits)
     setNewFrequency(freq);
 }
 
+
+/** Reset lower digits of main frequency control widget */
+void MainWindow::setFreqCtrlReset(bool enabled)
+{
+    ui->freqCtrl->setResetLowerDigits(enabled);
+}
+
 /**
  * @brief Select new demodulator.
  * @param demod New demodulator.
diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h
index 01b23b0..3d334de 100644
--- a/src/applications/gqrx/mainwindow.h
+++ b/src/applications/gqrx/mainwindow.h
@@ -139,6 +139,7 @@ private slots:
     void setDcCancel(bool enabled);
     void setIqBalance(bool enabled);
     void setIgnoreLimits(bool ignore_limits);
+    void setFreqCtrlReset(bool enabled);
     void selectDemod(QString demod);
     void selectDemod(int index);
     void setFmMaxdev(float max_dev);
diff --git a/src/qtgui/dockinputctl.cpp b/src/qtgui/dockinputctl.cpp
index 033d8d7..3a299b8 100644
--- a/src/qtgui/dockinputctl.cpp
+++ b/src/qtgui/dockinputctl.cpp
@@ -104,6 +104,11 @@ void DockInputCtl::readSettings(QSettings * settings)
             emit gainChanged(gain_name, gain_value);
         }
     }
+
+    // misc GUI settings
+    bool_val = settings->value("gui/fctl_reset_digits", true).toBool();
+    emit freqCtrlResetChanged(bool_val);
+    ui->freqCtrlResetButton->setChecked(bool_val);
 }
 
 void DockInputCtl::saveSettings(QSettings * settings)
@@ -159,6 +164,12 @@ void DockInputCtl::saveSettings(QSettings * settings)
         settings->setValue("input/antenna", ui->antSelector->currentText());
     else
         settings->remove("input/antenna");
+
+    // Remember state of freqReset button. Default is checked.
+    if (!ui->freqCtrlResetButton->isChecked())
+        settings->setValue("gui/fctl_reset_digits", false);
+    else
+        settings->remove("gui/fctl_reset_digits");
 }
 
 void DockInputCtl::readLnbLoFromSettings(QSettings * settings)
@@ -325,6 +336,12 @@ void DockInputCtl::setAntenna(const QString &antenna)
         ui->antSelector->setCurrentIndex(index);
 }
 
+/** Enable/disable resetting lower digits on freqCtrl widgets */
+void DockInputCtl::setFreqCtrlReset(bool enabled)
+{
+    ui->freqCtrlResetButton->setChecked(enabled);
+}
+
 /**
  * Set gain stages.
  * @param gain_list A list containing the gain stages for this device.
@@ -484,6 +501,12 @@ void DockInputCtl::on_antSelector_currentIndexChanged(const QString &antenna)
     emit antennaSelected(antenna);
 }
 
+/** Reset box has changed */
+void DockInputCtl::on_freqCtrlResetButton_toggled(bool checked)
+{
+    emit freqCtrlResetChanged(checked);
+}
+
 /** Remove all widgets from the lists. */
 void DockInputCtl::clearWidgets()
 {
diff --git a/src/qtgui/dockinputctl.h b/src/qtgui/dockinputctl.h
index 945f7d9..a6974df 100644
--- a/src/qtgui/dockinputctl.h
+++ b/src/qtgui/dockinputctl.h
@@ -101,6 +101,8 @@ class DockInputCtl : public QDockWidget
     void    setGainStages(gain_list_t &gain_list);
     void    restoreManualGains(QSettings *settings);
 
+    void    setFreqCtrlReset(bool enabled);
+
 signals:
     void gainChanged(QString name, double value);
     void autoGainChanged(bool enabled);
@@ -111,6 +113,7 @@ class DockInputCtl : public QDockWidget
     void iqBalanceChanged(bool enabled);
     void ignoreLimitsChanged(bool ignore);
     void antennaSelected(QString antenna);
+    void freqCtrlResetChanged(bool enabled);
 
 private slots:
     void on_lnbSpinBox_valueChanged(double value);
@@ -121,6 +124,7 @@ private slots:
     void on_iqBalanceButton_toggled(bool checked);
     void on_ignoreButton_toggled(bool checked);
     void on_antSelector_currentIndexChanged(const QString &antenna);
+    void on_freqCtrlResetButton_toggled(bool checked);
 
     void sliderValueChanged(int value);
 
diff --git a/src/qtgui/dockinputctl.ui b/src/qtgui/dockinputctl.ui
index fac3443..4d21b4b 100644
--- a/src/qtgui/dockinputctl.ui
+++ b/src/qtgui/dockinputctl.ui
@@ -214,6 +214,16 @@
       
      
     
+    
+     
+      
+       Reset lower digits of main frequency control widget
+      
+      
+       Reset frequency control
+      
+     
+    
     
      
       

From 89097d95379a339f828ed21af8490331a7872eb4 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 16 Feb 2017 20:11:00 +0100
Subject: [PATCH 197/334] Minor UI tweaks on inputctl

---
 src/qtgui/dockinputctl.ui | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/qtgui/dockinputctl.ui b/src/qtgui/dockinputctl.ui
index 4d21b4b..6c08f55 100644
--- a/src/qtgui/dockinputctl.ui
+++ b/src/qtgui/dockinputctl.ui
@@ -214,13 +214,20 @@
       
      
     
+    
+     
+      
+       Qt::Horizontal
+      
+     
+    
     
      
       
-       Reset lower digits of main frequency control widget
+       <html><head/><body><p>Reset subordinate digits in main frequency control widget</p></body></html>
       
       
-       Reset frequency control
+       Reset frequency controller digits
       
      
     

From ade22f9fb723ddf0f2619d198eaf8596794878cb Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 16 Feb 2017 20:25:56 +0100
Subject: [PATCH 198/334] Update news.txt

---
 resources/news.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/resources/news.txt b/resources/news.txt
index d885f34..244bb08 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -8,7 +8,11 @@
      FIXED: RDS status is not kept while jumping through bookmark.
   IMPROVED: Tuning through the remote control interface.
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
-  IMPROVED: Config record for reverting the behavior of the freq. controller
+
+
+     2.6.1: Released February 16, 2017
+
+  IMPROVED: Option for reverting the behavior of the frequency controller.
 
 
        2.6: Released October 3, 2016

From 80f008f066aa5495509dc2ae865a75c57b1971f7 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 19 Feb 2017 12:23:43 +0100
Subject: [PATCH 199/334] Add example sample rates for LimeSDR

---
 resources/news.txt     |  1 +
 src/qtgui/ioconfig.cpp | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/resources/news.txt b/resources/news.txt
index 244bb08..4fbdc89 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -8,6 +8,7 @@
      FIXED: RDS status is not kept while jumping through bookmark.
   IMPROVED: Tuning through the remote control interface.
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
+  IMPROVED: LimeSDR integration.
 
 
      2.6.1: Released February 16, 2017
diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp
index 557cdf6..43bb8d4 100644
--- a/src/qtgui/ioconfig.cpp
+++ b/src/qtgui/ioconfig.cpp
@@ -552,6 +552,24 @@ void CIoConfig::updateInputSampleRates(int rate)
         else
             ui->inSrCombo->setCurrentIndex(9); // select 2048 kHz
     }
+    else if (ui->inDevEdit->text().contains("lime"))
+    {
+        ui->inSrCombo->addItem("100000");
+        ui->inSrCombo->addItem("500000");
+        ui->inSrCombo->addItem("1000000");
+        ui->inSrCombo->addItem("2500000");
+        ui->inSrCombo->addItem("5000000");
+        ui->inSrCombo->addItem("10000000");
+        ui->inSrCombo->addItem("20000000");
+        ui->inSrCombo->addItem("50000000");
+        if (rate > 0)
+        {
+            ui->inSrCombo->insertItem(0, QString("%1").arg(rate));
+            ui->inSrCombo->setCurrentIndex(0);
+        }
+        else
+            ui->inSrCombo->setCurrentIndex(4); // select 5 MHz
+    }
     else
     {
         if (rate > 0)

From 958266aa276db80afa8b1a3d08a16b30e4c85499 Mon Sep 17 00:00:00 2001
From: Alexander Fasching 
Date: Thu, 2 Mar 2017 10:31:45 +0100
Subject: [PATCH 200/334] Check if new and old file are equal

---
 src/applications/gqrx/mainwindow.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index f9309d0..e3fb659 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -635,6 +635,11 @@ bool MainWindow::saveConfig(const QString cfgfile)
     else
         newfile = QString("%1/%2").arg(m_cfg_dir).arg(cfgfile);
 
+    if (newfile == oldfile) {
+        qDebug() << "New file is equal to old file => SYNCING...";
+        return true;
+    }
+
     if (QFile::exists(newfile))
     {
         qDebug() << "File" << newfile << "already exists => DELETING...";

From 66fe433ba5c9b74e7d2cefd7c35fc484b7938511 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 2 Mar 2017 23:55:37 +0100
Subject: [PATCH 201/334] Enable custom Airspy kernels by default

---
 CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b73dc31..291e609 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,7 +105,7 @@ find_package(Gnuradio REQUIRED)
 find_package(Gnuradio-osmosdr REQUIRED)
 
 if(NOT GNURADIO_RUNTIME_FOUND)
-    message(FATAL_ERROR "GnuRadio Runtime required to compile gr-air-modes")
+    message(FATAL_ERROR "GnuRadio Runtime required to compile gqrx")
 endif()
 
 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@@ -147,7 +147,7 @@ endif()
 
 
 # Airspy optimizations that require modified gr-osmosdr
-option(CUSTOM_AIRSPY_KERNELS "Enable non-standard Airspy optimizations" OFF)
+option(CUSTOM_AIRSPY_KERNELS "Enable non-standard Airspy optimizations" ON)
 if(CUSTOM_AIRSPY_KERNELS)
     add_definitions(-DCUSTOM_AIRSPY_KERNELS)
 endif(CUSTOM_AIRSPY_KERNELS)

From 74db13fefd8d99eaebebad580fab2ffd15ca79ff Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 5 Mar 2017 17:47:04 +0100
Subject: [PATCH 202/334] Update news.txt

---
 resources/news.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/news.txt b/resources/news.txt
index 4fbdc89..d0131e5 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -6,6 +6,7 @@
        NEW: Support for passband when setting mode through remote.
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
      FIXED: RDS status is not kept while jumping through bookmark.
+     FIXED: .conf files are deleted when changes are saved.
   IMPROVED: Tuning through the remote control interface.
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
   IMPROVED: LimeSDR integration.

From 821576b91ccc187059a4fd77550f38cbb18a5ac9 Mon Sep 17 00:00:00 2001
From: Alexander Fasching 
Date: Tue, 14 Mar 2017 21:14:18 +0100
Subject: [PATCH 203/334] Disable detected proxy settings

---
 src/applications/gqrx/remote_control.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index c7707b4..f0afa59 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -49,6 +49,9 @@ RemoteControl::RemoteControl(QObject *parent) :
 
     rc_socket = 0;
 
+    // Disable proxy setting detected by Qt
+    rc_server.setProxy(QNetworkProxy::NoProxy);
+
     connect(&rc_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
 
 }

From a6c92ad9c5ecece675191da296757be331fddadc Mon Sep 17 00:00:00 2001
From: Alexander Fasching 
Date: Tue, 14 Mar 2017 22:37:59 +0100
Subject: [PATCH 204/334] Add workaround for Qt versions < 5.9

---
 src/applications/gqrx/remote_control.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp
index f0afa59..705b661 100644
--- a/src/applications/gqrx/remote_control.cpp
+++ b/src/applications/gqrx/remote_control.cpp
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "remote_control.h"
 
 #define DEFAULT_RC_PORT            7356
@@ -49,8 +50,12 @@ RemoteControl::RemoteControl(QObject *parent) :
 
     rc_socket = 0;
 
+#if QT_VERSION < 0x050900
     // Disable proxy setting detected by Qt
+    // Workaround for https://bugreports.qt.io/browse/QTBUG-58374
+    // Fix: https://codereview.qt-project.org/#/c/186124/
     rc_server.setProxy(QNetworkProxy::NoProxy);
+#endif
 
     connect(&rc_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
 

From 8bcbd96aeb7274a312b85b270a8fb311ea989b52 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Wed, 15 Mar 2017 00:39:56 +0100
Subject: [PATCH 205/334] Update news.txt

---
 resources/news.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/news.txt b/resources/news.txt
index d0131e5..5ba868f 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -7,6 +7,7 @@
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
      FIXED: RDS status is not kept while jumping through bookmark.
      FIXED: .conf files are deleted when changes are saved.
+     FIXED: Remote control not working if $http_proxy is set.
   IMPROVED: Tuning through the remote control interface.
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
   IMPROVED: LimeSDR integration.

From 36f94578d5abe2cbb626c83b2c122895a5a865e9 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 16 Mar 2017 00:15:09 +0100
Subject: [PATCH 206/334] Add spin button for entering receiver frequency

---
 src/applications/gqrx/mainwindow.cpp |   3 +
 src/qtgui/dockrxopt.cpp              |  18 ++
 src/qtgui/dockrxopt.h                |   6 +
 src/qtgui/dockrxopt.ui               | 454 +++++++++++++++------------
 4 files changed, 272 insertions(+), 209 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index e3fb659..72725cc 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -183,6 +183,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
     connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), this, SLOT(setNewFrequency(qint64)));
     connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), remote, SLOT(setNewFrequency(qint64)));
     connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), uiDockAudio, SLOT(setRxFrequency(qint64)));
+    connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), uiDockRxOpt, SLOT(setRxFreq(qint64)));
     connect(uiDockInputCtl, SIGNAL(lnbLoChanged(double)), this, SLOT(setLnbLo(double)));
     connect(uiDockInputCtl, SIGNAL(gainChanged(QString, double)), this, SLOT(setGain(QString,double)));
     connect(uiDockInputCtl, SIGNAL(autoGainChanged(bool)), this, SLOT(setAutoGain(bool)));
@@ -193,6 +194,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
     connect(uiDockInputCtl, SIGNAL(ignoreLimitsChanged(bool)), this, SLOT(setIgnoreLimits(bool)));
     connect(uiDockInputCtl, SIGNAL(antennaSelected(QString)), this, SLOT(setAntenna(QString)));
     connect(uiDockInputCtl, SIGNAL(freqCtrlResetChanged(bool)), this, SLOT(setFreqCtrlReset(bool)));
+    connect(uiDockRxOpt, SIGNAL(rxFreqChanged(qint64)), ui->freqCtrl, SLOT(setFrequency(qint64)));
     connect(uiDockRxOpt, SIGNAL(filterOffsetChanged(qint64)), this, SLOT(setFilterOffset(qint64)));
     connect(uiDockRxOpt, SIGNAL(filterOffsetChanged(qint64)), remote, SLOT(setFilterOffset(qint64)));
     connect(uiDockRxOpt, SIGNAL(demodSelected(int)), this, SLOT(selectDemod(int)));
@@ -744,6 +746,7 @@ void MainWindow::updateFrequencyRange()
     qint64 stop  = (qint64)(rx->get_filter_offset()) + d_hw_freq_stop  + d_lnb_lo;
 
     ui->freqCtrl->setup(10, start, stop, 1, UNITS_MHZ);
+    uiDockRxOpt->setRxFreqRange(start, stop);
 }
 
 /**
diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index 1f234c7..ede6b1e 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -467,6 +467,24 @@ void DockRxOpt::saveSettings(QSettings *settings)
         settings->remove("receiver/agc_off");
 }
 
+/** RX frequency changed through spin box */
+void DockRxOpt::on_freqSpinBox_valueChanged(double freq)
+{
+    emit rxFreqChanged(1.e3 * freq);
+}
+
+void DockRxOpt::setRxFreq(qint64 freq_hz)
+{
+    ui->freqSpinBox->blockSignals(true);
+    ui->freqSpinBox->setValue(1.e-3 * (double)freq_hz);
+    ui->freqSpinBox->blockSignals(false);
+}
+
+void DockRxOpt::setRxFreqRange(qint64 min_hz, qint64 max_hz)
+{
+    ui->freqSpinBox->setRange(1.e-3 * (double)min_hz, 1.e-3 * (double)max_hz);
+}
+
 /**
  * @brief Channel filter offset has changed
  * @param freq The new filter offset in Hz
diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h
index 3564992..1bb47ed 100644
--- a/src/qtgui/dockrxopt.h
+++ b/src/qtgui/dockrxopt.h
@@ -94,6 +94,7 @@ class DockRxOpt : public QDockWidget
     int  currentFilterShape() const;
 
     void setHwFreq(qint64 freq_hz);
+    void setRxFreqRange(qint64 min_hz, qint64 max_hz);
 
     int  currentDemod() const;
     QString currentDemodAsString();
@@ -111,6 +112,7 @@ class DockRxOpt : public QDockWidget
     static bool IsModulationValid(QString strModulation);
 
 public slots:
+    void setRxFreq(qint64 freq_hz);
     void setCurrentDemod(int demod);
     void setFilterOffset(qint64 freq_hz);
     void setSquelchLevel(double level);
@@ -121,6 +123,9 @@ public slots:
     unsigned int filterIdxFromLoHi(int lo, int hi) const;
 
 signals:
+    /** Signal emitted when receiver frequency has changed */
+    void rxFreqChanged(qint64 freq_hz);
+
     /** Signal emitted when the channel filter frequency has changed. */
     void filterOffsetChanged(qint64 freq_hz);
 
@@ -173,6 +178,7 @@ public slots:
     void cwOffsetChanged(int offset);
 
 private slots:
+    void on_freqSpinBox_valueChanged(double freq);
     void on_filterFreq_newFrequency(qint64 freq);
     void on_filterCombo_activated(int index);
     void on_modeSelector_activated(int index);
diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui
index b66265a..7fbef4c 100644
--- a/src/qtgui/dockrxopt.ui
+++ b/src/qtgui/dockrxopt.ui
@@ -7,7 +7,7 @@
     0
     0
     266
-    300
+    313
    
   
   
@@ -19,7 +19,7 @@
   
    
     266
-    300
+    313
    
   
   
@@ -134,23 +134,150 @@ This is an offset from the hardware RF frequency.</p></body></htm
       
        5
       
-      
-       
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         
+          50
+          30
+         
+        
+        
+         
+          16777215
+          16777215
+         
+        
+        
+         Set squelch to the current signal or noise level
+        
+        
+         A
+        
+        
+         
+          16
+          16
+         
+        
+       
+      
+      
+       
         
          
           0
           0
          
         
+        
+         Squelch level in dB below full scale
+        
         
-         Filter width
+         Squelch
         
         
          Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
        
       
-      
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         
+          50
+          30
+         
+        
+        
+         
+          16777215
+          16777215
+         
+        
+        
+         AGC options
+        
+        
+         ...
+        
+        
+         
+          16
+          16
+         
+        
+        
+         false
+        
+       
+      
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         Demodulator type (mode)
+        
+        
+         Demodulator type (mode)
+        
+        
+         -1
+        
+        
+         30
+        
+       
+      
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         
+          50
+          30
+         
+        
+        
+         
+          16777215
+          16777215
+         
+        
+        
+         Noise blanker options
+        
+        
+         Noise blanker options
+        
+        
+         ...
+        
+       
+      
+      
        
         
          true
@@ -189,54 +316,44 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
        
       
-      
-       
+      
+       
         
-         
+         
           0
           0
          
         
-        
-         Filter shape
+        
+         Squelch level in dB below full scale
         
         
          Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
-       
-      
-      
-       
-        
-         
-          0
-          0
-         
+        
+         true
         
-        
-         Select the filter shape
+        
+          dBFS
         
-        
+        
          1
         
-        
-         
-          Soft
-         
-        
-        
-         
-          Normal
-         
-        
-        
-         
-          Sharp
-         
-        
+        
+         -150.000000000000000
+        
+        
+         0.000000000000000
+        
+        
+         1.000000000000000
+        
+        
+         -150.000000000000000
+        
        
       
-      
+      
        
         
          
@@ -258,29 +375,42 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
        
       
-      
-       
+      
+       
         
-         
+         
           0
           0
          
         
         
-         Demodulator type (mode)
+         Noise blanker settings
         
-        
-         Demodulator type (mode)
+        
+         Noise blanker
         
-        
-         -1
+        
+         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
-        
-         30
+       
+      
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         Filter shape
+        
+        
+         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
        
       
-      
+      
        
         
          
@@ -317,7 +447,23 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
        
       
-      
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         Filter width
+        
+        
+         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+        
+       
+      
+      
        
         
          
@@ -333,7 +479,7 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
        
       
-      
+      
        
         
          true
@@ -377,64 +523,8 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
        
       
-      
-       
-        
-         
-          0
-          0
-         
-        
-        
-         
-          50
-          30
-         
-        
-        
-         
-          16777215
-          16777215
-         
-        
-        
-         AGC options
-        
-        
-         ...
-        
-        
-         
-          16
-          16
-         
-        
-        
-         false
-        
-       
-      
-      
-       
-        
-         
-          0
-          0
-         
-        
-        
-         Squelch level in dB below full scale
-        
-        
-         Squelch
-        
-        
-         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-        
-       
-      
-      
-       
+      
+       
         
          
           0
@@ -442,88 +532,29 @@ This is an offset from the hardware RF frequency.</p></body></htm
          
         
         
-         Squelch level in dB below full scale
-        
-        
-         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-        
-        
-         true
-        
-        
-          dBFS
+         Select the filter shape
         
-        
+        
          1
         
-        
-         -150.000000000000000
-        
-        
-         0.000000000000000
-        
-        
-         1.000000000000000
-        
-        
-         -150.000000000000000
-        
-       
-      
-      
-       
-        
-         
-          0
-          0
-         
-        
-        
-         
-          50
-          30
-         
-        
-        
-         
-          16777215
-          16777215
-         
-        
-        
-         Set squelch to the current signal or noise level
-        
-        
-         A
-        
-        
-         
-          16
-          16
-         
-        
-       
-      
-      
-       
-        
-         
-          0
-          0
-         
-        
-        
-         Noise blanker settings
-        
-        
-         Noise blanker
-        
-        
-         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-        
+        
+         
+          Soft
+         
+        
+        
+         
+          Normal
+         
+        
+        
+         
+          Sharp
+         
+        
        
       
-      
+      
        
         
          5
@@ -604,34 +635,39 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
        
       
-      
-       
-        
-         
-          0
-          0
-         
+      
+       
+        
+         Frequency
         
-        
-         
-          50
-          30
-         
+        
+         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
-        
-         
-          16777215
-          16777215
-         
+       
+      
+      
+       
+        
+         Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
-        
-         Noise blanker options
+        
+         3
         
-        
-         Noise blanker options
+        
+         24000.000000000000000
         
+        
+         2200000.000000000000000
+        
+        
+         144500.000000000000000
+        
+       
+      
+      
+       
         
-         ...
+         kHz
         
        
       

From c157d00352bf6688cf03903c921bd8a88b372935 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 16 Mar 2017 00:22:48 +0100
Subject: [PATCH 207/334] Set accessibleName property for some control widgets

---
 src/qtgui/dockrxopt.ui | 49 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui
index 7fbef4c..89e47a7 100644
--- a/src/qtgui/dockrxopt.ui
+++ b/src/qtgui/dockrxopt.ui
@@ -157,6 +157,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Set squelch to the current signal or noise level
         
+        
+         Auto squelch
+        
         
          A
         
@@ -210,6 +213,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          AGC options
         
+        
+         AGC options
+        
         
          ...
         
@@ -238,6 +244,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Demodulator type (mode)
         
+        
+         Mode
+        
         
          -1
         
@@ -272,6 +281,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Noise blanker options
         
+        
+         Noise blanker options
+        
         
          ...
         
@@ -291,6 +303,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Apply mode dependent filter preset
         
+        
+         Filter width
+        
         
          1
         
@@ -327,6 +342,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Squelch level in dB below full scale
         
+        
+         Squelch
+        
         
          Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
@@ -433,6 +451,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Demodulator options
         
+        
+         Mode options
+        
         
          ...
         
@@ -493,6 +514,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          AGC presets
         
+        
+         AGC
+        
         
          1
         
@@ -534,6 +558,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
         
          Select the filter shape
         
+        
+         Filter shape
+        
         
          1
         
@@ -588,6 +615,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
           
            
           
+          
+           Noise blanker 1
+          
           
            NB1
           
@@ -625,6 +655,9 @@ This is an offset from the hardware RF frequency.</p></body></htm
           
            
           
+          
+           Noise blanker 2
+          
           
            NB2
           
@@ -647,6 +680,12 @@ This is an offset from the hardware RF frequency.</p></body></htm
       
       
        
+        
+         Receiver frequency
+        
+        
+         Frequency
+        
         
          Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
         
@@ -698,8 +737,18 @@ This is an offset from the hardware RF frequency.</p></body></htm
   
  
  
+  freqSpinBox
+  filterCombo
+  filterShapeCombo
+  modeSelector
+  modeButton
+  agcPresetCombo
+  agcButton
+  sqlSpinBox
+  autoSquelchButton
   nb1Button
   nb2Button
+  nbOptButton
  
  
   

From 4a66a03fcdd5ef1d929825d67793b0111c81e79a Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 16 Mar 2017 00:23:00 +0100
Subject: [PATCH 208/334] Update news file

---
 resources/news.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/resources/news.txt b/resources/news.txt
index 5ba868f..77f6ac3 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -4,6 +4,7 @@
        NEW: Restore FM parameters between sessions.
        NEW: Restore remote control state between sessions.
        NEW: Support for passband when setting mode through remote.
+       NEW: Widget to enter receiver frequency.
      FIXED: Keep waterfall zoom level and zoom slider synchronised.
      FIXED: RDS status is not kept while jumping through bookmark.
      FIXED: .conf files are deleted when changes are saved.
@@ -11,6 +12,7 @@
   IMPROVED: Tuning through the remote control interface.
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
   IMPROVED: LimeSDR integration.
+  IMPROVED: Voiceover interface.
 
 
      2.6.1: Released February 16, 2017

From 76026656a2d6db73e5b3f2b5a92d58914b6ba6e3 Mon Sep 17 00:00:00 2001
From: Panagiotis Nikolaou 
Date: Sat, 25 Mar 2017 14:33:37 -0700
Subject: [PATCH 209/334] Add Accessories categorie for xfce

Xfce missing Network and HamRadio caregories.
---
 gqrx.desktop | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gqrx.desktop b/gqrx.desktop
index 021a206..5bd3085 100644
--- a/gqrx.desktop
+++ b/gqrx.desktop
@@ -12,5 +12,5 @@ Comment[de]=Software defined Radio auf Basis von GNU Radio und dem Qt GUI Toolki
 Exec=gqrx
 Terminal=false
 Icon=gqrx
-Categories=Network;HamRadio;
+Categories=Network;HamRadio;Accessories;
 Keywords=SDR;Radio;HAM;

From 1ad103e293ae3956ed291afe0138a1da724a869c Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 2 Apr 2017 20:16:37 +0200
Subject: [PATCH 210/334] Add two-stage FIR decimator design by Youssef Touil

---
 src/dsp/filter/fir_decim.cpp    |  117 +++
 src/dsp/filter/fir_decim_coef.h | 1437 +++++++++++++++++++++++++++++++
 2 files changed, 1554 insertions(+)

diff --git a/src/dsp/filter/fir_decim.cpp b/src/dsp/filter/fir_decim.cpp
index 192c63e..d7fdf64 100644
--- a/src/dsp/filter/fir_decim.cpp
+++ b/src/dsp/filter/fir_decim.cpp
@@ -4,6 +4,7 @@
  *           http://gqrx.dk/
  *
  * Copyright 2016 Alexandru Csete OZ9AEC.
+ * Copyright 2017 Youssef Touil.
  *
  * Gqrx is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,6 +31,68 @@
 #include "fir_decim.h"
 #include "fir_decim_coef.h"
 
+#ifdef USE_NEW_FIR_DECIM
+struct decimation_stage
+{
+    int         decimation;
+    int         ratio;
+    int         length;
+    const float *kernel;
+};
+
+static const int decimation_stage_count = 8;
+static const decimation_stage decimation_stages[] =
+{
+    {
+        2,
+        2,
+        d_2_r_2_len,
+        d_2_r_2_kernel
+    },
+    {
+        4,
+        4,
+        d_4_r_4_len,
+        d_4_r_4_kernel
+    },
+    {
+        8,
+        8,
+        d_8_r_8_len,
+        d_8_r_8_kernel
+    },
+    {
+        16,
+        8,
+        d_16_r_8_len,
+        d_16_r_8_kernel
+    },
+    {
+        32,
+        16,
+        d_32_r_16_len,
+        d_32_r_16_kernel
+    },
+    {
+        64,
+        32,
+        d_64_r_32_len,
+        d_64_r_32_kernel
+    },
+    {
+        128,
+        32,
+        d_128_r_32_len,
+        d_128_r_32_kernel
+    },
+    {
+        256,
+        64,
+        d_256_r_64_len,
+        d_256_r_64_kernel
+    }
+};
+#endif
 
 fir_decim_cc_sptr make_fir_decim_cc(unsigned int decim)
 {
@@ -43,6 +106,59 @@ fir_decim_cc::fir_decim_cc(unsigned int decim)
 {
     std::vector  taps;
 
+#ifdef USE_NEW_FIR_DECIM
+    int this_stage = 0;
+    int index = decimation_stage_count - 1;
+
+    std::cout << "Decimation: " << decim << std::endl;
+    while (decim > 1 && index >= 0)
+    {
+        auto stage = &decimation_stages[index];
+
+        if (decim % stage->decimation == 0)
+        {
+            this_stage++;
+            taps.assign(stage->kernel, stage->kernel + stage->length);
+            if (this_stage == 1)
+                fir1 = gr::filter::fir_filter_ccf::make(stage->ratio, taps);
+            else if (this_stage == 2)
+                fir2 = gr::filter::fir_filter_ccf::make(stage->ratio, taps);
+            else if (this_stage == 3)  // NB: currently max 2 stages
+                fir3 = gr::filter::fir_filter_ccf::make(stage->ratio, taps);
+            else
+                std::cout << "  Too many decimation stages: " << this_stage
+                          << std::endl;
+
+            std::cout << "  stage: " << this_stage << "  ratio: " << stage->ratio
+                      << std::endl;
+            decim /= stage->ratio;
+        }
+        else
+        {
+            index--;
+        }
+    }
+
+    if (this_stage == 1)
+    {
+        connect(self(), 0, fir1, 0);
+        connect(fir1, 0, self(), 0);
+    }
+    else if (this_stage == 2)
+    {
+        connect(self(), 0, fir1, 0);
+        connect(fir1, 0, fir2, 0);
+        connect(fir2, 0, self(), 0);
+    }
+    else
+    {
+        connect(self(), 0, fir1, 0);
+        connect(fir1, 0, fir2, 0);
+        connect(fir2, 0, fir3, 0);
+        connect(fir3, 0, self(), 0);
+    }
+
+#else
     switch (decim)
     {
     default:
@@ -152,6 +268,7 @@ fir_decim_cc::fir_decim_cc(unsigned int decim)
         connect(fir3, 0, self(), 0);
         break;
     }
+#endif
 }
 
 fir_decim_cc::~fir_decim_cc()
diff --git a/src/dsp/filter/fir_decim_coef.h b/src/dsp/filter/fir_decim_coef.h
index d32cecc..315ede5 100644
--- a/src/dsp/filter/fir_decim_coef.h
+++ b/src/dsp/filter/fir_decim_coef.h
@@ -4,6 +4,7 @@
  *           http://gqrx.dk/
  *
  * Copyright 2016 Alexandru Csete OZ9AEC.
+ * Copyright 2017 Youssef Touil. 
  *
  * Gqrx is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +23,1439 @@
  */
 #pragma once
 
+#define USE_NEW_FIR_DECIM
+
+#ifdef USE_NEW_FIR_DECIM
+// New two-stage FIR decimator provided by Youssef
+
+static const int d_2_r_2_len = 69;
+static const float d_2_r_2_kernel[] =
+{
+	 0.000399985734121014f,
+	 0.002073370222476234f,
+	 0.004853019240304940f,
+	 0.005977464755456102f,
+	 0.002625480716699286f,
+	-0.002713628293157090f,
+	-0.003379460736391527f,
+	 0.001637205667907783f,
+	 0.004080689203761314f,
+	-0.000982433398470081f,
+	-0.005119016867477646f,
+	 0.000177424749467386f,
+	 0.006424890506348696f,
+	 0.001008090651156955f,
+	-0.007915926496343137f,
+	-0.002717062331286239f,
+	 0.009511042111613645f,
+	 0.005077150379032227f,
+	-0.011151300589456603f,
+	-0.008251061374053964f,
+	 0.012781117215688672f,
+	 0.012490374909303374f,
+	-0.014344287749952384f,
+	-0.018209086168089920f,
+	 0.015778580923975386f,
+	 0.026178028229057050f,
+	-0.017029165534577999f,
+	-0.038051941291319488f,
+	 0.018060406839966188f,
+	 0.058210457193828925f,
+	-0.018831122390764166f,
+	-0.102778567522516130f,
+	 0.019291268777910851f,
+	 0.317182812089170980f,
+	 0.480536048712957740f,
+	 0.317182812089170980f,
+	 0.019291268777910851f,
+	-0.102778567522516130f,
+	-0.018831122390764166f,
+	 0.058210457193828925f,
+	 0.018060406839966188f,
+	-0.038051941291319488f,
+	-0.017029165534577999f,
+	 0.026178028229057050f,
+	 0.015778580923975386f,
+	-0.018209086168089920f,
+	-0.014344287749952384f,
+	 0.012490374909303374f,
+	 0.012781117215688672f,
+	-0.008251061374053964f,
+	-0.011151300589456603f,
+	 0.005077150379032227f,
+	 0.009511042111613645f,
+	-0.002717062331286239f,
+	-0.007915926496343137f,
+	 0.001008090651156955f,
+	 0.006424890506348696f,
+	 0.000177424749467386f,
+	-0.005119016867477646f,
+	-0.000982433398470081f,
+	 0.004080689203761314f,
+	 0.001637205667907783f,
+	-0.003379460736391527f,
+	-0.002713628293157090f,
+	 0.002625480716699286f,
+	 0.005977464755456102f,
+	 0.004853019240304940f,
+	 0.002073370222476234f,
+	 0.000399985734121014f
+};
+
+static const int d_4_r_4_len = 139;
+static const float d_4_r_4_kernel[] =
+{
+	 0.000042167047949931f,
+	 0.000162480875041441f,
+	 0.000413474829003805f,
+	 0.000815488719349860f,
+	 0.001323484844111109f,
+	 0.001803932401530970f,
+	 0.002050805379425780f,
+	 0.001851476423100084f,
+	 0.001088358238163842f,
+	-0.000165599354540670f,
+	-0.001612840277093291f,
+	-0.002799173360323900f,
+	-0.003280737659419560f,
+	-0.002830930204582274f,
+	-0.001589296551711622f,
+	-0.000060142418430366f,
+	 0.001072157673911288f,
+	 0.001252059507347206f,
+	 0.000346781210023729f,
+	-0.001233491421169468f,
+	-0.002682865592015316f,
+	-0.003178340139233828f,
+	-0.002320119390193667f,
+	-0.000402092792444196f,
+	 0.001661437823975322f,
+	 0.002761727219457103f,
+	 0.002186981534424376f,
+	 0.000071307331744879f,
+	-0.002570893712874658f,
+	-0.004301512250227543f,
+	-0.004015094439084645f,
+	-0.001606879839533175f,
+	 0.001838674337622738f,
+	 0.004510048531846937f,
+	 0.004804547613530567f,
+	 0.002266863620581679f,
+	-0.002004704037111716f,
+	-0.005785548895574678f,
+	-0.006849655924079080f,
+	-0.004239720077392586f,
+	 0.001024318787772757f,
+	 0.006275193248599259f,
+	 0.008511512338709764f,
+	 0.006070603106211769f,
+	-0.000247611530141919f,
+	-0.007317511868656072f,
+	-0.011170336815604164f,
+	-0.009152698013614463f,
+	-0.001621157345452147f,
+	 0.007851435931989321f,
+	 0.014073238852672171f,
+	 0.012972692080589394f,
+	 0.004087473189926854f,
+	-0.008634954375856124f,
+	-0.018413964067748419f,
+	-0.019050011539439745f,
+	-0.008545626179408438f,
+	 0.009039966712164142f,
+	 0.024793283315122296f,
+	 0.029034181171149441f,
+	 0.016560363014866013f,
+	-0.009522346448795137f,
+	-0.037569562545468192f,
+	-0.051411140638474247f,
+	-0.037221789978391415f,
+	 0.009679493935209005f,
+	 0.081286213859684806f,
+	 0.158552299980228740f,
+	 0.217917169253869340f,
+	 0.240164834839879550f,
+	 0.217917169253869340f,
+	 0.158552299980228740f,
+	 0.081286213859684806f,
+	 0.009679493935209005f,
+	-0.037221789978391415f,
+	-0.051411140638474247f,
+	-0.037569562545468192f,
+	-0.009522346448795137f,
+	 0.016560363014866013f,
+	 0.029034181171149441f,
+	 0.024793283315122296f,
+	 0.009039966712164142f,
+	-0.008545626179408438f,
+	-0.019050011539439745f,
+	-0.018413964067748419f,
+	-0.008634954375856124f,
+	 0.004087473189926854f,
+	 0.012972692080589394f,
+	 0.014073238852672171f,
+	 0.007851435931989321f,
+	-0.001621157345452147f,
+	-0.009152698013614463f,
+	-0.011170336815604164f,
+	-0.007317511868656072f,
+	-0.000247611530141919f,
+	 0.006070603106211769f,
+	 0.008511512338709764f,
+	 0.006275193248599259f,
+	 0.001024318787772757f,
+	-0.004239720077392586f,
+	-0.006849655924079080f,
+	-0.005785548895574678f,
+	-0.002004704037111716f,
+	 0.002266863620581679f,
+	 0.004804547613530567f,
+	 0.004510048531846937f,
+	 0.001838674337622738f,
+	-0.001606879839533175f,
+	-0.004015094439084645f,
+	-0.004301512250227543f,
+	-0.002570893712874658f,
+	 0.000071307331744879f,
+	 0.002186981534424376f,
+	 0.002761727219457103f,
+	 0.001661437823975322f,
+	-0.000402092792444196f,
+	-0.002320119390193667f,
+	-0.003178340139233828f,
+	-0.002682865592015316f,
+	-0.001233491421169468f,
+	 0.000346781210023729f,
+	 0.001252059507347206f,
+	 0.001072157673911288f,
+	-0.000060142418430366f,
+	-0.001589296551711622f,
+	-0.002830930204582274f,
+	-0.003280737659419560f,
+	-0.002799173360323900f,
+	-0.001612840277093291f,
+	-0.000165599354540670f,
+	 0.001088358238163842f,
+	 0.001851476423100084f,
+	 0.002050805379425780f,
+	 0.001803932401530970f,
+	 0.001323484844111109f,
+	 0.000815488719349860f,
+	 0.000413474829003805f,
+	 0.000162480875041441f,
+	 0.000042167047949931f
+};
+
+static const int d_8_r_8_len = 280;
+static const float d_8_r_8_kernel[] =
+{
+	 0.000005299484859782f,
+	 0.000023653198869943f,
+	 0.000045443155025411f,
+	 0.000086660616597102f,
+	 0.000145468147843215f,
+	 0.000227646032445337f,
+	 0.000334591194217999f,
+	 0.000466890457500183f,
+	 0.000622018386430552f,
+	 0.000794466626663634f,
+	 0.000975304575250323f,
+	 0.001152454785657775f,
+	 0.001311296864337127f,
+	 0.001435783630074849f,
+	 0.001509953148215840f,
+	 0.001519741581366084f,
+	 0.001454903824191261f,
+	 0.001310813201213376f,
+	 0.001089882810057675f,
+	 0.000802361759738747f,
+	 0.000466304093914126f,
+	 0.000106589241438445f,
+	-0.000247017317721992f,
+	-0.000562646941659305f,
+	-0.000809708828030606f,
+	-0.000962510996013040f,
+	-0.001003685261621032f,
+	-0.000926952775265634f,
+	-0.000738799897838057f,
+	-0.000458730744403599f,
+	-0.000117916487516219f,
+	 0.000243742648939376f,
+	 0.000581911777806535f,
+	 0.000853035291692318f,
+	 0.001019866746633974f,
+	 0.001056611000192218f,
+	 0.000952962453331239f,
+	 0.000716408838645576f,
+	 0.000372351073038558f,
+	-0.000038150274869667f,
+	-0.000462881782404900f,
+	-0.000844797294892937f,
+	-0.001129425716907750f,
+	-0.001272432677940103f,
+	-0.001246307890160262f,
+	-0.001045192378203970f,
+	-0.000687044203214210f,
+	-0.000212653183490116f,
+	 0.000318579724580746f,
+	 0.000835734644546107f,
+	 0.001265542439063603f,
+	 0.001542487733459282f,
+	 0.001618487960413105f,
+	 0.001470755262270050f,
+	 0.001106608046232222f,
+	 0.000564346197878288f,
+	-0.000090197750452171f,
+	-0.000771230463597417f,
+	-0.001383890554706424f,
+	-0.001837132239362339f,
+	-0.002056896211703681f,
+	-0.001997709076123834f,
+	-0.001650953765714851f,
+	-0.001048413504576680f,
+	-0.000260276733547870f,
+	 0.000612469118131840f,
+	 0.001450527381084600f,
+	 0.002132190093380017f,
+	 0.002550584440683641f,
+	 0.002629881881769309f,
+	 0.002338080196576415f,
+	 0.001694308341293216f,
+	 0.000769260408641065f,
+	-0.000321736170028782f,
+	-0.001432485915523021f,
+	-0.002404976322971185f,
+	-0.003091310085438950f,
+	-0.003375549372556256f,
+	-0.003192330168178722f,
+	-0.002539372888669491f,
+	-0.001481713556478757f,
+	-0.000146533823587781f,
+	 0.001291251516558131f,
+	 0.002631154368260663f,
+	 0.003674321213032700f,
+	 0.004252198884660451f,
+	 0.004252637433548458f,
+	 0.003639528435255283f,
+	 0.002462762274858131f,
+	 0.000856475239499534f,
+	-0.000974892854265319f,
+	-0.002781496880057425f,
+	-0.004301065594668099f,
+	-0.005295755541230454f,
+	-0.005587859925192526f,
+	-0.005089203765495300f,
+	-0.003819632950038145f,
+	-0.001911267954229858f,
+	 0.000402995000090862f,
+	 0.002816115056235722f,
+	 0.004985868963592199f,
+	 0.006581423530514738f,
+	 0.007331423828496663f,
+	 0.007066900231758860f,
+	 0.005752595831756849f,
+	 0.003501526672561130f,
+	 0.000569595914029656f,
+	-0.002670342281476470f,
+	-0.005772755486290897f,
+	-0.008277141861910673f,
+	-0.009772095428011296f,
+	-0.009957304065452081f,
+	-0.008694779007964944f,
+	-0.006041501906687299f,
+	-0.002257673645446692f,
+	 0.002212348869418207f,
+	 0.006785874581560984f,
+	 0.010810304734210376f,
+	 0.013646746123386143f,
+	 0.014758915386036504f,
+	 0.013796112346034117f,
+	 0.010659097540521932f,
+	 0.005539210274923477f,
+	-0.001076115841043161f,
+	-0.008434444147245189f,
+	-0.015584625308516726f,
+	-0.021472430244782261f,
+	-0.025055744331654087f,
+	-0.025426655616721288f,
+	-0.021926322954481325f,
+	-0.014238733805135361f,
+	-0.002451384366749276f,
+	 0.012925647002682830f,
+	 0.030986186274100380f,
+	 0.050498778538203032f,
+	 0.070015421670629074f,
+	 0.088007266252761618f,
+	 0.103012981470773550f,
+	 0.113783757663955240f,
+	 0.119409036455313980f,
+	 0.119409036455313980f,
+	 0.113783757663955240f,
+	 0.103012981470773550f,
+	 0.088007266252761618f,
+	 0.070015421670629074f,
+	 0.050498778538203032f,
+	 0.030986186274100380f,
+	 0.012925647002682830f,
+	-0.002451384366749276f,
+	-0.014238733805135361f,
+	-0.021926322954481325f,
+	-0.025426655616721288f,
+	-0.025055744331654087f,
+	-0.021472430244782261f,
+	-0.015584625308516726f,
+	-0.008434444147245189f,
+	-0.001076115841043161f,
+	 0.005539210274923477f,
+	 0.010659097540521932f,
+	 0.013796112346034117f,
+	 0.014758915386036504f,
+	 0.013646746123386143f,
+	 0.010810304734210376f,
+	 0.006785874581560984f,
+	 0.002212348869418207f,
+	-0.002257673645446692f,
+	-0.006041501906687299f,
+	-0.008694779007964944f,
+	-0.009957304065452081f,
+	-0.009772095428011296f,
+	-0.008277141861910673f,
+	-0.005772755486290897f,
+	-0.002670342281476470f,
+	 0.000569595914029656f,
+	 0.003501526672561130f,
+	 0.005752595831756849f,
+	 0.007066900231758860f,
+	 0.007331423828496663f,
+	 0.006581423530514738f,
+	 0.004985868963592199f,
+	 0.002816115056235722f,
+	 0.000402995000090862f,
+	-0.001911267954229858f,
+	-0.003819632950038145f,
+	-0.005089203765495300f,
+	-0.005587859925192526f,
+	-0.005295755541230454f,
+	-0.004301065594668099f,
+	-0.002781496880057425f,
+	-0.000974892854265319f,
+	 0.000856475239499534f,
+	 0.002462762274858131f,
+	 0.003639528435255283f,
+	 0.004252637433548458f,
+	 0.004252198884660451f,
+	 0.003674321213032700f,
+	 0.002631154368260663f,
+	 0.001291251516558131f,
+	-0.000146533823587781f,
+	-0.001481713556478757f,
+	-0.002539372888669491f,
+	-0.003192330168178722f,
+	-0.003375549372556256f,
+	-0.003091310085438950f,
+	-0.002404976322971185f,
+	-0.001432485915523021f,
+	-0.000321736170028782f,
+	 0.000769260408641065f,
+	 0.001694308341293216f,
+	 0.002338080196576415f,
+	 0.002629881881769309f,
+	 0.002550584440683641f,
+	 0.002132190093380017f,
+	 0.001450527381084600f,
+	 0.000612469118131840f,
+	-0.000260276733547870f,
+	-0.001048413504576680f,
+	-0.001650953765714851f,
+	-0.001997709076123834f,
+	-0.002056896211703681f,
+	-0.001837132239362339f,
+	-0.001383890554706424f,
+	-0.000771230463597417f,
+	-0.000090197750452171f,
+	 0.000564346197878288f,
+	 0.001106608046232222f,
+	 0.001470755262270050f,
+	 0.001618487960413105f,
+	 0.001542487733459282f,
+	 0.001265542439063603f,
+	 0.000835734644546107f,
+	 0.000318579724580746f,
+	-0.000212653183490116f,
+	-0.000687044203214210f,
+	-0.001045192378203970f,
+	-0.001246307890160262f,
+	-0.001272432677940103f,
+	-0.001129425716907750f,
+	-0.000844797294892937f,
+	-0.000462881782404900f,
+	-0.000038150274869667f,
+	 0.000372351073038558f,
+	 0.000716408838645576f,
+	 0.000952962453331239f,
+	 0.001056611000192218f,
+	 0.001019866746633974f,
+	 0.000853035291692318f,
+	 0.000581911777806535f,
+	 0.000243742648939376f,
+	-0.000117916487516219f,
+	-0.000458730744403599f,
+	-0.000738799897838057f,
+	-0.000926952775265634f,
+	-0.001003685261621032f,
+	-0.000962510996013040f,
+	-0.000809708828030606f,
+	-0.000562646941659305f,
+	-0.000247017317721992f,
+	 0.000106589241438445f,
+	 0.000466304093914126f,
+	 0.000802361759738747f,
+	 0.001089882810057675f,
+	 0.001310813201213376f,
+	 0.001454903824191261f,
+	 0.001519741581366084f,
+	 0.001509953148215840f,
+	 0.001435783630074849f,
+	 0.001311296864337127f,
+	 0.001152454785657775f,
+	 0.000975304575250323f,
+	 0.000794466626663634f,
+	 0.000622018386430552f,
+	 0.000466890457500183f,
+	 0.000334591194217999f,
+	 0.000227646032445337f,
+	 0.000145468147843215f,
+	 0.000086660616597102f,
+	 0.000045443155025411f,
+	 0.000023653198869943f,
+	 0.000005299484859782f
+};
+
+static const int d_16_r_8_len = 54;
+static const float d_16_r_8_kernel[] =
+{
+	-0.000010553664672862f,
+	-0.000061498701563991f,
+	-0.000169601122616288f,
+	-0.000389180581238296f,
+	-0.000769984128346191f,
+	-0.001370862255977838f,
+	-0.002239657737237394f,
+	-0.003399895346870093f,
+	-0.004830710741492023f,
+	-0.006448450828431843f,
+	-0.008091858901382079f,
+	-0.009515843884697457f,
+	-0.010397443295914180f,
+	-0.010356613550454467f,
+	-0.008992200646607676f,
+	-0.005930785604319544f,
+	-0.000883275448312690f,
+	 0.006298249742162992f,
+	 0.015572313369334116f,
+	 0.026677316967261836f,
+	 0.039125602626276818f,
+	 0.052226529544645239f,
+	 0.065138652777540620f,
+	 0.076946528099683636f,
+	 0.086753462256061120f,
+	 0.093778457566739207f,
+	 0.097444274566674538f,
+	 0.097444274566674538f,
+	 0.093778457566739207f,
+	 0.086753462256061120f,
+	 0.076946528099683636f,
+	 0.065138652777540620f,
+	 0.052226529544645239f,
+	 0.039125602626276818f,
+	 0.026677316967261836f,
+	 0.015572313369334116f,
+	 0.006298249742162992f,
+	-0.000883275448312690f,
+	-0.005930785604319544f,
+	-0.008992200646607676f,
+	-0.010356613550454467f,
+	-0.010397443295914180f,
+	-0.009515843884697457f,
+	-0.008091858901382079f,
+	-0.006448450828431843f,
+	-0.004830710741492023f,
+	-0.003399895346870093f,
+	-0.002239657737237394f,
+	-0.001370862255977838f,
+	-0.000769984128346191f,
+	-0.000389180581238296f,
+	-0.000169601122616288f,
+	-0.000061498701563991f,
+	-0.000010553664672862f
+};
+
+static const int d_32_r_16_len = 107;
+static const float d_32_r_16_kernel[] =
+{
+	-0.000004024163639795f,
+	-0.000017672975608646f,
+	-0.000028369983125930f,
+	-0.000051841257358260f,
+	-0.000084114931088978f,
+	-0.000130374705334955f,
+	-0.000193165706690690f,
+	-0.000276282392544972f,
+	-0.000383294466797586f,
+	-0.000517836385761646f,
+	-0.000683246849920059f,
+	-0.000882378788952720f,
+	-0.001117308161626894f,
+	-0.001389043294976996f,
+	-0.001697213461428019f,
+	-0.002039760314912465f,
+	-0.002412643435722481f,
+	-0.002809577646098091f,
+	-0.003221818992095683f,
+	-0.003638016956253216f,
+	-0.004044149516577933f,
+	-0.004423556043039536f,
+	-0.004757080371798020f,
+	-0.005023332869090757f,
+	-0.005199075945795754f,
+	-0.005259732456805450f,
+	-0.005180010907146506f,
+	-0.004934635615957972f,
+	-0.004499164222082719f,
+	-0.003850869437258024f,
+	-0.002969657050308204f,
+	-0.001838988139263688f,
+	-0.000446770521598867f,
+	 0.001213817123243464f,
+	 0.003143605116121320f,
+	 0.005336851770962665f,
+	 0.007780833517050342f,
+	 0.010455633416035585f,
+	 0.013334149150643793f,
+	 0.016382334116677784f,
+	 0.019559676833852839f,
+	 0.022819914826782396f,
+	 0.026111969807273771f,
+	 0.029381081811115123f,
+	 0.032570111325119062f,
+	 0.035620970792186964f,
+	 0.038476140562399175f,
+	 0.041080219701286683f,
+	 0.043381459308086866f,
+	 0.045333225316341701f,
+	 0.046895339212960678f,
+	 0.048035248704517766f,
+	 0.048728985952954711f,
+	 0.048961878385199747f,
+	 0.048728985952954711f,
+	 0.048035248704517766f,
+	 0.046895339212960678f,
+	 0.045333225316341701f,
+	 0.043381459308086866f,
+	 0.041080219701286683f,
+	 0.038476140562399175f,
+	 0.035620970792186964f,
+	 0.032570111325119062f,
+	 0.029381081811115123f,
+	 0.026111969807273771f,
+	 0.022819914826782396f,
+	 0.019559676833852839f,
+	 0.016382334116677784f,
+	 0.013334149150643793f,
+	 0.010455633416035585f,
+	 0.007780833517050342f,
+	 0.005336851770962665f,
+	 0.003143605116121320f,
+	 0.001213817123243464f,
+	-0.000446770521598867f,
+	-0.001838988139263688f,
+	-0.002969657050308204f,
+	-0.003850869437258024f,
+	-0.004499164222082719f,
+	-0.004934635615957972f,
+	-0.005180010907146506f,
+	-0.005259732456805450f,
+	-0.005199075945795754f,
+	-0.005023332869090757f,
+	-0.004757080371798020f,
+	-0.004423556043039536f,
+	-0.004044149516577933f,
+	-0.003638016956253216f,
+	-0.003221818992095683f,
+	-0.002809577646098091f,
+	-0.002412643435722481f,
+	-0.002039760314912465f,
+	-0.001697213461428019f,
+	-0.001389043294976996f,
+	-0.001117308161626894f,
+	-0.000882378788952720f,
+	-0.000683246849920059f,
+	-0.000517836385761646f,
+	-0.000383294466797586f,
+	-0.000276282392544972f,
+	-0.000193165706690690f,
+	-0.000130374705334955f,
+	-0.000084114931088978f,
+	-0.000051841257358260f,
+	-0.000028369983125930f,
+	-0.000017672975608646f,
+	-0.000004024163639795f
+};
+
+static const int d_64_r_32_len = 212;
+static const float d_64_r_32_kernel[] =
+{
+	-0.000004403823942508f,
+	-0.000008963059919890f,
+	-0.000007276052892980f,
+	-0.000013448546764569f,
+	-0.000016407338246392f,
+	-0.000022821877811828f,
+	-0.000029059859493782f,
+	-0.000037502053326083f,
+	-0.000047050128769168f,
+	-0.000058647705667398f,
+	-0.000072066821233235f,
+	-0.000087775432302674f,
+	-0.000105848488644829f,
+	-0.000126598475702349f,
+	-0.000150205141042045f,
+	-0.000176926965601505f,
+	-0.000206973701715915f,
+	-0.000240575602493366f,
+	-0.000277937749971926f,
+	-0.000319260777052827f,
+	-0.000364722541989086f,
+	-0.000414482134953896f,
+	-0.000468670554403767f,
+	-0.000527388854339363f,
+	-0.000590701722925615f,
+	-0.000658633566464172f,
+	-0.000731163061150287f,
+	-0.000808218604975926f,
+	-0.000889673345622962f,
+	-0.000975340650633742f,
+	-0.001064969616730599f,
+	-0.001158240957389821f,
+	-0.001254763178484453f,
+	-0.001354069203096897f,
+	-0.001455613461052586f,
+	-0.001558769541846508f,
+	-0.001662828458596891f,
+	-0.001766997597152117f,
+	-0.001870400403116935f,
+	-0.001972076865069115f,
+	-0.002070984841172726f,
+	-0.002166002272448999f,
+	-0.002255930317598858f,
+	-0.002339497436442704f,
+	-0.002415364439683740f,
+	-0.002482130514177367f,
+	-0.002538340220525754f,
+	-0.002582491452580508f,
+	-0.002613044332960035f,
+	-0.002628431011812668f,
+	-0.002627066321370591f,
+	-0.002607359228695053f,
+	-0.002567725018271331f,
+	-0.002506598123060911f,
+	-0.002422445514576562f,
+	-0.002313780550524778f,
+	-0.002179177170034060f,
+	-0.002017284317828416f,
+	-0.001826840471286680f,
+	-0.001606688137875605f,
+	-0.001355788185007890f,
+	-0.001073233860638388f,
+	-0.000758264360902667f,
+	-0.000410277798843436f,
+	-0.000028843430628706f,
+	 0.000386287004249912f,
+	 0.000835168966487215f,
+	 0.001317655958647924f,
+	 0.001833391650175865f,
+	 0.002381803404668191f,
+	 0.002962097316406667f,
+	 0.003573254853063226f,
+	 0.004214031187543062f,
+	 0.004882955288187807f,
+	 0.005578331822331469f,
+	 0.006298244909815173f,
+	 0.007040563748502659f,
+	 0.007802950114525442f,
+	 0.008582867722817980f,
+	 0.009377593413961051f,
+	 0.010184230117287451f,
+	 0.010999721518727896f,
+	 0.011820868346749476f,
+	 0.012644346170734195f,
+	 0.013466724590201118f,
+	 0.014284487677241258f,
+	 0.015094055520281103f,
+	 0.015891806704001060f,
+	 0.016674101548252919f,
+	 0.017437305919088521f,
+	 0.018177815416425963f,
+	 0.018892079736813970f,
+	 0.019576627004361302f,
+	 0.020228087861972253f,
+	 0.020843219113185100f,
+	 0.021418926707647539f,
+	 0.021952287867040517f,
+	 0.022440572154110033f,
+	 0.022881261295670835f,
+	 0.023272067580484536f,
+	 0.023610950665041715f,
+	 0.023896132633698622f,
+	 0.024126111175283287f,
+	 0.024299670755100852f,
+	 0.024415891678976044f,
+	 0.024474156966027200f,
+	 0.024474156966027200f,
+	 0.024415891678976044f,
+	 0.024299670755100852f,
+	 0.024126111175283287f,
+	 0.023896132633698622f,
+	 0.023610950665041715f,
+	 0.023272067580484536f,
+	 0.022881261295670835f,
+	 0.022440572154110033f,
+	 0.021952287867040517f,
+	 0.021418926707647539f,
+	 0.020843219113185100f,
+	 0.020228087861972253f,
+	 0.019576627004361302f,
+	 0.018892079736813970f,
+	 0.018177815416425963f,
+	 0.017437305919088521f,
+	 0.016674101548252919f,
+	 0.015891806704001060f,
+	 0.015094055520281103f,
+	 0.014284487677241258f,
+	 0.013466724590201118f,
+	 0.012644346170734195f,
+	 0.011820868346749476f,
+	 0.010999721518727896f,
+	 0.010184230117287451f,
+	 0.009377593413961051f,
+	 0.008582867722817980f,
+	 0.007802950114525442f,
+	 0.007040563748502659f,
+	 0.006298244909815173f,
+	 0.005578331822331469f,
+	 0.004882955288187807f,
+	 0.004214031187543062f,
+	 0.003573254853063226f,
+	 0.002962097316406667f,
+	 0.002381803404668191f,
+	 0.001833391650175865f,
+	 0.001317655958647924f,
+	 0.000835168966487215f,
+	 0.000386287004249912f,
+	-0.000028843430628706f,
+	-0.000410277798843436f,
+	-0.000758264360902667f,
+	-0.001073233860638388f,
+	-0.001355788185007890f,
+	-0.001606688137875605f,
+	-0.001826840471286680f,
+	-0.002017284317828416f,
+	-0.002179177170034060f,
+	-0.002313780550524778f,
+	-0.002422445514576562f,
+	-0.002506598123060911f,
+	-0.002567725018271331f,
+	-0.002607359228695053f,
+	-0.002627066321370591f,
+	-0.002628431011812668f,
+	-0.002613044332960035f,
+	-0.002582491452580508f,
+	-0.002538340220525754f,
+	-0.002482130514177367f,
+	-0.002415364439683740f,
+	-0.002339497436442704f,
+	-0.002255930317598858f,
+	-0.002166002272448999f,
+	-0.002070984841172726f,
+	-0.001972076865069115f,
+	-0.001870400403116935f,
+	-0.001766997597152117f,
+	-0.001662828458596891f,
+	-0.001558769541846508f,
+	-0.001455613461052586f,
+	-0.001354069203096897f,
+	-0.001254763178484453f,
+	-0.001158240957389821f,
+	-0.001064969616730599f,
+	-0.000975340650633742f,
+	-0.000889673345622962f,
+	-0.000808218604975926f,
+	-0.000731163061150287f,
+	-0.000658633566464172f,
+	-0.000590701722925615f,
+	-0.000527388854339363f,
+	-0.000468670554403767f,
+	-0.000414482134953896f,
+	-0.000364722541989086f,
+	-0.000319260777052827f,
+	-0.000277937749971926f,
+	-0.000240575602493366f,
+	-0.000206973701715915f,
+	-0.000176926965601505f,
+	-0.000150205141042045f,
+	-0.000126598475702349f,
+	-0.000105848488644829f,
+	-0.000087775432302674f,
+	-0.000072066821233235f,
+	-0.000058647705667398f,
+	-0.000047050128769168f,
+	-0.000037502053326083f,
+	-0.000029059859493782f,
+	-0.000022821877811828f,
+	-0.000016407338246392f,
+	-0.000013448546764569f,
+	-0.000007276052892980f,
+	-0.000008963059919890f,
+	-0.000004403823942508f
+};
+
+static const int d_128_r_32_len = 174;
+static const float d_128_r_32_kernel[] =
+{
+	-0.000007703161797332f,
+	-0.000007067232655723f,
+	-0.000010206071983051f,
+	-0.000014172048980291f,
+	-0.000019092331824095f,
+	-0.000025093561850217f,
+	-0.000032309725460887f,
+	-0.000040869410108629f,
+	-0.000050902771287247f,
+	-0.000062527941809152f,
+	-0.000075857080877625f,
+	-0.000090981984892608f,
+	-0.000107979276021387f,
+	-0.000126895337525829f,
+	-0.000147750778600044f,
+	-0.000170524898241214f,
+	-0.000195159646270053f,
+	-0.000221543901544016f,
+	-0.000249517228886741f,
+	-0.000278854334896464f,
+	-0.000309268991706370f,
+	-0.000340399096744052f,
+	-0.000371811190567229f,
+	-0.000402986592324930f,
+	-0.000433326971103446f,
+	-0.000462142048725246f,
+	-0.000488656689255886f,
+	-0.000512000649038707f,
+	-0.000531217622524194f,
+	-0.000545257474301118f,
+	-0.000552987616398289f,
+	-0.000553188077307909f,
+	-0.000544565488882758f,
+	-0.000525751232639430f,
+	-0.000495318184744208f,
+	-0.000451782034515639f,
+	-0.000393620779029084f,
+	-0.000319279140356296f,
+	-0.000227190622760720f,
+	-0.000115784771504684f,
+	 0.000016488581452787f,
+	 0.000171149664304299f,
+	 0.000349662890884785f,
+	 0.000553425442457719f,
+	 0.000783740497411292f,
+	 0.001041804838025221f,
+	 0.001328682064289453f,
+	 0.001645290145967291f,
+	 0.001992375608565783f,
+	 0.002370502036550272f,
+	 0.002780026279675712f,
+	 0.003221088947286086f,
+	 0.003693593686280741f,
+	 0.004197200680900796f,
+	 0.004731309996663634f,
+	 0.005295059011515552f,
+	 0.005887310701543637f,
+	 0.006506655780921748f,
+	 0.007151406625936390f,
+	 0.007819604696828528f,
+	 0.008509020566706571f,
+	 0.009217166946123657f,
+	 0.009941305011649831f,
+	 0.010678463067957514f,
+	 0.011425449071796635f,
+	 0.012178874660574504f,
+	 0.012935173457761552f,
+	 0.013690629889370804f,
+	 0.014441402554104810f,
+	 0.015183556958199267f,
+	 0.015913092956531424f,
+	 0.016625980278750660f,
+	 0.017318188813430120f,
+	 0.017985725593062503f,
+	 0.018624666516886546f,
+	 0.019231193320663705f,
+	 0.019801625228558870f,
+	 0.020332454367773867f,
+	 0.020820375812973399f,
+	 0.021262319920613983f,
+	 0.021655479285054610f,
+	 0.021997336565315176f,
+	 0.022285687008084795f,
+	 0.022518660515178174f,
+	 0.022694738600454345f,
+	 0.022812769691468757f,
+	 0.022871979661449618f,
+	 0.022871979661449618f,
+	 0.022812769691468757f,
+	 0.022694738600454345f,
+	 0.022518660515178174f,
+	 0.022285687008084795f,
+	 0.021997336565315176f,
+	 0.021655479285054610f,
+	 0.021262319920613983f,
+	 0.020820375812973399f,
+	 0.020332454367773867f,
+	 0.019801625228558870f,
+	 0.019231193320663705f,
+	 0.018624666516886546f,
+	 0.017985725593062503f,
+	 0.017318188813430120f,
+	 0.016625980278750660f,
+	 0.015913092956531424f,
+	 0.015183556958199267f,
+	 0.014441402554104810f,
+	 0.013690629889370804f,
+	 0.012935173457761552f,
+	 0.012178874660574504f,
+	 0.011425449071796635f,
+	 0.010678463067957514f,
+	 0.009941305011649831f,
+	 0.009217166946123657f,
+	 0.008509020566706571f,
+	 0.007819604696828528f,
+	 0.007151406625936390f,
+	 0.006506655780921748f,
+	 0.005887310701543637f,
+	 0.005295059011515552f,
+	 0.004731309996663634f,
+	 0.004197200680900796f,
+	 0.003693593686280741f,
+	 0.003221088947286086f,
+	 0.002780026279675712f,
+	 0.002370502036550272f,
+	 0.001992375608565783f,
+	 0.001645290145967291f,
+	 0.001328682064289453f,
+	 0.001041804838025221f,
+	 0.000783740497411292f,
+	 0.000553425442457719f,
+	 0.000349662890884785f,
+	 0.000171149664304299f,
+	 0.000016488581452787f,
+	-0.000115784771504684f,
+	-0.000227190622760720f,
+	-0.000319279140356296f,
+	-0.000393620779029084f,
+	-0.000451782034515639f,
+	-0.000495318184744208f,
+	-0.000525751232639430f,
+	-0.000544565488882758f,
+	-0.000553188077307909f,
+	-0.000552987616398289f,
+	-0.000545257474301118f,
+	-0.000531217622524194f,
+	-0.000512000649038707f,
+	-0.000488656689255886f,
+	-0.000462142048725246f,
+	-0.000433326971103446f,
+	-0.000402986592324930f,
+	-0.000371811190567229f,
+	-0.000340399096744052f,
+	-0.000309268991706370f,
+	-0.000278854334896464f,
+	-0.000249517228886741f,
+	-0.000221543901544016f,
+	-0.000195159646270053f,
+	-0.000170524898241214f,
+	-0.000147750778600044f,
+	-0.000126895337525829f,
+	-0.000107979276021387f,
+	-0.000090981984892608f,
+	-0.000075857080877625f,
+	-0.000062527941809152f,
+	-0.000050902771287247f,
+	-0.000040869410108629f,
+	-0.000032309725460887f,
+	-0.000025093561850217f,
+	-0.000019092331824095f,
+	-0.000014172048980291f,
+	-0.000010206071983051f,
+	-0.000007067232655723f,
+	-0.000007703161797332f
+};
+
+static const int d_256_r_64_len = 348;
+static const float d_256_r_64_kernel[] =
+{
+	-0.000006032200297229f,
+	-0.000002790586794678f,
+	-0.000003423524464373f,
+	-0.000004141892670381f,
+	-0.000004959329780957f,
+	-0.000005880953015414f,
+	-0.000006916263845337f,
+	-0.000008064028056128f,
+	-0.000009336504822940f,
+	-0.000010742797132820f,
+	-0.000012302324525658f,
+	-0.000014003128525449f,
+	-0.000015868003792231f,
+	-0.000017906061357310f,
+	-0.000020111369902626f,
+	-0.000022508204619172f,
+	-0.000025093613992638f,
+	-0.000027881953296601f,
+	-0.000030875236885189f,
+	-0.000034086060833210f,
+	-0.000037517497377010f,
+	-0.000041176665997414f,
+	-0.000045067469478981f,
+	-0.000049199353227621f,
+	-0.000053568215176887f,
+	-0.000058185242147041f,
+	-0.000063047547807853f,
+	-0.000068158618146586f,
+	-0.000073517650784389f,
+	-0.000079124725926570f,
+	-0.000084976788235246f,
+	-0.000091070103041806f,
+	-0.000097399649098627f,
+	-0.000103959504668590f,
+	-0.000110738977492950f,
+	-0.000117729935644196f,
+	-0.000124919754739577f,
+	-0.000132293212128623f,
+	-0.000139836270835869f,
+	-0.000147529334756596f,
+	-0.000155353239032747f,
+	-0.000163284378055491f,
+	-0.000171298895948762f,
+	-0.000179368841745378f,
+	-0.000187464129074148f,
+	-0.000195552549576070f,
+	-0.000203599379753965f,
+	-0.000211565351775375f,
+	-0.000219411598860001f,
+	-0.000227093646507866f,
+	-0.000234565855614429f,
+	-0.000241779257421431f,
+	-0.000248682177854843f,
+	-0.000255220180724547f,
+	-0.000261335292980978f,
+	-0.000266967862740791f,
+	-0.000272054419087176f,
+	-0.000276528686849870f,
+	-0.000280322370041046f,
+	-0.000283363923695878f,
+	-0.000285578633373008f,
+	-0.000286890694598539f,
+	-0.000287220112764771f,
+	-0.000286486063219693f,
+	-0.000284603980740463f,
+	-0.000281488659987540f,
+	-0.000277051522643753f,
+	-0.000271202733437524f,
+	-0.000263850662609383f,
+	-0.000254902132867105f,
+	-0.000244261829079865f,
+	-0.000231834561467387f,
+	-0.000217522684614226f,
+	-0.000201228717970838f,
+	-0.000182854056621652f,
+	-0.000162300101972573f,
+	-0.000139467943568298f,
+	-0.000114258627064630f,
+	-0.000086574168670878f,
+	-0.000056316612617103f,
+	-0.000023389083735015f,
+	 0.000012303734435184f,
+	 0.000050856088211618f,
+	 0.000092360432854175f,
+	 0.000136906695012963f,
+	 0.000184583050199368f,
+	 0.000235474395169584f,
+	 0.000289663252276950f,
+	 0.000347228091667187f,
+	 0.000408244468331575f,
+	 0.000472783700962668f,
+	 0.000540912739938505f,
+	 0.000612694289527581f,
+	 0.000688186201030564f,
+	 0.000767440808596336f,
+	 0.000850505496981770f,
+	 0.000937421598757782f,
+	 0.001028224584686942f,
+	 0.001122943571650730f,
+	 0.001221601170177604f,
+	 0.001324213422447449f,
+	 0.001430788817328081f,
+	 0.001541329271676986f,
+	 0.001655828820474164f,
+	 0.001774273932442011f,
+	 0.001896643321221287f,
+	 0.002022907760579356f,
+	 0.002153029565104709f,
+	 0.002286963138555204f,
+	 0.002424654105591249f,
+	 0.002566039990527927f,
+	 0.002711049190015392f,
+	 0.002859602052878106f,
+	 0.003011609882021581f,
+	 0.003166975340851216f,
+	 0.003325592606007947f,
+	 0.003487347156138999f,
+	 0.003652115769225347f,
+	 0.003819766988190932f,
+	 0.003990160791661657f,
+	 0.004163149004759460f,
+	 0.004338575232032592f,
+	 0.004516275281704776f,
+	 0.004696077226065694f,
+	 0.004877801369702575f,
+	 0.005061261175365414f,
+	 0.005246262760259225f,
+	 0.005432605634097002f,
+	 0.005620082968897619f,
+	 0.005808481837004595f,
+	 0.005997583515661679f,
+	 0.006187164045980849f,
+	 0.006376994441064236f,
+	 0.006566841257680600f,
+	 0.006756466702660143f,
+	 0.006945629644096785f,
+	 0.007134085474240178f,
+	 0.007321586857189369f,
+	 0.007507884388699728f,
+	 0.007692726710717013f,
+	 0.007875861286146892f,
+	 0.008057034853723447f,
+	 0.008235993962285608f,
+	 0.008412485423992495f,
+	 0.008586256905270668f,
+	 0.008757057550423931f,
+	 0.008924638381879985f,
+	 0.009088752763977616f,
+	 0.009249157391806035f,
+	 0.009405612190690901f,
+	 0.009557881349450560f,
+	 0.009705733651032743f,
+	 0.009848943025250930f,
+	 0.009987289003226731f,
+	 0.010120557317645952f,
+	 0.010248540384643352f,
+	 0.010371037696321509f,
+	 0.010487856281889540f,
+	 0.010598811426250850f,
+	 0.010703726661456589f,
+	 0.010802434494593470f,
+	 0.010894776824678817f,
+	 0.010980605060844476f,
+	 0.011059780725514858f,
+	 0.011132175645830765f,
+	 0.011197672374601442f,
+	 0.011256164283833567f,
+	 0.011307555970121824f,
+	 0.011351763540287503f,
+	 0.011388714558166329f,
+	 0.011418348423280301f,
+	 0.011440616600089638f,
+	 0.011455482402780947f,
+	 0.011462921415360990f,
+	 0.011462921415360990f,
+	 0.011455482402780947f,
+	 0.011440616600089638f,
+	 0.011418348423280301f,
+	 0.011388714558166329f,
+	 0.011351763540287503f,
+	 0.011307555970121824f,
+	 0.011256164283833567f,
+	 0.011197672374601442f,
+	 0.011132175645830765f,
+	 0.011059780725514858f,
+	 0.010980605060844476f,
+	 0.010894776824678817f,
+	 0.010802434494593470f,
+	 0.010703726661456589f,
+	 0.010598811426250850f,
+	 0.010487856281889540f,
+	 0.010371037696321509f,
+	 0.010248540384643352f,
+	 0.010120557317645952f,
+	 0.009987289003226731f,
+	 0.009848943025250930f,
+	 0.009705733651032743f,
+	 0.009557881349450560f,
+	 0.009405612190690901f,
+	 0.009249157391806035f,
+	 0.009088752763977616f,
+	 0.008924638381879985f,
+	 0.008757057550423931f,
+	 0.008586256905270668f,
+	 0.008412485423992495f,
+	 0.008235993962285608f,
+	 0.008057034853723447f,
+	 0.007875861286146892f,
+	 0.007692726710717013f,
+	 0.007507884388699728f,
+	 0.007321586857189369f,
+	 0.007134085474240178f,
+	 0.006945629644096785f,
+	 0.006756466702660143f,
+	 0.006566841257680600f,
+	 0.006376994441064236f,
+	 0.006187164045980849f,
+	 0.005997583515661679f,
+	 0.005808481837004595f,
+	 0.005620082968897619f,
+	 0.005432605634097002f,
+	 0.005246262760259225f,
+	 0.005061261175365414f,
+	 0.004877801369702575f,
+	 0.004696077226065694f,
+	 0.004516275281704776f,
+	 0.004338575232032592f,
+	 0.004163149004759460f,
+	 0.003990160791661657f,
+	 0.003819766988190932f,
+	 0.003652115769225347f,
+	 0.003487347156138999f,
+	 0.003325592606007947f,
+	 0.003166975340851216f,
+	 0.003011609882021581f,
+	 0.002859602052878106f,
+	 0.002711049190015392f,
+	 0.002566039990527927f,
+	 0.002424654105591249f,
+	 0.002286963138555204f,
+	 0.002153029565104709f,
+	 0.002022907760579356f,
+	 0.001896643321221287f,
+	 0.001774273932442011f,
+	 0.001655828820474164f,
+	 0.001541329271676986f,
+	 0.001430788817328081f,
+	 0.001324213422447449f,
+	 0.001221601170177604f,
+	 0.001122943571650730f,
+	 0.001028224584686942f,
+	 0.000937421598757782f,
+	 0.000850505496981770f,
+	 0.000767440808596336f,
+	 0.000688186201030564f,
+	 0.000612694289527581f,
+	 0.000540912739938505f,
+	 0.000472783700962668f,
+	 0.000408244468331575f,
+	 0.000347228091667187f,
+	 0.000289663252276950f,
+	 0.000235474395169584f,
+	 0.000184583050199368f,
+	 0.000136906695012963f,
+	 0.000092360432854175f,
+	 0.000050856088211618f,
+	 0.000012303734435184f,
+	-0.000023389083735015f,
+	-0.000056316612617103f,
+	-0.000086574168670878f,
+	-0.000114258627064630f,
+	-0.000139467943568298f,
+	-0.000162300101972573f,
+	-0.000182854056621652f,
+	-0.000201228717970838f,
+	-0.000217522684614226f,
+	-0.000231834561467387f,
+	-0.000244261829079865f,
+	-0.000254902132867105f,
+	-0.000263850662609383f,
+	-0.000271202733437524f,
+	-0.000277051522643753f,
+	-0.000281488659987540f,
+	-0.000284603980740463f,
+	-0.000286486063219693f,
+	-0.000287220112764771f,
+	-0.000286890694598539f,
+	-0.000285578633373008f,
+	-0.000283363923695878f,
+	-0.000280322370041046f,
+	-0.000276528686849870f,
+	-0.000272054419087176f,
+	-0.000266967862740791f,
+	-0.000261335292980978f,
+	-0.000255220180724547f,
+	-0.000248682177854843f,
+	-0.000241779257421431f,
+	-0.000234565855614429f,
+	-0.000227093646507866f,
+	-0.000219411598860001f,
+	-0.000211565351775375f,
+	-0.000203599379753965f,
+	-0.000195552549576070f,
+	-0.000187464129074148f,
+	-0.000179368841745378f,
+	-0.000171298895948762f,
+	-0.000163284378055491f,
+	-0.000155353239032747f,
+	-0.000147529334756596f,
+	-0.000139836270835869f,
+	-0.000132293212128623f,
+	-0.000124919754739577f,
+	-0.000117729935644196f,
+	-0.000110738977492950f,
+	-0.000103959504668590f,
+	-0.000097399649098627f,
+	-0.000091070103041806f,
+	-0.000084976788235246f,
+	-0.000079124725926570f,
+	-0.000073517650784389f,
+	-0.000068158618146586f,
+	-0.000063047547807853f,
+	-0.000058185242147041f,
+	-0.000053568215176887f,
+	-0.000049199353227621f,
+	-0.000045067469478981f,
+	-0.000041176665997414f,
+	-0.000037517497377010f,
+	-0.000034086060833210f,
+	-0.000030875236885189f,
+	-0.000027881953296601f,
+	-0.000025093613992638f,
+	-0.000022508204619172f,
+	-0.000020111369902626f,
+	-0.000017906061357310f,
+	-0.000015868003792231f,
+	-0.000014003128525449f,
+	-0.000012302324525658f,
+	-0.000010742797132820f,
+	-0.000009336504822940f,
+	-0.000008064028056128f,
+	-0.000006916263845337f,
+	-0.000005880953015414f,
+	-0.000004959329780957f,
+	-0.000004141892670381f,
+	-0.000003423524464373f,
+	-0.000002790586794678f,
+	-0.000006032200297229f
+};
+
+
+#else
+// Previous FIR decimator
+
+
 /* Filter taps generated by matlab.
  * All filters are designed for 0.5 dB passband ripple and 90-100 dB stop-band
  * attenuation.
@@ -351,3 +1785,6 @@ const float *FIR_128_2_TAPS = FIR_8_1_TAPS;
 //    0.4500000000    0.5500000000    2
 #define FIR_128_3_LEN   FIR_2_1_LEN
 const float *FIR_128_3_TAPS = FIR_2_1_TAPS;
+
+#endif  // USE_NEW_FIR_DECIM
+

From 3e85f1316c382df899502a5fe2a9babf009902f2 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Wed, 5 Apr 2017 23:14:22 +0200
Subject: [PATCH 211/334] Indent fir_decim_coef

---
 src/dsp/filter/fir_decim_coef.h | 2770 +++++++++++++++----------------
 1 file changed, 1384 insertions(+), 1386 deletions(-)

diff --git a/src/dsp/filter/fir_decim_coef.h b/src/dsp/filter/fir_decim_coef.h
index 315ede5..d9a70af 100644
--- a/src/dsp/filter/fir_decim_coef.h
+++ b/src/dsp/filter/fir_decim_coef.h
@@ -4,7 +4,7 @@
  *           http://gqrx.dk/
  *
  * Copyright 2016 Alexandru Csete OZ9AEC.
- * Copyright 2017 Youssef Touil. 
+ * Copyright 2017 Youssef Touil.
  *
  * Gqrx is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,1431 +31,1429 @@
 static const int d_2_r_2_len = 69;
 static const float d_2_r_2_kernel[] =
 {
-	 0.000399985734121014f,
-	 0.002073370222476234f,
-	 0.004853019240304940f,
-	 0.005977464755456102f,
-	 0.002625480716699286f,
-	-0.002713628293157090f,
-	-0.003379460736391527f,
-	 0.001637205667907783f,
-	 0.004080689203761314f,
-	-0.000982433398470081f,
-	-0.005119016867477646f,
-	 0.000177424749467386f,
-	 0.006424890506348696f,
-	 0.001008090651156955f,
-	-0.007915926496343137f,
-	-0.002717062331286239f,
-	 0.009511042111613645f,
-	 0.005077150379032227f,
-	-0.011151300589456603f,
-	-0.008251061374053964f,
-	 0.012781117215688672f,
-	 0.012490374909303374f,
-	-0.014344287749952384f,
-	-0.018209086168089920f,
-	 0.015778580923975386f,
-	 0.026178028229057050f,
-	-0.017029165534577999f,
-	-0.038051941291319488f,
-	 0.018060406839966188f,
-	 0.058210457193828925f,
-	-0.018831122390764166f,
-	-0.102778567522516130f,
-	 0.019291268777910851f,
-	 0.317182812089170980f,
-	 0.480536048712957740f,
-	 0.317182812089170980f,
-	 0.019291268777910851f,
-	-0.102778567522516130f,
-	-0.018831122390764166f,
-	 0.058210457193828925f,
-	 0.018060406839966188f,
-	-0.038051941291319488f,
-	-0.017029165534577999f,
-	 0.026178028229057050f,
-	 0.015778580923975386f,
-	-0.018209086168089920f,
-	-0.014344287749952384f,
-	 0.012490374909303374f,
-	 0.012781117215688672f,
-	-0.008251061374053964f,
-	-0.011151300589456603f,
-	 0.005077150379032227f,
-	 0.009511042111613645f,
-	-0.002717062331286239f,
-	-0.007915926496343137f,
-	 0.001008090651156955f,
-	 0.006424890506348696f,
-	 0.000177424749467386f,
-	-0.005119016867477646f,
-	-0.000982433398470081f,
-	 0.004080689203761314f,
-	 0.001637205667907783f,
-	-0.003379460736391527f,
-	-0.002713628293157090f,
-	 0.002625480716699286f,
-	 0.005977464755456102f,
-	 0.004853019240304940f,
-	 0.002073370222476234f,
-	 0.000399985734121014f
+     0.000399985734121014f,
+     0.002073370222476234f,
+     0.004853019240304940f,
+     0.005977464755456102f,
+     0.002625480716699286f,
+    -0.002713628293157090f,
+    -0.003379460736391527f,
+     0.001637205667907783f,
+     0.004080689203761314f,
+    -0.000982433398470081f,
+    -0.005119016867477646f,
+     0.000177424749467386f,
+     0.006424890506348696f,
+     0.001008090651156955f,
+    -0.007915926496343137f,
+    -0.002717062331286239f,
+     0.009511042111613645f,
+     0.005077150379032227f,
+    -0.011151300589456603f,
+    -0.008251061374053964f,
+     0.012781117215688672f,
+     0.012490374909303374f,
+    -0.014344287749952384f,
+    -0.018209086168089920f,
+     0.015778580923975386f,
+     0.026178028229057050f,
+    -0.017029165534577999f,
+    -0.038051941291319488f,
+     0.018060406839966188f,
+     0.058210457193828925f,
+    -0.018831122390764166f,
+    -0.102778567522516130f,
+     0.019291268777910851f,
+     0.317182812089170980f,
+     0.480536048712957740f,
+     0.317182812089170980f,
+     0.019291268777910851f,
+    -0.102778567522516130f,
+    -0.018831122390764166f,
+     0.058210457193828925f,
+     0.018060406839966188f,
+    -0.038051941291319488f,
+    -0.017029165534577999f,
+     0.026178028229057050f,
+     0.015778580923975386f,
+    -0.018209086168089920f,
+    -0.014344287749952384f,
+     0.012490374909303374f,
+     0.012781117215688672f,
+    -0.008251061374053964f,
+    -0.011151300589456603f,
+     0.005077150379032227f,
+     0.009511042111613645f,
+    -0.002717062331286239f,
+    -0.007915926496343137f,
+     0.001008090651156955f,
+     0.006424890506348696f,
+     0.000177424749467386f,
+    -0.005119016867477646f,
+    -0.000982433398470081f,
+     0.004080689203761314f,
+     0.001637205667907783f,
+    -0.003379460736391527f,
+    -0.002713628293157090f,
+     0.002625480716699286f,
+     0.005977464755456102f,
+     0.004853019240304940f,
+     0.002073370222476234f,
+     0.000399985734121014f
 };
 
 static const int d_4_r_4_len = 139;
 static const float d_4_r_4_kernel[] =
 {
-	 0.000042167047949931f,
-	 0.000162480875041441f,
-	 0.000413474829003805f,
-	 0.000815488719349860f,
-	 0.001323484844111109f,
-	 0.001803932401530970f,
-	 0.002050805379425780f,
-	 0.001851476423100084f,
-	 0.001088358238163842f,
-	-0.000165599354540670f,
-	-0.001612840277093291f,
-	-0.002799173360323900f,
-	-0.003280737659419560f,
-	-0.002830930204582274f,
-	-0.001589296551711622f,
-	-0.000060142418430366f,
-	 0.001072157673911288f,
-	 0.001252059507347206f,
-	 0.000346781210023729f,
-	-0.001233491421169468f,
-	-0.002682865592015316f,
-	-0.003178340139233828f,
-	-0.002320119390193667f,
-	-0.000402092792444196f,
-	 0.001661437823975322f,
-	 0.002761727219457103f,
-	 0.002186981534424376f,
-	 0.000071307331744879f,
-	-0.002570893712874658f,
-	-0.004301512250227543f,
-	-0.004015094439084645f,
-	-0.001606879839533175f,
-	 0.001838674337622738f,
-	 0.004510048531846937f,
-	 0.004804547613530567f,
-	 0.002266863620581679f,
-	-0.002004704037111716f,
-	-0.005785548895574678f,
-	-0.006849655924079080f,
-	-0.004239720077392586f,
-	 0.001024318787772757f,
-	 0.006275193248599259f,
-	 0.008511512338709764f,
-	 0.006070603106211769f,
-	-0.000247611530141919f,
-	-0.007317511868656072f,
-	-0.011170336815604164f,
-	-0.009152698013614463f,
-	-0.001621157345452147f,
-	 0.007851435931989321f,
-	 0.014073238852672171f,
-	 0.012972692080589394f,
-	 0.004087473189926854f,
-	-0.008634954375856124f,
-	-0.018413964067748419f,
-	-0.019050011539439745f,
-	-0.008545626179408438f,
-	 0.009039966712164142f,
-	 0.024793283315122296f,
-	 0.029034181171149441f,
-	 0.016560363014866013f,
-	-0.009522346448795137f,
-	-0.037569562545468192f,
-	-0.051411140638474247f,
-	-0.037221789978391415f,
-	 0.009679493935209005f,
-	 0.081286213859684806f,
-	 0.158552299980228740f,
-	 0.217917169253869340f,
-	 0.240164834839879550f,
-	 0.217917169253869340f,
-	 0.158552299980228740f,
-	 0.081286213859684806f,
-	 0.009679493935209005f,
-	-0.037221789978391415f,
-	-0.051411140638474247f,
-	-0.037569562545468192f,
-	-0.009522346448795137f,
-	 0.016560363014866013f,
-	 0.029034181171149441f,
-	 0.024793283315122296f,
-	 0.009039966712164142f,
-	-0.008545626179408438f,
-	-0.019050011539439745f,
-	-0.018413964067748419f,
-	-0.008634954375856124f,
-	 0.004087473189926854f,
-	 0.012972692080589394f,
-	 0.014073238852672171f,
-	 0.007851435931989321f,
-	-0.001621157345452147f,
-	-0.009152698013614463f,
-	-0.011170336815604164f,
-	-0.007317511868656072f,
-	-0.000247611530141919f,
-	 0.006070603106211769f,
-	 0.008511512338709764f,
-	 0.006275193248599259f,
-	 0.001024318787772757f,
-	-0.004239720077392586f,
-	-0.006849655924079080f,
-	-0.005785548895574678f,
-	-0.002004704037111716f,
-	 0.002266863620581679f,
-	 0.004804547613530567f,
-	 0.004510048531846937f,
-	 0.001838674337622738f,
-	-0.001606879839533175f,
-	-0.004015094439084645f,
-	-0.004301512250227543f,
-	-0.002570893712874658f,
-	 0.000071307331744879f,
-	 0.002186981534424376f,
-	 0.002761727219457103f,
-	 0.001661437823975322f,
-	-0.000402092792444196f,
-	-0.002320119390193667f,
-	-0.003178340139233828f,
-	-0.002682865592015316f,
-	-0.001233491421169468f,
-	 0.000346781210023729f,
-	 0.001252059507347206f,
-	 0.001072157673911288f,
-	-0.000060142418430366f,
-	-0.001589296551711622f,
-	-0.002830930204582274f,
-	-0.003280737659419560f,
-	-0.002799173360323900f,
-	-0.001612840277093291f,
-	-0.000165599354540670f,
-	 0.001088358238163842f,
-	 0.001851476423100084f,
-	 0.002050805379425780f,
-	 0.001803932401530970f,
-	 0.001323484844111109f,
-	 0.000815488719349860f,
-	 0.000413474829003805f,
-	 0.000162480875041441f,
-	 0.000042167047949931f
+     0.000042167047949931f,
+     0.000162480875041441f,
+     0.000413474829003805f,
+     0.000815488719349860f,
+     0.001323484844111109f,
+     0.001803932401530970f,
+     0.002050805379425780f,
+     0.001851476423100084f,
+     0.001088358238163842f,
+    -0.000165599354540670f,
+    -0.001612840277093291f,
+    -0.002799173360323900f,
+    -0.003280737659419560f,
+    -0.002830930204582274f,
+    -0.001589296551711622f,
+    -0.000060142418430366f,
+     0.001072157673911288f,
+     0.001252059507347206f,
+     0.000346781210023729f,
+    -0.001233491421169468f,
+    -0.002682865592015316f,
+    -0.003178340139233828f,
+    -0.002320119390193667f,
+    -0.000402092792444196f,
+     0.001661437823975322f,
+     0.002761727219457103f,
+     0.002186981534424376f,
+     0.000071307331744879f,
+    -0.002570893712874658f,
+    -0.004301512250227543f,
+    -0.004015094439084645f,
+    -0.001606879839533175f,
+     0.001838674337622738f,
+     0.004510048531846937f,
+     0.004804547613530567f,
+     0.002266863620581679f,
+    -0.002004704037111716f,
+    -0.005785548895574678f,
+    -0.006849655924079080f,
+    -0.004239720077392586f,
+     0.001024318787772757f,
+     0.006275193248599259f,
+     0.008511512338709764f,
+     0.006070603106211769f,
+    -0.000247611530141919f,
+    -0.007317511868656072f,
+    -0.011170336815604164f,
+    -0.009152698013614463f,
+    -0.001621157345452147f,
+     0.007851435931989321f,
+     0.014073238852672171f,
+     0.012972692080589394f,
+     0.004087473189926854f,
+    -0.008634954375856124f,
+    -0.018413964067748419f,
+    -0.019050011539439745f,
+    -0.008545626179408438f,
+     0.009039966712164142f,
+     0.024793283315122296f,
+     0.029034181171149441f,
+     0.016560363014866013f,
+    -0.009522346448795137f,
+    -0.037569562545468192f,
+    -0.051411140638474247f,
+    -0.037221789978391415f,
+     0.009679493935209005f,
+     0.081286213859684806f,
+     0.158552299980228740f,
+     0.217917169253869340f,
+     0.240164834839879550f,
+     0.217917169253869340f,
+     0.158552299980228740f,
+     0.081286213859684806f,
+     0.009679493935209005f,
+    -0.037221789978391415f,
+    -0.051411140638474247f,
+    -0.037569562545468192f,
+    -0.009522346448795137f,
+     0.016560363014866013f,
+     0.029034181171149441f,
+     0.024793283315122296f,
+     0.009039966712164142f,
+    -0.008545626179408438f,
+    -0.019050011539439745f,
+    -0.018413964067748419f,
+    -0.008634954375856124f,
+     0.004087473189926854f,
+     0.012972692080589394f,
+     0.014073238852672171f,
+     0.007851435931989321f,
+    -0.001621157345452147f,
+    -0.009152698013614463f,
+    -0.011170336815604164f,
+    -0.007317511868656072f,
+    -0.000247611530141919f,
+     0.006070603106211769f,
+     0.008511512338709764f,
+     0.006275193248599259f,
+     0.001024318787772757f,
+    -0.004239720077392586f,
+    -0.006849655924079080f,
+    -0.005785548895574678f,
+    -0.002004704037111716f,
+     0.002266863620581679f,
+     0.004804547613530567f,
+     0.004510048531846937f,
+     0.001838674337622738f,
+    -0.001606879839533175f,
+    -0.004015094439084645f,
+    -0.004301512250227543f,
+    -0.002570893712874658f,
+     0.000071307331744879f,
+     0.002186981534424376f,
+     0.002761727219457103f,
+     0.001661437823975322f,
+    -0.000402092792444196f,
+    -0.002320119390193667f,
+    -0.003178340139233828f,
+    -0.002682865592015316f,
+    -0.001233491421169468f,
+     0.000346781210023729f,
+     0.001252059507347206f,
+     0.001072157673911288f,
+    -0.000060142418430366f,
+    -0.001589296551711622f,
+    -0.002830930204582274f,
+    -0.003280737659419560f,
+    -0.002799173360323900f,
+    -0.001612840277093291f,
+    -0.000165599354540670f,
+     0.001088358238163842f,
+     0.001851476423100084f,
+     0.002050805379425780f,
+     0.001803932401530970f,
+     0.001323484844111109f,
+     0.000815488719349860f,
+     0.000413474829003805f,
+     0.000162480875041441f,
+     0.000042167047949931f
 };
 
 static const int d_8_r_8_len = 280;
 static const float d_8_r_8_kernel[] =
 {
-	 0.000005299484859782f,
-	 0.000023653198869943f,
-	 0.000045443155025411f,
-	 0.000086660616597102f,
-	 0.000145468147843215f,
-	 0.000227646032445337f,
-	 0.000334591194217999f,
-	 0.000466890457500183f,
-	 0.000622018386430552f,
-	 0.000794466626663634f,
-	 0.000975304575250323f,
-	 0.001152454785657775f,
-	 0.001311296864337127f,
-	 0.001435783630074849f,
-	 0.001509953148215840f,
-	 0.001519741581366084f,
-	 0.001454903824191261f,
-	 0.001310813201213376f,
-	 0.001089882810057675f,
-	 0.000802361759738747f,
-	 0.000466304093914126f,
-	 0.000106589241438445f,
-	-0.000247017317721992f,
-	-0.000562646941659305f,
-	-0.000809708828030606f,
-	-0.000962510996013040f,
-	-0.001003685261621032f,
-	-0.000926952775265634f,
-	-0.000738799897838057f,
-	-0.000458730744403599f,
-	-0.000117916487516219f,
-	 0.000243742648939376f,
-	 0.000581911777806535f,
-	 0.000853035291692318f,
-	 0.001019866746633974f,
-	 0.001056611000192218f,
-	 0.000952962453331239f,
-	 0.000716408838645576f,
-	 0.000372351073038558f,
-	-0.000038150274869667f,
-	-0.000462881782404900f,
-	-0.000844797294892937f,
-	-0.001129425716907750f,
-	-0.001272432677940103f,
-	-0.001246307890160262f,
-	-0.001045192378203970f,
-	-0.000687044203214210f,
-	-0.000212653183490116f,
-	 0.000318579724580746f,
-	 0.000835734644546107f,
-	 0.001265542439063603f,
-	 0.001542487733459282f,
-	 0.001618487960413105f,
-	 0.001470755262270050f,
-	 0.001106608046232222f,
-	 0.000564346197878288f,
-	-0.000090197750452171f,
-	-0.000771230463597417f,
-	-0.001383890554706424f,
-	-0.001837132239362339f,
-	-0.002056896211703681f,
-	-0.001997709076123834f,
-	-0.001650953765714851f,
-	-0.001048413504576680f,
-	-0.000260276733547870f,
-	 0.000612469118131840f,
-	 0.001450527381084600f,
-	 0.002132190093380017f,
-	 0.002550584440683641f,
-	 0.002629881881769309f,
-	 0.002338080196576415f,
-	 0.001694308341293216f,
-	 0.000769260408641065f,
-	-0.000321736170028782f,
-	-0.001432485915523021f,
-	-0.002404976322971185f,
-	-0.003091310085438950f,
-	-0.003375549372556256f,
-	-0.003192330168178722f,
-	-0.002539372888669491f,
-	-0.001481713556478757f,
-	-0.000146533823587781f,
-	 0.001291251516558131f,
-	 0.002631154368260663f,
-	 0.003674321213032700f,
-	 0.004252198884660451f,
-	 0.004252637433548458f,
-	 0.003639528435255283f,
-	 0.002462762274858131f,
-	 0.000856475239499534f,
-	-0.000974892854265319f,
-	-0.002781496880057425f,
-	-0.004301065594668099f,
-	-0.005295755541230454f,
-	-0.005587859925192526f,
-	-0.005089203765495300f,
-	-0.003819632950038145f,
-	-0.001911267954229858f,
-	 0.000402995000090862f,
-	 0.002816115056235722f,
-	 0.004985868963592199f,
-	 0.006581423530514738f,
-	 0.007331423828496663f,
-	 0.007066900231758860f,
-	 0.005752595831756849f,
-	 0.003501526672561130f,
-	 0.000569595914029656f,
-	-0.002670342281476470f,
-	-0.005772755486290897f,
-	-0.008277141861910673f,
-	-0.009772095428011296f,
-	-0.009957304065452081f,
-	-0.008694779007964944f,
-	-0.006041501906687299f,
-	-0.002257673645446692f,
-	 0.002212348869418207f,
-	 0.006785874581560984f,
-	 0.010810304734210376f,
-	 0.013646746123386143f,
-	 0.014758915386036504f,
-	 0.013796112346034117f,
-	 0.010659097540521932f,
-	 0.005539210274923477f,
-	-0.001076115841043161f,
-	-0.008434444147245189f,
-	-0.015584625308516726f,
-	-0.021472430244782261f,
-	-0.025055744331654087f,
-	-0.025426655616721288f,
-	-0.021926322954481325f,
-	-0.014238733805135361f,
-	-0.002451384366749276f,
-	 0.012925647002682830f,
-	 0.030986186274100380f,
-	 0.050498778538203032f,
-	 0.070015421670629074f,
-	 0.088007266252761618f,
-	 0.103012981470773550f,
-	 0.113783757663955240f,
-	 0.119409036455313980f,
-	 0.119409036455313980f,
-	 0.113783757663955240f,
-	 0.103012981470773550f,
-	 0.088007266252761618f,
-	 0.070015421670629074f,
-	 0.050498778538203032f,
-	 0.030986186274100380f,
-	 0.012925647002682830f,
-	-0.002451384366749276f,
-	-0.014238733805135361f,
-	-0.021926322954481325f,
-	-0.025426655616721288f,
-	-0.025055744331654087f,
-	-0.021472430244782261f,
-	-0.015584625308516726f,
-	-0.008434444147245189f,
-	-0.001076115841043161f,
-	 0.005539210274923477f,
-	 0.010659097540521932f,
-	 0.013796112346034117f,
-	 0.014758915386036504f,
-	 0.013646746123386143f,
-	 0.010810304734210376f,
-	 0.006785874581560984f,
-	 0.002212348869418207f,
-	-0.002257673645446692f,
-	-0.006041501906687299f,
-	-0.008694779007964944f,
-	-0.009957304065452081f,
-	-0.009772095428011296f,
-	-0.008277141861910673f,
-	-0.005772755486290897f,
-	-0.002670342281476470f,
-	 0.000569595914029656f,
-	 0.003501526672561130f,
-	 0.005752595831756849f,
-	 0.007066900231758860f,
-	 0.007331423828496663f,
-	 0.006581423530514738f,
-	 0.004985868963592199f,
-	 0.002816115056235722f,
-	 0.000402995000090862f,
-	-0.001911267954229858f,
-	-0.003819632950038145f,
-	-0.005089203765495300f,
-	-0.005587859925192526f,
-	-0.005295755541230454f,
-	-0.004301065594668099f,
-	-0.002781496880057425f,
-	-0.000974892854265319f,
-	 0.000856475239499534f,
-	 0.002462762274858131f,
-	 0.003639528435255283f,
-	 0.004252637433548458f,
-	 0.004252198884660451f,
-	 0.003674321213032700f,
-	 0.002631154368260663f,
-	 0.001291251516558131f,
-	-0.000146533823587781f,
-	-0.001481713556478757f,
-	-0.002539372888669491f,
-	-0.003192330168178722f,
-	-0.003375549372556256f,
-	-0.003091310085438950f,
-	-0.002404976322971185f,
-	-0.001432485915523021f,
-	-0.000321736170028782f,
-	 0.000769260408641065f,
-	 0.001694308341293216f,
-	 0.002338080196576415f,
-	 0.002629881881769309f,
-	 0.002550584440683641f,
-	 0.002132190093380017f,
-	 0.001450527381084600f,
-	 0.000612469118131840f,
-	-0.000260276733547870f,
-	-0.001048413504576680f,
-	-0.001650953765714851f,
-	-0.001997709076123834f,
-	-0.002056896211703681f,
-	-0.001837132239362339f,
-	-0.001383890554706424f,
-	-0.000771230463597417f,
-	-0.000090197750452171f,
-	 0.000564346197878288f,
-	 0.001106608046232222f,
-	 0.001470755262270050f,
-	 0.001618487960413105f,
-	 0.001542487733459282f,
-	 0.001265542439063603f,
-	 0.000835734644546107f,
-	 0.000318579724580746f,
-	-0.000212653183490116f,
-	-0.000687044203214210f,
-	-0.001045192378203970f,
-	-0.001246307890160262f,
-	-0.001272432677940103f,
-	-0.001129425716907750f,
-	-0.000844797294892937f,
-	-0.000462881782404900f,
-	-0.000038150274869667f,
-	 0.000372351073038558f,
-	 0.000716408838645576f,
-	 0.000952962453331239f,
-	 0.001056611000192218f,
-	 0.001019866746633974f,
-	 0.000853035291692318f,
-	 0.000581911777806535f,
-	 0.000243742648939376f,
-	-0.000117916487516219f,
-	-0.000458730744403599f,
-	-0.000738799897838057f,
-	-0.000926952775265634f,
-	-0.001003685261621032f,
-	-0.000962510996013040f,
-	-0.000809708828030606f,
-	-0.000562646941659305f,
-	-0.000247017317721992f,
-	 0.000106589241438445f,
-	 0.000466304093914126f,
-	 0.000802361759738747f,
-	 0.001089882810057675f,
-	 0.001310813201213376f,
-	 0.001454903824191261f,
-	 0.001519741581366084f,
-	 0.001509953148215840f,
-	 0.001435783630074849f,
-	 0.001311296864337127f,
-	 0.001152454785657775f,
-	 0.000975304575250323f,
-	 0.000794466626663634f,
-	 0.000622018386430552f,
-	 0.000466890457500183f,
-	 0.000334591194217999f,
-	 0.000227646032445337f,
-	 0.000145468147843215f,
-	 0.000086660616597102f,
-	 0.000045443155025411f,
-	 0.000023653198869943f,
-	 0.000005299484859782f
+     0.000005299484859782f,
+     0.000023653198869943f,
+     0.000045443155025411f,
+     0.000086660616597102f,
+     0.000145468147843215f,
+     0.000227646032445337f,
+     0.000334591194217999f,
+     0.000466890457500183f,
+     0.000622018386430552f,
+     0.000794466626663634f,
+     0.000975304575250323f,
+     0.001152454785657775f,
+     0.001311296864337127f,
+     0.001435783630074849f,
+     0.001509953148215840f,
+     0.001519741581366084f,
+     0.001454903824191261f,
+     0.001310813201213376f,
+     0.001089882810057675f,
+     0.000802361759738747f,
+     0.000466304093914126f,
+     0.000106589241438445f,
+    -0.000247017317721992f,
+    -0.000562646941659305f,
+    -0.000809708828030606f,
+    -0.000962510996013040f,
+    -0.001003685261621032f,
+    -0.000926952775265634f,
+    -0.000738799897838057f,
+    -0.000458730744403599f,
+    -0.000117916487516219f,
+     0.000243742648939376f,
+     0.000581911777806535f,
+     0.000853035291692318f,
+     0.001019866746633974f,
+     0.001056611000192218f,
+     0.000952962453331239f,
+     0.000716408838645576f,
+     0.000372351073038558f,
+    -0.000038150274869667f,
+    -0.000462881782404900f,
+    -0.000844797294892937f,
+    -0.001129425716907750f,
+    -0.001272432677940103f,
+    -0.001246307890160262f,
+    -0.001045192378203970f,
+    -0.000687044203214210f,
+    -0.000212653183490116f,
+     0.000318579724580746f,
+     0.000835734644546107f,
+     0.001265542439063603f,
+     0.001542487733459282f,
+     0.001618487960413105f,
+     0.001470755262270050f,
+     0.001106608046232222f,
+     0.000564346197878288f,
+    -0.000090197750452171f,
+    -0.000771230463597417f,
+    -0.001383890554706424f,
+    -0.001837132239362339f,
+    -0.002056896211703681f,
+    -0.001997709076123834f,
+    -0.001650953765714851f,
+    -0.001048413504576680f,
+    -0.000260276733547870f,
+     0.000612469118131840f,
+     0.001450527381084600f,
+     0.002132190093380017f,
+     0.002550584440683641f,
+     0.002629881881769309f,
+     0.002338080196576415f,
+     0.001694308341293216f,
+     0.000769260408641065f,
+    -0.000321736170028782f,
+    -0.001432485915523021f,
+    -0.002404976322971185f,
+    -0.003091310085438950f,
+    -0.003375549372556256f,
+    -0.003192330168178722f,
+    -0.002539372888669491f,
+    -0.001481713556478757f,
+    -0.000146533823587781f,
+     0.001291251516558131f,
+     0.002631154368260663f,
+     0.003674321213032700f,
+     0.004252198884660451f,
+     0.004252637433548458f,
+     0.003639528435255283f,
+     0.002462762274858131f,
+     0.000856475239499534f,
+    -0.000974892854265319f,
+    -0.002781496880057425f,
+    -0.004301065594668099f,
+    -0.005295755541230454f,
+    -0.005587859925192526f,
+    -0.005089203765495300f,
+    -0.003819632950038145f,
+    -0.001911267954229858f,
+     0.000402995000090862f,
+     0.002816115056235722f,
+     0.004985868963592199f,
+     0.006581423530514738f,
+     0.007331423828496663f,
+     0.007066900231758860f,
+     0.005752595831756849f,
+     0.003501526672561130f,
+     0.000569595914029656f,
+    -0.002670342281476470f,
+    -0.005772755486290897f,
+    -0.008277141861910673f,
+    -0.009772095428011296f,
+    -0.009957304065452081f,
+    -0.008694779007964944f,
+    -0.006041501906687299f,
+    -0.002257673645446692f,
+     0.002212348869418207f,
+     0.006785874581560984f,
+     0.010810304734210376f,
+     0.013646746123386143f,
+     0.014758915386036504f,
+     0.013796112346034117f,
+     0.010659097540521932f,
+     0.005539210274923477f,
+    -0.001076115841043161f,
+    -0.008434444147245189f,
+    -0.015584625308516726f,
+    -0.021472430244782261f,
+    -0.025055744331654087f,
+    -0.025426655616721288f,
+    -0.021926322954481325f,
+    -0.014238733805135361f,
+    -0.002451384366749276f,
+     0.012925647002682830f,
+     0.030986186274100380f,
+     0.050498778538203032f,
+     0.070015421670629074f,
+     0.088007266252761618f,
+     0.103012981470773550f,
+     0.113783757663955240f,
+     0.119409036455313980f,
+     0.119409036455313980f,
+     0.113783757663955240f,
+     0.103012981470773550f,
+     0.088007266252761618f,
+     0.070015421670629074f,
+     0.050498778538203032f,
+     0.030986186274100380f,
+     0.012925647002682830f,
+    -0.002451384366749276f,
+    -0.014238733805135361f,
+    -0.021926322954481325f,
+    -0.025426655616721288f,
+    -0.025055744331654087f,
+    -0.021472430244782261f,
+    -0.015584625308516726f,
+    -0.008434444147245189f,
+    -0.001076115841043161f,
+     0.005539210274923477f,
+     0.010659097540521932f,
+     0.013796112346034117f,
+     0.014758915386036504f,
+     0.013646746123386143f,
+     0.010810304734210376f,
+     0.006785874581560984f,
+     0.002212348869418207f,
+    -0.002257673645446692f,
+    -0.006041501906687299f,
+    -0.008694779007964944f,
+    -0.009957304065452081f,
+    -0.009772095428011296f,
+    -0.008277141861910673f,
+    -0.005772755486290897f,
+    -0.002670342281476470f,
+     0.000569595914029656f,
+     0.003501526672561130f,
+     0.005752595831756849f,
+     0.007066900231758860f,
+     0.007331423828496663f,
+     0.006581423530514738f,
+     0.004985868963592199f,
+     0.002816115056235722f,
+     0.000402995000090862f,
+    -0.001911267954229858f,
+    -0.003819632950038145f,
+    -0.005089203765495300f,
+    -0.005587859925192526f,
+    -0.005295755541230454f,
+    -0.004301065594668099f,
+    -0.002781496880057425f,
+    -0.000974892854265319f,
+     0.000856475239499534f,
+     0.002462762274858131f,
+     0.003639528435255283f,
+     0.004252637433548458f,
+     0.004252198884660451f,
+     0.003674321213032700f,
+     0.002631154368260663f,
+     0.001291251516558131f,
+    -0.000146533823587781f,
+    -0.001481713556478757f,
+    -0.002539372888669491f,
+    -0.003192330168178722f,
+    -0.003375549372556256f,
+    -0.003091310085438950f,
+    -0.002404976322971185f,
+    -0.001432485915523021f,
+    -0.000321736170028782f,
+     0.000769260408641065f,
+     0.001694308341293216f,
+     0.002338080196576415f,
+     0.002629881881769309f,
+     0.002550584440683641f,
+     0.002132190093380017f,
+     0.001450527381084600f,
+     0.000612469118131840f,
+    -0.000260276733547870f,
+    -0.001048413504576680f,
+    -0.001650953765714851f,
+    -0.001997709076123834f,
+    -0.002056896211703681f,
+    -0.001837132239362339f,
+    -0.001383890554706424f,
+    -0.000771230463597417f,
+    -0.000090197750452171f,
+     0.000564346197878288f,
+     0.001106608046232222f,
+     0.001470755262270050f,
+     0.001618487960413105f,
+     0.001542487733459282f,
+     0.001265542439063603f,
+     0.000835734644546107f,
+     0.000318579724580746f,
+    -0.000212653183490116f,
+    -0.000687044203214210f,
+    -0.001045192378203970f,
+    -0.001246307890160262f,
+    -0.001272432677940103f,
+    -0.001129425716907750f,
+    -0.000844797294892937f,
+    -0.000462881782404900f,
+    -0.000038150274869667f,
+     0.000372351073038558f,
+     0.000716408838645576f,
+     0.000952962453331239f,
+     0.001056611000192218f,
+     0.001019866746633974f,
+     0.000853035291692318f,
+     0.000581911777806535f,
+     0.000243742648939376f,
+    -0.000117916487516219f,
+    -0.000458730744403599f,
+    -0.000738799897838057f,
+    -0.000926952775265634f,
+    -0.001003685261621032f,
+    -0.000962510996013040f,
+    -0.000809708828030606f,
+    -0.000562646941659305f,
+    -0.000247017317721992f,
+     0.000106589241438445f,
+     0.000466304093914126f,
+     0.000802361759738747f,
+     0.001089882810057675f,
+     0.001310813201213376f,
+     0.001454903824191261f,
+     0.001519741581366084f,
+     0.001509953148215840f,
+     0.001435783630074849f,
+     0.001311296864337127f,
+     0.001152454785657775f,
+     0.000975304575250323f,
+     0.000794466626663634f,
+     0.000622018386430552f,
+     0.000466890457500183f,
+     0.000334591194217999f,
+     0.000227646032445337f,
+     0.000145468147843215f,
+     0.000086660616597102f,
+     0.000045443155025411f,
+     0.000023653198869943f,
+     0.000005299484859782f
 };
 
 static const int d_16_r_8_len = 54;
 static const float d_16_r_8_kernel[] =
 {
-	-0.000010553664672862f,
-	-0.000061498701563991f,
-	-0.000169601122616288f,
-	-0.000389180581238296f,
-	-0.000769984128346191f,
-	-0.001370862255977838f,
-	-0.002239657737237394f,
-	-0.003399895346870093f,
-	-0.004830710741492023f,
-	-0.006448450828431843f,
-	-0.008091858901382079f,
-	-0.009515843884697457f,
-	-0.010397443295914180f,
-	-0.010356613550454467f,
-	-0.008992200646607676f,
-	-0.005930785604319544f,
-	-0.000883275448312690f,
-	 0.006298249742162992f,
-	 0.015572313369334116f,
-	 0.026677316967261836f,
-	 0.039125602626276818f,
-	 0.052226529544645239f,
-	 0.065138652777540620f,
-	 0.076946528099683636f,
-	 0.086753462256061120f,
-	 0.093778457566739207f,
-	 0.097444274566674538f,
-	 0.097444274566674538f,
-	 0.093778457566739207f,
-	 0.086753462256061120f,
-	 0.076946528099683636f,
-	 0.065138652777540620f,
-	 0.052226529544645239f,
-	 0.039125602626276818f,
-	 0.026677316967261836f,
-	 0.015572313369334116f,
-	 0.006298249742162992f,
-	-0.000883275448312690f,
-	-0.005930785604319544f,
-	-0.008992200646607676f,
-	-0.010356613550454467f,
-	-0.010397443295914180f,
-	-0.009515843884697457f,
-	-0.008091858901382079f,
-	-0.006448450828431843f,
-	-0.004830710741492023f,
-	-0.003399895346870093f,
-	-0.002239657737237394f,
-	-0.001370862255977838f,
-	-0.000769984128346191f,
-	-0.000389180581238296f,
-	-0.000169601122616288f,
-	-0.000061498701563991f,
-	-0.000010553664672862f
+    -0.000010553664672862f,
+    -0.000061498701563991f,
+    -0.000169601122616288f,
+    -0.000389180581238296f,
+    -0.000769984128346191f,
+    -0.001370862255977838f,
+    -0.002239657737237394f,
+    -0.003399895346870093f,
+    -0.004830710741492023f,
+    -0.006448450828431843f,
+    -0.008091858901382079f,
+    -0.009515843884697457f,
+    -0.010397443295914180f,
+    -0.010356613550454467f,
+    -0.008992200646607676f,
+    -0.005930785604319544f,
+    -0.000883275448312690f,
+     0.006298249742162992f,
+     0.015572313369334116f,
+     0.026677316967261836f,
+     0.039125602626276818f,
+     0.052226529544645239f,
+     0.065138652777540620f,
+     0.076946528099683636f,
+     0.086753462256061120f,
+     0.093778457566739207f,
+     0.097444274566674538f,
+     0.097444274566674538f,
+     0.093778457566739207f,
+     0.086753462256061120f,
+     0.076946528099683636f,
+     0.065138652777540620f,
+     0.052226529544645239f,
+     0.039125602626276818f,
+     0.026677316967261836f,
+     0.015572313369334116f,
+     0.006298249742162992f,
+    -0.000883275448312690f,
+    -0.005930785604319544f,
+    -0.008992200646607676f,
+    -0.010356613550454467f,
+    -0.010397443295914180f,
+    -0.009515843884697457f,
+    -0.008091858901382079f,
+    -0.006448450828431843f,
+    -0.004830710741492023f,
+    -0.003399895346870093f,
+    -0.002239657737237394f,
+    -0.001370862255977838f,
+    -0.000769984128346191f,
+    -0.000389180581238296f,
+    -0.000169601122616288f,
+    -0.000061498701563991f,
+    -0.000010553664672862f
 };
 
 static const int d_32_r_16_len = 107;
 static const float d_32_r_16_kernel[] =
 {
-	-0.000004024163639795f,
-	-0.000017672975608646f,
-	-0.000028369983125930f,
-	-0.000051841257358260f,
-	-0.000084114931088978f,
-	-0.000130374705334955f,
-	-0.000193165706690690f,
-	-0.000276282392544972f,
-	-0.000383294466797586f,
-	-0.000517836385761646f,
-	-0.000683246849920059f,
-	-0.000882378788952720f,
-	-0.001117308161626894f,
-	-0.001389043294976996f,
-	-0.001697213461428019f,
-	-0.002039760314912465f,
-	-0.002412643435722481f,
-	-0.002809577646098091f,
-	-0.003221818992095683f,
-	-0.003638016956253216f,
-	-0.004044149516577933f,
-	-0.004423556043039536f,
-	-0.004757080371798020f,
-	-0.005023332869090757f,
-	-0.005199075945795754f,
-	-0.005259732456805450f,
-	-0.005180010907146506f,
-	-0.004934635615957972f,
-	-0.004499164222082719f,
-	-0.003850869437258024f,
-	-0.002969657050308204f,
-	-0.001838988139263688f,
-	-0.000446770521598867f,
-	 0.001213817123243464f,
-	 0.003143605116121320f,
-	 0.005336851770962665f,
-	 0.007780833517050342f,
-	 0.010455633416035585f,
-	 0.013334149150643793f,
-	 0.016382334116677784f,
-	 0.019559676833852839f,
-	 0.022819914826782396f,
-	 0.026111969807273771f,
-	 0.029381081811115123f,
-	 0.032570111325119062f,
-	 0.035620970792186964f,
-	 0.038476140562399175f,
-	 0.041080219701286683f,
-	 0.043381459308086866f,
-	 0.045333225316341701f,
-	 0.046895339212960678f,
-	 0.048035248704517766f,
-	 0.048728985952954711f,
-	 0.048961878385199747f,
-	 0.048728985952954711f,
-	 0.048035248704517766f,
-	 0.046895339212960678f,
-	 0.045333225316341701f,
-	 0.043381459308086866f,
-	 0.041080219701286683f,
-	 0.038476140562399175f,
-	 0.035620970792186964f,
-	 0.032570111325119062f,
-	 0.029381081811115123f,
-	 0.026111969807273771f,
-	 0.022819914826782396f,
-	 0.019559676833852839f,
-	 0.016382334116677784f,
-	 0.013334149150643793f,
-	 0.010455633416035585f,
-	 0.007780833517050342f,
-	 0.005336851770962665f,
-	 0.003143605116121320f,
-	 0.001213817123243464f,
-	-0.000446770521598867f,
-	-0.001838988139263688f,
-	-0.002969657050308204f,
-	-0.003850869437258024f,
-	-0.004499164222082719f,
-	-0.004934635615957972f,
-	-0.005180010907146506f,
-	-0.005259732456805450f,
-	-0.005199075945795754f,
-	-0.005023332869090757f,
-	-0.004757080371798020f,
-	-0.004423556043039536f,
-	-0.004044149516577933f,
-	-0.003638016956253216f,
-	-0.003221818992095683f,
-	-0.002809577646098091f,
-	-0.002412643435722481f,
-	-0.002039760314912465f,
-	-0.001697213461428019f,
-	-0.001389043294976996f,
-	-0.001117308161626894f,
-	-0.000882378788952720f,
-	-0.000683246849920059f,
-	-0.000517836385761646f,
-	-0.000383294466797586f,
-	-0.000276282392544972f,
-	-0.000193165706690690f,
-	-0.000130374705334955f,
-	-0.000084114931088978f,
-	-0.000051841257358260f,
-	-0.000028369983125930f,
-	-0.000017672975608646f,
-	-0.000004024163639795f
+    -0.000004024163639795f,
+    -0.000017672975608646f,
+    -0.000028369983125930f,
+    -0.000051841257358260f,
+    -0.000084114931088978f,
+    -0.000130374705334955f,
+    -0.000193165706690690f,
+    -0.000276282392544972f,
+    -0.000383294466797586f,
+    -0.000517836385761646f,
+    -0.000683246849920059f,
+    -0.000882378788952720f,
+    -0.001117308161626894f,
+    -0.001389043294976996f,
+    -0.001697213461428019f,
+    -0.002039760314912465f,
+    -0.002412643435722481f,
+    -0.002809577646098091f,
+    -0.003221818992095683f,
+    -0.003638016956253216f,
+    -0.004044149516577933f,
+    -0.004423556043039536f,
+    -0.004757080371798020f,
+    -0.005023332869090757f,
+    -0.005199075945795754f,
+    -0.005259732456805450f,
+    -0.005180010907146506f,
+    -0.004934635615957972f,
+    -0.004499164222082719f,
+    -0.003850869437258024f,
+    -0.002969657050308204f,
+    -0.001838988139263688f,
+    -0.000446770521598867f,
+     0.001213817123243464f,
+     0.003143605116121320f,
+     0.005336851770962665f,
+     0.007780833517050342f,
+     0.010455633416035585f,
+     0.013334149150643793f,
+     0.016382334116677784f,
+     0.019559676833852839f,
+     0.022819914826782396f,
+     0.026111969807273771f,
+     0.029381081811115123f,
+     0.032570111325119062f,
+     0.035620970792186964f,
+     0.038476140562399175f,
+     0.041080219701286683f,
+     0.043381459308086866f,
+     0.045333225316341701f,
+     0.046895339212960678f,
+     0.048035248704517766f,
+     0.048728985952954711f,
+     0.048961878385199747f,
+     0.048728985952954711f,
+     0.048035248704517766f,
+     0.046895339212960678f,
+     0.045333225316341701f,
+     0.043381459308086866f,
+     0.041080219701286683f,
+     0.038476140562399175f,
+     0.035620970792186964f,
+     0.032570111325119062f,
+     0.029381081811115123f,
+     0.026111969807273771f,
+     0.022819914826782396f,
+     0.019559676833852839f,
+     0.016382334116677784f,
+     0.013334149150643793f,
+     0.010455633416035585f,
+     0.007780833517050342f,
+     0.005336851770962665f,
+     0.003143605116121320f,
+     0.001213817123243464f,
+    -0.000446770521598867f,
+    -0.001838988139263688f,
+    -0.002969657050308204f,
+    -0.003850869437258024f,
+    -0.004499164222082719f,
+    -0.004934635615957972f,
+    -0.005180010907146506f,
+    -0.005259732456805450f,
+    -0.005199075945795754f,
+    -0.005023332869090757f,
+    -0.004757080371798020f,
+    -0.004423556043039536f,
+    -0.004044149516577933f,
+    -0.003638016956253216f,
+    -0.003221818992095683f,
+    -0.002809577646098091f,
+    -0.002412643435722481f,
+    -0.002039760314912465f,
+    -0.001697213461428019f,
+    -0.001389043294976996f,
+    -0.001117308161626894f,
+    -0.000882378788952720f,
+    -0.000683246849920059f,
+    -0.000517836385761646f,
+    -0.000383294466797586f,
+    -0.000276282392544972f,
+    -0.000193165706690690f,
+    -0.000130374705334955f,
+    -0.000084114931088978f,
+    -0.000051841257358260f,
+    -0.000028369983125930f,
+    -0.000017672975608646f,
+    -0.000004024163639795f
 };
 
 static const int d_64_r_32_len = 212;
 static const float d_64_r_32_kernel[] =
 {
-	-0.000004403823942508f,
-	-0.000008963059919890f,
-	-0.000007276052892980f,
-	-0.000013448546764569f,
-	-0.000016407338246392f,
-	-0.000022821877811828f,
-	-0.000029059859493782f,
-	-0.000037502053326083f,
-	-0.000047050128769168f,
-	-0.000058647705667398f,
-	-0.000072066821233235f,
-	-0.000087775432302674f,
-	-0.000105848488644829f,
-	-0.000126598475702349f,
-	-0.000150205141042045f,
-	-0.000176926965601505f,
-	-0.000206973701715915f,
-	-0.000240575602493366f,
-	-0.000277937749971926f,
-	-0.000319260777052827f,
-	-0.000364722541989086f,
-	-0.000414482134953896f,
-	-0.000468670554403767f,
-	-0.000527388854339363f,
-	-0.000590701722925615f,
-	-0.000658633566464172f,
-	-0.000731163061150287f,
-	-0.000808218604975926f,
-	-0.000889673345622962f,
-	-0.000975340650633742f,
-	-0.001064969616730599f,
-	-0.001158240957389821f,
-	-0.001254763178484453f,
-	-0.001354069203096897f,
-	-0.001455613461052586f,
-	-0.001558769541846508f,
-	-0.001662828458596891f,
-	-0.001766997597152117f,
-	-0.001870400403116935f,
-	-0.001972076865069115f,
-	-0.002070984841172726f,
-	-0.002166002272448999f,
-	-0.002255930317598858f,
-	-0.002339497436442704f,
-	-0.002415364439683740f,
-	-0.002482130514177367f,
-	-0.002538340220525754f,
-	-0.002582491452580508f,
-	-0.002613044332960035f,
-	-0.002628431011812668f,
-	-0.002627066321370591f,
-	-0.002607359228695053f,
-	-0.002567725018271331f,
-	-0.002506598123060911f,
-	-0.002422445514576562f,
-	-0.002313780550524778f,
-	-0.002179177170034060f,
-	-0.002017284317828416f,
-	-0.001826840471286680f,
-	-0.001606688137875605f,
-	-0.001355788185007890f,
-	-0.001073233860638388f,
-	-0.000758264360902667f,
-	-0.000410277798843436f,
-	-0.000028843430628706f,
-	 0.000386287004249912f,
-	 0.000835168966487215f,
-	 0.001317655958647924f,
-	 0.001833391650175865f,
-	 0.002381803404668191f,
-	 0.002962097316406667f,
-	 0.003573254853063226f,
-	 0.004214031187543062f,
-	 0.004882955288187807f,
-	 0.005578331822331469f,
-	 0.006298244909815173f,
-	 0.007040563748502659f,
-	 0.007802950114525442f,
-	 0.008582867722817980f,
-	 0.009377593413961051f,
-	 0.010184230117287451f,
-	 0.010999721518727896f,
-	 0.011820868346749476f,
-	 0.012644346170734195f,
-	 0.013466724590201118f,
-	 0.014284487677241258f,
-	 0.015094055520281103f,
-	 0.015891806704001060f,
-	 0.016674101548252919f,
-	 0.017437305919088521f,
-	 0.018177815416425963f,
-	 0.018892079736813970f,
-	 0.019576627004361302f,
-	 0.020228087861972253f,
-	 0.020843219113185100f,
-	 0.021418926707647539f,
-	 0.021952287867040517f,
-	 0.022440572154110033f,
-	 0.022881261295670835f,
-	 0.023272067580484536f,
-	 0.023610950665041715f,
-	 0.023896132633698622f,
-	 0.024126111175283287f,
-	 0.024299670755100852f,
-	 0.024415891678976044f,
-	 0.024474156966027200f,
-	 0.024474156966027200f,
-	 0.024415891678976044f,
-	 0.024299670755100852f,
-	 0.024126111175283287f,
-	 0.023896132633698622f,
-	 0.023610950665041715f,
-	 0.023272067580484536f,
-	 0.022881261295670835f,
-	 0.022440572154110033f,
-	 0.021952287867040517f,
-	 0.021418926707647539f,
-	 0.020843219113185100f,
-	 0.020228087861972253f,
-	 0.019576627004361302f,
-	 0.018892079736813970f,
-	 0.018177815416425963f,
-	 0.017437305919088521f,
-	 0.016674101548252919f,
-	 0.015891806704001060f,
-	 0.015094055520281103f,
-	 0.014284487677241258f,
-	 0.013466724590201118f,
-	 0.012644346170734195f,
-	 0.011820868346749476f,
-	 0.010999721518727896f,
-	 0.010184230117287451f,
-	 0.009377593413961051f,
-	 0.008582867722817980f,
-	 0.007802950114525442f,
-	 0.007040563748502659f,
-	 0.006298244909815173f,
-	 0.005578331822331469f,
-	 0.004882955288187807f,
-	 0.004214031187543062f,
-	 0.003573254853063226f,
-	 0.002962097316406667f,
-	 0.002381803404668191f,
-	 0.001833391650175865f,
-	 0.001317655958647924f,
-	 0.000835168966487215f,
-	 0.000386287004249912f,
-	-0.000028843430628706f,
-	-0.000410277798843436f,
-	-0.000758264360902667f,
-	-0.001073233860638388f,
-	-0.001355788185007890f,
-	-0.001606688137875605f,
-	-0.001826840471286680f,
-	-0.002017284317828416f,
-	-0.002179177170034060f,
-	-0.002313780550524778f,
-	-0.002422445514576562f,
-	-0.002506598123060911f,
-	-0.002567725018271331f,
-	-0.002607359228695053f,
-	-0.002627066321370591f,
-	-0.002628431011812668f,
-	-0.002613044332960035f,
-	-0.002582491452580508f,
-	-0.002538340220525754f,
-	-0.002482130514177367f,
-	-0.002415364439683740f,
-	-0.002339497436442704f,
-	-0.002255930317598858f,
-	-0.002166002272448999f,
-	-0.002070984841172726f,
-	-0.001972076865069115f,
-	-0.001870400403116935f,
-	-0.001766997597152117f,
-	-0.001662828458596891f,
-	-0.001558769541846508f,
-	-0.001455613461052586f,
-	-0.001354069203096897f,
-	-0.001254763178484453f,
-	-0.001158240957389821f,
-	-0.001064969616730599f,
-	-0.000975340650633742f,
-	-0.000889673345622962f,
-	-0.000808218604975926f,
-	-0.000731163061150287f,
-	-0.000658633566464172f,
-	-0.000590701722925615f,
-	-0.000527388854339363f,
-	-0.000468670554403767f,
-	-0.000414482134953896f,
-	-0.000364722541989086f,
-	-0.000319260777052827f,
-	-0.000277937749971926f,
-	-0.000240575602493366f,
-	-0.000206973701715915f,
-	-0.000176926965601505f,
-	-0.000150205141042045f,
-	-0.000126598475702349f,
-	-0.000105848488644829f,
-	-0.000087775432302674f,
-	-0.000072066821233235f,
-	-0.000058647705667398f,
-	-0.000047050128769168f,
-	-0.000037502053326083f,
-	-0.000029059859493782f,
-	-0.000022821877811828f,
-	-0.000016407338246392f,
-	-0.000013448546764569f,
-	-0.000007276052892980f,
-	-0.000008963059919890f,
-	-0.000004403823942508f
+    -0.000004403823942508f,
+    -0.000008963059919890f,
+    -0.000007276052892980f,
+    -0.000013448546764569f,
+    -0.000016407338246392f,
+    -0.000022821877811828f,
+    -0.000029059859493782f,
+    -0.000037502053326083f,
+    -0.000047050128769168f,
+    -0.000058647705667398f,
+    -0.000072066821233235f,
+    -0.000087775432302674f,
+    -0.000105848488644829f,
+    -0.000126598475702349f,
+    -0.000150205141042045f,
+    -0.000176926965601505f,
+    -0.000206973701715915f,
+    -0.000240575602493366f,
+    -0.000277937749971926f,
+    -0.000319260777052827f,
+    -0.000364722541989086f,
+    -0.000414482134953896f,
+    -0.000468670554403767f,
+    -0.000527388854339363f,
+    -0.000590701722925615f,
+    -0.000658633566464172f,
+    -0.000731163061150287f,
+    -0.000808218604975926f,
+    -0.000889673345622962f,
+    -0.000975340650633742f,
+    -0.001064969616730599f,
+    -0.001158240957389821f,
+    -0.001254763178484453f,
+    -0.001354069203096897f,
+    -0.001455613461052586f,
+    -0.001558769541846508f,
+    -0.001662828458596891f,
+    -0.001766997597152117f,
+    -0.001870400403116935f,
+    -0.001972076865069115f,
+    -0.002070984841172726f,
+    -0.002166002272448999f,
+    -0.002255930317598858f,
+    -0.002339497436442704f,
+    -0.002415364439683740f,
+    -0.002482130514177367f,
+    -0.002538340220525754f,
+    -0.002582491452580508f,
+    -0.002613044332960035f,
+    -0.002628431011812668f,
+    -0.002627066321370591f,
+    -0.002607359228695053f,
+    -0.002567725018271331f,
+    -0.002506598123060911f,
+    -0.002422445514576562f,
+    -0.002313780550524778f,
+    -0.002179177170034060f,
+    -0.002017284317828416f,
+    -0.001826840471286680f,
+    -0.001606688137875605f,
+    -0.001355788185007890f,
+    -0.001073233860638388f,
+    -0.000758264360902667f,
+    -0.000410277798843436f,
+    -0.000028843430628706f,
+     0.000386287004249912f,
+     0.000835168966487215f,
+     0.001317655958647924f,
+     0.001833391650175865f,
+     0.002381803404668191f,
+     0.002962097316406667f,
+     0.003573254853063226f,
+     0.004214031187543062f,
+     0.004882955288187807f,
+     0.005578331822331469f,
+     0.006298244909815173f,
+     0.007040563748502659f,
+     0.007802950114525442f,
+     0.008582867722817980f,
+     0.009377593413961051f,
+     0.010184230117287451f,
+     0.010999721518727896f,
+     0.011820868346749476f,
+     0.012644346170734195f,
+     0.013466724590201118f,
+     0.014284487677241258f,
+     0.015094055520281103f,
+     0.015891806704001060f,
+     0.016674101548252919f,
+     0.017437305919088521f,
+     0.018177815416425963f,
+     0.018892079736813970f,
+     0.019576627004361302f,
+     0.020228087861972253f,
+     0.020843219113185100f,
+     0.021418926707647539f,
+     0.021952287867040517f,
+     0.022440572154110033f,
+     0.022881261295670835f,
+     0.023272067580484536f,
+     0.023610950665041715f,
+     0.023896132633698622f,
+     0.024126111175283287f,
+     0.024299670755100852f,
+     0.024415891678976044f,
+     0.024474156966027200f,
+     0.024474156966027200f,
+     0.024415891678976044f,
+     0.024299670755100852f,
+     0.024126111175283287f,
+     0.023896132633698622f,
+     0.023610950665041715f,
+     0.023272067580484536f,
+     0.022881261295670835f,
+     0.022440572154110033f,
+     0.021952287867040517f,
+     0.021418926707647539f,
+     0.020843219113185100f,
+     0.020228087861972253f,
+     0.019576627004361302f,
+     0.018892079736813970f,
+     0.018177815416425963f,
+     0.017437305919088521f,
+     0.016674101548252919f,
+     0.015891806704001060f,
+     0.015094055520281103f,
+     0.014284487677241258f,
+     0.013466724590201118f,
+     0.012644346170734195f,
+     0.011820868346749476f,
+     0.010999721518727896f,
+     0.010184230117287451f,
+     0.009377593413961051f,
+     0.008582867722817980f,
+     0.007802950114525442f,
+     0.007040563748502659f,
+     0.006298244909815173f,
+     0.005578331822331469f,
+     0.004882955288187807f,
+     0.004214031187543062f,
+     0.003573254853063226f,
+     0.002962097316406667f,
+     0.002381803404668191f,
+     0.001833391650175865f,
+     0.001317655958647924f,
+     0.000835168966487215f,
+     0.000386287004249912f,
+    -0.000028843430628706f,
+    -0.000410277798843436f,
+    -0.000758264360902667f,
+    -0.001073233860638388f,
+    -0.001355788185007890f,
+    -0.001606688137875605f,
+    -0.001826840471286680f,
+    -0.002017284317828416f,
+    -0.002179177170034060f,
+    -0.002313780550524778f,
+    -0.002422445514576562f,
+    -0.002506598123060911f,
+    -0.002567725018271331f,
+    -0.002607359228695053f,
+    -0.002627066321370591f,
+    -0.002628431011812668f,
+    -0.002613044332960035f,
+    -0.002582491452580508f,
+    -0.002538340220525754f,
+    -0.002482130514177367f,
+    -0.002415364439683740f,
+    -0.002339497436442704f,
+    -0.002255930317598858f,
+    -0.002166002272448999f,
+    -0.002070984841172726f,
+    -0.001972076865069115f,
+    -0.001870400403116935f,
+    -0.001766997597152117f,
+    -0.001662828458596891f,
+    -0.001558769541846508f,
+    -0.001455613461052586f,
+    -0.001354069203096897f,
+    -0.001254763178484453f,
+    -0.001158240957389821f,
+    -0.001064969616730599f,
+    -0.000975340650633742f,
+    -0.000889673345622962f,
+    -0.000808218604975926f,
+    -0.000731163061150287f,
+    -0.000658633566464172f,
+    -0.000590701722925615f,
+    -0.000527388854339363f,
+    -0.000468670554403767f,
+    -0.000414482134953896f,
+    -0.000364722541989086f,
+    -0.000319260777052827f,
+    -0.000277937749971926f,
+    -0.000240575602493366f,
+    -0.000206973701715915f,
+    -0.000176926965601505f,
+    -0.000150205141042045f,
+    -0.000126598475702349f,
+    -0.000105848488644829f,
+    -0.000087775432302674f,
+    -0.000072066821233235f,
+    -0.000058647705667398f,
+    -0.000047050128769168f,
+    -0.000037502053326083f,
+    -0.000029059859493782f,
+    -0.000022821877811828f,
+    -0.000016407338246392f,
+    -0.000013448546764569f,
+    -0.000007276052892980f,
+    -0.000008963059919890f,
+    -0.000004403823942508f
 };
 
 static const int d_128_r_32_len = 174;
 static const float d_128_r_32_kernel[] =
 {
-	-0.000007703161797332f,
-	-0.000007067232655723f,
-	-0.000010206071983051f,
-	-0.000014172048980291f,
-	-0.000019092331824095f,
-	-0.000025093561850217f,
-	-0.000032309725460887f,
-	-0.000040869410108629f,
-	-0.000050902771287247f,
-	-0.000062527941809152f,
-	-0.000075857080877625f,
-	-0.000090981984892608f,
-	-0.000107979276021387f,
-	-0.000126895337525829f,
-	-0.000147750778600044f,
-	-0.000170524898241214f,
-	-0.000195159646270053f,
-	-0.000221543901544016f,
-	-0.000249517228886741f,
-	-0.000278854334896464f,
-	-0.000309268991706370f,
-	-0.000340399096744052f,
-	-0.000371811190567229f,
-	-0.000402986592324930f,
-	-0.000433326971103446f,
-	-0.000462142048725246f,
-	-0.000488656689255886f,
-	-0.000512000649038707f,
-	-0.000531217622524194f,
-	-0.000545257474301118f,
-	-0.000552987616398289f,
-	-0.000553188077307909f,
-	-0.000544565488882758f,
-	-0.000525751232639430f,
-	-0.000495318184744208f,
-	-0.000451782034515639f,
-	-0.000393620779029084f,
-	-0.000319279140356296f,
-	-0.000227190622760720f,
-	-0.000115784771504684f,
-	 0.000016488581452787f,
-	 0.000171149664304299f,
-	 0.000349662890884785f,
-	 0.000553425442457719f,
-	 0.000783740497411292f,
-	 0.001041804838025221f,
-	 0.001328682064289453f,
-	 0.001645290145967291f,
-	 0.001992375608565783f,
-	 0.002370502036550272f,
-	 0.002780026279675712f,
-	 0.003221088947286086f,
-	 0.003693593686280741f,
-	 0.004197200680900796f,
-	 0.004731309996663634f,
-	 0.005295059011515552f,
-	 0.005887310701543637f,
-	 0.006506655780921748f,
-	 0.007151406625936390f,
-	 0.007819604696828528f,
-	 0.008509020566706571f,
-	 0.009217166946123657f,
-	 0.009941305011649831f,
-	 0.010678463067957514f,
-	 0.011425449071796635f,
-	 0.012178874660574504f,
-	 0.012935173457761552f,
-	 0.013690629889370804f,
-	 0.014441402554104810f,
-	 0.015183556958199267f,
-	 0.015913092956531424f,
-	 0.016625980278750660f,
-	 0.017318188813430120f,
-	 0.017985725593062503f,
-	 0.018624666516886546f,
-	 0.019231193320663705f,
-	 0.019801625228558870f,
-	 0.020332454367773867f,
-	 0.020820375812973399f,
-	 0.021262319920613983f,
-	 0.021655479285054610f,
-	 0.021997336565315176f,
-	 0.022285687008084795f,
-	 0.022518660515178174f,
-	 0.022694738600454345f,
-	 0.022812769691468757f,
-	 0.022871979661449618f,
-	 0.022871979661449618f,
-	 0.022812769691468757f,
-	 0.022694738600454345f,
-	 0.022518660515178174f,
-	 0.022285687008084795f,
-	 0.021997336565315176f,
-	 0.021655479285054610f,
-	 0.021262319920613983f,
-	 0.020820375812973399f,
-	 0.020332454367773867f,
-	 0.019801625228558870f,
-	 0.019231193320663705f,
-	 0.018624666516886546f,
-	 0.017985725593062503f,
-	 0.017318188813430120f,
-	 0.016625980278750660f,
-	 0.015913092956531424f,
-	 0.015183556958199267f,
-	 0.014441402554104810f,
-	 0.013690629889370804f,
-	 0.012935173457761552f,
-	 0.012178874660574504f,
-	 0.011425449071796635f,
-	 0.010678463067957514f,
-	 0.009941305011649831f,
-	 0.009217166946123657f,
-	 0.008509020566706571f,
-	 0.007819604696828528f,
-	 0.007151406625936390f,
-	 0.006506655780921748f,
-	 0.005887310701543637f,
-	 0.005295059011515552f,
-	 0.004731309996663634f,
-	 0.004197200680900796f,
-	 0.003693593686280741f,
-	 0.003221088947286086f,
-	 0.002780026279675712f,
-	 0.002370502036550272f,
-	 0.001992375608565783f,
-	 0.001645290145967291f,
-	 0.001328682064289453f,
-	 0.001041804838025221f,
-	 0.000783740497411292f,
-	 0.000553425442457719f,
-	 0.000349662890884785f,
-	 0.000171149664304299f,
-	 0.000016488581452787f,
-	-0.000115784771504684f,
-	-0.000227190622760720f,
-	-0.000319279140356296f,
-	-0.000393620779029084f,
-	-0.000451782034515639f,
-	-0.000495318184744208f,
-	-0.000525751232639430f,
-	-0.000544565488882758f,
-	-0.000553188077307909f,
-	-0.000552987616398289f,
-	-0.000545257474301118f,
-	-0.000531217622524194f,
-	-0.000512000649038707f,
-	-0.000488656689255886f,
-	-0.000462142048725246f,
-	-0.000433326971103446f,
-	-0.000402986592324930f,
-	-0.000371811190567229f,
-	-0.000340399096744052f,
-	-0.000309268991706370f,
-	-0.000278854334896464f,
-	-0.000249517228886741f,
-	-0.000221543901544016f,
-	-0.000195159646270053f,
-	-0.000170524898241214f,
-	-0.000147750778600044f,
-	-0.000126895337525829f,
-	-0.000107979276021387f,
-	-0.000090981984892608f,
-	-0.000075857080877625f,
-	-0.000062527941809152f,
-	-0.000050902771287247f,
-	-0.000040869410108629f,
-	-0.000032309725460887f,
-	-0.000025093561850217f,
-	-0.000019092331824095f,
-	-0.000014172048980291f,
-	-0.000010206071983051f,
-	-0.000007067232655723f,
-	-0.000007703161797332f
+    -0.000007703161797332f,
+    -0.000007067232655723f,
+    -0.000010206071983051f,
+    -0.000014172048980291f,
+    -0.000019092331824095f,
+    -0.000025093561850217f,
+    -0.000032309725460887f,
+    -0.000040869410108629f,
+    -0.000050902771287247f,
+    -0.000062527941809152f,
+    -0.000075857080877625f,
+    -0.000090981984892608f,
+    -0.000107979276021387f,
+    -0.000126895337525829f,
+    -0.000147750778600044f,
+    -0.000170524898241214f,
+    -0.000195159646270053f,
+    -0.000221543901544016f,
+    -0.000249517228886741f,
+    -0.000278854334896464f,
+    -0.000309268991706370f,
+    -0.000340399096744052f,
+    -0.000371811190567229f,
+    -0.000402986592324930f,
+    -0.000433326971103446f,
+    -0.000462142048725246f,
+    -0.000488656689255886f,
+    -0.000512000649038707f,
+    -0.000531217622524194f,
+    -0.000545257474301118f,
+    -0.000552987616398289f,
+    -0.000553188077307909f,
+    -0.000544565488882758f,
+    -0.000525751232639430f,
+    -0.000495318184744208f,
+    -0.000451782034515639f,
+    -0.000393620779029084f,
+    -0.000319279140356296f,
+    -0.000227190622760720f,
+    -0.000115784771504684f,
+     0.000016488581452787f,
+     0.000171149664304299f,
+     0.000349662890884785f,
+     0.000553425442457719f,
+     0.000783740497411292f,
+     0.001041804838025221f,
+     0.001328682064289453f,
+     0.001645290145967291f,
+     0.001992375608565783f,
+     0.002370502036550272f,
+     0.002780026279675712f,
+     0.003221088947286086f,
+     0.003693593686280741f,
+     0.004197200680900796f,
+     0.004731309996663634f,
+     0.005295059011515552f,
+     0.005887310701543637f,
+     0.006506655780921748f,
+     0.007151406625936390f,
+     0.007819604696828528f,
+     0.008509020566706571f,
+     0.009217166946123657f,
+     0.009941305011649831f,
+     0.010678463067957514f,
+     0.011425449071796635f,
+     0.012178874660574504f,
+     0.012935173457761552f,
+     0.013690629889370804f,
+     0.014441402554104810f,
+     0.015183556958199267f,
+     0.015913092956531424f,
+     0.016625980278750660f,
+     0.017318188813430120f,
+     0.017985725593062503f,
+     0.018624666516886546f,
+     0.019231193320663705f,
+     0.019801625228558870f,
+     0.020332454367773867f,
+     0.020820375812973399f,
+     0.021262319920613983f,
+     0.021655479285054610f,
+     0.021997336565315176f,
+     0.022285687008084795f,
+     0.022518660515178174f,
+     0.022694738600454345f,
+     0.022812769691468757f,
+     0.022871979661449618f,
+     0.022871979661449618f,
+     0.022812769691468757f,
+     0.022694738600454345f,
+     0.022518660515178174f,
+     0.022285687008084795f,
+     0.021997336565315176f,
+     0.021655479285054610f,
+     0.021262319920613983f,
+     0.020820375812973399f,
+     0.020332454367773867f,
+     0.019801625228558870f,
+     0.019231193320663705f,
+     0.018624666516886546f,
+     0.017985725593062503f,
+     0.017318188813430120f,
+     0.016625980278750660f,
+     0.015913092956531424f,
+     0.015183556958199267f,
+     0.014441402554104810f,
+     0.013690629889370804f,
+     0.012935173457761552f,
+     0.012178874660574504f,
+     0.011425449071796635f,
+     0.010678463067957514f,
+     0.009941305011649831f,
+     0.009217166946123657f,
+     0.008509020566706571f,
+     0.007819604696828528f,
+     0.007151406625936390f,
+     0.006506655780921748f,
+     0.005887310701543637f,
+     0.005295059011515552f,
+     0.004731309996663634f,
+     0.004197200680900796f,
+     0.003693593686280741f,
+     0.003221088947286086f,
+     0.002780026279675712f,
+     0.002370502036550272f,
+     0.001992375608565783f,
+     0.001645290145967291f,
+     0.001328682064289453f,
+     0.001041804838025221f,
+     0.000783740497411292f,
+     0.000553425442457719f,
+     0.000349662890884785f,
+     0.000171149664304299f,
+     0.000016488581452787f,
+    -0.000115784771504684f,
+    -0.000227190622760720f,
+    -0.000319279140356296f,
+    -0.000393620779029084f,
+    -0.000451782034515639f,
+    -0.000495318184744208f,
+    -0.000525751232639430f,
+    -0.000544565488882758f,
+    -0.000553188077307909f,
+    -0.000552987616398289f,
+    -0.000545257474301118f,
+    -0.000531217622524194f,
+    -0.000512000649038707f,
+    -0.000488656689255886f,
+    -0.000462142048725246f,
+    -0.000433326971103446f,
+    -0.000402986592324930f,
+    -0.000371811190567229f,
+    -0.000340399096744052f,
+    -0.000309268991706370f,
+    -0.000278854334896464f,
+    -0.000249517228886741f,
+    -0.000221543901544016f,
+    -0.000195159646270053f,
+    -0.000170524898241214f,
+    -0.000147750778600044f,
+    -0.000126895337525829f,
+    -0.000107979276021387f,
+    -0.000090981984892608f,
+    -0.000075857080877625f,
+    -0.000062527941809152f,
+    -0.000050902771287247f,
+    -0.000040869410108629f,
+    -0.000032309725460887f,
+    -0.000025093561850217f,
+    -0.000019092331824095f,
+    -0.000014172048980291f,
+    -0.000010206071983051f,
+    -0.000007067232655723f,
+    -0.000007703161797332f
 };
 
 static const int d_256_r_64_len = 348;
 static const float d_256_r_64_kernel[] =
 {
-	-0.000006032200297229f,
-	-0.000002790586794678f,
-	-0.000003423524464373f,
-	-0.000004141892670381f,
-	-0.000004959329780957f,
-	-0.000005880953015414f,
-	-0.000006916263845337f,
-	-0.000008064028056128f,
-	-0.000009336504822940f,
-	-0.000010742797132820f,
-	-0.000012302324525658f,
-	-0.000014003128525449f,
-	-0.000015868003792231f,
-	-0.000017906061357310f,
-	-0.000020111369902626f,
-	-0.000022508204619172f,
-	-0.000025093613992638f,
-	-0.000027881953296601f,
-	-0.000030875236885189f,
-	-0.000034086060833210f,
-	-0.000037517497377010f,
-	-0.000041176665997414f,
-	-0.000045067469478981f,
-	-0.000049199353227621f,
-	-0.000053568215176887f,
-	-0.000058185242147041f,
-	-0.000063047547807853f,
-	-0.000068158618146586f,
-	-0.000073517650784389f,
-	-0.000079124725926570f,
-	-0.000084976788235246f,
-	-0.000091070103041806f,
-	-0.000097399649098627f,
-	-0.000103959504668590f,
-	-0.000110738977492950f,
-	-0.000117729935644196f,
-	-0.000124919754739577f,
-	-0.000132293212128623f,
-	-0.000139836270835869f,
-	-0.000147529334756596f,
-	-0.000155353239032747f,
-	-0.000163284378055491f,
-	-0.000171298895948762f,
-	-0.000179368841745378f,
-	-0.000187464129074148f,
-	-0.000195552549576070f,
-	-0.000203599379753965f,
-	-0.000211565351775375f,
-	-0.000219411598860001f,
-	-0.000227093646507866f,
-	-0.000234565855614429f,
-	-0.000241779257421431f,
-	-0.000248682177854843f,
-	-0.000255220180724547f,
-	-0.000261335292980978f,
-	-0.000266967862740791f,
-	-0.000272054419087176f,
-	-0.000276528686849870f,
-	-0.000280322370041046f,
-	-0.000283363923695878f,
-	-0.000285578633373008f,
-	-0.000286890694598539f,
-	-0.000287220112764771f,
-	-0.000286486063219693f,
-	-0.000284603980740463f,
-	-0.000281488659987540f,
-	-0.000277051522643753f,
-	-0.000271202733437524f,
-	-0.000263850662609383f,
-	-0.000254902132867105f,
-	-0.000244261829079865f,
-	-0.000231834561467387f,
-	-0.000217522684614226f,
-	-0.000201228717970838f,
-	-0.000182854056621652f,
-	-0.000162300101972573f,
-	-0.000139467943568298f,
-	-0.000114258627064630f,
-	-0.000086574168670878f,
-	-0.000056316612617103f,
-	-0.000023389083735015f,
-	 0.000012303734435184f,
-	 0.000050856088211618f,
-	 0.000092360432854175f,
-	 0.000136906695012963f,
-	 0.000184583050199368f,
-	 0.000235474395169584f,
-	 0.000289663252276950f,
-	 0.000347228091667187f,
-	 0.000408244468331575f,
-	 0.000472783700962668f,
-	 0.000540912739938505f,
-	 0.000612694289527581f,
-	 0.000688186201030564f,
-	 0.000767440808596336f,
-	 0.000850505496981770f,
-	 0.000937421598757782f,
-	 0.001028224584686942f,
-	 0.001122943571650730f,
-	 0.001221601170177604f,
-	 0.001324213422447449f,
-	 0.001430788817328081f,
-	 0.001541329271676986f,
-	 0.001655828820474164f,
-	 0.001774273932442011f,
-	 0.001896643321221287f,
-	 0.002022907760579356f,
-	 0.002153029565104709f,
-	 0.002286963138555204f,
-	 0.002424654105591249f,
-	 0.002566039990527927f,
-	 0.002711049190015392f,
-	 0.002859602052878106f,
-	 0.003011609882021581f,
-	 0.003166975340851216f,
-	 0.003325592606007947f,
-	 0.003487347156138999f,
-	 0.003652115769225347f,
-	 0.003819766988190932f,
-	 0.003990160791661657f,
-	 0.004163149004759460f,
-	 0.004338575232032592f,
-	 0.004516275281704776f,
-	 0.004696077226065694f,
-	 0.004877801369702575f,
-	 0.005061261175365414f,
-	 0.005246262760259225f,
-	 0.005432605634097002f,
-	 0.005620082968897619f,
-	 0.005808481837004595f,
-	 0.005997583515661679f,
-	 0.006187164045980849f,
-	 0.006376994441064236f,
-	 0.006566841257680600f,
-	 0.006756466702660143f,
-	 0.006945629644096785f,
-	 0.007134085474240178f,
-	 0.007321586857189369f,
-	 0.007507884388699728f,
-	 0.007692726710717013f,
-	 0.007875861286146892f,
-	 0.008057034853723447f,
-	 0.008235993962285608f,
-	 0.008412485423992495f,
-	 0.008586256905270668f,
-	 0.008757057550423931f,
-	 0.008924638381879985f,
-	 0.009088752763977616f,
-	 0.009249157391806035f,
-	 0.009405612190690901f,
-	 0.009557881349450560f,
-	 0.009705733651032743f,
-	 0.009848943025250930f,
-	 0.009987289003226731f,
-	 0.010120557317645952f,
-	 0.010248540384643352f,
-	 0.010371037696321509f,
-	 0.010487856281889540f,
-	 0.010598811426250850f,
-	 0.010703726661456589f,
-	 0.010802434494593470f,
-	 0.010894776824678817f,
-	 0.010980605060844476f,
-	 0.011059780725514858f,
-	 0.011132175645830765f,
-	 0.011197672374601442f,
-	 0.011256164283833567f,
-	 0.011307555970121824f,
-	 0.011351763540287503f,
-	 0.011388714558166329f,
-	 0.011418348423280301f,
-	 0.011440616600089638f,
-	 0.011455482402780947f,
-	 0.011462921415360990f,
-	 0.011462921415360990f,
-	 0.011455482402780947f,
-	 0.011440616600089638f,
-	 0.011418348423280301f,
-	 0.011388714558166329f,
-	 0.011351763540287503f,
-	 0.011307555970121824f,
-	 0.011256164283833567f,
-	 0.011197672374601442f,
-	 0.011132175645830765f,
-	 0.011059780725514858f,
-	 0.010980605060844476f,
-	 0.010894776824678817f,
-	 0.010802434494593470f,
-	 0.010703726661456589f,
-	 0.010598811426250850f,
-	 0.010487856281889540f,
-	 0.010371037696321509f,
-	 0.010248540384643352f,
-	 0.010120557317645952f,
-	 0.009987289003226731f,
-	 0.009848943025250930f,
-	 0.009705733651032743f,
-	 0.009557881349450560f,
-	 0.009405612190690901f,
-	 0.009249157391806035f,
-	 0.009088752763977616f,
-	 0.008924638381879985f,
-	 0.008757057550423931f,
-	 0.008586256905270668f,
-	 0.008412485423992495f,
-	 0.008235993962285608f,
-	 0.008057034853723447f,
-	 0.007875861286146892f,
-	 0.007692726710717013f,
-	 0.007507884388699728f,
-	 0.007321586857189369f,
-	 0.007134085474240178f,
-	 0.006945629644096785f,
-	 0.006756466702660143f,
-	 0.006566841257680600f,
-	 0.006376994441064236f,
-	 0.006187164045980849f,
-	 0.005997583515661679f,
-	 0.005808481837004595f,
-	 0.005620082968897619f,
-	 0.005432605634097002f,
-	 0.005246262760259225f,
-	 0.005061261175365414f,
-	 0.004877801369702575f,
-	 0.004696077226065694f,
-	 0.004516275281704776f,
-	 0.004338575232032592f,
-	 0.004163149004759460f,
-	 0.003990160791661657f,
-	 0.003819766988190932f,
-	 0.003652115769225347f,
-	 0.003487347156138999f,
-	 0.003325592606007947f,
-	 0.003166975340851216f,
-	 0.003011609882021581f,
-	 0.002859602052878106f,
-	 0.002711049190015392f,
-	 0.002566039990527927f,
-	 0.002424654105591249f,
-	 0.002286963138555204f,
-	 0.002153029565104709f,
-	 0.002022907760579356f,
-	 0.001896643321221287f,
-	 0.001774273932442011f,
-	 0.001655828820474164f,
-	 0.001541329271676986f,
-	 0.001430788817328081f,
-	 0.001324213422447449f,
-	 0.001221601170177604f,
-	 0.001122943571650730f,
-	 0.001028224584686942f,
-	 0.000937421598757782f,
-	 0.000850505496981770f,
-	 0.000767440808596336f,
-	 0.000688186201030564f,
-	 0.000612694289527581f,
-	 0.000540912739938505f,
-	 0.000472783700962668f,
-	 0.000408244468331575f,
-	 0.000347228091667187f,
-	 0.000289663252276950f,
-	 0.000235474395169584f,
-	 0.000184583050199368f,
-	 0.000136906695012963f,
-	 0.000092360432854175f,
-	 0.000050856088211618f,
-	 0.000012303734435184f,
-	-0.000023389083735015f,
-	-0.000056316612617103f,
-	-0.000086574168670878f,
-	-0.000114258627064630f,
-	-0.000139467943568298f,
-	-0.000162300101972573f,
-	-0.000182854056621652f,
-	-0.000201228717970838f,
-	-0.000217522684614226f,
-	-0.000231834561467387f,
-	-0.000244261829079865f,
-	-0.000254902132867105f,
-	-0.000263850662609383f,
-	-0.000271202733437524f,
-	-0.000277051522643753f,
-	-0.000281488659987540f,
-	-0.000284603980740463f,
-	-0.000286486063219693f,
-	-0.000287220112764771f,
-	-0.000286890694598539f,
-	-0.000285578633373008f,
-	-0.000283363923695878f,
-	-0.000280322370041046f,
-	-0.000276528686849870f,
-	-0.000272054419087176f,
-	-0.000266967862740791f,
-	-0.000261335292980978f,
-	-0.000255220180724547f,
-	-0.000248682177854843f,
-	-0.000241779257421431f,
-	-0.000234565855614429f,
-	-0.000227093646507866f,
-	-0.000219411598860001f,
-	-0.000211565351775375f,
-	-0.000203599379753965f,
-	-0.000195552549576070f,
-	-0.000187464129074148f,
-	-0.000179368841745378f,
-	-0.000171298895948762f,
-	-0.000163284378055491f,
-	-0.000155353239032747f,
-	-0.000147529334756596f,
-	-0.000139836270835869f,
-	-0.000132293212128623f,
-	-0.000124919754739577f,
-	-0.000117729935644196f,
-	-0.000110738977492950f,
-	-0.000103959504668590f,
-	-0.000097399649098627f,
-	-0.000091070103041806f,
-	-0.000084976788235246f,
-	-0.000079124725926570f,
-	-0.000073517650784389f,
-	-0.000068158618146586f,
-	-0.000063047547807853f,
-	-0.000058185242147041f,
-	-0.000053568215176887f,
-	-0.000049199353227621f,
-	-0.000045067469478981f,
-	-0.000041176665997414f,
-	-0.000037517497377010f,
-	-0.000034086060833210f,
-	-0.000030875236885189f,
-	-0.000027881953296601f,
-	-0.000025093613992638f,
-	-0.000022508204619172f,
-	-0.000020111369902626f,
-	-0.000017906061357310f,
-	-0.000015868003792231f,
-	-0.000014003128525449f,
-	-0.000012302324525658f,
-	-0.000010742797132820f,
-	-0.000009336504822940f,
-	-0.000008064028056128f,
-	-0.000006916263845337f,
-	-0.000005880953015414f,
-	-0.000004959329780957f,
-	-0.000004141892670381f,
-	-0.000003423524464373f,
-	-0.000002790586794678f,
-	-0.000006032200297229f
+    -0.000006032200297229f,
+    -0.000002790586794678f,
+    -0.000003423524464373f,
+    -0.000004141892670381f,
+    -0.000004959329780957f,
+    -0.000005880953015414f,
+    -0.000006916263845337f,
+    -0.000008064028056128f,
+    -0.000009336504822940f,
+    -0.000010742797132820f,
+    -0.000012302324525658f,
+    -0.000014003128525449f,
+    -0.000015868003792231f,
+    -0.000017906061357310f,
+    -0.000020111369902626f,
+    -0.000022508204619172f,
+    -0.000025093613992638f,
+    -0.000027881953296601f,
+    -0.000030875236885189f,
+    -0.000034086060833210f,
+    -0.000037517497377010f,
+    -0.000041176665997414f,
+    -0.000045067469478981f,
+    -0.000049199353227621f,
+    -0.000053568215176887f,
+    -0.000058185242147041f,
+    -0.000063047547807853f,
+    -0.000068158618146586f,
+    -0.000073517650784389f,
+    -0.000079124725926570f,
+    -0.000084976788235246f,
+    -0.000091070103041806f,
+    -0.000097399649098627f,
+    -0.000103959504668590f,
+    -0.000110738977492950f,
+    -0.000117729935644196f,
+    -0.000124919754739577f,
+    -0.000132293212128623f,
+    -0.000139836270835869f,
+    -0.000147529334756596f,
+    -0.000155353239032747f,
+    -0.000163284378055491f,
+    -0.000171298895948762f,
+    -0.000179368841745378f,
+    -0.000187464129074148f,
+    -0.000195552549576070f,
+    -0.000203599379753965f,
+    -0.000211565351775375f,
+    -0.000219411598860001f,
+    -0.000227093646507866f,
+    -0.000234565855614429f,
+    -0.000241779257421431f,
+    -0.000248682177854843f,
+    -0.000255220180724547f,
+    -0.000261335292980978f,
+    -0.000266967862740791f,
+    -0.000272054419087176f,
+    -0.000276528686849870f,
+    -0.000280322370041046f,
+    -0.000283363923695878f,
+    -0.000285578633373008f,
+    -0.000286890694598539f,
+    -0.000287220112764771f,
+    -0.000286486063219693f,
+    -0.000284603980740463f,
+    -0.000281488659987540f,
+    -0.000277051522643753f,
+    -0.000271202733437524f,
+    -0.000263850662609383f,
+    -0.000254902132867105f,
+    -0.000244261829079865f,
+    -0.000231834561467387f,
+    -0.000217522684614226f,
+    -0.000201228717970838f,
+    -0.000182854056621652f,
+    -0.000162300101972573f,
+    -0.000139467943568298f,
+    -0.000114258627064630f,
+    -0.000086574168670878f,
+    -0.000056316612617103f,
+    -0.000023389083735015f,
+     0.000012303734435184f,
+     0.000050856088211618f,
+     0.000092360432854175f,
+     0.000136906695012963f,
+     0.000184583050199368f,
+     0.000235474395169584f,
+     0.000289663252276950f,
+     0.000347228091667187f,
+     0.000408244468331575f,
+     0.000472783700962668f,
+     0.000540912739938505f,
+     0.000612694289527581f,
+     0.000688186201030564f,
+     0.000767440808596336f,
+     0.000850505496981770f,
+     0.000937421598757782f,
+     0.001028224584686942f,
+     0.001122943571650730f,
+     0.001221601170177604f,
+     0.001324213422447449f,
+     0.001430788817328081f,
+     0.001541329271676986f,
+     0.001655828820474164f,
+     0.001774273932442011f,
+     0.001896643321221287f,
+     0.002022907760579356f,
+     0.002153029565104709f,
+     0.002286963138555204f,
+     0.002424654105591249f,
+     0.002566039990527927f,
+     0.002711049190015392f,
+     0.002859602052878106f,
+     0.003011609882021581f,
+     0.003166975340851216f,
+     0.003325592606007947f,
+     0.003487347156138999f,
+     0.003652115769225347f,
+     0.003819766988190932f,
+     0.003990160791661657f,
+     0.004163149004759460f,
+     0.004338575232032592f,
+     0.004516275281704776f,
+     0.004696077226065694f,
+     0.004877801369702575f,
+     0.005061261175365414f,
+     0.005246262760259225f,
+     0.005432605634097002f,
+     0.005620082968897619f,
+     0.005808481837004595f,
+     0.005997583515661679f,
+     0.006187164045980849f,
+     0.006376994441064236f,
+     0.006566841257680600f,
+     0.006756466702660143f,
+     0.006945629644096785f,
+     0.007134085474240178f,
+     0.007321586857189369f,
+     0.007507884388699728f,
+     0.007692726710717013f,
+     0.007875861286146892f,
+     0.008057034853723447f,
+     0.008235993962285608f,
+     0.008412485423992495f,
+     0.008586256905270668f,
+     0.008757057550423931f,
+     0.008924638381879985f,
+     0.009088752763977616f,
+     0.009249157391806035f,
+     0.009405612190690901f,
+     0.009557881349450560f,
+     0.009705733651032743f,
+     0.009848943025250930f,
+     0.009987289003226731f,
+     0.010120557317645952f,
+     0.010248540384643352f,
+     0.010371037696321509f,
+     0.010487856281889540f,
+     0.010598811426250850f,
+     0.010703726661456589f,
+     0.010802434494593470f,
+     0.010894776824678817f,
+     0.010980605060844476f,
+     0.011059780725514858f,
+     0.011132175645830765f,
+     0.011197672374601442f,
+     0.011256164283833567f,
+     0.011307555970121824f,
+     0.011351763540287503f,
+     0.011388714558166329f,
+     0.011418348423280301f,
+     0.011440616600089638f,
+     0.011455482402780947f,
+     0.011462921415360990f,
+     0.011462921415360990f,
+     0.011455482402780947f,
+     0.011440616600089638f,
+     0.011418348423280301f,
+     0.011388714558166329f,
+     0.011351763540287503f,
+     0.011307555970121824f,
+     0.011256164283833567f,
+     0.011197672374601442f,
+     0.011132175645830765f,
+     0.011059780725514858f,
+     0.010980605060844476f,
+     0.010894776824678817f,
+     0.010802434494593470f,
+     0.010703726661456589f,
+     0.010598811426250850f,
+     0.010487856281889540f,
+     0.010371037696321509f,
+     0.010248540384643352f,
+     0.010120557317645952f,
+     0.009987289003226731f,
+     0.009848943025250930f,
+     0.009705733651032743f,
+     0.009557881349450560f,
+     0.009405612190690901f,
+     0.009249157391806035f,
+     0.009088752763977616f,
+     0.008924638381879985f,
+     0.008757057550423931f,
+     0.008586256905270668f,
+     0.008412485423992495f,
+     0.008235993962285608f,
+     0.008057034853723447f,
+     0.007875861286146892f,
+     0.007692726710717013f,
+     0.007507884388699728f,
+     0.007321586857189369f,
+     0.007134085474240178f,
+     0.006945629644096785f,
+     0.006756466702660143f,
+     0.006566841257680600f,
+     0.006376994441064236f,
+     0.006187164045980849f,
+     0.005997583515661679f,
+     0.005808481837004595f,
+     0.005620082968897619f,
+     0.005432605634097002f,
+     0.005246262760259225f,
+     0.005061261175365414f,
+     0.004877801369702575f,
+     0.004696077226065694f,
+     0.004516275281704776f,
+     0.004338575232032592f,
+     0.004163149004759460f,
+     0.003990160791661657f,
+     0.003819766988190932f,
+     0.003652115769225347f,
+     0.003487347156138999f,
+     0.003325592606007947f,
+     0.003166975340851216f,
+     0.003011609882021581f,
+     0.002859602052878106f,
+     0.002711049190015392f,
+     0.002566039990527927f,
+     0.002424654105591249f,
+     0.002286963138555204f,
+     0.002153029565104709f,
+     0.002022907760579356f,
+     0.001896643321221287f,
+     0.001774273932442011f,
+     0.001655828820474164f,
+     0.001541329271676986f,
+     0.001430788817328081f,
+     0.001324213422447449f,
+     0.001221601170177604f,
+     0.001122943571650730f,
+     0.001028224584686942f,
+     0.000937421598757782f,
+     0.000850505496981770f,
+     0.000767440808596336f,
+     0.000688186201030564f,
+     0.000612694289527581f,
+     0.000540912739938505f,
+     0.000472783700962668f,
+     0.000408244468331575f,
+     0.000347228091667187f,
+     0.000289663252276950f,
+     0.000235474395169584f,
+     0.000184583050199368f,
+     0.000136906695012963f,
+     0.000092360432854175f,
+     0.000050856088211618f,
+     0.000012303734435184f,
+    -0.000023389083735015f,
+    -0.000056316612617103f,
+    -0.000086574168670878f,
+    -0.000114258627064630f,
+    -0.000139467943568298f,
+    -0.000162300101972573f,
+    -0.000182854056621652f,
+    -0.000201228717970838f,
+    -0.000217522684614226f,
+    -0.000231834561467387f,
+    -0.000244261829079865f,
+    -0.000254902132867105f,
+    -0.000263850662609383f,
+    -0.000271202733437524f,
+    -0.000277051522643753f,
+    -0.000281488659987540f,
+    -0.000284603980740463f,
+    -0.000286486063219693f,
+    -0.000287220112764771f,
+    -0.000286890694598539f,
+    -0.000285578633373008f,
+    -0.000283363923695878f,
+    -0.000280322370041046f,
+    -0.000276528686849870f,
+    -0.000272054419087176f,
+    -0.000266967862740791f,
+    -0.000261335292980978f,
+    -0.000255220180724547f,
+    -0.000248682177854843f,
+    -0.000241779257421431f,
+    -0.000234565855614429f,
+    -0.000227093646507866f,
+    -0.000219411598860001f,
+    -0.000211565351775375f,
+    -0.000203599379753965f,
+    -0.000195552549576070f,
+    -0.000187464129074148f,
+    -0.000179368841745378f,
+    -0.000171298895948762f,
+    -0.000163284378055491f,
+    -0.000155353239032747f,
+    -0.000147529334756596f,
+    -0.000139836270835869f,
+    -0.000132293212128623f,
+    -0.000124919754739577f,
+    -0.000117729935644196f,
+    -0.000110738977492950f,
+    -0.000103959504668590f,
+    -0.000097399649098627f,
+    -0.000091070103041806f,
+    -0.000084976788235246f,
+    -0.000079124725926570f,
+    -0.000073517650784389f,
+    -0.000068158618146586f,
+    -0.000063047547807853f,
+    -0.000058185242147041f,
+    -0.000053568215176887f,
+    -0.000049199353227621f,
+    -0.000045067469478981f,
+    -0.000041176665997414f,
+    -0.000037517497377010f,
+    -0.000034086060833210f,
+    -0.000030875236885189f,
+    -0.000027881953296601f,
+    -0.000025093613992638f,
+    -0.000022508204619172f,
+    -0.000020111369902626f,
+    -0.000017906061357310f,
+    -0.000015868003792231f,
+    -0.000014003128525449f,
+    -0.000012302324525658f,
+    -0.000010742797132820f,
+    -0.000009336504822940f,
+    -0.000008064028056128f,
+    -0.000006916263845337f,
+    -0.000005880953015414f,
+    -0.000004959329780957f,
+    -0.000004141892670381f,
+    -0.000003423524464373f,
+    -0.000002790586794678f,
+    -0.000006032200297229f
 };
 
-
 #else
 // Previous FIR decimator
 
-
 /* Filter taps generated by matlab.
  * All filters are designed for 0.5 dB passband ripple and 90-100 dB stop-band
  * attenuation.

From d85fafa903f970bd6157b517c2ac80a313525488 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Wed, 5 Apr 2017 23:23:06 +0200
Subject: [PATCH 212/334] Update readme

---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 48b3003..5ed20ff 100644
--- a/README.md
+++ b/README.md
@@ -277,7 +277,8 @@ Wolfgang Fritz DK7OB
 - Various UI improvements.
 
 Youssef Touil
-- FIRCalc design tool for optimizing input decimator.
+- Two-stage FIR decimator design.
+- FIRCalc design tool for optimizing previous input decimator.
 
 Some of the icons are from:
 - The GNOME icon theme CC-SA 3.0 by GNOME icon artists 

From 1b83c02c601fb35f0761a7674bdd0d90db8f039e Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Thu, 6 Apr 2017 21:09:18 +0200
Subject: [PATCH 213/334] Update news.txt

---
 resources/news.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/news.txt b/resources/news.txt
index 77f6ac3..782c32f 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -13,6 +13,7 @@
   IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT).
   IMPROVED: LimeSDR integration.
   IMPROVED: Voiceover interface.
+  IMPROVED: Input decimator performance.
 
 
      2.6.1: Released February 16, 2017

From 5bcb07b20ffa734eaf0fcb3642164a16acf23821 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Fri, 7 Apr 2017 21:01:26 +0200
Subject: [PATCH 214/334] Don't use auto type for variables

Fixes issue #508.
---
 src/dsp/filter/fir_decim.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/dsp/filter/fir_decim.cpp b/src/dsp/filter/fir_decim.cpp
index d7fdf64..af2ebda 100644
--- a/src/dsp/filter/fir_decim.cpp
+++ b/src/dsp/filter/fir_decim.cpp
@@ -113,7 +113,7 @@ fir_decim_cc::fir_decim_cc(unsigned int decim)
     std::cout << "Decimation: " << decim << std::endl;
     while (decim > 1 && index >= 0)
     {
-        auto stage = &decimation_stages[index];
+        const decimation_stage  *stage = &decimation_stages[index];
 
         if (decim % stage->decimation == 0)
         {

From a2965f0805bfff024f61fd4de363eb724a05ce18 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 00:35:14 +0200
Subject: [PATCH 215/334] Allow frequency controller to have up to max digits

---
 src/applications/gqrx/mainwindow.cpp |  4 ++--
 src/qtgui/freqctrl.cpp               | 17 +++++++++++++++--
 src/qtgui/freqctrl.h                 |  2 +-
 3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 72725cc..9b08e7d 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -83,7 +83,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
     setWindowTitle(QString("Gqrx %1").arg(VERSION));
 
     /* frequency control widget */
-    ui->freqCtrl->setup(10, (quint64) 0, (quint64) 9999e6, 1, UNITS_MHZ);
+    ui->freqCtrl->setup(0, (quint64) 0, (quint64) 9999e6, 1, UNITS_MHZ);
     ui->freqCtrl->setFrequency(144500000);
 
     d_filter_shape = receiver::FILTER_SHAPE_NORMAL;
@@ -745,7 +745,7 @@ void MainWindow::updateFrequencyRange()
     qint64 start = (qint64)(rx->get_filter_offset()) + d_hw_freq_start + d_lnb_lo;
     qint64 stop  = (qint64)(rx->get_filter_offset()) + d_hw_freq_stop  + d_lnb_lo;
 
-    ui->freqCtrl->setup(10, start, stop, 1, UNITS_MHZ);
+    ui->freqCtrl->setup(0, start, stop, 1, UNITS_MHZ);
     uiDockRxOpt->setRxFreqRange(start, stop);
 }
 
diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp
index 980f2d1..47d231e 100644
--- a/src/qtgui/freqctrl.cpp
+++ b/src/qtgui/freqctrl.cpp
@@ -72,7 +72,7 @@ CFreqCtrl::CFreqCtrl(QWidget *parent) :
     m_HighlightColor = QColor(0x5A, 0x5A, 0x5A, 0xFF);
     m_UnitsColor = Qt::gray;
     m_freq = 146123456;
-    setup(10, 1, 4000000000U, 1, UNITS_MHZ);
+    setup(0, 1, 4000000000U, 1, UNITS_MHZ);
     m_Oldfreq = 0;
     m_LastLeadZeroPos = 0;
     m_LRMouseFreqSel = false;
@@ -113,6 +113,18 @@ bool CFreqCtrl::inRect(QRect &rect, QPoint &point)
         return false;
 }
 
+static int fmax_to_numdigits(qint64 fmax)
+{
+    if (fmax < 1e9)
+        return 9;
+    else if (fmax < 10e9)
+        return 10;
+    else if (fmax < 100e9)
+        return 11;
+
+    return 12;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 //  Setup various parameters for the control
 //////////////////////////////////////////////////////////////////////////////
@@ -122,7 +134,8 @@ void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNIT
     qint64 pwr = 1;
     m_LastEditDigit = 0;
     m_Oldfreq = -1;
-    m_NumDigits = NumDigits;
+
+    m_NumDigits = NumDigits ? NumDigits : fmax_to_numdigits(Maxf);
 
     if (m_NumDigits > MAX_DIGITS)
         m_NumDigits = MAX_DIGITS;
diff --git a/src/qtgui/freqctrl.h b/src/qtgui/freqctrl.h
index cafcd3c..9828318 100644
--- a/src/qtgui/freqctrl.h
+++ b/src/qtgui/freqctrl.h
@@ -50,7 +50,7 @@ class CFreqCtrl : public QFrame
     QSize minimumSizeHint() const;
     QSize sizeHint() const;
 
-    //primary access routines
+    // Use NumDigits=0 for auto
     void setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNITS UnitsType);
     void setUnits(FUNITS units);
     void setDigitColor(QColor cr);

From 4d061234078c4de578cfdde0465b30bfb55c83e1 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 00:44:00 +0200
Subject: [PATCH 216/334] Increase LNB LO range to +/- 500 GHz

Fixes #343.
---
 src/qtgui/dockinputctl.ui | 4 ++--
 src/qtgui/ioconfig.ui     | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/qtgui/dockinputctl.ui b/src/qtgui/dockinputctl.ui
index 6c08f55..b4e8ead 100644
--- a/src/qtgui/dockinputctl.ui
+++ b/src/qtgui/dockinputctl.ui
@@ -82,10 +82,10 @@
          6
         
         
-         -2000.000000000000000
+         -500000.000000000000000
         
         
-         7900.000000000000000
+         500000.000000000000000
         
        
       
diff --git a/src/qtgui/ioconfig.ui b/src/qtgui/ioconfig.ui
index c95c5d8..bd961eb 100644
--- a/src/qtgui/ioconfig.ui
+++ b/src/qtgui/ioconfig.ui
@@ -126,10 +126,10 @@
          6
         
         
-         -15000.000000000000000
+         -500000.000000000000000
         
         
-         15000.000000000000000
+         500000.000000000000000
         
        
       

From 3b253e093582014b55df444321761d7570446b14 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 01:13:49 +0200
Subject: [PATCH 217/334] Remove incorrect type cast

---
 src/applications/gqrx/mainwindow.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp
index 9b08e7d..f646a0e 100644
--- a/src/applications/gqrx/mainwindow.cpp
+++ b/src/applications/gqrx/mainwindow.cpp
@@ -83,7 +83,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) :
     setWindowTitle(QString("Gqrx %1").arg(VERSION));
 
     /* frequency control widget */
-    ui->freqCtrl->setup(0, (quint64) 0, (quint64) 9999e6, 1, UNITS_MHZ);
+    ui->freqCtrl->setup(0, 0, 9999e6, 1, UNITS_MHZ);
     ui->freqCtrl->setFrequency(144500000);
 
     d_filter_shape = receiver::FILTER_SHAPE_NORMAL;

From e7a9d6c54f0d8a3ad846685f595f0264d1a7957d Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 01:32:21 +0200
Subject: [PATCH 218/334] Update news.txt

---
 resources/news.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/resources/news.txt b/resources/news.txt
index 782c32f..a401e4d 100644
--- a/resources/news.txt
+++ b/resources/news.txt
@@ -14,6 +14,7 @@
   IMPROVED: LimeSDR integration.
   IMPROVED: Voiceover interface.
   IMPROVED: Input decimator performance.
+  IMPROVED: Increased frequency limit to 999 GHz (500 GHz LO).
 
 
      2.6.1: Released February 16, 2017

From ca4010d37ccfa2655c436721016926cd84958cc5 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 22:14:33 +0200
Subject: [PATCH 219/334] Reduce the number of active digits for HF radios

---
 src/qtgui/freqctrl.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp
index 47d231e..72fdd7e 100644
--- a/src/qtgui/freqctrl.cpp
+++ b/src/qtgui/freqctrl.cpp
@@ -115,7 +115,11 @@ bool CFreqCtrl::inRect(QRect &rect, QPoint &point)
 
 static int fmax_to_numdigits(qint64 fmax)
 {
-    if (fmax < 1e9)
+    if (fmax < 10e6)
+        return 7;
+    else if (fmax < 100e6)
+        return 8;
+    else if (fmax < 1e9)
         return 9;
     else if (fmax < 10e9)
         return 10;

From a400ad490a8f6e42fd15b10b1002876fd485e159 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 22:56:59 +0200
Subject: [PATCH 220/334] Disable digit group separators

---
 src/qtgui/freqctrl.cpp | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp
index 72fdd7e..9bb359e 100644
--- a/src/qtgui/freqctrl.cpp
+++ b/src/qtgui/freqctrl.cpp
@@ -684,14 +684,13 @@ void CFreqCtrl::drawBkGround(QPainter &Painter)
                                    rect.bottom());
             Painter.fillRect(m_SepRect[i], m_BkColor);
             digpos -= sepwidth;
-            if (i==m_DecPos)
+            if (i == m_DecPos)
                 Painter.drawText(m_SepRect[i], Qt::AlignHCenter|Qt::AlignVCenter, ".");
-            else
-                if (i>m_DecPos && i m_DecPos && i < m_LeadZeroPos)
+//                Painter.drawText(m_SepRect[i], Qt::AlignHCenter|Qt::AlignVCenter, ",");
+            else if (i < m_LeadZeroPos)
+                Painter.drawText(m_SepRect[i], Qt::AlignHCenter|Qt::AlignVCenter, " ");
         }
         else
         {

From ff597b93d6b4065072c79c6c8911f5ce9f0b1995 Mon Sep 17 00:00:00 2001
From: Alexandru Csete 
Date: Sun, 23 Apr 2017 23:30:26 +0200
Subject: [PATCH 221/334] Adjust SSB filter presets

---
 src/qtgui/dockrxopt.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp
index ede6b1e..217e0d6 100644
--- a/src/qtgui/dockrxopt.cpp
+++ b/src/qtgui/dockrxopt.cpp
@@ -37,8 +37,8 @@ static const int filter_preset_table[DockRxOpt::MODE_LAST][3][2] =
     {{ -10000,  10000}, { -5000,  5000}, { -2500,  2500}},  // MODE_NFM
     {{-100000, 100000}, {-80000, 80000}, {-60000, 60000}},  // MODE_WFM_MONO
     {{-100000, 100000}, {-80000, 80000}, {-60000, 60000}},  // MODE_WFM_STEREO
-    {{  -4000,   -100}, { -2800,  -100}, { -1600,  -200}},  // MODE_LSB
-    {{    100,   4000}, {   100,  2800}, {   200,  1600}},  // MODE_USB
+    {{  -4000,   -100}, { -2800,  -100}, { -2400,  -300}},  // MODE_LSB
+    {{    100,   4000}, {   100,  2800}, {   300,  2400}},  // MODE_USB
     {{  -1000,   1000}, {  -250,   250}, {  -100,   100}},  // MODE_CWL
     {{  -1000,   1000}, {  -250,   250}, {  -100,   100}},  // MODE_CWU
     {{-100000, 100000}, {-80000, 80000}, {-60000, 60000}}   // MODE_WFM_STEREO_OIRT

From fdc8f6ba80347e1a646f7ba808737a756225cebd Mon Sep 17 00:00:00 2001
From: AsciiWolf 
Date: Wed, 26 Apr 2017 20:25:47 +0200
Subject: [PATCH 222/334] Add description to the AppData file

Based on description from the Gqrx website
---
 gqrx.appdata.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gqrx.appdata.xml b/gqrx.appdata.xml
index 4b4bc7d..ccc04b7 100644
--- a/gqrx.appdata.xml
+++ b/gqrx.appdata.xml
@@ -8,10 +8,10 @@
   Alexandru Csete
   
    

- + Gqrx is an open source software defined radio receiver (SDR) powered by the GNU Radio and the Qt graphical toolkit.

- + Gqrx supports many of the SDR hardware available, including Airspy, Funcube Dongles, rtl-sdr, HackRF and USRP devices.

CC-BY-3.0 From 0fc320b3704a69ca92fadfced3d9f00dfd88423d Mon Sep 17 00:00:00 2001 From: Matt Hostetter Date: Thu, 27 Apr 2017 17:15:50 -0400 Subject: [PATCH 223/334] Add additional waterfall time spans --- src/qtgui/dockfft.cpp | 4 +++- src/qtgui/dockfft.ui | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index 5056eca..a26acb3 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -364,6 +364,8 @@ void DockFft::on_fftRateComboBox_currentIndexChanged(const QString & text) static const quint64 wf_span_table[] = { 0, // Auto + 1*60*1000, // 1 minute + 2*60*1000, // 2 minutes 5*60*1000, // 5 minutes 10*60*1000, // 10 minutes 15*60*1000, // 15 minutes @@ -381,7 +383,7 @@ static const quint64 wf_span_table[] = /** Waterfall time span changed. */ void DockFft::on_wfSpanComboBox_currentIndexChanged(int index) { - if (index < 0 || index > 12) + if (index < 0 || index > 14) return; emit wfSpanChanged(wf_span_table[index]); diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index 6742884..e47fd6f 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -628,6 +628,16 @@ Auto + + + 1 min + + + + + 2 min + + 5 min From e62104bdaf0c210ca2fab3df96e4202987fe7192 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 29 Apr 2017 11:27:22 +0200 Subject: [PATCH 224/334] Update news.txt --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index a401e4d..24a95d6 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -15,6 +15,7 @@ IMPROVED: Voiceover interface. IMPROVED: Input decimator performance. IMPROVED: Increased frequency limit to 999 GHz (500 GHz LO). + IMPROVED: More short waterfall time spans. 2.6.1: Released February 16, 2017 From e6612afff02100b16d2f398aeae41d1dd34400d8 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 3 May 2017 22:53:40 +0200 Subject: [PATCH 225/334] Change squelch units to dB to free up some layout space --- src/qtgui/dockrxopt.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index 89e47a7..a3c820d 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -352,7 +352,7 @@ This is an offset from the hardware RF frequency.</p></body></htm true - dBFS + dB 1 From d47fd73e758ce42fc97a339b6cb5511b8139e580 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 3 May 2017 23:01:58 +0200 Subject: [PATCH 226/334] Add squelch reset button Fixes #516. --- resources/news.txt | 1 + src/qtgui/dockrxopt.cpp | 7 ++ src/qtgui/dockrxopt.h | 1 + src/qtgui/dockrxopt.ui | 220 ++++++++++++++++++++++------------------ 4 files changed, 131 insertions(+), 98 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index 24a95d6..3a12f81 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -5,6 +5,7 @@ NEW: Restore remote control state between sessions. NEW: Support for passband when setting mode through remote. NEW: Widget to enter receiver frequency. + NEW: Button to reset squelch to its default (-150 dB) value. FIXED: Keep waterfall zoom level and zoom slider synchronised. FIXED: RDS status is not kept while jumping through bookmark. FIXED: .conf files are deleted when changes are saved. diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 217e0d6..412feae 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -75,12 +75,14 @@ DockRxOpt::DockRxOpt(qint64 filterOffsetRange, QWidget *parent) : ui->modeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); ui->agcButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); ui->autoSquelchButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); + ui->resetSquelchButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); #endif #ifdef Q_OS_LINUX ui->modeButton->setMinimumSize(32, 24); ui->agcButton->setMinimumSize(32, 24); ui->autoSquelchButton->setMinimumSize(32, 24); + ui->resetSquelchButton->setMinimumSize(32, 24); ui->nbOptButton->setMinimumSize(32, 24); ui->nb2Button->setMinimumSize(32, 24); ui->nb1Button->setMinimumSize(32, 24); @@ -567,6 +569,11 @@ void DockRxOpt::on_autoSquelchButton_clicked() ui->sqlSpinBox->setValue(newval); } +void DockRxOpt::on_resetSquelchButton_clicked() +{ + ui->sqlSpinBox->setValue(-150.0); +} + /** AGC preset has changed. */ void DockRxOpt::on_agcPresetCombo_currentIndexChanged(int index) { diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h index 1bb47ed..4255365 100644 --- a/src/qtgui/dockrxopt.h +++ b/src/qtgui/dockrxopt.h @@ -185,6 +185,7 @@ private slots: void on_modeButton_clicked(); void on_agcButton_clicked(); void on_autoSquelchButton_clicked(); + void on_resetSquelchButton_clicked(); //void on_agcPresetCombo_activated(int index); void on_agcPresetCombo_currentIndexChanged(int index); void on_sqlSpinBox_valueChanged(double value); diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index a3c820d..5b83284 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -6,8 +6,8 @@ 0 0 - 266 - 313 + 305 + 335 @@ -18,8 +18,8 @@ - 266 - 313 + 305 + 335 @@ -40,21 +40,6 @@ - - 4 - - - 4 - - - 2 - - - 4 - - - 2 - @@ -134,43 +119,6 @@ This is an offset from the hardware RF frequency.</p></body></htm 5 - - - - - 0 - 0 - - - - - 50 - 30 - - - - - 16777215 - 16777215 - - - - Set squelch to the current signal or noise level - - - Auto squelch - - - A - - - - 16 - 16 - - - - @@ -331,46 +279,6 @@ This is an offset from the hardware RF frequency.</p></body></htm - - - - - 0 - 0 - - - - Squelch level in dB below full scale - - - Squelch - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - dB - - - 1 - - - -150.000000000000000 - - - 0.000000000000000 - - - 1.000000000000000 - - - -150.000000000000000 - - - @@ -710,6 +618,124 @@ This is an offset from the hardware RF frequency.</p></body></htm + + + + + 0 + 0 + + + + + 50 + 30 + + + + + 16777215 + 16777215 + + + + Reset squelch to its default value + + + Auto squelch + + + R + + + + 16 + 16 + + + + + + + + + + + 0 + 0 + + + + Squelch level in dB below full scale + + + Squelch + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + dB + + + 1 + + + -150.000000000000000 + + + 0.000000000000000 + + + 1.000000000000000 + + + -150.000000000000000 + + + + + + + + 0 + 0 + + + + + 50 + 30 + + + + + 16777215 + 16777215 + + + + Set squelch to the current signal or noise level + + + Auto squelch + + + A + + + + 16 + 16 + + + + + + @@ -744,8 +770,6 @@ This is an offset from the hardware RF frequency.</p></body></htm modeButton agcPresetCombo agcButton - sqlSpinBox - autoSquelchButton nb1Button nb2Button nbOptButton From a815c3880fd5c17d38f0cecacaef30bdefb8d595 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 3 May 2017 23:09:03 +0200 Subject: [PATCH 227/334] Update tab order in DockRxOpt --- src/qtgui/dockrxopt.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index 5b83284..877ebfd 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -770,6 +770,9 @@ This is an offset from the hardware RF frequency.</p></body></htm modeButton agcPresetCombo agcButton + sqlSpinBox + autoSquelchButton + resetSquelchButton nb1Button nb2Button nbOptButton From 5baeb40b7ff4385db62eecf891bb4e9becc069ab Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 3 May 2017 23:10:19 +0200 Subject: [PATCH 228/334] Update tab order in I/O config --- src/qtgui/ioconfig.ui | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qtgui/ioconfig.ui b/src/qtgui/ioconfig.ui index bd961eb..4c82e66 100644 --- a/src/qtgui/ioconfig.ui +++ b/src/qtgui/ioconfig.ui @@ -349,6 +349,16 @@ Leave it at default unless you know what you are doing. + + inDevCombo + inDevEdit + inSrCombo + decimCombo + bwSpinBox + loSpinBox + outDevCombo + outSrCombo + From b860cc80d6a8eb10b61f5f737925c3ab05f0e97d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 4 May 2017 00:00:44 +0200 Subject: [PATCH 229/334] Update CFreqCtl to support unitless display Syncing from softrig so it also includes various formatting changes. --- src/applications/gqrx/mainwindow.cpp | 4 +- src/qtgui/dockrxopt.cpp | 5 +- src/qtgui/freqctrl.cpp | 683 ++++++++++++--------------- src/qtgui/freqctrl.h | 231 +++++---- 4 files changed, 418 insertions(+), 505 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index f646a0e..b095dd2 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -83,7 +83,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : setWindowTitle(QString("Gqrx %1").arg(VERSION)); /* frequency control widget */ - ui->freqCtrl->setup(0, 0, 9999e6, 1, UNITS_MHZ); + ui->freqCtrl->setup(0, 0, 9999e6, 1, FCTL_UNIT_MHZ); ui->freqCtrl->setFrequency(144500000); d_filter_shape = receiver::FILTER_SHAPE_NORMAL; @@ -745,7 +745,7 @@ void MainWindow::updateFrequencyRange() qint64 start = (qint64)(rx->get_filter_offset()) + d_hw_freq_start + d_lnb_lo; qint64 stop = (qint64)(rx->get_filter_offset()) + d_hw_freq_stop + d_lnb_lo; - ui->freqCtrl->setup(0, start, stop, 1, UNITS_MHZ); + ui->freqCtrl->setup(0, start, stop, 1, FCTL_UNIT_MHZ); uiDockRxOpt->setRxFreqRange(start, stop); } diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 412feae..1a178a5 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -88,7 +88,8 @@ DockRxOpt::DockRxOpt(qint64 filterOffsetRange, QWidget *parent) : ui->nb1Button->setMinimumSize(32, 24); #endif - ui->filterFreq->setup(7, -filterOffsetRange/2, filterOffsetRange/2, 1, UNITS_KHZ); + ui->filterFreq->setup(7, -filterOffsetRange/2, filterOffsetRange/2, 1, + FCTL_UNIT_KHZ); ui->filterFreq->setFrequency(0); // use same slot for filteCombo and filterShapeCombo @@ -139,7 +140,7 @@ void DockRxOpt::setFilterOffset(qint64 freq_hz) void DockRxOpt::setFilterOffsetRange(qint64 range_hz) { if (range_hz > 0) - ui->filterFreq->setup(7, -range_hz/2, range_hz/2, 1, UNITS_KHZ); + ui->filterFreq->setup(7, -range_hz/2, range_hz/2, 1, FCTL_UNIT_KHZ); } /** diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index 9bb359e..7e36d39 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -1,65 +1,51 @@ -///////////////////////////////////////////////////////////////////// -// freqctrl.cpp: implementation of the CFreqCtrl class. -// -// This class implements a frequency control widget to set/change -//frequency data. -// -// History: -// 2010-09-15 Initial creation MSW -// 2011-03-27 Initial release -// 2011-04-17 Fixed bug with m_Oldfreq being set after emit instead of before -///////////////////////////////////////////////////////////////////// - -//========================================================================================== -// + + + This Software is released under the "Simplified BSD License" + + + -// Copyright 2010 Moe Wheatley. -// Copyright 2012 Alexandru Csete -// All rights reserved. -// -//Redistribution and use in source and binary forms, with or without modification, are -//permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -//THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED -//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR -//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//The views and conclusions contained in the software and documentation are those of the -//authors and should not be interpreted as representing official policies, either expressed -//or implied, of Moe Wheatley. -//========================================================================================== - +/* + * Frequency controller widget (originally from CuteSDR) + * + * This file is part of gqrx sdr. + * + * Copyright 2010 Moe Wheatley AE4JY + * Copyright 2012-2017 Alexandru Csete OZ9AEC + * All rights reserved. + * + * This software is released under the "Simplified BSD License". + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ #include #include "freqctrl.h" - -//Manual adjustment of Font size as percent of control height +// Manual adjustment of Font size as percent of control height #define DIGIT_SIZE_PERCENT 90 #define UNITS_SIZE_PERCENT 60 -//adjustment for separation between digits -#define SEPRATIO_N 100 //separation rectangle size ratio numerator times 100 -#define SEPRATIO_D 3 //separation rectangle size ratio denominator +// adjustment for separation between digits +#define SEPRATIO_N 100 // separation rectangle size ratio numerator times 100 +#define SEPRATIO_D 3 // separation rectangle size ratio denominator #define STATUS_TIP \ "Scroll or left-click to increase/decrease digit. " \ "Right-click to clear digits." -///////////////////////////////////////////////////////////////////// -// Constructor/Destructor -///////////////////////////////////////////////////////////////////// CFreqCtrl::CFreqCtrl(QWidget *parent) : QFrame(parent) { @@ -72,7 +58,7 @@ CFreqCtrl::CFreqCtrl(QWidget *parent) : m_HighlightColor = QColor(0x5A, 0x5A, 0x5A, 0xFF); m_UnitsColor = Qt::gray; m_freq = 146123456; - setup(0, 1, 4000000000U, 1, UNITS_MHZ); + setup(0, 1, 4000000000U, 1, FCTL_UNIT_NONE); m_Oldfreq = 0; m_LastLeadZeroPos = 0; m_LRMouseFreqSel = false; @@ -88,9 +74,6 @@ CFreqCtrl::~CFreqCtrl() { } -///////////////////////////////////////////////////////////////////// -// Size hint stuff -///////////////////////////////////////////////////////////////////// QSize CFreqCtrl::minimumSizeHint() const { return QSize(100, 20); @@ -101,9 +84,6 @@ QSize CFreqCtrl::sizeHint() const return QSize(100, 20); } -///////////////////////////////////////////////////////////////////// -// Various helper functions -///////////////////////////////////////////////////////////////////// bool CFreqCtrl::inRect(QRect &rect, QPoint &point) { if ((point.x() < rect.right()) && (point.x() > rect.x()) && @@ -129,23 +109,21 @@ static int fmax_to_numdigits(qint64 fmax) return 12; } -////////////////////////////////////////////////////////////////////////////// -// Setup various parameters for the control -////////////////////////////////////////////////////////////////////////////// -void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNITS UnitsType) +void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf, int MinStep, + FctlUnit unit) { - int i; - qint64 pwr = 1; + int i; + qint64 pwr = 1; m_LastEditDigit = 0; m_Oldfreq = -1; m_NumDigits = NumDigits ? NumDigits : fmax_to_numdigits(Maxf); - if (m_NumDigits > MAX_DIGITS) - m_NumDigits = MAX_DIGITS; + if (m_NumDigits > FCTL_MAX_DIGITS) + m_NumDigits = FCTL_MAX_DIGITS; - if (m_NumDigits < MIN_DIGITS) - m_NumDigits = MIN_DIGITS; + if (m_NumDigits < FCTL_MIN_DIGITS) + m_NumDigits = FCTL_MIN_DIGITS; m_UnitString = ""; m_MinStep = MinStep; @@ -173,9 +151,9 @@ void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNIT } if (m_MaxFreq > pwr) - m_MaxFreq = pwr-1; + m_MaxFreq = pwr - 1; - m_MaxFreq = m_MaxFreq - m_MaxFreq%m_MinStep; + m_MaxFreq = m_MaxFreq - m_MaxFreq % m_MinStep; if (m_MinFreq > pwr) m_MinFreq = 1; @@ -183,43 +161,9 @@ void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNIT m_MinFreq = m_MinFreq - m_MinFreq % m_MinStep; m_DigStart = 0; - switch (UnitsType) - { - case UNITS_HZ: - m_DecPos = 0; - m_UnitString = "Hz "; - break; - case UNITS_KHZ: - m_DecPos = 3; - m_UnitString = "kHz"; - break; - case UNITS_MHZ: - m_DecPos = 6; - m_UnitString = "MHz"; - break; - case UNITS_GHZ: - m_DecPos = 9; - m_UnitString = "GHz"; - break; - case UNITS_SEC: - m_DecPos = 6; - m_UnitString = "Sec"; - break; - case UNITS_MSEC: - m_DecPos = 3; - m_UnitString = "mS "; - break; - case UNITS_USEC: - m_DecPos = 0; - m_UnitString = "uS "; - break; - case UNITS_NSEC: - m_DecPos = 0; - m_UnitString = "nS "; - break; - } + setUnit(unit); - for (i = m_NumDigits-1; i >= 0; i--) + for (i = m_NumDigits - 1; i >= 0; i--) { if (m_DigitInfo[i].weight <= m_MinStep) { @@ -230,25 +174,22 @@ void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNIT } else { - if ((m_MinStep%m_DigitInfo[i+1].weight) != 0) + if ((m_MinStep % m_DigitInfo[i + 1].weight) != 0) m_DigStart = i; m_DigitInfo[i].incval = 0; } } } - m_NumSeps = (m_NumDigits-1)/3 - m_DigStart/3; + m_NumSeps = (m_NumDigits - 1) / 3 - m_DigStart / 3; } -////////////////////////////////////////////////////////////////////////////// -// Sets the frequency and individual digit values -////////////////////////////////////////////////////////////////////////////// void CFreqCtrl::setFrequency(qint64 freq) { - int i; - qint64 acc = 0; - qint64 rem; - int val; + int i; + qint64 acc = 0; + qint64 rem; + int val; if (freq == m_Oldfreq) return; @@ -263,7 +204,7 @@ void CFreqCtrl::setFrequency(qint64 freq) rem = m_freq; m_LeadZeroPos = m_NumDigits; - for (i = m_NumDigits-1; i >= m_DigStart; i--) + for (i = m_NumDigits - 1; i >= m_DigStart; i--) { val = (int)(rem / m_DigitInfo[i].weight); if (m_DigitInfo[i].val != val) @@ -271,7 +212,7 @@ void CFreqCtrl::setFrequency(qint64 freq) m_DigitInfo[i].val = val; m_DigitInfo[i].modified = true; } - rem = rem - val*m_DigitInfo[i].weight; + rem = rem - val * m_DigitInfo[i].weight; acc += val; if ((acc == 0) && (i > m_DecPos)) { @@ -292,10 +233,11 @@ void CFreqCtrl::setFrequency(qint64 freq) /** TBC if this works for all configurations */ if (m_freq < 0) { - if (m_DigitInfo[m_LeadZeroPos-1].val > 0) - m_DigitInfo[m_LeadZeroPos-1].val = -m_DigitInfo[m_LeadZeroPos-1].val; + if (m_DigitInfo[m_LeadZeroPos - 1].val > 0) + m_DigitInfo[m_LeadZeroPos - + 1].val = -m_DigitInfo[m_LeadZeroPos - 1].val; - for (i = 0; i < (m_LeadZeroPos-1); i++) + for (i = 0; i < (m_LeadZeroPos - 1); i++) { if (m_DigitInfo[i].val < 0) m_DigitInfo[i].val = -m_DigitInfo[i].val; @@ -304,74 +246,70 @@ void CFreqCtrl::setFrequency(qint64 freq) // signal the new frequency to world m_Oldfreq = m_freq; - emit newFrequency(m_freq); + emit newFrequency(m_freq); updateCtrl(m_LastLeadZeroPos != m_LeadZeroPos); m_LastLeadZeroPos = m_LeadZeroPos; } -////////////////////////////////////////////////////////////////////////////// -// Sets the Digit and comma and decimal pt color -////////////////////////////////////////////////////////////////////////////// -void CFreqCtrl::setDigitColor(QColor cr) +void CFreqCtrl::setDigitColor(QColor col) { m_UpdateAll = true; - m_DigitColor = cr; - for(int i=m_DigStart; i=0) +void CFreqCtrl::leaveEvent(QEvent *) +{ + // called when mouse cursor leaves this control so deactivate any highlights + if (m_ActiveEditDigit >= 0) { - if( m_DigitInfo[m_ActiveEditDigit].editmode ) + if (m_DigitInfo[m_ActiveEditDigit].editmode) { m_DigitInfo[m_ActiveEditDigit].editmode = false; m_DigitInfo[m_ActiveEditDigit].modified = true; @@ -440,32 +365,26 @@ void CFreqCtrl::leaveEvent( QEvent * ) } } -///////////////////////////////////////////////////////////////////// -// main draw event for this control -///////////////////////////////////////////////////////////////////// void CFreqCtrl::paintEvent(QPaintEvent *) { - QPainter painter(&m_Pixmap); + QPainter painter(&m_Pixmap); - if (m_UpdateAll) //if need to redraw everything + if (m_UpdateAll) // if need to redraw everything { drawBkGround(painter); m_UpdateAll = false; } // draw any modified digits to the m_MemDC drawDigits(painter); - //now draw pixmap onto screen - QPainter scrnpainter(this); - scrnpainter.drawPixmap(0,0,m_Pixmap); //blt to the screen(flickers like a candle, why?) + // now draw pixmap onto screen + QPainter scrnpainter(this); + scrnpainter.drawPixmap(0, 0, m_Pixmap); // blt to the screen(flickers like a candle, why?) } -///////////////////////////////////////////////////////////////////// -// Mouse Event overrides -///////////////////////////////////////////////////////////////////// -void CFreqCtrl::mouseMoveEvent(QMouseEvent * event) +void CFreqCtrl::mouseMoveEvent(QMouseEvent *event) { -QPoint pt = event->pos(); - //find which digit is to be edited + QPoint pt = event->pos(); + // find which digit is to be edited if (isActiveWindow()) { if (!hasFocus()) @@ -482,7 +401,8 @@ QPoint pt = event->pos(); } } else - { //un-highlight the previous digit if moved off it + { + // un-highlight the previous digit if moved off it if (m_DigitInfo[i].editmode) { m_DigitInfo[i].editmode = false; @@ -495,17 +415,14 @@ QPoint pt = event->pos(); } } -////////////////////////////////////////////////////////////////////////////// -// Service mouse button clicks to inc or dec the selected frequency -////////////////////////////////////////////////////////////////////////////// -void CFreqCtrl::mousePressEvent(QMouseEvent * event) +void CFreqCtrl::mousePressEvent(QMouseEvent *event) { - QPoint pt = event->pos(); + QPoint pt = event->pos(); if (event->button() == Qt::LeftButton) { for (int i = m_DigStart; i < m_NumDigits; i++) { - if (inRect(m_DigitInfo[i].dQRect, pt)) //if in i'th digit + if (inRect(m_DigitInfo[i].dQRect, pt)) // if in i'th digit { if (m_LRMouseFreqSel) { @@ -513,10 +430,10 @@ void CFreqCtrl::mousePressEvent(QMouseEvent * event) } else { - if (pt.y() < m_DigitInfo[i].dQRect.bottom()/2) //top half? + if (pt.y() < m_DigitInfo[i].dQRect.bottom() / 2) // top half? incFreq(); else - decFreq(); //bottom half + decFreq(); // bottom half } } } @@ -525,7 +442,7 @@ void CFreqCtrl::mousePressEvent(QMouseEvent * event) { for (int i = m_DigStart; i < m_NumDigits; i++) { - if (inRect(m_DigitInfo[i].dQRect, pt)) //if in i'th digit + if (inRect(m_DigitInfo[i].dQRect, pt)) // if in i'th digit { if (m_LRMouseFreqSel) { @@ -540,18 +457,15 @@ void CFreqCtrl::mousePressEvent(QMouseEvent * event) } } -///////////////////////////////////////////////////////////////////// -// Mouse Wheel Event overrides -///////////////////////////////////////////////////////////////////// -void CFreqCtrl::wheelEvent(QWheelEvent * event) +void CFreqCtrl::wheelEvent(QWheelEvent *event) { - QPoint pt = event->pos(); - int numDegrees = event->delta() / 8; - int numSteps = numDegrees / 15; + QPoint pt = event->pos(); + int numDegrees = event->delta() / 8; + int numSteps = numDegrees / 15; for (int i = m_DigStart; i < m_NumDigits; i++) { - if (inRect(m_DigitInfo[i].dQRect, pt)) //if in i'th digit + if (inRect(m_DigitInfo[i].dQRect, pt)) // if in i'th digit { if (numSteps > 0) incFreq(); @@ -561,122 +475,119 @@ void CFreqCtrl::wheelEvent(QWheelEvent * event) } } - -///////////////////////////////////////////////////////////////////// -// Keyboard Event overrides -///////////////////////////////////////////////////////////////////// -void CFreqCtrl::keyPressEvent( QKeyEvent * event ) +void CFreqCtrl::keyPressEvent(QKeyEvent *event) { - //call base class if dont over ride key - bool fSkipMsg = false; - qint64 tmp; + // call base class if dont over ride key + bool fSkipMsg = false; + qint64 tmp; - //qDebug() <key(); + // qDebug() <key(); - switch(event->key()) + switch (event->key()) { - case Qt::Key_0: - case Qt::Key_1: - case Qt::Key_2: - case Qt::Key_3: - case Qt::Key_4: - case Qt::Key_5: - case Qt::Key_6: - case Qt::Key_7: - case Qt::Key_8: - case Qt::Key_9: - if (m_ActiveEditDigit >= 0) + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + if (m_ActiveEditDigit >= 0) + { + if (m_DigitInfo[m_ActiveEditDigit].editmode) { - if (m_DigitInfo[m_ActiveEditDigit].editmode) - { - tmp = (m_freq/m_DigitInfo[m_ActiveEditDigit].weight) % 10; - m_freq -= tmp*m_DigitInfo[m_ActiveEditDigit].weight; - m_freq = m_freq+(event->key()-'0')*m_DigitInfo[m_ActiveEditDigit].weight; - setFrequency(m_freq); - } + tmp = (m_freq / m_DigitInfo[m_ActiveEditDigit].weight) % 10; + m_freq -= tmp * m_DigitInfo[m_ActiveEditDigit].weight; + m_freq = m_freq + (event->key() - '0') * + m_DigitInfo[m_ActiveEditDigit].weight; + setFrequency(m_freq); } - moveCursorRight(); + } + moveCursorRight(); + fSkipMsg = true; + break; + case Qt::Key_Left: + if (m_ActiveEditDigit != -1) + { + moveCursorLeft(); fSkipMsg = true; - break; - case Qt::Key_Left: - if (m_ActiveEditDigit != -1) - { - moveCursorLeft(); - fSkipMsg = true; - } - break; - case Qt::Key_Up: - if (m_ActiveEditDigit != -1) - { - incFreq(); - fSkipMsg = true; - } - break; - case Qt::Key_Down: - if (m_ActiveEditDigit != -1) - { - decFreq(); - fSkipMsg = true; - } - break; - case Qt::Key_Right: - if (m_ActiveEditDigit != -1) - { - moveCursorRight(); - fSkipMsg = true; - } - break; - case Qt::Key_Home: - cursorHome(); + } + break; + case Qt::Key_Up: + if (m_ActiveEditDigit != -1) + { + incFreq(); fSkipMsg = true; - break; - case Qt::Key_End: - cursorEnd(); + } + break; + case Qt::Key_Down: + if (m_ActiveEditDigit != -1) + { + decFreq(); fSkipMsg = true; - break; - default: - break; + } + break; + case Qt::Key_Right: + if (m_ActiveEditDigit != -1) + { + moveCursorRight(); + fSkipMsg = true; + } + break; + case Qt::Key_Home: + cursorHome(); + fSkipMsg = true; + break; + case Qt::Key_End: + cursorEnd(); + fSkipMsg = true; + break; + default: + break; } if (!fSkipMsg) QFrame::keyPressEvent(event); } - -////////////////////////////////////////////////////////////////////////////// -// Calculates all the rectangles for the digits, separators, and units text -// and creates the fonts for them. -////////////////////////////////////////////////////////////////////////////// void CFreqCtrl::drawBkGround(QPainter &Painter) { - QRect rect(0, 0, width(), height()); - - //qDebug() < m_DigStart) && ((i%3)==0)) + if ((i > m_DigStart) && ((i % 3) == 0)) { m_SepRect[i].setCoords(digpos - sepwidth, rect.top(), @@ -684,30 +595,34 @@ void CFreqCtrl::drawBkGround(QPainter &Painter) rect.bottom()); Painter.fillRect(m_SepRect[i], m_BkColor); digpos -= sepwidth; - if (i == m_DecPos) - Painter.drawText(m_SepRect[i], Qt::AlignHCenter|Qt::AlignVCenter, "."); -// disable digit group separators -// else if (i > m_DecPos && i < m_LeadZeroPos) -// Painter.drawText(m_SepRect[i], Qt::AlignHCenter|Qt::AlignVCenter, ","); - else if (i < m_LeadZeroPos) - Painter.drawText(m_SepRect[i], Qt::AlignHCenter|Qt::AlignVCenter, " "); + if (m_Unit == FCTL_UNIT_NONE) + { + if (m_LeadZeroPos > i) + dgsep = '.'; + else + dgsep = ' '; + } + else + { + if (i == m_DecPos) + dgsep = '.'; + else if (i < m_LeadZeroPos) + dgsep = ' '; + } + Painter.drawText(m_SepRect[i], Qt::AlignHCenter | Qt::AlignVCenter, + QChar(dgsep)); } else { m_SepRect[i].setCoords(0, 0, 0, 0); } - m_DigitInfo[i].dQRect.setCoords(digpos - cellwidth, - rect.top(), - digpos, - rect.bottom()); + m_DigitInfo[i].dQRect.setCoords(digpos - cellwidth, rect.top(), + digpos, rect.bottom()); digpos -= cellwidth; } - } -////////////////////////////////////////////////////////////////////////////// // Draws just the Digits that have been modified -////////////////////////////////////////////////////////////////////////////// void CFreqCtrl::drawDigits(QPainter &Painter) { Painter.setFont(m_DigitFont); @@ -731,47 +646,55 @@ void CFreqCtrl::drawDigits(QPainter &Painter) Painter.setPen(m_DigitColor); if (m_freq < 0 && i == m_LeadZeroPos - 1 && m_DigitInfo[i].val == 0) - Painter.drawText(m_DigitInfo[i].dQRect, Qt::AlignHCenter|Qt::AlignVCenter, + Painter.drawText(m_DigitInfo[i].dQRect, + Qt::AlignHCenter | Qt::AlignVCenter, QString("-0")); else - Painter.drawText(m_DigitInfo[i].dQRect, Qt::AlignHCenter|Qt::AlignVCenter, + Painter.drawText(m_DigitInfo[i].dQRect, + Qt::AlignHCenter | Qt::AlignVCenter, QString().number(m_DigitInfo[i].val)); m_DigitInfo[i].modified = false; } } } -////////////////////////////////////////////////////////////////////////////// -// Increment just the digit active in edit mode -////////////////////////////////////////////////////////////////////////////// +// Increment just the digit active in edit mode void CFreqCtrl::incDigit() { /** FIXME: no longer used? */ - int tmp; - qint64 tmpl; + int tmp; + qint64 tmpl; if (m_ActiveEditDigit >= 0) { if (m_DigitInfo[m_ActiveEditDigit].editmode) { - if (m_DigitInfo[m_ActiveEditDigit].weight == m_DigitInfo[m_ActiveEditDigit].incval) + if (m_DigitInfo[m_ActiveEditDigit].weight == + m_DigitInfo[m_ActiveEditDigit].incval) { // get the current digit value - tmp = (int)((m_freq/m_DigitInfo[m_ActiveEditDigit].weight) % 10); + tmp = + (int)((m_freq / m_DigitInfo[m_ActiveEditDigit].weight) % + 10); // set the current digit value to zero - m_freq -= tmp*m_DigitInfo[m_ActiveEditDigit].weight; + m_freq -= tmp * m_DigitInfo[m_ActiveEditDigit].weight; tmp++; if (tmp > 9) tmp = 0; - m_freq = m_freq + (qint64)tmp*m_DigitInfo[m_ActiveEditDigit].weight; + m_freq = m_freq + (qint64)tmp * + m_DigitInfo[m_ActiveEditDigit].weight; } else { - tmp = (int)((m_freq/m_DigitInfo[m_ActiveEditDigit+1].weight) % 10); + tmp = + (int)((m_freq / m_DigitInfo[m_ActiveEditDigit + 1].weight) % + 10); tmpl = m_freq + m_DigitInfo[m_ActiveEditDigit].incval; - if (tmp != (int)((tmpl/m_DigitInfo[m_ActiveEditDigit+1].weight) % 10)) + if (tmp != + (int)((tmpl / m_DigitInfo[m_ActiveEditDigit + 1].weight) % + 10)) { - tmpl -= m_DigitInfo[m_ActiveEditDigit+1].weight; + tmpl -= m_DigitInfo[m_ActiveEditDigit + 1].weight; } m_freq = tmpl; } @@ -780,9 +703,7 @@ void CFreqCtrl::incDigit() } } -////////////////////////////////////////////////////////////////////////////// -// Increment the frequency by this digit active in edit mode -////////////////////////////////////////////////////////////////////////////// +// Increment the frequency by this digit active in edit mode void CFreqCtrl::incFreq() { if (m_ActiveEditDigit >= 0) @@ -790,9 +711,11 @@ void CFreqCtrl::incFreq() if (m_DigitInfo[m_ActiveEditDigit].editmode) { m_freq += m_DigitInfo[m_ActiveEditDigit].incval; - if (m_ResetLowerDigits) { + if (m_ResetLowerDigits) + { /* Set digits below the active one to 0 */ - m_freq = m_freq - m_freq%m_DigitInfo[m_ActiveEditDigit].weight; + m_freq = m_freq - m_freq % + m_DigitInfo[m_ActiveEditDigit].weight; } setFrequency(m_freq); m_LastEditDigit = m_ActiveEditDigit; @@ -800,37 +723,43 @@ void CFreqCtrl::incFreq() } } -////////////////////////////////////////////////////////////////////////////// -// Decrement the digit active in edit mode -////////////////////////////////////////////////////////////////////////////// +// Decrement the digit active in edit mode void CFreqCtrl::decDigit() { /** FIXME: no longer used? */ - int tmp; - qint64 tmpl; + int tmp; + qint64 tmpl; if (m_ActiveEditDigit >= 0) { if (m_DigitInfo[m_ActiveEditDigit].editmode) { - if (m_DigitInfo[m_ActiveEditDigit].weight == m_DigitInfo[m_ActiveEditDigit].incval) + if (m_DigitInfo[m_ActiveEditDigit].weight == + m_DigitInfo[m_ActiveEditDigit].incval) { // get the current digit value - tmp = (int)((m_freq/m_DigitInfo[m_ActiveEditDigit].weight) % 10); + tmp = + (int)((m_freq / m_DigitInfo[m_ActiveEditDigit].weight) % + 10); // set the current digit value to zero - m_freq -= tmp*m_DigitInfo[m_ActiveEditDigit].weight; + m_freq -= tmp * m_DigitInfo[m_ActiveEditDigit].weight; tmp--; if (tmp < 0) tmp = 9; - m_freq = m_freq+(qint64)tmp*m_DigitInfo[m_ActiveEditDigit].weight; + m_freq = m_freq + (qint64)tmp * + m_DigitInfo[m_ActiveEditDigit].weight; } else { - tmp = (int)((m_freq/m_DigitInfo[m_ActiveEditDigit+1].weight) % 10); + tmp = + (int)((m_freq / m_DigitInfo[m_ActiveEditDigit + 1].weight) % + 10); tmpl = m_freq - m_DigitInfo[m_ActiveEditDigit].incval; - if (tmp != (int)((tmpl/m_DigitInfo[m_ActiveEditDigit+1].weight)%10)) + if (tmp != + (int)((tmpl / m_DigitInfo[m_ActiveEditDigit + 1].weight) % + 10)) { - tmpl += m_DigitInfo[m_ActiveEditDigit+1].weight; + tmpl += m_DigitInfo[m_ActiveEditDigit + 1].weight; } m_freq = tmpl; } @@ -839,9 +768,7 @@ void CFreqCtrl::decDigit() } } -////////////////////////////////////////////////////////////////////////////// -// Decrement the frequency by this digit active in edit mode -////////////////////////////////////////////////////////////////////////////// +// Decrement the frequency by this digit active in edit mode void CFreqCtrl::decFreq() { if (m_ActiveEditDigit >= 0) @@ -852,7 +779,8 @@ void CFreqCtrl::decFreq() if (m_ResetLowerDigits) { /* digits below the active one are reset to 0 */ - m_freq = m_freq - m_freq%m_DigitInfo[m_ActiveEditDigit].weight; + m_freq = m_freq - m_freq % + m_DigitInfo[m_ActiveEditDigit].weight; } setFrequency(m_freq); @@ -861,9 +789,7 @@ void CFreqCtrl::decFreq() } } -////////////////////////////////////////////////////////////////////////////// -// Clear the selected digit and the digits below (i.e. set them to 0) -////////////////////////////////////////////////////////////////////////////// +// Clear the selected digit and the digits below (i.e. set them to 0) void CFreqCtrl::clearFreq() { if (m_ActiveEditDigit >= 0) @@ -871,7 +797,7 @@ void CFreqCtrl::clearFreq() if (m_DigitInfo[m_ActiveEditDigit].editmode) { m_freq -= m_DigitInfo[m_ActiveEditDigit].val * - m_DigitInfo[m_ActiveEditDigit].incval; + m_DigitInfo[m_ActiveEditDigit].incval; /* digits below the active one are reset to 0 */ m_freq -= m_freq % m_DigitInfo[m_ActiveEditDigit].weight; @@ -880,17 +806,15 @@ void CFreqCtrl::clearFreq() m_LastEditDigit = m_ActiveEditDigit; } } - } -///////////////////////////////////////////////////////////////////// // Cursor move routines for arrow key editing -///////////////////////////////////////////////////////////////////// void CFreqCtrl::moveCursorLeft() { - if ((m_ActiveEditDigit >= 0) && (m_ActiveEditDigit < m_NumDigits-1)) + if ((m_ActiveEditDigit >= 0) && (m_ActiveEditDigit < m_NumDigits - 1)) { - cursor().setPos(mapToGlobal(m_DigitInfo[++m_ActiveEditDigit].dQRect.center())); + cursor().setPos(mapToGlobal(m_DigitInfo[++m_ActiveEditDigit].dQRect. + center())); } } @@ -898,7 +822,8 @@ void CFreqCtrl::moveCursorRight() { if (m_ActiveEditDigit > m_FirstEditableDigit) { - cursor().setPos(mapToGlobal(m_DigitInfo[--m_ActiveEditDigit].dQRect.center())); + cursor().setPos(mapToGlobal(m_DigitInfo[--m_ActiveEditDigit].dQRect. + center())); } } @@ -906,7 +831,8 @@ void CFreqCtrl::cursorHome() { if (m_ActiveEditDigit >= 0) { - cursor().setPos(mapToGlobal( m_DigitInfo[m_NumDigits-1].dQRect.center())); + cursor().setPos(mapToGlobal( + m_DigitInfo[m_NumDigits - 1].dQRect.center())); } } @@ -914,6 +840,7 @@ void CFreqCtrl::cursorEnd() { if (m_ActiveEditDigit > 0) { - cursor().setPos(mapToGlobal(m_DigitInfo[m_FirstEditableDigit].dQRect.center())); + cursor().setPos(mapToGlobal(m_DigitInfo[m_FirstEditableDigit].dQRect. + center())); } } diff --git a/src/qtgui/freqctrl.h b/src/qtgui/freqctrl.h index 9828318..a3ce398 100644 --- a/src/qtgui/freqctrl.h +++ b/src/qtgui/freqctrl.h @@ -1,148 +1,133 @@ -////////////////////////////////////////////////////////////////////// -// freqctrl.h: interface for the CFreqCtrl class. -// -// History: -// 2010-09-15 Initial creation MSW -// 2011-03-27 Initial release -///////////////////////////////////////////////////////////////////// -#ifndef FREQCTRL_H -#define FREQCTRL_H -/////////////////////////////////////////////////////////////////////// -// To use this control, add a frame using the QT designer editor. -// Promote it to the CFreqCtrl class and include file freqctrl.h -// Initilaize the control in the constructor of the controls parent -// ex: ui->frameFreqCtrl->Setup(9, 10000U, 230000000U, 1, UNITS_MHZ ); -// where 9 is the number of display digits, min freq is 10kHz , Max is 230MHz -// the minimum step size is 1Hz and the freq is displayed as MHz -// NOTE: the frequency is a qint64 64 bit integer value -// to change frequency call SetFrequency() -// ex: ui->frameFreqCtrl->SetFrequency(146000000); -// -// One signal is sent when the control frequency changes: -//void NewFrequency(qint64 freq); //emitted when frequency has changed -/////////////////////////////////////////////////////////////////////// +/* + * Frequency controller widget (originally from CuteSDR) + */ +#pragma once -#include #include #include +#include -enum FUNITS -{ - UNITS_HZ, - UNITS_KHZ, - UNITS_MHZ, - UNITS_GHZ, - UNITS_SEC, - UNITS_MSEC, - UNITS_USEC, - UNITS_NSEC +enum FctlUnit { + FCTL_UNIT_NONE, // Freq displayed without unit: 14.236.000 + FCTL_UNIT_HZ, + FCTL_UNIT_KHZ, + FCTL_UNIT_MHZ, + FCTL_UNIT_GHZ, + FCTL_UNIT_SEC, + FCTL_UNIT_MSEC, + FCTL_UNIT_USEC, + FCTL_UNIT_NSEC }; -#define MAX_DIGITS 12 -#define MIN_DIGITS 4 +#define FCTL_MAX_DIGITS 12 +#define FCTL_MIN_DIGITS 4 class CFreqCtrl : public QFrame { Q_OBJECT + public: explicit CFreqCtrl(QWidget *parent = 0); ~CFreqCtrl(); - QSize minimumSizeHint() const; - QSize sizeHint() const; + + QSize minimumSizeHint() const; + QSize sizeHint() const; // Use NumDigits=0 for auto - void setup(int NumDigits, qint64 Minf, qint64 Maxf,int MinStep, FUNITS UnitsType); - void setUnits(FUNITS units); - void setDigitColor(QColor cr); - void setBkColor(QColor cr); - void setUnitsColor(QColor cr); - void setHighlightColor(QColor cr); - qint64 getFrequency() { return m_freq; } - - void setResetLowerDigits(bool reset) { + void setup(int NumDigits, qint64 Minf, qint64 Maxf, int MinStep, + FctlUnit unit); + void setUnit(FctlUnit unit); + void setDigitColor(QColor col); + void setBgColor(QColor col); + void setUnitsColor(QColor col); + void setHighlightColor(QColor col); + qint64 getFrequency() const + { + return m_freq; + } + + void setResetLowerDigits(bool reset) + { m_ResetLowerDigits = reset; } signals: - void newFrequency(qint64 freq); //emitted when frequency has changed + void newFrequency(qint64 freq); // emitted when frequency has changed public slots: - void setFrequency(qint64 freq); + void setFrequency(qint64 freq); -protected: //overrides for this control - void paintEvent(QPaintEvent *); - void resizeEvent(QResizeEvent *); - void mouseMoveEvent(QMouseEvent *); - void mousePressEvent(QMouseEvent *); - void wheelEvent(QWheelEvent *); - void leaveEvent(QEvent *); - void keyPressEvent(QKeyEvent *); +protected: + void paintEvent(QPaintEvent *); + void resizeEvent(QResizeEvent *); + void mouseMoveEvent(QMouseEvent *); + void mousePressEvent(QMouseEvent *); + void wheelEvent(QWheelEvent *); + void leaveEvent(QEvent *); + void keyPressEvent(QKeyEvent *); private: - void updateCtrl(bool all); - void drawBkGround(QPainter &Painter); - void drawDigits(QPainter &Painter); - void incDigit(); - void decDigit(); - void incFreq(); - void decFreq(); - void clearFreq(); - void cursorHome(); - void cursorEnd(); - void moveCursorLeft(); - void moveCursorRight(); - bool inRect(QRect &rect, QPoint &point); - - bool m_UpdateAll; - bool m_ExternalKeyActive; - bool m_LRMouseFreqSel; /*! Use left/right mouse buttons. If FALSE click area determines up/down. */ - - bool m_ResetLowerDigits; /*! If TRUE digits below the active one will be reset to 0 - when the active digit is incremented or decremented. */ - - int m_FirstEditableDigit; - int m_LastLeadZeroPos; - int m_LeadZeroPos; - int m_NumDigits; - int m_DigStart; - int m_ActiveEditDigit; - int m_LastEditDigit; - int m_DecPos; - int m_NumSeps; - - qint64 m_MinStep; - qint64 m_freq; - qint64 m_Oldfreq; - qint64 m_MinFreq; - qint64 m_MaxFreq; - - QColor m_DigitColor; - QColor m_BkColor; - QColor m_UnitsColor; - QColor m_HighlightColor; - - QPixmap m_Pixmap; - QSize m_Size; - FUNITS m_Units; - - QRect m_rectCtrl; //main control rectangle - QRect m_UnitsRect; //rectangle where Units text goes - QRect m_SepRect[MAX_DIGITS]; //separation rectangles for commas,dec pt, etc. - - QString m_UnitString; - - QFont m_DigitFont; - QFont m_UnitsFont; - - struct DigStuct - { - qint64 weight; //decimal weight of this digit - qint64 incval; //value this digit increments or decrements - QRect dQRect; //Digit bounding rectangle - int val; //value of this digit(0-9) - bool modified; //set if this digit has been modified - bool editmode; //set if this digit is selected for editing - } m_DigitInfo[MAX_DIGITS]; + void updateCtrl(bool all); + void drawBkGround(QPainter &Painter); + void drawDigits(QPainter &Painter); + void incDigit(); + void decDigit(); + void incFreq(); + void decFreq(); + void clearFreq(); + void cursorHome(); + void cursorEnd(); + void moveCursorLeft(); + void moveCursorRight(); + bool inRect(QRect &rect, QPoint &point); + + bool m_UpdateAll; + bool m_ExternalKeyActive; + bool m_LRMouseFreqSel; /* Use left/right mouse buttons. If FALSE click area determines up/down. */ + + bool m_ResetLowerDigits; /* If TRUE digits below the active one will be reset to 0 + * when the active digit is incremented or decremented. */ + + int m_FirstEditableDigit; + int m_LastLeadZeroPos; + int m_LeadZeroPos; + int m_NumDigits; + int m_DigStart; + int m_ActiveEditDigit; + int m_LastEditDigit; + int m_DecPos; + int m_NumSeps; + + qint64 m_MinStep; + qint64 m_freq; + qint64 m_Oldfreq; + qint64 m_MinFreq; + qint64 m_MaxFreq; + + QColor m_DigitColor; + QColor m_BkColor; + QColor m_UnitsColor; + QColor m_HighlightColor; + + QPixmap m_Pixmap; + QSize m_Size; + FctlUnit m_Unit; + + QRect m_rectCtrl; // main control rectangle + QRect m_UnitsRect; // rectangle where Units text goes + QRect m_SepRect[FCTL_MAX_DIGITS]; // separation rectangles for commas, decimal point, etc. + + QString m_UnitString; + + QFont m_DigitFont; + QFont m_UnitsFont; + + struct DigStuct { + qint64 weight; // decimal weight of this digit + qint64 incval; // value this digit increments or decrements + QRect dQRect; // Digit bounding rectangle + int val; // value of this digit(0-9) + bool modified; // set if this digit has been modified + bool editmode; // set if this digit is selected for editing + } m_DigitInfo[FCTL_MAX_DIGITS]; }; - -#endif // FREQCTRL_H From 7a39d989c8aa994e27df3bda8c721e7e29d134d0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 4 May 2017 00:13:37 +0200 Subject: [PATCH 230/334] Fix incorrect digit separator in CFreqCtrl --- src/qtgui/freqctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index 7e36d39..8d9a7b1 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -606,7 +606,7 @@ void CFreqCtrl::drawBkGround(QPainter &Painter) { if (i == m_DecPos) dgsep = '.'; - else if (i < m_LeadZeroPos) + else dgsep = ' '; } Painter.drawText(m_SepRect[i], Qt::AlignHCenter | Qt::AlignVCenter, From 09f89e4c384bb39258b52c286febc51d8e75e2eb Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 11 May 2017 23:39:47 +0200 Subject: [PATCH 231/334] Switch to Hamradio style frequency display --- resources/news.txt | 1 + src/applications/gqrx/mainwindow.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index 3a12f81..dabc394 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -16,6 +16,7 @@ IMPROVED: Voiceover interface. IMPROVED: Input decimator performance. IMPROVED: Increased frequency limit to 999 GHz (500 GHz LO). + IMPROVED: Hamradio style frequency display. IMPROVED: More short waterfall time spans. diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index b095dd2..225ca04 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -83,7 +83,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : setWindowTitle(QString("Gqrx %1").arg(VERSION)); /* frequency control widget */ - ui->freqCtrl->setup(0, 0, 9999e6, 1, FCTL_UNIT_MHZ); + ui->freqCtrl->setup(0, 0, 9999e6, 1, FCTL_UNIT_NONE); ui->freqCtrl->setFrequency(144500000); d_filter_shape = receiver::FILTER_SHAPE_NORMAL; @@ -745,7 +745,7 @@ void MainWindow::updateFrequencyRange() qint64 start = (qint64)(rx->get_filter_offset()) + d_hw_freq_start + d_lnb_lo; qint64 stop = (qint64)(rx->get_filter_offset()) + d_hw_freq_stop + d_lnb_lo; - ui->freqCtrl->setup(0, start, stop, 1, FCTL_UNIT_MHZ); + ui->freqCtrl->setup(0, start, stop, 1, FCTL_UNIT_NONE); uiDockRxOpt->setRxFreqRange(start, stop); } From 82e0cc2c6be3c3d360cf7565f84b6d942329cc53 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 1 Jun 2017 00:44:29 +0200 Subject: [PATCH 232/334] Add new logos to be integrated Sponsored by Libre Space Foundation --- new_logo/PNG/horizontal color.png | Bin 0 -> 28448 bytes new_logo/PNG/horizontal white.png | Bin 0 -> 21815 bytes new_logo/PNG/icon color.png | Bin 0 -> 10986 bytes new_logo/PNG/icon white.png | Bin 0 -> 8964 bytes new_logo/PNG/vertical color.png | Bin 0 -> 27363 bytes new_logo/PNG/vertical white.png | Bin 0 -> 21238 bytes new_logo/SVG/horizontal color.svg | 91 +++++++++++++++++++++ new_logo/SVG/horizontal white.svg | 94 ++++++++++++++++++++++ new_logo/SVG/icon color.svg | 82 +++++++++++++++++++ new_logo/SVG/icon white.svg | 84 ++++++++++++++++++++ new_logo/SVG/vertical color.svg | 126 ++++++++++++++++++++++++++++++ new_logo/SVG/vertical white.svg | 126 ++++++++++++++++++++++++++++++ 12 files changed, 603 insertions(+) create mode 100644 new_logo/PNG/horizontal color.png create mode 100644 new_logo/PNG/horizontal white.png create mode 100644 new_logo/PNG/icon color.png create mode 100644 new_logo/PNG/icon white.png create mode 100644 new_logo/PNG/vertical color.png create mode 100644 new_logo/PNG/vertical white.png create mode 100644 new_logo/SVG/horizontal color.svg create mode 100644 new_logo/SVG/horizontal white.svg create mode 100644 new_logo/SVG/icon color.svg create mode 100644 new_logo/SVG/icon white.svg create mode 100644 new_logo/SVG/vertical color.svg create mode 100644 new_logo/SVG/vertical white.svg diff --git a/new_logo/PNG/horizontal color.png b/new_logo/PNG/horizontal color.png new file mode 100644 index 0000000000000000000000000000000000000000..3fdbde4a29fc77acbdbd432b516945c99e068791 GIT binary patch literal 28448 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ʊlZthZHh@OJ7~`RsGp< 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 literal 0 HcmV?d00001 diff --git a/new_logo/PNG/horizontal white.png b/new_logo/PNG/horizontal white.png new file mode 100644 index 0000000000000000000000000000000000000000..64716306dd58ba0eb946f34bf44f22d0ae390808 GIT binary patch literal 21815 zcmd3OhgVb07H>j;s5B!YC_NMlO{9mWA3+ER2uQDr2I(#IuAdO32kA{EfOIr;1fn9S zGzrpM1O-D!TBvykz4xuV-e2&tmJ6JmIkRWao?U;NnA`eVET=A<0)ap*C~c$>2n3;l zKwz^IjKIhy>F5CXLGSYq>dpz^6LR7{7Wn^3Pi+ey5QyW=@joy!zv&Dxcpjr^jxqK? zWBl)WKLGjr`%5~xyZAWV^?V@d;q92cqH+NQ5&)r)H|_-FEKNFQ+&5|5UZ=_Y5EeiY zL65j#U`^&raP(Czr1v?bca)$b4+q1IH&`fSrp$Zo753@VM^AP1uNeL~EnM6<&E~@9 z$kkL_R=P9hvRbYzB*K5VG44@$d20N15|>>*Yt4;e0Vz zXk>wIwDg~O+~t2(2my`x^n#WNa)S)Y^Py~bkXO! z9gc_5^0F!$9&Vmq$a2+1s7MckHADGG0G#l7y}RvrvD&AOM-{T*=7g;nYye%x*ux9| zVf2rgX`Ovjq_uo@Up~aT{|?uGi2w0`W=fhRios_(MnjYFY@lfmQJjUu+oeC}V);=9 z`1&L}#}NqTrM5QC`1|j1vWWB@SY2iViQR0sX$g6auLp6?$KN;Q?mNf^h_EONn48v7 zdO7@_UjQC<@<7~y@9%0aerAS?efP63#0I>|hoXXbJujcOFv=Y4{GUCa*C8ZZL&MV5!`m z`tgB(WhyEUUVf9QY2~z^nM8*Cp%EJQgud+R(o#@REUxbjFINfbliGm(rPyVpEjAhUl@!WS1C-t`kfekRKJ6sr~aA&aZ) z&xG>We{ed{)h{-au~b{*$EYl(h70B|N~C+x4*!p6@`SPF4F8CLt(({(sJ?DcA1h@i|cfw*Ow?B?~|@eS=P!i@+eOEL?y6U+I^j4OL0`zCJ#U{m25Hd9EAj zkm)P`(ZSDv$M(FWs_!8uj1ixn3->Ttv#GRU(qMvQ31SbimPq$tR`!3DP8biac`d!h zx_42ly@2>#sk7QqQ3f8y3#$irrm_CfLh_{m(JgyWrz)C5BV&@R!kPjZ0`v0i@S3Bm zWHkLG7X@Aet-V=zr77G4wT8T{epreIwsFjfV~sLY7V2~ED76nP1umN75r*f1SidMm zfj!sajui$Ucv~#v&&7AW56~X8&S^i0&B${Bp<+P_Nr-i(05{};^lX4}ggUsYSFQuw z3=SA9SBMj4SW~u-hnHl{{zrUL@8<5dRbV0n3BkSZ+ukV9{ORpL(0QKnJz8d#PaJG# z_qFL$&tVu$o%q*Xt!Tqe3R- zIK;imN46(+?B7RPKMGg-W7aOn#eJl`fO&CLvv|5tuJT^AuV?H~I-3z5m&i{dj_fO3 z?YI<}^R4+Vycx{q*n98K*{0qVJE~$xpu=K=BYW0<&wQq$k=A*@nqrXr^Ya59xXrwr zS*>=1h*<9g>3c<*?X~QohR6xJTP^~Le{_ztH4Ci>;t`Lv>pQrCvSX-|U@sZqgWAGi z3UfS25(BZ>aYIB;mfQOAw|^zQY^XY2Vw>m+gz^>PufmVUtFR#X$PIWJep~uk~_ewvjvvhvujdXIq)AZ~LU(eQniS6qKqODFO{yIz!x+LkFfE8z5<5=^sI4 z>V+!*6P}Lo!^bR?A?TRx9H{Ff_76*M@QFKFkapMmD&$P+53j+evW|s139%z}HKuDq z3lT%k3o=s8#(#{=j+iK8Zdz%987{`lqO8DnWgA&f0{Z?s7CL5*M{L|Rz@gNgx<9Et zCH*pU`84!e<9mL4nEm{PH*sR{6~>~UJPs!gp0B)b`|V5q%{(l3ObfS@P0nuHxd1)n zttO=mypOh4Z+w%F&l1x$4^hiY7=}qP00U3}pyQFi)HiPjiW54dyXdf>(BV zd7(TYVR^G-EdMpYI>YFrVu;l@L#kOF!;!^6ZPUWZ11+B6D7?TYqlqO+#S50T#Qw@b)?0H!>e&IPa_cgNhvyoCo2C=)x>E z9`HkLO?_kf{vn0ni~PFgE)+a=7dmWF&+s{o5(AmhZT#T5DD+>0gDIi5K>{?96J|S4 zL_$w~vINzCdrW+)l->u?ZlVuxh|>?<->5VrtS8uVF-VBg*x) zY>^?tz@eE!!l2!$J~`(aV`Ud<*DJxL3f19)lWsjf+u(4Qftx69Nbx*R0i+1xak7$;~LlBibs*u9jGKYWy6iUdJ)wiEf@Yx`B(2*VTpzt=UO9q|;)z`L@HVf!T7(z z63`GvD%Wyo!Zav^MNtmELYa@m*`Dmq7BNvhIuD~s^1j3`1aG3qv-m*~Hy;tou0MJZ zTknWVqqj{0p5cqfie>XuFBB8BQyjJ_mDq;De5kf1N5-jggT^BpgJjdn5C*DYm6%y+ zN}*}@dGUhrn@*|bP}{za4ZxmBZ$N=PcyPlm%1hstGd>iv?-A_~`(;Ts0aSM-SXe@P ztZV13wL|w0E!b<@Ua)W|JypL~+Hy(FzR<`6CsLtdd1_1qkbqmbIZ=*%E0D(v<>D0; zx*QGXGvfn2rl?_3?<4Q1W%$g$B*83ECz!p1z0X+ifRpJC7@Cq7p1AWHgvy7sX2=cx zu;zfpyDOw(_}1Qub}kwB>Aez>VBmp-WckT0x1Li>zjH>SkKub&}z!& zP`5(}TZ8Ndmz!Mek0o>D0T0!%WW8rWz)2bv3{ikg3oL88?YpdX&q3rNlIfcj&W!yC zB&kd|_aEo`^6~B*Jh7loy6}|EBhuY+aTIsbp0u0x{;4!bO?{a3}?W(k~ zJ!Tadj7A*#FZ}&tfjW||8j>BlWuCocU7T^%N1|5i=$9x)0t*>$WX6ilKYK@syyGiRku z#7c_fIZDyvs2~H%>C9a1=6bgHc|rTf*npwnd3jD+v{t*xlMc1y@3~GBwUO@2P+YOl z+R|GKQnNSfX&5IR=TDx3Cw_d3oLU3$8Ot#*_V?u%2eZGOmpR=3da&9)F~{gfU-_&i zjB<6`6=y3-u_mD;M0Pah*96I@P%h6{@AbSAO_QXPzmi*MAO=xS-kfwUdvBgVFX?{O z*oKbUgr84i#XZLBp$>01J)FljxR)E$)Kc5h9_gY=X99G|;kpk#{dkL|`T|l}fgIB^ zfB#}osaw zoPzIg9x8bL4#;^G~fs3cz23a>hJx`(nDImU#mQo zIa+{kWvPI{cIcp~y?5pLP`bK^e9Wz>SlxN25l8JVD?1a!r&qYMIC;3+@K{bzue?Wd zAW9}NIGy!gptdCsRpjeKpY~hlz^$T`iPH5sfa7SAbE)LsGkkfcy8?=ImMq&8xN$U1 zEFxI_oa~sP;U@?KEl;r<+VPoD?}mLm3SOm6hhCcJQdO)$)Cv~2Xe*RNjrI>R8IFgf z$`&{eT`}qR6}kGQ=aVTYOu}iBbmOL;uj>z~2$_hFu~C<2Z=*g;R5=NoOs<7rZ#G~# z-`*L~C0ucB11dCwAy2?#L|5riHWS?HX)O^G@$EjNelLZ%#!U~VZ|pI7q%22dW9=2{q9#`tTv}8&;A`F%2m#lHCxUis@boLlaep%LF^3Iua zHC!jj7e0gFm=&o$7^Cbq%Xt=_glY@-0-2h2#Z|Bl@`pk0EunjzZF;WK7L&SPrZP>!=`PEL$+Axvd9BY4^WW ziMqWv?!Gp_52I=L8z>?yjm+#g6B%uRC>E4QFCT}62JOz&ou$zPC48I+EfH;LtkMw> zA-Mm}*Pe%VLTRC;$^lBeAQfC-oTw^8NL^%sz(omorD$%x%TR-}$2uDYEhDg~i1J`O zqJLY7NlVL0tdaA$l*rEwvt!INLm)Md)bvv}Y)}{dFg*vvQ5?c|!;GX%St)(;0X|dT z66R&~l%^{5a&X@YJ|k`KKwc+V?0K>ilonpF;^qo+gB{Ws{XQvOM^1Ejay-AN+0Id@ zv3WO~oJSIL#oU?vmMFB<{;+GYIQ}$>pFWIE+!UePCBe1?5jWog# z5H=^xSX+#rU}<1w2(m;Ec<+#UvlVBbVuK$J`>}K18{95RiOkh;eBFOXj&YyW2|X?< z??C~{Cw-uxVe+pQJNA*tgX9%Hueag8Ld8t_0(uwxdOi?~g-i=A~qai_eJTZ#&#^WSvQ)Cn4a0gRBXXp`kuy( zCk*slxaj0VLVo5cBxF3OkzCs*30{!z56<|2I#g{!>yzW0pLn{MD43{QB03}dVzAO? z3EldX85$P*>s#jJVEj|PhcwsKJeH-&sr>ELz)2LzD6>;B%Uw#n4VO^fnrY%&Pv}v2 zUOrpu5UUSTvjEZ^qA06m)7)oaedshR&g=@kAvwbSeG`9IorT09IVmWs81Fq5z_a2p z16Gv0Puy7%vD2;;n(SG~!8T;_B^qD)5e-}4IF5w)My||r$yp?I?;n-U3M773x`|ds zA{`SY;;{Tl+r+G&Ynt|5z#+?`_7o{|1D7No%X5pcSK5{@BviU9jT@4hb)qv;@k%JM zy>nM`ffP6-n;G%hs+7uEy{tGXp)3g3XFRf_@HhlK#az4L9u3)$y{gY!SCOFk#p!~l z)tt09)emWX2Z3bqgY){{Gv!7#CpCJ#8VwL`VNhi6qh_;|MMsPW@4m+>redCI4%2(; zKvWy{YT4GJNP>(tZpaCxUypTLp65IZMmGs&Luglc@11i*B8LiY2)CT02J}ih%S&Zu zk7~9H;lobb{60|~yaIfqNqVHziN%&h7<(t&Ezl$dqiha=bENzv?qcRen=`jo$J87> z>LDwiI7AB`pvrz(-XJaDXWC-*W3Z?#jF{oUG)hKhVAP~%s!lT3K{S!hn44?srkyV_ThEEsQhZ6}`jqcc4K+9lG1nIo`@`55{8 z+#!N+_s_rrfR@lN_W?nF@H}@`^Y;WcjbSP=yz8D1HKp@Q-h7_}F;SSc95?T1dU56L z5tI3I%sFmVToGuR-qsKioB3dP$4L{m&Q5M;w#Zroyl%0a?~3HYCo;_U5Kj3tJa?~x z%^&@k9h_9U)@Dt*(%4zL1e*Bz)qJ)wz5Ao}RuR7IsmT=L)QikjySEjvvP zF=I!2chOttUqw`jddP$FUMc7cO)PRkPxX4{a;hY!m$m)T*75BMCk1Qzp_ z86Vh$+4{P>EiUz#3C&0W+<&_76c_66D@U4KnD8rD(&1S=jq*vVTe`2B`rcJOL2ye; zn$YhV%(7q4#^7vmYO0z+yNkx{R4V4=Vt**w@x{I#+fdZYByV`2&g#ks8{p=0xlsK> zoIjf`N0g%E5E5EZN_Q}TuiV#bq@$Ylf=dZX1pbr5&ufKSgyuo8^=YCMkUEP9eu&=c zC?Z}U>>j`d#mxXu!*Of?J22)EEU@!bfFO;sWFINTu*$gHneI74n+%#})1|o6nGv~B z>~a<;%gB|=h5eJ~P5l%M5BSf+%;xxzBn19_uy|LpJM(?B!!~)P#bzsrg6X!%)@?4) zXt}SR_ousuSBKSr3>d%#_cwYq%x)GJs886I^cLjq$yb(ctX*|=dc#_pprQKYTCr57 zg;K5TQYkIz|@=k&bUF}Ji2uIj@q zPt?U?mA$PM9oMDo$FUFZojiyno>C2&JgJu>r8ICYCx?(QfRf2>4@kbup1e5(dT`hs!=i<%Dex;NXWKaZOnE|m^A z$`4MvvG@ZG+tG!;E!zFtIxT$Ai%qo-71u@z8holD=iRCQ! zda^KA`&3v5yKib$d<;iU=pp>xZaS7tG8{A)FP zd}J2~^STgts;v{%Rpz6d^?f=z;CAi&wc^8wi!zDQd0G$2y~RKQZFObiE|@1}A8n1y zVLAYe+Yl-r?naY#v92|8-T>+W<=D>1@Nc30*oLGUmL``XP_a&_i^mb*uLpfGCfs>zITttHYg0#I@YmQ?|~9seusSK>GEu~mZN^UNg9tR=UunDr*v(a8Sn=qWPB2& zxuZ3a%TiZm%G~pq$56g{WOliZ^L+_54*O4PuMg6{+I|p)4jtit_#;D1#wC{<4j;yU z?fuqP`21v7ifNMmQ~b`rS78rEt()ytK5V!GD$NUd-)_!Y?j?6k*%2L{k$u!IpzMKS zw$b#poc)LoE-#Ct*|Eilev5-HP_<ES5_xXo=~)chMie4J~z7YKIPVdfK&*a?3d^KKz*eN+tYUb36j2Y1pS=gL_xTt`)veMhv6 zoNNfg4L7h*byzGqOeDVZeUz!%c~ zRUAhJy48fneOnqR_ZlqymFB*6WKH z%Lr7Os^`76zJI}sv_eSu7>rzSMU7&kdd z{pku|+RJR47tQX$q~Juu-ylzAr;?3YAoDqPV_$ug>>vf+Lec!R`Mtuq> z5ea>NgVkMrGF24HjPiX;RX_Pw5`JX;p%$%6$|O2Ew=QwQU&cJ>)JDX;OUpUpFqfOR zSjL?LyMxYk$=&QyJyCud=Ku4;^F8HO7#9X*ELEh59GbBM!dL(6xnhogGj`5z=Lp(k z5g7Vg`U67md)`{!BxMmjbmu?aM|diE!aO-V+1`oX;ZF@9{4TTVMEPWqO?5`2Ps+4H=o2qm;j4<_xNEak*!G&`A|(&W?jY_sW& z_e!;drwQ`yo6lg8Txdx3XKAbZ2ujg>n>M=_8{Gy@pV{i)O=S;50e`kj5h7(LUn~i` zX)5fzn`SBJfw9Z$rEjtr}!rPzh5#Klz@Yw6wuTlx$=Kig?1jx~&!~%@5Jz9ckaJs2Y|rvU;R!A^3dU z4<(`>G5cD=-Q~?j64+Uum+C=sf~zmr^WTz_!DwyGE6AwXRzw9$IR)+o;YAze1M|_; zQ#5FV2i-I@tluL)6B`g$bAf!m>$!-8-q_TxJ~@>5z7}6=xXwkvPTSF$C7G&Dj_F1p zI-d({TSwc5va&!|o|EF-cSXGhVA zbYedb?mnvlIX%%#C=#~1iL~hv>AbUbvms5^A>%`*(9C#dB})W;I0YRcG;lg^*CVr( zX{~}dQAqekzCkV{#=yLMdLv7@!HX&STMtXM^o_IfcH82wqVz6A7;|gtZ3NOj=-{EZGSb20!qP1l+^d$1gMAs z9I!>KdGt5K!1tjU+sxVNthXOCMVe{0zZ>*E?9gnNijYG+>2?#jW?pu1HXsn`$_=ZR zmwSj*F*#J5$de6hxZL7DtQ-f!kUEwqG3(89EmbXX?#4_FajDHD{!$7@27YfE=SCg|Kc_s*5 z&O56PSy|?vZr~NBSL3nSI?*vFG}|-rqLGc+^_I%2ItZoNT$q=`X93u{Co+c*=7I|f zI`n=NEvvSno|1biQT^4ja0QT`VlB*Wxt>t!e(#(Numc~xrNoOpAo<2S?uO($sK#wN z^@=9l##z_aAOB(-1RWVs9)fayZyfjV_=#YqJ^|k!dF4%{HPZUt=40QXtrAr8y!Lxz~t&22Qvl5gp4&N zt%0-G{Cld>ei>AJH;OhTjEvq1UQ6s%>fn+uL%R}Uuv!n%zVWGB$s{o2RR=MHGP7c2 zdw6n|{jTU3HAtZ?(P%L&s2b!6SRm{W$={oR!tH@A}tcA}E7e4ORM_MzNgI#YR zo;XEO@KJpq?^wkUhB!0d0;;ntTs^8rr(Ty2B428HbWTotopyR{wCQo&YyfH9MTBR7 z*t&YYPSE#7-Y5*VUe!Gt7KbS!#4jJ>ylICa+!@_QQ{1RSA@A|r8qPM9v348TN0~_> z>4GKBRLFxcVqKSjl}cyrk6m~*t#G?fr|1RT>D1bHk`m+ErL}jYF5_Smw-^iVh8EAW zUGq0cJ+I1ipcGBytwgMGM5^|9I{2vncFJZ9&#hI}Q)Bm~Q2e59Rll+(g=VS>HHh{f zX|}NSouQ9c1#boO){rGW%ozq0_|?{$8E>L4G^+Dg?JNFMOhEl zz9^3AF^C+R=w7V{oE3`e_i|y0o5~lwD)cpSh08cc*~@4u&&SeJ2IPsl*Ak_fr{I?t zc{{KTAnHdD+o2Qkpe<`Q?kAT$fNMJMf3P4v4BW%|xR%3?rYaXzy`yMvg>lhB%ZfTy zPd$pb#P3!>Iy|kBA;lQ%jXR;ZDV7O4MC{-K6-zawoKAtkIFapXg+ASElU`zvMU=jnTsWW!e?;XuHxG3cF>vn`OD?bH$|u@;#Fxzpn!`D<3t?kTpM;4-*= zr!!@xCatawU+y1VX4k8?X;3})Hrr1nJa}st+t7@`elD$Jtn9>2-%6=bq-+(4@iEA| zYG{;xE;aoY`U1mR_L0?1dHMb)SH>SJ((SUi|D~?3)Js9tv<+*`S zLsPnE&1I%65ZC#`xM1_oSPj#$)B?N}s;BbipyjO{Mkwe`s;(Ogwi7b3o9n{l4EjRt33gq9U&jsiEP&_)QBtQ_!wSWPdzKJ z|2in8hWQwwmf|VwR2I#G2BJHalBTLWx!z(1*Jum+fafzQ8wv}AJnn&3|Ptjf({KjLq$_g7Zf43scR%9#F8{AMzz9L z)8s8ReG@)bUmpO!s2y~dayk?dwJm3~^s+E=`M79EBae#R;(H!Bn=Ty6W3IfTm{LQR z*#=FW)Sj%W$Zqo1XzVKc>>5&*&ib_=obDLY=6bFTi&X}4;D%7T^fcCf!{D3kc0dML zdwnKfwyVJ&Si+KCu`rS_?IK9|K+FcvaPVNAAblV>6XiHCp!p;3t12`j+-5)JIDC6Z zTi~hy^bMM<3&7k|gnKlcNuz#dW-=1;Ax+*JlsLu&PWi=Q105)r$>8c^7BGL+NPd2Q z@=ly)Y&a@kG?!sQbCGU5omD!yH2=L|p$~KB$B0~?!~I(jri30E=f20`d|0uqd+JqD@kq*Z!GiI}4Ey5VlXDM6}JQnn^je zs%ehj%=sXTM}%Sm=oNci^3OsI<`*`?5}AQ<1rfm!yh8WN`9QVFn{@WWIS%)$-B$A3 zumKTi3hu9^eP8rvMR=sM-rXuQ%_}!YXt9M+j77_ztkAvTrMRdngO8Oa?`r^0N5Eih zQ*(CJSwGpR`~-?tQFzllBLOFH$W3QSCfxSFj_j}PZtZ{Bn> zLZ?bjSmMT&BZ>UL$WTB`;z}{(Y6-?c%36JnzEzMS2kTE;$uN$b;H9w0 zr(}oPPYU2DmlO_Qj%|u3t~#8Qt`9)YYtjYKp5Nq7$1D ziz)ai^TY>0Av7t8_bjpEF#5;?4*>LnmQ+h=IZP|y?HuXtmqaW#ySZc{@h#@Ym0F2FwK>4l_ak(QU36JqW_ zG#f;o3D-6`)JnUY>p)je#h-L38K0!I4YGp5>=4Mi!CJ`TeIr?;1Kl7&&)e({wL~1A zgSC*S*Hg}T=_y-X1!b1LNIFEfevUo?D8W8;*$)ekP)}#I9~IZ#53dh8W_JP!>>2`F z7p|6G^Q4GBIe5Bx)HslpwX2?ok=%PlO~SKe^W7os5fOTcE(XdCm zcE^RL>X&H}y!Ld7$qCRm-)rtrK&op!7hTGFef9a}U|uZMS`;3J2{s^R9MFYkmM?v5 z!?Q$e`6Lef)2Zw1I&J5BfBd^%yrYAqnNgWX>z&-M(T9QFIruXdGtHIHj{6N3a8E9I zyz+fPZF_+M5xg*d{9D-FQw9Fk%XKER^Sxb`2WFG)&0$g0=jRxEOE2)s-(@GKvcx}_ zRsP2)yWVC=Pa(@tuS1NhHH>knxsH=I4D8-Q!Vqzt4QN`hQZ+?H=#?*YRf{Ao|67>0 z>yFGZMj&mxIg2_;M+*0pDm0xjKqYOLD^F;=X~nk&Q>g0;6gCQdWPb>tVu1z-O>tWU zk={ChrC##w{JPKAu`e<-UPCz+-X}3>;}I1)(XWi_fZWX(zUXwpiYH3Uk#BZ`$aF37 zZi{lwI}ZLs#d8_;7;Ka{c*z*?FGv4&rkO&`1^2#Vj_%z2cgMuaDsZk%1IV5c&jY1% zS>BOL@TdjqXC;wPiGkYb_~u?nHzY^UsRtYIb|qHVGOpkCZ9lq-PK_bQ2Jwj*Hw6x< z#w0|A>XU}y?+MmI|BxnXXpF;cy3p$KJY#_J6>;Dq$WO2p2G>ES=mCAG%?RKo<_k5x zx#>r_Ue?g9(6LO*cM$bfHwp*4q(2r3RqkZT4>RdmO%Tg1h-i!~h+qTo7x5Oafa}{p z<#%@rXWiR%MArh19U^XY*0=T(m6khAh^>VhKfZPpe*WNWfbuBWc!W!X)Rk;xnP&e) z>2ZzQLrKp68g9OD9()`hRmW*do^cteJyiNNpPxB+1uh9rkjyQ(`R5i16+Zq!o@rAu zju;Rb-0dJ=CDqZn6hlhUaUZoU&y2L)k2Sf_gA`HHHNpzvl+mF9L&&qJKW%2L|v8YhPTxd=T zxY`;@DfR|pK_BX&fF`gep@5O1$*JoH+2B6}0Na+!f$p!;Ug7&cVFosvRjjDW2+UnOLrcjuc70 zE=5g}(PK4pQgfuQOSi+WxIW_PYeO7eMpSr*qdCsKO~Aqf0HSev&^cTDhdVzvkwA7q zfV3W_(evcSd0h~M_qBO0f4F&zmpH*jL@soj8b!2ZNgVZ4*1gbC@NkJ%)3Qd#Y4@RW z`B3xVK!zYLTyY)oprq^^SieH_YgAe+&0Fm@Z+w3h3rY)W=`T*dH1y3LcaA>cq4QhT zOm4-um=j&4%TLlvLzCs-j)g(KbRG4S`whM(ISw2Z6|-BUV|0eTdav6JrSE6PJd>63 zyxpOa*2jv=oBnFPpOnQiMhLB05mM;cJN-eez`o{izYI{9u9udX-nL?}fJJxuNfPw- z0_H!$&(eZ&E5^V9hR1JsOPp$imZVuPKMT%D$ToG$fBk*qKA>wdnlT`NpuQXGwC-|K zoN007P6JC8R8fO;`>1u3oBVr@-efQ- zM%;Sh=zFR?NU2iwU)JpI7;e?uNK7L|&&>CGKwe-36nMGonC-#-TuSC3#oWG-BzSGK zptMg?k{7Qpc{F~PkIaKA1G)(aVMe4k#OHRhDs_eeAYK@&C_ zKSb7@mqobYkRWW4iS;*n-8Fz2b{uF20mNn z31(aStWQfe>sSWQv1td%Q3BMt`S@`)XdBM5w5nCB;jL~&Ia3#fQ|g$KeIL)5Kc|-i zQmF!znCle^&@=MwhvPhu1Af2hbhQt~C?5J{E&%2M|%01?`-nS?MX@lQWc14U-x5cRQBS2j~ zfH~kTCgEhkF+6xz zF|XhAq3^|7Dcm_a*1n|9^2H;YWAkvpR^NR5jvQjFPV`lRdorLN0Q`l-Rdr9lbdQ%! zR0T1Y2V{1LihDT8Vhg=}3qaxG!&6zmK28T*6!fGZ&<(wP>S@pGw!MU@nf5X@~u?a zX{4R7lPbA|<%jfQ={VpSzH7X)&+5Mj0tX{2^Nlr1%FM15zuCnU+8no-UMZC;gn6 zE>}GVRZ}0jSZa4ASdP21JY`I6@zmNssFgkSx9*aF0Ybq4Zx zbjMx-!9fF6!6p4k}3Q4eM^e07nxpp{a&1<=(i$CFEe$>m~BN5_Z?Uq8qY zAmRl@DCfg%>*G~7lu%vo2mI}ezw4Kw4;zY(SJETB1?Y5I<#V6};Dwzg%mO^ht;20zAd^Wqx)HCKKB^OM0#bcgI(t-k2_Tw(CpjE#szevy zOF6AE1431}l`b65nWK}W1Mq5C3+Q1ZKx9j^ZYRXTPV(51js^3J16@^LaGQQ)A0XIE z1|&z@vKmMm98+1PsRO;b_{t?R`k1O5qUiD70C)dufj*{Ko}eNuL6`H?<$Y6ywxwP_ z;^<~}=IHGhZ1Jz&C7M2NPK@`x^A6xn2h}9t0rwgxk%n*t00FaxvodNGKvS6>_r$t# z9li!=l6bOn#8$8vNt57x2{n#5Jicags4)=r4uwZUJi=H+!UFNB+ZyP_9KE_{Lji@3 zR4i*jEW+XU5NnGhrJzj|N(#96-C07EUE(^hk?Vl_;DjPAJRLe#7U&PZ(t&}y4ECKQ z!E!$!e0Z(}KzoimV0)5e85AMrHJCKDNqQa&AUIHiJIw+;a)0J&0G)C`Lk2>Ne>=U# z^%#^Hs|(~m08~x^&@AiHJ|F3;1Ay1Q-OWSK63#st<%XEo$R z#U>}lbmnLR^tW7ov=NMaEhKu}MtAZ7yfK0_nU@hSE4v0+!oy^E1B&9K7_)4KwJWW92N} z?f9BS+!5)qLTF0~FL#}m6EC;mbSzGTgpH=Hd}B}E3?t8DR)1Y1h=yct%1p{BK=$Ky zK4Ym+hS*=IF+)dAbvTQ!SN=7Aq#+%AFX}PEVfhp2X zJILhEH_>>Zh*bzvdauKfJWh=s^E!D6V?Tfmuzysge5&D1q>3*S`97-8Ey(^4S8L$^ z5CZ|l`aX;J05^1r_r594mhpgZl}>TJ+o9FG?IfMJaJ*w<@VCkgE zY##o!nj0w)z~;#i?(Vpdrrt?rb1I&o67cZOUnaWc3Xn>n7U{(qi~d5O0|7|h0?~QH z4HDmA;P-f3%`{# zBU}3kZW$YYUvev$KUn29{v?vc6wce#UsDk|$rNW*%nwp#p^kiv)OFGG(BJ`q&gLBd zU4ZUuX$6t&0D>j$GI5KcqgD_G!(kY&)?(5wyk(|l;=3ZHz|(Qq^8L>u5=^cqT$wPX zkPs_my92IQkfXw;?vf{cbtZl`QbuUz$Qo!grhA*Wd4YEM`Fb`h+C~TfG$sRr{Ogmm zXqyylJqfR;U0jA)?jXM>THvP6!A4zP$#c-^k?neVY*#K17t;7(JIueYqu7Rci*6{$ zt+(f<;v)g{2xk;lz2l!DJz@OI@tfGQa@JzVzKn|4l<7qYk!d?pJxYO1DtAl# z$BjGcK4o-^pw;ptCGl_%kz8a}Ja^O~MJ(A}jaQUng`c0+gh^9&qy|rNdO+1cf_Q? z3-AbG&nF#kM;BgpWX&=GR=K*k5K-z+Jiwc1bV0;Shl4J!F+QhGt=wgY0sSE|_LC$F z=Nf@(&8>MaRC?0(j2)9T!vy^VKP<6lkGQb3KA)T*V8sw1SAC7bywsR=!bASwBDyL- z|AP`C+-58Xq7LdLzi2Z9HKSS9)Xfwu)us2wA4UI)dgg=KL7yv%TrimLn6!EIY5~aV z-|rcrD=(dx&DPZkjgj>x;dwVmDa39qKZ!WAl#D?g5;scWQS-w#Y{R`boF#SUZr7Vm zj@AycZGh&rgWQlRSuUq(GjcKn!*vHE&hLh@>P~IjFB{gRobKd5_W2#&*QU9?Z$Pj_ zSw_^fRJiO z0#H?}(LjC+L)!Tk06HOjvDFV!1aj1|lpX#EH2B^82dRRDOk#REjC(wJZ4uGOUcX3W zRcf#F^9`YyO>53X?0BSvkBvHEKE>4MTkoHhvZ~0V;bM!fMhYP^gwKi$=A{@cc!I$- zH#iBanD~w9MXda@&6p-Bz(oL-(2?5@2W+i;Q)vOGzXZ@3-lR*CCk6p>{%`|JHPdid z23Z3!ps%tai3#X3{G+Zl?HHY>9Ul&r0i~~oY5;4v$OkkNY5}?T=j=i=(RwWBfS%fH zkgo!V>w7q{1m~<=_(vbb=NuzPn=!21fz2R;VzeaiOOUyn4-3 z{Lp(-~7%3BZw7{H$tb!%MI+ue7Zk^cb zUmX8G)m-^sQro)*aY!w!ZznASP1|PV(5dt$;n1MzmeRsZ&GD2uR+<)C4nUoj=-a~=}4vZT}C#g16!6q(WywN#XxQbD+D^UJ;e!u^TGUi*FD=bfIlHXqhr+~7Z{ zC0q~~ZKzs07e*Sa*PC1h!P((3U!%{Dl9Ji+m4iEB&ePAnb|9{UZ(K}qC4Ipf;vUU5 z)SFDN65=>}{>c#S&2Cnl6&p)7(pCB>KlFU%CU69SI;FR&^|D(Ag9+*3QaboX#U5^$ zx=QdIQjgK7e}9%@%Da0;^7or70f${bMhy9Yua1Ysgq1stdG3)ZcbZ38*TBaI4Ofzm!LMuP3IyUHWvT&7dwnR^bp1`=Ge%v6 z?>T#1N{Z5JR!Z^&R0h030Uc$chJVn!oEKjx2| zn2%yRzc7s6B{oMg14zf$w2~E4&(y6~BU#-Y_$?(+e^C>Kk*7o0!q@W#o@TG-X$hku zhCk$w^xjq6F!51qT;A}At_xGgHwIOrfi>{X6AcM=y*pzrnE~IYD`+j250h&K0}-&I z#28Cb1?1YW9SOsXi%>VVO|7Cd*QvdIW1;O;dEeD!cciitzomjc+_r0HzvU53uZ9gL zJ*MrT{pZQeaC-<{( zKO0id7o^89gs-{YH&2dUiNZ}(5RV=~dbJ2H4(z!n+awhhNf(qlOy+GQrriCUCt11Ud-e(G!a{h#JAJzukNl5EK4q+m)?%L{ zy^pHd0+F@jwd^k@QM*3f!-{KsBQ)+DLY}8JW{22vx7}4(=Rfc z9)l28x=lV580qqIm{Sp;3R9>g9YKc%T1huZyqhdL=E`Utu3sbz_kH#*j{}cCCLVo& z+}jyzG=cyxh5Ev~;!~={dZ2jK`g}o{?6XA2ID5=9p-9#sH<$BdpOD3ca~7B=KuyRe zSCqkh$&Axq3mn@&SuEH!^zqAcd92CP-{RFFT3?Po=ks zo~bEQv1z1Vd7CMU5l%!5-}&&eFn!OEJReo6<`SbW2@}R=pZ?`DW_0q&2F?>7%PIw?lcigd0g^(?3 zODnrKRh`ha#47*Q^~JVM1LyhB?C^At)k9V-9IHZwp&<4tEh?Q>r*5y=`y9l<&uLrr z?;Zk^{3N>}$x`9tWr`rQhW|p!sFP9Lhs^b?(M`@rma5qh<4;H@o{@g}{B1j+FU$QG z>fS(J5>JTMf8DU8%3y9uYdY_91~{6$<8sLEqNs6oyh}`ic%3ygPmnwS3^SccYw=J* z&Uc9kMFyD8n3OH|1~8!*cefe_GFmS=_r=`vzUDuFA5zD_mek2CZiN*UD?LvT?h{^x z@oq65;@{gLz|GjoVo+tyrt@y%ADZ9h`(leSY2%S7@D(OLX`($a9VcI6v&!3_ z+||&93slL=3udoqn^klfhaS1Y?!Z@dAhP@ZT5|`ouclu!bJp)Wyv>IeCEj8indFnNn6`ajf~zd}@m9kiDJ zvSJt|VkLe-dh0Us%QY-jUuu$6UzK`ht6N^R^k z_Y~L7oUg_j4X3a0Q%TgeNpKx5HY8t~sJ;_2%U2B5uAkAvMn%=%cE|{!PLGQt^&Uxo zy<=k?FfVt-<|!JX(MNNOCU7je4vgHYORNkF#MFMmQri7g<835CLM(TpuJSmyZf#P| z47Xe?Ee$g`8D}Ta7G_z+z1-aYW?=qN;rlqb*C!dFb`9Kx8Lr)oaV7myp=0Q$0>6Bc zt?8{uS}RwuUp)`Y)UHrDrF!cAxqUr@T%EMuzo2l~2Q}M3-yx(eOubuPtyRI-@%&PC?Z@DlP zp#kpHRo?0STr_bg=!?K-FWR52=E{pMBoi*ojg1Ih^J)h{3NHVSUe@>ZmEBa&?B;LH zpGxaJLIG$wCp=MnBU!YTE~_}1PD$?ZrGe$dok&48%1`0Jh3P361zz@t*!GwKrfOBO6=FZ2mWj#&V`7VqcgcEOsB$hQWXv1 zO6=Le$CWxm(6(03pw(&Q=`=2nH>f)K)$!U;I;wR<1@#x_<@!`Z;w@aW_65CIKO($W zHSqy`35-1BqK(6>4V^XAw#E0X>LJeIgvr*io|E68$OtqE+NkB3eWc@&LBq2%S7v8i zgj=|&J4-H&rk>?$f*lglu?o$}jslBW9Tfw0S+exJjpWwsB2iGUE3@#uEo%PXn=(O? zw`Vv1STv|glFqWk(mno-^&P3jXp}9hK`qoy%k{k7w$)YsknTn%y6{FYEz7(Vod%SJ z7cRNq!QZ-5ZLUaQ1U%D6JzE9MYoY9^{{76v0u`CgLGgA@?GTO#jMRgzCBKx`oluCI zPRkf0eRoCKN@-)IG+FLoorRq!LxWsV0}vcy4=A)_w^!NnDkC&*L&c@2KF^^!#f29Z zJVl2Rk+N+t%?i_5PvLi^vK^?huixer@yS|a>|lTKIs`hKi>{QZ(K3d4JyyEmX*GR0 zj4Yr5r={4)9S{yT8Mb^(bVLeXqHWM&7lla-SbS8D!|#g;K^4qgRVsjE)=FXs3U(w> z(he1YZ3#^4SMtSuDDd@9#f@@o03uq+x#;2%?F-5>4wr4@O}aLk@n?{m=QkX&tNG(<|2XUxbCq3C z@dR~kC2;Nans>8`8SW46F@%sO%HrVQ^*vQ@Cc-U$rgdybE8#rE^O;VNG3+GaLG_T- z^l1rwUASs#SmvC#!}6!}lz1m%WvM5Jkq(DSjaha2V`A`9GZy%}vHRpei%-G9ub9N; z@qtKAWXkP=OUmSJgAZrW@K}C<^oyctPwXQ_EmR6-_nuiHNfr*|4Q5&WrZl{f=Tn%T z7DmUMX|?8tbDa?o+Ur)A!8TQuFEMW_c%aNrU=$``=i*O=N}|r3dyo^Ny=nONyK3Dz z^XL-@*fHKNczYBLM$x953h<_s@}wjZ?<`d&rD}7u<~B;kA%|k(UPLzsEd&GKzd@Rr zvEh6PJ6BZWBws9e`|p1o;B7p#5Ec7lWr|ZmSK(3NZg47q0v~q!mO!=kUqaAG+{6IaOz{??h&TW268o^pAqCZ2j_wm{BWtMpsN>a6DG0> z`qAeD81StSZ9Fhob`Q7#2H-dv$S)XJMWf2VK%Ea<0E2ce3K0zSZBR5|fD8S9tz^-# Z&v19jjhCU$e literal 0 HcmV?d00001 diff --git a/new_logo/PNG/icon color.png b/new_logo/PNG/icon color.png new file mode 100644 index 0000000000000000000000000000000000000000..94844ac20bb94cf6c9deae8b89018d10280afae6 GIT binary patch literal 10986 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 kAN0Rp_4t3srQVtu)t{-sp4f!{5Bcg6cK`qY literal 0 HcmV?d00001 diff --git a/new_logo/PNG/icon white.png b/new_logo/PNG/icon white.png new file mode 100644 index 0000000000000000000000000000000000000000..f9eb14393e1e9c316ecf2eb754aca909ae19e6ec GIT binary patch literal 8964 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 My2d&AOHXW literal 0 HcmV?d00001 diff --git a/new_logo/PNG/vertical color.png b/new_logo/PNG/vertical color.png new file mode 100644 index 0000000000000000000000000000000000000000..c946a403f4985a09dd6b046c7d76f9358cf30167 GIT binary patch literal 27363 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 literal 0 HcmV?d00001 diff --git a/new_logo/SVG/horizontal color.svg b/new_logo/SVG/horizontal color.svg new file mode 100644 index 0000000..907f8b9 --- /dev/null +++ b/new_logo/SVG/horizontal color.svg @@ -0,0 +1,91 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/new_logo/SVG/horizontal white.svg b/new_logo/SVG/horizontal white.svg new file mode 100644 index 0000000..4f09310 --- /dev/null +++ b/new_logo/SVG/horizontal white.svg @@ -0,0 +1,94 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/new_logo/SVG/icon color.svg b/new_logo/SVG/icon color.svg new file mode 100644 index 0000000..99dfee2 --- /dev/null +++ b/new_logo/SVG/icon color.svg @@ -0,0 +1,82 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/new_logo/SVG/icon white.svg b/new_logo/SVG/icon white.svg new file mode 100644 index 0000000..2abbf19 --- /dev/null +++ b/new_logo/SVG/icon white.svg @@ -0,0 +1,84 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/new_logo/SVG/vertical color.svg b/new_logo/SVG/vertical color.svg new file mode 100644 index 0000000..36140af --- /dev/null +++ b/new_logo/SVG/vertical color.svg @@ -0,0 +1,126 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/new_logo/SVG/vertical white.svg b/new_logo/SVG/vertical white.svg new file mode 100644 index 0000000..e1a3dbd --- /dev/null +++ b/new_logo/SVG/vertical white.svg @@ -0,0 +1,126 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1ea0e91aa77075b8c69c674b22bfc88e39e7368d Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Sat, 8 Jul 2017 10:28:19 +0200 Subject: [PATCH 233/334] Ignore playing of deleted file --- src/qtgui/dockaudio.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index c99a342..71bb527 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -221,12 +221,20 @@ void DockAudio::on_audioRecButton_clicked(bool checked) void DockAudio::on_audioPlayButton_clicked(bool checked) { if (checked) { - // emit signal and start timer - emit audioPlayStarted(last_audio); - - ui->audioRecLabel->setText(QFileInfo(last_audio).fileName()); - ui->audioPlayButton->setToolTip(tr("Stop audio playback")); - ui->audioRecButton->setEnabled(false); // prevent recording while we play + QFileInfo info(last_audio); + + if(info.exists()) { + // emit signal and start timer + emit audioPlayStarted(last_audio); + + ui->audioRecLabel->setText(info.fileName()); + ui->audioPlayButton->setToolTip(tr("Stop audio playback")); + ui->audioRecButton->setEnabled(false); // prevent recording while we play + } + else { + ui->audioPlayButton->setChecked(false); + ui->audioPlayButton->setEnabled(false); + } } else { ui->audioRecLabel->setText("DSP"); From b6d0c751877c62c5409572ea166db8ede05a0ae4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 9 Jul 2017 10:30:01 +0200 Subject: [PATCH 234/334] Update news.txt --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index dabc394..bad51fb 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -10,6 +10,7 @@ FIXED: RDS status is not kept while jumping through bookmark. FIXED: .conf files are deleted when changes are saved. FIXED: Remote control not working if $http_proxy is set. + FIXED: Audio rec does not work after trying to play deleted file. IMPROVED: Tuning through the remote control interface. IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT). IMPROVED: LimeSDR integration. From 75c8ee792034c87136f780309a1806f32396afbb Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 17 Jul 2017 00:02:44 +0200 Subject: [PATCH 235/334] Add dummy QSvgWidget to enforce linking to QtSvg Addresses the issue with QtSvg not being a build time dependency: * https://github.com/csete/gqrx/issues/529 * https://bugs.launchpad.net/ubuntu/+source/gqrx-sdr/+bug/1652531 --- CMakeLists.txt | 2 +- gqrx.pro | 2 +- resources/news.txt | 1 + src/applications/gqrx/mainwindow.cpp | 6 +++++- src/applications/gqrx/mainwindow.h | 4 ++++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 291e609..a94d75c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ endfunction(add_source_files) # 3rd Party Dependency Stuff -find_package(Qt5 COMPONENTS Core Network Widgets REQUIRED) +find_package(Qt5 COMPONENTS Core Network Widgets Svg REQUIRED) find_package(Boost COMPONENTS system program_options REQUIRED) set(GR_REQUIRED_COMPONENTS RUNTIME ANALOG AUDIO BLOCKS DIGITAL FILTER FFT PMT) find_package(Gnuradio REQUIRED) diff --git a/gqrx.pro b/gqrx.pro index 897e91d..a3af1fe 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -10,7 +10,7 @@ # BOOST_SUFFIX=-mt To link against libboost-xyz-mt (needed for pybombs) #-------------------------------------------------------------------------------- -QT += core gui network widgets +QT += core gui network widgets svg lessThan(QT_MAJOR_VERSION,5) { error("Gqrx requires Qt 5.") diff --git a/resources/news.txt b/resources/news.txt index bad51fb..7b3397a 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -11,6 +11,7 @@ FIXED: .conf files are deleted when changes are saved. FIXED: Remote control not working if $http_proxy is set. FIXED: Audio rec does not work after trying to play deleted file. + FIXED: QtSvg dependency. IMPROVED: Tuning through the remote control interface. IMPROVED: Increase narrow band receiver rate to 96 ksps (for APT). IMPROVED: LimeSDR integration. diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 225ca04..6085d51 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include "qtgui/ioconfig.h" #include "mainwindow.h" @@ -315,7 +316,9 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : { configOk = true; } - } + } + + qsvg_dummy = new QSvgWidget(this); } MainWindow::~MainWindow() @@ -370,6 +373,7 @@ MainWindow::~MainWindow() delete [] d_realFftData; delete [] d_iirFftData; delete [] d_pwrFftData; + delete qsvg_dummy; } /** diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index 3d334de..8b82dc1 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "qtgui/dockrxopt.h" #include "qtgui/dockaudio.h" @@ -118,6 +119,9 @@ public slots: std::map devList; + // dummy widget to enforce linking to QtSvg + QSvgWidget *qsvg_dummy; + private: void updateHWFrequencyRange(bool ignore_limits); void updateFrequencyRange(); From 7c3068c27e267048e526b513df5ad87bf5ed41e4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 18 Aug 2017 00:50:45 +0200 Subject: [PATCH 236/334] Add some sample rates for PlutoSDR --- resources/news.txt | 1 + src/qtgui/ioconfig.cpp | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 7b3397a..5c63030 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,6 @@ 2.7: TBD... + NEW: PlutoSDR integration. NEW: Restore filter low cut and high cut between sessions. NEW: Restore FM parameters between sessions. NEW: Restore remote control state between sessions. diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 43bb8d4..9e22554 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -570,6 +570,25 @@ void CIoConfig::updateInputSampleRates(int rate) else ui->inSrCombo->setCurrentIndex(4); // select 5 MHz } + else if (ui->inDevEdit->text().contains("plutosdr")) + { + ui->inSrCombo->addItem("600000"); + ui->inSrCombo->addItem("1000000"); + ui->inSrCombo->addItem("1500000"); + ui->inSrCombo->addItem("2000000"); + ui->inSrCombo->addItem("3000000"); + ui->inSrCombo->addItem("6000000"); + ui->inSrCombo->addItem("16000000"); + ui->inSrCombo->addItem("20000000"); + ui->inSrCombo->addItem("56000000"); + if (rate > 0) + { + ui->inSrCombo->insertItem(0, QString("%1").arg(rate)); + ui->inSrCombo->setCurrentIndex(0); + } + else + ui->inSrCombo->setCurrentIndex(2); // select 2 MHz + } else { if (rate > 0) From 67265103ae10fc5efefa478c402be2f093beeedf Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 19 Aug 2017 01:24:40 +0200 Subject: [PATCH 237/334] Add Airspy HF+ sample rate --- resources/news.txt | 1 + src/qtgui/ioconfig.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 5c63030..40c5a0a 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,6 @@ 2.7: TBD... + NEW: Airspy HF+ integration. NEW: PlutoSDR integration. NEW: Restore filter low cut and high cut between sessions. NEW: Restore FM parameters between sessions. diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 9e22554..2ddc6aa 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -508,6 +508,10 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->addItem("6000000"); ui->inSrCombo->addItem("10000000"); } + else if (ui->inDevEdit->text().contains("airspyhf")) + { + ui->inSrCombo->addItem("768000"); + } else if (ui->inDevEdit->text().contains("redpitaya")) { ui->inSrCombo->addItem("20000"); From 9e68d78c0f7f43842e1fd81d1d6ad8ca35048e89 Mon Sep 17 00:00:00 2001 From: Wolfgang Fritz Date: Sat, 19 Aug 2017 10:17:28 +0200 Subject: [PATCH 238/334] IQ rec/play: Fix navigation in large IQ files Fixed a play navigation error in large IQ files due to integer overflow. Signed-off-by: Wolfgang Fritz --- src/qtgui/iq_tool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qtgui/iq_tool.cpp b/src/qtgui/iq_tool.cpp index e63f6bd..dbb87fc 100644 --- a/src/qtgui/iq_tool.cpp +++ b/src/qtgui/iq_tool.cpp @@ -230,7 +230,7 @@ void CIqTool::on_slider_valueChanged(int value) { refreshTimeWidgets(); - qint64 seek_pos = (qint64)(value*sample_rate); + qint64 seek_pos = (qint64)(value)*sample_rate; emit seek(seek_pos); } From d03175a3004d0a1aefc96088cb48a3d2ad620eef Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 19 Aug 2017 15:29:09 +0200 Subject: [PATCH 239/334] Update version string to 2.7 --- CMakeLists.txt | 8 ++++---- resources/news.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a94d75c..cf370be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,11 @@ cmake_minimum_required(VERSION 2.8.0) # Project name project(gqrx) set(${PROJECT_NAME}_MAJOR "2") -set(${PROJECT_NAME}_MINOR "6") +set(${PROJECT_NAME}_MINOR "7") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -##add_definitions(-DVERSION="${VERSION}") +set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_definitions(-DVERSION="${GITVERSION}") +##add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/resources/news.txt b/resources/news.txt index 40c5a0a..25a2222 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,4 +1,4 @@ - 2.7: TBD... + 2.7: Released August 19, 2017 NEW: Airspy HF+ integration. NEW: PlutoSDR integration. From 0e00f701bf3a0d7d9436fd738a89d5536942525c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 26 Aug 2017 13:23:13 +0200 Subject: [PATCH 240/334] Continue with git vesion --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf370be..7ed189f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "7") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") add_definitions(-DVERSION="${VERSION}") # development version @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -##add_definitions(-DVERSION="${GITVERSION}") +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) From 8f68f7a6fc9affcc2f58b2390d1c0c651ebb5373 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 26 Aug 2017 21:14:23 +0200 Subject: [PATCH 241/334] Add device string hint for PlutoSDR --- src/qtgui/ioconfig.ui | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/qtgui/ioconfig.ui b/src/qtgui/ioconfig.ui index 4c82e66..a330d03 100644 --- a/src/qtgui/ioconfig.ui +++ b/src/qtgui/ioconfig.ui @@ -136,18 +136,7 @@ - <html><head/><body><p>The device argument is a delimited string used to locate devices on your system. Use the device id or name (if applicable) to specify a certain device or list of devices. If left blank, the first device found will be used.</p><p>Examples (some arguments may be optional):</p> -<p> -fcd=0<br/> -rtl=0<br/> -rtl=0,rtl_xtal=28.80001e6,tuner_xtal=26e6,buffers=64 ...<br/> -rtl_tcp=127.0.0.1:1234,psize=16384<br/> -uhd,subdev=A:0,label='USRP1',lo_offset=1500000<br/> -osmosdr=0|name,mcr=64e6,nchan=5,port=/dev/ttyUSB0 ...<br/> -file=/path/to/file.ext,freq=428e6,rate=1e6,repeat=true,throttle=true ... -</p> -<p> -You can test the device strings in gnuradio-companion.</p></body></html> + <html><head/><body><p>The device argument is a delimited string used to locate devices on your system. Use the device id or name (if applicable) to specify a certain device or list of devices. If left blank, the first device found will be used.</p><p>Examples (some arguments may be optional):</p><p>fcd=0<br/>rtl=0<br/>rtl=0,rtl_xtal=28.80001e6,tuner_xtal=26e6,buffers=64 ...<br/>rtl_tcp=127.0.0.1:1234,psize=16384<br/>plutosdr,uri=usb:6.36.5<br/>file=/path/to/file.ext,freq=428e6,rate=1e6,repeat=true,throttle=true ... </p><p>You can test the device strings in gnuradio-companion.</p></body></html> From ccd40cfda9e4585785219198924f765a6da8e8f6 Mon Sep 17 00:00:00 2001 From: Stuart Donnan Date: Sat, 26 Aug 2017 16:02:53 -0500 Subject: [PATCH 242/334] Add LNB_LO command to remote control interface --- resources/remote-control.txt | 3 +++ src/applications/gqrx/mainwindow.cpp | 3 +++ src/applications/gqrx/remote_control.cpp | 33 ++++++++++++++++++++++++ src/applications/gqrx/remote_control.h | 4 +++ src/qtgui/dockinputctl.h | 4 ++- 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/resources/remote-control.txt b/resources/remote-control.txt index 0927644..4e269ba 100644 --- a/resources/remote-control.txt +++ b/resources/remote-control.txt @@ -27,6 +27,9 @@ Supported commands: Acquisition of signal (AOS) event, start audio recording LOS Loss of signal (LOS) event, stop audio recording + LNB_LO [frequency] + If frequency [Hz] is specified set the LNB LO frequency used for + display. Otherwise print the current LNB LO frequency [Hz]. \dump_state Dump state (only usable for hamlib compatibility) v diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 6085d51..427308f 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -186,6 +186,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), uiDockAudio, SLOT(setRxFrequency(qint64))); connect(ui->freqCtrl, SIGNAL(newFrequency(qint64)), uiDockRxOpt, SLOT(setRxFreq(qint64))); connect(uiDockInputCtl, SIGNAL(lnbLoChanged(double)), this, SLOT(setLnbLo(double))); + connect(uiDockInputCtl, SIGNAL(lnbLoChanged(double)), remote, SLOT(setLnbLo(double))); connect(uiDockInputCtl, SIGNAL(gainChanged(QString, double)), this, SLOT(setGain(QString,double))); connect(uiDockInputCtl, SIGNAL(autoGainChanged(bool)), this, SLOT(setAutoGain(bool))); connect(uiDockInputCtl, SIGNAL(freqCorrChanged(double)), this, SLOT(setFreqCorr(double))); @@ -264,6 +265,8 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : connect(remote, SIGNAL(newFilterOffset(qint64)), this, SLOT(setFilterOffset(qint64))); connect(remote, SIGNAL(newFilterOffset(qint64)), uiDockRxOpt, SLOT(setFilterOffset(qint64))); connect(remote, SIGNAL(newFrequency(qint64)), ui->freqCtrl, SLOT(setFrequency(qint64))); + connect(remote, SIGNAL(newLnbLo(double)), uiDockInputCtl, SLOT(setLnbLo(double))); + connect(remote, SIGNAL(newLnbLo(double)), this, SLOT(setLnbLo(double))); connect(remote, SIGNAL(newMode(int)), this, SLOT(selectDemod(int))); connect(remote, SIGNAL(newMode(int)), uiDockRxOpt, SLOT(setCurrentDemod(int))); connect(remote, SIGNAL(newSquelchLevel(double)), this, SLOT(setSqlLevel(double))); diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index 705b661..1d36e36 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -226,6 +226,8 @@ void RemoteControl::startRead() answer = cmd_AOS(); else if (cmd == "LOS") answer = cmd_LOS(); + else if (cmd == "LNB_LO") + answer = cmd_lnb_lo(cmdlist); else if (cmd == "\\dump_state") answer = cmd_dump_state(); else if (cmd == "q" || cmd == "Q") @@ -261,6 +263,14 @@ void RemoteControl::setFilterOffset(qint64 freq) rc_filter_offset = freq; } +/*! \brief Slot called when the LNB LO frequency has changed + * \param freq_mhz new LNB LO frequency in MHz + */ +void RemoteControl::setLnbLo(double freq_mhz) +{ + rc_lnb_lo_mhz = freq_mhz; +} + void RemoteControl::setBandwidth(qint64 bw) { // we want to leave some margin @@ -699,6 +709,29 @@ QString RemoteControl::cmd_LOS() return QString("RPRT 0\n"); } +/* Set the LNB LO value */ +QString RemoteControl::cmd_lnb_lo(QStringList cmdlist) +{ + if(cmdlist.size() == 2) + { + bool ok; + qint64 freq = cmdlist[1].toLongLong(&ok); + + if (ok) + { + rc_lnb_lo_mhz = freq / 1e6; + emit newLnbLo(rc_lnb_lo_mhz); + return QString("RPRT 0\n"); + } + + return QString("RPRT 1\n"); + } + else + { + return QString("%1\n").arg((qint64)(rc_lnb_lo_mhz * 1e6)); + } +} + /* * '\dump_state' used by hamlib clients, e.g. xdx, fldigi, rigctl and etc * More info: diff --git a/src/applications/gqrx/remote_control.h b/src/applications/gqrx/remote_control.h index 1050f8d..0729c13 100644 --- a/src/applications/gqrx/remote_control.h +++ b/src/applications/gqrx/remote_control.h @@ -82,6 +82,7 @@ class RemoteControl : public QObject public slots: void setNewFrequency(qint64 freq); void setFilterOffset(qint64 freq); + void setLnbLo(double freq_mhz); void setBandwidth(qint64 bw); void setSignalLevel(float level); void setMode(int mode); @@ -93,6 +94,7 @@ public slots: signals: void newFrequency(qint64 freq); void newFilterOffset(qint64 offset); + void newLnbLo(double freq_mhz); void newMode(int mode); void newPassband(int passband); void newSquelchLevel(double level); @@ -113,6 +115,7 @@ private slots: qint64 rc_freq; qint64 rc_filter_offset; qint64 bw_half; + double rc_lnb_lo_mhz; /*!< Current LNB LO freq in MHz */ int rc_mode; /*!< Current mode. */ int rc_passband_lo; /*!< Current low cutoff. */ @@ -143,6 +146,7 @@ private slots: QString cmd_get_info() const; QString cmd_AOS(); QString cmd_LOS(); + QString cmd_lnb_lo(QStringList cmdlist); QString cmd_dump_state() const; }; diff --git a/src/qtgui/dockinputctl.h b/src/qtgui/dockinputctl.h index a6974df..1fac067 100644 --- a/src/qtgui/dockinputctl.h +++ b/src/qtgui/dockinputctl.h @@ -70,7 +70,6 @@ class DockInputCtl : public QDockWidget void readSettings(QSettings * settings); void saveSettings(QSettings * settings); - void setLnbLo(double freq_mhz); double lnbLo(); void readLnbLoFromSettings(QSettings * settings); @@ -115,6 +114,9 @@ class DockInputCtl : public QDockWidget void antennaSelected(QString antenna); void freqCtrlResetChanged(bool enabled); +public slots: + void setLnbLo(double freq_mhz); + private slots: void on_lnbSpinBox_valueChanged(double value); void on_agcButton_toggled(bool checked); From ee5f76d1861cb0a0b34fc85fc8a7de48da2ba5f3 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 27 Aug 2017 16:22:40 +0200 Subject: [PATCH 243/334] Update news.txt --- resources/news.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 25a2222..3af0797 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,3 +1,8 @@ + 2.8: Released TBD... + + NEW: Remote control command to set LNB LO (LNB_LO). + + 2.7: Released August 19, 2017 NEW: Airspy HF+ integration. From 965bbd4d7c64883ecd5499093f48e5abe1f80741 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 30 Aug 2017 22:48:48 +0200 Subject: [PATCH 244/334] Avoid redefinition of VERSION --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ed189f..0a5095a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(${PROJECT_NAME}_MINOR "7") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +##add_definitions(-DVERSION="${VERSION}") # development version execute_process( From 82cb67f5aae37a96e50460298b6f14d79d9b1189 Mon Sep 17 00:00:00 2001 From: Petter Gustad Date: Fri, 1 Sep 2017 01:05:05 +0200 Subject: [PATCH 245/334] FindGnuradio-osmosdr.cmake to find include The search is performed on the same path which is included in the source. Also the GNURADIO_OSMOSDR_INCLUDE_DIRS is added to the include directories list. --- CMakeLists.txt | 1 + cmake/Modules/FindGnuradio-osmosdr.cmake | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a5095a..5e4c017 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/include ${Boost_INCLUDE_DIRS} ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${GNURADIO_OSMOSDR_INCLUDE_DIRS} ) link_directories( diff --git a/cmake/Modules/FindGnuradio-osmosdr.cmake b/cmake/Modules/FindGnuradio-osmosdr.cmake index b0f4c43..11bc0c6 100644 --- a/cmake/Modules/FindGnuradio-osmosdr.cmake +++ b/cmake/Modules/FindGnuradio-osmosdr.cmake @@ -3,8 +3,8 @@ PKG_CHECK_MODULES(PC_GNURADIO_OSMOSDR gnuradio-osmosdr) FIND_PATH( GNURADIO_OSMOSDR_INCLUDE_DIRS - NAMES source.h - HINTS $ENV{GNURADIO_OSMOSDR_DIR}/include/osmosdr + NAMES osmosdr/source.h + HINTS $ENV{GNURADIO_OSMOSDR_DIR}/include ${PC_GNURADIO_OSMOSDR_INCLUDEDIR} ${CMAKE_INSTALL_PREFIX}/include/osmosdr PATHS /usr/local/include/osmosdr From 033c02d7b1ddacc50f1e3d5d9fb6cdae44a2e90e Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 3 Sep 2017 20:23:48 +0200 Subject: [PATCH 246/334] Fix inactive Start DSP and Config buttons Thanks @paulrames for heads up. --- src/applications/gqrx/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 427308f..d173e40 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -321,7 +321,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : } } - qsvg_dummy = new QSvgWidget(this); + qsvg_dummy = new QSvgWidget(); } MainWindow::~MainWindow() From 1cec28fb76d8eb13815aafd4d2583f51fa49e42f Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 3 Sep 2017 20:24:08 +0200 Subject: [PATCH 247/334] Update news file --- resources/news.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 3af0797..5978e1c 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,6 +1,8 @@ 2.8: Released TBD... NEW: Remote control command to set LNB LO (LNB_LO). + FIXED: Inactive Start DSP and Config buttins in toolbar. + IMPROVED: Detection of gr-osmosdr when installed in custom directory. 2.7: Released August 19, 2017 From 0a9a4ba9acc2988844d0a9b71bfe528f4c84bf66 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 3 Sep 2017 20:27:41 +0200 Subject: [PATCH 248/334] Fix typo --- resources/news.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 5978e1c..248e764 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,7 +1,7 @@ 2.8: Released TBD... NEW: Remote control command to set LNB LO (LNB_LO). - FIXED: Inactive Start DSP and Config buttins in toolbar. + FIXED: Inactive Start DSP and Config buttons in toolbar. IMPROVED: Detection of gr-osmosdr when installed in custom directory. From d842419c15b4c4527d5da8f40ff8c5ec2837ccf0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 9 Sep 2017 11:57:00 +0200 Subject: [PATCH 249/334] Ensure FreqCtrl digits are drawn after resize --- src/qtgui/freqctrl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index 8d9a7b1..6a75228 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -348,6 +348,7 @@ void CFreqCtrl::resizeEvent(QResizeEvent *) m_Pixmap = QPixmap(size()); // resize pixmap to current control size m_Pixmap.fill(m_BkColor); m_UpdateAll = true; + updateCtrl(true); } void CFreqCtrl::leaveEvent(QEvent *) From 11db1e9aeb540771eae7efcdbcc9881ad01a0718 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 9 Sep 2017 11:57:50 +0200 Subject: [PATCH 250/334] Update news file --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 248e764..294f7d0 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,6 +2,7 @@ NEW: Remote control command to set LNB LO (LNB_LO). FIXED: Inactive Start DSP and Config buttons in toolbar. + FIXED: Frequency controller digit not redrawn after a resize. IMPROVED: Detection of gr-osmosdr when installed in custom directory. From 950996a4787274b491db92a930b0a1637e19ac9d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 16 Sep 2017 21:14:54 +0200 Subject: [PATCH 251/334] Tweak remote frequency handling Fixes issue #471. --- src/applications/gqrx/remote_control.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index 1d36e36..b1d44df 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -303,23 +303,23 @@ void RemoteControl::setPassband(int passband_lo, int passband_hi) void RemoteControl::setNewRemoteFreq(qint64 freq) { qint64 delta = freq - rc_freq; + qint64 bwh_eff = 0.8f * (float)bw_half; rc_filter_offset += delta; - if (((rc_filter_offset > 0) && ((rc_filter_offset + rc_passband_hi) < bw_half)) - || ((rc_filter_offset < 0) && ((rc_filter_offset + rc_passband_lo) > -bw_half))) + if ((rc_filter_offset > 0 && rc_filter_offset + rc_passband_hi < bwh_eff) || + (rc_filter_offset < 0 && rc_filter_offset + rc_passband_lo > -bwh_eff)) { // move filter offset emit newFilterOffset(rc_filter_offset); } else { - // move rx freqeucy and let MainWindow deal with it - // (will usually change hardware PLL) - // reset the filter_offset, otherwise the MainWindow will preserve it + // moving filter offset would push it too close to or beyond the edge + // move it close to the center and adjust hardware freq if (rc_filter_offset < 0) - rc_filter_offset = bw_half - rc_passband_hi; + rc_filter_offset = -0.2f * bwh_eff; else - rc_filter_offset = -bw_half - rc_passband_lo; + rc_filter_offset = 0.2f * bwh_eff; emit newFilterOffset(rc_filter_offset); emit newFrequency(freq); } From 7dbe7c8e68b6dbd72fe86584ce9eda9e5c5daf1c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 16 Sep 2017 21:16:04 +0200 Subject: [PATCH 252/334] Update news.txt --- resources/news.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 294f7d0..6708869 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -4,7 +4,7 @@ FIXED: Inactive Start DSP and Config buttons in toolbar. FIXED: Frequency controller digit not redrawn after a resize. IMPROVED: Detection of gr-osmosdr when installed in custom directory. - + IMPROVED: Remote frequency handling. 2.7: Released August 19, 2017 From c7e9f15ab29c175ac2e367f30acf6b8dd30b7217 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 16 Sep 2017 21:40:18 +0200 Subject: [PATCH 253/334] Set default mode to AM instead of none Fixes issue #435 --- src/qtgui/dockrxopt.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 1a178a5..be8bd2d 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -384,12 +384,13 @@ void DockRxOpt::readSettings(QSettings *settings) if (settings->value("receiver/agc_off", false).toBool()) ui->agcPresetCombo->setCurrentIndex(4); - int_val = settings->value("receiver/demod", 0).toInt(&conv_ok); - if (int_val >= 0) - { - setCurrentDemod(int_val); - emit demodSelected(int_val); - } + int_val = MODE_AM; + if (settings->contains("receiver/demod")) + int_val = settings->value("receiver/demod").toInt(&conv_ok); + + setCurrentDemod(int_val); + emit demodSelected(int_val); + } /** Save receiver configuration to settings. */ From 18d86eac63ecfe79e2ee66a283d16855d0d9b34a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 16 Sep 2017 21:44:10 +0200 Subject: [PATCH 254/334] Update news.txt --- resources/news.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 6708869..5ea5c43 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,8 +1,9 @@ - 2.8: Released TBD... + 2.8: Released September 16, 2017 NEW: Remote control command to set LNB LO (LNB_LO). FIXED: Inactive Start DSP and Config buttons in toolbar. FIXED: Frequency controller digit not redrawn after a resize. + FIXED: Set default mode to AM instead of none. IMPROVED: Detection of gr-osmosdr when installed in custom directory. IMPROVED: Remote frequency handling. From 39084efc0fa9683c5404905006b2e264d0650b93 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 16 Sep 2017 21:52:39 +0200 Subject: [PATCH 255/334] Update version to 2.8 --- CMakeLists.txt | 8 ++++---- gqrx.pro | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e4c017..2f70816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,11 @@ cmake_minimum_required(VERSION 2.8.0) # Project name project(gqrx) set(${PROJECT_NAME}_MAJOR "2") -set(${PROJECT_NAME}_MINOR "7") +set(${PROJECT_NAME}_MINOR "8") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -##add_definitions(-DVERSION="${VERSION}") +set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_definitions(-DVERSION="${GITVERSION}") +##add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index a3af1fe..3d8c86d 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -67,14 +67,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - VER = $$system(git describe --abbrev=8) - ##VER = 2.6 + ##VER = $$system(git describe --abbrev=8) + VER = 2.8 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - VER = $$system(git describe --abbrev=1) - ##VER = 2.6 + ##VER = $$system(git describe --abbrev=1) + VER = 2.8 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 514a08ad5096fba4bf76035f7e9ffbad19f8350c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 16 Sep 2017 21:55:38 +0200 Subject: [PATCH 256/334] Continue with development version string --- CMakeLists.txt | 6 +++--- gqrx.pro | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f70816..6dc8da9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "8") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +##add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -##add_definitions(-DVERSION="${GITVERSION}") +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 3d8c86d..9269bc3 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -67,14 +67,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - ##VER = $$system(git describe --abbrev=8) - VER = 2.8 + VER = $$system(git describe --abbrev=8) + ##VER = 2.8 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - ##VER = $$system(git describe --abbrev=1) - VER = 2.8 + VER = $$system(git describe --abbrev=1) + ##VER = 2.8 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From fd9956e83bbe44a916f0548875d7c3d71944edc5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 17 Oct 2017 17:25:27 +0200 Subject: [PATCH 257/334] Check for Airspy HF+ before R2 or Mini This prevents erroneous detection of Airspy HF+ as R2 or mini. --- src/qtgui/ioconfig.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 2ddc6aa..1a2dafa 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -498,6 +498,11 @@ void CIoConfig::updateInputSampleRates(int rate) else ui->inSrCombo->setCurrentIndex(4); // select 240 kHz } + else if (ui->inDevEdit->text().contains("airspyhf")) + { + ui->inSrCombo->addItem("768000"); + } + // NB: must list airspyhf first else if (ui->inDevEdit->text().contains("airspy")) { if (rate > 0) @@ -508,10 +513,6 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->addItem("6000000"); ui->inSrCombo->addItem("10000000"); } - else if (ui->inDevEdit->text().contains("airspyhf")) - { - ui->inSrCombo->addItem("768000"); - } else if (ui->inDevEdit->text().contains("redpitaya")) { ui->inSrCombo->addItem("20000"); From 0474b9fc0c375ca59cf075772fe6a699304c221b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 00:25:19 +0100 Subject: [PATCH 258/334] Always save list of allowed remote control clients Fixes #563 --- src/applications/gqrx/remote_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index b1d44df..0abe924 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -120,7 +120,7 @@ void RemoteControl::saveSettings(QSettings *settings) const else settings->remove("port"); - if ((rc_allowed_hosts.count() != 1) || (rc_allowed_hosts.at(0) != DEFAULT_RC_ALLOWED_HOSTS)) + if (rc_allowed_hosts.count() > 0) settings->setValue("allowed_hosts", rc_allowed_hosts); else settings->remove("allowed_hosts"); From a9bfa18dc8df69afb19fb0d1db62ee5ab2fe08e7 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 00:29:50 +0100 Subject: [PATCH 259/334] Always save UDP host string, unless it is empty Fixes #559 --- src/qtgui/dockaudio.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index 71bb527..7c27aee 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -327,10 +327,10 @@ void DockAudio::saveSettings(QSettings *settings) else settings->remove("rec_dir"); - if ((udp_host != "localhost") && (udp_host != "127.0.0.1")) - settings->setValue("udp_host", udp_host); - else + if (udp_host.isEmpty()) settings->remove("udp_host"); + else + settings->setValue("udp_host", udp_host); if (udp_port != 7355) settings->setValue("udp_port", udp_port); From a283b1de2b83d4e3800b0b77328ce22d62be160a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 00:41:06 +0100 Subject: [PATCH 260/334] Update news file --- resources/news.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 5ea5c43..658912c 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,3 +1,8 @@ + 2.9: Released November XX, 2017 + + NEW: Airspy HF+ support. + FIXED: Always save TCP and UDP host settings. + 2.8: Released September 16, 2017 NEW: Remote control command to set LNB LO (LNB_LO). From ebb09d84674872ddaca56f13a69e30e529e33cca Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 00:44:44 +0100 Subject: [PATCH 261/334] Use floating point division when calculating bandwidth Fixes CID 33717. --- src/applications/gqrx/remote_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index 0abe924..7eaf670 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -274,7 +274,7 @@ void RemoteControl::setLnbLo(double freq_mhz) void RemoteControl::setBandwidth(qint64 bw) { // we want to leave some margin - bw_half = 0.9 * (bw / 2); + bw_half = (qint64)(0.9f * (bw / 2.f)); } /*! \brief Set signal level in dBFS. */ From c9e271211738743fd0ef7a4ad5fa64cb21c13262 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 00:52:51 +0100 Subject: [PATCH 262/334] Initialize all scalar fields in CAgc Fixes CID 33715 --- src/dsp/agc_impl.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/dsp/agc_impl.cpp b/src/dsp/agc_impl.cpp index 002a10d..e3212f4 100644 --- a/src/dsp/agc_impl.cpp +++ b/src/dsp/agc_impl.cpp @@ -89,6 +89,23 @@ CAgc::CAgc() m_Decay = 0; m_SampleRate = 100.0; m_SigDelayBuf_r = (float*)(&m_SigDelayBuf); + m_ManualAgcGain = 0.f; + m_DecayAve = 0.f; + m_AttackAve = 0.f; + m_AttackRiseAlpha = 0.f; + m_AttackFallAlpha = 0.f; + m_DecayRiseAlpha = 0.f; + m_DecayFallAlpha = 0.f; + m_FixedGain = 0.f; + m_Knee = 0.f; + m_GainSlope = 0.f; + m_Peak = 0.f; + m_SigDelayPtr = 0; + m_MagBufPos = 0; + m_DelaySamples = 0; + m_WindowSamples = 0; + m_HangTime = 0; + m_HangTimer = 0; } CAgc::~CAgc() From 5d401d25a7253c5ac4b46747842447297253b055 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 00:56:12 +0100 Subject: [PATCH 263/334] Initialize program_identification Fixes CID 33708. --- src/dsp/rds/parser_impl.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dsp/rds/parser_impl.cc b/src/dsp/rds/parser_impl.cc index 492ff94..1cb31da 100644 --- a/src/dsp/rds/parser_impl.cc +++ b/src/dsp/rds/parser_impl.cc @@ -53,6 +53,7 @@ void parser_impl::reset() { memset(radiotext, ' ', sizeof(radiotext)); memset(program_service_name, '.', sizeof(program_service_name)); + program_identification = 0; radiotext_AB_flag = 0; traffic_program = false; traffic_announcement = false; From 7c9819cd3ec462b7c9048ef793b7199054d3ff8d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Thu, 9 Nov 2017 01:02:01 +0100 Subject: [PATCH 264/334] Initrialize scalar members in DecoderImpl Fixes CID 33710. --- src/dsp/rds/decoder_impl.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/dsp/rds/decoder_impl.cc b/src/dsp/rds/decoder_impl.cc index a0b065d..70b351f 100644 --- a/src/dsp/rds/decoder_impl.cc +++ b/src/dsp/rds/decoder_impl.cc @@ -36,7 +36,19 @@ decoder_impl::decoder_impl(bool log, bool debug) log(log), debug(debug) { - set_output_multiple(104); // 1 RDS datagroup = 104 bits + bit_counter = 0; + lastseen_offset_counter = 0; + reg = 0; + block_bit_counter = 0; + wrong_blocks_counter = 0; + blocks_counter = 0; + group_good_blocks_counter = 0; + good_block = false; + group_assembly_started = false; + lastseen_offset = 0; + block_number = 0; + + set_output_multiple(104); // 1 RDS datagroup = 104 bits message_port_register_out(pmt::mp("out")); enter_no_sync(); } From 3a9c667f5e1be8d5b11a2851e403af8099183e44 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 10 Nov 2017 00:22:13 +0100 Subject: [PATCH 265/334] Initial all non-static memenbers in remote control interface Fixes CID 33713. --- src/applications/gqrx/remote_control.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index 7eaf670..3727abd 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -38,7 +38,10 @@ RemoteControl::RemoteControl(QObject *parent) : rc_freq = 0; rc_filter_offset = 0; bw_half = 740e3; + rc_lnb_lo_mhz = 0.0; rc_mode = 0; + rc_passband_lo = 0; + rc_passband_hi = 0; signal_level = -200.0; squelch_level = -150.0; audio_recorder_status = false; From 9beec1056a1acb3400e92a58574cae9c97dce3a2 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 10 Nov 2017 22:16:21 +0100 Subject: [PATCH 266/334] Update copyright year --- src/applications/gqrx/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index d173e40..0cae713 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2190,7 +2190,7 @@ void MainWindow::on_actionAbout_triggered() { QMessageBox::about(this, tr("About Gqrx"), tr("

This is Gqrx %1

" - "

Copyright (C) 2011-2016 Alexandru Csete & contributors.

" + "

Copyright (C) 2011-2017 Alexandru Csete & contributors.

" "

Gqrx uses the GrOsmoSDR " From 884d5d9f9f92f2567db395a7c8f4b29562cf02e6 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 10 Nov 2017 22:16:34 +0100 Subject: [PATCH 267/334] Update news file --- resources/news.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 658912c..c7f06c0 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,7 +1,10 @@ - 2.9: Released November XX, 2017 + + 2.9: Released November 11, 2017 NEW: Airspy HF+ support. FIXED: Always save TCP and UDP host settings. + FIXED: Application hangs when pulseaudio server is not running. + 2.8: Released September 16, 2017 @@ -12,6 +15,7 @@ IMPROVED: Detection of gr-osmosdr when installed in custom directory. IMPROVED: Remote frequency handling. + 2.7: Released August 19, 2017 NEW: Airspy HF+ integration. From ad9b582a8ba70d84f75940dc2c45afc8a177c0d0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 10 Nov 2017 22:16:43 +0100 Subject: [PATCH 268/334] Check and report on pulseaudio errors. Fixes #285 - Hangs when pulseaudio is not present. --- src/applications/gqrx/main.cpp | 47 +++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index d10477c..73175b9 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,10 @@ #ifdef WITH_PORTAUDIO #include #endif +#ifdef WITH_PULSEAUDIO +#include +#include +#endif #include "mainwindow.h" #include "gqrx.h" @@ -67,13 +72,6 @@ int main(int argc, char *argv[]) else qDebug() << "Failed to disable controlport"; -#ifdef WITH_PORTAUDIO - PaError err = Pa_Initialize(); - if (err != paNoError) - qCritical() << "Failed to initialize Portaudio backend:" - << Pa_GetErrorText(err); -#endif - // setup the program options po::options_description desc("Command line options"); desc.add_options() @@ -120,6 +118,41 @@ int main(int argc, char *argv[]) return 0; } + // check whether audio backend is functional +#ifdef WITH_PORTAUDIO + PaError err = Pa_Initialize(); + if (err != paNoError) + { + QString message = QString("Portaudio error: %1").arg(Pa_GetErrorText(err)); + qCritical() << message; + QMessageBox::critical(0, "Audio Error", message, + QMessageBox::Abort, QMessageBox::NoButton); + return 1; + } +#endif + +#ifdef WITH_PULSEAUDIO + int error = 0; + pa_simple *test_sink; + pa_sample_spec ss; + + ss.format = PA_SAMPLE_FLOAT32LE; + ss.rate = 48000; + ss.channels = 2; + test_sink = pa_simple_new(NULL, "Gqrx Test", PA_STREAM_PLAYBACK, NULL, + "Test stream", &ss, NULL, NULL, &error); + if (!test_sink) + { + QString message = QString("Pulseaudio error: %1").arg(pa_strerror(error)); + qCritical() << message; + QMessageBox::critical(0, "Audio Error", message, + QMessageBox::Abort, QMessageBox::NoButton); + return 1; + } + pa_simple_free(test_sink); +#endif + + if (!conf.empty()) { cfg_file = QString::fromStdString(conf); From 1503682202ea11afebeccba25d2f345d849e83c2 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 10 Nov 2017 23:07:41 +0100 Subject: [PATCH 269/334] Update version number --- CMakeLists.txt | 8 ++++---- gqrx.pro | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dc8da9..5c97bab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,11 @@ cmake_minimum_required(VERSION 2.8.0) # Project name project(gqrx) set(${PROJECT_NAME}_MAJOR "2") -set(${PROJECT_NAME}_MINOR "8") +set(${PROJECT_NAME}_MINOR "9") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -##add_definitions(-DVERSION="${VERSION}") +set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_definitions(-DVERSION="${GITVERSION}") +##add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 9269bc3..951fb45 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -67,14 +67,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - VER = $$system(git describe --abbrev=8) - ##VER = 2.8 + ##VER = $$system(git describe --abbrev=8) + VER = 2.9 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - VER = $$system(git describe --abbrev=1) - ##VER = 2.8 + ##VER = $$system(git describe --abbrev=1) + VER = 2.9 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 76bf3315f09e701b20b634c47826717b3603c1d2 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 25 Nov 2017 23:32:34 +0100 Subject: [PATCH 270/334] Continue with devel version string --- CMakeLists.txt | 6 +++--- gqrx.pro | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c97bab..731a15f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "9") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +##add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -##add_definitions(-DVERSION="${GITVERSION}") +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 951fb45..bb39c34 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -67,14 +67,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - ##VER = $$system(git describe --abbrev=8) - VER = 2.9 + VER = $$system(git describe --abbrev=8) + ##VER = 2.9 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - ##VER = $$system(git describe --abbrev=1) - VER = 2.9 + VER = $$system(git describe --abbrev=1) + ##VER = 2.9 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From a36123552b83607fe7304c322a1a237ca13c3ef8 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 10 Dec 2017 20:44:28 +0100 Subject: [PATCH 271/334] Remove invalid category Patch from Debian package. --- gqrx.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gqrx.desktop b/gqrx.desktop index 5bd3085..021a206 100644 --- a/gqrx.desktop +++ b/gqrx.desktop @@ -12,5 +12,5 @@ Comment[de]=Software defined Radio auf Basis von GNU Radio und dem Qt GUI Toolki Exec=gqrx Terminal=false Icon=gqrx -Categories=Network;HamRadio;Accessories; +Categories=Network;HamRadio; Keywords=SDR;Radio;HAM; From bab5577b5e09ee2d0ee6f39466107abd95c2b202 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 10 Dec 2017 20:56:29 +0100 Subject: [PATCH 272/334] Add missing header file --- gqrx.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/gqrx.pro b/gqrx.pro index bb39c34..71af524 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -158,6 +158,7 @@ HEADERS += \ src/dsp/rds/decoder_impl.h \ src/dsp/rds/parser_impl.h \ src/dsp/rds/constants.h \ + src/dsp/rds/tmc_events.h \ src/dsp/resampler_xx.h \ src/dsp/rx_agc_xx.h \ src/dsp/rx_demod_am.h \ From 413803805a44c99a6aa56e34d6b48a21cf52d67d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 10 Dec 2017 20:58:04 +0100 Subject: [PATCH 273/334] Fix spelling errors Patch from Debian package. --- resources/news.txt | 2 +- src/dsp/rds/tmc_events.h | 2 +- src/dsp/rx_filter.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index c7f06c0..730abce 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -126,7 +126,7 @@ FIXED: Use correct main category in desktop entry file. IMPROVED: Support up to 1M point FFT. IMPROVED: Fractional PPM correction. - IMPROVED: AGC peformance. + IMPROVED: AGC performance. IMPROVED: FFT performance. IMPROVED: Right click on frequency digit to clear digits. IMPROVED: Robustness against malformed remote control commands. diff --git a/src/dsp/rds/tmc_events.h b/src/dsp/rds/tmc_events.h index c3c86f9..d8ca28a 100644 --- a/src/dsp/rds/tmc_events.h +++ b/src/dsp/rds/tmc_events.h @@ -891,7 +891,7 @@ static const std::string tmc_events[TMC_EVENTS][4]={ {"857","(Q) obstruction(s) on roadway {something that does block the road or part of it}","901","0"}, {"858","(Q) obstructions on the road. Danger","902","0"}, {"859","(Q) obstructions on the road. Passable with care","981","0"}, - {"860","(Q) object(s) on roadway {something that does not neccessarily block the road or part of it} ","61","0"}, + {"860","(Q) object(s) on roadway {something that does not necessarily block the road or part of it} ","61","0"}, {"861","(Q) object(s) on the road. Danger","63","0"}, {"862","(Q) shed load(s)","210","0"}, {"863","(Q) shed load(s). Danger","359","0"}, diff --git a/src/dsp/rx_filter.cpp b/src/dsp/rx_filter.cpp index 8800702..3edd9de 100644 --- a/src/dsp/rx_filter.cpp +++ b/src/dsp/rx_filter.cpp @@ -90,7 +90,7 @@ void rx_filter::set_param(double low, double high, double trans_width) d_trans_width); #ifndef QT_NO_DEBUG_OUTPUT - std::cout << "Genrating taps for new filter LO:" << d_low + std::cout << "Generating taps for new filter LO:" << d_low << " HI:" << d_high << " TW:" << d_trans_width << " Taps: " << d_taps.size() << std::endl; #endif From 903a11318d2c7a793e379f4644e52a68acf574cb Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 2 Jan 2018 00:17:14 +0100 Subject: [PATCH 274/334] Avoid emitting spurious set_freq signals during init Should fix issue #504. --- src/qtgui/dockrxopt.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index be8bd2d..3236330 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -486,7 +486,9 @@ void DockRxOpt::setRxFreq(qint64 freq_hz) void DockRxOpt::setRxFreqRange(qint64 min_hz, qint64 max_hz) { + ui->freqSpinBox->blockSignals(true); ui->freqSpinBox->setRange(1.e-3 * (double)min_hz, 1.e-3 * (double)max_hz); + ui->freqSpinBox->blockSignals(false); } /** From 951dcd7d8da812f3ed0c501066576217719656b8 Mon Sep 17 00:00:00 2001 From: Jeff Long Date: Sun, 31 Dec 2017 17:15:59 -0500 Subject: [PATCH 275/334] sdrplay: fix sample rate list, range is 2M to 10M with 2.048M default --- src/qtgui/ioconfig.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 1a2dafa..41b4e9e 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -531,31 +531,23 @@ void CIoConfig::updateInputSampleRates(int rate) } else if (ui->inDevEdit->text().contains("sdrplay")) { - ui->inSrCombo->addItem("222222"); - ui->inSrCombo->addItem("333333"); - ui->inSrCombo->addItem("428571"); - ui->inSrCombo->addItem("500000"); - ui->inSrCombo->addItem("571429"); - ui->inSrCombo->addItem("750000"); - ui->inSrCombo->addItem("875000"); - ui->inSrCombo->addItem("1000000"); - ui->inSrCombo->addItem("1536000"); + ui->inSrCombo->addItem("2000000"); ui->inSrCombo->addItem("2048000"); + ui->inSrCombo->addItem("3000000"); + ui->inSrCombo->addItem("4000000"); ui->inSrCombo->addItem("5000000"); ui->inSrCombo->addItem("6000000"); ui->inSrCombo->addItem("7000000"); ui->inSrCombo->addItem("8000000"); ui->inSrCombo->addItem("9000000"); ui->inSrCombo->addItem("10000000"); - ui->inSrCombo->addItem("11000000"); - ui->inSrCombo->addItem("12000000"); if (rate > 0) { ui->inSrCombo->insertItem(0, QString("%1").arg(rate)); ui->inSrCombo->setCurrentIndex(0); } else - ui->inSrCombo->setCurrentIndex(9); // select 2048 kHz + ui->inSrCombo->setCurrentIndex(1); // select 2048 kHz } else if (ui->inDevEdit->text().contains("lime")) { From 50c51b9060f2f45cebd2413df16f67d58995c8c5 Mon Sep 17 00:00:00 2001 From: Jeff Long Date: Sun, 31 Dec 2017 17:20:02 -0500 Subject: [PATCH 276/334] sdrplay: clip rate to range 2M-10M --- src/qtgui/ioconfig.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 41b4e9e..3c76417 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -543,6 +543,10 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->addItem("10000000"); if (rate > 0) { + if (rate < 2000000) + rate = 2000000; + if (rate > 10000000) + rate = 10000000; ui->inSrCombo->insertItem(0, QString("%1").arg(rate)); ui->inSrCombo->setCurrentIndex(0); } From b1336d1a91419c11dde5c953447f45ab3a366dd1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Tue, 2 Jan 2018 01:13:34 +0100 Subject: [PATCH 277/334] Update readme and news --- README.md | 145 +++++++++++---------------------------------- resources/news.txt | 7 +++ 2 files changed, 42 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index 5ed20ff..e81589c 100644 --- a/README.md +++ b/README.md @@ -165,120 +165,45 @@ come with a Simplified BSD license. Following people and organisations have contributed to gqrx: -Alex Grinkov: -- FM stereo demodulator. - -Alexander Fasching: -- Bug fixes. - -Andy Sloane: -- Bug fixes and improvements. - -Andrea Merello: -- Cmake build option to build using gr-audio. - -Anthony Willard: -- Various fixes and improvements - -Bastian Bloessl: -Pavel Stano: -- RDS support via gr-rds. - -Chris Kuethe: -- Fractional PPM correction. - -Christian Lindner DL2VCL: -charlylima: -Stefano Leucci: -- Bookmarks implementation. - -Daniil Cherednik: -- FM OIRT stereo. - -Dominic Chen: -- Bug fixes. - -Elias Önal: -- Building Gqrx on Mac OS X. -- Crash recovery dialog. - -Frank Brickle, AB2KT: -Bob McGwier, N4HY: -- Noise blanker (from dttsp). - -Göran Weinholt, SA6CJK: -- Various GUI improvements. - -Grigory Shipunov: -- Initial .desktop file. - -Jiří Pinkava: -- Port to gnuradio 3.7 API. - +Alex Grinkov +Alexander Fasching +Andy Sloane +Andrea Merello +Anthony Willard +Bastian Bloessl +Pavel Stano +Chris Kuethe +Christian Lindner DL2VCL +charlylima +Stefano Leucci +Daniil Cherednik +Dominic Chen +Elias Önal +Frank Brickle, AB2KT +Bob McGwier, N4HY +Göran Weinholt, SA6CJK +Grigory Shipunov +Jiří Pinkava +Jeff Long Josh Blum -- Windows build and MSVC tweaks. - -Kate Adams: -- Auto squelch. - -Kitware Inc.: -- Widgets from the CTK library (http://commontk.org/). - -Michael Dickens: -- Bugfixes and audio on OSX. - -Michael Lass: -- Improved tuning ranges at hardware limits. - -Michael Tatarinov: -- Documentation and bugfixes. - -Moe Weatley: -- FFT plotter and waterfall. -- Frequency selector. -- Signal strength indicator. -- AGC - -Nadeem Hasan: -- Bug fixes. - -Nokia: -- QtColorPicker widget. - -Phil Vachon: -- Bug fixes. - -Rob Frohne: -- Initial Qt5 support. - -Stefano Leucci: -- Peak detection and hold for the FFT plot. - -Timothy Reaves: -- UI layout fixes for Mac. -- cmake build files - -Valentin Ochs: -- ALSA support improvement. -- Various bugfixes. - -Vesa Solonen: -- DC removal in AM demodulator. - +Kate Adams +Kitware Inc. +Michael Dickens +Michael Lass +Michael Tatarinov +Moe Weatley +Nadeem Hasan +Nokia +Phil Vachon +Rob Frohne +Stefano Leucci +Timothy Reaves +Valentin Ochs +Vesa Solonen Vincent Pelletier -- Initial work on the horizontal zooming / scrolling. - Will Scales -- Bug fixes. - Wolfgang Fritz DK7OB -- SDRPlay integration. -- 1-2-5 scaling on FFT plot. -- Various UI improvements. - Youssef Touil -- Two-stage FIR decimator design. -- FIRCalc design tool for optimizing previous input decimator. Some of the icons are from: - The GNOME icon theme CC-SA 3.0 by GNOME icon artists @@ -288,6 +213,6 @@ Some of the icons are from: Also thanks to Volker Schroer and Alexey Bazhin for bringing Funcube Dongle Pro+ support to GNU Radio and Gqrx. -Let me know if somebody or someting is missing from the list! +Let me know if somebody is missing from the list. Alex OZ9AEC diff --git a/resources/news.txt b/resources/news.txt index 730abce..edf35d4 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,4 +1,11 @@ + 2.10: Released TBC... + + FIXED: Crash when starting gqrx using hackrf. + FIXED: Spelling errors. + IMPROVED: Predefined list of sample rates for SDRPlay. + + 2.9: Released November 11, 2017 NEW: Airspy HF+ support. From c8aa21990601c166974f85d5d1d39d57b028a41e Mon Sep 17 00:00:00 2001 From: Jeff Long Date: Tue, 9 Jan 2018 21:14:56 -0500 Subject: [PATCH 278/334] sdrplay: lower min sample rate to 62500 (driver provides decimation) --- src/qtgui/ioconfig.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 3c76417..435d116 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -531,6 +531,11 @@ void CIoConfig::updateInputSampleRates(int rate) } else if (ui->inDevEdit->text().contains("sdrplay")) { + ui->inSrCombo->addItem("62500"); + ui->inSrCombo->addItem("125000"); + ui->inSrCombo->addItem("250000"); + ui->inSrCombo->addItem("500000"); + ui->inSrCombo->addItem("1000000"); ui->inSrCombo->addItem("2000000"); ui->inSrCombo->addItem("2048000"); ui->inSrCombo->addItem("3000000"); @@ -543,8 +548,8 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->addItem("10000000"); if (rate > 0) { - if (rate < 2000000) - rate = 2000000; + if (rate < 62500) + rate = 62500; if (rate > 10000000) rate = 10000000; ui->inSrCombo->insertItem(0, QString("%1").arg(rate)); From f2020f444681e2e74c9cb2c678e900991a319fc9 Mon Sep 17 00:00:00 2001 From: Jeff Long Date: Sat, 13 Jan 2018 07:32:25 -0500 Subject: [PATCH 279/334] sdrplay: make default 2 MS/s --- src/qtgui/ioconfig.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 435d116..62b921d 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -537,7 +537,6 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->addItem("500000"); ui->inSrCombo->addItem("1000000"); ui->inSrCombo->addItem("2000000"); - ui->inSrCombo->addItem("2048000"); ui->inSrCombo->addItem("3000000"); ui->inSrCombo->addItem("4000000"); ui->inSrCombo->addItem("5000000"); @@ -556,7 +555,7 @@ void CIoConfig::updateInputSampleRates(int rate) ui->inSrCombo->setCurrentIndex(0); } else - ui->inSrCombo->setCurrentIndex(1); // select 2048 kHz + ui->inSrCombo->setCurrentIndex(5); // select 2 MHz } else if (ui->inDevEdit->text().contains("lime")) { From 7246556a9a6e2e39015b06478152f96b837e6ac4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 21 Jan 2018 21:05:48 +0100 Subject: [PATCH 280/334] Update news file --- resources/news.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index edf35d4..70dfde1 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,9 +1,9 @@ - 2.10: Released TBC... + 2.10: Released January 21, 2018 FIXED: Crash when starting gqrx using hackrf. FIXED: Spelling errors. - IMPROVED: Predefined list of sample rates for SDRPlay. + IMPROVED: SDRPlay integration. 2.9: Released November 11, 2017 From 84a663ff410cedd7aa6bebcf8ad5a45f95f907a5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 21 Jan 2018 21:37:37 +0100 Subject: [PATCH 281/334] Update version to 2.10 --- CMakeLists.txt | 20 ++++++++++---------- gqrx.pro | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 731a15f..ceacda4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,20 +3,20 @@ cmake_minimum_required(VERSION 2.8.0) # Project name project(gqrx) set(${PROJECT_NAME}_MAJOR "2") -set(${PROJECT_NAME}_MINOR "9") +set(${PROJECT_NAME}_MINOR "10") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -##add_definitions(-DVERSION="${VERSION}") +set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +add_definitions(-DVERSION="${VERSION}") # development version -execute_process( - COMMAND git describe --long --dirty - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GITVERSION - OUTPUT_STRIP_TRAILING_WHITESPACE -) -add_definitions(-DVERSION="${GITVERSION}") +#execute_process( +# COMMAND git describe --long --dirty +# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +# OUTPUT_VARIABLE GITVERSION +# OUTPUT_STRIP_TRAILING_WHITESPACE +#) +#add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 71af524..22a249b 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -67,14 +67,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - VER = $$system(git describe --abbrev=8) - ##VER = 2.9 + ##VER = $$system(git describe --abbrev=8) + VER = 2.10 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - VER = $$system(git describe --abbrev=1) - ##VER = 2.9 + ##VER = $$system(git describe --abbrev=1) + VER = 2.10 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From deedabb29de0de02981ef8923645f32df1c432bc Mon Sep 17 00:00:00 2001 From: Andrea Montefusco IW0HDV Date: Thu, 1 Feb 2018 19:05:48 +0100 Subject: [PATCH 282/334] Microtelecom Perseus intial support added --- src/qtgui/ioconfig.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 62b921d..6e3e39f 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -594,6 +594,26 @@ void CIoConfig::updateInputSampleRates(int rate) else ui->inSrCombo->setCurrentIndex(2); // select 2 MHz } + else if (ui->inDevEdit->text().contains("perseus")) + { + ui->inSrCombo->addItem("48000"); + ui->inSrCombo->addItem("95000"); + ui->inSrCombo->addItem("96000"); + ui->inSrCombo->addItem("125000"); + ui->inSrCombo->addItem("192000"); + ui->inSrCombo->addItem("250000"); + ui->inSrCombo->addItem("500000"); + ui->inSrCombo->addItem("1000000"); + ui->inSrCombo->addItem("1600000"); + ui->inSrCombo->addItem("2000000"); + if (rate > 0) + { + ui->inSrCombo->insertItem(0, QString("%1").arg(rate)); + ui->inSrCombo->setCurrentIndex(0); + } + else + ui->inSrCombo->setCurrentIndex(4); // select 192 kHz + } else { if (rate > 0) From 5de0a298be5c61b0ca91086bf9af203210ba24a4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 3 Feb 2018 11:12:12 +0100 Subject: [PATCH 283/334] Update news and readme --- README.md | 1 + resources/news.txt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index e81589c..ebcfaa1 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ Alex Grinkov Alexander Fasching Andy Sloane Andrea Merello +Andrea Montefusco IW0HDV Anthony Willard Bastian Bloessl Pavel Stano diff --git a/resources/news.txt b/resources/news.txt index 70dfde1..edb2bcc 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,4 +1,9 @@ + 2.11: Released TBD... + + IMPROVED: Microtelecom Perseus integration. + + 2.10: Released January 21, 2018 FIXED: Crash when starting gqrx using hackrf. From 69b0f62dab4ca020b29c5b30280ad80d1cf9d756 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 3 Feb 2018 11:13:16 +0100 Subject: [PATCH 284/334] Continue with development version --- CMakeLists.txt | 18 +++++++++--------- gqrx.pro | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ceacda4..c25ff69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,17 +6,17 @@ set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "10") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +#set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +#add_definitions(-DVERSION="${VERSION}") # development version -#execute_process( -# COMMAND git describe --long --dirty -# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} -# OUTPUT_VARIABLE GITVERSION -# OUTPUT_STRIP_TRAILING_WHITESPACE -#) -#add_definitions(-DVERSION="${GITVERSION}") +execute_process( + COMMAND git describe --long --dirty + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GITVERSION + OUTPUT_STRIP_TRAILING_WHITESPACE +) +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 22a249b..86012b8 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -67,14 +67,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - ##VER = $$system(git describe --abbrev=8) - VER = 2.10 + VER = $$system(git describe --abbrev=8) + ##VER = 2.10 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - ##VER = $$system(git describe --abbrev=1) - VER = 2.10 + VER = $$system(git describe --abbrev=1) + ##VER = 2.10 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 1ff0ff9d4e56aa8f0c34323c519e4c5e19aea03a Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 3 Mar 2018 12:39:40 +0100 Subject: [PATCH 285/334] Update dependencies --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ebcfaa1..86f0eb7 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ To compile gqrx from source you need the following dependencies: - Network - Widgets - Svg (runtime only) +- pkg-config - cmake version >= 3.2.0 if you wish to build using cmake. To build using qmake, you can either open the gqrx.pro file in Qt Creator and From 6ff705450d1782da5a353b97a8ce6d242ad8d290 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Sat, 3 Mar 2018 12:53:38 +0100 Subject: [PATCH 286/334] Check for pkg-config when building with qmake --- gqrx.pro | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gqrx.pro b/gqrx.pro index 86012b8..0e6efdb 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -16,6 +16,11 @@ lessThan(QT_MAJOR_VERSION,5) { error("Gqrx requires Qt 5.") } +PKGCONFIG_EXISTS = $$system(pkg-config --version) +isEmpty(PKGCONFIG_EXISTS) { + error("Gqrx requires pkg-config to build.") +} + TEMPLATE = app macx { From 51c8ccc6ee2875e763614d2a35e2fe725c7eee90 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 5 Mar 2018 20:52:49 +0100 Subject: [PATCH 287/334] Expand allowed FFT window type range --- src/dsp/rx_fft.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dsp/rx_fft.cpp b/src/dsp/rx_fft.cpp index c264e02..c1bf7af 100644 --- a/src/dsp/rx_fft.cpp +++ b/src/dsp/rx_fft.cpp @@ -181,7 +181,7 @@ void rx_fft_c::set_window_type(int wintype) d_wintype = wintype; - if ((d_wintype < gr::filter::firdes::WIN_HAMMING) || (d_wintype > gr::filter::firdes::WIN_BLACKMAN_hARRIS)) + if ((d_wintype < gr::filter::firdes::WIN_HAMMING) || (d_wintype > gr::filter::firdes::WIN_FLATTOP)) { d_wintype = gr::filter::firdes::WIN_HAMMING; } @@ -354,7 +354,7 @@ void rx_fft_f::set_window_type(int wintype) d_wintype = wintype; - if ((d_wintype < gr::filter::firdes::WIN_HAMMING) || (d_wintype > gr::filter::firdes::WIN_BLACKMAN_hARRIS)) + if ((d_wintype < gr::filter::firdes::WIN_HAMMING) || (d_wintype > gr::filter::firdes::WIN_FLATTOP)) { d_wintype = gr::filter::firdes::WIN_HAMMING; } From 033c7f4322fe36155812eb113396ac68ae1a3b80 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 5 Mar 2018 20:55:31 +0100 Subject: [PATCH 288/334] Make some functions const --- src/dsp/rx_fft.cpp | 8 ++++---- src/dsp/rx_fft.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dsp/rx_fft.cpp b/src/dsp/rx_fft.cpp index c1bf7af..14ad569 100644 --- a/src/dsp/rx_fft.cpp +++ b/src/dsp/rx_fft.cpp @@ -165,7 +165,7 @@ void rx_fft_c::set_fft_size(unsigned int fftsize) } /*! \brief Get currently used FFT size. */ -unsigned int rx_fft_c::get_fft_size() +unsigned int rx_fft_c::get_fft_size() const { return d_fftsize; } @@ -191,7 +191,7 @@ void rx_fft_c::set_window_type(int wintype) } /*! \brief Get currently used window type. */ -int rx_fft_c::get_window_type() +int rx_fft_c::get_window_type() const { return d_wintype; } @@ -338,7 +338,7 @@ void rx_fft_f::set_fft_size(unsigned int fftsize) } /*! \brief Get currently used FFT size. */ -unsigned int rx_fft_f::get_fft_size() +unsigned int rx_fft_f::get_fft_size() const { return d_fftsize; } @@ -364,7 +364,7 @@ void rx_fft_f::set_window_type(int wintype) } /*! \brief Get currently used window type. */ -int rx_fft_f::get_window_type() +int rx_fft_f::get_window_type() const { return d_wintype; } diff --git a/src/dsp/rx_fft.h b/src/dsp/rx_fft.h index 8d99cc0..75c8d87 100644 --- a/src/dsp/rx_fft.h +++ b/src/dsp/rx_fft.h @@ -80,10 +80,10 @@ class rx_fft_c : public gr::sync_block void get_fft_data(std::complex* fftPoints, unsigned int &fftSize); void set_window_type(int wintype); - int get_window_type(); + int get_window_type() const; void set_fft_size(unsigned int fftsize); - unsigned int get_fft_size(); + unsigned int get_fft_size() const; private: unsigned int d_fftsize; /*! Current FFT size. */ @@ -142,10 +142,10 @@ class rx_fft_f : public gr::sync_block void get_fft_data(std::complex* fftPoints, unsigned int &fftSize); void set_window_type(int wintype); - int get_window_type(); + int get_window_type() const; void set_fft_size(unsigned int fftsize); - unsigned int get_fft_size(); + unsigned int get_fft_size() const; private: unsigned int d_fftsize; /*! Current FFT size. */ From d3482423cf56051239a220746c1a9573709818b5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 5 Mar 2018 21:14:41 +0100 Subject: [PATCH 289/334] Implement selectable IQ FFT window type --- resources/news.txt | 2 + src/applications/gqrx/mainwindow.cpp | 6 ++ src/applications/gqrx/mainwindow.h | 1 + src/applications/gqrx/receiver.cpp | 9 ++- src/applications/gqrx/receiver.h | 1 + src/qtgui/dockfft.cpp | 15 ++++ src/qtgui/dockfft.h | 2 + src/qtgui/dockfft.ui | 108 +++++++++++++++++++++------ 8 files changed, 118 insertions(+), 26 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index edb2bcc..746c1f2 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,6 +1,8 @@ 2.11: Released TBD... + NEW: Selectable IQ FFT window type. + IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Microtelecom Perseus integration. diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 0cae713..4b2ad66 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -226,6 +226,7 @@ MainWindow::MainWindow(const QString cfgfile, bool edit_conf, QWidget *parent) : connect(uiDockAudio, SIGNAL(fftRateChanged(int)), this, SLOT(setAudioFftRate(int))); connect(uiDockFft, SIGNAL(fftSizeChanged(int)), this, SLOT(setIqFftSize(int))); connect(uiDockFft, SIGNAL(fftRateChanged(int)), this, SLOT(setIqFftRate(int))); + connect(uiDockFft, SIGNAL(fftWindowChanged(int)), this, SLOT(setIqFftWindow(int))); connect(uiDockFft, SIGNAL(wfSpanChanged(quint64)), this, SLOT(setWfTimeSpan(quint64))); connect(uiDockFft, SIGNAL(fftSplitChanged(int)), this, SLOT(setIqFftSplit(int))); connect(uiDockFft, SIGNAL(fftAvgChanged(float)), this, SLOT(setIqFftAvg(float))); @@ -1603,6 +1604,11 @@ void MainWindow::setIqFftRate(int fps) iq_fft_timer->setInterval(interval); } +void MainWindow::setIqFftWindow(int type) +{ + rx->set_iq_fft_window(type); +} + /** Waterfall time span has changed. */ void MainWindow::setWfTimeSpan(quint64 span_ms) { diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index 8b82dc1..087cfd3 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -181,6 +181,7 @@ private slots: /* FFT settings */ void setIqFftSize(int size); void setIqFftRate(int fps); + void setIqFftWindow(int type); void setIqFftSplit(int pct_wf); void setIqFftAvg(float avg); void setAudioFftRate(int fps); diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 4c5fcbb..361be52 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -123,9 +123,9 @@ receiver::receiver(const std::string input_device, iq_swap = make_iq_swap_cc(false); dc_corr = make_dc_corr_cc(d_quad_rate, 1.0); - iq_fft = make_rx_fft_c(8192u, 0); + iq_fft = make_rx_fft_c(8192u, gr::filter::firdes::WIN_HANN); - audio_fft = make_rx_fft_f(8192u); + audio_fft = make_rx_fft_f(8192u, gr::filter::firdes::WIN_HANN); audio_gain0 = gr::blocks::multiply_const_ff::make(0.1); audio_gain1 = gr::blocks::multiply_const_ff::make(0.1); @@ -725,6 +725,11 @@ void receiver::set_iq_fft_size(int newsize) iq_fft->set_fft_size(newsize); } +void receiver::set_iq_fft_window(int window_type) +{ + iq_fft->set_window_type(window_type); +} + /** Get latest baseband FFT data. */ void receiver::get_iq_fft_data(std::complex* fftPoints, unsigned int &fftsize) { diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index a95af5c..f86d741 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -159,6 +159,7 @@ class receiver status set_freq_corr(double ppm); float get_signal_pwr(bool dbfs) const; void set_iq_fft_size(int newsize); + void set_iq_fft_window(int window_type); void get_iq_fft_data(std::complex* fftPoints, unsigned int &fftsize); void get_audio_fft_data(std::complex* fftPoints, diff --git a/src/qtgui/dockfft.cpp b/src/qtgui/dockfft.cpp index a26acb3..8430334 100644 --- a/src/qtgui/dockfft.cpp +++ b/src/qtgui/dockfft.cpp @@ -31,6 +31,7 @@ #define DEFAULT_FFT_MIN_DB -135 #define DEFAULT_FFT_RATE 25 #define DEFAULT_FFT_SIZE 8192 +#define DEFAULT_FFT_WINDOW 1 // Hann #define DEFAULT_FFT_SPLIT 35 #define DEFAULT_FFT_AVG 75 @@ -200,6 +201,12 @@ void DockFft::saveSettings(QSettings *settings) else settings->remove("fft_rate"); + intval = ui->fftWinComboBox->currentIndex(); + if (intval != DEFAULT_FFT_WINDOW) + settings->setValue("fft_window", intval); + else + settings->remove("fft_window"); + if (ui->fftAvgSlider->value() != DEFAULT_FFT_AVG) settings->setValue("averaging", ui->fftAvgSlider->value()); else @@ -277,6 +284,10 @@ void DockFft::readSettings(QSettings *settings) if (conv_ok) setFftSize(intval); + intval = settings->value("fft_window", DEFAULT_FFT_WINDOW).toInt(&conv_ok); + if (conv_ok) + ui->fftWinComboBox->setCurrentIndex(intval); + intval = settings->value("averaging", DEFAULT_FFT_AVG).toInt(&conv_ok); if (conv_ok) ui->fftAvgSlider->setValue(intval); @@ -360,6 +371,10 @@ void DockFft::on_fftRateComboBox_currentIndexChanged(const QString & text) updateInfoLabels(); } +void DockFft::on_fftWinComboBox_currentIndexChanged(int index) +{ + emit fftWindowChanged(index); +} static const quint64 wf_span_table[] = { diff --git a/src/qtgui/dockfft.h b/src/qtgui/dockfft.h index 37b49bc..85f0123 100644 --- a/src/qtgui/dockfft.h +++ b/src/qtgui/dockfft.h @@ -53,6 +53,7 @@ class DockFft : public QDockWidget signals: void fftSizeChanged(int size); /*! FFT size changed. */ void fftRateChanged(int fps); /*! FFT rate changed. */ + void fftWindowChanged(int window); /*! FFT window type changed */ void wfSpanChanged(quint64 span_ms); /*! Waterfall span changed. */ void fftSplitChanged(int pct); /*! Split between pandapter and waterfall changed. */ void fftZoomChanged(float level); /*! Zoom level slider changed. */ @@ -76,6 +77,7 @@ public slots: private slots: void on_fftSizeComboBox_currentIndexChanged(const QString & text); void on_fftRateComboBox_currentIndexChanged(const QString & text); + void on_fftWinComboBox_currentIndexChanged(int index); void on_wfSpanComboBox_currentIndexChanged(int index); void on_fftSplitSlider_valueChanged(int value); void on_fftAvgSlider_valueChanged(int value); diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index e47fd6f..21f07ee 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -6,8 +6,8 @@ 0 0 - 320 - 386 + 288 + 416 @@ -83,8 +83,8 @@ 0 0 - 310 - 357 + 278 + 387 @@ -123,7 +123,7 @@ 6 - + @@ -154,7 +154,7 @@ - + @@ -176,7 +176,7 @@ - + 2 @@ -264,7 +264,7 @@ - + @@ -280,7 +280,7 @@ - + @@ -336,7 +336,7 @@ - + Set zoom level on the frequency axis @@ -352,7 +352,7 @@ - + @@ -386,7 +386,7 @@ - + Color for the FFT plot @@ -399,7 +399,7 @@ - + @@ -532,7 +532,7 @@ - + Set pandapter dB range @@ -548,7 +548,7 @@ - + @@ -564,7 +564,7 @@ - + @@ -596,7 +596,7 @@ - + Set waterfall dB range @@ -793,7 +793,7 @@ - + 2 @@ -884,7 +884,7 @@ - + @@ -918,7 +918,7 @@ - + Peak @@ -938,7 +938,7 @@ - + Set waterfall dB range @@ -967,7 +967,7 @@ - + @@ -998,7 +998,7 @@ - + Qt::Vertical @@ -1011,7 +1011,7 @@ - + true @@ -1042,6 +1042,66 @@ + + + + FFT window + + + Window + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + FFT window + + + + Hamming + + + + + Hann + + + + + Blackman + + + + + Rectangular + + + + + Kaiser + + + + + Blackman-Harris + + + + + Bartlett + + + + + Flattop + + + + From 7d0841e73329466107639627950e35fd815e72e0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 14 Mar 2018 00:19:45 +0100 Subject: [PATCH 290/334] Add portaudio to cmake info --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c25ff69..2ccb193 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(NOT LINUX_AUDIO_BACKEND) - set(LINUX_AUDIO_BACKEND Pulseaudio CACHE STRING "Choose the audio backend, options are: Pulseaudio, Gr-audio" FORCE) + set(LINUX_AUDIO_BACKEND Pulseaudio CACHE STRING "Choose the audio backend, options are: Pulseaudio, Portaudio, Gr-audio" FORCE) endif() if(${LINUX_AUDIO_BACKEND} MATCHES "Pulseaudio") From 7556b3b586220b97590ab613ac72882564945c83 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 14 Mar 2018 00:37:00 +0100 Subject: [PATCH 291/334] Add option to build with Portaudio on Mac OS X NB: Automatic detection of Funcube Dongle Pro and Pro+ is disabled. --- CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ src/CMakeLists.txt | 6 +++++- src/qtgui/ioconfig.cpp | 5 +++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ccb193..f7706d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,6 +145,36 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif() endif() +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + if(NOT OSX_AUDIO_BACKEND) + set(OSX_AUDIO_BACKEND Portaudio CACHE STRING "Choose the audio backend, options are: Portaudio and Gr-audio" FORCE) + endif() + + if(${OSX_AUDIO_BACKEND} MATCHES "Portaudio") + find_package(Portaudio REQUIRED) + add_definitions(-DWITH_PORTAUDIO) + unset(PULSEAUDIO_FOUND CACHE) + unset(PULSEAUDIO_INCLUDE_DIR CACHE) + unset(PULSEAUDIO_LIBRARY CACHE) + unset(PulseAudio_DIR CACHE) + unset(PULSE-SIMPLE CACHE) + unset(PULSEAUDIO_INCLUDE_DIR CACHE) + unset(PULSEAUDIO_MAINLOOP_LIBRARY CACHE) + elseif(${OSX_AUDIO_BACKEND} MATCHES "Gr-audio") + unset(PULSEAUDIO_FOUND CACHE) + unset(PULSEAUDIO_INCLUDE_DIR CACHE) + unset(PULSEAUDIO_LIBRARY CACHE) + unset(PulseAudio_DIR CACHE) + unset(PULSE-SIMPLE CACHE) + unset(PULSEAUDIO_INCLUDE_DIR CACHE) + unset(PULSEAUDIO_MAINLOOP_LIBRARY CACHE) + unset(PORTAUDIO_INCLUDE_DIRS CACHE) + unset(PORTAUDIO_LIBRARIES CACHE) + else() + message(FATAL_ERROR "Invalid audio backend: should be either Portaudio or Gr-audio") + endif() +endif() + # Airspy optimizations that require modified gr-osmosdr option(CUSTOM_AIRSPY_KERNELS "Enable non-standard Airspy optimizations" ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c707f11..6c0cbd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,11 @@ add_subdirectory(qtgui) add_subdirectory(receivers) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_subdirectory(osxaudio) + if(${OSX_AUDIO_BACKEND} MATCHES "Portaudio") + add_subdirectory(portaudio) + else() + add_subdirectory(osxaudio) + endif() add_definitions(-DGQRX_OS_MACX) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9) elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 6e3e39f..e0a13bf 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -197,7 +197,8 @@ void CIoConfig::getDeviceList(std::map &devList) QString devstr; QString devlabel; -#if defined(GQRX_OS_MACX) +#if 0 +//#if defined(GQRX_OS_MACX) // automatic discovery of FCD does not work on Mac // so we do it ourselves osxaudio_device_list devices; @@ -266,7 +267,7 @@ void CIoConfig::saveConfig() idx = ui->outDevCombo->currentIndex(); -#if defined(WITH_PULSEAUDIO) || defined(GQRX_OS_MACX) +#if defined(WITH_PULSEAUDIO) || defined(WITH_PORTAUDIO) || defined(GQRX_OS_MACX) if (idx > 0) { qDebug() << "Output device" << idx << ":" << QString(outDevList[idx-1].get_name().c_str()); From 81cd7959cb55849ef7133c9bda76734799658ae0 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 16 Mar 2018 00:04:48 +0100 Subject: [PATCH 292/334] Re-enable Funcube Dongle detection on Mac --- src/qtgui/ioconfig.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index e0a13bf..6fd516c 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -193,17 +193,20 @@ CIoConfig::~CIoConfig() */ void CIoConfig::getDeviceList(std::map &devList) { - unsigned int i=0; - QString devstr; - QString devlabel; + unsigned int i; + QString devstr; + QString devlabel; -#if 0 -//#if defined(GQRX_OS_MACX) // automatic discovery of FCD does not work on Mac // so we do it ourselves - osxaudio_device_list devices; - vector inDevList = devices.get_input_devices(); - +#if defined(GQRX_OS_MACX) +#ifdef WITH_PORTAUDIO + portaudio_device_list devices; + vector inDevList = devices.get_input_devices(); +#else + osxaudio_device_list devices; + vector inDevList = devices.get_input_devices(); +#endif string this_dev; for (i = 0; i < inDevList.size(); i++) { From 769c0f760c00457f06131a92a8a3ba49522fc066 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 16 Mar 2018 01:09:45 +0100 Subject: [PATCH 293/334] Update news file --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 746c1f2..7b51cf8 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,6 +2,7 @@ 2.11: Released TBD... NEW: Selectable IQ FFT window type. + FIXED: Problems on Mac Pro computers without built-in audio IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Microtelecom Perseus integration. From 6d43356a1f1f80e2abccb1097613d8e26dfaf81e Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 00:35:36 +0100 Subject: [PATCH 294/334] Show path when using -l and --list Issue #577. --- src/applications/gqrx/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index 73175b9..19cd2c0 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -229,7 +229,10 @@ static void list_conf(void) QDir conf_dir = QDir(conf_path, "*.conf", QDir::Name, QDir::Files); QStringList conf_files = conf_dir.entryList(QStringList("*.conf")); - std::cout << " Existing configuration files:" << std::endl; + std::cout << std::endl + << " Existing configuration files in " + << conf_path.toStdString() + << std::endl; if (conf_files.isEmpty()) { From 6de6a246c8ab2332971ac5c41c4e2d2ec530da25 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 00:55:58 +0100 Subject: [PATCH 295/334] Fix black on black tooltips in the main window Issue #512. --- src/applications/gqrx/mainwindow.ui | 225 +++++++++++++++------------- 1 file changed, 124 insertions(+), 101 deletions(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index 66f077e..c3c18e4 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 950 - 600 + 702 @@ -27,18 +27,15 @@ true - - background-color: rgb(31, 29, 29); - - 10 + 0 0 - 10 + 0 0 @@ -47,103 +44,126 @@ 0 - - - 10 + + + + 0 + 0 + - - 20 + + background-color: rgb(31, 29, 29); - - 10 + + QFrame::StyledPanel - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 371 - 41 - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 171 - 41 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + QFrame::Raised + + + + 10 + + + 20 + + + 10 + + + 10 + + + 10 + + + + + Qt::Horizontal + + + + 109 + 17 + + + + + + + + + 0 + 0 + + + + + 371 + 41 + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 109 + 17 + + + + + + + + + 0 + 0 + + + + + 171 + 41 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 109 + 17 + + + + + + @@ -153,6 +173,9 @@ 0 + + true + QFrame::StyledPanel @@ -169,7 +192,7 @@ 0 0 950 - 20 + 19 From b67ff6737b95f7ddcca78821e76d21142677a841 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 00:56:51 +0100 Subject: [PATCH 296/334] Update news file --- resources/news.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 7b51cf8..805f4de 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,9 +2,13 @@ 2.11: Released TBD... NEW: Selectable IQ FFT window type. - FIXED: Problems on Mac Pro computers without built-in audio + FIXED: Problems on Mac Pro computers without built-in audio. + FIXED: Black on black tooltips in the main window. IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Microtelecom Perseus integration. + IMPROVED: Implemented PPM correction for RF Space Cloud IQ (gr-osmosdr-gqrx) + IMPORVED: Implemented PPM correction for PlutoSDR (gr-osmosdr-gqrx) + IMPROVED: Show configuration file path when listing config files using -l 2.10: Released January 21, 2018 From 38257e74112f3bc0dde42a4760b24f6d49addbfb Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 01:15:46 +0100 Subject: [PATCH 297/334] Avoid auto squelch setting 0 dBFS Issue #520. --- src/applications/gqrx/mainwindow.cpp | 3 +++ src/qtgui/dockrxopt.cpp | 5 +++++ src/qtgui/dockrxopt.h | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 4b2ad66..4561d50 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1228,6 +1228,9 @@ void MainWindow::setSqlLevel(double level_db) double MainWindow::setSqlLevelAuto() { double level = rx->get_signal_pwr(true) + 1.0; + if (level > -90.0) // avoid 0 dBFS + level = uiDockRxOpt->getSqlLevel(); + setSqlLevel(level); return level; } diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 3236330..9a77751 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -287,6 +287,11 @@ void DockRxOpt::setSquelchLevel(double level) ui->sqlSpinBox->setValue(level); } +double DockRxOpt::getSqlLevel(void) const +{ + return ui->sqlSpinBox->value(); +} + /** * @brief Get the current squelch level * @returns The current squelch setting in dBFS diff --git a/src/qtgui/dockrxopt.h b/src/qtgui/dockrxopt.h index 4255365..6146305 100644 --- a/src/qtgui/dockrxopt.h +++ b/src/qtgui/dockrxopt.h @@ -106,6 +106,8 @@ class DockRxOpt : public QDockWidget void getFilterPreset(int mode, int preset, int * lo, int * hi) const; int getCwOffset() const; + double getSqlLevel(void) const; + static QStringList ModulationStrings; static QString GetStringForModulationIndex(int iModulationIndex); static int GetEnumForModulationString(QString param); From f6ba80bee05fd3dfe9f9a4fcdd8ff1b10d73e86b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 01:17:20 +0100 Subject: [PATCH 298/334] Update news file --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 805f4de..68e3605 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -4,6 +4,7 @@ NEW: Selectable IQ FFT window type. FIXED: Problems on Mac Pro computers without built-in audio. FIXED: Black on black tooltips in the main window. + FIXED: Auto-squelch sets 0 dBFS too often. IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Microtelecom Perseus integration. IMPROVED: Implemented PPM correction for RF Space Cloud IQ (gr-osmosdr-gqrx) From 81047b85efbf983550326e97ad3ff84464896bd4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 01:39:51 +0100 Subject: [PATCH 299/334] Fix I/Q files replay when path contains spaces Issue #584. --- resources/news.txt | 1 + src/applications/gqrx/mainwindow.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 68e3605..03113d8 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -5,6 +5,7 @@ FIXED: Problems on Mac Pro computers without built-in audio. FIXED: Black on black tooltips in the main window. FIXED: Auto-squelch sets 0 dBFS too often. + FIXED: Can not play I/Q files if path contains a space. IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Microtelecom Perseus integration. IMPROVED: Implemented PPM correction for RF Space Cloud IQ (gr-osmosdr-gqrx) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 4561d50..2fd20f6 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1496,7 +1496,7 @@ void MainWindow::startIqPlayback(const QString filename, float samprate) storeSession(); int sri = (int)samprate; - QString devstr = QString("file=%1,rate=%2,throttle=true,repeat=false") + QString devstr = QString("file='%1',rate=%2,throttle=true,repeat=false") .arg(filename).arg(sri); qDebug() << __func__ << ":" << devstr; From e85e7b43ffc4c53d0faf5704fb3c7f7d5cd67b12 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 11:33:40 +0100 Subject: [PATCH 300/334] Restore gains to slider states when AGC is disabled Issue #587. --- resources/news.txt | 1 + src/applications/gqrx/mainwindow.cpp | 5 +--- src/qtgui/dockinputctl.cpp | 36 ++++++++++------------------ src/qtgui/dockinputctl.h | 2 +- 4 files changed, 16 insertions(+), 28 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index 03113d8..cb8d835 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -6,6 +6,7 @@ FIXED: Black on black tooltips in the main window. FIXED: Auto-squelch sets 0 dBFS too often. FIXED: Can not play I/Q files if path contains a space. + FIXED: Restore gains to slider states when hardware AGC is disabled IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Microtelecom Perseus integration. IMPROVED: Implemented PPM correction for RF Space Cloud IQ (gr-osmosdr-gqrx) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 2fd20f6..c37e1b6 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -879,11 +879,8 @@ void MainWindow::setGain(QString name, double gain) void MainWindow::setAutoGain(bool enabled) { rx->set_auto_gain(enabled); - if (!enabled) - { - uiDockInputCtl->restoreManualGains(m_settings); - } + uiDockInputCtl->restoreManualGains(); } /** diff --git a/src/qtgui/dockinputctl.cpp b/src/qtgui/dockinputctl.cpp index 3a299b8..397fb5f 100644 --- a/src/qtgui/dockinputctl.cpp +++ b/src/qtgui/dockinputctl.cpp @@ -72,10 +72,6 @@ void DockInputCtl::readSettings(QSettings * settings) setIgnoreLimits(bool_val); emit ignoreLimitsChanged(bool_val); - bool_val = settings->value("input/hwagc", false).toBool(); - setAgc(bool_val); - emit autoGainChanged(bool_val); - // Ignore antenna selection if there is only one option if (ui->antSelector->count() > 1) { @@ -105,6 +101,10 @@ void DockInputCtl::readSettings(QSettings * settings) } } + bool_val = settings->value("input/hwagc", false).toBool(); + setAgc(bool_val); + emit autoGainChanged(bool_val); + // misc GUI settings bool_val = settings->value("gui/fctl_reset_digits", true).toBool(); emit freqCtrlResetChanged(bool_val); @@ -408,27 +408,17 @@ void DockInputCtl::setGainStages(gain_list_t &gain_list) * Can be used for restoring the manual gains after auto-gain has been * disabled. */ -void DockInputCtl::restoreManualGains(QSettings *settings) +void DockInputCtl::restoreManualGains(void) { - // gains are stored as a QMap - // note that we store the integer values, i.e. dB*10 - QMap allgains; - QString gain_name; - double gain_value; - if (settings->contains("input/gains")) - { - allgains = settings->value("input/gains").toMap(); - QMapIterator gain_iter(allgains); - - while (gain_iter.hasNext()) - { - gain_iter.next(); + QString gain_stage; + double gain_value; + int i; - gain_name = gain_iter.key(); - gain_value = 0.1 * (double)(gain_iter.value().toInt()); - setGain(gain_name, gain_value); - emit gainChanged(gain_name, gain_value); - } + for (i = 0; i < gain_sliders.length(); i++) + { + gain_stage = gain_sliders.at(i)->property("name").toString(); + gain_value = 0.1 * (double)gain_sliders.at(i)->value(); + emit gainChanged(gain_stage, gain_value); } } diff --git a/src/qtgui/dockinputctl.h b/src/qtgui/dockinputctl.h index 1fac067..9999e40 100644 --- a/src/qtgui/dockinputctl.h +++ b/src/qtgui/dockinputctl.h @@ -98,7 +98,7 @@ class DockInputCtl : public QDockWidget void setAntenna(const QString &antenna); void setGainStages(gain_list_t &gain_list); - void restoreManualGains(QSettings *settings); + void restoreManualGains(void); void setFreqCtrlReset(bool enabled); From d4927c4533860c22427898782854d062782e5348 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 12:34:41 +0100 Subject: [PATCH 301/334] Clean-up meter widget code and add SQL indicator Issue #48. --- resources/news.txt | 3 +- src/applications/gqrx/mainwindow.cpp | 1 + src/qtgui/meter.cpp | 84 ++++++++++++++++------------ src/qtgui/meter.h | 20 +++---- 4 files changed, 60 insertions(+), 48 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index cb8d835..6b9e681 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -8,10 +8,11 @@ FIXED: Can not play I/Q files if path contains a space. FIXED: Restore gains to slider states when hardware AGC is disabled IMPROVED: Default FFT window for reduced spectral leakage. + IMPROVED: Visual indicator of squelch level in the signal meter. + IMPROVED: Show configuration file path when listing config files using -l IMPROVED: Microtelecom Perseus integration. IMPROVED: Implemented PPM correction for RF Space Cloud IQ (gr-osmosdr-gqrx) IMPORVED: Implemented PPM correction for PlutoSDR (gr-osmosdr-gqrx) - IMPROVED: Show configuration file path when listing config files using -l 2.10: Released January 21, 2018 diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index c37e1b6..f426b0d 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1216,6 +1216,7 @@ void MainWindow::setNoiseBlanker(int nbid, bool on, float threshold) void MainWindow::setSqlLevel(double level_db) { rx->set_sql_level(level_db); + ui->sMeter->setSqlLevel(level_db); } /** diff --git a/src/qtgui/meter.cpp b/src/qtgui/meter.cpp index 9cdd6dc..caa3551 100644 --- a/src/qtgui/meter.cpp +++ b/src/qtgui/meter.cpp @@ -41,8 +41,11 @@ #define CTRL_XAXIS_HEGHT 0.4 // vertical position of horizontal axis #define CTRL_NEEDLE_TOP 0.4 // vertical position of top of needle triangle -#define MIN_DB -100.0 -#define MAX_DB +0.0 +#define MIN_DB -100.0f +#define MAX_DB +0.0f + +#define ALPHA_DECAY 0.25f +#define ALPHA_RISE 0.70f CMeter::CMeter(QWidget *parent) : QFrame(parent) { @@ -54,13 +57,14 @@ CMeter::CMeter(QWidget *parent) : QFrame(parent) setAttribute(Qt::WA_NoSystemBackground, true); setMouseTracking(true); + m_Font = QFont("Arial"); + m_Font.setWeight(QFont::Normal); m_2DPixmap = QPixmap(0,0); m_OverlayPixmap = QPixmap(0,0); m_Size = QSize(0,0); - m_Slevel = 0; - m_dBm = -120; - d_alpha_decay = 0.25; // FIXME: Should set delta-t and Fs instead - d_alpha_rise = 0.7; // FIXME: Should set delta-t and Fs instead + m_Siglevel = 0; + m_dBFS = MIN_DB; + m_SqlLevel = 0.0f; } CMeter::~CMeter() @@ -77,7 +81,7 @@ QSize CMeter::sizeHint() const return QSize(100, 30); } -void CMeter::resizeEvent(QResizeEvent* ) +void CMeter::resizeEvent(QResizeEvent *) { if (!size().isValid()) return; @@ -90,6 +94,10 @@ void CMeter::resizeEvent(QResizeEvent* ) m_OverlayPixmap.fill(Qt::black); m_2DPixmap = QPixmap(m_Size.width(), m_Size.height()); m_2DPixmap.fill(Qt::black); + + qreal w = m_2DPixmap.width() - 2 * CTRL_MARGIN * m_2DPixmap.width(); + m_pixperdb = w / fabs(MAX_DB - MIN_DB); + setSqlLevel(m_Sql); } DrawOverlay(); @@ -98,29 +106,30 @@ void CMeter::resizeEvent(QResizeEvent* ) void CMeter::setLevel(float dbfs) { - if(dbfs < MIN_DB) + if (dbfs < MIN_DB) dbfs = MIN_DB; - - if(dbfs > MAX_DB) + else if (dbfs > MAX_DB) dbfs = MAX_DB; - // decay delay - float level = (float)m_dBm; - if (dbfs < level) - level = level * (1.f - d_alpha_decay) + dbfs * d_alpha_decay; - else - level = level * (1.f - d_alpha_rise) + dbfs * d_alpha_rise; + float level = m_dBFS; + float alpha = dbfs < level ? ALPHA_DECAY : ALPHA_RISE; + m_dBFS -= alpha * (level - dbfs); + m_Siglevel = (int)((level - MIN_DB) * m_pixperdb); - m_dBm = (int)level; + draw(); +} - qreal w = (qreal)m_2DPixmap.width(); - w -= 2 * CTRL_MARGIN * w; // width of meter scale in pixels +void CMeter::setSqlLevel(float dbfs) +{ + if (dbfs >= 0.f) + m_SqlLevel = 0.0f; + else + m_SqlLevel = (dbfs - MIN_DB) * m_pixperdb; - // pixels / dB - qreal pixperdb = w / fabs(MAX_DB - MIN_DB); - m_Slevel = (int)(-(MIN_DB - level) * pixperdb); + if (m_SqlLevel < 0.0f) + m_SqlLevel = 0.0f; - draw(); + m_Sql = dbfs; } // Called by QT when screen needs to be redrawn @@ -138,7 +147,7 @@ void CMeter::draw() int w; int h; - if(m_2DPixmap.isNull()) + if (m_2DPixmap.isNull()) return; // get/draw the 2D spectrum @@ -153,7 +162,7 @@ void CMeter::draw() qreal hline = (qreal) h * CTRL_XAXIS_HEGHT; qreal marg = (qreal) w * CTRL_MARGIN; qreal ht = (qreal) h * CTRL_NEEDLE_TOP; - qreal x = marg + m_Slevel; + qreal x = marg + m_Siglevel; QPoint pts[3]; pts[0].setX(x); pts[0].setY(ht + 2); @@ -173,16 +182,20 @@ void CMeter::draw() painter.drawRect(marg, ht + 2, x - marg, 6); #endif - // create Font to use for scales - QFont Font("Arial"); + if (m_SqlLevel > 0.0f) + { + x = marg + m_SqlLevel; + painter.setPen(QPen(Qt::yellow, 1, Qt::SolidLine)); + painter.drawLine(QLineF(x, hline, x, hline + 8)); + } + int y = (h) / 4; - Font.setPixelSize(y); - Font.setWeight(QFont::Normal); - painter.setFont(Font); + m_Font.setPixelSize(y); + painter.setFont(m_Font); painter.setPen(QColor(0xDA, 0xDA, 0xDA, 0xFF)); painter.setOpacity(1.0); - m_Str.setNum(m_dBm); + m_Str.setNum(m_dBFS); painter.drawText(marg, h - 2, m_Str + " dBFS" ); update(); @@ -192,7 +205,7 @@ void CMeter::draw() // does not need to be recreated every fft data update. void CMeter::DrawOverlay() { - if(m_OverlayPixmap.isNull()) + if (m_OverlayPixmap.isNull()) return; int w = m_OverlayPixmap.width(); @@ -223,12 +236,9 @@ void CMeter::DrawOverlay() } // draw scale text - // create Font to use for scales - QFont Font("Arial"); y = h / 4; - Font.setPixelSize(y); - Font.setWeight(QFont::Normal); - painter.setFont(Font); + m_Font.setPixelSize(y); + painter.setFont(m_Font); int rwidth = (int)((hstop - marg) / 5.0); m_Str = "-100"; rect.setRect(marg / 2 - 5, 0, rwidth, magstart); diff --git a/src/qtgui/meter.h b/src/qtgui/meter.h index 3877d53..4d76d72 100644 --- a/src/qtgui/meter.h +++ b/src/qtgui/meter.h @@ -29,8 +29,7 @@ * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of Moe Wheatley. */ -#ifndef METER_H -#define METER_H +#pragma once #include #include @@ -58,6 +57,7 @@ class CMeter : public QFrame public slots: void setLevel(float dbfs); + void setSqlLevel(float dbfs); protected: void paintEvent(QPaintEvent *event); @@ -65,15 +65,15 @@ public slots: private: void DrawOverlay(); + + QFont m_Font; QPixmap m_2DPixmap; QPixmap m_OverlayPixmap; - QSize m_Size; + QSize m_Size; QString m_Str; - int m_Slevel; - int m_dBm; - - float d_alpha_decay; - float d_alpha_rise; + qreal m_pixperdb; // pixels / dB + int m_Siglevel; + int m_dBFS; + qreal m_Sql; + qreal m_SqlLevel; }; - -#endif // METER_H From ca19a5779bcdf3bc84a548c21ec5bba8f3135906 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 14:47:25 +0100 Subject: [PATCH 302/334] Clean-up in bookmarks code --- src/qtgui/dockbookmarks.cpp | 85 +++++++++++++++++++------------------ src/qtgui/dockbookmarks.h | 17 +------- 2 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/qtgui/dockbookmarks.cpp b/src/qtgui/dockbookmarks.cpp index 8c6bb43..cca7182 100644 --- a/src/qtgui/dockbookmarks.cpp +++ b/src/qtgui/dockbookmarks.cpp @@ -22,19 +22,19 @@ */ #include #include +#include +#include #include #include -#include #include -#include -#include +#include #include "bookmarks.h" #include "bookmarkstaglist.h" #include "dockbookmarks.h" -#include "ui_dockbookmarks.h" -#include "qtcolorpicker.h" #include "dockrxopt.h" +#include "qtcolorpicker.h" +#include "ui_dockbookmarks.h" DockBookmarks::DockBookmarks(QWidget *parent) : QDockWidget(parent), @@ -46,8 +46,8 @@ DockBookmarks::DockBookmarks(QWidget *parent) : // Frequency List ui->tableViewFrequencyList->setModel(bookmarksTableModel); - ui->tableViewFrequencyList->setColumnWidth( BookmarksTableModel::COL_NAME, - ui->tableViewFrequencyList->columnWidth(BookmarksTableModel::COL_NAME)*2 ); + ui->tableViewFrequencyList->setColumnWidth(BookmarksTableModel::COL_NAME, + ui->tableViewFrequencyList->columnWidth(BookmarksTableModel::COL_NAME) * 2); ui->tableViewFrequencyList->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableViewFrequencyList->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableViewFrequencyList->installEventFilter(this); @@ -77,8 +77,8 @@ DockBookmarks::DockBookmarks(QWidget *parent) : Bookmarks::Get().load(); bookmarksTableModel->update(); - m_currentFrequency=0; - m_updating=false; + m_currentFrequency = 0; + m_updating = false; // TagList updateTags(); @@ -101,7 +101,7 @@ DockBookmarks::~DockBookmarks() bookmarksTableModel = 0; } -void DockBookmarks::activated(const QModelIndex & index ) +void DockBookmarks::activated(const QModelIndex & index) { BookmarkInfo *info = bookmarksTableModel->getBookmarkAtRow(index.row()); emit newBookmarkActivated(info->frequency, info->modulation, info->bandwidth); @@ -111,24 +111,24 @@ void DockBookmarks::setNewFrequency(qint64 rx_freq) { ui->tableViewFrequencyList->clearSelection(); const int iRowCount = bookmarksTableModel->rowCount(); - for(int row=0; rowgetBookmarkAtRow(row)); - if( std::abs(rx_freq - info.frequency) <= ((info.bandwidth/2)+1) ) + if (std::abs(rx_freq - info.frequency) <= ((info.bandwidth / 2 ) + 1)) { ui->tableViewFrequencyList->selectRow(row); - ui->tableViewFrequencyList->scrollTo( ui->tableViewFrequencyList->currentIndex(), QAbstractItemView::EnsureVisible ); + ui->tableViewFrequencyList->scrollTo(ui->tableViewFrequencyList->currentIndex(), QAbstractItemView::EnsureVisible ); break; } } - m_currentFrequency=rx_freq; + m_currentFrequency = rx_freq; } void DockBookmarks::updateTags() { - m_updating=true; + m_updating = true; ui->tableWidgetTagList->updateTags(); - m_updating=false; + m_updating = false; } void DockBookmarks::updateBookmarks() @@ -149,7 +149,8 @@ void DockBookmarks::on_tableWidgetTagList_itemChanged(QTableWidgetItem *item) if(ui->tableWidgetTagList->m_bUpdating) return; int col = item->column(); - if (col != 1) return; + if (col != 1) + return; QString strText = item->text(); Bookmarks::Get().setTagChecked(strText, (item->checkState() == Qt::Checked)); @@ -157,27 +158,27 @@ void DockBookmarks::on_tableWidgetTagList_itemChanged(QTableWidgetItem *item) bool DockBookmarks::eventFilter(QObject* object, QEvent* event) { - if (event->type()==QEvent::KeyPress) - { - QKeyEvent* pKeyEvent=static_cast(event); - if (pKeyEvent->key() == Qt::Key_Delete && ui->tableViewFrequencyList->hasFocus()) + if (event->type() == QEvent::KeyPress) { - return DeleteSelectedBookmark(); + QKeyEvent* pKeyEvent = static_cast(event); + if (pKeyEvent->key() == Qt::Key_Delete && ui->tableViewFrequencyList->hasFocus()) + { + return DeleteSelectedBookmark(); + } } - } - return QWidget::eventFilter(object, event); + return QWidget::eventFilter(object, event); } bool DockBookmarks::DeleteSelectedBookmark() { QModelIndexList selected = ui->tableViewFrequencyList->selectionModel()->selectedRows(); - if(selected.empty()) + if (selected.empty()) { return true; } - if(QMessageBox::question(this, "Delete bookmark", "Really delete?", QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes) + if (QMessageBox::question(this, "Delete bookmark", "Really delete?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { int iIndex = bookmarksTableModel->GetBookmarksIndexForRow(selected.first().row()); Bookmarks::Get().remove(iIndex); @@ -206,32 +207,32 @@ ComboBoxDelegateModulation::ComboBoxDelegateModulation(QObject *parent) QWidget *ComboBoxDelegateModulation::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const { - QComboBox* comboBox = new QComboBox(parent); - for(int i = 0; i < DockRxOpt::ModulationStrings.size(); ++i) - { - comboBox->addItem(DockRxOpt::ModulationStrings[i]); - } - setEditorData(comboBox, index); - return comboBox; + QComboBox* comboBox = new QComboBox(parent); + for (int i = 0; i < DockRxOpt::ModulationStrings.size(); ++i) + { + comboBox->addItem(DockRxOpt::ModulationStrings[i]); + } + setEditorData(comboBox, index); + return comboBox; } void ComboBoxDelegateModulation::setEditorData(QWidget *editor, const QModelIndex &index) const { - QComboBox *comboBox = static_cast(editor); - QString value = index.model()->data(index, Qt::EditRole).toString(); - int iModulation = DockRxOpt::GetEnumForModulationString(value); - comboBox->setCurrentIndex(iModulation); + QComboBox *comboBox = static_cast(editor); + QString value = index.model()->data(index, Qt::EditRole).toString(); + int iModulation = DockRxOpt::GetEnumForModulationString(value); + comboBox->setCurrentIndex(iModulation); } void ComboBoxDelegateModulation::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { - QComboBox *comboBox = static_cast(editor); - model->setData(index, comboBox->currentText(), Qt::EditRole); + QComboBox *comboBox = static_cast(editor); + model->setData(index, comboBox->currentText(), Qt::EditRole); } void DockBookmarks::changeBookmarkTags(int row, int /*column*/) { - bool ok=false; + bool ok = false; QString tags; // list of tags separated by comma int iIdx = bookmarksTableModel->GetBookmarksIndexForRow(row); @@ -266,11 +267,11 @@ void DockBookmarks::changeBookmarkTags(int row, int /*column*/) // Change Tags of Bookmark QStringList listTags = tags.split(",",QString::SkipEmptyParts); bmi.tags.clear(); - if(listTags.size()==0) + if (listTags.size() == 0) { bmi.tags.append(&Bookmarks::Get().findOrAddTag("")); // "Untagged" } - for(int i=0; i #include @@ -42,18 +41,6 @@ Q_OBJECT void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; }; -#if 0 -class DelegateTags : public QItemDelegate -{ -Q_OBJECT -public: - DelegateTags(QObject *parent = 0); - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; - void setEditorData(QWidget *editor, const QModelIndex &index) const; - void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; -}; -#endif - class DockBookmarks : public QDockWidget { Q_OBJECT @@ -95,5 +82,3 @@ private slots: bool DeleteSelectedBookmark(); void doubleClicked(const QModelIndex & index); }; - -#endif // DOCKFREQTABLE_H From e0cf2dce3e5b062f948cfc2d82f4bf28d61519e2 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 20:48:52 +0100 Subject: [PATCH 303/334] Update news file --- resources/news.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index 6b9e681..8ab55c7 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -6,7 +6,8 @@ FIXED: Black on black tooltips in the main window. FIXED: Auto-squelch sets 0 dBFS too often. FIXED: Can not play I/Q files if path contains a space. - FIXED: Restore gains to slider states when hardware AGC is disabled + FIXED: Restore gains to slider states when hardware AGC is disabled. + FIXED: Crash on startup when audio output device is gone (Mac OS X). IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Visual indicator of squelch level in the signal meter. IMPROVED: Show configuration file path when listing config files using -l From a029b2a578375418dd085649c3b3edd55c4e4409 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 21:10:34 +0100 Subject: [PATCH 304/334] Use correct upper limit for auto-squelch --- src/applications/gqrx/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index f426b0d..95240c6 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1226,7 +1226,7 @@ void MainWindow::setSqlLevel(double level_db) double MainWindow::setSqlLevelAuto() { double level = rx->get_signal_pwr(true) + 1.0; - if (level > -90.0) // avoid 0 dBFS + if (level > -10.0) // avoid 0 dBFS level = uiDockRxOpt->getSqlLevel(); setSqlLevel(level); From b15a648cb367f1489fb81b38a93a748bf64ae069 Mon Sep 17 00:00:00 2001 From: Marc L Date: Sat, 17 Mar 2018 13:44:16 -0400 Subject: [PATCH 305/334] added MANIFEST.md for CGRAN parsing sake We are currently working on revitalizing CGRAN, the current version is here https://gnuradio.org/cgran/ and just like the old CGRAN it parses OOT's manifest files to get its information. Feel free to modify stuff, I just copied whatever info I could find. --- MANIFEST.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 MANIFEST.md diff --git a/MANIFEST.md b/MANIFEST.md new file mode 100644 index 0000000..10df372 --- /dev/null +++ b/MANIFEST.md @@ -0,0 +1,46 @@ +title: gqrx +brief: SDR receiver implemented using GNU Radio and the Qt GUI toolkit +tags: + - AM + - FM + - SSB + - FFT +author: + - Alexandru Csete +copyright_owner: + - Alexandru Csete +dependencies: + - gnuradio + - gnuradio-osmosdr + - Qt5 +repo: https://github.com/csete/gqrx.git +stable_release: HEAD +icon: +--- + +Gqrx is an open source software defined radio (SDR) receiver implemented using GNU Radio and the Qt GUI toolkit. +Currently it works on Linux and Mac with hardware supported by gr-osmosdr, including Funcube Dongle, RTL-SDR, Airspy, HackRF, BladeRF, RFSpace, USRP and SoapySDR. +Gqrx can operate as an AM/FM/SSB receiver with audio output or as an FFT-only instrument. +There are also various hooks for interacting with external application using nertwork sockets. + +Download: + +Gqrx is distributed as source code package and binaries for Linux and Mac. +Alternate Mac support is available through macports and homebrew. +Please see http://gqrx.dk/download for a list of download resources. + +Usage: + +It is strongly recommended to run the "volk_profile" gnuradio utility before running gqrx. +This will detect and enable processor specific optimisations and will in many cases give a significant performance boost. +The first time you start gqrx it will open a device configuration dialog. +Supported devices that are connected to the computer are discovered automatically and you can select any of them in the drop-down list. +If you don't see your device listed in the drop-down list it could be because: +1. The driver has not been included in a binary distribution +2. The udev rule has not been properly configured +3. Linux kernel driver is blocking access to the device +You can test your device using device specific tools, such as rtl_test, airspy_rx, hackrf_transfer, qthid, etc. +Gqrx supports multiple configurations and sessions if you have several devices or if you want to use the same device under different configurations. +You can load a configuration from the GUI or using the -c command line argument. +See "gqrx --help" for a complete list of command line arguments. +Tutorials and howtos are being written and published on the website http://gqrx.dk/ From a851f67e0f059665b1c65b6b85a36f4b8393f2a1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 17 Mar 2018 22:22:57 +0100 Subject: [PATCH 306/334] Make filter offset limit a function of the bandwidth The filter offset can now have up to 9 digits. Issue #582. --- resources/news.txt | 1 + src/qtgui/dockrxopt.cpp | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/resources/news.txt b/resources/news.txt index 8ab55c7..cf4e89f 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -8,6 +8,7 @@ FIXED: Can not play I/Q files if path contains a space. FIXED: Restore gains to slider states when hardware AGC is disabled. FIXED: Crash on startup when audio output device is gone (Mac OS X). + FIXED: Filter offset no longer limited to +/- 9.999999 MHz. IMPROVED: Default FFT window for reduced spectral leakage. IMPROVED: Visual indicator of squelch level in the signal meter. IMPROVED: Show configuration file path when listing config files using -l diff --git a/src/qtgui/dockrxopt.cpp b/src/qtgui/dockrxopt.cpp index 9a77751..7d14caa 100644 --- a/src/qtgui/dockrxopt.cpp +++ b/src/qtgui/dockrxopt.cpp @@ -139,8 +139,24 @@ void DockRxOpt::setFilterOffset(qint64 freq_hz) */ void DockRxOpt::setFilterOffsetRange(qint64 range_hz) { - if (range_hz > 0) - ui->filterFreq->setup(7, -range_hz/2, range_hz/2, 1, FCTL_UNIT_KHZ); + int num_digits; + + if (range_hz <= 0) + return; + + range_hz /= 2; + if (range_hz < 100e3) + num_digits = 5; + else if (range_hz < 1e6) + num_digits = 6; + else if (range_hz < 1e7) + num_digits = 7; + else if (range_hz < 1e8) + num_digits = 8; + else + num_digits = 9; + + ui->filterFreq->setup(num_digits, -range_hz, range_hz, 1, FCTL_UNIT_KHZ); } /** From a8c14f5e8c87869967ff273dc79fb74fb03c1585 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 18 Mar 2018 12:26:00 +0100 Subject: [PATCH 307/334] Update version to 2.11 --- CMakeLists.txt | 8 ++++---- gqrx.pro | 8 ++++---- resources/news.txt | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7706d6..a74be15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,11 @@ cmake_minimum_required(VERSION 2.8.0) # Project name project(gqrx) set(${PROJECT_NAME}_MAJOR "2") -set(${PROJECT_NAME}_MINOR "10") +set(${PROJECT_NAME}_MINOR "11") set(${PROJECT_NAME}_PATCH "0") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -#set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -#add_definitions(-DVERSION="${VERSION}") +set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_definitions(-DVERSION="${GITVERSION}") +#add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 0e6efdb..b18dc48 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -72,14 +72,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - VER = $$system(git describe --abbrev=8) - ##VER = 2.10 + ##VER = $$system(git describe --abbrev=8) + VER = 2.11 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - VER = $$system(git describe --abbrev=1) - ##VER = 2.10 + ##VER = $$system(git describe --abbrev=1) + VER = 2.11 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin diff --git a/resources/news.txt b/resources/news.txt index cf4e89f..e540f55 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,5 @@ - 2.11: Released TBD... + 2.11: Released MArch 18, 2018 NEW: Selectable IQ FFT window type. FIXED: Problems on Mac Pro computers without built-in audio. From 3ca58b684b75d1dfb0f65d3314f538a874144bc6 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 18 Mar 2018 15:30:01 +0100 Subject: [PATCH 308/334] Remove visible border around frequency and meter widgets --- src/applications/gqrx/mainwindow.ui | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index c3c18e4..75ccc1f 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -55,10 +55,13 @@ background-color: rgb(31, 29, 29); - QFrame::StyledPanel + QFrame::NoFrame - QFrame::Raised + QFrame::Plain + + + 0 From 10095a2988b2764c53a186d0d32e1fa29d2b89d1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 18 Mar 2018 15:30:29 +0100 Subject: [PATCH 309/334] Update version to 2.11.1 --- CMakeLists.txt | 6 +++--- gqrx.pro | 4 ++-- resources/news.txt | 6 +++++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a74be15..8bb1cef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,9 +4,9 @@ cmake_minimum_required(VERSION 2.8.0) project(gqrx) set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "11") -set(${PROJECT_NAME}_PATCH "0") -##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") -set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") +set(${PROJECT_NAME}_PATCH "1") +set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") +##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") add_definitions(-DVERSION="${VERSION}") # development version diff --git a/gqrx.pro b/gqrx.pro index b18dc48..9b311c8 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -73,13 +73,13 @@ CONFIG(debug, debug|release) { # Define version string (see below for releases) ##VER = $$system(git describe --abbrev=8) - VER = 2.11 + VER = 2.11.1 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT ##VER = $$system(git describe --abbrev=1) - VER = 2.11 + VER = 2.11.1 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin diff --git a/resources/news.txt b/resources/news.txt index e540f55..e758e14 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,9 @@ + 2.11.1: Released March 18, 2018 - 2.11: Released MArch 18, 2018 + FIXED: Removed visible border around frequency and meter widgets. + + + 2.11: Released March 18, 2018 NEW: Selectable IQ FFT window type. FIXED: Problems on Mac Pro computers without built-in audio. From 89f85773c30ddc539f250c2a7d9afa2aadc0cf9c Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 23 Mar 2018 01:05:40 +0100 Subject: [PATCH 310/334] Reduce width of horizontal separators in the main window --- src/applications/gqrx/mainwindow.ui | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index 75ccc1f..d88250f 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -6,7 +6,7 @@ 0 0 - 950 + 946 702 @@ -68,13 +68,13 @@ 10 - 20 + 0 10 - 10 + 0 10 @@ -86,8 +86,8 @@ - 109 - 17 + 5 + 15 @@ -102,8 +102,8 @@ - 371 - 41 + 350 + 40 @@ -124,8 +124,8 @@ - 109 - 17 + 5 + 15 @@ -159,8 +159,8 @@ - 109 - 17 + 5 + 15 @@ -194,7 +194,7 @@ 0 0 - 950 + 946 19 From cbc8a2d72397d2d9ffafddc37e80b0f5aedded5e Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Mar 2018 15:14:29 +0100 Subject: [PATCH 311/334] More layout adjustments for small screens --- src/applications/gqrx/mainwindow.ui | 16 ++++++++-------- src/qtgui/dockfft.ui | 6 +++--- src/qtgui/dockrxopt.ui | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/applications/gqrx/mainwindow.ui b/src/applications/gqrx/mainwindow.ui index d88250f..0fb1f36 100644 --- a/src/applications/gqrx/mainwindow.ui +++ b/src/applications/gqrx/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 946 - 702 + 521 + 350 @@ -65,7 +65,7 @@ - 10 + 0 0 @@ -102,7 +102,7 @@ - 350 + 280 40 @@ -140,8 +140,8 @@ - 171 - 41 + 150 + 40 @@ -153,7 +153,7 @@ - + Qt::Horizontal @@ -194,7 +194,7 @@ 0 0 - 946 + 521 19 diff --git a/src/qtgui/dockfft.ui b/src/qtgui/dockfft.ui index 21f07ee..afbc0e5 100644 --- a/src/qtgui/dockfft.ui +++ b/src/qtgui/dockfft.ui @@ -6,7 +6,7 @@ 0 0 - 288 + 280 416 @@ -18,7 +18,7 @@ - 200 + 280 200 @@ -83,7 +83,7 @@ 0 0 - 278 + 270 387 diff --git a/src/qtgui/dockrxopt.ui b/src/qtgui/dockrxopt.ui index 877ebfd..7d6c91e 100644 --- a/src/qtgui/dockrxopt.ui +++ b/src/qtgui/dockrxopt.ui @@ -6,8 +6,8 @@ 0 0 - 305 - 335 + 280 + 330 @@ -18,8 +18,8 @@ - 305 - 335 + 280 + 330 From dfefbcf3fbfb8997e4b233df26039f59c4aebdf3 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Mar 2018 15:15:05 +0100 Subject: [PATCH 312/334] Avoid extra space around frequency controller We can save space corresponding to two digits, when we have no units after the frequency controller. --- src/qtgui/freqctrl.cpp | 8 +++++--- src/qtgui/freqctrl.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index 6a75228..5a1a4df 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -262,9 +262,11 @@ void CFreqCtrl::setDigitColor(QColor col) void CFreqCtrl::setUnit(FctlUnit unit) { + m_NumDigitsForUnit = 2; switch (unit) { case FCTL_UNIT_NONE: + m_NumDigitsForUnit = 0; m_DecPos = 0; m_UnitString = QString(); break; @@ -559,8 +561,8 @@ void CFreqCtrl::drawBkGround(QPainter &Painter) // qDebug() < m_DigStart) && ((i % 3) == 0)) diff --git a/src/qtgui/freqctrl.h b/src/qtgui/freqctrl.h index a3ce398..97f2fe7 100644 --- a/src/qtgui/freqctrl.h +++ b/src/qtgui/freqctrl.h @@ -92,6 +92,7 @@ public slots: int m_LastLeadZeroPos; int m_LeadZeroPos; int m_NumDigits; + int m_NumDigitsForUnit; // number of digits allocated for unit (kHz, MHz, ...) int m_DigStart; int m_ActiveEditDigit; int m_LastEditDigit; From e829653e14ae8c51fcb4a7d7f1c3539769b50f27 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Mar 2018 15:34:05 +0100 Subject: [PATCH 313/334] Use git version --- gqrx.pro | 8 ++++---- resources/news.txt | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/gqrx.pro b/gqrx.pro index 9b311c8..75bd7ff 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -72,14 +72,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - ##VER = $$system(git describe --abbrev=8) - VER = 2.11.1 + VER = $$system(git describe --abbrev=8) + ##VER = 2.11.1 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - ##VER = $$system(git describe --abbrev=1) - VER = 2.11.1 + VER = $$system(git describe --abbrev=1) + ##VER = 2.11.1 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin diff --git a/resources/news.txt b/resources/news.txt index e758e14..9e99994 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,3 +1,8 @@ + 2.11.2: Released March 24, 2018 + + FIXED: Layout on low resolution monitors. + + 2.11.1: Released March 18, 2018 FIXED: Removed visible border around frequency and meter widgets. From 0fc8467b61e8a01b18fbc904071aa31da91d0725 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Mar 2018 15:34:36 +0100 Subject: [PATCH 314/334] Simplify debug output when listing input devices --- src/qtgui/ioconfig.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 6fd516c..e4fdd8f 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -193,7 +193,6 @@ CIoConfig::~CIoConfig() */ void CIoConfig::getDeviceList(std::map &devList) { - unsigned int i; QString devstr; QString devlabel; @@ -208,6 +207,7 @@ void CIoConfig::getDeviceList(std::map &devList) vector inDevList = devices.get_input_devices(); #endif string this_dev; + int i; for (i = 0; i < inDevList.size(); i++) { this_dev = inDevList[i].get_name(); @@ -253,9 +253,7 @@ void CIoConfig::getDeviceList(std::map &devList) devstr = QString(dev.to_string().c_str()); devList.insert(std::pair(devlabel, devstr)); - - qDebug() << " " << i << ":" << devlabel; - ++i; + qDebug() << " " << devlabel; } } From e914318fef542bfb9d340f1c189afb1619e0f9d1 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Mar 2018 15:35:02 +0100 Subject: [PATCH 315/334] Use git version --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bb1cef..3189b4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(${PROJECT_NAME}_MINOR "11") set(${PROJECT_NAME}_PATCH "1") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +#add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -#add_definitions(-DVERSION="${GITVERSION}") +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) From 4eb8e6953bb05b40ce673b364bd678ef8ee4b7b2 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 24 Mar 2018 22:54:36 +0100 Subject: [PATCH 316/334] Ensure gain sliders expand while labels stay fixed --- src/qtgui/dockinputctl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qtgui/dockinputctl.cpp b/src/qtgui/dockinputctl.cpp index 397fb5f..6ab694d 100644 --- a/src/qtgui/dockinputctl.cpp +++ b/src/qtgui/dockinputctl.cpp @@ -363,16 +363,16 @@ void DockInputCtl::setGainStages(gain_list_t &gain_list) step = (int)(10.0 * gain_list[i].step); gain = (int)(10.0 * gain_list[i].value); - label = new QLabel(QString("%1 gain").arg(gain_list[i].name.c_str()), this); - label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); + label = new QLabel(QString("%1 ").arg(gain_list[i].name.c_str()), this); + label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); - value = new QLabel(QString("%1 dB").arg(gain_list[i].value, 0, 'f', 1), this); - value->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); + value = new QLabel(QString(" %1 dB").arg(gain_list[i].value, 0, 'f', 1), this); + value->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); slider = new QSlider(Qt::Horizontal, this); slider->setProperty("idx", i); slider->setProperty("name", QString(gain_list[i].name.c_str())); - slider->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum)); + slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); slider->setRange(start, stop); slider->setSingleStep(step); slider->setValue(gain); @@ -380,7 +380,7 @@ void DockInputCtl::setGainStages(gain_list_t &gain_list) slider->setPageStep(10 * step); gainLayout->addWidget(label, i, 0, Qt::AlignLeft); - gainLayout->addWidget(slider, i, 1, Qt::AlignCenter); + gainLayout->addWidget(slider, i, 1); // setting alignment would force minimum size gainLayout->addWidget(value, i, 2, Qt::AlignLeft); gain_labels.push_back(label); From be7e23c8464ecc372704e9798fac11609dab365b Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sun, 25 Mar 2018 00:18:01 +0100 Subject: [PATCH 317/334] Update version to 2.11.2 --- CMakeLists.txt | 6 +++--- gqrx.pro | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3189b4a..f2d42f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,10 @@ cmake_minimum_required(VERSION 2.8.0) project(gqrx) set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "11") -set(${PROJECT_NAME}_PATCH "1") +set(${PROJECT_NAME}_PATCH "2") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -#add_definitions(-DVERSION="${VERSION}") +add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_definitions(-DVERSION="${GITVERSION}") +#add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 75bd7ff..b05b11f 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -72,14 +72,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - VER = $$system(git describe --abbrev=8) - ##VER = 2.11.1 + ##VER = $$system(git describe --abbrev=8) + VER = 2.11.2 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - VER = $$system(git describe --abbrev=1) - ##VER = 2.11.1 + ##VER = $$system(git describe --abbrev=1) + VER = 2.11.2 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 8643d088c5301c14478f76d3252815b538baf667 Mon Sep 17 00:00:00 2001 From: Arinerron Date: Thu, 29 Mar 2018 14:54:58 -0700 Subject: [PATCH 318/334] Add backspace key to frequency controller Backspace key has the same function as the left arrow key. --- src/qtgui/freqctrl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qtgui/freqctrl.cpp b/src/qtgui/freqctrl.cpp index 5a1a4df..4946bf2 100644 --- a/src/qtgui/freqctrl.cpp +++ b/src/qtgui/freqctrl.cpp @@ -512,6 +512,7 @@ void CFreqCtrl::keyPressEvent(QKeyEvent *event) moveCursorRight(); fSkipMsg = true; break; + case Qt::Key_Backspace: case Qt::Key_Left: if (m_ActiveEditDigit != -1) { From 70ae6044426cb1b3978a73fa50558b1d5e6c6ef8 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 2 Apr 2018 12:06:06 +0200 Subject: [PATCH 319/334] Continue with git version --- CMakeLists.txt | 4 ++-- gqrx.pro | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2d42f5..4d02a7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(${PROJECT_NAME}_MINOR "11") set(${PROJECT_NAME}_PATCH "2") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +##add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -#add_definitions(-DVERSION="${GITVERSION}") +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index b05b11f..5d21448 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -72,14 +72,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - ##VER = $$system(git describe --abbrev=8) - VER = 2.11.2 + VER = $$system(git describe --abbrev=8) + ##VER = 2.11.2 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT - ##VER = $$system(git describe --abbrev=1) - VER = 2.11.2 + VER = $$system(git describe --abbrev=1) + ##VER = 2.11.2 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 74931e8b5315437ab8398f0b641eab28bb360809 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Mon, 9 Apr 2018 19:39:46 +0200 Subject: [PATCH 320/334] Delete remote control socket after closing it --- src/applications/gqrx/remote_control.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index 3727abd..1ee8149 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -79,8 +79,11 @@ void RemoteControl::start_server() /*! \brief Stop the server. */ void RemoteControl::stop_server() { - if (rc_socket != 0) + if (rc_socket != 0) { rc_socket->close(); + delete rc_socket; + rc_socket = 0; + } if (rc_server.isListening()) rc_server.close(); @@ -162,6 +165,11 @@ void RemoteControl::setHosts(QStringList hosts) */ void RemoteControl::acceptConnection() { + if (rc_socket) + { + rc_socket->close(); + delete rc_socket; + } rc_socket = rc_server.nextPendingConnection(); // check if host is allowed @@ -171,6 +179,8 @@ void RemoteControl::acceptConnection() std::cout << "*** Remote connection attempt from " << address.toStdString() << " (not in allowed list)" << std::endl; rc_socket->close(); + delete rc_socket; + rc_socket = 0; } else { @@ -237,6 +247,8 @@ void RemoteControl::startRead() { // FIXME: for now we assume 'close' command rc_socket->close(); + delete rc_socket; + rc_socket = 0; return; } else From a0bfd7c608a574b4ee889c36947de6bdce9a94db Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 9 Apr 2018 20:44:54 +0200 Subject: [PATCH 321/334] Update news file --- resources/news.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 9e99994..c751856 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,3 +1,10 @@ + + 2.xx.y: Released TBD + + FIXED: Memory leak in remote control interface. + IMPROVED: Add backspace key to frequency controller. + + 2.11.2: Released March 24, 2018 FIXED: Layout on low resolution monitors. From 35c2b9d3b60c5c22b868624c04bb82b4b323f189 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 13 Apr 2018 12:50:36 +0200 Subject: [PATCH 322/334] Update news file --- resources/news.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/news.txt b/resources/news.txt index c751856..6b1f674 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,5 +1,5 @@ - 2.xx.y: Released TBD + 2.11.3: Released April 13, 2018 FIXED: Memory leak in remote control interface. IMPROVED: Add backspace key to frequency controller. From a6217547f0238ee033e65ec0ef73c9cf6954c7ea Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 13 Apr 2018 12:55:03 +0200 Subject: [PATCH 323/334] Update text about dialog --- src/applications/gqrx/mainwindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 95240c6..33d3917 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2197,12 +2197,12 @@ void MainWindow::on_actionAbout_triggered() { QMessageBox::about(this, tr("About Gqrx"), tr("

This is Gqrx %1

" - "

Copyright (C) 2011-2017 Alexandru Csete & contributors.

" + "

Copyright (C) 2011-2018 Alexandru Csete & contributors.

" "

Gqrx is a software defined radio (SDR) receiver powered by " "GNU Radio and the Qt toolkit. " - "

Gqrx uses the GrOsmoSDR " + "

Gqrx uses the GrOsmoSDR " "input source block and and works with any input device supported by it, including " - "Funcube Dongles, RTL-SDR, Airspy, HackRF, RFSpace, BladeRF and USRP receivers." + "Funcube Dongle, RTL-SDR, Airspy, HackRF, RFSpace, BladeRF and USRP receivers." "

" "

You can download the latest version from the " "Gqrx website." From cc5cccb41573fb7e6c347e87911ebfd17ad6d404 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Fri, 13 Apr 2018 13:05:38 +0200 Subject: [PATCH 324/334] Version 2.11.3 --- CMakeLists.txt | 6 +++--- gqrx.pro | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d02a7f..7e8295c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,10 @@ cmake_minimum_required(VERSION 2.8.0) project(gqrx) set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "11") -set(${PROJECT_NAME}_PATCH "2") +set(${PROJECT_NAME}_PATCH "3") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -##add_definitions(-DVERSION="${VERSION}") +add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_definitions(-DVERSION="${GITVERSION}") +##add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 5d21448..f1857ac 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -72,14 +72,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - VER = $$system(git describe --abbrev=8) - ##VER = 2.11.2 + ##VER = $$system(git describe --abbrev=8) + VER = 2.11.3 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT VER = $$system(git describe --abbrev=1) - ##VER = 2.11.2 + VER = 2.11.3 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 2ec4f0826e9e82340e0c3a00e277c526da65c13d Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 16 Apr 2018 01:41:16 +0200 Subject: [PATCH 325/334] Reduce size of color selector button in bookmarks tag list Fixes issue #622. --- src/qtgui/dockbookmarks.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qtgui/dockbookmarks.ui b/src/qtgui/dockbookmarks.ui index 54deeb5..4a924bb 100644 --- a/src/qtgui/dockbookmarks.ui +++ b/src/qtgui/dockbookmarks.ui @@ -101,6 +101,12 @@ false + + 30 + + + 18 + true From 1253ee19840caa0d7e1c8365c7b421669458bca9 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 16 Apr 2018 01:42:45 +0200 Subject: [PATCH 326/334] Update news file --- resources/news.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/news.txt b/resources/news.txt index 6b1f674..71bdc21 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,4 +1,9 @@ + 2.11.4: Released April 17, 2018 + + FIXED: Reduced size of color selector button in bookmarks tag list. + + 2.11.3: Released April 13, 2018 FIXED: Memory leak in remote control interface. From 2838ca87c652beb1c9f6965b61388127cde3b725 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 16 Apr 2018 01:49:57 +0200 Subject: [PATCH 327/334] Version 2.11.4 --- CMakeLists.txt | 2 +- gqrx.pro | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e8295c..c218902 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8.0) project(gqrx) set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "11") -set(${PROJECT_NAME}_PATCH "3") +set(${PROJECT_NAME}_PATCH "4") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") add_definitions(-DVERSION="${VERSION}") diff --git a/gqrx.pro b/gqrx.pro index f1857ac..230c03b 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -73,13 +73,13 @@ CONFIG(debug, debug|release) { # Define version string (see below for releases) ##VER = $$system(git describe --abbrev=8) - VER = 2.11.3 + VER = 2.11.4 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT VER = $$system(git describe --abbrev=1) - VER = 2.11.3 + VER = 2.11.4 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 6dc627bc0854eb477b9a319ccbcf302bad1d7706 Mon Sep 17 00:00:00 2001 From: Darin Franklin Date: Tue, 15 May 2018 21:45:20 -0500 Subject: [PATCH 328/334] Fix crash in remote_control q command Use deleteLater() instead of delete so that the event loop can handle pending signals before deleting the socket object. --- src/applications/gqrx/remote_control.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/applications/gqrx/remote_control.cpp b/src/applications/gqrx/remote_control.cpp index 1ee8149..83cb337 100644 --- a/src/applications/gqrx/remote_control.cpp +++ b/src/applications/gqrx/remote_control.cpp @@ -81,7 +81,7 @@ void RemoteControl::stop_server() { if (rc_socket != 0) { rc_socket->close(); - delete rc_socket; + rc_socket->deleteLater(); rc_socket = 0; } @@ -168,7 +168,7 @@ void RemoteControl::acceptConnection() if (rc_socket) { rc_socket->close(); - delete rc_socket; + rc_socket->deleteLater(); } rc_socket = rc_server.nextPendingConnection(); @@ -179,7 +179,7 @@ void RemoteControl::acceptConnection() std::cout << "*** Remote connection attempt from " << address.toStdString() << " (not in allowed list)" << std::endl; rc_socket->close(); - delete rc_socket; + rc_socket->deleteLater(); rc_socket = 0; } else @@ -247,7 +247,7 @@ void RemoteControl::startRead() { // FIXME: for now we assume 'close' command rc_socket->close(); - delete rc_socket; + rc_socket->deleteLater(); rc_socket = 0; return; } From 5d9f8edfe3b1b175a9b1a7807b82886e2d0fb2e4 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 16 May 2018 23:30:55 +0200 Subject: [PATCH 329/334] Update readme and news files --- README.md | 1 + resources/news.txt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 86f0eb7..0693740 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ Pavel Stano Chris Kuethe Christian Lindner DL2VCL charlylima +Darin Franklin Stefano Leucci Daniil Cherednik Dominic Chen diff --git a/resources/news.txt b/resources/news.txt index 71bdc21..336cd2a 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -1,4 +1,9 @@ + 2.11.5: Released May 17, 2018 + + FIXED: Crash in remote control 'q' command. + + 2.11.4: Released April 17, 2018 FIXED: Reduced size of color selector button in bookmarks tag list. From 1e9193f143f65cb6639f1478f09f84c165189ae9 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Wed, 16 May 2018 23:32:13 +0200 Subject: [PATCH 330/334] Version 2.11.5 --- CMakeLists.txt | 2 +- gqrx.pro | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c218902..b60f976 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8.0) project(gqrx) set(${PROJECT_NAME}_MAJOR "2") set(${PROJECT_NAME}_MINOR "11") -set(${PROJECT_NAME}_PATCH "4") +set(${PROJECT_NAME}_PATCH "5") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") add_definitions(-DVERSION="${VERSION}") diff --git a/gqrx.pro b/gqrx.pro index 230c03b..00cbcac 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -73,13 +73,13 @@ CONFIG(debug, debug|release) { # Define version string (see below for releases) ##VER = $$system(git describe --abbrev=8) - VER = 2.11.4 + VER = 2.11.5 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT VER = $$system(git describe --abbrev=1) - VER = 2.11.4 + VER = 2.11.5 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin From 1bc4d9d5019daa737697500be98791c187f4a0ba Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Wed, 30 May 2018 14:03:35 +0200 Subject: [PATCH 331/334] Initialize adjusted minimum in dB scale --- src/qtgui/plotter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qtgui/plotter.cpp b/src/qtgui/plotter.cpp index b877546..1e01636 100644 --- a/src/qtgui/plotter.cpp +++ b/src/qtgui/plotter.cpp @@ -1715,6 +1715,7 @@ void CPlotter::calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adj step = 1; divs = high - low; int index = 0; + adjlow = (low / step) * step; while (divs > divswanted) { From cc8b8f0cc9c0b1dfda7cd0ae3392aacecff79abd Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Sat, 2 Jun 2018 00:54:36 +0200 Subject: [PATCH 332/334] Fix text in about box --- CMakeLists.txt | 4 ++-- gqrx.pro | 6 +++--- src/applications/gqrx/mainwindow.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b60f976..16bbd47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(${PROJECT_NAME}_MINOR "11") set(${PROJECT_NAME}_PATCH "5") set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") ##set(VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}") -add_definitions(-DVERSION="${VERSION}") +##add_definitions(-DVERSION="${VERSION}") # development version execute_process( @@ -16,7 +16,7 @@ execute_process( OUTPUT_VARIABLE GITVERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) -##add_definitions(-DVERSION="${GITVERSION}") +add_definitions(-DVERSION="${GITVERSION}") set(PACKAGE ${PROJECT_NAME}) diff --git a/gqrx.pro b/gqrx.pro index 00cbcac..0732bea 100644 --- a/gqrx.pro +++ b/gqrx.pro @@ -72,14 +72,14 @@ CONFIG(debug, debug|release) { #QMAKE_CFLAGS_DEBUG += '-g -O0' # Define version string (see below for releases) - ##VER = $$system(git describe --abbrev=8) - VER = 2.11.5 + VER = $$system(git describe --abbrev=8) + ##VER = 2.11.5 } else { DEFINES += QT_NO_DEBUG DEFINES += QT_NO_DEBUG_OUTPUT VER = $$system(git describe --abbrev=1) - VER = 2.11.5 + ##VER = 2.11.5 # Release binaries with gr bundled # QMAKE_RPATH & co won't work with origin diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 33d3917..aebef85 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2201,7 +2201,7 @@ void MainWindow::on_actionAbout_triggered() "

Gqrx is a software defined radio (SDR) receiver powered by " "GNU Radio and the Qt toolkit. " "

Gqrx uses the GrOsmoSDR " - "input source block and and works with any input device supported by it, including " + "input source block and works with any input device supported by it, including " "Funcube Dongle, RTL-SDR, Airspy, HackRF, RFSpace, BladeRF and USRP receivers." "

" "

You can download the latest version from the " From f94660a75ea4cfd432be58bb962cbc9eef404814 Mon Sep 17 00:00:00 2001 From: Alexander Fasching Date: Wed, 30 May 2018 11:11:54 +0200 Subject: [PATCH 333/334] Replace deprecated qt5_use_modules macro --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16bbd47..a010cbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.0) +cmake_minimum_required(VERSION 2.8.11) # Project name project(gqrx) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c0cbd3..2598f22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,10 +58,13 @@ endif(WIN32) ####################################################################################################################### # Build the program add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SOURCE} ${UIS_HDRS} ${RESOURCES_LIST}) -qt5_use_modules(${PROJECT_NAME} Core Network Widgets Svg) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11) # The pulse libraries are only needed on Linux. On other platforms they will not be found, so having them here is fine. target_link_libraries(${PROJECT_NAME} + Qt5::Core + Qt5::Network + Qt5::Widgets + Qt5::Svg ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES} ${GNURADIO_OSMOSDR_LIBRARIES} From 473c88533f6a0accb5565e4f6e330c92ec3efdb5 Mon Sep 17 00:00:00 2001 From: Alexandru Csete Date: Mon, 4 Jun 2018 23:53:05 +0200 Subject: [PATCH 334/334] Fix spelling error --- src/applications/gqrx/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index aebef85..b0d0ed1 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -2125,7 +2125,7 @@ void MainWindow::on_actionUserGroup_triggered() } /** - * Show news.txt in a dialog window. + * Show ftxt in a dialog window. */ void MainWindow::on_actionNews_triggered() { @@ -2153,7 +2153,7 @@ void MainWindow::showSimpleTextFile(const QString &resource_path, if (!news.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Unable to open file: " << news.fileName() << - " besause of error " << news.errorString(); + " because of error " << news.errorString(); return; }

Gqrx is a software defined radio (SDR) receiver powered by " "GNU Radio and the Qt toolkit. " "