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.
filesinkthread.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016 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 <algorithm>
22 #include <QDebug>
23 
24 #include "dsp/samplesourcefifo.h"
25 #include "filesinkthread.h"
26 
27 FileSinkThread::FileSinkThread(std::ofstream *samplesStream, SampleSourceFifo* sampleFifo, QObject* parent) :
28  QThread(parent),
29  m_running(false),
30  m_ofstream(samplesStream),
31  m_bufsize(0),
32  m_samplesChunkSize(0),
33  m_sampleFifo(sampleFifo),
34  m_samplesCount(0),
35  m_samplerate(0),
36  m_log2Interpolation(0),
37  m_throttlems(FILESINK_THROTTLE_MS),
38  m_maxThrottlems(50),
39  m_throttleToggle(false),
40  m_buf(0)
41 {
42  assert(m_ofstream != 0);
43 }
44 
46 {
47  if (m_running) {
48  stopWork();
49  }
50 
51  if (m_buf) delete[] m_buf;
52 }
53 
55 {
56  qDebug() << "FileSinkThread::startWork: ";
57 
58  if (m_ofstream->is_open())
59  {
60  qDebug() << "FileSinkThread::startWork: file stream open, starting...";
61  m_maxThrottlems = 0;
62  m_startWaitMutex.lock();
63  m_elapsedTimer.start();
64  start();
65  while(!m_running)
66  m_startWaiter.wait(&m_startWaitMutex, 100);
67  m_startWaitMutex.unlock();
68  }
69  else
70  {
71  qDebug() << "FileSinkThread::startWork: file stream closed, not starting.";
72  }
73 }
74 
76 {
77  qDebug() << "FileSinkThread::stopWork";
78  m_running = false;
79  wait();
80 }
81 
82 void FileSinkThread::setSamplerate(int samplerate)
83 {
84  if (samplerate != m_samplerate)
85  {
86  qDebug() << "FileSinkThread::setSamplerate:"
87  << " new:" << samplerate
88  << " old:" << m_samplerate;
89 
90  bool wasRunning = false;
91 
92  if (m_running)
93  {
94  stopWork();
95  wasRunning = true;
96  }
97 
98  // resize sample FIFO
99  if (m_sampleFifo) {
100  m_sampleFifo->resize(samplerate); // 1s buffer
101  }
102 
103  // resize output buffer
104  if (m_buf) delete[] m_buf;
105  m_buf = new int16_t[samplerate*(1<<m_log2Interpolation)*2];
106 
107  m_samplerate = samplerate;
108  m_samplesChunkSize = (m_samplerate * m_throttlems) / 1000;
109 
110  if (wasRunning) {
111  startWork();
112  }
113  }
114 }
115 
116 void FileSinkThread::setLog2Interpolation(int log2Interpolation)
117 {
118  if ((log2Interpolation < 0) || (log2Interpolation > 6))
119  {
120  return;
121  }
122 
123  if (log2Interpolation != m_log2Interpolation)
124  {
125  qDebug() << "FileSinkThread::setLog2Interpolation:"
126  << " new:" << log2Interpolation
127  << " old:" << m_log2Interpolation;
128 
129  bool wasRunning = false;
130 
131  if (m_running)
132  {
133  stopWork();
134  wasRunning = true;
135  }
136 
137  // resize output buffer
138  if (m_buf) delete[] m_buf;
139  m_buf = new int16_t[m_samplerate*(1<<log2Interpolation)*2];
140 
141  m_log2Interpolation = log2Interpolation;
142 
143  if (wasRunning) {
144  startWork();
145  }
146  }
147 }
148 
150 {
151  m_running = true;
152  m_startWaiter.wakeAll();
153 
154  while(m_running) // actual work is in the tick() function
155  {
156  sleep(1);
157  }
158 
159  m_running = false;
160 }
161 
162 void FileSinkThread::connectTimer(const QTimer& timer)
163 {
164  qDebug() << "FileSinkThread::connectTimer";
165  connect(&timer, SIGNAL(timeout()), this, SLOT(tick()));
166 }
167 
169 {
170  if (m_running)
171  {
172  qint64 throttlems = m_elapsedTimer.restart();
173 
174  if (throttlems != m_throttlems)
175  {
176  m_throttlems = throttlems;
179  }
180 
181 // if (m_throttlems > m_maxThrottlems)
182 // {
183 // qDebug("FileSinkThread::tick: m_maxThrottlems: %d", m_maxThrottlems);
184 // m_maxThrottlems = m_throttlems;
185 // }
186 
187  SampleVector::iterator readUntil;
188 
190  SampleVector::iterator beginRead = readUntil - m_samplesChunkSize;
192 
193  if (m_log2Interpolation == 0)
194  {
195  m_ofstream->write(reinterpret_cast<char*>(&(*beginRead)), m_samplesChunkSize*sizeof(Sample));
196  }
197  else
198  {
199  int chunkSize = std::min((int) m_samplesChunkSize, m_samplerate);
200 
201  switch (m_log2Interpolation)
202  {
203  case 1:
204  m_interpolators.interpolate2_cen(&beginRead, m_buf, chunkSize*(1<<m_log2Interpolation)*2);
205  break;
206  case 2:
207  m_interpolators.interpolate4_cen(&beginRead, m_buf, chunkSize*(1<<m_log2Interpolation)*2);
208  break;
209  case 3:
210  m_interpolators.interpolate8_cen(&beginRead, m_buf, chunkSize*(1<<m_log2Interpolation)*2);
211  break;
212  case 4:
213  m_interpolators.interpolate16_cen(&beginRead, m_buf, chunkSize*(1<<m_log2Interpolation)*2);
214  break;
215  case 5:
216  m_interpolators.interpolate32_cen(&beginRead, m_buf, chunkSize*(1<<m_log2Interpolation)*2);
217  break;
218  case 6:
219  m_interpolators.interpolate64_cen(&beginRead, m_buf, chunkSize*(1<<m_log2Interpolation)*2);
220  break;
221  default:
222  break;
223  }
224 
225  m_ofstream->write(reinterpret_cast<char*>(m_buf), m_samplesChunkSize*(1<<m_log2Interpolation)*2*sizeof(int16_t));
226  }
227 
228  }
229 }
short int16_t
Definition: rtptypes_win.h:43
#define FILESINK_THROTTLE_MS
void interpolate64_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void setLog2Interpolation(int log2Interpolation)
QWaitCondition m_startWaiter
volatile bool m_running
FileSinkThread(std::ofstream *samplesStream, SampleSourceFifo *sampleFifo, QObject *parent=0)
void interpolate32_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate8_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
unsigned int m_samplesChunkSize
int16_t * m_buf
void interpolate2_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void readAdvance(SampleVector::iterator &readUntil, unsigned int nbSamples)
QElapsedTimer m_elapsedTimer
void resize(uint32_t size)
SampleSourceFifo * m_sampleFifo
std::size_t m_samplesCount
Interpolators< qint16, SDR_TX_SAMP_SZ, 16 > m_interpolators
QMutex m_startWaitMutex
void interpolate16_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate4_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void connectTimer(const QTimer &timer)
std::ofstream * m_ofstream
void setSamplerate(int samplerate)
T min(const T &x, const T &y)
Definition: framework.h:440