diff --git a/plugins/channelrx/filesink/filesinkgui.ui b/plugins/channelrx/filesink/filesinkgui.ui
index f8b7227c9..e9fc5b051 100644
--- a/plugins/channelrx/filesink/filesinkgui.ui
+++ b/plugins/channelrx/filesink/filesinkgui.ui
@@ -6,7 +6,7 @@
0
0
- 552
+ 441
458
@@ -18,7 +18,7 @@
- 552
+ 400
102
@@ -31,535 +31,531 @@
File Sink
-
-
-
- 0
- 0
- 550
- 100
-
-
-
-
- 550
- 0
-
-
-
- Settings
-
-
-
- 2
-
-
- 2
-
-
- 2
-
-
- 2
-
- -
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Settings
+
+
+
+ 2
+
+
+ 2
+
2
+
+ 2
+
-
-
-
-
- 16
- 0
-
+
+
+ 2
-
- Df
-
-
+
-
+
+
+
+ 16
+ 0
+
+
+
+ Df
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ Liberation Mono
+ 12
+
+
+
+ PointingHandCursor
+
+
+ Qt::StrongFocus
+
+
+ Demod shift frequency from center in Hz
+
+
+
+ -
+
+
+ Hz
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ Dec
+
+
+
+ -
+
+
+
+ 55
+ 16777215
+
+
+
+ Decimation factor
+
+
-
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 4
+
+
+ -
+
+ 8
+
+
+ -
+
+ 16
+
+
+ -
+
+ 32
+
+
+ -
+
+ 64
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 50
+ 0
+
+
+
+ Sink rate (kS/s)
+
+
+ 0000k
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 32
+ 0
+
+
+
+ Number of captures (files) in recording session updated at end of file
+
+
+ #000
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 52
+ 0
+
+
+
+ Total recording time (HH:MM:SS)
+
+
+ 00:00:00
+
+
+
+ -
+
+
+
+ 52
+ 0
+
+
+
+ Total recording size (k: kB, M: MB, G: GB)
+
+
+ 999.99M
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
-
-
-
- true
+
+
+ 10
+
-
+
+
+ Use fixed frequency shift positions for little performance improvement
+
+
+ Pos
+
+
+
+ -
+
+
+ Center frequency position
+
+
+ 2
+
+
+ 1
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 24
+ 0
+
+
+
+ Filter chain hash code
+
+
+ 000
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ Toggle spectrum squelch recording
+
+
+ SQ
+
+
+ true
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Spectrum squelch level (dB)
+
+
+ -120
+
+
+ 0
+
+
+ 1
+
+
+ -50
+
+
+
+ -
+
+
+ Spectrum squelch level (dB)
+
+
+ -100
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Pre-recording time (s)
+
+
+ 10
+
+
+ 1
+
+
+
+ -
+
+
+ Squelched recoding pre-recording time (s)
+
+
+ 10
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Squelched recording post-recording time (s)
+
+
+ 10
+
+
+ 1
+
+
+
+ -
+
+
+ Squelched recording post-recording time (s)
+
+
+ 10
+
+
+
+ -
+
+
+ Squelched recording enable
+
+
+ REC
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 24
+ 16777215
+
+
+
+ Start/stop recording
+
+
+
+
+
+
+ :/record_off.png:/record_off.png
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+ Open file
+
+
+
+
+
+
+ :/preset-load.png:/preset-load.png
+
+
+
+ -
+
+
+ true
+
+
+ Current recording file
+
+
+ ...
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 10
+
+
-
+
-
+
0
0
- 32
- 16
+ 300
+ 300
Liberation Mono
- 12
+ 8
-
- PointingHandCursor
-
-
- Qt::StrongFocus
-
-
- Demod shift frequency from center in Hz
-
-
-
-
- Hz
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- -
-
-
- Dec
-
-
-
- -
-
-
-
- 55
- 16777215
-
-
-
- Decimation factor
-
-
-
-
- 1
-
-
- -
-
- 2
-
-
- -
-
- 4
-
-
- -
-
- 8
-
-
- -
-
- 16
-
-
- -
-
- 32
-
-
- -
-
- 64
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 50
- 0
-
-
-
- Sink rate (kS/s)
-
-
- 0000k
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 32
- 0
-
-
-
- Number of captures (files) in recording session updated at end of file
-
-
- #000
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 52
- 0
-
-
-
- Total recording time (HH:MM:SS)
-
-
- 00:00:00
-
-
-
- -
-
-
-
- 52
- 0
-
-
-
- Total recording size (k: kB, M: MB, G: GB)
-
-
- 999.99M
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
+
-
- -
-
-
- 10
-
-
-
-
-
- Use fixed frequency shift positions for little performance improvement
-
-
- Pos
-
-
-
- -
-
-
- Center frequency position
-
-
- 2
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- 24
- 0
-
-
-
- Filter chain hash code
-
-
- 000
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- -
-
-
- Toggle spectrum squelch recording
-
-
- SQ
-
-
- true
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
- Spectrum squelch level (dB)
-
-
- -120
-
-
- 0
-
-
- 1
-
-
- -50
-
-
-
- -
-
-
- Spectrum squelch level (dB)
-
-
- -100
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
- Pre-recording time (s)
-
-
- 10
-
-
- 1
-
-
-
- -
-
-
- Squelched recoding pre-recording time (s)
-
-
- 10
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
- Squelched recording post-recording time (s)
-
-
- 10
-
-
- 1
-
-
-
- -
-
-
- Squelched recording post-recording time (s)
-
-
- 10
-
-
-
- -
-
-
- Squelched recording enable
-
-
- REC
-
-
-
-
-
- -
-
-
-
-
-
-
- 24
- 16777215
-
-
-
- Start/stop recording
-
-
-
-
-
-
- :/record_off.png:/record_off.png
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
- Open file
-
-
-
-
-
-
- :/preset-load.png:/preset-load.png
-
-
-
- -
-
-
- true
-
-
- Current recording file
-
-
- ...
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
-
-
-
-
-
-
-
- 0
- 100
- 541
- 351
-
-
-
-
- 0
- 0
-
-
-
-
- 10
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 300
- 300
-
-
-
-
- Liberation Mono
- 8
-
-
-
-
- -
-
-
-
-
+
+
+
diff --git a/plugins/samplesource/fileinput/fileinput.cpp b/plugins/samplesource/fileinput/fileinput.cpp
index 503bd9100..899eb6de4 100644
--- a/plugins/samplesource/fileinput/fileinput.cpp
+++ b/plugins/samplesource/fileinput/fileinput.cpp
@@ -100,7 +100,17 @@ void FileInput::openFileStream()
{
//stopInput();
- if (m_ifstream.is_open()) {
+#ifdef ANDROID
+ if (m_inputFile.isOpen()) {
+ m_inputFile.close();
+ }
+
+ m_inputFile.setFileName(m_settings.m_fileName);
+ m_inputFile.open(QIODevice::ReadOnly | QIODevice::ExistingOnly);
+ quint64 fileSize = (quint64) m_inputFile.size();
+
+#else
+ if (m_ifstream.is_open()) {
m_ifstream.close();
}
@@ -110,12 +120,18 @@ void FileInput::openFileStream()
m_ifstream.open(m_settings.m_fileName.toStdString().c_str(), std::ios::binary | std::ios::ate);
#endif
quint64 fileSize = m_ifstream.tellg();
+#endif
if (m_settings.m_fileName.endsWith(".wav"))
{
WavFileRecord::Header header;
+#ifdef ANDROID
+ m_inputFile.seek(0);
+ bool headerOK = WavFileRecord::readHeader(m_inputFile, header);
+#else
m_ifstream.seekg(0, std::ios_base::beg);
bool headerOK = WavFileRecord::readHeader(m_ifstream, header);
+#endif
m_sampleRate = header.m_sampleRate;
if (header.m_auxiHeader.m_size > 0)
{
@@ -136,7 +152,12 @@ void FileInput::openFileStream()
if (headerOK && (m_sampleRate > 0) && (m_sampleSize > 0))
{
- m_recordLengthMuSec = ((fileSize - m_ifstream.tellg()) * 1000000UL) / ((m_sampleSize == 24 ? 8 : 4) * m_sampleRate);
+#ifdef ANDROID
+ qint64 pos = m_inputFile.pos();
+#else
+ qint64 pos = m_ifstream.tellg();
+#endif
+ m_recordLengthMuSec = ((fileSize - pos) * 1000000UL) / ((m_sampleSize == 24 ? 8 : 4) * m_sampleRate);
}
else
{
@@ -153,8 +174,13 @@ void FileInput::openFileStream()
else if (fileSize > sizeof(FileRecord::Header))
{
FileRecord::Header header;
+#ifdef ANDROID
+ m_inputFile.seek(0);
+ bool crcOK = FileRecord::readHeader(m_inputFile, header);
+#else
m_ifstream.seekg(0,std::ios_base::beg);
bool crcOK = FileRecord::readHeader(m_ifstream, header);
+#endif
m_sampleRate = header.sampleRate;
m_centerFrequency = header.centerFrequency;
m_startingTimeStamp = header.startTimeStamp;
@@ -208,7 +234,11 @@ void FileInput::openFileStream()
}
if (m_recordLengthMuSec == 0) {
+#ifdef ANDROID
+ m_inputFile.close();
+#else
m_ifstream.close();
+#endif
}
}
@@ -216,14 +246,24 @@ void FileInput::seekFileStream(int seekMillis)
{
QMutexLocker mutexLocker(&m_mutex);
- if ((m_ifstream.is_open()) && m_fileInputWorker && !m_fileInputWorker->isRunning())
+ if (
+#ifdef ANDROID
+ m_inputFile.isOpen()
+#else
+ m_ifstream.is_open()
+#endif
+ && m_fileInputWorker && !m_fileInputWorker->isRunning())
{
quint64 seekPoint = ((m_recordLengthMuSec * seekMillis) / 1000) * m_sampleRate;
seekPoint /= 1000000UL;
m_fileInputWorker->setSamplesCount(seekPoint);
seekPoint *= (m_sampleSize == 24 ? 8 : 4); // + sizeof(FileRecord::Header)
+#ifdef ANDROID
+ m_inputFile.seek(seekPoint + sizeof(FileRecord::Header));
+#else
m_ifstream.clear();
m_ifstream.seekg(seekPoint + sizeof(FileRecord::Header), std::ios::beg);
+#endif
}
}
@@ -235,7 +275,11 @@ void FileInput::init()
bool FileInput::start()
{
+#ifdef ANDROID
+ if (!m_inputFile.isOpen())
+#else
if (!m_ifstream.is_open())
+#endif
{
qWarning("FileInput::start: file not open. not starting");
return false;
@@ -244,11 +288,15 @@ bool FileInput::start()
QMutexLocker mutexLocker(&m_mutex);
qDebug() << "FileInput::start";
+#ifdef ANDROID
+ m_inputFile.seek(0);
+#else
if (m_ifstream.tellg() != (std::streampos)0)
{
m_ifstream.clear();
m_ifstream.seekg(sizeof(FileRecord::Header), std::ios::beg);
}
+#endif
if (!m_sampleFifo.setSize(m_settings.m_accelerationFactor * m_sampleRate * sizeof(Sample)))
{
@@ -256,7 +304,11 @@ bool FileInput::start()
return false;
}
+#ifdef ANDROID
+ m_fileInputWorker = new FileInputWorker(&m_inputFile, &m_sampleFifo, m_masterTimer, &m_inputMessageQueue);
+#else
m_fileInputWorker = new FileInputWorker(&m_ifstream, &m_sampleFifo, m_masterTimer, &m_inputMessageQueue);
+#endif
m_fileInputWorker->moveToThread(&m_fileInputWorkerThread);
m_fileInputWorker->setSampleRateAndSize(m_settings.m_accelerationFactor * m_sampleRate, m_sampleSize); // Fast Forward: 1 corresponds to live. 1/2 is half speed, 2 is double speed
startWorker();
diff --git a/plugins/samplesource/fileinput/fileinput.h b/plugins/samplesource/fileinput/fileinput.h
index 08e3e9c81..c372edba1 100644
--- a/plugins/samplesource/fileinput/fileinput.h
+++ b/plugins/samplesource/fileinput/fileinput.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include "dsp/devicesamplesource.h"
#include "fileinputsettings.h"
@@ -334,7 +335,11 @@ public:
DeviceAPI *m_deviceAPI;
QMutex m_mutex;
FileInputSettings m_settings;
+#ifdef ANDROID
+ QFile m_inputFile;
+#else
std::ifstream m_ifstream;
+#endif
FileInputWorker* m_fileInputWorker;
QThread m_fileInputWorkerThread;
QString m_deviceDescription;
diff --git a/plugins/samplesource/fileinput/fileinputgui.cpp b/plugins/samplesource/fileinput/fileinputgui.cpp
index 143925a3b..0de5c2e2f 100644
--- a/plugins/samplesource/fileinput/fileinputgui.cpp
+++ b/plugins/samplesource/fileinput/fileinputgui.cpp
@@ -28,6 +28,7 @@
#include "gui/colormapper.h"
#include "gui/glspectrum.h"
#include "gui/basicdevicesettingsdialog.h"
+#include "gui/dialogpositioner.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
@@ -313,7 +314,8 @@ void FileInputGUI::on_showFileDialog_clicked(bool checked)
{
(void) checked;
QString fileName = QFileDialog::getOpenFileName(this,
- tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq *.wav)"), 0, QFileDialog::DontUseNativeDialog);
+ tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq *.wav)"), 0);
+
if (fileName != "")
{
@@ -450,6 +452,7 @@ void FileInputGUI::openDeviceSettingsDialog(const QPoint& p)
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
dialog.move(p);
+ new DialogPositioner(&dialog, false);
dialog.exec();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
diff --git a/plugins/samplesource/fileinput/fileinputworker.cpp b/plugins/samplesource/fileinput/fileinputworker.cpp
index f1b61f75d..42a74fbe4 100644
--- a/plugins/samplesource/fileinput/fileinputworker.cpp
+++ b/plugins/samplesource/fileinput/fileinputworker.cpp
@@ -26,7 +26,12 @@
MESSAGE_CLASS_DEFINITION(FileInputWorker::MsgReportEOF, Message)
-FileInputWorker::FileInputWorker(std::ifstream *samplesStream,
+FileInputWorker::FileInputWorker(
+#ifdef ANDROID
+ QFile *samplesStream,
+#else
+ std::ifstream *samplesStream,
+#endif
SampleSinkFifo* sampleFifo,
const QTimer& timer,
MessageQueue *fileInputMessageQueue,
@@ -69,7 +74,11 @@ void FileInputWorker::startWork()
{
qDebug() << "FileInputThread::startWork: ";
+#ifdef ANDROID
+ if (m_ifstream->isOpen())
+#else
if (m_ifstream->is_open())
+#endif
{
qDebug() << "FileInputThread::startWork: file stream open, starting...";
m_elapsedTimer.start();
@@ -172,6 +181,23 @@ void FileInputWorker::tick()
setBuffers(m_chunksize);
}
+
+#ifdef ANDROID
+ // read samples directly feeding the SampleFifo (no callback)
+ qint64 bytesRead = m_ifstream->read(reinterpret_cast(m_fileBuf), m_chunksize);
+
+ if (m_ifstream->atEnd())
+ {
+ writeToSampleFifo(m_fileBuf, (qint32) bytesRead);
+ MsgReportEOF *message = MsgReportEOF::create();
+ m_fileInputMessageQueue->push(message);
+ }
+ else
+ {
+ writeToSampleFifo(m_fileBuf, (qint32) m_chunksize);
+ m_samplesCount += m_chunksize / (2 * m_samplebytes);
+ }
+#else
// read samples directly feeding the SampleFifo (no callback)
m_ifstream->read(reinterpret_cast(m_fileBuf), m_chunksize);
@@ -186,6 +212,7 @@ void FileInputWorker::tick()
writeToSampleFifo(m_fileBuf, (qint32) m_chunksize);
m_samplesCount += m_chunksize / (2 * m_samplebytes);
}
+#endif
}
}
diff --git a/plugins/samplesource/fileinput/fileinputworker.h b/plugins/samplesource/fileinput/fileinputworker.h
index c81fc635a..19787b148 100644
--- a/plugins/samplesource/fileinput/fileinputworker.h
+++ b/plugins/samplesource/fileinput/fileinputworker.h
@@ -50,7 +50,12 @@ public:
{ }
};
- FileInputWorker(std::ifstream *samplesStream,
+ FileInputWorker(
+#ifdef ANDROID
+ QFile *samplesStream,
+#else
+ std::ifstream *samplesStream,
+#endif
SampleSinkFifo* sampleFifo,
const QTimer& timer,
MessageQueue *fileInputMessageQueue,
@@ -68,7 +73,11 @@ public:
private:
volatile bool m_running;
+#ifdef ANDROID
+ QFile *m_ifstream;
+#else
std::ifstream* m_ifstream;
+#endif
quint8 *m_fileBuf;
quint8 *m_convertBuf;
std::size_t m_bufsize;
diff --git a/sdrbase/dsp/filerecord.cpp b/sdrbase/dsp/filerecord.cpp
index 603e8931c..0b9bcc492 100644
--- a/sdrbase/dsp/filerecord.cpp
+++ b/sdrbase/dsp/filerecord.cpp
@@ -114,16 +114,31 @@ bool FileRecord::startRecording()
stopRecording();
}
+#ifdef ANDROID
+ if (!m_sampleFile.isOpen())
+#else
if (!m_sampleFile.is_open())
+#endif
{
qDebug() << "FileRecord::startRecording";
- m_currentFileName = QString("%1.%2.sdriq").arg(m_fileBase).arg(QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddTHH_mm_ss_zzz"));
+#ifdef ANDROID
+ // FIXME: No idea how to write to a file where the filename doesn't come from the file picker
+ m_currentFileName = m_fileBase + ".sdriq";
+ m_sampleFile.setFileName(m_currentFileName);
+ if (!m_sampleFile.open(QIODevice::ReadWrite))
+ {
+ qWarning() << "FileRecord::startRecording: failed to open file: " << m_currentFileName << " error " << m_sampleFile.error();
+ return false;
+ }
+#else
+ m_currentFileName = m_fileBase + "." + QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddTHH_mm_ss_zzz") + ".sdriq"; // Don't use QString::arg on Android, as filename can contain %2
m_sampleFile.open(m_currentFileName.toStdString().c_str(), std::ios::binary);
if (!m_sampleFile.is_open())
{
qWarning() << "FileRecord::startRecording: failed to open file: " << m_currentFileName;
return false;
}
+#endif
m_recordOn = true;
m_recordStart = true;
m_byteCount = 0;
@@ -135,17 +150,24 @@ bool FileRecord::stopRecording()
{
QMutexLocker mutexLocker(&m_mutex);
+#ifdef ANDROID
+ if (m_sampleFile.isOpen())
+#else
if (m_sampleFile.is_open())
+#endif
{
qDebug() << "FileRecord::stopRecording";
m_sampleFile.close();
m_recordOn = false;
m_recordStart = false;
+#ifdef ANDROID
+#else
if (m_sampleFile.bad())
{
qWarning() << "FileRecord::stopRecording: an error occurred while writing to " << m_currentFileName;
return false;
}
+#endif
}
return true;
}
@@ -197,6 +219,14 @@ bool FileRecord::readHeader(std::ifstream& sampleFile, Header& header)
return header.crc32 == crc32.checksum();
}
+bool FileRecord::readHeader(QFile& sampleFile, Header& header)
+{
+ sampleFile.read((char *) &header, sizeof(Header));
+ boost::crc_32_type crc32;
+ crc32.process_bytes(&header, 28);
+ return header.crc32 == crc32.checksum();
+}
+
void FileRecord::writeHeader(std::ofstream& sampleFile, Header& header)
{
boost::crc_32_type crc32;
@@ -204,3 +234,11 @@ void FileRecord::writeHeader(std::ofstream& sampleFile, Header& header)
header.crc32 = crc32.checksum();
sampleFile.write((const char *) &header, sizeof(Header));
}
+
+void FileRecord::writeHeader(QFile& sampleFile, Header& header)
+{
+ boost::crc_32_type crc32;
+ crc32.process_bytes(&header, 28);
+ header.crc32 = crc32.checksum();
+ sampleFile.write((const char *) &header, sizeof(Header));
+}
diff --git a/sdrbase/dsp/filerecord.h b/sdrbase/dsp/filerecord.h
index 02ba5d706..e2086115c 100644
--- a/sdrbase/dsp/filerecord.h
+++ b/sdrbase/dsp/filerecord.h
@@ -18,6 +18,8 @@
#ifndef INCLUDE_FILERECORD_H
#define INCLUDE_FILERECORD_H
+#include
+
#include
#include
#include
@@ -65,7 +67,9 @@ public:
virtual bool isRecording() const { return m_recordOn; }
static bool readHeader(std::ifstream& samplefile, Header& header); //!< returns true if CRC checksum is correct else false
+ static bool readHeader(QFile& samplefile, Header& header); //!< returns true if CRC checksum is correct else false
static void writeHeader(std::ofstream& samplefile, Header& header);
+ static void writeHeader(QFile& samplefile, Header& header);
private:
QString m_fileBase;
@@ -73,7 +77,11 @@ private:
quint64 m_centerFrequency;
bool m_recordOn;
bool m_recordStart;
+#ifdef ANDROID
+ QFile m_sampleFile;
+#else
std::ofstream m_sampleFile;
+#endif
QString m_currentFileName;
quint64 m_byteCount;
qint64 m_msShift;
diff --git a/sdrbase/dsp/wavfilerecord.cpp b/sdrbase/dsp/wavfilerecord.cpp
index 2cc572f07..2647e69e9 100644
--- a/sdrbase/dsp/wavfilerecord.cpp
+++ b/sdrbase/dsp/wavfilerecord.cpp
@@ -105,8 +105,8 @@ void WavFileRecord::feed(const SampleVector::const_iterator& begin, const Sample
{
// Convert from 24-bit to 16-bit
int16_t samples[2];
- samples[0] = it->real() >> 8;
- samples[1] = it->imag() >> 8;
+ samples[0] = std::min(32767, std::max(it->real() >> 8, -32768));
+ samples[1] = std::min(32767, std::max(it->imag() >> 8, -32768));
m_sampleFile.write(reinterpret_cast(&samples), 4);
m_byteCount += 4;
}
@@ -154,16 +154,31 @@ bool WavFileRecord::startRecording()
stopRecording();
}
+#ifdef ANDROID
+ if (!m_sampleFile.isOpen())
+#else
if (!m_sampleFile.is_open())
+#endif
{
qDebug() << "WavFileRecord::startRecording";
- m_currentFileName = QString("%1.%2.wav").arg(m_fileBase).arg(QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddTHH_mm_ss_zzz"));
+#ifdef ANDROID
+ // FIXME: No idea how to write to a file where the filename doesn't come from the file picker
+ m_currentFileName = m_fileBase + ".wav";
+ m_sampleFile.setFileName(m_currentFileName);
+ if (!m_sampleFile.open(QIODevice::ReadWrite))
+ {
+ qWarning() << "WavFileRecord::startRecording: failed to open file: " << m_currentFileName << " error " << m_sampleFile.error();
+ return false;
+ }
+#else
+ m_currentFileName = m_fileBase + "_" + QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddTHH_mm_ss_zzz") + ".wav"; // Don't use QString::arg on Android, as filename can contain %2
m_sampleFile.open(m_currentFileName.toStdString().c_str(), std::ios::binary);
if (!m_sampleFile.is_open())
{
qWarning() << "WavFileRecord::startRecording: failed to open file: " << m_currentFileName;
return false;
}
+#endif
m_recordOn = true;
m_recordStart = true;
m_byteCount = 0;
@@ -173,25 +188,41 @@ bool WavFileRecord::startRecording()
bool WavFileRecord::stopRecording()
{
+#ifdef ANDROID
+ if (m_sampleFile.isOpen())
+#else
if (m_sampleFile.is_open())
+#endif
{
qDebug() << "WavFileRecord::stopRecording";
// Fix up chunk sizes
+#ifdef ANDROID
+ long fileSize = (long)m_sampleFile.size();
+ m_sampleFile.seek(offsetof(Header, m_riffHeader.m_size));
+#else
long fileSize = m_sampleFile.tellp();
m_sampleFile.seekp(offsetof(Header, m_riffHeader.m_size));
+#endif
qint32 size = (fileSize - 8);
m_sampleFile.write((char *)&size, 4);
+#ifdef ANDROID
+ m_sampleFile.seek(offsetof(Header, m_dataHeader.m_size));
+#else
m_sampleFile.seekp(offsetof(Header, m_dataHeader.m_size));
+#endif
size = fileSize - sizeof(Header);
m_sampleFile.write((char *)&size, 4);
m_sampleFile.close();
m_recordOn = false;
m_recordStart = false;
+#ifdef ANDROID
+#else
if (m_sampleFile.bad())
{
qWarning() << "WavFileRecord::stopRecording: an error occurred while writing to " << m_currentFileName;
return false;
}
+#endif
}
return true;
}
@@ -305,35 +336,7 @@ bool WavFileRecord::readHeader(std::ifstream& sampleFile, Header& header)
return false;
}
- if (strncmp(header.m_riffHeader.m_id, "RIFF", 4))
- {
- qDebug() << "WavFileRecord::readHeader: No RIFF header";
- return false;
- }
- if (strncmp(header.m_type, "WAVE", 4))
- {
- qDebug() << "WavFileRecord::readHeader: No WAVE header";
- return false;
- }
- if (strncmp(header.m_fmtHeader.m_id, "fmt ", 4))
- {
- qDebug() << "WavFileRecord::readHeader: No fmt header";
- return false;
- }
- if (header.m_audioFormat != 1)
- {
- qDebug() << "WavFileRecord::readHeader: Audio format is not PCM";
- return false;
- }
- if (header.m_numChannels != 2)
- {
- qDebug() << "WavFileRecord::readHeader: Number of channels is not 2";
- return false;
- }
- // FileInputWorker can't handle other bits sizes
- if (header.m_bitsPerSample != 16)
- {
- qDebug() << "WavFileRecord::readHeader: Number of bits per sample is not 16";
+ if (!checkHeader(header)) {
return false;
}
@@ -365,11 +368,89 @@ bool WavFileRecord::readHeader(std::ifstream& sampleFile, Header& header)
return true;
}
+bool WavFileRecord::readHeader(QFile& sampleFile, Header& header)
+{
+ memset(&header, 0, sizeof(Header));
+
+ sampleFile.read((char *) &header, 8+4+8+16);
+
+ if (!checkHeader(header)) {
+ return false;
+ }
+
+ Chunk chunkHeader;
+ bool gotData = false;
+ while (!gotData)
+ {
+ if (sampleFile.read((char *) &chunkHeader, 8) != 8)
+ {
+ qDebug() << "WavFileRecord::readHeader: End of file without reading data header";
+ return false;
+ }
+
+ if (!strncmp(chunkHeader.m_id, "auxi", 4))
+ {
+ memcpy(&header.m_auxiHeader, &chunkHeader, sizeof(Chunk));
+ if (sampleFile.read((char *) &header.m_auxi, sizeof(Auxi)) != sizeof(Auxi)) {
+ return false;
+ }
+ }
+ else if (!strncmp(chunkHeader.m_id, "data", 4))
+ {
+ memcpy(&header.m_dataHeader, &chunkHeader, sizeof(Chunk));
+ gotData = true;
+ }
+ }
+
+ return true;
+}
+
+bool WavFileRecord::checkHeader(Header& header)
+{
+ if (strncmp(header.m_riffHeader.m_id, "RIFF", 4))
+ {
+ qDebug() << "WavFileRecord::readHeader: No RIFF header";
+ return false;
+ }
+ if (strncmp(header.m_type, "WAVE", 4))
+ {
+ qDebug() << "WavFileRecord::readHeader: No WAVE header";
+ return false;
+ }
+ if (strncmp(header.m_fmtHeader.m_id, "fmt ", 4))
+ {
+ qDebug() << "WavFileRecord::readHeader: No fmt header";
+ return false;
+ }
+ if (header.m_audioFormat != 1)
+ {
+ qDebug() << "WavFileRecord::readHeader: Audio format is not PCM";
+ return false;
+ }
+ if (header.m_numChannels != 2)
+ {
+ qDebug() << "WavFileRecord::readHeader: Number of channels is not 2";
+ return false;
+ }
+ // FileInputWorker can't handle other bits sizes
+ if (header.m_bitsPerSample != 16)
+ {
+ qDebug() << "WavFileRecord::readHeader: Number of bits per sample is not 16";
+ return false;
+ }
+ return true;
+}
+
void WavFileRecord::writeHeader(std::ofstream& sampleFile, Header& header)
{
sampleFile.write((const char *) &header, sizeof(Header));
}
+void WavFileRecord::writeHeader(QFile& sampleFile, Header& header)
+{
+ sampleFile.write((const char *) &header, sizeof(Header));
+}
+
bool WavFileRecord::getCenterFrequency(QString fileName, quint64& centerFrequency)
{
// Attempt to extract center frequency from filename
diff --git a/sdrbase/dsp/wavfilerecord.h b/sdrbase/dsp/wavfilerecord.h
index 6e1e49317..9cf2db22b 100644
--- a/sdrbase/dsp/wavfilerecord.h
+++ b/sdrbase/dsp/wavfilerecord.h
@@ -27,6 +27,7 @@
#include
#include
+#include
#include "dsp/filerecordinterface.h"
#include "export.h"
@@ -111,7 +112,9 @@ public:
virtual bool isRecording() const override { return m_recordOn; }
static bool readHeader(std::ifstream& samplefile, Header& header);
+ static bool readHeader(QFile& samplefile, Header& header);
static void writeHeader(std::ofstream& samplefile, Header& header);
+ static void writeHeader(QFile& samplefile, Header& header);
// These functions guess from the filename, not contents
static bool getCenterFrequency(QString fileName, quint64& centerFrequency);
@@ -123,13 +126,19 @@ private:
quint64 m_centerFrequency;
bool m_recordOn;
bool m_recordStart;
+#ifdef ANDROID
+ QFile m_sampleFile;
+#else
std::ofstream m_sampleFile;
+#endif
QString m_currentFileName;
quint64 m_byteCount;
qint64 m_msShift;
int m_nbChannels;
void writeHeader();
+
+ static bool checkHeader(Header& header);
};
#endif // INCLUDE_WAV_FILERECORD_H