From 12a97b96440387f35b84f6abb45a3a6243575329 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 25 Jan 2018 18:39:54 +0100 Subject: [PATCH] File Input and record: 16/24 bit DSP compatibility --- .../filesource/filesourceinput.cpp | 6 +- .../samplesource/filesource/filesourceinput.h | 1 + .../filesource/filesourceplugin.cpp | 2 +- .../filesource/filesourcethread.cpp | 127 ++++++++++++++---- .../filesource/filesourcethread.h | 13 +- sdrbase/dsp/filerecord.cpp | 14 +- sdrbase/dsp/filerecord.h | 5 +- 7 files changed, 127 insertions(+), 41 deletions(-) diff --git a/plugins/samplesource/filesource/filesourceinput.cpp b/plugins/samplesource/filesource/filesourceinput.cpp index 8a6b79b72..c48f966f4 100644 --- a/plugins/samplesource/filesource/filesourceinput.cpp +++ b/plugins/samplesource/filesource/filesourceinput.cpp @@ -48,6 +48,7 @@ FileSourceInput::FileSourceInput(DeviceSourceAPI *deviceAPI) : m_deviceDescription(), m_fileName("..."), m_sampleRate(0), + m_sampleSize(0), m_centerFrequency(0), m_recordLength(0), m_startingTimeStamp(0), @@ -85,6 +86,7 @@ void FileSourceInput::openFileStream() m_sampleRate = header.sampleRate; m_centerFrequency = header.centerFrequency; m_startingTimeStamp = header.startTimeStamp; + m_sampleSize = header.sampleSize; if (fileSize > sizeof(FileRecord::Header)) { m_recordLength = (fileSize - sizeof(FileRecord::Header)) / (4 * m_sampleRate); @@ -136,7 +138,7 @@ bool FileSourceInput::start() m_ifstream.seekg(sizeof(FileRecord::Header), std::ios::beg); } - if(!m_sampleFifo.setSize(m_sampleRate * 4)) { + if(!m_sampleFifo.setSize(m_sampleRate * sizeof(Sample))) { qCritical("Could not allocate SampleFifo"); return false; } @@ -149,7 +151,7 @@ bool FileSourceInput::start() return false; } - m_fileSourceThread->setSamplerate(m_sampleRate); + m_fileSourceThread->setSampleRateAndSize(m_sampleRate, m_sampleSize); m_fileSourceThread->connectTimer(m_masterTimer); m_fileSourceThread->startWork(); m_deviceDescription = "FileSource"; diff --git a/plugins/samplesource/filesource/filesourceinput.h b/plugins/samplesource/filesource/filesourceinput.h index e3e157468..c56d59bba 100644 --- a/plugins/samplesource/filesource/filesourceinput.h +++ b/plugins/samplesource/filesource/filesourceinput.h @@ -265,6 +265,7 @@ public: QString m_deviceDescription; QString m_fileName; int m_sampleRate; + quint32 m_sampleSize; quint64 m_centerFrequency; quint32 m_recordLength; //!< record length in seconds computed from file size std::time_t m_startingTimeStamp; diff --git a/plugins/samplesource/filesource/filesourceplugin.cpp b/plugins/samplesource/filesource/filesourceplugin.cpp index 4705c4de4..f4a962afd 100644 --- a/plugins/samplesource/filesource/filesourceplugin.cpp +++ b/plugins/samplesource/filesource/filesourceplugin.cpp @@ -29,7 +29,7 @@ const PluginDescriptor FileSourcePlugin::m_pluginDescriptor = { QString("File source input"), - QString("3.10.1"), + QString("3.11.1"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/filesource/filesourcethread.cpp b/plugins/samplesource/filesource/filesourcethread.cpp index 0df5d73c5..d69099bbf 100644 --- a/plugins/samplesource/filesource/filesourcethread.cpp +++ b/plugins/samplesource/filesource/filesourcethread.cpp @@ -27,12 +27,15 @@ FileSourceThread::FileSourceThread(std::ifstream *samplesStream, SampleSinkFifo* QThread(parent), m_running(false), m_ifstream(samplesStream), - m_buf(0), + m_fileBuf(0), + m_convertBuf(0), m_bufsize(0), m_chunksize(0), m_sampleFifo(sampleFifo), m_samplesCount(0), m_samplerate(0), + m_samplesize(0), + m_samplebytes(0), m_throttlems(FILESOURCE_THROTTLE_MS), m_throttleToggle(false) { @@ -45,8 +48,12 @@ FileSourceThread::~FileSourceThread() stopWork(); } - if (m_buf != 0) { - free(m_buf); + if (m_fileBuf != 0) { + free(m_fileBuf); + } + + if (m_convertBuf != 0) { + free(m_convertBuf); } } @@ -77,49 +84,67 @@ void FileSourceThread::stopWork() wait(); } -void FileSourceThread::setSamplerate(int samplerate) +void FileSourceThread::setSampleRateAndSize(int samplerate, quint32 samplesize) { - qDebug() << "FileSourceThread::setSamplerate:" - << " new:" << samplerate - << " old:" << m_samplerate; + qDebug() << "FileSourceThread::setSampleRateAndSize:" + << " new rate:" << samplerate + << " new size:" << samplesize + << " old rate:" << m_samplerate + << " old size:" << m_samplesize; - if (samplerate != m_samplerate) + if ((samplerate != m_samplerate) || (samplesize != m_samplesize)) { if (m_running) { stopWork(); } m_samplerate = samplerate; - // TODO: implement FF and slow motion here. 4 corresponds to live. 2 is half speed, 8 is doulbe speed - m_chunksize = (m_samplerate * 4 * m_throttlems) / 1000; + m_samplesize = samplesize; + m_samplebytes = m_samplesize > 16 ? sizeof(int32_t) : sizeof(int16_t); + // TODO: implement FF and slow motion here. 2 corresponds to live. 1 is half speed, 4 is double speed + m_chunksize = (m_samplerate * 2 * m_samplebytes * m_throttlems) / 1000; - setBuffer(m_chunksize); + setBuffers(m_chunksize); } //m_samplerate = samplerate; } -void FileSourceThread::setBuffer(std::size_t chunksize) +void FileSourceThread::setBuffers(std::size_t chunksize) { if (chunksize > m_bufsize) { m_bufsize = chunksize; + int nbSamples = m_bufsize/(2 * m_samplebytes); - if (m_buf == 0) + if (m_fileBuf == 0) { - qDebug() << "FileSourceThread::setBuffer: Allocate buffer"; - m_buf = (quint8*) malloc(m_bufsize); + qDebug() << "FileSourceThread::setBuffers: Allocate file buffer"; + m_fileBuf = (quint8*) malloc(m_bufsize); } else { - qDebug() << "FileSourceThread::setBuffer: Re-allocate buffer"; - quint8 *buf = m_buf; - m_buf = (quint8*) realloc((void*) m_buf, m_bufsize); - if (!m_buf) free(buf); + qDebug() << "FileSourceThread::setBuffers: Re-allocate file buffer"; + quint8 *buf = m_fileBuf; + m_fileBuf = (quint8*) realloc((void*) m_fileBuf, m_bufsize); + if (!m_fileBuf) free(buf); } - qDebug() << "FileSourceThread::setBuffer: size: " << m_bufsize - << " #samples: " << (m_bufsize/4); + if (m_convertBuf == 0) + { + qDebug() << "FileSourceThread::setBuffers: Allocate conversion buffer"; + m_convertBuf = (quint8*) malloc(nbSamples*sizeof(Sample)); + } + else + { + qDebug() << "FileSourceThread::setBuffers: Re-allocate conversion buffer"; + quint8 *buf = m_convertBuf; + m_convertBuf = (quint8*) realloc((void*) m_convertBuf, nbSamples*sizeof(Sample)); + if (!m_convertBuf) free(buf); + } + + qDebug() << "FileSourceThread::setBuffers: size: " << m_bufsize + << " #samples: " << nbSamples; } } @@ -151,17 +176,18 @@ void FileSourceThread::tick() if (throttlems != m_throttlems) { m_throttlems = throttlems; - m_chunksize = 4 * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000); + m_chunksize = 2 * m_samplebytes * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000); m_throttleToggle = !m_throttleToggle; - setBuffer(m_chunksize); + setBuffers(m_chunksize); } // read samples directly feeding the SampleFifo (no callback) - m_ifstream->read(reinterpret_cast(m_buf), m_chunksize); + m_ifstream->read(reinterpret_cast(m_fileBuf), m_chunksize); if (m_ifstream->eof()) { - m_sampleFifo->write(m_buf, m_ifstream->gcount()); + writeToSampleFifo(m_fileBuf, (qint32) m_ifstream->gcount()); + //m_sampleFifo->write(m_buf, m_ifstream->gcount()); // TODO: handle loop playback situation m_ifstream->clear(); m_ifstream->seekg(sizeof(FileRecord::Header), std::ios::beg); @@ -171,8 +197,55 @@ void FileSourceThread::tick() } else { - m_sampleFifo->write(m_buf, m_chunksize); - m_samplesCount += m_chunksize / 4; + writeToSampleFifo(m_fileBuf, (qint32) m_chunksize); + //m_sampleFifo->write(m_buf, m_chunksize); + m_samplesCount += m_chunksize / (2 * m_samplebytes); } } } + +void FileSourceThread::writeToSampleFifo(const quint8* buf, qint32 nbBytes) +{ + if (m_samplesize == 16) + { + if (SDR_RX_SAMP_SZ == 16) + { + m_sampleFifo->write(buf, nbBytes); + } + else if (SDR_RX_SAMP_SZ == 24) + { + FixReal *convertBuf = (FixReal *) m_convertBuf; + const int16_t *fileBuf = (int16_t *) buf; + int nbSamples = nbBytes / (2 * m_samplebytes); + + for (int is = 0; is < nbSamples; is++) + { + convertBuf[2*is] = fileBuf[2*is] << 8; + convertBuf[2*is+1] = fileBuf[2*is+1] << 8; + } + + m_sampleFifo->write((quint8*) convertBuf, nbSamples*sizeof(Sample)); + } + } + else if (m_samplesize == 24) + { + if (SDR_RX_SAMP_SZ == 24) + { + m_sampleFifo->write(buf, nbBytes); + } + else if (SDR_RX_SAMP_SZ == 16) + { + FixReal *convertBuf = (FixReal *) m_convertBuf; + const int32_t *fileBuf = (int32_t *) buf; + int nbSamples = nbBytes / (2 * m_samplebytes); + + for (int is = 0; is < nbSamples; is++) + { + convertBuf[2*is] = fileBuf[2*is] >> 8; + convertBuf[2*is+1] = fileBuf[2*is+1] >> 8; + } + + m_sampleFifo->write((quint8*) convertBuf, nbSamples*sizeof(Sample)); + } + } +} diff --git a/plugins/samplesource/filesource/filesourcethread.h b/plugins/samplesource/filesource/filesourcethread.h index ca777a241..ff483b84d 100644 --- a/plugins/samplesource/filesource/filesourcethread.h +++ b/plugins/samplesource/filesource/filesourcethread.h @@ -41,8 +41,8 @@ public: void startWork(); void stopWork(); - void setSamplerate(int samplerate); - void setBuffer(std::size_t chunksize); + void setSampleRateAndSize(int samplerate, quint32 samplesize); + void setBuffers(std::size_t chunksize); bool isRunning() const { return m_running; } std::size_t getSamplesCount() const { return m_samplesCount; } void setSamplesCount(int samplesCount) { m_samplesCount = samplesCount; } @@ -55,20 +55,23 @@ private: bool m_running; std::ifstream* m_ifstream; - quint8 *m_buf; + quint8 *m_fileBuf; + quint8 *m_convertBuf; std::size_t m_bufsize; std::size_t m_chunksize; SampleSinkFifo* m_sampleFifo; std::size_t m_samplesCount; - int m_samplerate; + int m_samplerate; //!< File I/Q stream original sample rate + quint32 m_samplesize; //!< File effective sample size in bits (I or Q). Ex: 16, 24. + quint32 m_samplebytes; //!< Number of bytes used to store a I or Q sample. Ex: 2. 4. int m_throttlems; QElapsedTimer m_elapsedTimer; bool m_throttleToggle; void run(); //void decimate1(SampleVector::iterator* it, const qint16* buf, qint32 len); - //void callback(const qint16* buf, qint32 len); + void writeToSampleFifo(const quint8* buf, qint32 nbBytes); private slots: void tick(); }; diff --git a/sdrbase/dsp/filerecord.cpp b/sdrbase/dsp/filerecord.cpp index f0f2fd3e8..e2e5606e3 100644 --- a/sdrbase/dsp/filerecord.cpp +++ b/sdrbase/dsp/filerecord.cpp @@ -122,15 +122,21 @@ void FileRecord::handleConfigure(const std::string& fileName) void FileRecord::writeHeader() { - m_sampleFile.write((const char *) &m_sampleRate, sizeof(int)); - m_sampleFile.write((const char *) &m_centerFrequency, sizeof(quint64)); + m_sampleFile.write((const char *) &m_sampleRate, sizeof(qint32)); // 4 bytes + m_sampleFile.write((const char *) &m_centerFrequency, sizeof(quint64)); // 8 bytes std::time_t ts = time(0); - m_sampleFile.write((const char *) &ts, sizeof(std::time_t)); + m_sampleFile.write((const char *) &ts, sizeof(std::time_t)); // 8 bytes + quint32 sampleSize = SDR_RX_SAMP_SZ; + m_sampleFile.write((const char *) &sampleSize, sizeof(int)); // 4 bytes } void FileRecord::readHeader(std::ifstream& sampleFile, Header& header) { - sampleFile.read((char *) &(header.sampleRate), sizeof(int)); + sampleFile.read((char *) &(header.sampleRate), sizeof(qint32)); sampleFile.read((char *) &(header.centerFrequency), sizeof(quint64)); sampleFile.read((char *) &(header.startTimeStamp), sizeof(std::time_t)); + sampleFile.read((char *) &(header.sampleSize), sizeof(quint32)); + if ((header.sampleSize != 16) || (header.sampleSize != 24)) { // assume 16 bits if garbage (old I/Q file) + header.sampleSize = 16; + } } diff --git a/sdrbase/dsp/filerecord.h b/sdrbase/dsp/filerecord.h index 9444966a3..dac0be078 100644 --- a/sdrbase/dsp/filerecord.h +++ b/sdrbase/dsp/filerecord.h @@ -16,9 +16,10 @@ public: struct Header { - int sampleRate; + qint32 sampleRate; quint64 centerFrequency; std::time_t startTimeStamp; + quint32 sampleSize; }; FileRecord(); @@ -39,7 +40,7 @@ public: private: std::string m_fileName; - int m_sampleRate; + qint32 m_sampleRate; quint64 m_centerFrequency; bool m_recordOn; bool m_recordStart;