From e109604afec35c78aa80fb90ec13e49c02005a8d Mon Sep 17 00:00:00 2001 From: andrei Date: Sat, 17 Oct 2020 14:54:17 +0300 Subject: [PATCH 01/20] Add plot bandwidth measurement to UI --- mainwindow.cpp | 6 +++++- mainwindow.h | 1 + plotview.cpp | 6 ++++-- plotview.h | 2 +- spectrogramcontrols.cpp | 17 +++++++++++++++++ spectrogramcontrols.h | 5 +++++ spectrogramplot.cpp | 30 ++++++++++++++++-------------- spectrogramplot.h | 6 +++--- tuner.cpp | 3 ++- tuner.h | 2 +- 10 files changed, 55 insertions(+), 23 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index b5aa3ac..fb6c06b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -38,7 +38,10 @@ MainWindow::MainWindow() input = new InputSource(); - plots = new PlotView(input); + QSettings settings; + tuner = new Tuner(settings.value("FFTSize", 9).toInt(), this); + + plots = new PlotView(input, tuner); setCentralWidget(plots); // Connect dock inputs @@ -50,6 +53,7 @@ MainWindow::MainWindow() connect(dock->cursorsCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableCursors); connect(dock->scalesCheckBox, &QCheckBox::stateChanged, plots, &PlotView::enableScales); connect(dock->cursorSymbolsSpinBox, static_cast(&QSpinBox::valueChanged), plots, &PlotView::setCursorSegments); + connect(tuner, &Tuner::tunerMoved, dock, &SpectrogramControls::tunerMoved); // Connect dock outputs connect(plots, &PlotView::timeSelectionChanged, dock, &SpectrogramControls::timeSelectionChanged); diff --git a/mainwindow.h b/mainwindow.h index 187400c..439d4df 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -42,4 +42,5 @@ public slots: SpectrogramControls *dock; PlotView *plots; InputSource *input; + Tuner *tuner; }; diff --git a/plotview.cpp b/plotview.cpp index 5db1b2a..847ac60 100644 --- a/plotview.cpp +++ b/plotview.cpp @@ -34,7 +34,7 @@ #include #include "plots.h" -PlotView::PlotView(InputSource *input) : cursors(this), viewRange({0, 0}) +PlotView::PlotView(InputSource *input, Tuner *tuner) : cursors(this), viewRange({0, 0}) { mainSampleSource = input; setDragMode(QGraphicsView::ScrollHandDrag); @@ -43,9 +43,11 @@ PlotView::PlotView(InputSource *input) : cursors(this), viewRange({0, 0}) enableCursors(false); connect(&cursors, &Cursors::cursorsMoved, this, &PlotView::cursorsMoved); - spectrogramPlot = new SpectrogramPlot(std::shared_ptr>>(mainSampleSource)); + spectrogramPlot = new SpectrogramPlot(std::shared_ptr>>(mainSampleSource), tuner); auto tunerOutput = std::dynamic_pointer_cast>>(spectrogramPlot->output()); + connect(tuner, &Tuner::tunerMoved, spectrogramPlot, &SpectrogramPlot::tunerMoved); + enableScales(true); addPlot(spectrogramPlot); diff --git a/plotview.h b/plotview.h index d558936..81b50f3 100644 --- a/plotview.h +++ b/plotview.h @@ -34,7 +34,7 @@ class PlotView : public QGraphicsView, Subscriber Q_OBJECT public: - PlotView(InputSource *input); + PlotView(InputSource *input, Tuner *tuner); void setSampleRate(double rate); signals: diff --git a/spectrogramcontrols.cpp b/spectrogramcontrols.cpp index 08007d9..6d6e7f8 100644 --- a/spectrogramcontrols.cpp +++ b/spectrogramcontrols.cpp @@ -93,6 +93,9 @@ SpectrogramControls::SpectrogramControls(const QString & title, QWidget * parent symbolPeriodLabel = new QLabel(); layout->addRow(new QLabel(tr("Symbol period:")), symbolPeriodLabel); + bandwidthLabel = new QLabel(); + layout->addRow(new QLabel(tr("Bandwidth:")), bandwidthLabel); + widget->setLayout(layout); setWidget(widget); @@ -110,6 +113,7 @@ void SpectrogramControls::clearCursorLabels() rateLabel->setText(""); symbolPeriodLabel->setText(""); symbolRateLabel->setText(""); + bandwidthLabel->setText(""); } void SpectrogramControls::cursorsStateChanged(int state) @@ -226,3 +230,16 @@ void SpectrogramControls::zoomOut() { zoomLevelSlider->setValue(zoomLevelSlider->value() - 1); } + +void SpectrogramControls::tunerMoved(int deviation) +{ + // int deviation is width in pixels from plot + bandwidthLabel->setText(QString::number(getBandwidth(deviation)) + "kHz"); +} + +int SpectrogramControls::getBandwidth(int deviation) { + double rate = sampleRate->text().toDouble(); + double fftSize = pow(2, fftSizeSlider->value()); + double hzPerPx = rate / fftSize; + return deviation * hzPerPx / 1000 * 2; +} \ No newline at end of file diff --git a/spectrogramcontrols.h b/spectrogramcontrols.h index abe06d6..f1a1255 100644 --- a/spectrogramcontrols.h +++ b/spectrogramcontrols.h @@ -27,6 +27,7 @@ #include #include #include +#include "tuner.h" class SpectrogramControls : public QDockWidget { @@ -44,6 +45,7 @@ public slots: void timeSelectionChanged(float time); void zoomIn(); void zoomOut(); + void tunerMoved(int deviation); private slots: void fftSizeChanged(int value); @@ -58,6 +60,7 @@ private slots: QFormLayout *layout; void clearCursorLabels(); void fftOrZoomChanged(void); + int getBandwidth(int deviation); public: QPushButton *fileOpenButton; @@ -72,5 +75,7 @@ private slots: QLabel *periodLabel; QLabel *symbolRateLabel; QLabel *symbolPeriodLabel; + QLabel *bandwidthLabel; QCheckBox *scalesCheckBox; + }; diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index 975c69b..ea3e913 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -31,8 +31,10 @@ #include "util.h" -SpectrogramPlot::SpectrogramPlot(std::shared_ptr>> src) : Plot(src), inputSource(src), fftSize(512), tuner(fftSize, this) +SpectrogramPlot::SpectrogramPlot(std::shared_ptr>> src, Tuner *tuner) + : Plot(src), inputSource(src), fftSize(512) //, tuner(fftSize, this) { + this->tuner = tuner; setFFTSize(fftSize); zoomLevel = 1; powerMax = 0.0f; @@ -46,7 +48,7 @@ SpectrogramPlot::SpectrogramPlot(std::shared_ptr(src); - connect(&tuner, &Tuner::tunerMoved, this, &SpectrogramPlot::tunerMoved); +// connect(&tuner, &Tuner::tunerMoved, this, &SpectrogramPlot::tunerMoved); } void SpectrogramPlot::invalidateEvent() @@ -62,7 +64,7 @@ void SpectrogramPlot::invalidateEvent() void SpectrogramPlot::paintFront(QPainter &painter, QRect &rect, range_t sampleRange) { if (tunerEnabled()) - tuner.paintFront(painter, rect, sampleRange); + tuner->paintFront(painter, rect, sampleRange); if (frequencyScaleEnabled) paintFrequencyScale(painter, rect); @@ -248,13 +250,13 @@ int SpectrogramPlot::getStride() float SpectrogramPlot::getTunerPhaseInc() { - auto freq = 0.5f - tuner.centre() / (float)fftSize; + auto freq = 0.5f - tuner->centre() / (float)fftSize; return freq * Tau; } std::vector SpectrogramPlot::getTunerTaps() { - float cutoff = tuner.deviation() / (float)fftSize; + float cutoff = tuner->deviation() / (float)fftSize; float gain = pow(10.0f, powerMax / -10.0f); auto atten = 60.0f; auto len = estimate_req_filter_len(std::min(cutoff, 0.05f), atten); @@ -273,7 +275,7 @@ int SpectrogramPlot::linesPerTile() bool SpectrogramPlot::mouseEvent(QEvent::Type type, QMouseEvent event) { if (tunerEnabled()) - return tuner.mouseEvent(type, event); + return tuner->mouseEvent(type, event); return false; } @@ -299,18 +301,18 @@ void SpectrogramPlot::setFFTSize(int size) } else { setHeight(fftSize); } - auto dev = tuner.deviation(); - auto centre = tuner.centre(); - tuner.setHeight(height()); - tuner.setDeviation( dev * sizeScale ); - tuner.setCentre( centre * sizeScale ); + auto dev = tuner->deviation(); + auto centre = tuner->centre(); + tuner->setHeight(height()); + tuner->setDeviation( dev * sizeScale ); + tuner->setCentre( centre * sizeScale ); } void SpectrogramPlot::setPowerMax(int power) { powerMax = power; pixmapCache.clear(); - tunerMoved(); + tunerMoved(666); } void SpectrogramPlot::setPowerMin(int power) @@ -339,11 +341,11 @@ bool SpectrogramPlot::tunerEnabled() return (tunerTransform->subscriberCount() > 0); } -void SpectrogramPlot::tunerMoved() +void SpectrogramPlot::tunerMoved(int deviation) { tunerTransform->setFrequency(getTunerPhaseInc()); tunerTransform->setTaps(getTunerTaps()); - tunerTransform->setRelativeBandwith(tuner.deviation() * 2.0 / height()); + tunerTransform->setRelativeBandwith(deviation * 2.0 / height()); // TODO: for invalidating traceplot cache, this shouldn't really go here QPixmapCache::clear(); diff --git a/spectrogramplot.h b/spectrogramplot.h index ffe1d6a..873b46d 100644 --- a/spectrogramplot.h +++ b/spectrogramplot.h @@ -38,7 +38,7 @@ class SpectrogramPlot : public Plot Q_OBJECT public: - SpectrogramPlot(std::shared_ptr>> src); + SpectrogramPlot(std::shared_ptr>> src, Tuner *tuner); void invalidateEvent() override; std::shared_ptr output() override; void paintFront(QPainter &painter, QRect &rect, range_t sampleRange) override; @@ -54,12 +54,13 @@ public slots: void setPowerMax(int power); void setPowerMin(int power); void setZoomLevel(int zoom); - void tunerMoved(); + void tunerMoved(int deviation); private: const int linesPerGraduation = 50; static const int tileSize = 65536; // This must be a multiple of the maximum FFT size + Tuner *tuner; std::shared_ptr>> inputSource; std::unique_ptr fft; std::unique_ptr window; @@ -74,7 +75,6 @@ public slots: size_t sampleRate; bool frequencyScaleEnabled; - Tuner tuner; std::shared_ptr tunerTransform; QPixmap* getPixmapTile(size_t tile); diff --git a/tuner.cpp b/tuner.cpp index 6ccac61..c6a5b46 100644 --- a/tuner.cpp +++ b/tuner.cpp @@ -109,6 +109,7 @@ void Tuner::setDeviation(int dev) { _deviation = std::max(1, dev); updateCursors(); + emit tunerMoved(_deviation); } void Tuner::setHeight(int height) @@ -120,5 +121,5 @@ void Tuner::updateCursors() { minCursor->setPos(cfCursor->pos() - _deviation); maxCursor->setPos(cfCursor->pos() + _deviation); - emit tunerMoved(); + emit tunerMoved(_deviation); } diff --git a/tuner.h b/tuner.h index 958d9a7..d761baa 100644 --- a/tuner.h +++ b/tuner.h @@ -44,7 +44,7 @@ public slots: void cursorMoved(); signals: - void tunerMoved(); + void tunerMoved(int deviation); private: void updateCursors(); From 5ecee1908db5f1d178f04de1637fe38ad30b009d Mon Sep 17 00:00:00 2001 From: schneider Date: Sat, 14 Nov 2020 01:12:47 +0100 Subject: [PATCH 02/20] fix(plotview): Implement showEvent() as an empty stub Closes #171 --- plotview.cpp | 5 +++++ plotview.h | 1 + 2 files changed, 6 insertions(+) diff --git a/plotview.cpp b/plotview.cpp index 847ac60..d74496a 100644 --- a/plotview.cpp +++ b/plotview.cpp @@ -534,6 +534,11 @@ void PlotView::scrollContentsBy(int dx, int dy) updateView(); } +void PlotView::showEvent(QShowEvent *event) +{ + // Intentionally left blank. See #171 +} + void PlotView::updateViewRange(bool reCenter) { // Update current view diff --git a/plotview.h b/plotview.h index 81b50f3..528add4 100644 --- a/plotview.h +++ b/plotview.h @@ -59,6 +59,7 @@ public slots: void resizeEvent(QResizeEvent * event) override; void scrollContentsBy(int dx, int dy) override; bool viewportEvent(QEvent *event) override; + void showEvent(QShowEvent *event) override; private: Cursors cursors; From 41245ec22b6675e3e8300dc420d3277aa5d73a68 Mon Sep 17 00:00:00 2001 From: sanjay-cpu Date: Thu, 15 Oct 2020 20:19:31 +0000 Subject: [PATCH 03/20] Travis-ci: added support for ppc64le --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ee3f9fa..2a2b203 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,9 @@ dist: bionic os: - linux - osx - +arch: + - amd64 + - ppc64le compiler: - gcc - clang @@ -18,6 +20,8 @@ matrix: # /usr/bin/gcc on OS X is clang, so it's not meaningful to build against both. - os: osx compiler: gcc + - os: osx + arch: ppc64le addons: apt: From 321c7d57b096af9ece5ebbf989a011bc0f0f14e9 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Sat, 5 Dec 2020 16:15:53 +0000 Subject: [PATCH 04/20] Setup Github Actions closes #178 --- .github/workflows/build.yml | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..9ba400f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,45 @@ +name: Build + +on: [push] + +env: + BUILD_TYPE: Release + # For macOS qt keg-only package + CMAKE_PREFIX_PATH: '/usr/local/opt/qt' + +jobs: + build: + strategy: + matrix: + os: ['macos-latest', 'ubuntu-latest'] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + + - name: Install dependencies (macOS) + run: brew install fftw liquid-dsp qt5 + if: matrix.os == 'macos-latest' + + - name: Install dependencies (Ubuntu) + run: sudo apt install libfftw3-dev libliquid-dev qtbase5-dev + if: matrix.os == 'ubuntu-latest' + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake --build . --config $BUILD_TYPE + + - name: Test + working-directory: ${{runner.workspace}}/build + shell: bash + run: ctest -C $BUILD_TYPE + From 160ece39d36b28ece0ce5ecc88a0769d2deb7a66 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Sat, 5 Dec 2020 18:32:21 +0000 Subject: [PATCH 05/20] Drop travis-ci --- .travis.yml | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2a2b203..0000000 --- a/.travis.yml +++ /dev/null @@ -1,47 +0,0 @@ -language: c - -cache: apt - -sudo: required -dist: bionic - -os: - - linux - - osx -arch: - - amd64 - - ppc64le -compiler: - - gcc - - clang - -matrix: - exclude: - # /usr/bin/gcc on OS X is clang, so it's not meaningful to build against both. - - os: osx - compiler: gcc - - os: osx - arch: ppc64le - -addons: - apt: - sources: -# - ubuntu-sdk-team - packages: - - qtbase5-dev - - qtdeclarative5-dev - - libfftw3-dev - - libliquid-dev - -before_install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - # cmake and pkg-config are already installed. - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt5 fftw liquid-dsp; fi - -script: - - mkdir build - - cd build - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export CMAKE_PREFIX_PATH=$(brew --prefix qt5)/lib/cmake; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then DYLIB_SUFFIX=dylib; else DYLIB_SUFFIX=so; fi - - CFLAGS="-g -Wall -Wextra -Werror -Wno-zero-length-array" cmake .. - - make From 1d746d5eff687cc82d1436dfa1b04c21e7e45bcc Mon Sep 17 00:00:00 2001 From: schneider Date: Sat, 14 Nov 2020 04:35:26 +0100 Subject: [PATCH 06/20] fix(spectrogramplot): Avoid infinite loop at extremely high sample rates --- spectrogramplot.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index ea3e913..f7f5724 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -72,6 +72,14 @@ void SpectrogramPlot::paintFront(QPainter &painter, QRect &rect, range_t void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) { + if (sampleRate == 0) { + return; + } + + if (sampleRate / 2 > UINT64_MAX) { + return; + } + // At which pixel is F_+sampleRate/2 int y = rect.y(); @@ -82,7 +90,7 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) double bwPerPixel = (double)sampleRate / plotHeight; int tickHeight = 50; - int bwPerTick = 10 * pow(10, floor(log(bwPerPixel * tickHeight) / log(10))); + uint64_t bwPerTick = 10 * pow(10, floor(log(bwPerPixel * tickHeight) / log(10))); if (bwPerTick < 1) { return; @@ -95,7 +103,7 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) QFontMetrics fm(painter.font()); - int tick = 0; + uint64_t tick = 0; while (tick <= sampleRate / 2) { @@ -109,12 +117,14 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) if (tick != 0) { char buf[128]; - if (bwPerTick % 1000000 == 0) { - snprintf(buf, sizeof(buf), "-%d MHz", (int)tick / 1000000); + if (bwPerTick % 1000000000 == 0) { + snprintf(buf, sizeof(buf), "-%lu GHz", tick / 1000000000); + } else if (bwPerTick % 1000000 == 0) { + snprintf(buf, sizeof(buf), "-%lu MHz", tick / 1000000); } else if(bwPerTick % 1000 == 0) { - snprintf(buf, sizeof(buf), "-%d kHz", tick / 1000); + snprintf(buf, sizeof(buf), "-%lu kHz", tick / 1000); } else { - snprintf(buf, sizeof(buf), "-%d Hz", tick); + snprintf(buf, sizeof(buf), "-%lu Hz", tick); } if (!inputSource->realSignal()) From 6d2a59f332795ef44051ab6fbef0f51ea65a6caa Mon Sep 17 00:00:00 2001 From: schneider Date: Thu, 30 Jan 2020 18:30:13 +0100 Subject: [PATCH 07/20] feat(sigmf): Add support for SigMF recordings --- CMakeLists.txt | 5 ++- inputsource.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++- inputsource.h | 2 + mainwindow.cpp | 7 ++++ mainwindow.h | 3 +- samplesource.cpp | 6 +++ samplesource.h | 16 ++++++++ spectrogramplot.cpp | 45 +++++++++++++++++++++- spectrogramplot.h | 5 ++- util.h | 1 + 10 files changed, 175 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ddb0bd9..b8f7285 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,7 @@ if (NOT CMAKE_CXX_FLAGS) endif (NOT CMAKE_CXX_FLAGS) # This only works in cmake >3.1 -#set_property(TARGET inspectrum PROPERTY CXX_STANDARD 11) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") +set(CMAKE_CXX_STANDARD 14) list(APPEND inspectrum_sources abstractsamplesource.cpp @@ -61,6 +60,7 @@ find_package(Qt5Widgets REQUIRED) find_package(Qt5Concurrent REQUIRED) find_package(FFTW REQUIRED) find_package(Liquid REQUIRED) +find_package(libsigmf REQUIRED) include_directories( ${FFTW_INCLUDES} @@ -71,6 +71,7 @@ add_executable(inspectrum ${EXE_ARGS} ${inspectrum_sources}) target_link_libraries(inspectrum Qt5::Core Qt5::Widgets Qt5::Concurrent + libsigmf::libsigmf ${FFTW_LIBRARIES} ${LIQUID_LIBRARIES} ) diff --git a/inputsource.cpp b/inputsource.cpp index 6a7ebac..caae783 100644 --- a/inputsource.cpp +++ b/inputsource.cpp @@ -29,6 +29,19 @@ #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + class ComplexF32SampleAdapter : public SampleAdapter { public: size_t sampleSize() override { @@ -181,6 +194,63 @@ void InputSource::cleanup() } } +void InputSource::readMetaData(const QString &filename) +{ + QFile datafile(filename); + if (!datafile.open(QFile::ReadOnly | QIODevice::Text)) { + throw std::runtime_error("Error while opening meta data file: " + datafile.errorString().toStdString()); + } + + sigmf::SigMF, + sigmf::Capture, + sigmf::Annotation > metaData = json::parse(datafile.readAll()); + + auto global_core = metaData.global.access(); + + if(global_core.datatype.compare("cf32_le") == 0) { + sampleAdapter = std::unique_ptr(new ComplexF32SampleAdapter()); + } else if(global_core.datatype.compare("ci16_le") == 0) { + sampleAdapter = std::unique_ptr(new ComplexS16SampleAdapter()); + } else if(global_core.datatype.compare("ci8") == 0) { + sampleAdapter = std::unique_ptr(new ComplexS8SampleAdapter()); + } else if(global_core.datatype.compare("cu8") == 0) { + sampleAdapter = std::unique_ptr(new ComplexU8SampleAdapter()); + } else if(global_core.datatype.compare("rf32_le") == 0) { + sampleAdapter = std::unique_ptr(new RealF32SampleAdapter()); + _realSignal = true; + } else if(global_core.datatype.compare("ri16_le") == 0) { + sampleAdapter = std::unique_ptr(new RealS16SampleAdapter()); + _realSignal = true; + } else if(global_core.datatype.compare("ri8") == 0) { + sampleAdapter = std::unique_ptr(new RealS8SampleAdapter()); + _realSignal = true; + } else if(global_core.datatype.compare("ru8") == 0) { + sampleAdapter = std::unique_ptr(new RealU8SampleAdapter()); + _realSignal = true; + } else { + throw std::runtime_error("SigMF meta data specifies unsupported datatype"); + } + + setSampleRate(global_core.sample_rate); + + for(auto capture : metaData.captures) { + auto core = capture.access(); + frequency = core.frequency; + } + + for(auto annotation : metaData.annotations) { + Annotation a; + auto core = annotation.access(); + + a.sampleRange = range_t{core.sample_start, core.sample_start + core.sample_count - 1}; + a.frequencyRange = range_t{core.freq_lower_edge, core.freq_upper_edge}; + a.description = QString::fromStdString(core.description); + + annotationList.append(a); + } +} + + void InputSource::openFile(const char *filename) { QFileInfo fileInfo(filename); @@ -218,7 +288,27 @@ void InputSource::openFile(const char *filename) sampleAdapter = std::unique_ptr(new ComplexF32SampleAdapter()); } - std::unique_ptr file(new QFile(filename)); + QString dataFilename; + QString metaFilename; + + if (suffix == "sigmf-meta") { + dataFilename = fileInfo.path() + "/" + fileInfo.completeBaseName() + ".sigmf-data"; + metaFilename = filename; + readMetaData(metaFilename); + } + else if (suffix == "sigmf-data") { + dataFilename = filename; + metaFilename = fileInfo.path() + "/" + fileInfo.completeBaseName() + ".sigmf-meta"; + readMetaData(metaFilename); + } + else if (suffix == "sigmf") { + throw std::runtime_error("SigMF archives are not supported. Consider extracting a recording."); + } + else { + dataFilename = filename; + } + + std::unique_ptr file(new QFile(dataFilename)); if (!file->open(QFile::ReadOnly)) { throw std::runtime_error(file->errorString().toStdString()); } diff --git a/inputsource.h b/inputsource.h index d6d76e0..dd55092 100644 --- a/inputsource.h +++ b/inputsource.h @@ -41,6 +41,8 @@ class InputSource : public SampleSource> std::string _fmt; bool _realSignal = false; + void readMetaData(const QString &filename); + public: InputSource(); ~InputSource(); diff --git a/mainwindow.cpp b/mainwindow.cpp index fb6c06b..28c780d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -37,6 +37,7 @@ MainWindow::MainWindow() addDockWidget(Qt::LeftDockWidgetArea, dock); input = new InputSource(); + input->subscribe(this); QSettings settings; tuner = new Tuner(settings.value("FFTSize", 9).toInt(), this); @@ -100,6 +101,12 @@ void MainWindow::openFile(QString fileName) } } +void MainWindow::invalidateEvent() +{ + plots->setSampleRate(input->rate()); + setSampleRate(input->rate()); +} + void MainWindow::setSampleRate(QString rate) { auto sampleRate = rate.toDouble(); diff --git a/mainwindow.h b/mainwindow.h index 439d4df..c7a45a6 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -24,7 +24,7 @@ #include "spectrogramcontrols.h" #include "plotview.h" -class MainWindow : public QMainWindow +class MainWindow : public QMainWindow, Subscriber { Q_OBJECT @@ -37,6 +37,7 @@ public slots: void setSampleRate(QString rate); void setSampleRate(double rate); void setFormat(QString fmt); + void invalidateEvent() override; private: SpectrogramControls *dock; diff --git a/samplesource.cpp b/samplesource.cpp index 619a2cd..3d6eaf0 100644 --- a/samplesource.cpp +++ b/samplesource.cpp @@ -25,5 +25,11 @@ std::type_index SampleSource::sampleType() return typeid(T); } +template +double SampleSource::getFrequency() +{ + return frequency; +} + template class SampleSource>; template class SampleSource; diff --git a/samplesource.h b/samplesource.h index ed0c0e3..9995eb4 100644 --- a/samplesource.h +++ b/samplesource.h @@ -23,9 +23,23 @@ #include #include "abstractsamplesource.h" +#include "util.h" +#include +#include + +class Annotation +{ +public: + range_t sampleRange; + range_t frequencyRange; + QString description; +}; + template class SampleSource : public AbstractSampleSource { +protected: + double frequency; public: virtual ~SampleSource() {}; @@ -35,6 +49,8 @@ class SampleSource : public AbstractSampleSource virtual size_t count() = 0; virtual double rate() = 0; virtual float relativeBandwidth() = 0; + QList annotationList; std::type_index sampleType() override; virtual bool realSignal() { return false; }; + double getFrequency(); }; diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index f7f5724..d91b4e9 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -68,6 +68,7 @@ void SpectrogramPlot::paintFront(QPainter &painter, QRect &rect, range_t if (frequencyScaleEnabled) paintFrequencyScale(painter, rect); + paintAnnotations(painter, rect, sampleRange); } void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) @@ -157,6 +158,48 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) painter.restore(); } +void SpectrogramPlot::paintAnnotations(QPainter &painter, QRect &rect, range_t sampleRange) +{ + // Pixel (from the top) at which 0 Hz sits + int zero = rect.y() + rect.height() / 2; + + painter.save(); + QPen pen(Qt::white, 1, Qt::SolidLine); + painter.setPen(pen); + QFontMetrics fm(painter.font()); + + for (int i = 0; i < inputSource->annotationList.size(); i++) { + Annotation a = inputSource->annotationList.at(i); + + uint64_t descriptionLength = fm.boundingRect(a.description).width() * getStride(); + + // Check if: + // (1) End of annotation (might be maximum, or end of description text) is still visible in time + // (2) Part of the annotation is already visible in time + // + // Currently there is no check if the annotation is visible in frequency. This is a + // possible performance improvement + // + size_t start = a.sampleRange.minimum; + size_t end = std::max(a.sampleRange.minimum + descriptionLength, a.sampleRange.maximum); + + if(start <= sampleRange.maximum && end >= sampleRange.minimum) { + + double frequency = a.frequencyRange.maximum - inputSource->getFrequency(); + int x = (a.sampleRange.minimum - sampleRange.minimum) / getStride(); + int y = zero - frequency / sampleRate * rect.height(); + int height = (a.frequencyRange.maximum - a.frequencyRange.minimum) / sampleRate * rect.height(); + int width = (a.sampleRange.maximum - a.sampleRange.minimum) / getStride(); + + // Draw the description 2 pixels above the box + painter.drawText(x, y - 2, a.description); + painter.drawRect(x, y, width, height); + } + } + + painter.restore(); +} + void SpectrogramPlot::paintMid(QPainter &painter, QRect &rect, range_t sampleRange) { if (!inputSource || inputSource->count() == 0) @@ -336,7 +379,7 @@ void SpectrogramPlot::setZoomLevel(int zoom) zoomLevel = zoom; } -void SpectrogramPlot::setSampleRate(size_t rate) +void SpectrogramPlot::setSampleRate(double rate) { sampleRate = rate; } diff --git a/spectrogramplot.h b/spectrogramplot.h index 873b46d..af4b794 100644 --- a/spectrogramplot.h +++ b/spectrogramplot.h @@ -45,7 +45,7 @@ class SpectrogramPlot : public Plot void paintMid(QPainter &painter, QRect &rect, range_t sampleRange) override; bool mouseEvent(QEvent::Type type, QMouseEvent event) override; std::shared_ptr>> input() { return inputSource; }; - void setSampleRate(size_t sampleRate); + void setSampleRate(double sampleRate); bool tunerEnabled(); void enableScales(bool enabled); @@ -72,7 +72,7 @@ public slots: int zoomLevel; float powerMax; float powerMin; - size_t sampleRate; + double sampleRate; bool frequencyScaleEnabled; std::shared_ptr tunerTransform; @@ -85,6 +85,7 @@ public slots: std::vector getTunerTaps(); int linesPerTile(); void paintFrequencyScale(QPainter &painter, QRect &rect); + void paintAnnotations(QPainter &painter, QRect &rect, range_t sampleRange); }; class TileCacheKey diff --git a/util.h b/util.h index 0e22e9d..157d401 100644 --- a/util.h +++ b/util.h @@ -57,6 +57,7 @@ struct range_t { range_t& operator=(const range_t &other) { minimum = other.minimum; maximum = other.maximum; + return *this; } range_t& operator=(const std::initializer_list &other) { From 156782d36d4ae4e4ac47d524187eef3f6185bce7 Mon Sep 17 00:00:00 2001 From: schneider Date: Fri, 19 Feb 2021 00:17:33 +0100 Subject: [PATCH 08/20] fix(mainwindow): Only update the sample rate text box if needed This prevents the cursor from jumping when changing the sample rate. Also prevents the text box from changing representation (e.g. from normal to scientific). --- mainwindow.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 28c780d..f1adf7a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -104,7 +104,14 @@ void MainWindow::openFile(QString fileName) void MainWindow::invalidateEvent() { plots->setSampleRate(input->rate()); - setSampleRate(input->rate()); + + // Only update the text box if it is not already representing + // the current value. Otherwise the cursor might jump or the + // representation might change (e.g. to scientific). + double currentValue = dock->sampleRate->text().toDouble(); + if(QString::number(input->rate()) != QString::number(currentValue)) { + setSampleRate(input->rate()); + } } void MainWindow::setSampleRate(QString rate) From cd2a76b1c002ad993d9a4536ccf958aafaa476b9 Mon Sep 17 00:00:00 2001 From: schneider Date: Sat, 20 Feb 2021 12:35:23 +0100 Subject: [PATCH 09/20] feat(sigmf): Only compile support if libsigmf is found --- CMakeLists.txt | 14 ++++++++++++-- inputsource.cpp | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8f7285..f03e61b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ find_package(Qt5Widgets REQUIRED) find_package(Qt5Concurrent REQUIRED) find_package(FFTW REQUIRED) find_package(Liquid REQUIRED) -find_package(libsigmf REQUIRED) +find_package(libsigmf QUIET) include_directories( ${FFTW_INCLUDES} @@ -71,10 +71,20 @@ add_executable(inspectrum ${EXE_ARGS} ${inspectrum_sources}) target_link_libraries(inspectrum Qt5::Core Qt5::Widgets Qt5::Concurrent - libsigmf::libsigmf ${FFTW_LIBRARIES} ${LIQUID_LIBRARIES} ) + +if (libsigmf_FOUND) + message("-- libsigmf found. Enabling SigMF support") + target_link_libraries(inspectrum + libsigmf::libsigmf + ) + add_definitions(-DENABLE_SIGMF) +else() + message("-- libsigmf not found. Disabling SigMF support") +endif() + set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") install(TARGETS inspectrum RUNTIME DESTINATION ${INSTALL_DEFAULT_BINDIR}) diff --git a/inputsource.cpp b/inputsource.cpp index caae783..59abe38 100644 --- a/inputsource.cpp +++ b/inputsource.cpp @@ -29,7 +29,9 @@ #include +#if ENABLE_SIGMF #include +#endif #include #include @@ -194,6 +196,7 @@ void InputSource::cleanup() } } +#if ENABLE_SIGMF void InputSource::readMetaData(const QString &filename) { QFile datafile(filename); @@ -249,6 +252,7 @@ void InputSource::readMetaData(const QString &filename) annotationList.append(a); } } +#endif void InputSource::openFile(const char *filename) @@ -289,6 +293,8 @@ void InputSource::openFile(const char *filename) } QString dataFilename; + +#if ENABLE_SIGMF QString metaFilename; if (suffix == "sigmf-meta") { @@ -304,6 +310,11 @@ void InputSource::openFile(const char *filename) else if (suffix == "sigmf") { throw std::runtime_error("SigMF archives are not supported. Consider extracting a recording."); } +#else + if (suffix == "sigmf-meta" || suffix == "sigmf-data" || suffix == "sigmf") { + throw std::runtime_error("Support for SigMF recordings is not enabled"); + } +#endif else { dataFilename = filename; } From 541f7348fc79664d11c9727c0b13c6bbfb5c7b66 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 22 Feb 2021 20:45:15 +0000 Subject: [PATCH 10/20] spectrogramplot: match types for std::max to fix mac build --- spectrogramplot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index d91b4e9..769255a 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -171,7 +171,7 @@ void SpectrogramPlot::paintAnnotations(QPainter &painter, QRect &rect, range_tannotationList.size(); i++) { Annotation a = inputSource->annotationList.at(i); - uint64_t descriptionLength = fm.boundingRect(a.description).width() * getStride(); + size_t descriptionLength = fm.boundingRect(a.description).width() * getStride(); // Check if: // (1) End of annotation (might be maximum, or end of description text) is still visible in time From c0d251adc03c9d1a104cce303bb8e31a774b18b8 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 22 Feb 2021 21:10:35 +0000 Subject: [PATCH 11/20] spectrogramplot: use bind as bind1st is deprecated --- spectrogramplot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index 769255a..ba719ef 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -316,7 +316,7 @@ std::vector SpectrogramPlot::getTunerTaps() auto taps = std::vector(len); liquid_firdes_kaiser(len, cutoff, atten, 0.0f, taps.data()); std::transform(taps.begin(), taps.end(), taps.begin(), - std::bind1st(std::multiplies(), gain)); + std::bind(std::multiplies(), std::placeholders::_1, gain)); return taps; } From 5828c4c9cbc45246691f55237fbb17427413c918 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 22 Feb 2021 21:17:44 +0000 Subject: [PATCH 12/20] inputsource: add missing virtual destructor for SampleAdapter --- inputsource.h | 1 + 1 file changed, 1 insertion(+) diff --git a/inputsource.h b/inputsource.h index dd55092..47b457c 100644 --- a/inputsource.h +++ b/inputsource.h @@ -28,6 +28,7 @@ class SampleAdapter { public: virtual size_t sampleSize() = 0; virtual void copyRange(const void* const src, size_t start, size_t length, std::complex* const dest) = 0; + virtual ~SampleAdapter() { }; }; class InputSource : public SampleSource> From 9bbf0f2a581bba09f279e2a9f08e43e3187c6a53 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 22 Feb 2021 21:44:53 +0000 Subject: [PATCH 13/20] use make_unique instead of new --- inputsource.cpp | 38 +++++++++++++++++++------------------- samplebuffer.cpp | 4 ++-- tunertransform.cpp | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/inputsource.cpp b/inputsource.cpp index 59abe38..50a617c 100644 --- a/inputsource.cpp +++ b/inputsource.cpp @@ -211,24 +211,24 @@ void InputSource::readMetaData(const QString &filename) auto global_core = metaData.global.access(); if(global_core.datatype.compare("cf32_le") == 0) { - sampleAdapter = std::unique_ptr(new ComplexF32SampleAdapter()); + sampleAdapter = std::make_unique(); } else if(global_core.datatype.compare("ci16_le") == 0) { - sampleAdapter = std::unique_ptr(new ComplexS16SampleAdapter()); + sampleAdapter = std::make_unique(); } else if(global_core.datatype.compare("ci8") == 0) { - sampleAdapter = std::unique_ptr(new ComplexS8SampleAdapter()); + sampleAdapter = std::make_unique(); } else if(global_core.datatype.compare("cu8") == 0) { - sampleAdapter = std::unique_ptr(new ComplexU8SampleAdapter()); + sampleAdapter = std::make_unique(); } else if(global_core.datatype.compare("rf32_le") == 0) { - sampleAdapter = std::unique_ptr(new RealF32SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else if(global_core.datatype.compare("ri16_le") == 0) { - sampleAdapter = std::unique_ptr(new RealS16SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else if(global_core.datatype.compare("ri8") == 0) { - sampleAdapter = std::unique_ptr(new RealS8SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else if(global_core.datatype.compare("ru8") == 0) { - sampleAdapter = std::unique_ptr(new RealU8SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else { throw std::runtime_error("SigMF meta data specifies unsupported datatype"); @@ -261,35 +261,35 @@ void InputSource::openFile(const char *filename) std::string suffix = std::string(fileInfo.suffix().toLower().toUtf8().constData()); if(_fmt!=""){ suffix = _fmt; } // allow fmt override if ((suffix == "cfile") || (suffix == "cf32") || (suffix == "fc32")) { - sampleAdapter = std::unique_ptr(new ComplexF32SampleAdapter()); + sampleAdapter = std::make_unique(); } else if ((suffix == "cs16") || (suffix == "sc16") || (suffix == "c16")) { - sampleAdapter = std::unique_ptr(new ComplexS16SampleAdapter()); + sampleAdapter = std::make_unique(); } else if ((suffix == "cs8") || (suffix == "sc8") || (suffix == "c8")) { - sampleAdapter = std::unique_ptr(new ComplexS8SampleAdapter()); + sampleAdapter = std::make_unique(); } else if ((suffix == "cu8") || (suffix == "uc8")) { - sampleAdapter = std::unique_ptr(new ComplexU8SampleAdapter()); + sampleAdapter = std::make_unique(); } else if (suffix == "f32") { - sampleAdapter = std::unique_ptr(new RealF32SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else if (suffix == "s16") { - sampleAdapter = std::unique_ptr(new RealS16SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else if (suffix == "s8") { - sampleAdapter = std::unique_ptr(new RealS8SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else if (suffix == "u8") { - sampleAdapter = std::unique_ptr(new RealU8SampleAdapter()); + sampleAdapter = std::make_unique(); _realSignal = true; } else { - sampleAdapter = std::unique_ptr(new ComplexF32SampleAdapter()); + sampleAdapter = std::make_unique(); } QString dataFilename; @@ -319,7 +319,7 @@ void InputSource::openFile(const char *filename) dataFilename = filename; } - std::unique_ptr file(new QFile(dataFilename)); + auto file = std::make_unique(dataFilename); if (!file->open(QFile::ReadOnly)) { throw std::runtime_error(file->errorString().toStdString()); } @@ -364,7 +364,7 @@ std::unique_ptr[]> InputSource::getSamples(size_t start, siz if (start + length > sampleCount) return nullptr; - std::unique_ptr[]> dest(new std::complex[length]); + auto dest = std::make_unique[]>(length); sampleAdapter->copyRange(mmapData, start, length, dest.get()); return dest; diff --git a/samplebuffer.cpp b/samplebuffer.cpp index f008a3c..4fb0e09 100644 --- a/samplebuffer.cpp +++ b/samplebuffer.cpp @@ -42,8 +42,8 @@ std::unique_ptr SampleBuffer::getSamples(size_t start, size_t if (samples == nullptr) return nullptr; - std::unique_ptr temp(new Tout[history + length]); - std::unique_ptr dest(new Tout[length]); + auto temp = std::make_unique(history + length); + auto dest = std::make_unique(length); QMutexLocker ml(&mutex); work(samples.get(), temp.get(), history + length, start); memcpy(dest.get(), temp.get() + history, length * sizeof(Tout)); diff --git a/tunertransform.cpp b/tunertransform.cpp index 11fed07..fc89a36 100644 --- a/tunertransform.cpp +++ b/tunertransform.cpp @@ -29,7 +29,7 @@ TunerTransform::TunerTransform(std::shared_ptr> void TunerTransform::work(void *input, void *output, int count, size_t sampleid) { auto out = static_cast*>(output); - std::unique_ptr[]> temp(new std::complex[count]); + auto temp = std::make_unique[]>(count); // Mix down nco_crcf mix = nco_crcf_create(LIQUID_NCO); From bef181931cb45151fe6f727192ac7d82ee95b9f7 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Sat, 27 Feb 2021 09:42:43 +0000 Subject: [PATCH 14/20] make a `src` directory --- CMakeLists.txt | 97 +------------------ src/CMakeLists.txt | 96 ++++++++++++++++++ .../abstractsamplesource.cpp | 0 .../abstractsamplesource.h | 0 amplitudedemod.cpp => src/amplitudedemod.cpp | 0 amplitudedemod.h => src/amplitudedemod.h | 0 cursor.cpp => src/cursor.cpp | 0 cursor.h => src/cursor.h | 0 cursors.cpp => src/cursors.cpp | 0 cursors.h => src/cursors.h | 0 fft.cpp => src/fft.cpp | 0 fft.h => src/fft.h | 0 frequencydemod.cpp => src/frequencydemod.cpp | 0 frequencydemod.h => src/frequencydemod.h | 0 inputsource.cpp => src/inputsource.cpp | 0 inputsource.h => src/inputsource.h | 0 main.cpp => src/main.cpp | 0 mainwindow.cpp => src/mainwindow.cpp | 0 mainwindow.h => src/mainwindow.h | 0 phasedemod.cpp => src/phasedemod.cpp | 0 phasedemod.h => src/phasedemod.h | 0 plot.cpp => src/plot.cpp | 0 plot.h => src/plot.h | 0 plots.cpp => src/plots.cpp | 0 plots.h => src/plots.h | 0 plotview.cpp => src/plotview.cpp | 0 plotview.h => src/plotview.h | 0 samplebuffer.cpp => src/samplebuffer.cpp | 0 samplebuffer.h => src/samplebuffer.h | 0 samplesource.cpp => src/samplesource.cpp | 0 samplesource.h => src/samplesource.h | 0 .../spectrogramcontrols.cpp | 0 .../spectrogramcontrols.h | 0 .../spectrogramplot.cpp | 0 spectrogramplot.h => src/spectrogramplot.h | 0 subscriber.h => src/subscriber.h | 0 threshold.cpp => src/threshold.cpp | 0 threshold.h => src/threshold.h | 0 traceplot.cpp => src/traceplot.cpp | 0 traceplot.h => src/traceplot.h | 0 tuner.cpp => src/tuner.cpp | 0 tuner.h => src/tuner.h | 0 tunertransform.cpp => src/tunertransform.cpp | 0 tunertransform.h => src/tunertransform.h | 0 util.cpp => src/util.cpp | 0 util.h => src/util.h | 0 46 files changed, 97 insertions(+), 96 deletions(-) create mode 100644 src/CMakeLists.txt rename abstractsamplesource.cpp => src/abstractsamplesource.cpp (100%) rename abstractsamplesource.h => src/abstractsamplesource.h (100%) rename amplitudedemod.cpp => src/amplitudedemod.cpp (100%) rename amplitudedemod.h => src/amplitudedemod.h (100%) rename cursor.cpp => src/cursor.cpp (100%) rename cursor.h => src/cursor.h (100%) rename cursors.cpp => src/cursors.cpp (100%) rename cursors.h => src/cursors.h (100%) rename fft.cpp => src/fft.cpp (100%) rename fft.h => src/fft.h (100%) rename frequencydemod.cpp => src/frequencydemod.cpp (100%) rename frequencydemod.h => src/frequencydemod.h (100%) rename inputsource.cpp => src/inputsource.cpp (100%) rename inputsource.h => src/inputsource.h (100%) rename main.cpp => src/main.cpp (100%) rename mainwindow.cpp => src/mainwindow.cpp (100%) rename mainwindow.h => src/mainwindow.h (100%) rename phasedemod.cpp => src/phasedemod.cpp (100%) rename phasedemod.h => src/phasedemod.h (100%) rename plot.cpp => src/plot.cpp (100%) rename plot.h => src/plot.h (100%) rename plots.cpp => src/plots.cpp (100%) rename plots.h => src/plots.h (100%) rename plotview.cpp => src/plotview.cpp (100%) rename plotview.h => src/plotview.h (100%) rename samplebuffer.cpp => src/samplebuffer.cpp (100%) rename samplebuffer.h => src/samplebuffer.h (100%) rename samplesource.cpp => src/samplesource.cpp (100%) rename samplesource.h => src/samplesource.h (100%) rename spectrogramcontrols.cpp => src/spectrogramcontrols.cpp (100%) rename spectrogramcontrols.h => src/spectrogramcontrols.h (100%) rename spectrogramplot.cpp => src/spectrogramplot.cpp (100%) rename spectrogramplot.h => src/spectrogramplot.h (100%) rename subscriber.h => src/subscriber.h (100%) rename threshold.cpp => src/threshold.cpp (100%) rename threshold.h => src/threshold.h (100%) rename traceplot.cpp => src/traceplot.cpp (100%) rename traceplot.h => src/traceplot.h (100%) rename tuner.cpp => src/tuner.cpp (100%) rename tuner.h => src/tuner.h (100%) rename tunertransform.cpp => src/tunertransform.cpp (100%) rename tunertransform.h => src/tunertransform.h (100%) rename util.cpp => src/util.cpp (100%) rename util.h => src/util.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f03e61b..beb1c4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,99 +2,4 @@ cmake_minimum_required(VERSION 2.8.11) project(inspectrum CXX) enable_testing() -set(CMAKE_AUTOMOC ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) -list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) - -# For OSX - don't clear RPATH on install -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - -if (MSVC) - #force std::complex<> typedefs in liquiddsp - add_definitions(-D_LIBCPP_COMPLEX) - - #enable math definitions in math.h - add_definitions(-D_USE_MATH_DEFINES) - - #build a graphical application without the console - option(BUILD_WIN32 "Build win32 app, false for console" TRUE) - if (BUILD_WIN32) - set(EXE_ARGS WIN32) - set(CMAKE_EXE_LINKER_FLAGS "/entry:mainCRTStartup ${CMAKE_EXE_LINKER_FLAGS}") - endif (BUILD_WIN32) -endif (MSVC) - -if (NOT CMAKE_CXX_FLAGS) - set(CMAKE_CXX_FLAGS "-O2") -endif (NOT CMAKE_CXX_FLAGS) - -# This only works in cmake >3.1 -set(CMAKE_CXX_STANDARD 14) - -list(APPEND inspectrum_sources - abstractsamplesource.cpp - amplitudedemod.cpp - cursor.cpp - cursors.cpp - main.cpp - fft.cpp - frequencydemod.cpp - mainwindow.cpp - inputsource.cpp - phasedemod.cpp - plot.cpp - plots.cpp - plotview.cpp - samplebuffer.cpp - samplesource.cpp - spectrogramcontrols.cpp - spectrogramplot.cpp - threshold.cpp - traceplot.cpp - tuner.cpp - tunertransform.cpp - util.cpp -) - -find_package(Qt5Widgets REQUIRED) -find_package(Qt5Concurrent REQUIRED) -find_package(FFTW REQUIRED) -find_package(Liquid REQUIRED) -find_package(libsigmf QUIET) - -include_directories( - ${FFTW_INCLUDES} - ${LIQUID_INCLUDES} -) - -add_executable(inspectrum ${EXE_ARGS} ${inspectrum_sources}) - -target_link_libraries(inspectrum - Qt5::Core Qt5::Widgets Qt5::Concurrent - ${FFTW_LIBRARIES} - ${LIQUID_LIBRARIES} -) - -if (libsigmf_FOUND) - message("-- libsigmf found. Enabling SigMF support") - target_link_libraries(inspectrum - libsigmf::libsigmf - ) - add_definitions(-DENABLE_SIGMF) -else() - message("-- libsigmf not found. Disabling SigMF support") -endif() - -set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") - -install(TARGETS inspectrum RUNTIME DESTINATION ${INSTALL_DEFAULT_BINDIR}) - -# Create uninstall target -configure_file( - ${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -@ONLY) - -add_custom_target(uninstall - ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -) +add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..3bdffde --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,96 @@ +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) + +# For OSX - don't clear RPATH on install +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +if (MSVC) + #force std::complex<> typedefs in liquiddsp + add_definitions(-D_LIBCPP_COMPLEX) + + #enable math definitions in math.h + add_definitions(-D_USE_MATH_DEFINES) + + #build a graphical application without the console + option(BUILD_WIN32 "Build win32 app, false for console" TRUE) + if (BUILD_WIN32) + set(EXE_ARGS WIN32) + set(CMAKE_EXE_LINKER_FLAGS "/entry:mainCRTStartup ${CMAKE_EXE_LINKER_FLAGS}") + endif (BUILD_WIN32) +endif (MSVC) + +if (NOT CMAKE_CXX_FLAGS) + set(CMAKE_CXX_FLAGS "-O2") +endif (NOT CMAKE_CXX_FLAGS) + +# This only works in cmake >3.1 +set(CMAKE_CXX_STANDARD 14) + +list(APPEND inspectrum_sources + abstractsamplesource.cpp + amplitudedemod.cpp + cursor.cpp + cursors.cpp + main.cpp + fft.cpp + frequencydemod.cpp + mainwindow.cpp + inputsource.cpp + phasedemod.cpp + plot.cpp + plots.cpp + plotview.cpp + samplebuffer.cpp + samplesource.cpp + spectrogramcontrols.cpp + spectrogramplot.cpp + threshold.cpp + traceplot.cpp + tuner.cpp + tunertransform.cpp + util.cpp +) + +find_package(Qt5Widgets REQUIRED) +find_package(Qt5Concurrent REQUIRED) +find_package(FFTW REQUIRED) +find_package(Liquid REQUIRED) +find_package(libsigmf QUIET) + +include_directories( + ${FFTW_INCLUDES} + ${LIQUID_INCLUDES} +) + +add_executable(inspectrum ${EXE_ARGS} ${inspectrum_sources}) + +target_link_libraries(inspectrum + Qt5::Core Qt5::Widgets Qt5::Concurrent + ${FFTW_LIBRARIES} + ${LIQUID_LIBRARIES} +) + +if (libsigmf_FOUND) + message("-- libsigmf found. Enabling SigMF support") + target_link_libraries(inspectrum + libsigmf::libsigmf + ) + add_definitions(-DENABLE_SIGMF) +else() + message("-- libsigmf not found. Disabling SigMF support") +endif() + +set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") + +install(TARGETS inspectrum RUNTIME DESTINATION ${INSTALL_DEFAULT_BINDIR}) + +# Create uninstall target +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +@ONLY) + +add_custom_target(uninstall + ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +) diff --git a/abstractsamplesource.cpp b/src/abstractsamplesource.cpp similarity index 100% rename from abstractsamplesource.cpp rename to src/abstractsamplesource.cpp diff --git a/abstractsamplesource.h b/src/abstractsamplesource.h similarity index 100% rename from abstractsamplesource.h rename to src/abstractsamplesource.h diff --git a/amplitudedemod.cpp b/src/amplitudedemod.cpp similarity index 100% rename from amplitudedemod.cpp rename to src/amplitudedemod.cpp diff --git a/amplitudedemod.h b/src/amplitudedemod.h similarity index 100% rename from amplitudedemod.h rename to src/amplitudedemod.h diff --git a/cursor.cpp b/src/cursor.cpp similarity index 100% rename from cursor.cpp rename to src/cursor.cpp diff --git a/cursor.h b/src/cursor.h similarity index 100% rename from cursor.h rename to src/cursor.h diff --git a/cursors.cpp b/src/cursors.cpp similarity index 100% rename from cursors.cpp rename to src/cursors.cpp diff --git a/cursors.h b/src/cursors.h similarity index 100% rename from cursors.h rename to src/cursors.h diff --git a/fft.cpp b/src/fft.cpp similarity index 100% rename from fft.cpp rename to src/fft.cpp diff --git a/fft.h b/src/fft.h similarity index 100% rename from fft.h rename to src/fft.h diff --git a/frequencydemod.cpp b/src/frequencydemod.cpp similarity index 100% rename from frequencydemod.cpp rename to src/frequencydemod.cpp diff --git a/frequencydemod.h b/src/frequencydemod.h similarity index 100% rename from frequencydemod.h rename to src/frequencydemod.h diff --git a/inputsource.cpp b/src/inputsource.cpp similarity index 100% rename from inputsource.cpp rename to src/inputsource.cpp diff --git a/inputsource.h b/src/inputsource.h similarity index 100% rename from inputsource.h rename to src/inputsource.h diff --git a/main.cpp b/src/main.cpp similarity index 100% rename from main.cpp rename to src/main.cpp diff --git a/mainwindow.cpp b/src/mainwindow.cpp similarity index 100% rename from mainwindow.cpp rename to src/mainwindow.cpp diff --git a/mainwindow.h b/src/mainwindow.h similarity index 100% rename from mainwindow.h rename to src/mainwindow.h diff --git a/phasedemod.cpp b/src/phasedemod.cpp similarity index 100% rename from phasedemod.cpp rename to src/phasedemod.cpp diff --git a/phasedemod.h b/src/phasedemod.h similarity index 100% rename from phasedemod.h rename to src/phasedemod.h diff --git a/plot.cpp b/src/plot.cpp similarity index 100% rename from plot.cpp rename to src/plot.cpp diff --git a/plot.h b/src/plot.h similarity index 100% rename from plot.h rename to src/plot.h diff --git a/plots.cpp b/src/plots.cpp similarity index 100% rename from plots.cpp rename to src/plots.cpp diff --git a/plots.h b/src/plots.h similarity index 100% rename from plots.h rename to src/plots.h diff --git a/plotview.cpp b/src/plotview.cpp similarity index 100% rename from plotview.cpp rename to src/plotview.cpp diff --git a/plotview.h b/src/plotview.h similarity index 100% rename from plotview.h rename to src/plotview.h diff --git a/samplebuffer.cpp b/src/samplebuffer.cpp similarity index 100% rename from samplebuffer.cpp rename to src/samplebuffer.cpp diff --git a/samplebuffer.h b/src/samplebuffer.h similarity index 100% rename from samplebuffer.h rename to src/samplebuffer.h diff --git a/samplesource.cpp b/src/samplesource.cpp similarity index 100% rename from samplesource.cpp rename to src/samplesource.cpp diff --git a/samplesource.h b/src/samplesource.h similarity index 100% rename from samplesource.h rename to src/samplesource.h diff --git a/spectrogramcontrols.cpp b/src/spectrogramcontrols.cpp similarity index 100% rename from spectrogramcontrols.cpp rename to src/spectrogramcontrols.cpp diff --git a/spectrogramcontrols.h b/src/spectrogramcontrols.h similarity index 100% rename from spectrogramcontrols.h rename to src/spectrogramcontrols.h diff --git a/spectrogramplot.cpp b/src/spectrogramplot.cpp similarity index 100% rename from spectrogramplot.cpp rename to src/spectrogramplot.cpp diff --git a/spectrogramplot.h b/src/spectrogramplot.h similarity index 100% rename from spectrogramplot.h rename to src/spectrogramplot.h diff --git a/subscriber.h b/src/subscriber.h similarity index 100% rename from subscriber.h rename to src/subscriber.h diff --git a/threshold.cpp b/src/threshold.cpp similarity index 100% rename from threshold.cpp rename to src/threshold.cpp diff --git a/threshold.h b/src/threshold.h similarity index 100% rename from threshold.h rename to src/threshold.h diff --git a/traceplot.cpp b/src/traceplot.cpp similarity index 100% rename from traceplot.cpp rename to src/traceplot.cpp diff --git a/traceplot.h b/src/traceplot.h similarity index 100% rename from traceplot.h rename to src/traceplot.h diff --git a/tuner.cpp b/src/tuner.cpp similarity index 100% rename from tuner.cpp rename to src/tuner.cpp diff --git a/tuner.h b/src/tuner.h similarity index 100% rename from tuner.h rename to src/tuner.h diff --git a/tunertransform.cpp b/src/tunertransform.cpp similarity index 100% rename from tunertransform.cpp rename to src/tunertransform.cpp diff --git a/tunertransform.h b/src/tunertransform.h similarity index 100% rename from tunertransform.h rename to src/tunertransform.h diff --git a/util.cpp b/src/util.cpp similarity index 100% rename from util.cpp rename to src/util.cpp diff --git a/util.h b/src/util.h similarity index 100% rename from util.h rename to src/util.h From f0d969fb2d97b447c78b9efeef7235f386753278 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 1 Mar 2021 15:06:04 +0000 Subject: [PATCH 15/20] Update minimum CMake version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index beb1c4c..462a682 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.11) +cmake_minimum_required(VERSION 3.1) project(inspectrum CXX) enable_testing() From 81d3f7784e1c9c6ff1b90593d44c2f317e91ad95 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 1 Mar 2021 15:25:31 +0000 Subject: [PATCH 16/20] Test build on more Ubuntu releases --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ba400f..cf415cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: build: strategy: matrix: - os: ['macos-latest', 'ubuntu-latest'] + os: ['macos-latest', 'ubuntu-20.04', 'ubuntu-18.04'] runs-on: ${{ matrix.os }} steps: @@ -23,7 +23,7 @@ jobs: - name: Install dependencies (Ubuntu) run: sudo apt install libfftw3-dev libliquid-dev qtbase5-dev - if: matrix.os == 'ubuntu-latest' + if: startsWith(matrix.os, 'ubuntu-') - name: Create Build Environment run: cmake -E make_directory ${{runner.workspace}}/build From f8dca68d4eb316876fd01aa4a51dded3fa3e002b Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 1 Mar 2021 15:36:25 +0000 Subject: [PATCH 17/20] Update README with SigMF support & cmake version --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b5d439c..b4b9b6a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ inspectrum is a tool for analysing captured signals, primarily from software-def ## Try it ### Prerequisites - * cmake >= 2.8.11 + * cmake >= 3.1 * fftw 3.x * [liquid-dsp](https://github.com/jgaeddert/liquid-dsp) >= v1.3.0 * pkg-config @@ -22,6 +22,7 @@ Build instructions can be found here: https://github.com/miek/inspectrum/wiki/Bu ## Input inspectrum supports the following file types: + * `*.sigmf-meta, *.sigmf-data` - SigMF recordings * `*.cf32`, `*.cfile` - Complex 32-bit floating point samples (GNURadio, osmocom_fft) * `*.cs16` - Complex 16-bit signed integer samples (BladeRF) * `*.cs8` - Complex 8-bit signed integer samples (HackRF) From d463fae9670a60ec326cdb84ce225c53687224e1 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Tue, 2 Mar 2021 18:50:51 +0000 Subject: [PATCH 18/20] Add libsigmf dep --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b4b9b6a..102ff71 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ inspectrum is a tool for analysing captured signals, primarily from software-def * [liquid-dsp](https://github.com/jgaeddert/liquid-dsp) >= v1.3.0 * pkg-config * qt5 + * [libsigmf](https://github.com/deepsig/libsigmf) (optional, for SigMF support) ### Build instructions From b3fc3e0408665dec653d6e9c1d80010b652c0d6e Mon Sep 17 00:00:00 2001 From: devnulling Date: Thu, 25 Mar 2021 05:34:51 -0700 Subject: [PATCH 19/20] Clear SigMF annotations on new file load (#183) Clear SigMF annotations on new file load --- src/inputsource.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/inputsource.cpp b/src/inputsource.cpp index 50a617c..fd90020 100644 --- a/src/inputsource.cpp +++ b/src/inputsource.cpp @@ -295,6 +295,7 @@ void InputSource::openFile(const char *filename) QString dataFilename; #if ENABLE_SIGMF + annotationList.clear(); QString metaFilename; if (suffix == "sigmf-meta") { From 70e435c02df7ab7f44abbac82bba02905a28e61c Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Thu, 25 Mar 2021 12:51:11 +0000 Subject: [PATCH 20/20] actions: update homebrew qt package name qt5 seems to have been renamed to qt@5 in homebrew, so builds were failing at the CMAKE_PREFIX_PATH was no longer correct. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf415cb..e00be0e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ on: [push] env: BUILD_TYPE: Release # For macOS qt keg-only package - CMAKE_PREFIX_PATH: '/usr/local/opt/qt' + CMAKE_PREFIX_PATH: '/usr/local/opt/qt@5' jobs: build: @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 - name: Install dependencies (macOS) - run: brew install fftw liquid-dsp qt5 + run: brew install fftw liquid-dsp qt@5 if: matrix.os == 'macos-latest' - name: Install dependencies (Ubuntu)