SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
fileinputthread.cpp
Go to the documentation of this file.
1 // Copyright (C) 2015-2019 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include <stdio.h>
19 #include <errno.h>
20 #include <assert.h>
21 #include <QDebug>
22 
23 #include "dsp/filerecord.h"
24 #include "fileinputthread.h"
25 #include "dsp/samplesinkfifo.h"
26 #include "util/messagequeue.h"
27 
29 
30 FileInputThread::FileInputThread(std::ifstream *samplesStream,
31  SampleSinkFifo* sampleFifo,
32  const QTimer& timer,
33  MessageQueue *fileInputMessageQueue,
34  QObject* parent) :
35  QThread(parent),
36  m_running(false),
37  m_ifstream(samplesStream),
38  m_fileBuf(0),
39  m_convertBuf(0),
40  m_bufsize(0),
41  m_chunksize(0),
42  m_sampleFifo(sampleFifo),
43  m_samplesCount(0),
44  m_timer(timer),
45  m_fileInputMessageQueue(fileInputMessageQueue),
46  m_samplerate(0),
47  m_samplesize(0),
48  m_samplebytes(0),
49  m_throttlems(FILESOURCE_THROTTLE_MS),
50  m_throttleToggle(false)
51 {
52  assert(m_ifstream != 0);
53 }
54 
56 {
57  if (m_running) {
58  stopWork();
59  }
60 
61  if (m_fileBuf != 0) {
62  free(m_fileBuf);
63  }
64 
65  if (m_convertBuf != 0) {
66  free(m_convertBuf);
67  }
68 }
69 
71 {
72  qDebug() << "FileInputThread::startWork: ";
73 
74  if (m_ifstream->is_open())
75  {
76  qDebug() << "FileInputThread::startWork: file stream open, starting...";
77  m_startWaitMutex.lock();
78  m_elapsedTimer.start();
79  start();
80  while(!m_running)
81  m_startWaiter.wait(&m_startWaitMutex, 100);
82  m_startWaitMutex.unlock();
83  connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
84  }
85  else
86  {
87  qDebug() << "FileInputThread::startWork: file stream closed, not starting.";
88  }
89 }
90 
92 {
93  qDebug() << "FileInputThread::stopWork";
94  disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
95  m_running = false;
96  wait();
97 }
98 
99 void FileInputThread::setSampleRateAndSize(int samplerate, quint32 samplesize)
100 {
101  qDebug() << "FileInputThread::setSampleRateAndSize:"
102  << " new rate:" << samplerate
103  << " new size:" << samplesize
104  << " old rate:" << m_samplerate
105  << " old size:" << m_samplesize;
106 
107  if ((samplerate != m_samplerate) || (samplesize != m_samplesize))
108  {
109  if (m_running) {
110  stopWork();
111  }
112 
113  m_samplerate = samplerate;
114  m_samplesize = samplesize;
115  m_samplebytes = m_samplesize > 16 ? sizeof(int32_t) : sizeof(int16_t);
117 
119  }
120 
121  //m_samplerate = samplerate;
122 }
123 
124 void FileInputThread::setBuffers(std::size_t chunksize)
125 {
126  if (chunksize > m_bufsize)
127  {
128  m_bufsize = chunksize;
129  int nbSamples = m_bufsize/(2 * m_samplebytes);
130 
131  if (m_fileBuf == 0)
132  {
133  qDebug() << "FileInputThread::setBuffers: Allocate file buffer";
134  m_fileBuf = (quint8*) malloc(m_bufsize);
135  }
136  else
137  {
138  qDebug() << "FileInputThread::setBuffers: Re-allocate file buffer";
139  quint8 *buf = m_fileBuf;
140  m_fileBuf = (quint8*) realloc((void*) m_fileBuf, m_bufsize);
141  if (!m_fileBuf) free(buf);
142  }
143 
144  if (m_convertBuf == 0)
145  {
146  qDebug() << "FileInputThread::setBuffers: Allocate conversion buffer";
147  m_convertBuf = (quint8*) malloc(nbSamples*sizeof(Sample));
148  }
149  else
150  {
151  qDebug() << "FileInputThread::setBuffers: Re-allocate conversion buffer";
152  quint8 *buf = m_convertBuf;
153  m_convertBuf = (quint8*) realloc((void*) m_convertBuf, nbSamples*sizeof(Sample));
154  if (!m_convertBuf) free(buf);
155  }
156 
157  qDebug() << "FileInputThread::setBuffers: size: " << m_bufsize
158  << " #samples: " << nbSamples;
159  }
160 }
161 
163 {
164  m_running = true;
165  m_startWaiter.wakeAll();
166 
167  while(m_running) // actual work is in the tick() function
168  {
169  sleep(1);
170  }
171 
172  m_running = false;
173 }
174 
176 {
177  if (m_running)
178  {
179  qint64 throttlems = m_elapsedTimer.restart();
180 
181  if (throttlems != m_throttlems)
182  {
183  m_throttlems = throttlems;
184  m_chunksize = 2 * m_samplebytes * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000);
187  }
188 
189  // read samples directly feeding the SampleFifo (no callback)
190  m_ifstream->read(reinterpret_cast<char*>(m_fileBuf), m_chunksize);
191 
192  if (m_ifstream->eof())
193  {
194  writeToSampleFifo(m_fileBuf, (qint32) m_ifstream->gcount());
195  MsgReportEOF *message = MsgReportEOF::create();
196  m_fileInputMessageQueue->push(message);
197  }
198  else
199  {
201  m_samplesCount += m_chunksize / (2 * m_samplebytes);
202  }
203  }
204 }
205 
206 void FileInputThread::writeToSampleFifo(const quint8* buf, qint32 nbBytes)
207 {
208  if (m_samplesize == 16)
209  {
210  if (SDR_RX_SAMP_SZ == 16)
211  {
212  m_sampleFifo->write(buf, nbBytes);
213  }
214  else if (SDR_RX_SAMP_SZ == 24)
215  {
216  FixReal *convertBuf = (FixReal *) m_convertBuf;
217  const int16_t *fileBuf = (int16_t *) buf;
218  int nbSamples = nbBytes / (2 * m_samplebytes);
219 
220  for (int is = 0; is < nbSamples; is++)
221  {
222  convertBuf[2*is] = fileBuf[2*is] << 8;
223  convertBuf[2*is+1] = fileBuf[2*is+1] << 8;
224  }
225 
226  m_sampleFifo->write((quint8*) convertBuf, nbSamples*sizeof(Sample));
227  }
228  }
229  else if (m_samplesize == 24)
230  {
231  if (SDR_RX_SAMP_SZ == 24)
232  {
233  m_sampleFifo->write(buf, nbBytes);
234  }
235  else if (SDR_RX_SAMP_SZ == 16)
236  {
237  FixReal *convertBuf = (FixReal *) m_convertBuf;
238  const int32_t *fileBuf = (int32_t *) buf;
239  int nbSamples = nbBytes / (2 * m_samplebytes);
240 
241  for (int is = 0; is < nbSamples; is++)
242  {
243  convertBuf[2*is] = fileBuf[2*is] >> 8;
244  convertBuf[2*is+1] = fileBuf[2*is+1] >> 8;
245  }
246 
247  m_sampleFifo->write((quint8*) convertBuf, nbSamples*sizeof(Sample));
248  }
249  }
250 }
std::size_t m_bufsize
short int16_t
Definition: rtptypes_win.h:43
void push(Message *message, bool emitSignal=true)
Push message onto queue.
uint write(const quint8 *data, uint count)
volatile bool m_running
QWaitCondition m_startWaiter
quint64 m_samplesize
File effective sample size in bits (I or Q). Ex: 16, 24.
void writeToSampleFifo(const quint8 *buf, qint32 nbBytes)
#define SDR_RX_SAMP_SZ
Definition: dsptypes.h:32
#define FILESOURCE_THROTTLE_MS
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
quint8 * m_convertBuf
const QTimer & m_timer
quint64 m_samplebytes
Number of bytes used to store a I or Q sample. Ex: 2. 4.
int int32_t
Definition: rtptypes_win.h:45
std::ifstream * m_ifstream
MessageQueue * m_fileInputMessageQueue
quint64 m_samplesCount
SampleSinkFifo * m_sampleFifo
void setSampleRateAndSize(int samplerate, quint32 samplesize)
void setBuffers(std::size_t chunksize)
static MsgReportEOF * create()
QElapsedTimer m_elapsedTimer
qint16 FixReal
Definition: dsptypes.h:35
int m_samplerate
File I/Q stream original sample rate.