diff --git a/plugins/samplesink/fileoutput/fileoutput.cpp b/plugins/samplesink/fileoutput/fileoutput.cpp index d00c38f66..735fab4ca 100644 --- a/plugins/samplesink/fileoutput/fileoutput.cpp +++ b/plugins/samplesink/fileoutput/fileoutput.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016-2023 Edouard Griffiths, F4EXB // +// Copyright (C) 2016-2026 Edouard Griffiths, F4EXB // // Copyright (C) 2021 Andreas Baulig // // // // This program is free software; you can redistribute it and/or modify // @@ -45,6 +45,7 @@ MESSAGE_CLASS_DEFINITION(FileOutput::MsgReportFileOutputStreamTiming, Message) FileOutput::FileOutput(DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_settings(), + m_spectrumVis(SDR_TX_SCALEF), m_deviceDescription("FileOutput"), m_masterTimer(deviceAPI->getMasterTimer()) { @@ -77,7 +78,7 @@ void FileOutput::openFileStream() header.centerFrequency = m_settings.m_centerFrequency; m_startingTimeStamp = QDateTime::currentMSecsSinceEpoch(); header.startTimeStamp = (quint64)m_startingTimeStamp; - header.sampleSize = SDR_RX_SAMP_SZ; + header.sampleSize = SDR_TX_SAMP_SZ; FileRecord::writeHeader(m_ofstream, header); @@ -91,8 +92,6 @@ void FileOutput::init() bool FileOutput::start() { - QMutexLocker mutexLocker(&m_mutex); - if (m_running) { return true; } @@ -103,13 +102,13 @@ bool FileOutput::start() m_fileOutputWorker = new FileOutputWorker(&m_ofstream, &m_sampleSourceFifo); m_fileOutputWorker->moveToThread(&m_fileOutputWorkerThread); + m_fileOutputWorker->setSpectrumSink(&m_spectrumVis); m_fileOutputWorker->setSamplerate((int) m_settings.m_sampleRate); m_fileOutputWorker->setLog2Interpolation(m_settings.m_log2Interp); m_fileOutputWorker->connectTimer(m_masterTimer); startWorker(); m_running = true; - mutexLocker.unlock(); qDebug("FileOutput::start: started"); if (getMessageQueueToGUI()) @@ -123,8 +122,6 @@ bool FileOutput::start() void FileOutput::stop() { - QMutexLocker mutexLocker(&m_mutex); - if (!m_running) { return; } @@ -298,8 +295,8 @@ bool FileOutput::handleMessage(const Message& message) void FileOutput::applySettings(const FileOutputSettings& settings, const QList& settingsKeys, bool force) { qDebug() << "FileOutput::applySettings: force:" << force << settings.getDebugString(settingsKeys, force); - QMutexLocker mutexLocker(&m_mutex); bool forwardChange = false; + bool needRestart = false; if (force || settingsKeys.contains("centerFrequency")) { @@ -308,19 +305,13 @@ void FileOutput::applySettings(const FileOutputSettings& settings, const QListsetSamplerate((int) settings.m_sampleRate); - } - + needRestart = true; forwardChange = true; } if (force || settingsKeys.contains("log2Interp")) { - if (m_fileOutputWorker != nullptr) { - m_fileOutputWorker->setLog2Interpolation(settings.m_log2Interp); - } - + needRestart = true; forwardChange = true; } @@ -339,6 +330,12 @@ void FileOutput::applySettings(const FileOutputSettings& settings, const QList // -// Copyright (C) 2015-2017, 2019-2022 Edouard Griffiths, F4EXB // +// Copyright (C) 2015-2017, 2019-2026 Edouard Griffiths, F4EXB // // Copyright (C) 2021 Andreas Baulig // // // // This program is free software; you can redistribute it and/or modify // @@ -32,6 +32,7 @@ #include #include "dsp/devicesamplesink.h" +#include "dsp/spectrumvis.h" #include "fileoutputsettings.h" class QNetworkAccessManager; @@ -231,11 +232,14 @@ public: const QStringList& deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings& response); + SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } + void setSpectrumGUI(Serializable *spectrumGUI) { m_settings.setSpectrumGUI(spectrumGUI); } + private: DeviceAPI *m_deviceAPI; - QMutex m_mutex; bool m_running = false; FileOutputSettings m_settings; + SpectrumVis m_spectrumVis; std::ofstream m_ofstream; FileOutputWorker* m_fileOutputWorker = nullptr; QThread m_fileOutputWorkerThread; diff --git a/plugins/samplesink/fileoutput/fileoutputgui.cpp b/plugins/samplesink/fileoutput/fileoutputgui.cpp index e90d9b972..8770e9400 100644 --- a/plugins/samplesink/fileoutput/fileoutputgui.cpp +++ b/plugins/samplesink/fileoutput/fileoutputgui.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2015-2022 Edouard Griffiths, F4EXB // +// Copyright (C) 2015-2026 Edouard Griffiths, F4EXB // // Copyright (C) 2018 beta-tester // // Copyright (C) 2020, 2022-2023 Jon Beniston, M7RCE // // // @@ -31,6 +31,7 @@ #include "gui/basicdevicesettingsdialog.h" #include "gui/dialogpositioner.h" #include "dsp/dspcommands.h" +#include "dsp/spectrumvis.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" @@ -54,6 +55,7 @@ FileOutputGui::FileOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : setAttribute(Qt::WA_DeleteOnClose, true); ui->setupUi(getContents()); sizeToContents(); + setMinimumSize(m_MinimumWidth, m_MinimumHeight); getContents()->setStyleSheet("#FileOutputGui { background-color: rgb(64, 64, 64); }"); m_helpURL = "plugins/samplesink/fileoutput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -66,6 +68,15 @@ FileOutputGui::FileOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : ui->fileNameText->setText(m_settings.m_fileName); + m_deviceSampleSink = (FileOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); + + m_spectrumVis = m_deviceSampleSink->getSpectrumVis(); + m_spectrumVis->setGLSpectrum(ui->glSpectrum); + ui->glSpectrum->setCenterFrequency(m_settings.m_centerFrequency); + ui->glSpectrum->setSampleRate(m_settings.m_sampleRate*(1<spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); + m_deviceSampleSink->setSpectrumGUI(ui->spectrumGUI); + connect(&(m_deviceUISet->m_deviceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick())); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); @@ -75,7 +86,6 @@ FileOutputGui::FileOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : makeUIConnections(); m_resizer.enableChildMouseTracking(); - m_deviceSampleSink = (FileOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } @@ -256,6 +266,7 @@ void FileOutputGui::updateStatus() void FileOutputGui::on_centerFrequency_changed(quint64 value) { m_settings.m_centerFrequency = value * 1000; + ui->glSpectrum->setCenterFrequency(m_settings.m_centerFrequency); m_settingsKeys.append("centerFrequency"); sendSettings(); } @@ -263,6 +274,7 @@ void FileOutputGui::on_centerFrequency_changed(quint64 value) void FileOutputGui::on_sampleRate_changed(quint64 value) { m_settings.m_sampleRate = value; + ui->glSpectrum->setSampleRate(m_settings.m_sampleRate*(1<glSpectrum->setSampleRate(m_settings.m_sampleRate*(1< // +// Copyright (C) 2015-2017, 2019-2026 Edouard Griffiths, F4EXB // // Copyright (C) 2022 Jon Beniston, M7RCE // // // // This program is free software; you can redistribute it and/or modify // @@ -31,6 +31,7 @@ class DeviceSampleSink; class DeviceUISet; +class SpectrumVis; namespace Ui { class FileOutputGui; @@ -58,7 +59,7 @@ private: QList m_settingsKeys; QTimer m_updateTimer; QTimer m_statusTimer; - DeviceSampleSink* m_deviceSampleSink; + FileOutput* m_deviceSampleSink; int m_sampleRate; quint64 m_deviceCenterFrequency; //!< Center frequency in device bool m_generation; @@ -67,6 +68,9 @@ private: std::size_t m_tickCount; int m_lastEngineState; MessageQueue m_inputMessageQueue; + SpectrumVis* m_spectrumVis; + static const int m_MinimumWidth = 370; + static const int m_MinimumHeight = 470; void blockApplySettings(bool block) { m_doApplySettings = !block; } void displaySettings(); diff --git a/plugins/samplesink/fileoutput/fileoutputgui.ui b/plugins/samplesink/fileoutput/fileoutputgui.ui index c36dbb4e6..26c13dea8 100644 --- a/plugins/samplesink/fileoutput/fileoutputgui.ui +++ b/plugins/samplesink/fileoutput/fileoutputgui.ui @@ -6,26 +6,20 @@ 0 0 - 360 - 126 + 370 + 470 - + 0 0 - 360 - 126 - - - - - 380 - 144 + 370 + 470 @@ -226,13 +220,6 @@ - - - - Qt::Horizontal - - - @@ -361,29 +348,91 @@ - - - - Qt::Vertical - - - + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 354 + 200 + + + + + Liberation Mono + 8 + + + + + + + + + 0 + 0 + + + + + 354 + 30 + + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + GLSpectrum + QWidget +
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
+ 1 +
ValueDial QWidget
gui/valuedial.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
diff --git a/plugins/samplesink/fileoutput/fileoutputsettings.cpp b/plugins/samplesink/fileoutput/fileoutputsettings.cpp index 4a3a4a042..ce5364fc4 100644 --- a/plugins/samplesink/fileoutput/fileoutputsettings.cpp +++ b/plugins/samplesink/fileoutput/fileoutputsettings.cpp @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // written by Christian Daniel // -// Copyright (C) 2015-2017, 2019-2022 Edouard Griffiths, F4EXB // +// Copyright (C) 2015-2017, 2019-2026 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // @@ -18,6 +18,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include "util/simpleserializer.h" +#include "settings/serializable.h" #include "fileoutputsettings.h" FileOutputSettings::FileOutputSettings() @@ -31,6 +32,7 @@ void FileOutputSettings::resetToDefaults() m_sampleRate = 48000; m_log2Interp = 0; m_fileName = "./test.sdriq"; + m_spectrumGUI = nullptr; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -49,6 +51,10 @@ QByteArray FileOutputSettings::serialize() const s.writeU32(6, m_reverseAPIPort); s.writeU32(7, m_reverseAPIDeviceIndex); + if (m_spectrumGUI) { + s.writeBlob(8, m_spectrumGUI->serialize()); + } + return s.final(); } @@ -82,6 +88,13 @@ bool FileOutputSettings::deserialize(const QByteArray& data) d.readU32(7, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + if (m_spectrumGUI) + { + QByteArray bytetmp; + d.readBlob(8, &bytetmp); + m_spectrumGUI->deserialize(bytetmp); + } + return true; } else diff --git a/plugins/samplesink/fileoutput/fileoutputsettings.h b/plugins/samplesink/fileoutput/fileoutputsettings.h index 83fbb16d9..26f8de404 100644 --- a/plugins/samplesink/fileoutput/fileoutputsettings.h +++ b/plugins/samplesink/fileoutput/fileoutputsettings.h @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // written by Christian Daniel // -// Copyright (C) 2015-2017, 2019-2022 Edouard Griffiths, F4EXB // +// Copyright (C) 2015-2017, 2019-2026 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // @@ -20,11 +20,14 @@ #ifndef PLUGINS_SAMPLESINK_FILEOUTPUT_FILEOUTPUTSETTINGS_H_ #define PLUGINS_SAMPLESINK_FILEOUTPUT_FILEOUTPUTSETTINGS_H_ +class Serializable; + struct FileOutputSettings { quint64 m_centerFrequency; quint64 m_sampleRate; quint32 m_log2Interp; QString m_fileName; + Serializable *m_spectrumGUI; bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; @@ -36,6 +39,7 @@ struct FileOutputSettings { bool deserialize(const QByteArray& data); void applySettings(const QStringList& settingsKeys, const FileOutputSettings& settings); QString getDebugString(const QStringList& settingsKeys, bool force=false) const; + void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; } }; #endif /* PLUGINS_SAMPLESINK_FILEOUTPUT_FILEOUTPUTSETTINGS_H_ */ diff --git a/plugins/samplesink/fileoutput/fileoutputworker.cpp b/plugins/samplesink/fileoutput/fileoutputworker.cpp index 158e2d857..908f94ef7 100644 --- a/plugins/samplesink/fileoutput/fileoutputworker.cpp +++ b/plugins/samplesink/fileoutput/fileoutputworker.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016-2017, 2019-2020 Edouard Griffiths, F4EXB // +// Copyright (C) 2016-2017, 2019-2026 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // @@ -21,6 +21,7 @@ #include #include "dsp/samplesourcefifo.h" +#include "dsp/basebandsamplesink.h" #include "fileoutputworker.h" FileOutputWorker::FileOutputWorker(std::ofstream *samplesStream, SampleSourceFifo* sampleFifo, QObject* parent) : @@ -180,7 +181,9 @@ void FileOutputWorker::callbackPart(SampleVector& data, unsigned int iBegin, uns if (m_log2Interpolation == 0) { - m_ofstream->write(reinterpret_cast(&(*beginRead)), chunkSize*sizeof(Sample)); + m_interpolators.interpolate1(&beginRead, m_buf, 2*chunkSize); + m_ofstream->write(reinterpret_cast(m_buf), chunkSize*2*sizeof(int16_t)); + feedSpectrum(m_buf, 2*chunkSize); } else { @@ -209,5 +212,27 @@ void FileOutputWorker::callbackPart(SampleVector& data, unsigned int iBegin, uns } m_ofstream->write(reinterpret_cast(m_buf), chunkSize*(1< Sample { + return Sample{s.m_real, s.m_imag}; + } + ); + + m_spectrumSink->feed(m_samplesVector.m_vector.begin(), m_samplesVector.m_vector.begin() + (bufSize/2), false); +} diff --git a/plugins/samplesink/fileoutput/fileoutputworker.h b/plugins/samplesink/fileoutput/fileoutputworker.h index 44f44119c..45c6f7e3b 100644 --- a/plugins/samplesink/fileoutput/fileoutputworker.h +++ b/plugins/samplesink/fileoutput/fileoutputworker.h @@ -2,7 +2,7 @@ // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // written by Christian Daniel // // Copyright (C) 2014 John Greb // -// Copyright (C) 2015-2020 Edouard Griffiths, F4EXB // +// Copyright (C) 2015-2026 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // @@ -30,10 +30,12 @@ #include #include "dsp/interpolators.h" +#include "util/incrementalvector.h" #define FILEOUTPUT_THROTTLE_MS 50 class SampleSourceFifo; +class BasebandSampleSink; class FileOutputWorker : public QObject { Q_OBJECT @@ -50,10 +52,18 @@ public: bool isRunning() const { return m_running; } std::size_t getSamplesCount() const { return m_samplesCount; } void setSamplesCount(int samplesCount) { m_samplesCount = samplesCount; } + void setSpectrumSink(BasebandSampleSink *spectrumSink) { m_spectrumSink = spectrumSink; } void connectTimer(const QTimer& timer); private: +#pragma pack(push, 1) + struct Sample16 + { + int16_t m_real; + int16_t m_imag; + }; +#pragma pack(pop) volatile bool m_running; std::ofstream* m_ofstream; @@ -68,11 +78,14 @@ private: int m_maxThrottlems; QElapsedTimer m_elapsedTimer; bool m_throttleToggle; + BasebandSampleSink* m_spectrumSink; + IncrementalVector m_samplesVector; Interpolators m_interpolators; int16_t *m_buf; void callbackPart(SampleVector& data, unsigned int iBegin, unsigned int iEnd); + void feedSpectrum(int16_t *buf, unsigned int bufSize); private slots: void tick(); diff --git a/plugins/samplesink/fileoutput/readme.md b/plugins/samplesink/fileoutput/readme.md index 63007e351..2b5ddde62 100644 --- a/plugins/samplesink/fileoutput/readme.md +++ b/plugins/samplesink/fileoutput/readme.md @@ -22,6 +22,8 @@ The top and bottom bars of the device window are described [here](../../../sdrgu ![File output plugin GUI](../../../doc/img/FileOutput_plugin.png) +Note: the associated spectrum in the independent spectrum window shows the baseband. The interpolated output that will go to the file appears in the attached spectrum view below the settings. +

1: Start/Stop

Device start / stop button.