1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-08-14 23:43:43 -04:00

Add instant replay

This commit is contained in:
srcejon
2023-11-22 14:28:35 +00:00
parent cbab429395
commit 7cc9cd1bf1
41 changed files with 2270 additions and 460 deletions
@@ -18,6 +18,7 @@
#include <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include "sdrplayv3gui.h"
#include "sdrplayv3input.h"
@@ -306,6 +307,10 @@ void SDRPlayV3Gui::displaySettings()
ui->gainIF->setValue(gain);
QString gainText = QStringLiteral("%1").arg(gain, 2, 10, QLatin1Char('0'));
ui->gainIFText->setText(gainText);
displayReplayLength();
displayReplayOffset();
displayReplayStep();
ui->replayLoop->setChecked(m_settings.m_replayLoop);
}
void SDRPlayV3Gui::updateLNAValues()
@@ -563,6 +568,9 @@ void SDRPlayV3Gui::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);
@@ -576,10 +584,17 @@ void SDRPlayV3Gui::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();
}
@@ -587,6 +602,91 @@ void SDRPlayV3Gui::openDeviceSettingsDialog(const QPoint& p)
resetContextMenuType();
}
void SDRPlayV3Gui::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 SDRPlayV3Gui::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 SDRPlayV3Gui::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 SDRPlayV3Gui::on_replayOffset_valueChanged(int value)
{
m_settings.m_replayOffset = value / 10.0f;
displayReplayOffset();
m_settingsKeys.append("replayOffset");
sendSettings();
}
void SDRPlayV3Gui::on_replayNow_clicked()
{
ui->replayOffset->setValue(0);
}
void SDRPlayV3Gui::on_replayPlus_clicked()
{
ui->replayOffset->setValue(ui->replayOffset->value() + m_settings.m_replayStep * 10);
}
void SDRPlayV3Gui::on_replayMinus_clicked()
{
ui->replayOffset->setValue(ui->replayOffset->value() - m_settings.m_replayStep * 10);
}
void SDRPlayV3Gui::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)
{
SDRPlayV3Input::MsgSaveReplay *message = SDRPlayV3Input::MsgSaveReplay::create(fileNames[0]);
m_sdrPlayV3Input->getInputMessageQueue()->push(message);
}
}
}
void SDRPlayV3Gui::on_replayLoop_toggled(bool checked)
{
m_settings.m_replayLoop = checked;
m_settingsKeys.append("replayLoop");
sendSettings();
}
void SDRPlayV3Gui::makeUIConnections()
{
QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &SDRPlayV3Gui::on_centerFrequency_changed);
@@ -610,4 +710,10 @@ void SDRPlayV3Gui::makeUIConnections()
QObject::connect(ui->gainIF, &QDial::valueChanged, this, &SDRPlayV3Gui::on_gainIF_valueChanged);
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_startStop_toggled);
QObject::connect(ui->transverter, &TransverterButton::clicked, this, &SDRPlayV3Gui::on_transverter_clicked);
QObject::connect(ui->replayOffset, &QSlider::valueChanged, this, &SDRPlayV3Gui::on_replayOffset_valueChanged);
QObject::connect(ui->replayNow, &QToolButton::clicked, this, &SDRPlayV3Gui::on_replayNow_clicked);
QObject::connect(ui->replayPlus, &QToolButton::clicked, this, &SDRPlayV3Gui::on_replayPlus_clicked);
QObject::connect(ui->replayMinus, &QToolButton::clicked, this, &SDRPlayV3Gui::on_replayMinus_clicked);
QObject::connect(ui->replaySave, &QToolButton::clicked, this, &SDRPlayV3Gui::on_replaySave_clicked);
QObject::connect(ui->replayLoop, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_replayLoop_toggled);
}
@@ -64,6 +64,9 @@ private:
void blockApplySettings(bool block) { m_doApplySettings = !block; }
void displaySettings();
void displayReplayLength();
void displayReplayOffset();
void displayReplayStep();
void updateLNAValues();
void sendSettings();
void updateSampleRateAndFrequency();
@@ -96,6 +99,12 @@ private slots:
void on_gainIF_valueChanged(int value);
void on_startStop_toggled(bool checked);
void on_transverter_clicked();
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);
};
+113 -9
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>360</width>
<height>234</height>
<height>280</height>
</rect>
</property>
<property name="sizePolicy">
@@ -19,13 +19,13 @@
<property name="minimumSize">
<size>
<width>360</width>
<height>234</height>
<height>280</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>409</width>
<height>297</height>
<height>280</height>
</size>
</property>
<property name="font">
@@ -636,7 +636,6 @@
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
@@ -764,20 +763,125 @@
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</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>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<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>
@@ -42,6 +42,7 @@
MESSAGE_CLASS_DEFINITION(SDRPlayV3Input::MsgConfigureSDRPlayV3, Message)
MESSAGE_CLASS_DEFINITION(SDRPlayV3Input::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(SDRPlayV3Input::MsgSaveReplay, Message)
SDRPlayV3Input::SDRPlayV3Input(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
@@ -155,7 +156,7 @@ bool SDRPlayV3Input::start()
if (m_running) stop();
m_sdrPlayThread = new SDRPlayV3Thread(m_dev, &m_sampleFifo);
m_sdrPlayThread = new SDRPlayV3Thread(m_dev, &m_sampleFifo, &m_replayBuffer);
m_sdrPlayThread->setLog2Decimation(m_settings.m_log2Decim);
m_sdrPlayThread->setFcPos((int) m_settings.m_fcPos);
m_sdrPlayThread->startWork();
@@ -306,6 +307,12 @@ bool SDRPlayV3Input::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;
@@ -408,7 +415,10 @@ bool SDRPlayV3Input::applySettings(const SDRPlayV3Settings& settings, const QLis
else
qDebug() << "SDRPlayV3Input::applySettings: sample rate set to " << sampleRate;
forwardChange = true;
}
if (settings.m_devSampleRate != m_settings.m_devSampleRate) {
m_replayBuffer.clear();
}
}
}
if (settingsKeys.contains("log2Decim") || force)
@@ -696,6 +706,18 @@ bool SDRPlayV3Input::applySettings(const SDRPlayV3Settings& settings, const QLis
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);
}
if (forwardChange)
{
int sampleRate = getSampleRate();
@@ -27,6 +27,7 @@
#include <sdrplay_api.h>
#include "dsp/devicesamplesource.h"
#include "dsp/replaybuffer.h"
#include "sdrplayv3settings.h"
class QNetworkAccessManager;
@@ -82,6 +83,25 @@ public:
{ }
};
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)
{ }
};
SDRPlayV3Input(DeviceAPI *deviceAPI);
virtual ~SDRPlayV3Input();
virtual void destroy();
@@ -149,6 +169,7 @@ private:
bool m_running;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
ReplayBuffer<qint16> m_replayBuffer;
bool openDevice();
void closeDevice();
@@ -50,6 +50,10 @@ void SDRPlayV3Settings::resetToDefaults()
m_transverterMode = false;
m_iqOrder = true;
m_transverterDeltaFrequency = 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;
@@ -85,6 +89,10 @@ QByteArray SDRPlayV3Settings::serialize() const
s.writeBool(26, m_transverterMode);
s.writeS64(27, m_transverterDeltaFrequency);
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();
}
@@ -138,6 +146,10 @@ bool SDRPlayV3Settings::deserialize(const QByteArray& data)
d.readBool(26, &m_transverterMode, false);
d.readS64(27, &m_transverterDeltaFrequency, 0);
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;
}
@@ -216,6 +228,18 @@ void SDRPlayV3Settings::applySettings(const QStringList& settingsKeys, const SDR
if (settingsKeys.contains("m_transverterDeltaFrequency")) {
m_transverterDeltaFrequency = settings.m_transverterDeltaFrequency;
}
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;
}
@@ -300,6 +324,18 @@ QString SDRPlayV3Settings::getDebugString(const QStringList& settingsKeys, bool
if (settingsKeys.contains("transverterDeltaFrequency") || force) {
ostr << " m_transverterDeltaFrequency: " << m_transverterDeltaFrequency;
}
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;
}
@@ -53,6 +53,10 @@ struct SDRPlayV3Settings {
bool m_transverterMode;
bool m_iqOrder;
qint64 m_transverterDeltaFrequency;
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;
+202 -155
View File
@@ -27,13 +27,14 @@
#include <QDebug>
SDRPlayV3Thread::SDRPlayV3Thread(sdrplay_api_DeviceT* dev, SampleSinkFifo* sampleFifo, QObject* parent) :
SDRPlayV3Thread::SDRPlayV3Thread(sdrplay_api_DeviceT* dev, SampleSinkFifo* sampleFifo, ReplayBuffer<qint16> *replayBuffer, QObject* parent) :
QThread(parent),
m_running(false),
m_dev(dev),
m_convertBuffer(SDRPLAYV3_INIT_NBSAMPLES),
m_sampleFifo(sampleFifo),
m_samplerate(2000000),
m_replayBuffer(replayBuffer),
m_log2Decim(0),
m_fcPos(0),
m_iqOrder(true),
@@ -171,188 +172,234 @@ void SDRPlayV3Thread::callbackHelper(short *xi, short *xq, sdrplay_api_StreamCbP
}
}
void SDRPlayV3Thread::callbackIQ(const qint16* buf, qint32 len)
void SDRPlayV3Thread::callbackIQ(const qint16* inBuf, qint32 len)
{
SampleVector::iterator it = m_convertBuffer.begin();
if (m_log2Decim == 0)
{
m_decimatorsIQ.decimate1(&it, buf, len);
}
else
{
if (m_fcPos == 0) // Infradyne
// 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;
if (m_log2Decim == 0)
{
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;
}
m_decimatorsIQ.decimate1(&it, buf, len);
}
else if (m_fcPos == 1) // Supradyne
else
{
switch (m_log2Decim)
if (m_fcPos == 0) // Infradyne
{
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;
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 // Centered
{
switch (m_log2Decim)
else if (m_fcPos == 1) // Supradyne
{
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;
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_sampleFifo->write(m_convertBuffer.begin(), it);
}
void SDRPlayV3Thread::callbackQI(const qint16* buf, qint32 len)
void SDRPlayV3Thread::callbackQI(const qint16* inBuf, qint32 len)
{
SampleVector::iterator it = m_convertBuffer.begin();
if (m_log2Decim == 0)
{
m_decimatorsQI.decimate1(&it, buf, len);
}
else
{
if (m_fcPos == 0) // Infradyne
// 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;
if (m_log2Decim == 0)
{
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;
}
m_decimatorsQI.decimate1(&it, buf, len);
}
else if (m_fcPos == 1) // Supradyne
else
{
switch (m_log2Decim)
if (m_fcPos == 0) // Infradyne
{
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;
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 // Centered
{
switch (m_log2Decim)
else if (m_fcPos == 1) // Supradyne
{
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;
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_sampleFifo->write(m_convertBuffer.begin(), it);
}
@@ -29,6 +29,7 @@
#include <sdrplay_api.h>
#include "dsp/samplesinkfifo.h"
#include "dsp/decimators.h"
#include "dsp/replaybuffer.h"
#define SDRPLAYV3_INIT_NBSAMPLES (1<<14)
@@ -36,7 +37,7 @@ class SDRPlayV3Thread : public QThread {
Q_OBJECT
public:
SDRPlayV3Thread(sdrplay_api_DeviceT* dev, SampleSinkFifo* sampleFifo, QObject* parent = NULL);
SDRPlayV3Thread(sdrplay_api_DeviceT* dev, SampleSinkFifo* sampleFifo, ReplayBuffer<qint16> *replayBuffer, QObject* parent = NULL);
~SDRPlayV3Thread();
void startWork();
@@ -58,6 +59,7 @@ private:
sdrplay_api_DeviceT *m_dev;
SampleVector m_convertBuffer;
SampleSinkFifo* m_sampleFifo;
ReplayBuffer<qint16> *m_replayBuffer;
int m_samplerate;
unsigned int m_log2Decim;