MythTV master
freesurround.cpp
Go to the documentation of this file.
1/*
2Copyright (C) 2007 Christian Kothe, Mark Spieth
3Copyright (C) 2010-2011 Jean-Yves Avenard
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19#include "freesurround.h"
20
21#include <algorithm>
22#include <cstdio>
23#include <cstdlib>
24#include <cerrno>
25#include <cmath>
26#include <iostream>
27#include <numbers>
28#include <sstream>
29#include <vector>
30#include <list>
31#include <map>
32
34
35#include <QString>
36
38
39// our default internal block size, in floats
40static constexpr unsigned default_block_size = SURROUND_BUFSIZE;
41// Gain of center and lfe channels in passive mode (sqrt 0.5)
42//static constexpr float center_level = 1.0F/std::numbers::sqrt2;
43static constexpr float m3db = 1.0F/std::numbers::sqrt2; // 3dB = SQRT(2)
44static constexpr float m6db = 0.5; // 6dB = SQRT(4)
45//static constexpr float m7db = 0.44721359549996; // 7dB = SQRT(5)
46
47namespace {
49}
50
51struct buffers
52{
53 explicit buffers(unsigned int s):
54 m_l(s),m_r(s),m_c(s),m_ls(s),m_rs(s),m_lfe(s), m_rls(s), m_rrs(s) { }
55 void resize(unsigned int s)
56 {
57 m_l.resize(s); m_r.resize(s); m_lfe.resize(s);
58 m_ls.resize(s); m_rs.resize(s); m_c.resize(s);
59 m_rls.resize(s); m_rrs.resize(s);
60 }
61 void clear()
62 {
63 m_l.clear(); m_r.clear(); m_lfe.clear();
64 m_ls.clear(); m_rs.clear(); m_c.clear();
65 m_rls.clear(); m_rrs.clear();
66 }
67 std::vector<float> m_l,m_r,m_c,m_ls,m_rs,m_lfe,m_cs,m_lcs,m_rcs,
68 m_rls, m_rrs; // for demultiplexing
69};
70
71//#define SPEAKERTEST
72#ifdef SPEAKERTEST
73int channel_select = -1;
74#endif
75
76FreeSurround::FreeSurround(uint srate, bool moviemode, SurroundMode smode) :
77 m_srate(srate),
78 m_surroundMode(smode)
79{
80 LOG(VB_AUDIO, LOG_DEBUG,
81 QString("FreeSurround::FreeSurround rate %1 moviemode %2")
82 .arg(srate).arg(moviemode));
83
84 if (moviemode)
85 {
89 }
90 else
91 {
94 }
95 switch (m_surroundMode)
96 {
99 break;
101 m_params.steering = 1;
103 break;
104 default:
105 break;
106 }
107
108 m_bufs = new buffers(block_size/2);
109 open();
110#ifdef SPEAKERTEST
111 channel_select++;
112 if (channel_select>=6)
113 channel_select = 0;
114 LOG(VB_AUDIO, LOG_DEBUG,
115 QString("FreeSurround::FreeSurround channel_select %1")
116 .arg(channel_select));
117#endif
118 LOG(VB_AUDIO, LOG_DEBUG, QString("FreeSurround::FreeSurround done"));
119}
120
122{
123 if (m_decoder)
124 {
129 }
130}
131
133{
134 LOG(VB_AUDIO, LOG_DEBUG, QString("FreeSurround::~FreeSurround"));
135 close();
136 delete m_bufs;
137 m_bufs = nullptr;
138 LOG(VB_AUDIO, LOG_DEBUG, QString("FreeSurround::~FreeSurround done"));
139}
140
141uint FreeSurround::putFrames(void* buffer, uint numFrames, uint numChannels)
142{
143 uint i = 0;
144 uint ic = m_inCount;
145 uint bs = block_size/2;
146 bool process = true;
147 auto *samples = (float *)buffer;
148 // demultiplex
149
150 if ((m_surroundMode != SurroundModePassive) && (ic+numFrames > bs))
151 {
152 numFrames = bs - ic;
153 }
154
155 switch (numChannels)
156 {
157 case 1:
158 switch (m_surroundMode)
159 {
162 for (i = 0; i < numFrames && ic < bs; i++,ic++)
163 {
164 // should be -7dB to keep power level the same
165 // but we bump the level a tad.
166 m_bufs->m_c[ic] = m_bufs->m_l[ic] = m_bufs->m_r[ic] = samples[i] * m6db;
167 m_bufs->m_ls[ic] = m_bufs->m_rs[ic] = m_bufs->m_c[ic];
168 }
169 process = false;
170 break;
171 default:
172 float **inputs = m_decoder->getInputBuffers();
173 float *lt = &inputs[0][ic];
174 float *rt = &inputs[1][ic];
175 for (i=0; i<numFrames; i++)
176 *lt++ = *rt++ = *samples++;
177 process = true;
178 break;
179 }
180 m_channels = 6;
181 break;
182
183 case 2:
184 switch (m_surroundMode)
185 {
187 for (i = 0; i < numFrames && ic < bs; i++,ic++)
188 {
189 float lt = *samples++;
190 float rt = *samples++;
191 m_bufs->m_l[ic] = lt;
192 m_bufs->m_lfe[ic] = m_bufs->m_c[ic] = (lt+rt) * m3db;
193 m_bufs->m_r[ic] = rt;
194 // surround channels receive out-of-phase
195 m_bufs->m_ls[ic] = (rt-lt) * 0.5F;
196 m_bufs->m_rs[ic] = (lt-rt) * 0.5F;
197 }
198 process = false;
199 break;
201 for (i = 0; i < numFrames && ic < bs; i++,ic++)
202 {
203 float lt = *samples++;
204 float rt = *samples++;
205 m_bufs->m_l[ic] = lt * m3db;
206 m_bufs->m_lfe[ic] = m_bufs->m_c[ic] = (lt+rt) * m3db;
207 m_bufs->m_r[ic] = rt * m3db;
208 m_bufs->m_ls[ic] = m_bufs->m_l[ic];
209 m_bufs->m_rs[ic] = m_bufs->m_r[ic];
210 }
211 process = false;
212 break;
213 default:
214 float **inputs = m_decoder->getInputBuffers();
215 float *lt = &inputs[0][ic];
216 float *rt = &inputs[1][ic];
217 for (i=0; i<numFrames; i++)
218 {
219 *lt++ = *samples++;
220 *rt++ = *samples++;
221 }
222 process = true;
223 break;
224 }
225 m_channels = 6;
226 break;
227
228 case 5:
229 for (i = 0; i < numFrames && ic < bs; i++,ic++)
230 {
231 float lt = *samples++;
232 float rt = *samples++;
233 float c = *samples++;
234 float ls = *samples++;
235 float rs = *samples++;
236 m_bufs->m_l[ic] = lt;
237 m_bufs->m_lfe[ic] = 0.0F;
238 m_bufs->m_c[ic] = c;
239 m_bufs->m_r[ic] = rt;
240 m_bufs->m_ls[ic] = ls;
241 m_bufs->m_rs[ic] = rs;
242 }
243 process = false;
244 m_channels = 6;
245 break;
246
247 case 7:
248 for (i = 0; i < numFrames && ic < bs; i++,ic++)
249 {
250 // 3F3R-LFE L R C LFE BC LS RS
251 float lt = *samples++;
252 float rt = *samples++;
253 float c = *samples++;
254 float lfe = *samples++;
255 float cs = *samples++;
256 float ls = *samples++;
257 float rs = *samples++;
258 m_bufs->m_l[ic] = lt;
259 m_bufs->m_lfe[ic] = lfe;
260 m_bufs->m_c[ic] = c;
261 m_bufs->m_r[ic] = rt;
262 m_bufs->m_ls[ic] = ls;
263 m_bufs->m_rs[ic] = rs;
264 m_bufs->m_rls[ic] = m_bufs->m_rrs[ic] = cs * m3db;
265 }
266 process = false;
267 m_channels = 8;
268 break;
269 default:
270 break;
271 }
272 if (process)
273 {
274 ic += numFrames;
275 if (ic != bs)
276 {
277 // dont modify unless no processing is to be done
278 // for audiotime consistency
279 m_inCount = ic;
280 }
281 else
282 {
283 m_processed = process;
284 // process_block takes some time so dont update in and out count
285 // before its finished so that Audiotime is correctly calculated
287 m_inCount = 0;
288 m_outCount = bs;
289 m_processedSize = bs;
291 }
292 }
293 else
294 {
295 m_inCount = 0;
297 m_processed = false;
298 m_latencyFrames = 0;
299 }
300
301 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_DEBUG,
302 QString("FreeSurround::putFrames %1 #ch %2 used %3 generated %4")
303 .arg(numFrames).arg(numChannels).arg(i).arg(m_outCount));
304
305 return i;
306}
307
308uint FreeSurround::receiveFrames(void *buffer, uint maxFrames)
309{
310 uint oc = m_outCount;
311 maxFrames = std::min(maxFrames, oc);
312 uint outindex = m_processedSize - oc;
313 auto *output = (float *)buffer;
314 if (m_channels == 8)
315 {
316 float *l = &m_bufs->m_l[outindex];
317 float *c = &m_bufs->m_c[outindex];
318 float *r = &m_bufs->m_r[outindex];
319 float *ls = &m_bufs->m_ls[outindex];
320 float *rs = &m_bufs->m_rs[outindex];
321 float *lfe = &m_bufs->m_lfe[outindex];
322 float *rls = &m_bufs->m_rls[outindex];
323 float *rrs = &m_bufs->m_rrs[outindex];
324 for (uint i = 0; i < maxFrames; i++)
325 {
326// printf("1:%f 2:%f 3:%f 4:%f 5:%f 6:%f 7:%f 8:%f\n",
327// *l, *r, *c, *lfe, *rls, *rrs, *ls, *rs);
328
329 // 3F4-LFE L R C LFE Rls Rrs LS RS
330 *output++ = *l++;
331 *output++ = *r++;
332 *output++ = *c++;
333 *output++ = *lfe++;
334 *output++ = *rls++;
335 *output++ = *rrs++;
336 *output++ = *ls++;
337 *output++ = *rs++;
338 }
339 oc -= maxFrames;
340 }
341 else // channels == 6
342 {
343 if (m_processed)
344 {
345 float** outputs = m_decoder->getOutputBuffers();
346 float *l = &outputs[0][outindex];
347 float *c = &outputs[1][outindex];
348 float *r = &outputs[2][outindex];
349 float *ls = &outputs[3][outindex];
350 float *rs = &outputs[4][outindex];
351 float *lfe = &outputs[5][outindex];
352 for (uint i = 0; i < maxFrames; i++)
353 {
354 *output++ = *l++;
355 *output++ = *r++;
356 *output++ = *c++;
357 *output++ = *lfe++;
358 *output++ = *ls++;
359 *output++ = *rs++;
360 }
361 oc -= maxFrames;
362 }
363 else
364 {
365 float *l = &m_bufs->m_l[outindex];
366 float *c = &m_bufs->m_c[outindex];
367 float *r = &m_bufs->m_r[outindex];
368 float *ls = &m_bufs->m_ls[outindex];
369 float *rs = &m_bufs->m_rs[outindex];
370 float *lfe = &m_bufs->m_lfe[outindex];
371 for (uint i = 0; i < maxFrames; i++)
372 {
373 *output++ = *l++;
374 *output++ = *r++;
375 *output++ = *c++;
376 *output++ = *lfe++;
377 *output++ = *ls++;
378 *output++ = *rs++;
379 }
380 oc -= maxFrames;
381 }
382 }
383 m_outCount = oc;
384 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_DEBUG,
385 QString("FreeSurround::receiveFrames %1").arg(maxFrames));
386 return maxFrames;
387}
388
390{
391 // process the data
392 try
393 {
394 if (m_decoder)
395 {
397 }
398 }
399 catch(const std::exception& ex)
400 {
401 LOG(VB_AUDIO, LOG_DEBUG,
402 QString("FreeSurround::process_block exception: %1").arg(ex.what()));
403 }
404 catch(...)
405 {
406 LOG(VB_AUDIO, LOG_DEBUG,
407 QString("FreeSurround::process_block exception: unknown"));
408 }
409}
410
412{
413 // returns in usec
414 if (m_latencyFrames == 0)
415 return 0;
416 if (m_decoder == nullptr)
417 return 0;
418 return ((m_latencyFrames + m_inCount) * 1000000LL) / (2LL * m_srate);
419}
420
422{
423 if (m_decoder)
424 m_decoder->flush();
425 m_bufs->clear();
426}
427
428// load the lib and initialize the interface
430{
431 if (!m_decoder)
432 {
434 m_decoder->flush();
435 if (m_bufs)
436 m_bufs->clear();
438 }
439 SetParams();
440}
441
443{
444 delete m_decoder;
445 m_decoder = nullptr;
446}
447
449{
450 return m_inCount;
451}
452
454{
455 return m_outCount;
456}
457
459{
460 if (m_processed)
461 return m_inCount + m_outCount + (block_size/2);
462 return m_inCount + m_outCount;
463}
464
466{
467 return block_size/2;
468}
469
int m_processedSize
Definition: freesurround.h:87
void process_block()
uint frameLatency() const
@ SurroundModeActiveSimple
Definition: freesurround.h:35
@ SurroundModeActiveLinear
Definition: freesurround.h:36
@ SurroundModePassiveHall
Definition: freesurround.h:37
int m_latencyFrames
Definition: freesurround.h:89
uint numFrames() const
static uint framesPerBlock()
SurroundMode m_surroundMode
Definition: freesurround.h:88
struct FreeSurround::fsurround_params m_params
uint receiveFrames(void *buffer, uint maxFrames)
long long getLatency()
struct buffers * m_bufs
Definition: freesurround.h:82
class fsurround_decoder * m_decoder
Definition: freesurround.h:83
FreeSurround(uint srate, bool moviemode, SurroundMode mode)
uint numUnprocessedFrames() const
bool m_processed
Definition: freesurround.h:86
uint putFrames(void *buffer, uint numFrames, uint numChannels)
void steering_mode(bool mode)
void decode(float center_width=1, float dimension=0, float adaption_rate=1)
void separation(float front, float rear)
void surround_coefficients(float a, float b)
void sample_rate(unsigned int samplerate)
void phase_mode(unsigned mode)
unsigned int uint
Definition: compat.h:60
static const std::array< const uint64_t, 4 > samples
Definition: element.cpp:46
static constexpr unsigned default_block_size
static constexpr float m6db
static constexpr float m3db
static constexpr uint16_t SURROUND_BUFSIZE
Definition: freesurround.h:27
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
std::vector< float > m_ls
std::vector< float > m_rcs
std::vector< float > m_cs
std::vector< float > m_lfe
std::vector< float > m_c
std::vector< float > m_r
std::vector< float > m_l
std::vector< float > m_rrs
std::vector< float > m_lcs
void clear()
std::vector< float > m_rs
void resize(unsigned int s)
std::vector< float > m_rls
buffers(unsigned int s)
#define output