diff --git a/plugins/channeltx/filesource/filesourcegui.cpp b/plugins/channeltx/filesource/filesourcegui.cpp
index a54277213..154081106 100644
--- a/plugins/channeltx/filesource/filesourcegui.cpp
+++ b/plugins/channeltx/filesource/filesourcegui.cpp
@@ -427,7 +427,7 @@ void FileSourceGUI::on_showFileDialog_clicked(bool checked)
{
(void) checked;
QString fileName = QFileDialog::getOpenFileName(this,
- tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq)"), 0, QFileDialog::DontUseNativeDialog);
+ tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq *.wav)"), 0, QFileDialog::DontUseNativeDialog);
if (fileName != "")
{
diff --git a/plugins/channeltx/filesource/filesourcesource.cpp b/plugins/channeltx/filesource/filesourcesource.cpp
index df95dab5b..1b6bf7a7c 100644
--- a/plugins/channeltx/filesource/filesourcesource.cpp
+++ b/plugins/channeltx/filesource/filesourcesource.cpp
@@ -32,6 +32,7 @@
#include "dsp/devicesamplesink.h"
#include "dsp/hbfilterchainconverter.h"
#include "dsp/filerecord.h"
+#include "dsp/wavfilerecord.h"
#include "util/db.h"
FileSourceSource::FileSourceSource() :
@@ -173,7 +174,46 @@ void FileSourceSource::openFileStream(const QString& fileName)
quint64 fileSize = m_ifstream.tellg();
m_samplesCount = 0;
- if (fileSize > sizeof(FileRecord::Header))
+ if (m_fileName.endsWith(".wav"))
+ {
+ WavFileRecord::Header header;
+ m_ifstream.seekg(0, std::ios_base::beg);
+ bool headerOK = WavFileRecord::readHeader(m_ifstream, header);
+ m_fileSampleRate = header.m_sampleRate;
+ if (header.m_auxiHeader.m_size > 0)
+ {
+ // Some WAV files written by SDR tools have auxi header
+ m_centerFrequency = header.m_auxi.m_centerFreq;
+ m_startingTimeStamp = header.getStartTime().toMSecsSinceEpoch() / 1000;
+ }
+ else
+ {
+ // Attempt to extract start time and frequency from filename
+ QDateTime startTime;
+ if (WavFileRecord::getStartTime(m_fileName, startTime)) {
+ m_startingTimeStamp = startTime.toMSecsSinceEpoch() / 1000;
+ }
+ WavFileRecord::getCenterFrequency(m_fileName, m_centerFrequency);
+ }
+ m_sampleSize = header.m_bitsPerSample;
+
+ if (headerOK && (m_fileSampleRate > 0) && (m_sampleSize > 0))
+ {
+ m_recordLengthMuSec = ((fileSize - m_ifstream.tellg()) * 1000000UL) / ((m_sampleSize == 24 ? 8 : 4) * m_fileSampleRate);
+ }
+ else
+ {
+ qCritical("FileSourceSource::openFileStream: invalid .wav file");
+ m_recordLengthMuSec = 0;
+ }
+
+ if (getMessageQueueToGUI())
+ {
+ FileSourceReport::MsgReportHeaderCRC *report = FileSourceReport::MsgReportHeaderCRC::create(headerOK);
+ getMessageQueueToGUI()->push(report);
+ }
+ }
+ else if (fileSize > sizeof(FileRecord::Header))
{
FileRecord::Header header;
m_ifstream.seekg(0,std::ios_base::beg);
diff --git a/plugins/channeltx/filesource/readme.md b/plugins/channeltx/filesource/readme.md
index e13f4ec9a..be7ee073d 100644
--- a/plugins/channeltx/filesource/readme.md
+++ b/plugins/channeltx/filesource/readme.md
@@ -2,7 +2,9 @@
Introduction
-This plugin reads a file of I/Q samples that have been previously saved with the file record button of other sampling source devices. The file starts with a 32 byte header of all unsigned integer of various sizes containing meta data:
+This plugin reads a file of I/Q samples that have been previously saved with the file record button of other sampling source devices. File formats supported include SDRangel's `.sdriq` and signed 16-bit PCM `.wav` files.
+
+`.sqriq` files start with a 32 byte header of all unsigned integer of various sizes containing meta data:
diff --git a/plugins/samplesource/fileinput/fileinput.cpp b/plugins/samplesource/fileinput/fileinput.cpp
index 84233661b..f0dfa1f44 100644
--- a/plugins/samplesource/fileinput/fileinput.cpp
+++ b/plugins/samplesource/fileinput/fileinput.cpp
@@ -21,7 +21,6 @@
#include
#include
#include
-#include
#include "SWGDeviceSettings.h"
#include "SWGFileInputSettings.h"
@@ -111,44 +110,16 @@ void FileInput::openFileStream()
{
// Some WAV files written by SDR tools have auxi header
m_centerFrequency = header.m_auxi.m_centerFreq;
- m_startingTimeStamp = QDateTime(QDate(
- header.m_auxi.m_startTime.m_year,
- header.m_auxi.m_startTime.m_month,
- header.m_auxi.m_startTime.m_day
- ), QTime(
- header.m_auxi.m_startTime.m_hour,
- header.m_auxi.m_startTime.m_minute,
- header.m_auxi.m_startTime.m_second,
- header.m_auxi.m_startTime.m_milliseconds
- )).toMSecsSinceEpoch() / 1000;
+ m_startingTimeStamp = header.getStartTime().toMSecsSinceEpoch() / 1000;
}
else
{
- // Attempt to extract time and frequency from filename
- QRegExp dateTimeRE("([12][0-9][0-9][0-9]).?([01][0-9]).?([0-3][0-9]).?([0-2][0-9]).?([0-5][0-9]).?([0-5][0-9])");
- if (dateTimeRE.indexIn(m_settings.m_fileName) != -1)
- {
- m_startingTimeStamp = QDateTime(QDate(
- dateTimeRE.capturedTexts()[1].toInt(),
- dateTimeRE.capturedTexts()[2].toInt(),
- dateTimeRE.capturedTexts()[3].toInt()
- ), QTime(
- dateTimeRE.capturedTexts()[4].toInt(),
- dateTimeRE.capturedTexts()[5].toInt(),
- dateTimeRE.capturedTexts()[6].toInt()
- )).toMSecsSinceEpoch() / 1000;
- }
- // Attempt to extract centre frequency from filename
- QRegExp freqkRE("(([0-9]+)kHz)");
- QRegExp freqRE("(([0-9]+)Hz)");
- if (freqkRE.indexIn(m_settings.m_fileName))
- {
- m_centerFrequency = freqkRE.capturedTexts()[2].toLongLong() * 1000LL;
- }
- else if (freqRE.indexIn(m_settings.m_fileName))
- {
- m_centerFrequency = freqRE.capturedTexts()[2].toLongLong();
+ // Attempt to extract start time and frequency from filename
+ QDateTime startTime;
+ if (WavFileRecord::getStartTime(m_settings.m_fileName, startTime)) {
+ m_startingTimeStamp = startTime.toMSecsSinceEpoch() / 1000;
}
+ WavFileRecord::getCenterFrequency(m_settings.m_fileName, m_centerFrequency);
}
m_sampleSize = header.m_bitsPerSample;
diff --git a/sdrbase/dsp/wavfilerecord.cpp b/sdrbase/dsp/wavfilerecord.cpp
index 89bb7e114..62f735601 100644
--- a/sdrbase/dsp/wavfilerecord.cpp
+++ b/sdrbase/dsp/wavfilerecord.cpp
@@ -21,6 +21,7 @@
#include
#include
+#include
#include "dsp/dspcommands.h"
#include "util/simpleserializer.h"
@@ -340,3 +341,51 @@ void WavFileRecord::writeHeader(std::ofstream& sampleFile, Header& header)
{
sampleFile.write((const char *) &header, sizeof(Header));
}
+
+bool WavFileRecord::getCenterFrequency(QString fileName, quint64& centerFrequency)
+{
+ // Attempt to extract center frequency from filename
+ QRegExp freqkRE("(([0-9]+)kHz)");
+ QRegExp freqRE("(([0-9]+)Hz)");
+ if (freqkRE.indexIn(fileName))
+ {
+ centerFrequency = freqkRE.capturedTexts()[2].toLongLong() * 1000LL;
+ return true;
+ }
+ else if (freqRE.indexIn(fileName))
+ {
+ centerFrequency = freqRE.capturedTexts()[2].toLongLong();
+ return true;
+ }
+ return false;
+}
+
+bool WavFileRecord::getStartTime(QString fileName, QDateTime& startTime)
+{
+ // Attempt to extract start time from filename
+ QRegExp dateTimeRE("([12][0-9][0-9][0-9]).?([01][0-9]).?([0-3][0-9]).?([0-2][0-9]).?([0-5][0-9]).?([0-5][0-9])");
+ if (dateTimeRE.indexIn(fileName) != -1)
+ {
+ startTime = QDateTime(QDate(
+ dateTimeRE.capturedTexts()[1].toInt(),
+ dateTimeRE.capturedTexts()[2].toInt(),
+ dateTimeRE.capturedTexts()[3].toInt()),
+ QTime(
+ dateTimeRE.capturedTexts()[4].toInt(),
+ dateTimeRE.capturedTexts()[5].toInt(),
+ dateTimeRE.capturedTexts()[6].toInt()));
+ return true;
+ }
+ return false;
+}
+
+QDateTime WavFileRecord::Header::getStartTime() const
+{
+ return QDateTime(QDate(m_auxi.m_startTime.m_year,
+ m_auxi.m_startTime.m_month,
+ m_auxi.m_startTime.m_day),
+ QTime(m_auxi.m_startTime.m_hour,
+ m_auxi.m_startTime.m_minute,
+ m_auxi.m_startTime.m_second,
+ m_auxi.m_startTime.m_milliseconds));
+}
diff --git a/sdrbase/dsp/wavfilerecord.h b/sdrbase/dsp/wavfilerecord.h
index ccb5615ab..3392be696 100644
--- a/sdrbase/dsp/wavfilerecord.h
+++ b/sdrbase/dsp/wavfilerecord.h
@@ -66,7 +66,7 @@ public:
quint32 m_unused5;
char m_nextFilename[96];
};
- struct Header
+ struct SDRBASE_API Header
{
Chunk m_riffHeader;
char m_type[4]; // "WAVE"
@@ -80,6 +80,8 @@ public:
Chunk m_auxiHeader;
Auxi m_auxi;
Chunk m_dataHeader;
+
+ QDateTime getStartTime() const;
};
#pragma pack(pop)
@@ -107,6 +109,10 @@ public:
static bool readHeader(std::ifstream& samplefile, Header& header);
static void writeHeader(std::ofstream& samplefile, Header& header);
+ // These functions guess from the filename, not contents
+ static bool getCenterFrequency(QString fileName, quint64& centerFrequency);
+ static bool getStartTime(QString fileName, QDateTime& startTime);
+
private:
QString m_fileBase;
quint32 m_sampleRate;