2015-08-02 19:04:20 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
|
|
|
// //
|
|
|
|
// This program is free software; you can redistribute it and/or modify //
|
|
|
|
// it under the terms of the GNU General Public License as published by //
|
|
|
|
// the Free Software Foundation as version 3 of the License, or //
|
|
|
|
// //
|
|
|
|
// This program is distributed in the hope that it will be useful, //
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
|
|
// GNU General Public License V3 for more details. //
|
|
|
|
// //
|
|
|
|
// You should have received a copy of the GNU General Public License //
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
2015-08-03 22:17:24 -04:00
|
|
|
#include <assert.h>
|
2015-08-09 04:33:04 -04:00
|
|
|
#include <QDebug>
|
2015-08-02 19:04:20 -04:00
|
|
|
|
2016-10-08 04:02:36 -04:00
|
|
|
#include "dsp/filerecord.h"
|
2015-08-02 19:04:20 -04:00
|
|
|
#include "filesourcethread.h"
|
2016-10-08 04:02:36 -04:00
|
|
|
#include "dsp/samplesinkfifo.h"
|
2015-08-02 19:04:20 -04:00
|
|
|
|
2016-10-06 13:18:02 -04:00
|
|
|
FileSourceThread::FileSourceThread(std::ifstream *samplesStream, SampleSinkFifo* sampleFifo, QObject* parent) :
|
2015-08-02 19:04:20 -04:00
|
|
|
QThread(parent),
|
|
|
|
m_running(false),
|
|
|
|
m_ifstream(samplesStream),
|
2018-01-25 12:39:54 -05:00
|
|
|
m_fileBuf(0),
|
|
|
|
m_convertBuf(0),
|
2015-08-02 19:04:20 -04:00
|
|
|
m_bufsize(0),
|
|
|
|
m_chunksize(0),
|
|
|
|
m_sampleFifo(sampleFifo),
|
2015-08-05 19:14:44 -04:00
|
|
|
m_samplesCount(0),
|
2016-03-13 20:43:21 -04:00
|
|
|
m_samplerate(0),
|
2018-01-25 12:39:54 -05:00
|
|
|
m_samplesize(0),
|
|
|
|
m_samplebytes(0),
|
2016-03-13 20:43:21 -04:00
|
|
|
m_throttlems(FILESOURCE_THROTTLE_MS),
|
|
|
|
m_throttleToggle(false)
|
2015-08-02 19:04:20 -04:00
|
|
|
{
|
2015-08-03 22:17:24 -04:00
|
|
|
assert(m_ifstream != 0);
|
2015-08-02 19:04:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
FileSourceThread::~FileSourceThread()
|
|
|
|
{
|
|
|
|
if (m_running) {
|
|
|
|
stopWork();
|
|
|
|
}
|
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
if (m_fileBuf != 0) {
|
|
|
|
free(m_fileBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_convertBuf != 0) {
|
|
|
|
free(m_convertBuf);
|
2015-08-02 19:04:20 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileSourceThread::startWork()
|
|
|
|
{
|
2015-08-09 04:33:04 -04:00
|
|
|
qDebug() << "FileSourceThread::startWork: ";
|
2016-10-08 04:02:36 -04:00
|
|
|
|
2015-08-03 22:17:24 -04:00
|
|
|
if (m_ifstream->is_open())
|
|
|
|
{
|
2016-02-25 08:07:39 -05:00
|
|
|
qDebug() << "FileSourceThread::startWork: file stream open, starting...";
|
2015-08-03 22:17:24 -04:00
|
|
|
m_startWaitMutex.lock();
|
2016-03-13 20:43:21 -04:00
|
|
|
m_elapsedTimer.start();
|
2015-08-03 22:17:24 -04:00
|
|
|
start();
|
|
|
|
while(!m_running)
|
|
|
|
m_startWaiter.wait(&m_startWaitMutex, 100);
|
|
|
|
m_startWaitMutex.unlock();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-25 08:07:39 -05:00
|
|
|
qDebug() << "FileSourceThread::startWork: file stream closed, not starting.";
|
2015-08-03 22:17:24 -04:00
|
|
|
}
|
2015-08-02 19:04:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileSourceThread::stopWork()
|
|
|
|
{
|
2015-08-09 04:33:04 -04:00
|
|
|
qDebug() << "FileSourceThread::stopWork";
|
2015-08-02 19:04:20 -04:00
|
|
|
m_running = false;
|
|
|
|
wait();
|
|
|
|
}
|
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
void FileSourceThread::setSampleRateAndSize(int samplerate, quint32 samplesize)
|
2015-08-02 19:04:20 -04:00
|
|
|
{
|
2018-01-25 12:39:54 -05:00
|
|
|
qDebug() << "FileSourceThread::setSampleRateAndSize:"
|
|
|
|
<< " new rate:" << samplerate
|
|
|
|
<< " new size:" << samplesize
|
|
|
|
<< " old rate:" << m_samplerate
|
|
|
|
<< " old size:" << m_samplesize;
|
2015-08-03 22:17:24 -04:00
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
if ((samplerate != m_samplerate) || (samplesize != m_samplesize))
|
2015-08-02 19:04:20 -04:00
|
|
|
{
|
|
|
|
if (m_running) {
|
|
|
|
stopWork();
|
|
|
|
}
|
|
|
|
|
2015-08-03 22:17:24 -04:00
|
|
|
m_samplerate = samplerate;
|
2018-01-25 12:39:54 -05:00
|
|
|
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;
|
2015-08-03 22:17:24 -04:00
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
setBuffers(m_chunksize);
|
2015-08-02 19:04:20 -04:00
|
|
|
}
|
|
|
|
|
2015-08-05 18:10:23 -04:00
|
|
|
//m_samplerate = samplerate;
|
2015-08-02 19:04:20 -04:00
|
|
|
}
|
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
void FileSourceThread::setBuffers(std::size_t chunksize)
|
2016-03-13 20:43:21 -04:00
|
|
|
{
|
|
|
|
if (chunksize > m_bufsize)
|
|
|
|
{
|
|
|
|
m_bufsize = chunksize;
|
2018-01-25 12:39:54 -05:00
|
|
|
int nbSamples = m_bufsize/(2 * m_samplebytes);
|
|
|
|
|
|
|
|
if (m_fileBuf == 0)
|
|
|
|
{
|
|
|
|
qDebug() << "FileSourceThread::setBuffers: Allocate file buffer";
|
|
|
|
m_fileBuf = (quint8*) malloc(m_bufsize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2016-03-13 20:43:21 -04:00
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
if (m_convertBuf == 0)
|
2016-03-13 20:43:21 -04:00
|
|
|
{
|
2018-01-25 12:39:54 -05:00
|
|
|
qDebug() << "FileSourceThread::setBuffers: Allocate conversion buffer";
|
|
|
|
m_convertBuf = (quint8*) malloc(nbSamples*sizeof(Sample));
|
2016-03-13 20:43:21 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-25 12:39:54 -05:00
|
|
|
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);
|
2016-03-13 20:43:21 -04:00
|
|
|
}
|
|
|
|
|
2018-01-25 12:39:54 -05:00
|
|
|
qDebug() << "FileSourceThread::setBuffers: size: " << m_bufsize
|
|
|
|
<< " #samples: " << nbSamples;
|
2016-03-13 20:43:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-02 19:04:20 -04:00
|
|
|
void FileSourceThread::run()
|
|
|
|
{
|
|
|
|
m_running = true;
|
|
|
|
m_startWaiter.wakeAll();
|
|
|
|
|
2015-08-03 22:17:24 -04:00
|
|
|
while(m_running) // actual work is in the tick() function
|
2015-08-02 19:04:20 -04:00
|
|
|
{
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_running = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileSourceThread::connectTimer(const QTimer& timer)
|
|
|
|
{
|
2015-08-09 04:33:04 -04:00
|
|
|
qDebug() << "FileSourceThread::connectTimer";
|
2015-08-02 19:04:20 -04:00
|
|
|
connect(&timer, SIGNAL(timeout()), this, SLOT(tick()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileSourceThread::tick()
|
|
|
|
{
|
|
|
|
if (m_running)
|
|
|
|
{
|
2016-03-13 20:43:21 -04:00
|
|
|
qint64 throttlems = m_elapsedTimer.restart();
|
|
|
|
|
|
|
|
if (throttlems != m_throttlems)
|
|
|
|
{
|
|
|
|
m_throttlems = throttlems;
|
2018-01-25 12:39:54 -05:00
|
|
|
m_chunksize = 2 * m_samplebytes * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000);
|
2016-03-13 20:43:21 -04:00
|
|
|
m_throttleToggle = !m_throttleToggle;
|
2018-01-25 12:39:54 -05:00
|
|
|
setBuffers(m_chunksize);
|
2016-03-13 20:43:21 -04:00
|
|
|
}
|
|
|
|
|
2015-08-02 19:04:20 -04:00
|
|
|
// read samples directly feeding the SampleFifo (no callback)
|
2018-01-25 12:39:54 -05:00
|
|
|
m_ifstream->read(reinterpret_cast<char*>(m_fileBuf), m_chunksize);
|
2016-10-08 04:02:36 -04:00
|
|
|
|
2015-08-03 22:17:24 -04:00
|
|
|
if (m_ifstream->eof())
|
|
|
|
{
|
2018-01-25 12:39:54 -05:00
|
|
|
writeToSampleFifo(m_fileBuf, (qint32) m_ifstream->gcount());
|
|
|
|
//m_sampleFifo->write(m_buf, m_ifstream->gcount());
|
2015-08-03 22:17:24 -04:00
|
|
|
// TODO: handle loop playback situation
|
2015-08-05 03:26:00 -04:00
|
|
|
m_ifstream->clear();
|
2016-10-08 04:02:36 -04:00
|
|
|
m_ifstream->seekg(sizeof(FileRecord::Header), std::ios::beg);
|
2015-08-05 19:14:44 -04:00
|
|
|
m_samplesCount = 0;
|
2015-08-05 03:26:00 -04:00
|
|
|
//stopWork();
|
2015-08-04 21:25:06 -04:00
|
|
|
//m_ifstream->close();
|
2015-08-03 22:17:24 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-25 12:39:54 -05:00
|
|
|
writeToSampleFifo(m_fileBuf, (qint32) m_chunksize);
|
|
|
|
//m_sampleFifo->write(m_buf, m_chunksize);
|
|
|
|
m_samplesCount += m_chunksize / (2 * m_samplebytes);
|
2015-08-03 22:17:24 -04:00
|
|
|
}
|
2015-08-02 19:04:20 -04:00
|
|
|
}
|
|
|
|
}
|
2018-01-25 12:39:54 -05:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|