From 55261f93a32429e3a65d20375bb2e0c6bfc2fc7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luna=20Gr=C3=A4fje?= Date: Sat, 14 Jan 2023 16:39:15 +0100 Subject: [PATCH 1/3] Add SigMF metadata to IQ recordings --- src/applications/gqrx/mainwindow.cpp | 45 ++++++++++++++++++++++++---- src/applications/gqrx/mainwindow.h | 2 +- src/qtgui/iq_tool.cpp | 3 +- src/qtgui/iq_tool.h | 2 +- src/qtgui/iq_tool.ui | 24 +++++++++++++++ 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 09403fe78..4d4f3270c 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -317,7 +318,7 @@ MainWindow::MainWindow(const QString& cfgfile, bool edit_conf, QWidget *parent) connect(&DXCSpots::Get(), SIGNAL(dxcSpotsUpdated()), this, SLOT(updateClusterSpots())); // I/Q playback - connect(iq_tool, SIGNAL(startRecording(QString)), this, SLOT(startIqRecording(QString))); + connect(iq_tool, SIGNAL(startRecording(QString, QString)), this, SLOT(startIqRecording(QString, QString))); connect(iq_tool, SIGNAL(stopRecording()), this, SLOT(stopIqRecording())); connect(iq_tool, SIGNAL(startPlayback(QString,float,qint64)), this, SLOT(startIqPlayback(QString,float,qint64))); connect(iq_tool, SIGNAL(stopPlayback()), this, SLOT(stopIqPlayback())); @@ -1629,7 +1630,7 @@ void MainWindow::stopAudioStreaming() } /** Start I/Q recording. */ -void MainWindow::startIqRecording(const QString& recdir) +void MainWindow::startIqRecording(const QString& recdir, const QString& format) { qDebug() << __func__; // generate file name using date, time, rf freq in kHz and BW in Hz @@ -1637,13 +1638,45 @@ void MainWindow::startIqRecording(const QString& recdir) auto freq = qRound64(rx->get_rf_freq()); auto sr = qRound64(rx->get_input_rate()); auto dec = (quint32)(rx->get_input_decim()); - auto lastRec = QDateTime::currentDateTimeUtc(). - toString("%1/gqrx_yyyyMMdd_hhmmss_%2_%3_fc.'raw'") - .arg(recdir).arg(freq).arg(sr/dec); + auto currentDate = QDateTime::currentDateTimeUtc(); + auto filenameTemplate = currentDate.toString("%1/gqrx_yyyyMMdd_hhmmss_%2_%3_fc.%4").arg(recdir).arg(freq).arg(sr/dec); + bool sigmf = (format == "SigMF"); + auto lastRec = filenameTemplate.arg(sigmf ? "sigmf-data" : "raw"); + + QFile metaFile(filenameTemplate.arg("sigmf-meta")); + bool ok = true; + if (sigmf) { + auto meta = QJsonDocument { QJsonObject { + {"global", QJsonObject { +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + {"core:datatype", "cf32_be"}, +#else + {"core:datatype", "cf32_le"}, +#endif + {"core:sample_rate", sr/dec}, + {"core:version", "1.0.0"}, + {"core:recorder", "Gqrx " VERSION}, + }}, {"captures", QJsonArray { + QJsonObject { + {"core:sample_start", 0}, + {"core:frequency", freq}, + {"core:datetime", currentDate.toString(Qt::ISODateWithMs)}, + }, + }}, {"annotations", QJsonArray {}}, + }}.toJson(); + + if (!metaFile.open(QIODevice::WriteOnly) || metaFile.write(meta) != meta.size()) { + ok = false; + } + } // start recorder; fails if recording already in progress - if (rx->start_iq_recording(lastRec.toStdString())) + if (!ok || rx->start_iq_recording(lastRec.toStdString())) { + // remove metadata file if we managed to open it + if (sigmf && metaFile.isOpen()) + metaFile.remove(); + // reset action status ui->statusBar->showMessage(tr("Error starting I/Q recoder")); diff --git a/src/applications/gqrx/mainwindow.h b/src/applications/gqrx/mainwindow.h index 2b2092a1f..5151bb2c1 100644 --- a/src/applications/gqrx/mainwindow.h +++ b/src/applications/gqrx/mainwindow.h @@ -195,7 +195,7 @@ private slots: void stopAudioStreaming(); /* I/Q playback and recording*/ - void startIqRecording(const QString& recdir); + void startIqRecording(const QString& recdir, const QString& format); void stopIqRecording(); void startIqPlayback(const QString& filename, float samprate, qint64 center_freq); void stopIqPlayback(); diff --git a/src/qtgui/iq_tool.cpp b/src/qtgui/iq_tool.cpp index bbc1fda09..adbd24572 100644 --- a/src/qtgui/iq_tool.cpp +++ b/src/qtgui/iq_tool.cpp @@ -52,6 +52,7 @@ CIqTool::CIqTool(QWidget *parent) : //ui->recDirEdit->setText(QDir::currentPath()); recdir = new QDir(QDir::homePath(), "*.raw"); + recdir->setNameFilters(recdir->nameFilters() << "*.sigmf-data"); error_palette = new QPalette(); error_palette->setColor(QPalette::Text, Qt::red); @@ -173,7 +174,7 @@ void CIqTool::on_recButton_clicked(bool checked) if (checked) { ui->playButton->setEnabled(false); - emit startRecording(recdir->path()); + emit startRecording(recdir->path(), ui->formatCombo->currentText()); refreshDir(); ui->listWidget->setCurrentRow(ui->listWidget->count()-1); diff --git a/src/qtgui/iq_tool.h b/src/qtgui/iq_tool.h index cb8da0f5b..b078da708 100644 --- a/src/qtgui/iq_tool.h +++ b/src/qtgui/iq_tool.h @@ -62,7 +62,7 @@ class CIqTool : public QDialog void readSettings(QSettings *settings); signals: - void startRecording(const QString recdir); + void startRecording(const QString recdir, const QString format); void stopRecording(); void startPlayback(const QString filename, float samprate, qint64 center_freq); void stopPlayback(); diff --git a/src/qtgui/iq_tool.ui b/src/qtgui/iq_tool.ui index 1d9d74eb1..3485db5bc 100644 --- a/src/qtgui/iq_tool.ui +++ b/src/qtgui/iq_tool.ui @@ -32,6 +32,30 @@ + + + + Format: + + + + + + + File format + + + + Raw + + + + + SigMF + + + + From 98a796f42597c8bd2733a0d34653edddce34d949 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Thu, 5 Oct 2023 20:43:07 -0400 Subject: [PATCH 2/3] Update news --- resources/news.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/news.txt b/resources/news.txt index 261d62cf5..b175c8455 100644 --- a/resources/news.txt +++ b/resources/news.txt @@ -2,6 +2,7 @@ 2.17.1: In progress... NEW: Delete key clears the waterfall. + NEW: I/Q tool can save recordings in SigMF format. IMPROVED: Reduced CPU utilization of waterfall display. CHANGED: DMG release requires macOS 12.7 or later. From 4c4f9d5eeb1cfff652b39f82ea6abe4a678d3016 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Thu, 5 Oct 2023 20:43:15 -0400 Subject: [PATCH 3/3] Update contributors --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0ae264324..af9ed7e6b 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ The following people and organisations have contributed to gqrx: * Kenji Rikitake, JJ1BDX * Kitware Inc. * Konrad Beckmann +* Luna Gräfje * luzpaz * Marco Savelli * Markus Kolb