Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow recording and playing whole BW also to/from WAV file #1162

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/applications/gqrx/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ MainWindow::MainWindow(const QString& cfgfile, bool edit_conf, QWidget *parent)
connect(&DXCSpots::Get(), SIGNAL(dxcSpotsUpdated()), this, SLOT(updateClusterSpots()));

// I/Q playback
connect(iq_tool, SIGNAL(startRecording(QString)), this, SLOT(startIqRecording(QString)));
connect(iq_tool, SIGNAL(startRecording(QString,receiver::RecordingFormat)),
this, SLOT(startIqRecording(QString,receiver::RecordingFormat)));
connect(iq_tool, SIGNAL(stopRecording()), this, SLOT(stopIqRecording()));
connect(iq_tool, SIGNAL(startPlayback(QString,float,qint64)), this, SLOT(startIqPlayback(QString,float,qint64)));
connect(iq_tool, SIGNAL(stopPlayback()), this, SLOT(stopIqPlayback()));
Expand Down Expand Up @@ -1540,20 +1541,21 @@ void MainWindow::stopAudioStreaming()
}

/** Start I/Q recording. */
void MainWindow::startIqRecording(const QString& recdir)
void MainWindow::startIqRecording(const QString& recdir, const receiver::RecordingFormat format)
{
qDebug() << __func__;
// generate file name using date, time, rf freq in kHz and BW in Hz
// gqrx_iq_yyyymmdd_hhmmss_freq_bw_fc.raw
// gqrx_iq_yyyymmdd_hhmmss_freq_bw_fc.format
const char * const suffix = format == receiver::RecordingFormat::RAW ? "raw" : "wav";
auto freq = (qint64)(rx->get_rf_freq());
auto sr = (qint64)(rx->get_input_rate());
auto dec = (quint32)(rx->get_input_decim());
auto lastRec = QDateTime::currentDateTimeUtc().
toString("%1/gqrx_yyyyMMdd_hhmmss_%2_%3_fc.'raw'")
.arg(recdir).arg(freq).arg(sr/dec);
toString("%1/gqrx_yyyyMMdd_hhmmss_%2_%3_fc.%4")
.arg(recdir).arg(freq).arg(sr/dec).arg(suffix);

// start recorder; fails if recording already in progress
if (rx->start_iq_recording(lastRec.toStdString()))
if (rx->start_iq_recording(lastRec.toStdString(), format))
{
// reset action status
ui->statusBar->showMessage(tr("Error starting I/Q recoder"));
Expand All @@ -1564,7 +1566,6 @@ void MainWindow::startIqRecording(const QString& recdir)
msg_box.setText(tr("There was an error starting the I/Q recorder.\n"
"Check write permissions for the selected location."));
msg_box.exec();

}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/applications/gqrx/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ private slots:
void stopAudioStreaming();

/* I/Q playback and recording*/
void startIqRecording(const QString& recdir);
void startIqRecording(const QString& recdir, const receiver::RecordingFormat format);
void stopIqRecording();
void startIqPlayback(const QString& filename, float samprate, qint64 center_freq);
void stopIqPlayback();
Expand Down
42 changes: 37 additions & 5 deletions src/applications/gqrx/receiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,7 @@ receiver::status receiver::stop_udp_streaming()
* @brief Start I/Q data recorder.
* @param filename The filename where to record.
*/
receiver::status receiver::start_iq_recording(const std::string filename)
receiver::status receiver::start_iq_recording(const std::string filename, const receiver::RecordingFormat format)
{
receiver::status status = STATUS_OK;

Expand All @@ -1187,9 +1187,18 @@ receiver::status receiver::start_iq_recording(const std::string filename)
return STATUS_ERROR;
}

gr::basic_block_sptr iq_sink;
try
{
iq_sink = gr::blocks::file_sink::make(sizeof(gr_complex), filename.c_str(), true);
if (format == receiver::RecordingFormat::WAV) {
iq_sink_wav = gr::blocks::wavfile_sink::make(
filename.c_str(), 2, get_quad_rate(), gr::blocks::FORMAT_WAV, gr::blocks::FORMAT_FLOAT);
iq_complex_to_float = gr::blocks::complex_to_float::make();
iq_sink = iq_complex_to_float;
} else {
iq_sink_raw = gr::blocks::file_sink::make(sizeof(gr_complex), filename.c_str(), true);
iq_sink = iq_sink_raw;
}
}
catch (std::runtime_error &e)
{
Expand All @@ -1198,6 +1207,10 @@ receiver::status receiver::start_iq_recording(const std::string filename)
}

tb->lock();
if (format == receiver::RecordingFormat::WAV) {
tb->connect(iq_complex_to_float, 0, iq_sink_wav, 0);
tb->connect(iq_complex_to_float, 1, iq_sink_wav, 1);
}
if (d_decim >= 2)
tb->connect(input_decim, 0, iq_sink, 0);
else
Expand All @@ -1216,16 +1229,28 @@ receiver::status receiver::stop_iq_recording()
return STATUS_ERROR;
}

gr::basic_block_sptr iq_sink;
tb->lock();
iq_sink->close();
if (iq_sink_raw) {
iq_sink_raw->close();
iq_sink = iq_sink_raw;
}
if (iq_sink_wav) {
iq_sink_wav->close();
iq_sink = iq_complex_to_float;
tb->disconnect(iq_complex_to_float, 0, iq_sink_wav, 0);
tb->disconnect(iq_complex_to_float, 1, iq_sink_wav, 1);
}

if (d_decim >= 2)
tb->disconnect(input_decim, 0, iq_sink, 0);
else
tb->disconnect(src, 0, iq_sink, 0);

tb->unlock();
iq_sink.reset();
iq_sink_raw.reset();
iq_sink_wav.reset();
iq_complex_to_float.reset();
d_recording_iq = false;

return STATUS_OK;
Expand Down Expand Up @@ -1330,7 +1355,14 @@ void receiver::connect_all(rx_chain type)
if (d_recording_iq)
{
// We record IQ with minimal pre-processing
tb->connect(b, 0, iq_sink, 0);
if (iq_sink_raw) {
tb->connect(b, 0, iq_sink_raw, 0);
}
if (iq_sink_wav) {
tb->connect(b, 0, iq_complex_to_float, 0);
tb->connect(iq_complex_to_float, 0, iq_sink_wav, 0);
tb->connect(iq_complex_to_float, 1, iq_sink_wav, 1);
}
}

tb->connect(b, 0, iq_swap, 0);
Expand Down
11 changes: 9 additions & 2 deletions src/applications/gqrx/receiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ class receiver
FILTER_SHAPE_SHARP = 2 /*!< Sharp: Transition band is TBD of width. */
};

enum class RecordingFormat {
RAW,
WAV,
};

receiver(const std::string input_device="",
const std::string audio_device="",
unsigned int decimation=1);
Expand Down Expand Up @@ -210,7 +215,7 @@ class receiver
status stop_udp_streaming();

/* I/Q recording and playback */
status start_iq_recording(const std::string filename);
status start_iq_recording(const std::string filename, const RecordingFormat format);
status stop_iq_recording();
status seek_iq_file(long pos);

Expand Down Expand Up @@ -275,7 +280,9 @@ class receiver
gr::blocks::multiply_const_ff::sptr audio_gain0; /*!< Audio gain block. */
gr::blocks::multiply_const_ff::sptr audio_gain1; /*!< Audio gain block. */

gr::blocks::file_sink::sptr iq_sink; /*!< I/Q file sink. */
gr::blocks::file_sink::sptr iq_sink_raw; /*!< I/Q file sink. */
gr::blocks::wavfile_sink::sptr iq_sink_wav; /*!< I/Q file sink. */
gr::blocks::complex_to_float::sptr iq_complex_to_float;

gr::blocks::wavfile_sink::sptr wav_sink; /*!< WAV file sink for recording. */
gr::blocks::wavfile_source::sptr wav_src; /*!< WAV file source for playback. */
Expand Down
16 changes: 8 additions & 8 deletions src/qtgui/freqctrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/param.h>

#include <QDebug>
#include "freqctrl.h"

Expand Down Expand Up @@ -876,13 +878,11 @@ void CFreqCtrl::cursorEnd()

void CFreqCtrl::setFrequencyFocus()
{
uint8_t position = floor(log10(m_freq));
position = (uint8_t)fmax(position, 4); // restrict min to 100s of kHz
if (!hasFocus() || m_ActiveEditDigit == -1) {
// Select last digit or 5th digit (100s of kHz), whatever is bigger.
uint8_t position = MAX(int(log10(m_freq)), 5);

QMouseEvent mouseEvent(QEvent::MouseMove,
m_DigitInfo[position].dQRect.center(),
Qt::NoButton,
Qt::NoButton,
Qt::NoModifier);
mouseMoveEvent(&mouseEvent);
setFocus(Qt::ShortcutFocusReason);
setActiveDigit(position);
}
}
35 changes: 31 additions & 4 deletions src/qtgui/iq_tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@

CIqTool::CIqTool(QWidget *parent) :
QDialog(parent),
ui(new Ui::CIqTool)
ui(new Ui::CIqTool),
format(receiver::RecordingFormat::RAW)
{
ui->setupUi(this);

Expand All @@ -51,7 +52,8 @@ CIqTool::CIqTool(QWidget *parent) :

//ui->recDirEdit->setText(QDir::currentPath());

recdir = new QDir(QDir::homePath(), "*.raw");
recdir = new QDir(QDir::homePath(), "*.raw;*.wav");
recdir->setFilter(QDir::Files);

error_palette = new QPalette();
error_palette->setColor(QPalette::Text, Qt::red);
Expand Down Expand Up @@ -100,6 +102,16 @@ void CIqTool::on_listWidget_currentTextChanged(const QString &currentText)

}

void CIqTool::on_wavRadioButton_clicked(bool checked)
{
format = receiver::RecordingFormat::WAV;
}

void CIqTool::on_rawRadioButton_clicked(bool checked)
{
format = receiver::RecordingFormat::RAW;
}

/*! \brief Start/stop playback */
void CIqTool::on_playButton_clicked(bool checked)
{
Expand Down Expand Up @@ -173,7 +185,7 @@ void CIqTool::on_recButton_clicked(bool checked)
if (checked)
{
ui->playButton->setEnabled(false);
emit startRecording(recdir->path());
emit startRecording(recdir->path(), format);

refreshDir();
ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
Expand Down Expand Up @@ -235,6 +247,11 @@ void CIqTool::saveSettings(QSettings *settings)
else
settings->remove("baseband/rec_dir");

if (format == receiver::RecordingFormat::RAW) {
settings->setValue("baseband/rec_format", "raw");
} else {
settings->setValue("baseband/rec_format", "wav");
}
}

void CIqTool::readSettings(QSettings *settings)
Expand All @@ -245,8 +262,18 @@ void CIqTool::readSettings(QSettings *settings)
// Location of baseband recordings
QString dir = settings->value("baseband/rec_dir", QDir::homePath()).toString();
ui->recDirEdit->setText(dir);
}

QString fmt = settings->value("baseband/rec_format", "raw").toString();
if (fmt == "wav") {
ui->rawRadioButton->setChecked(false);
ui->wavRadioButton->setChecked(true);
format = receiver::RecordingFormat::WAV;
} else {
ui->rawRadioButton->setChecked(true);
ui->wavRadioButton->setChecked(false);
format = receiver::RecordingFormat::RAW;
}
}

/*! \brief Slot called when the recordings directory has changed either
* because of user input or programmatically.
Expand Down
7 changes: 6 additions & 1 deletion src/qtgui/iq_tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#include <QString>
#include <QTimer>

#include "applications/gqrx/receiver.h"

namespace Ui {
class CIqTool;
}
Expand Down Expand Up @@ -62,7 +64,7 @@ class CIqTool : public QDialog
void readSettings(QSettings *settings);

signals:
void startRecording(const QString recdir);
void startRecording(const QString recdir, const receiver::RecordingFormat format);
void stopRecording();
void startPlayback(const QString filename, float samprate, qint64 center_freq);
void stopPlayback();
Expand All @@ -79,6 +81,8 @@ private slots:
void on_playButton_clicked(bool checked);
void on_slider_valueChanged(int value);
void on_listWidget_currentTextChanged(const QString &currentText);
void on_wavRadioButton_clicked(bool checked);
void on_rawRadioButton_clicked(bool checked);
void timeoutFunction(void);

private:
Expand All @@ -89,6 +93,7 @@ private slots:
private:
Ui::CIqTool *ui;

receiver::RecordingFormat format;
QDir *recdir;
QTimer *timer;
QPalette *error_palette; /*!< Palette used to indicate an error. */
Expand Down
43 changes: 29 additions & 14 deletions src/qtgui/iq_tool.ui
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
Expand All @@ -166,27 +166,42 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="timeLabel">
<widget class="QLabel" name="label">
<property name="text">
<string>00:00:00 / 00:00:00</string>
<string>File format:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rawRadioButton">
<property name="text">
<string>Raw</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<widget class="QRadioButton" name="wavRadioButton">
<property name="text">
<string>WAV</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>00:00:00 / 00:00:00</string>
</property>
</spacer>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
Expand Down