From 238a40b9e09d64433e14de848f7ff1f4fe21ad02 Mon Sep 17 00:00:00 2001
From: srcejon <jon@beniston.com>
Date: Wed, 6 Dec 2023 10:09:30 +0000
Subject: [PATCH 1/5] Allow replay time offset to be set by ctrl+left click in
 waterfall.

---
 plugins/samplesource/airspyhf/airspyhfgui.cpp |  5 +++++
 plugins/samplesource/airspyhf/airspyhfgui.h   |  1 +
 plugins/samplesource/rtlsdr/rtlsdrgui.cpp     |  5 +++++
 plugins/samplesource/rtlsdr/rtlsdrgui.h       |  1 +
 .../samplesource/sdrplayv3/sdrplayv3gui.cpp   |  5 +++++
 plugins/samplesource/sdrplayv3/sdrplayv3gui.h |  1 +
 .../samplesource/usrpinput/usrpinputgui.cpp   |  5 +++++
 plugins/samplesource/usrpinput/usrpinputgui.h |  1 +
 .../samplesource/usrpinput/usrpinputgui.ui    | 22 +++++++++----------
 .../usrpinput/usrpinputsettings.h             |  2 +-
 sdrgui/device/devicegui.h                     |  1 +
 sdrgui/device/deviceuiset.cpp                 |  9 ++++++++
 sdrgui/device/deviceuiset.h                   |  1 +
 sdrgui/gui/glspectrumview.cpp                 | 12 ++++++++++
 sdrgui/gui/glspectrumview.h                   |  2 ++
 sdrgui/mainspectrum/mainspectrumgui.cpp       |  7 ++++++
 sdrgui/mainspectrum/mainspectrumgui.h         |  2 ++
 17 files changed, 70 insertions(+), 12 deletions(-)

diff --git a/plugins/samplesource/airspyhf/airspyhfgui.cpp b/plugins/samplesource/airspyhf/airspyhfgui.cpp
index 59e464db7..159f996f2 100644
--- a/plugins/samplesource/airspyhf/airspyhfgui.cpp
+++ b/plugins/samplesource/airspyhf/airspyhfgui.cpp
@@ -623,6 +623,11 @@ void AirspyHFGui::on_replayLoop_toggled(bool checked)
     sendSettings();
 }
 
+void AirspyHFGui::setReplayTime(float time)
+{
+    ui->replayOffset->setValue(std::ceil(time * 10.0f));
+}
+
 void AirspyHFGui::makeUIConnections()
 {
     QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AirspyHFGui::on_centerFrequency_changed);
diff --git a/plugins/samplesource/airspyhf/airspyhfgui.h b/plugins/samplesource/airspyhf/airspyhfgui.h
index 877dd3e90..d3d48cd42 100644
--- a/plugins/samplesource/airspyhf/airspyhfgui.h
+++ b/plugins/samplesource/airspyhf/airspyhfgui.h
@@ -46,6 +46,7 @@ public:
 	QByteArray serialize() const;
 	bool deserialize(const QByteArray& data);
 	virtual MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
+    void setReplayTime(float time) override;
 
 	uint32_t getDevSampleRate(unsigned int index);
 	int getDevSampleRateIndex(uint32_t sampleRate);
diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp
index 963e224c4..1cb0e9b21 100644
--- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp
+++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp
@@ -691,6 +691,11 @@ void RTLSDRGui::on_replayLoop_toggled(bool checked)
     sendSettings();
 }
 
+void RTLSDRGui::setReplayTime(float time)
+{
+    ui->replayOffset->setValue(std::ceil(time * 10.0f));
+}
+
 void RTLSDRGui::makeUIConnections()
 {
     QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &RTLSDRGui::on_centerFrequency_changed);
diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.h b/plugins/samplesource/rtlsdr/rtlsdrgui.h
index 3cac63c4d..7abfaeba3 100644
--- a/plugins/samplesource/rtlsdr/rtlsdrgui.h
+++ b/plugins/samplesource/rtlsdr/rtlsdrgui.h
@@ -50,6 +50,7 @@ public:
 	QByteArray serialize() const;
 	bool deserialize(const QByteArray& data);
 	virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+    void setReplayTime(float time) override;
 
 private:
 	Ui::RTLSDRGui* ui;
diff --git a/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp b/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp
index 1b7d6e43c..a1df4ec8d 100644
--- a/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp
+++ b/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp
@@ -687,6 +687,11 @@ void SDRPlayV3Gui::on_replayLoop_toggled(bool checked)
     sendSettings();
 }
 
+void SDRPlayV3Gui::setReplayTime(float time)
+{
+    ui->replayOffset->setValue(std::ceil(time * 10.0f));
+}
+
 void SDRPlayV3Gui::makeUIConnections()
 {
     QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &SDRPlayV3Gui::on_centerFrequency_changed);
diff --git a/plugins/samplesource/sdrplayv3/sdrplayv3gui.h b/plugins/samplesource/sdrplayv3/sdrplayv3gui.h
index 7a130bebc..8e65a9fa5 100644
--- a/plugins/samplesource/sdrplayv3/sdrplayv3gui.h
+++ b/plugins/samplesource/sdrplayv3/sdrplayv3gui.h
@@ -46,6 +46,7 @@ public:
     virtual QByteArray serialize() const;
     virtual bool deserialize(const QByteArray& data);
     virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+    void setReplayTime(float time) override;
 
 private:
     Ui::SDRPlayV3Gui* ui;
diff --git a/plugins/samplesource/usrpinput/usrpinputgui.cpp b/plugins/samplesource/usrpinput/usrpinputgui.cpp
index 523dff5a5..5a856f5fb 100644
--- a/plugins/samplesource/usrpinput/usrpinputgui.cpp
+++ b/plugins/samplesource/usrpinput/usrpinputgui.cpp
@@ -769,6 +769,11 @@ void USRPInputGUI::on_replayLoop_toggled(bool checked)
     sendSettings();
 }
 
+void USRPInputGUI::setReplayTime(float time)
+{
+    ui->replayOffset->setValue(std::ceil(time * 10.0f));
+}
+
 void USRPInputGUI::makeUIConnections()
 {
     QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &USRPInputGUI::on_startStop_toggled);
diff --git a/plugins/samplesource/usrpinput/usrpinputgui.h b/plugins/samplesource/usrpinput/usrpinputgui.h
index 9a0f3dfcc..1a5fa8107 100644
--- a/plugins/samplesource/usrpinput/usrpinputgui.h
+++ b/plugins/samplesource/usrpinput/usrpinputgui.h
@@ -50,6 +50,7 @@ public:
     QByteArray serialize() const;
     bool deserialize(const QByteArray& data);
     virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+    void setReplayTime(float time) override;
 
 private:
     Ui::USRPInputGUI* ui;
diff --git a/plugins/samplesource/usrpinput/usrpinputgui.ui b/plugins/samplesource/usrpinput/usrpinputgui.ui
index b20bc042b..1110ab685 100644
--- a/plugins/samplesource/usrpinput/usrpinputgui.ui
+++ b/plugins/samplesource/usrpinput/usrpinputgui.ui
@@ -875,28 +875,28 @@
   </layout>
  </widget>
  <customwidgets>
-  <customwidget>
-   <class>ValueDial</class>
-   <extends>QWidget</extends>
-   <header>gui/valuedial.h</header>
-   <container>1</container>
-  </customwidget>
   <customwidget>
    <class>ButtonSwitch</class>
    <extends>QToolButton</extends>
    <header>gui/buttonswitch.h</header>
   </customwidget>
-  <customwidget>
-   <class>TransverterButton</class>
-   <extends>QPushButton</extends>
-   <header>gui/transverterbutton.h</header>
-  </customwidget>
   <customwidget>
    <class>ValueDialZ</class>
    <extends>QWidget</extends>
    <header>gui/valuedialz.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>ValueDial</class>
+   <extends>QWidget</extends>
+   <header>gui/valuedial.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>TransverterButton</class>
+   <extends>QPushButton</extends>
+   <header>gui/transverterbutton.h</header>
+  </customwidget>
  </customwidgets>
  <resources>
   <include location="../../../sdrgui/resources/res.qrc"/>
diff --git a/plugins/samplesource/usrpinput/usrpinputsettings.h b/plugins/samplesource/usrpinput/usrpinputsettings.h
index 6bd90fa36..ae2f6e15d 100644
--- a/plugins/samplesource/usrpinput/usrpinputsettings.h
+++ b/plugins/samplesource/usrpinput/usrpinputsettings.h
@@ -55,7 +55,7 @@ struct USRPInputSettings
 	float    m_replayOffset; //!< Replay offset in seconds
 	float    m_replayLength; //!< Replay buffer size in seconds
 	float    m_replayStep;   //!< Replay forward/back step size in seconds
-	bool     m_replayLoop;    //!< Replay buffer repeatedly without recording new data
+	bool     m_replayLoop;   //!< Replay buffer repeatedly without recording new data
     bool     m_useReverseAPI;
     QString  m_reverseAPIAddress;
     uint16_t m_reverseAPIPort;
diff --git a/sdrgui/device/devicegui.h b/sdrgui/device/devicegui.h
index 69f78ee3a..94eb2a4c6 100644
--- a/sdrgui/device/devicegui.h
+++ b/sdrgui/device/devicegui.h
@@ -81,6 +81,7 @@ public:
     void setCurrentDeviceIndex(int index) { m_currentDeviceIndex = index; } //!< index in plugins list
     void setChannelNames(const QStringList& channelNames) { m_channelAddDialog.addChannelNames(channelNames); }
     DeviceUISet* getDeviceUISet() { return m_deviceUISet; }
+    virtual void setReplayTime(float time) {} //!< Not supported by all devices
 
 protected:
     void closeEvent(QCloseEvent *event) override;
diff --git a/sdrgui/device/deviceuiset.cpp b/sdrgui/device/deviceuiset.cpp
index 28c1dfe03..53bde72f2 100644
--- a/sdrgui/device/deviceuiset.cpp
+++ b/sdrgui/device/deviceuiset.cpp
@@ -73,6 +73,8 @@ DeviceUISet::DeviceUISet(int deviceSetIndex, DeviceSet *deviceSet)
     font.setFamily(QStringLiteral("Liberation Sans"));
     font.setPointSize(9);
     m_spectrum->setFont(font);
+
+    connect(m_mainSpectrumGUI, &MainSpectrumGUI::timeSelected, this, &DeviceUISet::onTimeSelected);
 }
 
 DeviceUISet::~DeviceUISet()
@@ -825,3 +827,10 @@ int DeviceUISet::webapiSpectrumServerDelete(SWGSDRangel::SWGSuccessResponse& res
 {
     return m_spectrumVis->webapiSpectrumServerDelete(response, errorMessage);
 }
+
+void DeviceUISet::onTimeSelected(int deviceSetIndex, float time)
+{
+    if (m_deviceGUI) {
+        m_deviceGUI->setReplayTime(time);
+    }
+}
diff --git a/sdrgui/device/deviceuiset.h b/sdrgui/device/deviceuiset.h
index d0cd6f38b..f195364fd 100644
--- a/sdrgui/device/deviceuiset.h
+++ b/sdrgui/device/deviceuiset.h
@@ -167,6 +167,7 @@ private:
 private slots:
     void handleChannelGUIClosing(ChannelGUI* channelGUI);
     void handleDeleteChannel(ChannelAPI *channelAPI);
+    void onTimeSelected(int deviceSetIndex, float time);
 };
 
 
diff --git a/sdrgui/gui/glspectrumview.cpp b/sdrgui/gui/glspectrumview.cpp
index 8b0edc547..a6d83347f 100644
--- a/sdrgui/gui/glspectrumview.cpp
+++ b/sdrgui/gui/glspectrumview.cpp
@@ -4175,6 +4175,18 @@ void GLSpectrumView::mousePressEvent(QMouseEvent* event)
         {
             frequencyPan(event);
         }
+        else if (event->modifiers() & Qt::ControlModifier)
+        {
+            if (!m_display3DSpectrogram && pointInWaterfallOrSpectrogram(ep))
+            {
+                QPointF pWat = ep;
+                pWat.rx() = (ep.x()/width() - m_waterfallRect.left()) / m_waterfallRect.width();
+                pWat.ry() = (ep.y()/height() - m_waterfallRect.top()) / m_waterfallRect.height();
+                float time = m_timeScale.getRangeMin() + pWat.y()*m_timeScale.getRange();
+                emit timeSelected(time);
+            }
+            return;
+        }
         else if (m_display3DSpectrogram)
         {
             // Detect click and drag to rotate 3D spectrogram
diff --git a/sdrgui/gui/glspectrumview.h b/sdrgui/gui/glspectrumview.h
index 6bc21fe30..8bef04239 100644
--- a/sdrgui/gui/glspectrumview.h
+++ b/sdrgui/gui/glspectrumview.h
@@ -541,6 +541,8 @@ signals:
     void requestCenterFrequency(qint64 frequency);
     // Emitted when annotations are changed
     void updateAnnotations();
+    // Emitted when user ctrl-clicks on waterfall to select a time. time is in seconds.
+    void timeSelected(float time);
 
 };
 
diff --git a/sdrgui/mainspectrum/mainspectrumgui.cpp b/sdrgui/mainspectrum/mainspectrumgui.cpp
index bdaf66a43..d01381e13 100644
--- a/sdrgui/mainspectrum/mainspectrumgui.cpp
+++ b/sdrgui/mainspectrum/mainspectrumgui.cpp
@@ -157,6 +157,8 @@ MainSpectrumGUI::MainSpectrumGUI(GLSpectrum *spectrum, GLSpectrumGUI *spectrumGU
     connect(spectrum->getSpectrumView(), &GLSpectrumView::requestCenterFrequency, this, &MainSpectrumGUI::onRequestCenterFrequency);
     connect(spectrumGUI, &GLSpectrumGUI::requestCenterFrequency, this, &MainSpectrumGUI::onRequestCenterFrequency);
 
+    connect(spectrum->getSpectrumView(), &GLSpectrumView::timeSelected, this, &MainSpectrumGUI::onTimeSelected);
+
     m_resizer.enableChildMouseTracking();
     shrinkWindow();
 }
@@ -380,3 +382,8 @@ void MainSpectrumGUI::onRequestCenterFrequency(qint64 frequency)
 {
     emit requestCenterFrequency(m_deviceSetIndex, frequency);
 }
+
+void MainSpectrumGUI::onTimeSelected(float time)
+{
+    emit timeSelected(m_deviceSetIndex, time);
+}
diff --git a/sdrgui/mainspectrum/mainspectrumgui.h b/sdrgui/mainspectrum/mainspectrumgui.h
index 608e27800..ce8a21b9c 100644
--- a/sdrgui/mainspectrum/mainspectrumgui.h
+++ b/sdrgui/mainspectrum/mainspectrumgui.h
@@ -113,12 +113,14 @@ private slots:
     void shrinkWindow();
     void maximizeWindow();
     void onRequestCenterFrequency(qint64 frequency);
+    void onTimeSelected(float time);
 
 signals:
     void closing();
     void moveToWorkspace(int workspaceIndex);
     void forceShrink();
     void requestCenterFrequency(int deviceSetIndex, qint64 frequency); // an action from the user to move device center frequency
+    void timeSelected(int deviceSetIndex, float time); // user ctrl-clicked waterfall to set a time
 };
 
 

From 2ac7cfd800a63fc66374cf80ddfaaaf7cc41d0e7 Mon Sep 17 00:00:00 2001
From: srcejon <jon@beniston.com>
Date: Wed, 6 Dec 2023 10:09:46 +0000
Subject: [PATCH 2/5] Add replay support to Lime Input

---
 .../limesdrinput/limesdrinput.cpp             |  24 ++-
 .../samplesource/limesdrinput/limesdrinput.h  |  23 ++-
 .../limesdrinput/limesdrinputgui.cpp          | 110 ++++++++++++
 .../limesdrinput/limesdrinputgui.h            |  10 ++
 .../limesdrinput/limesdrinputgui.ui           | 106 +++++++++++-
 .../limesdrinput/limesdrinputsettings.cpp     |  36 ++++
 .../limesdrinput/limesdrinputsettings.h       |   4 +
 .../limesdrinput/limesdrinputthread.cpp       | 157 ++++++++++++------
 .../limesdrinput/limesdrinputthread.h         |   4 +-
 9 files changed, 413 insertions(+), 61 deletions(-)

diff --git a/plugins/samplesource/limesdrinput/limesdrinput.cpp b/plugins/samplesource/limesdrinput/limesdrinput.cpp
index 9757df2c3..f0eaae215 100644
--- a/plugins/samplesource/limesdrinput/limesdrinput.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinput.cpp
@@ -48,6 +48,7 @@ MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgGetDeviceInfo, Message)
 MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgReportStreamInfo, Message)
 MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgStartStop, Message)
 MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgCalibrationResult, Message)
+MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgSaveReplay, Message)
 
 LimeSDRInput::LimeSDRInput(DeviceAPI *deviceAPI) :
     m_deviceAPI(deviceAPI),
@@ -422,7 +423,7 @@ bool LimeSDRInput::start()
 
     // start / stop streaming is done in the thread.
 
-    m_limeSDRInputThread = new LimeSDRInputThread(&m_streamId, &m_sampleFifo);
+    m_limeSDRInputThread = new LimeSDRInputThread(&m_streamId, &m_sampleFifo, &m_replayBuffer);
     qDebug("LimeSDRInput::start: thread created");
 
     applySettings(m_settings, QList<QString>(), true);
@@ -778,6 +779,12 @@ bool LimeSDRInput::handleMessage(const Message& message)
 
         return true;
     }
+    else if (MsgSaveReplay::match(message))
+    {
+        MsgSaveReplay& cmd = (MsgSaveReplay&) message;
+        m_replayBuffer.save(cmd.getFilename(), m_settings.m_devSampleRate, getCenterFrequency());
+        return true;
+    }
     else
     {
         return false;
@@ -977,6 +984,9 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, const QLi
                         settings.m_devSampleRate,
                         1<<settings.m_log2HardDecim);
             }
+            if (settings.m_devSampleRate != m_settings.m_devSampleRate) {
+                m_replayBuffer.clear();
+            }
         }
     }
 
@@ -1168,6 +1178,18 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, const QLi
         m_settings.applySettings(settingsKeys, settings);
     }
 
+    if (settingsKeys.contains("replayLength") || settingsKeys.contains("devSampleRate") || force) {
+        m_replayBuffer.setSize(m_settings.m_replayLength, m_settings.m_devSampleRate);
+    }
+
+    if (settingsKeys.contains("replayOffset") || settingsKeys.contains("devSampleRate")  || force) {
+        m_replayBuffer.setReadOffset(((unsigned)(m_settings.m_replayOffset * m_settings.m_devSampleRate)) * 2);
+    }
+
+    if (settingsKeys.contains("replayLoop") || force) {
+        m_replayBuffer.setLoop(m_settings.m_replayLoop);
+    }
+
     double clockGenFreqAfter;
 
     if (LMS_GetClockFreq(m_deviceShared.m_deviceParams->getDevice(), LMS_CLOCK_CGEN, &clockGenFreqAfter) != 0)
diff --git a/plugins/samplesource/limesdrinput/limesdrinput.h b/plugins/samplesource/limesdrinput/limesdrinput.h
index 64df518b9..d86128e48 100644
--- a/plugins/samplesource/limesdrinput/limesdrinput.h
+++ b/plugins/samplesource/limesdrinput/limesdrinput.h
@@ -29,6 +29,7 @@
 #include <QNetworkRequest>
 
 #include "dsp/devicesamplesource.h"
+#include "dsp/replaybuffer.h"
 #include "limesdr/devicelimesdrshared.h"
 #include "limesdrinputsettings.h"
 
@@ -209,7 +210,26 @@ public:
         { }
     };
 
-    LimeSDRInput(DeviceAPI *deviceAPI);
+   class MsgSaveReplay : public Message {
+        MESSAGE_CLASS_DECLARATION
+
+    public:
+        QString getFilename() const { return m_filename; }
+
+        static MsgSaveReplay* create(const QString& filename) {
+            return new MsgSaveReplay(filename);
+        }
+
+    protected:
+        QString m_filename;
+
+        MsgSaveReplay(const QString& filename) :
+            Message(),
+            m_filename(filename)
+        { }
+    };
+
+   LimeSDRInput(DeviceAPI *deviceAPI);
     virtual ~LimeSDRInput();
     virtual void destroy();
 
@@ -280,6 +300,7 @@ private:
     lms_stream_t m_streamId;
     QNetworkAccessManager *m_networkManager;
     QNetworkRequest m_networkRequest;
+    ReplayBuffer<qint16> m_replayBuffer;
 
     bool openDevice();
     void closeDevice();
diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp
index 3a387c44c..b5e72e3bf 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp
@@ -469,6 +469,10 @@ void LimeSDRInputGUI::displaySettings()
     setNCODisplay();
 
     ui->ncoEnable->setChecked(m_settings.m_ncoEnable);
+    displayReplayLength();
+    displayReplayOffset();
+    displayReplayStep();
+    ui->replayLoop->setChecked(m_settings.m_replayLoop);
 }
 
 void LimeSDRInputGUI::setNCODisplay()
@@ -805,6 +809,9 @@ void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p)
     if (m_contextMenuType == ContextMenuDeviceSettings)
     {
         BasicDeviceSettingsDialog dialog(this);
+        dialog.setReplayBytesPerSecond(m_settings.m_devSampleRate * 2 * sizeof(qint16));
+        dialog.setReplayLength(m_settings.m_replayLength);
+        dialog.setReplayStep(m_settings.m_replayStep);
         dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
         dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
         dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
@@ -818,10 +825,17 @@ void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p)
         m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
         m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
         m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
+        m_settings.m_replayLength = dialog.getReplayLength();
+        m_settings.m_replayStep = dialog.getReplayStep();
+        displayReplayLength();
+        displayReplayOffset();
+        displayReplayStep();
         m_settingsKeys.append("useReverseAPI");
         m_settingsKeys.append("reverseAPIAddress");
         m_settingsKeys.append("reverseAPIPort");
         m_settingsKeys.append("reverseAPIDeviceIndex");
+        m_settingsKeys.append("replayLength");
+        m_settingsKeys.append("replayStep");
 
         sendSettings();
     }
@@ -829,6 +843,96 @@ void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p)
     resetContextMenuType();
 }
 
+void LimeSDRInputGUI::displayReplayLength()
+{
+    bool replayEnabled = m_settings.m_replayLength > 0.0f;
+    if (!replayEnabled) {
+        ui->replayOffset->setMaximum(0);
+    } else {
+        ui->replayOffset->setMaximum(m_settings.m_replayLength * 10 - 1);
+    }
+    ui->replayLabel->setEnabled(replayEnabled);
+    ui->replayOffset->setEnabled(replayEnabled);
+    ui->replayOffsetText->setEnabled(replayEnabled);
+    ui->replaySave->setEnabled(replayEnabled);
+}
+
+void LimeSDRInputGUI::displayReplayOffset()
+{
+    bool replayEnabled = m_settings.m_replayLength > 0.0f;
+    ui->replayOffset->setValue(m_settings.m_replayOffset * 10);
+    ui->replayOffsetText->setText(QString("%1s").arg(m_settings.m_replayOffset, 0, 'f', 1));
+    ui->replayNow->setEnabled(replayEnabled && (m_settings.m_replayOffset > 0.0f));
+    ui->replayPlus->setEnabled(replayEnabled && (std::round(m_settings.m_replayOffset * 10) < ui->replayOffset->maximum()));
+    ui->replayMinus->setEnabled(replayEnabled && (m_settings.m_replayOffset > 0.0f));
+}
+
+void LimeSDRInputGUI::displayReplayStep()
+{
+    QString step;
+    float intpart;
+    float frac = modf(m_settings.m_replayStep, &intpart);
+    if (frac == 0.0f) {
+        step = QString::number((int)intpart);
+    } else {
+        step = QString::number(m_settings.m_replayStep, 'f', 1);
+    }
+    ui->replayPlus->setText(QString("+%1s").arg(step));
+    ui->replayPlus->setToolTip(QString("Add %1 seconds to time delay").arg(step));
+    ui->replayMinus->setText(QString("-%1s").arg(step));
+    ui->replayMinus->setToolTip(QString("Remove %1 seconds from time delay").arg(step));
+}
+
+void LimeSDRInputGUI::on_replayOffset_valueChanged(int value)
+{
+    m_settings.m_replayOffset = value / 10.0f;
+    displayReplayOffset();
+    m_settingsKeys.append("replayOffset");
+    sendSettings();
+}
+
+void LimeSDRInputGUI::on_replayNow_clicked()
+{
+    ui->replayOffset->setValue(0);
+}
+
+void LimeSDRInputGUI::on_replayPlus_clicked()
+{
+    ui->replayOffset->setValue(ui->replayOffset->value() + m_settings.m_replayStep * 10);
+}
+
+void LimeSDRInputGUI::on_replayMinus_clicked()
+{
+    ui->replayOffset->setValue(ui->replayOffset->value() - m_settings.m_replayStep * 10);
+}
+
+void LimeSDRInputGUI::on_replaySave_clicked()
+{
+    QFileDialog fileDialog(nullptr, "Select file to save IQ data to", "", "*.wav");
+    fileDialog.setAcceptMode(QFileDialog::AcceptSave);
+    if (fileDialog.exec())
+    {
+        QStringList fileNames = fileDialog.selectedFiles();
+        if (fileNames.size() > 0)
+        {
+            LimeSDRInput::MsgSaveReplay *message = LimeSDRInput::MsgSaveReplay::create(fileNames[0]);
+            m_limeSDRInput->getInputMessageQueue()->push(message);
+        }
+    }
+}
+
+void LimeSDRInputGUI::on_replayLoop_toggled(bool checked)
+{
+    m_settings.m_replayLoop = checked;
+    m_settingsKeys.append("replayLoop");
+    sendSettings();
+}
+
+void LimeSDRInputGUI::setReplayTime(float time)
+{
+    ui->replayOffset->setValue(std::ceil(time * 10.0f));
+}
+
 void LimeSDRInputGUI::makeUIConnections()
 {
     QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_startStop_toggled);
@@ -852,4 +956,10 @@ void LimeSDRInputGUI::makeUIConnections()
     QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &LimeSDRInputGUI::on_extClock_clicked);
     QObject::connect(ui->transverter, &TransverterButton::clicked, this, &LimeSDRInputGUI::on_transverter_clicked);
     QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &LimeSDRInputGUI::on_sampleRateMode_toggled);
+    QObject::connect(ui->replayOffset, &QSlider::valueChanged, this, &LimeSDRInputGUI::on_replayOffset_valueChanged);
+    QObject::connect(ui->replayNow, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replayNow_clicked);
+    QObject::connect(ui->replayPlus, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replayPlus_clicked);
+    QObject::connect(ui->replayMinus, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replayMinus_clicked);
+    QObject::connect(ui->replaySave, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replaySave_clicked);
+    QObject::connect(ui->replayLoop, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_replayLoop_toggled);
 }
diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.h b/plugins/samplesource/limesdrinput/limesdrinputgui.h
index 8f49c22fa..3da20c14e 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputgui.h
+++ b/plugins/samplesource/limesdrinput/limesdrinputgui.h
@@ -45,6 +45,7 @@ public:
     QByteArray serialize() const;
     bool deserialize(const QByteArray& data);
     virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+    void setReplayTime(float time) override;
 
 private:
     Ui::LimeSDRInputGUI* ui;
@@ -66,6 +67,9 @@ private:
 
     void displaySettings();
     void displaySampleRate();
+	void displayReplayLength();
+	void displayReplayOffset();
+	void displayReplayStep();
     void setNCODisplay();
     void setCenterFrequencyDisplay();
     void setCenterFrequencySetting(uint64_t kHzValue);
@@ -101,6 +105,12 @@ private slots:
     void on_extClock_clicked();
     void on_transverter_clicked();
     void on_sampleRateMode_toggled(bool checked);
+  	void on_replayOffset_valueChanged(int value);
+	void on_replayNow_clicked();
+	void on_replayPlus_clicked();
+	void on_replayMinus_clicked();
+	void on_replaySave_clicked();
+	void on_replayLoop_toggled(bool checked);
     void openDeviceSettingsDialog(const QPoint& p);
 
     void updateHardware();
diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.ui b/plugins/samplesource/limesdrinput/limesdrinputgui.ui
index baba795b6..5ed2119ce 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputgui.ui
+++ b/plugins/samplesource/limesdrinput/limesdrinputgui.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>360</width>
-    <height>230</height>
+    <height>255</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -19,13 +19,13 @@
   <property name="minimumSize">
    <size>
     <width>360</width>
-    <height>230</height>
+    <height>255</height>
    </size>
   </property>
   <property name="maximumSize">
    <size>
-    <width>380</width>
-    <height>266</height>
+    <width>386</width>
+    <height>280</height>
    </size>
   </property>
   <property name="font">
@@ -1169,6 +1169,104 @@ QToolTip{background-color: white; color: black;}</string>
      </item>
     </layout>
    </item>
+   <item>
+    <layout class="QHBoxLayout" name="replayLayout">
+     <item>
+      <widget class="QLabel" name="replayLabel">
+       <property name="minimumSize">
+        <size>
+         <width>65</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Time Delay</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QSlider" name="replayOffset">
+       <property name="toolTip">
+        <string>Replay time delay in seconds</string>
+       </property>
+       <property name="maximum">
+        <number>500</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="replayOffsetText">
+       <property name="toolTip">
+        <string>Replay time delay in seconds</string>
+       </property>
+       <property name="text">
+        <string>0.0s</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="replayNow">
+       <property name="toolTip">
+        <string>Set time delay to 0 seconds</string>
+       </property>
+       <property name="text">
+        <string>Now</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="replayPlus">
+       <property name="toolTip">
+        <string>Add displayed number of seconds to time delay</string>
+       </property>
+       <property name="text">
+        <string>+5s</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="replayMinus">
+       <property name="toolTip">
+        <string>Remove displayed number of seconds from time delay</string>
+       </property>
+       <property name="text">
+        <string>-5s</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="ButtonSwitch" name="replayLoop">
+       <property name="toolTip">
+        <string>Repeatedly replay data in replay buffer</string>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset resource="../../../sdrgui/resources/res.qrc">
+         <normaloff>:/playloop.png</normaloff>:/playloop.png</iconset>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="replaySave">
+       <property name="toolTip">
+        <string>Save replay buffer to a file</string>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset resource="../../../sdrgui/resources/res.qrc">
+         <normaloff>:/save.png</normaloff>:/save.png</iconset>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
   </layout>
  </widget>
  <customwidgets>
diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp
index 1112d721c..088eafc0e 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp
@@ -51,6 +51,10 @@ void LimeSDRInputSettings::resetToDefaults()
     m_iqOrder = true;
     m_gpioDir = 0;
     m_gpioPins = 0;
+    m_replayOffset = 0.0f;
+    m_replayLength = 20.0f;
+    m_replayStep = 5.0f;
+    m_replayLoop = false;
     m_useReverseAPI = false;
     m_reverseAPIAddress = "127.0.0.1";
     m_reverseAPIPort = 8888;
@@ -88,6 +92,10 @@ QByteArray LimeSDRInputSettings::serialize() const
     s.writeU32(26, m_reverseAPIPort);
     s.writeU32(27, m_reverseAPIDeviceIndex);
     s.writeBool(28, m_iqOrder);
+    s.writeFloat(29, m_replayOffset);
+    s.writeFloat(30, m_replayLength);
+    s.writeFloat(31, m_replayStep);
+    s.writeBool(32, m_replayLoop);
 
     return s.final();
 }
@@ -146,6 +154,10 @@ bool LimeSDRInputSettings::deserialize(const QByteArray& data)
         d.readU32(27, &uintval, 0);
         m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval;
         d.readBool(28, &m_iqOrder, true);
+        d.readFloat(29, &m_replayOffset, 0.0f);
+        d.readFloat(30, &m_replayLength, 20.0f);
+        d.readFloat(31, &m_replayStep, 5.0f);
+        d.readBool(32, &m_replayLoop, false);
 
         return true;
     }
@@ -231,6 +243,18 @@ void LimeSDRInputSettings::applySettings(const QStringList& settingsKeys, const
     if (settingsKeys.contains("gpioPins")) {
         m_gpioPins = settings.m_gpioPins;
     }
+    if (settingsKeys.contains("replayOffset")) {
+        m_replayOffset = settings.m_replayOffset;
+    }
+    if (settingsKeys.contains("replayLength")) {
+        m_replayLength = settings.m_replayLength;
+    }
+    if (settingsKeys.contains("replayStep")) {
+        m_replayStep = settings.m_replayStep;
+    }
+    if (settingsKeys.contains("replayLoop")) {
+        m_replayLoop = settings.m_replayLoop;
+    }
     if (settingsKeys.contains("useReverseAPI")) {
         m_useReverseAPI = settings.m_useReverseAPI;
     }
@@ -321,6 +345,18 @@ QString LimeSDRInputSettings::getDebugString(const QStringList& settingsKeys, bo
     if (settingsKeys.contains("gpioPins") || force) {
         ostr << " m_gpioPins: " << m_gpioPins;
     }
+    if (settingsKeys.contains("replayOffset") || force) {
+        ostr << " m_replayOffset: " << m_replayOffset;
+    }
+    if (settingsKeys.contains("replayLength") || force) {
+        ostr << " m_replayLength: " << m_replayLength;
+    }
+    if (settingsKeys.contains("replayStep") || force) {
+        ostr << " m_replayStep: " << m_replayStep;
+    }
+    if (settingsKeys.contains("replayLoop") || force) {
+        ostr << " m_replayLoop: " << m_replayLoop;
+    }
     if (settingsKeys.contains("useReverseAPI") || force) {
         ostr << " m_useReverseAPI: " << m_useReverseAPI;
     }
diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.h b/plugins/samplesource/limesdrinput/limesdrinputsettings.h
index 84c2a3a93..67b8a5c3c 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputsettings.h
+++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.h
@@ -71,6 +71,10 @@ struct LimeSDRInputSettings
     bool     m_iqOrder;
     uint8_t  m_gpioDir;      //!< GPIO pin direction LSB first; 0 input, 1 output
     uint8_t  m_gpioPins;     //!< GPIO pins to write; LSB first
+	float    m_replayOffset; //!< Replay offset in seconds
+	float    m_replayLength; //!< Replay buffer size in seconds
+	float    m_replayStep;   //!< Replay forward/back step size in seconds
+	bool     m_replayLoop;   //!< Replay buffer repeatedly without recording new data
     bool     m_useReverseAPI;
     QString  m_reverseAPIAddress;
     uint16_t m_reverseAPIPort;
diff --git a/plugins/samplesource/limesdrinput/limesdrinputthread.cpp b/plugins/samplesource/limesdrinput/limesdrinputthread.cpp
index cb5df8c20..7ec9ebca0 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputthread.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinputthread.cpp
@@ -18,15 +18,18 @@
 #include <errno.h>
 #include <algorithm>
 
+#include "dsp/replaybuffer.h"
 #include "limesdrinputsettings.h"
 #include "limesdrinputthread.h"
 
-LimeSDRInputThread::LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo, QObject* parent) :
+LimeSDRInputThread::LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo,
+        ReplayBuffer<qint16> *replayBuffer, QObject* parent) :
     QThread(parent),
     m_running(false),
     m_stream(stream),
     m_convertBuffer(DeviceLimeSDR::blockSize),
     m_sampleFifo(sampleFifo),
+    m_replayBuffer(replayBuffer),
     m_log2Decim(0),
     m_iqOrder(true)
 {
@@ -106,70 +109,116 @@ void LimeSDRInputThread::run()
 }
 
 //  Decimate according to specified log2 (ex: log2=4 => decim=16)
-void LimeSDRInputThread::callbackIQ(const qint16* buf, qint32 len)
+void LimeSDRInputThread::callbackIQ(const qint16* inBuf, qint32 len)
 {
     SampleVector::iterator it = m_convertBuffer.begin();
 
-    switch (m_log2Decim)
-    {
-    case 0:
-        m_decimatorsIQ.decimate1(&it, buf, len);
-        break;
-    case 1:
-        m_decimatorsIQ.decimate2_cen(&it, buf, len);
-        break;
-    case 2:
-        m_decimatorsIQ.decimate4_cen(&it, buf, len);
-        break;
-    case 3:
-        m_decimatorsIQ.decimate8_cen(&it, buf, len);
-        break;
-    case 4:
-        m_decimatorsIQ.decimate16_cen(&it, buf, len);
-        break;
-    case 5:
-        m_decimatorsIQ.decimate32_cen(&it, buf, len);
-        break;
-    case 6:
-        m_decimatorsIQ.decimate64_cen(&it, buf, len);
-        break;
-    default:
-        break;
+    // Save data to replay buffer
+	m_replayBuffer->lock();
+	bool replayEnabled = m_replayBuffer->getSize() > 0;
+	if (replayEnabled) {
+		m_replayBuffer->write(inBuf, len);
+	}
+
+	const qint16* buf = inBuf;
+	qint32 remaining = len;
+
+    while (remaining > 0)
+	{
+		// Choose between live data or replayed data
+		if (replayEnabled && m_replayBuffer->useReplay()) {
+			len = m_replayBuffer->read(remaining, buf);
+		} else {
+			len = remaining;
+		}
+		remaining -= len;
+
+        switch (m_log2Decim)
+        {
+        case 0:
+            m_decimatorsIQ.decimate1(&it, buf, len);
+            break;
+        case 1:
+            m_decimatorsIQ.decimate2_cen(&it, buf, len);
+            break;
+        case 2:
+            m_decimatorsIQ.decimate4_cen(&it, buf, len);
+            break;
+        case 3:
+            m_decimatorsIQ.decimate8_cen(&it, buf, len);
+            break;
+        case 4:
+            m_decimatorsIQ.decimate16_cen(&it, buf, len);
+            break;
+        case 5:
+            m_decimatorsIQ.decimate32_cen(&it, buf, len);
+            break;
+        case 6:
+            m_decimatorsIQ.decimate64_cen(&it, buf, len);
+            break;
+        default:
+            break;
+        }
     }
 
+    m_replayBuffer->unlock();
+
     m_sampleFifo->write(m_convertBuffer.begin(), it);
 }
 
-void LimeSDRInputThread::callbackQI(const qint16* buf, qint32 len)
+void LimeSDRInputThread::callbackQI(const qint16* inBuf, qint32 len)
 {
     SampleVector::iterator it = m_convertBuffer.begin();
 
-    switch (m_log2Decim)
-    {
-    case 0:
-        m_decimatorsQI.decimate1(&it, buf, len);
-        break;
-    case 1:
-        m_decimatorsQI.decimate2_cen(&it, buf, len);
-        break;
-    case 2:
-        m_decimatorsQI.decimate4_cen(&it, buf, len);
-        break;
-    case 3:
-        m_decimatorsQI.decimate8_cen(&it, buf, len);
-        break;
-    case 4:
-        m_decimatorsQI.decimate16_cen(&it, buf, len);
-        break;
-    case 5:
-        m_decimatorsQI.decimate32_cen(&it, buf, len);
-        break;
-    case 6:
-        m_decimatorsQI.decimate64_cen(&it, buf, len);
-        break;
-    default:
-        break;
-    }
+    // Save data to replay buffer
+	m_replayBuffer->lock();
+	bool replayEnabled = m_replayBuffer->getSize() > 0;
+	if (replayEnabled) {
+		m_replayBuffer->write(inBuf, len);
+	}
+
+	const qint16* buf = inBuf;
+	qint32 remaining = len;
+
+    while (remaining > 0)
+	{
+		// Choose between live data or replayed data
+		if (replayEnabled && m_replayBuffer->useReplay()) {
+			len = m_replayBuffer->read(remaining, buf);
+		} else {
+			len = remaining;
+		}
+		remaining -= len;
+
+        switch (m_log2Decim)
+        {
+        case 0:
+            m_decimatorsQI.decimate1(&it, buf, len);
+            break;
+        case 1:
+            m_decimatorsQI.decimate2_cen(&it, buf, len);
+            break;
+        case 2:
+            m_decimatorsQI.decimate4_cen(&it, buf, len);
+            break;
+        case 3:
+            m_decimatorsQI.decimate8_cen(&it, buf, len);
+            break;
+        case 4:
+            m_decimatorsQI.decimate16_cen(&it, buf, len);
+            break;
+        case 5:
+            m_decimatorsQI.decimate32_cen(&it, buf, len);
+            break;
+        case 6:
+            m_decimatorsQI.decimate64_cen(&it, buf, len);
+            break;
+        default:
+            break;
+        }
+            }
+
+    m_replayBuffer->unlock();
 
     m_sampleFifo->write(m_convertBuffer.begin(), it);
 }
diff --git a/plugins/samplesource/limesdrinput/limesdrinputthread.h b/plugins/samplesource/limesdrinput/limesdrinputthread.h
index 7fe318494..1c473de40 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputthread.h
+++ b/plugins/samplesource/limesdrinput/limesdrinputthread.h
@@ -37,7 +37,8 @@ class LimeSDRInputThread : public QThread, public DeviceLimeSDRShared::ThreadInt
     Q_OBJECT
 
 public:
-    LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo, QObject* parent = 0);
+    LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo,
+        ReplayBuffer<qint16> *replayBuffer, QObject* parent = 0);
     ~LimeSDRInputThread();
 
     virtual void startWork();
@@ -56,6 +57,7 @@ private:
     qint16 m_buf[2*DeviceLimeSDR::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size
     SampleVector m_convertBuffer;
     SampleSinkFifo* m_sampleFifo;
+	ReplayBuffer<qint16> *m_replayBuffer;
 
     unsigned int m_log2Decim; // soft decimation
     bool m_iqOrder;

From c30af7f39f8d5f910052098b32020ac5ebd03ec7 Mon Sep 17 00:00:00 2001
From: srcejon <jon@beniston.com>
Date: Wed, 6 Dec 2023 10:14:01 +0000
Subject: [PATCH 3/5] Fix gcc warnings.

---
 sdrgui/device/devicegui.h     | 2 +-
 sdrgui/device/deviceuiset.cpp | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/sdrgui/device/devicegui.h b/sdrgui/device/devicegui.h
index 94eb2a4c6..c376c2c7e 100644
--- a/sdrgui/device/devicegui.h
+++ b/sdrgui/device/devicegui.h
@@ -81,7 +81,7 @@ public:
     void setCurrentDeviceIndex(int index) { m_currentDeviceIndex = index; } //!< index in plugins list
     void setChannelNames(const QStringList& channelNames) { m_channelAddDialog.addChannelNames(channelNames); }
     DeviceUISet* getDeviceUISet() { return m_deviceUISet; }
-    virtual void setReplayTime(float time) {} //!< Not supported by all devices
+    virtual void setReplayTime(float time) { (void) time; } //!< Not supported by all devices
 
 protected:
     void closeEvent(QCloseEvent *event) override;
diff --git a/sdrgui/device/deviceuiset.cpp b/sdrgui/device/deviceuiset.cpp
index 53bde72f2..0de391efc 100644
--- a/sdrgui/device/deviceuiset.cpp
+++ b/sdrgui/device/deviceuiset.cpp
@@ -830,6 +830,8 @@ int DeviceUISet::webapiSpectrumServerDelete(SWGSDRangel::SWGSuccessResponse& res
 
 void DeviceUISet::onTimeSelected(int deviceSetIndex, float time)
 {
+    (void) deviceSetIndex;
+
     if (m_deviceGUI) {
         m_deviceGUI->setReplayTime(time);
     }

From 720630c2fbd154cd1ac5a84b7d02a1fa89230430 Mon Sep 17 00:00:00 2001
From: srcejon <jon@beniston.com>
Date: Wed, 6 Dec 2023 10:53:28 +0000
Subject: [PATCH 4/5] Remove tabs.

---
 .../samplesource/airspyhf/airspyhfworker.cpp  |  68 +--
 .../limesdrinput/limesdrinputthread.cpp       |  62 +--
 plugins/samplesource/rtlsdr/rtlsdrthread.cpp  | 432 +++++++++---------
 .../sdrplayv3/sdrplayv3thread.cpp             |  60 +--
 .../usrpinput/usrpinputthread.cpp             |  30 +-
 5 files changed, 326 insertions(+), 326 deletions(-)

diff --git a/plugins/samplesource/airspyhf/airspyhfworker.cpp b/plugins/samplesource/airspyhf/airspyhfworker.cpp
index 82d6549ad..8c1977df2 100644
--- a/plugins/samplesource/airspyhf/airspyhfworker.cpp
+++ b/plugins/samplesource/airspyhf/airspyhfworker.cpp
@@ -77,27 +77,27 @@ void AirspyHFWorker::setLog2Decimation(unsigned int log2_decim)
 //  Decimate according to specified log2 (ex: log2=4 => decim=16)
 void AirspyHFWorker::callbackIQ(const float* inBuf, qint32 len)
 {
-	SampleVector::iterator it = m_convertBuffer.begin();
+    SampleVector::iterator it = m_convertBuffer.begin();
 
     // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const float* buf = inBuf;
-	qint32 remaining = len;
+    const float* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         switch (m_log2Decim)
         {
@@ -135,32 +135,32 @@ void AirspyHFWorker::callbackIQ(const float* inBuf, qint32 len)
 
     m_replayBuffer->unlock();
 
-	m_sampleFifo->write(m_convertBuffer.begin(), it);
+    m_sampleFifo->write(m_convertBuffer.begin(), it);
 }
 
 void AirspyHFWorker::callbackQI(const float* inBuf, qint32 len)
 {
-	SampleVector::iterator it = m_convertBuffer.begin();
+    SampleVector::iterator it = m_convertBuffer.begin();
 
    // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const float* buf = inBuf;
-	qint32 remaining = len;
+    const float* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         switch (m_log2Decim)
         {
@@ -198,7 +198,7 @@ void AirspyHFWorker::callbackQI(const float* inBuf, qint32 len)
 
     m_replayBuffer->unlock();
 
-	m_sampleFifo->write(m_convertBuffer.begin(), it);
+    m_sampleFifo->write(m_convertBuffer.begin(), it);
 }
 
 int AirspyHFWorker::rx_callback(airspyhf_transfer_t* transfer)
diff --git a/plugins/samplesource/limesdrinput/limesdrinputthread.cpp b/plugins/samplesource/limesdrinput/limesdrinputthread.cpp
index 7ec9ebca0..2ec3f4164 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputthread.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinputthread.cpp
@@ -114,24 +114,24 @@ void LimeSDRInputThread::callbackIQ(const qint16* inBuf, qint32 len)
     SampleVector::iterator it = m_convertBuffer.begin();
 
     // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const qint16* buf = inBuf;
-	qint32 remaining = len;
+    const qint16* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         switch (m_log2Decim)
         {
@@ -171,24 +171,24 @@ void LimeSDRInputThread::callbackQI(const qint16* inBuf, qint32 len)
     SampleVector::iterator it = m_convertBuffer.begin();
 
     // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const qint16* buf = inBuf;
-	qint32 remaining = len;
+    const qint16* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         switch (m_log2Decim)
         {
@@ -216,7 +216,7 @@ void LimeSDRInputThread::callbackQI(const qint16* inBuf, qint32 len)
         default:
             break;
         }
-            }
+    }
 
     m_replayBuffer->unlock();
 
diff --git a/plugins/samplesource/rtlsdr/rtlsdrthread.cpp b/plugins/samplesource/rtlsdr/rtlsdrthread.cpp
index a51e7a0ed..49e81a3fc 100644
--- a/plugins/samplesource/rtlsdr/rtlsdrthread.cpp
+++ b/plugins/samplesource/rtlsdr/rtlsdrthread.cpp
@@ -98,240 +98,240 @@ void RTLSDRThread::run()
 //  Len is total samples (i.e. one I and Q pair will have len=2)
 void RTLSDRThread::callbackIQ(const quint8* inBuf, qint32 len)
 {
-	SampleVector::iterator it = m_convertBuffer.begin();
+    SampleVector::iterator it = m_convertBuffer.begin();
 
-	// Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    // Save data to replay buffer
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const quint8* buf = inBuf;
-	qint32 remaining = len;
+    const quint8* buf = inBuf;
+    qint32 remaining = len;
 
-	while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    while (remaining > 0)
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
-		if (m_log2Decim == 0)
-		{
-			m_decimatorsIQ.decimate1(&it, buf, len);
-		}
-		else
-		{
-			if (m_fcPos == 0) // Infradyne
-			{
-				switch (m_log2Decim)
-				{
-				case 1:
-					m_decimatorsIQ.decimate2_inf(&it, buf, len);
-					break;
-				case 2:
-					m_decimatorsIQ.decimate4_inf(&it, buf, len);
-					break;
-				case 3:
-					m_decimatorsIQ.decimate8_inf(&it, buf, len);
-					break;
-				case 4:
-					m_decimatorsIQ.decimate16_inf(&it, buf, len);
-					break;
-				case 5:
-					m_decimatorsIQ.decimate32_inf(&it, buf, len);
-					break;
-				case 6:
-					m_decimatorsIQ.decimate64_inf(&it, buf, len);
-					break;
-				default:
-					break;
-				}
-			}
-			else if (m_fcPos == 1) // Supradyne
-			{
-				switch (m_log2Decim)
-				{
-				case 1:
-					m_decimatorsIQ.decimate2_sup(&it, buf, len);
-					break;
-				case 2:
-					m_decimatorsIQ.decimate4_sup(&it, buf, len);
-					break;
-				case 3:
-					m_decimatorsIQ.decimate8_sup(&it, buf, len);
-					break;
-				case 4:
-					m_decimatorsIQ.decimate16_sup(&it, buf, len);
-					break;
-				case 5:
-					m_decimatorsIQ.decimate32_sup(&it, buf, len);
-					break;
-				case 6:
-					m_decimatorsIQ.decimate64_sup(&it, buf, len);
-					break;
-				default:
-					break;
-				}
-			}
-			else // Centered
-			{
-				switch (m_log2Decim)
-				{
-				case 1:
-					m_decimatorsIQ.decimate2_cen(&it, buf, len);
-					break;
-				case 2:
-					m_decimatorsIQ.decimate4_cen(&it, buf, len);
-					break;
-				case 3:
-					m_decimatorsIQ.decimate8_cen(&it, buf, len);
-					break;
-				case 4:
-					m_decimatorsIQ.decimate16_cen(&it, buf, len);
-					break;
-				case 5:
-					m_decimatorsIQ.decimate32_cen(&it, buf, len);
-					break;
-				case 6:
-					m_decimatorsIQ.decimate64_cen(&it, buf, len);
-					break;
-				default:
-					break;
-				}
-			}
-		}
-	}
+        if (m_log2Decim == 0)
+        {
+            m_decimatorsIQ.decimate1(&it, buf, len);
+        }
+        else
+        {
+            if (m_fcPos == 0) // Infradyne
+            {
+                switch (m_log2Decim)
+                {
+                case 1:
+                    m_decimatorsIQ.decimate2_inf(&it, buf, len);
+                    break;
+                case 2:
+                    m_decimatorsIQ.decimate4_inf(&it, buf, len);
+                    break;
+                case 3:
+                    m_decimatorsIQ.decimate8_inf(&it, buf, len);
+                    break;
+                case 4:
+                    m_decimatorsIQ.decimate16_inf(&it, buf, len);
+                    break;
+                case 5:
+                    m_decimatorsIQ.decimate32_inf(&it, buf, len);
+                    break;
+                case 6:
+                    m_decimatorsIQ.decimate64_inf(&it, buf, len);
+                    break;
+                default:
+                    break;
+                }
+            }
+            else if (m_fcPos == 1) // Supradyne
+            {
+                switch (m_log2Decim)
+                {
+                case 1:
+                    m_decimatorsIQ.decimate2_sup(&it, buf, len);
+                    break;
+                case 2:
+                    m_decimatorsIQ.decimate4_sup(&it, buf, len);
+                    break;
+                case 3:
+                    m_decimatorsIQ.decimate8_sup(&it, buf, len);
+                    break;
+                case 4:
+                    m_decimatorsIQ.decimate16_sup(&it, buf, len);
+                    break;
+                case 5:
+                    m_decimatorsIQ.decimate32_sup(&it, buf, len);
+                    break;
+                case 6:
+                    m_decimatorsIQ.decimate64_sup(&it, buf, len);
+                    break;
+                default:
+                    break;
+                }
+            }
+            else // Centered
+            {
+                switch (m_log2Decim)
+                {
+                case 1:
+                    m_decimatorsIQ.decimate2_cen(&it, buf, len);
+                    break;
+                case 2:
+                    m_decimatorsIQ.decimate4_cen(&it, buf, len);
+                    break;
+                case 3:
+                    m_decimatorsIQ.decimate8_cen(&it, buf, len);
+                    break;
+                case 4:
+                    m_decimatorsIQ.decimate16_cen(&it, buf, len);
+                    break;
+                case 5:
+                    m_decimatorsIQ.decimate32_cen(&it, buf, len);
+                    break;
+                case 6:
+                    m_decimatorsIQ.decimate64_cen(&it, buf, len);
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+    }
 
-	m_replayBuffer->unlock();
+    m_replayBuffer->unlock();
 
-	m_sampleFifo->write(m_convertBuffer.begin(), it);
+    m_sampleFifo->write(m_convertBuffer.begin(), it);
 
-	if(!m_running)
-		rtlsdr_cancel_async(m_dev);
+    if(!m_running)
+        rtlsdr_cancel_async(m_dev);
 }
 
 void RTLSDRThread::callbackQI(const quint8* inBuf, qint32 len)
 {
-	SampleVector::iterator it = m_convertBuffer.begin();
+    SampleVector::iterator it = m_convertBuffer.begin();
 
-	// Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    // Save data to replay buffer
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const quint8* buf = inBuf;
-	qint32 remaining = len;
+    const quint8* buf = inBuf;
+    qint32 remaining = len;
 
-	while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    while (remaining > 0)
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
-		if (m_log2Decim == 0)
-		{
-			m_decimatorsQI.decimate1(&it, buf, len);
-		}
-		else
-		{
-			if (m_fcPos == 0) // Infradyne
-			{
-				switch (m_log2Decim)
-				{
-				case 1:
-					m_decimatorsQI.decimate2_inf(&it, buf, len);
-					break;
-				case 2:
-					m_decimatorsQI.decimate4_inf(&it, buf, len);
-					break;
-				case 3:
-					m_decimatorsQI.decimate8_inf(&it, buf, len);
-					break;
-				case 4:
-					m_decimatorsQI.decimate16_inf(&it, buf, len);
-					break;
-				case 5:
-					m_decimatorsQI.decimate32_inf(&it, buf, len);
-					break;
-				case 6:
-					m_decimatorsQI.decimate64_inf(&it, buf, len);
-					break;
-				default:
-					break;
-				}
-			}
-			else if (m_fcPos == 1) // Supradyne
-			{
-				switch (m_log2Decim)
-				{
-				case 1:
-					m_decimatorsQI.decimate2_sup(&it, buf, len);
-					break;
-				case 2:
-					m_decimatorsQI.decimate4_sup(&it, buf, len);
-					break;
-				case 3:
-					m_decimatorsQI.decimate8_sup(&it, buf, len);
-					break;
-				case 4:
-					m_decimatorsQI.decimate16_sup(&it, buf, len);
-					break;
-				case 5:
-					m_decimatorsQI.decimate32_sup(&it, buf, len);
-					break;
-				case 6:
-					m_decimatorsQI.decimate64_sup(&it, buf, len);
-					break;
-				default:
-					break;
-				}
-			}
-			else // Centered
-			{
-				switch (m_log2Decim)
-				{
-				case 1:
-					m_decimatorsQI.decimate2_cen(&it, buf, len);
-					break;
-				case 2:
-					m_decimatorsQI.decimate4_cen(&it, buf, len);
-					break;
-				case 3:
-					m_decimatorsQI.decimate8_cen(&it, buf, len);
-					break;
-				case 4:
-					m_decimatorsQI.decimate16_cen(&it, buf, len);
-					break;
-				case 5:
-					m_decimatorsQI.decimate32_cen(&it, buf, len);
-					break;
-				case 6:
-					m_decimatorsQI.decimate64_cen(&it, buf, len);
-					break;
-				default:
-					break;
-				}
-			}
-		}
-	}
+        if (m_log2Decim == 0)
+        {
+            m_decimatorsQI.decimate1(&it, buf, len);
+        }
+        else
+        {
+            if (m_fcPos == 0) // Infradyne
+            {
+                switch (m_log2Decim)
+                {
+                case 1:
+                    m_decimatorsQI.decimate2_inf(&it, buf, len);
+                    break;
+                case 2:
+                    m_decimatorsQI.decimate4_inf(&it, buf, len);
+                    break;
+                case 3:
+                    m_decimatorsQI.decimate8_inf(&it, buf, len);
+                    break;
+                case 4:
+                    m_decimatorsQI.decimate16_inf(&it, buf, len);
+                    break;
+                case 5:
+                    m_decimatorsQI.decimate32_inf(&it, buf, len);
+                    break;
+                case 6:
+                    m_decimatorsQI.decimate64_inf(&it, buf, len);
+                    break;
+                default:
+                    break;
+                }
+            }
+            else if (m_fcPos == 1) // Supradyne
+            {
+                switch (m_log2Decim)
+                {
+                case 1:
+                    m_decimatorsQI.decimate2_sup(&it, buf, len);
+                    break;
+                case 2:
+                    m_decimatorsQI.decimate4_sup(&it, buf, len);
+                    break;
+                case 3:
+                    m_decimatorsQI.decimate8_sup(&it, buf, len);
+                    break;
+                case 4:
+                    m_decimatorsQI.decimate16_sup(&it, buf, len);
+                    break;
+                case 5:
+                    m_decimatorsQI.decimate32_sup(&it, buf, len);
+                    break;
+                case 6:
+                    m_decimatorsQI.decimate64_sup(&it, buf, len);
+                    break;
+                default:
+                    break;
+                }
+            }
+            else // Centered
+            {
+                switch (m_log2Decim)
+                {
+                case 1:
+                    m_decimatorsQI.decimate2_cen(&it, buf, len);
+                    break;
+                case 2:
+                    m_decimatorsQI.decimate4_cen(&it, buf, len);
+                    break;
+                case 3:
+                    m_decimatorsQI.decimate8_cen(&it, buf, len);
+                    break;
+                case 4:
+                    m_decimatorsQI.decimate16_cen(&it, buf, len);
+                    break;
+                case 5:
+                    m_decimatorsQI.decimate32_cen(&it, buf, len);
+                    break;
+                case 6:
+                    m_decimatorsQI.decimate64_cen(&it, buf, len);
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+    }
 
-	m_replayBuffer->unlock();
+    m_replayBuffer->unlock();
 
-	m_sampleFifo->write(m_convertBuffer.begin(), it);
+    m_sampleFifo->write(m_convertBuffer.begin(), it);
 
-	if(!m_running)
-		rtlsdr_cancel_async(m_dev);
+    if(!m_running)
+        rtlsdr_cancel_async(m_dev);
 }
 
 void RTLSDRThread::callbackHelper(unsigned char* buf, uint32_t len, void* ctx)
diff --git a/plugins/samplesource/sdrplayv3/sdrplayv3thread.cpp b/plugins/samplesource/sdrplayv3/sdrplayv3thread.cpp
index e4f069ac2..7e6a52617 100644
--- a/plugins/samplesource/sdrplayv3/sdrplayv3thread.cpp
+++ b/plugins/samplesource/sdrplayv3/sdrplayv3thread.cpp
@@ -177,24 +177,24 @@ void SDRPlayV3Thread::callbackIQ(const qint16* inBuf, qint32 len)
     SampleVector::iterator it = m_convertBuffer.begin();
 
     // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const qint16* buf = inBuf;
-	qint32 remaining = len;
+    const qint16* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         if (m_log2Decim == 0)
         {
@@ -293,24 +293,24 @@ void SDRPlayV3Thread::callbackQI(const qint16* inBuf, qint32 len)
     SampleVector::iterator it = m_convertBuffer.begin();
 
     // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const qint16* buf = inBuf;
-	qint32 remaining = len;
+    const qint16* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         if (m_log2Decim == 0)
         {
diff --git a/plugins/samplesource/usrpinput/usrpinputthread.cpp b/plugins/samplesource/usrpinput/usrpinputthread.cpp
index 5f2ffd5c8..b53d60b2a 100644
--- a/plugins/samplesource/usrpinput/usrpinputthread.cpp
+++ b/plugins/samplesource/usrpinput/usrpinputthread.cpp
@@ -198,24 +198,24 @@ void USRPInputThread::callbackIQ(const qint16* inBuf, qint32 len)
     SampleVector::iterator it = m_convertBuffer.begin();
 
     // Save data to replay buffer
-	m_replayBuffer->lock();
-	bool replayEnabled = m_replayBuffer->getSize() > 0;
-	if (replayEnabled) {
-		m_replayBuffer->write(inBuf, len);
-	}
+    m_replayBuffer->lock();
+    bool replayEnabled = m_replayBuffer->getSize() > 0;
+    if (replayEnabled) {
+        m_replayBuffer->write(inBuf, len);
+    }
 
-	const qint16* buf = inBuf;
-	qint32 remaining = len;
+    const qint16* buf = inBuf;
+    qint32 remaining = len;
 
     while (remaining > 0)
-	{
-		// Choose between live data or replayed data
-		if (replayEnabled && m_replayBuffer->useReplay()) {
-			len = m_replayBuffer->read(remaining, buf);
-		} else {
-			len = remaining;
-		}
-		remaining -= len;
+    {
+        // Choose between live data or replayed data
+        if (replayEnabled && m_replayBuffer->useReplay()) {
+            len = m_replayBuffer->read(remaining, buf);
+        } else {
+            len = remaining;
+        }
+        remaining -= len;
 
         switch (m_log2Decim)
         {

From 30497b5204828d8241fa22479a26f43b94fa442d Mon Sep 17 00:00:00 2001
From: srcejon <jon@beniston.com>
Date: Wed, 6 Dec 2023 13:08:09 +0000
Subject: [PATCH 5/5] More fixes for Mac build

---
 .github/workflows/sdrangel.yml | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/.github/workflows/sdrangel.yml b/.github/workflows/sdrangel.yml
index 5ad2b6e86..5fb05eada 100644
--- a/.github/workflows/sdrangel.yml
+++ b/.github/workflows/sdrangel.yml
@@ -130,6 +130,14 @@ jobs:
         id: get_filename
         run: echo "filename=$(grep CPACK_PACKAGE_FILE_NAME build/CMakeCache.txt | cut -d "=" -f2)" >> $GITHUB_OUTPUT
       - name: Build SDRangel on Mac
+        run: |
+          cd build
+          make -j3
+      - name: Stop XProtectBehaviorService
+        run: |
+          echo "killing XProject as it can interfere with hdiutil"; sudo pkill -9 XProtect >/dev/null || true;
+          echo "waiting..."; while pgrep XProtect; do sleep 3; done;
+      - name: Build DMG
         run: |
           cd build
           make package -j3