UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
utils.cpp
Go to the documentation of this file.
1
6/*
7 * Copyright (c) 2011-2024 CESNET
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, is permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of CESNET nor the names of its contributors may be
22 * used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
27 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
29 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include "audio/utils.h"
40
41#include <algorithm>
42#include <cassert>
43#include <cctype> // for isdigit
44#include <climits>
45#include <cmath>
46#include <cstdio> // for snprintf
47#include <cstdlib> // for free, malloc, abort, atoi, abs, calloc
48#include <cstring>
49#include <memory> // for unique_ptr
50#include <ostream> // for operator<<, basic_ostream, basic_ostrea...
51#include <string> // for char_traits, basic_string, stoi, hash
52#include <unordered_map> // for operator==, unordered_map, _Node_iterat...
53#include <vector> // for vector
54
55#include "utils/color_out.h" // for color_printf, TBOLD, TERM_RESET
56#include "audio/types.h"
57#include "debug.h"
58#include "host.h" // ADD_TO_PARAM
59#include "utils/macros.h"
60#include "utils/misc.h"
61
62
63static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
64 "The code below assumes little endianness.");
65
66using std::max;
67using std::stoi;
68using std::string;
69using std::unique_ptr;
70using std::vector;
71
72static int32_t format_from_in_bps(const char *in, int bps);
73static void format_to_out_bps(char *out, int bps, int32_t out_value);
74
79template<int BPS> static int32_t load_sample(const char *data);
80
81template<> int32_t load_sample<1>(const char *data) {
82 return *reinterpret_cast<const int8_t *>(data);
83}
84
85template<> int32_t load_sample<2>(const char *data) {
86 return *reinterpret_cast<const int16_t *>(data);
87}
88
89template<> int32_t load_sample<3>(const char *data) {
90 int32_t in_value = 0;
91 memcpy(&in_value, data, 3);
92
93 if ((in_value & 1U<<23U) != 0U) { // negative
94 in_value |= 0xFF000000U;
95 }
96
97 return in_value;
98}
99
100template<> int32_t load_sample<4>(const char *data) {
101 return *reinterpret_cast<const int32_t *>(data);
102}
103
112template<int BPS>
113static double calculate_rms_helper(const char *channel_data,
114 int sample_count,
115 double *peak,
116 int sample_stride = 1)
117{
118 double sum = 0;
119 *peak = 0;
120 const int byte_stride = BPS * sample_stride;
121 for (int i = 0; i < sample_count; i += 1) {
122 double val = load_sample<BPS>(channel_data + i * byte_stride) / static_cast<double>(1U << (BPS * CHAR_BIT - 1U));
123 sum += val;
124 *peak = max(fabs(val), *peak);
125 }
126
127 double average = sum / sample_count;
128
129 double sumMeanSquare = 0.0;
130
131 for (int i = 0; i < sample_count; i += 1) {
132 sumMeanSquare += pow(load_sample<BPS>(channel_data + i * byte_stride) / static_cast<double>(1U << (BPS * CHAR_BIT - 1U))
133 - average, 2.0);
134 }
135
136 double averageMeanSquare = sumMeanSquare / sample_count;
137 double rootMeanSquare = sqrt(averageMeanSquare);
138
139 return rootMeanSquare;
140}
141
150double calculate_rms(audio_frame2 *frame, int channel, double *peak)
151{
152 assert(frame->get_codec() == AC_PCM);
153 int sample_count = frame->get_data_len(channel) / frame->get_bps();
154 switch (frame->get_bps()) {
155 case 1:
156 return calculate_rms_helper<1>(frame->get_data(channel), sample_count, peak);
157 case 2:
158 return calculate_rms_helper<2>(frame->get_data(channel), sample_count, peak);
159 case 3:
160 return calculate_rms_helper<3>(frame->get_data(channel), sample_count, peak);
161 case 4:
162 return calculate_rms_helper<4>(frame->get_data(channel), sample_count, peak);
163 default:
164 LOG(LOG_LEVEL_FATAL) << "Wrong BPS " << frame->get_bps() << "\n";
165 abort();
166 }
167}
168
169double calculate_rms(audio_frame *frame, int channel, double *peak)
170{
171 assert(channel < frame->ch_count);
172 char *data = frame->data + channel * frame->bps;
173 int sample_count = frame->data_len / frame->bps / frame->ch_count;
174 switch (frame->bps) {
175 case 1:
176 return calculate_rms_helper<1>(data, sample_count, peak, frame->ch_count);
177 case 2:
178 return calculate_rms_helper<2>(data, sample_count, peak, frame->ch_count);
179 case 3:
180 return calculate_rms_helper<3>(data, sample_count, peak, frame->ch_count);
181 case 4:
182 return calculate_rms_helper<4>(data, sample_count, peak, frame->ch_count);
183 default:
184 LOG(LOG_LEVEL_FATAL) << "Wrong BPS " << frame->bps << "\n";
185 abort();
186 }
187}
188
189bool audio_desc_eq(struct audio_desc a1, struct audio_desc a2) {
190 return a1.bps == a2.bps &&
191 a1.sample_rate == a2.sample_rate &&
192 a1.ch_count == a2.ch_count &&
193 a1.codec == a2.codec;
194}
195
197 return audio_desc { frame->bps,
198 frame->sample_rate,
199 frame->ch_count,
200 AC_PCM
201 };
202}
203
204struct audio_desc
206{
207 return audio_desc { channel->bps,
208 channel->sample_rate,
209 1,
210 channel->codec
211 };
212}
213
221{
222 f->bps = desc.bps;
223 f->sample_rate = desc.sample_rate;
224 f->ch_count = desc.ch_count;
225}
226
227int32_t downshift_with_dither(int32_t val, int shift){
228 static thread_local uint32_t last_rand = 0;
229
230 //Quick and dirty random number generation (ranqd1)
231 //Numerical Recipes in C, page 284
232 last_rand = (last_rand * 1664525) + 1013904223L;
233 int triangle_dither = last_rand >> (32 - shift);
234 last_rand = (last_rand * 1664525) + 1013904223L;
235 triangle_dither -= last_rand >> (32 - shift); //triangle probability distribution
236
237 /* Prevent over/underflow when val is big.
238 *
239 * abs(val) could cause problems if val is INT32_MIN, but integer
240 * 32-bit pcm is rare and should not contain the value INT32_MIN
241 * anyway because of symmetry, as specified by AES17 and IEC 61606-3
242 */
243 if(INT32_MAX - abs(val) < (1 << shift) - 1 + (1 << (shift - 1)))
244 return val / (1 << shift);
245
246 if(val > 0)
247 val += 1 << (shift - 1);
248 else
249 val -= 1 << (shift - 1);
250
251 return (val + triangle_dither) / (1 << shift);
252}
253
254#define NO_DITHER_PARAM "no-dither"
256 " Disable audio dithering when reducing bit depth\n");
257
258void change_bps(char *out, int out_bps, const char *in, int in_bps, int in_len /* bytes */) {
259 static const bool dither = commandline_params.find(NO_DITHER_PARAM) == commandline_params.end();
260 change_bps2(out, out_bps, in, in_bps, in_len, dither);
261}
262
263void change_bps2(char *out, int out_bps, const char *in, int in_bps, int in_len /* bytes */, bool dither)
264{
265 assert ((unsigned int) out_bps <= sizeof(int32_t));
266 static_assert(-2>>1 == -1, "Implementation-defined behavior doesn't work as expected by the implementation.");
267
268 if (in_bps == out_bps ) {
269 memcpy(out, in, in_len);
270 return;
271 }
272
273 if (in_bps < out_bps ) {
274 for (int i = 0; i < in_len / in_bps; i++) {
275 int32_t in_value = format_from_in_bps(in, in_bps);
276 int32_t out_value = in_value << (out_bps * 8 - in_bps * 8);
277 format_to_out_bps(out, out_bps, out_value);
278 in += in_bps;
279 out += out_bps;
280 }
281 return;
282 }
283
284 // downsampling
285 if (dither) {
286 const int downshift = in_bps * 8 - out_bps * 8;
287 for (int i = 0; i < in_len / in_bps; i++) {
288 int32_t in_value = format_from_in_bps(in, in_bps);
289 int32_t out_value = downshift_with_dither(in_value, downshift);
290 format_to_out_bps(out, out_bps, out_value);
291 in += in_bps;
292 out += out_bps;
293 }
294 return;
295 }
296 // no dithering
297 for (int i = 0; i < in_len / in_bps; i++) {
298 int32_t in_value = format_from_in_bps(in, in_bps);
299 int32_t out_value = in_value >> (in_bps * 8 - out_bps * 8);
300 format_to_out_bps(out, out_bps, out_value);
301 in += in_bps;
302 out += out_bps;
303 }
304}
305
306void copy_channel(char *out, const char *in, int bps, int in_len /* bytes */, int out_channel_count)
307{
308 int samples = in_len / bps;
309 int i;
310
311 assert(out_channel_count > 0);
312 assert(bps > 0);
313 assert(in_len >= 0);
314
315 in += in_len;
316 out += in_len * out_channel_count;
317 for (i = samples; i > 0 ; --i) {
318 int j;
319
320 in -= bps;
321 for (j = out_channel_count + 0; j > 0; --j) {
322 out -= bps;
323 memmove(out, in, bps);
324 }
325 }
326}
327
328void audio_frame_multiply_channel(struct audio_frame *frame, int new_channel_count) {
329 assert((unsigned int) frame->max_size >= (unsigned int) frame->data_len * new_channel_count / frame->ch_count);
330
331 copy_channel(frame->data, frame->data, frame->bps, frame->data_len, new_channel_count);
332}
333
334void demux_channel(char *out, char *in, int bps, int in_len, int in_stream_channels, int pos_in_stream)
335{
336 int samples = in_len / (in_stream_channels * bps);
337 int i;
338
339 assert (bps <= 4);
340
341 in += pos_in_stream * bps;
342
343 for (i = 0; i < samples; ++i) {
344 memcpy(out, in, bps);
345
346 out += bps;
347 in += in_stream_channels * bps;
348
349 }
350}
351
352void remux_channel(char *out, const char *in, int bps, int in_len, int in_stream_channels, int out_stream_channels, int pos_in_stream, int pos_out_stream)
353{
354 int samples = in_len / (in_stream_channels * bps);
355 int i;
356
357 assert (bps <= 4);
358
359 in += pos_in_stream * bps;
360 out += pos_out_stream * bps;
361
362 for (i = 0; i < samples; ++i) {
363 memcpy(out, in, bps);
364
365 out += bps * out_stream_channels;
366 in += bps * in_stream_channels;
367
368 }
369}
370
371void mux_channel(char *out, const char *in, int bps, int in_len, int out_stream_channels, int pos_in_stream, double scale)
372{
373 int samples = in_len / bps;
374 int i;
375
376 assert (bps <= 4);
377
378 out += pos_in_stream * bps;
379
380 if(scale == 1.0) {
381 for (i = 0; i < samples; ++i) {
382 memcpy(out, in, bps);
383
384 in += bps;
385 out += out_stream_channels * bps;
386
387 }
388 } else {
389 for (i = 0; i < samples; ++i) {
390 int32_t in_value = format_from_in_bps(in, bps);
391
392 in_value *= scale;
393
394 format_to_out_bps(out, bps, in_value);
395
396 in += bps;
397 out += out_stream_channels * bps;
398 }
399 }
400}
401
402void mux_and_mix_channel(char *out, const char *in, int bps, int in_len, int out_stream_channels, int pos_in_stream, double scale)
403{
404 int i;
405
406 assert (bps <= 4);
407
408 out += pos_in_stream * bps;
409
410 for(i = 0; i < in_len / bps; i++) {
411 int32_t in_value = format_from_in_bps(in, bps);
412 int32_t out_value = format_from_in_bps(out, bps);
413
414 int32_t new_value = (double)in_value * scale + out_value;
415
416 format_to_out_bps(out, bps, new_value);
417
418 in += bps;
419 out += out_stream_channels * bps;
420 }
421}
422
423void remux_and_mix_channel(char *out, const char *in, int bps, int frames, int in_stream_channels, int out_stream_channels, int in_channel, int out_channel, double scale)
424{
425 int i;
426
427 assert (bps <= 4);
428
429 out += out_channel * bps;
430 in += in_channel * bps;
431
432 for(i = 0; i < frames; i++) {
433 int32_t in_value = format_from_in_bps(in, bps);
434 int32_t out_value = format_from_in_bps(out, bps);
435
436 int32_t new_value = (double)in_value * scale + out_value;
437
438 format_to_out_bps(out, bps, new_value);
439
440 in += in_stream_channels * bps;
441 out += out_stream_channels * bps;
442 }
443}
444
445template<int BPS>
446static double get_avg_volume_helper(const char *data, int sample_count, int stream_channels, int pos_in_stream)
447{
448 int64_t vol = 0;
449
450 data += pos_in_stream * BPS;
451
452 for (int i = 0; i < sample_count; i++) {
453 int32_t in_value = load_sample<BPS> (data + i * BPS * stream_channels);
454
455 vol += labs(in_value);
456 }
457
458 return static_cast<double>(vol) / sample_count / ((1U << (BPS * 8U - 1U)));
459}
460
461double get_avg_volume(char *data, int bps, int sample_count, int stream_channels, int pos_in_stream) {
462 switch (bps) {
463 case 1:
464 return get_avg_volume_helper<1>(data, sample_count, stream_channels, pos_in_stream);
465 case 2:
466 return get_avg_volume_helper<2>(data, sample_count, stream_channels, pos_in_stream);
467 case 3:
468 return get_avg_volume_helper<3>(data, sample_count, stream_channels, pos_in_stream);
469 case 4:
470 return get_avg_volume_helper<4>(data, sample_count, stream_channels, pos_in_stream);
471 default:
472 LOG(LOG_LEVEL_FATAL) << "Wrong BPS " << bps << "\n";
473 abort();
474 }
475}
476
477const float INT_MAX_FLT = nexttowardf((float) INT_MAX, INT_MAX); // max int representable as float
478
482void float2int(char *out, const char *in, int len)
483{
484 const float *inf = (const float *)(const void *) in;
485 int32_t *outi = (int32_t *)(void *) out;
486 int items = len / sizeof(int32_t);
487
488 while(items-- > 0) {
489 float sample = *inf++;
490 if(sample > 1.0) sample = 1.0;
491 if(sample < -1.0) sample = -1.0;
492 *outi++ = sample * INT_MAX_FLT;
493 }
494}
495
496void int2float(char *out, const char *in, int len)
497{
498 const int32_t *ini = (const int32_t *)(const void *) in;
499 float *outf = (float *)(void *) out;
500 int items = len / sizeof(int32_t);
501
502 while(items-- > 0) {
503 *outf++ = (float) *ini++ / (float) INT_MAX;
504 }
505}
506
515void signed2unsigned(char *out, const char *in, int in_len)
516{
517 const auto *inch = reinterpret_cast<const int8_t *>(in);
518 uint8_t *outch = (uint8_t *) out;
519 int items = in_len / sizeof(int8_t);
520
521 while(items-- > 0) {
522 int8_t in_value = *inch++;
523 uint8_t out_value = (int) 128 + in_value;
524 *outch++ = out_value;
525 }
526}
527
528void audio_channel_demux(const audio_frame2 *frame, int index, audio_channel *channel)
529{
530 channel->data = frame->get_data(index);
531 channel->data_len = frame->get_data_len(index);
532 channel->codec = frame->get_codec();
533 channel->bps = frame->get_bps();
534 channel->sample_rate = frame->get_sample_rate();
535}
536
538static int32_t
539format_from_in_bps(const char *in, int bps)
540{
541 switch (bps) {
542 case 1: return load_sample<1>(in);
543 case 2: return load_sample<2>(in);
544 case 3: return load_sample<3>(in);
545 case 4: return load_sample<4>(in);
546 default: abort();
547 }
548}
549
555static void
556format_to_out_bps(char *out, int bps, int32_t out_value)
557{
558#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
559 memcpy(out, &out_value, bps);
560#else
561 memcpy(out, (char *) &out_value + 4 - bps, bps);
562#endif
563}
564
565void
566interleaved2noninterleaved2(char **out_ch, const char *in, int bps, int in_len,
567 int channel_count)
568{
569 for (int i = 0; i < in_len / channel_count / bps; ++i) {
570 for (int ch = 0; ch < channel_count; ++ch) {
571 memcpy(out_ch[ch] + (ptrdiff_t) i * bps, in, bps);
572 in += bps;
573 }
574 }
575}
576
577void
578interleaved2noninterleaved_float(char **out_ch, const char *in, int in_bps, int in_len,
579 int channel_count)
580{
581 for (int ch = 0; ch < channel_count; ++ch) {
582 assert((uintptr_t) out_ch[ch] % 4 == 0);
583 }
584 if (in_bps == 1) { // bps 1 is unsigned
585 for (int i = 0; i < in_len / channel_count; ++i) {
586 for (int ch = 0; ch < channel_count; ++ch) {
587 const int val =
588 INT8_MIN + *(const uint8_t *) in;
589 *(float *) (void *) (out_ch[ch] +
590 (ptrdiff_t) i * 4) =
591 (float) val / -INT8_MIN;
592 in++;;
593 }
594 }
595 } else {
596 for (int i = 0; i < in_len / channel_count / in_bps; ++i) {
597 for (int ch = 0; ch < channel_count; ++ch) {
598 int32_t val = 0;
599 memcpy((char *) &val + 4 - in_bps, in, in_bps);
600 *(float *) (void *) (out_ch[ch] +
601 (ptrdiff_t) i * 4) =
602 (float) val / (-1.0F * INT32_MIN);
603 in += in_bps;
604 }
605 }
606 }
607}
608
609void
610interleaved2noninterleaved(char *out, const char *in, int bps, int in_len,
611 int channel_count)
612{
613 vector<char *> out_ch(channel_count);
614 for (int i = 0; i < channel_count; ++i) {
615 out_ch[i] = out + (ptrdiff_t) in_len / channel_count * i;
616 }
617 interleaved2noninterleaved2(out_ch.data(), in, bps, in_len, channel_count);
618}
619
620bool append_audio_frame(struct audio_frame *frame, char *data, size_t data_len) {
621 bool ret = true;
622 if (frame->data_len + data_len > (size_t) frame->max_size) {
623 log_msg(LOG_LEVEL_WARNING, "Audio frame overrun, discarding some data.\n");
624 data_len = frame->max_size - frame->data_len;
625 ret = false;
626 }
627 memcpy(frame->data + frame->data_len, data, data_len);
628 frame->data_len += data_len;
629
630 return ret;
631}
632
633struct audio_frame *audio_frame_copy(const struct audio_frame *src, bool keep_size) {
634 struct audio_frame *ret = (struct audio_frame *) malloc(sizeof(struct audio_frame));
635 memcpy(ret, src, sizeof *ret);
636 if (!keep_size) {
637 ret->max_size = src->data_len;
638 }
639 ret->data = (char *) malloc(ret->max_size);
640 memcpy(ret->data, src->data, src->data_len);
641 return ret;
642}
643
645 thread_local string str = desc;
646 return str.c_str();
647}
648
655int parse_audio_format(const char *str, struct audio_desc *ret) {
656 if (strcmp(str, "help") == 0) {
657 color_printf(TBOLD("Audio format") " syntax:\n");
658 color_printf(TBOLD("\t{channels=<num>|bps=<bits_per_sample>|sample_rate=<rate>}*\n"));
659 color_printf("\t\tmultiple options can be separated by a colon\n");
660 return 1;
661 }
662
663 unique_ptr<char[]> arg_copy(new char[strlen(str) + 1]);
664 char *arg = arg_copy.get();
665 strcpy(arg, str);
666
667 char *save_ptr = nullptr;
668 char *tmp = arg;
669
670 while (char *item = strtok_r(tmp, ",:", &save_ptr)) {
671 const char *const val = strchr(item, '=') + 1;
672 if (IS_KEY_PREFIX(item, "channels")) {
673 ret->ch_count = stoi(val);
674 if (ret->ch_count < 1 ||
675 ret->ch_count > MAX_AUD_CH_COUNT) {
677 "Invalid number of channels %s! Valid "
678 "range 1-%d.\n",
680 return -1;
681 }
682 } else if (IS_KEY_PREFIX(item, "bps")) {
683 const int bps = stoi(val);
684 if (bps % 8 != 0 || bps <= 0 || bps > 32) {
685 log_msg(LOG_LEVEL_ERROR, "Invalid bps %s!\n",
686 val);
687 if (bps % 8 != 0) {
688 LOG(LOG_LEVEL_WARNING) << "bps is in bits per sample but a value not divisible by 8 was given.\n";
689 }
690 log_msg(LOG_LEVEL_ERROR, "Supported values are 8, 16, 24, or 32 bits.\n");
691 return -1;
692 }
693 ret->bps = bps / 8;
694 } else if (IS_KEY_PREFIX(item, "sample_rate")) {
695 const long long rate = unit_evaluate(val, nullptr);
696 if (rate <= 0 || rate > MAX_AUD_SAMPLE_RATE) {
698 << "Invalid sample_rate " << rate
699 << "! Valid range 1-"
700 << MAX_AUD_SAMPLE_RATE << ".\n";
701 return -1;
702 }
703 ret->sample_rate = (int) rate;
704 } else {
705 LOG(LOG_LEVEL_ERROR) << "Unkonwn option \"" << item << "\" for audio format!\n";
706 LOG(LOG_LEVEL_INFO) << "Use \"help\" keyword for syntax.!\n";
707 return -1;
708 }
709
710 tmp = nullptr;
711 }
712 return 0;
713}
714
715
716bool parse_channel_map_cfg(struct channel_map *channel_map, const char *cfg){
717 char *save_ptr = NULL;
718 char *item;
719 char *ptr;
720 char *tmp = ptr = strdup(cfg);
721
722 channel_map->size = 0;
723 while((item = strtok_r(ptr, ",", &save_ptr))) {
724 ptr = NULL;
725 // item is in format x1:y1
726 if(isdigit(item[0])) {
727 channel_map->size = std::max(channel_map->size, atoi(item) + 1);
728 }
729 }
730
731 channel_map->map = (int **) malloc(channel_map->size * sizeof(int *));
732 channel_map->sizes = (int *) malloc(channel_map->size * sizeof(int));
733
734 /* default value, do not process */
735 for(int i = 0; i < channel_map->size; ++i) {
736 channel_map->map[i] = NULL;
737 channel_map->sizes[i] = 0;
738 }
739
740 free (tmp);
741 tmp = ptr = strdup(cfg);
742
743 while((item = strtok_r(ptr, ",", &save_ptr))) {
744 ptr = NULL;
745
746 assert(strchr(item, ':') != NULL);
747 int src;
748 if(isdigit(item[0])) {
749 src = atoi(item);
750 } else {
751 src = -1;
752 }
753 if(!isdigit(strchr(item, ':')[1])) {
754 log_msg(LOG_LEVEL_ERROR, "Audio destination channel not entered!\n");
755 free(tmp);
756 return false;
757 }
758 int dst = atoi(strchr(item, ':') + 1);
759 if(src >= 0) {
760 channel_map->sizes[src] += 1;
761 if(channel_map->map[src] == NULL) {
762 channel_map->map[src] = (int *) malloc(1 * sizeof(int));
763 } else {
764 channel_map->map[src] = (int *) realloc(channel_map->map[src], channel_map->sizes[src] * sizeof(int));
765 }
766 channel_map->map[src][channel_map->sizes[src] - 1] = dst;
767 }
768 }
769
770 free(tmp);
771 tmp = NULL;
772
773 if (!channel_map->validate()) {
774 log_msg(LOG_LEVEL_ERROR, "Wrong audio mapping.\n");
775 return false;
776 }
778
779 return true;
780}
781
783 free(sizes);
784 for(int i = 0; i < size; ++i) {
785 free(map[i]);
786 }
787 free(map);
788 free(contributors);
789}
790
792 for(int i = 0; i < size; ++i) {
793 for(int j = 0; j < sizes[i]; ++j) {
794 if(map[i][j] < 0) {
795 log_msg(LOG_LEVEL_ERROR, "Audio channel mapping - negative parameter occured.\n");
796 return false;
797 }
798 }
799 }
800
801 return true;
802}
803
805 for (int i = 0; i < size; ++i) {
806 for (int j = 0; j < sizes[i]; ++j) {
807 max_output = std::max(map[i][j], max_output);
808 }
809 }
810 contributors = (int *) calloc(max_output + 1, sizeof(int));
811 for (int i = 0; i < size; ++i) {
812 for (int j = 0; j < sizes[i]; ++j) {
813 contributors[map[i][j]] += 1;
814 }
815 }
816}
817
827void
828format_audio_channel_volume(int chan_idx, double rms, double peak, const char *format_color,
829 char **volume_start, char *volume_end)
830{
831 if (chan_idx > 0) {
832 *volume_start +=
833 snprintf(*volume_start, volume_end - *volume_start, ", ");
834 }
835 const double rms_dbfs = 20.0 * log(rms) / log(10.0);
836 const double peak_dbfs = 20.0 * log(peak) / log(10.0);
837 *volume_start +=
838 snprintf(*volume_start, volume_end - *volume_start,
839 "[%d] %s%.2f" TERM_RESET "/%s%.2f" TERM_RESET, chan_idx,
840 format_color, rms_dbfs, format_color, peak_dbfs);
841}
int void * val
struct video_desc desc
struct video_frame * frame
int void size_t * len
This file contains definition of some common audio types.
@ AC_PCM
Definition types.h:53
@ MAX_AUD_CH_COUNT
Definition types.h:68
@ MAX_AUD_SAMPLE_RATE
Definition types.h:69
int color_printf(const char *format,...)
#define TERM_RESET
Definition color_out.h:47
#define TBOLD(x)
Definition color_out.h:70
static __device__ vec2 abs(const vec2 &v)
Definition cuda_dxt.cu:118
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG(level)
Definition debug.h:313
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
std::unordered_map< std::string, std::string > commandline_params
Definition host.cpp:184
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
long long unit_evaluate(const char *str, const char **endptr)
Definition misc.cpp:81
#define BPS
Definition mixer.cpp:64
#define max(a, b)
Definition rtp.c:98
Audio channel is a non-owning view on audio_frame2 isolating one channel.
Definition types.h:122
audio_codec_t codec
Definition types.h:127
const char * data
Definition types.h:125
int sample_rate
Definition types.h:124
int data_len
Definition types.h:126
int sample_rate
Definition types.h:78
int ch_count
Definition types.h:79
int bps
Definition types.h:77
audio_codec_t codec
Definition types.h:80
struct used to comunicate with audio capture/playback device
Definition types.h:99
int sample_rate
Definition types.h:101
char * data
Definition types.h:102
int ch_count
Definition types.h:104
int data_len
Definition types.h:103
int bps
Definition types.h:100
int max_size
Definition types.h:105
int * contributors
Definition utils.h:172
int max_output
Definition utils.h:174
int * sizes
Definition utils.h:171
void compute_contributors()
Definition utils.cpp:804
bool validate()
Definition utils.cpp:791
int size
Definition utils.h:173
int ** map
Definition utils.h:170
Definition hd-rum.c:27
void mux_and_mix_channel(char *out, const char *in, int bps, int in_len, int out_stream_channels, int pos_in_stream, double scale)
Definition utils.cpp:402
void copy_channel(char *out, const char *in, int bps, int in_len, int out_channel_count)
Definition utils.cpp:306
int32_t load_sample< 4 >(const char *data)
Definition utils.cpp:100
struct audio_desc audio_desc_from_frame(const struct audio_frame *frame)
Definition utils.cpp:196
int32_t load_sample< 2 >(const char *data)
Definition utils.cpp:85
void remux_and_mix_channel(char *out, const char *in, int bps, int frames, int in_stream_channels, int out_stream_channels, int in_channel, int out_channel, double scale)
Definition utils.cpp:423
bool parse_channel_map_cfg(struct channel_map *channel_map, const char *cfg)
Definition utils.cpp:716
int32_t load_sample< 3 >(const char *data)
Definition utils.cpp:89
bool audio_desc_eq(struct audio_desc a1, struct audio_desc a2)
Definition utils.cpp:189
void interleaved2noninterleaved_float(char **out_ch, const char *in, int in_bps, int in_len, int channel_count)
Definition utils.cpp:578
void signed2unsigned(char *out, const char *in, int in_len)
Definition utils.cpp:515
void audio_channel_demux(const audio_frame2 *frame, int index, audio_channel *channel)
Definition utils.cpp:528
static double get_avg_volume_helper(const char *data, int sample_count, int stream_channels, int pos_in_stream)
Definition utils.cpp:446
void float2int(char *out, const char *in, int len)
Definition utils.cpp:482
void audio_frame_write_desc(struct audio_frame *f, struct audio_desc desc)
Definition utils.cpp:220
static int32_t format_from_in_bps(const char *in, int bps)
reads sample at specified BPS and returns it in i32 container (not scaled)
Definition utils.cpp:539
bool append_audio_frame(struct audio_frame *frame, char *data, size_t data_len)
Definition utils.cpp:620
double get_avg_volume(char *data, int bps, int sample_count, int stream_channels, int pos_in_stream)
Definition utils.cpp:461
void mux_channel(char *out, const char *in, int bps, int in_len, int out_stream_channels, int pos_in_stream, double scale)
Definition utils.cpp:371
static void format_to_out_bps(char *out, int bps, int32_t out_value)
Definition utils.cpp:556
void change_bps2(char *out, int out_bps, const char *in, int in_bps, int in_len, bool dither)
changes bps with option to specify whether or not do the dithering
Definition utils.cpp:263
void interleaved2noninterleaved2(char **out_ch, const char *in, int bps, int in_len, int channel_count)
Definition utils.cpp:566
void interleaved2noninterleaved(char *out, const char *in, int bps, int in_len, int channel_count)
Definition utils.cpp:610
static double calculate_rms_helper(const char *channel_data, int sample_count, double *peak, int sample_stride=1)
Calculates mean and peak RMS from audio samples.
Definition utils.cpp:113
int32_t load_sample< 1 >(const char *data)
Definition utils.cpp:81
const float INT_MAX_FLT
Definition utils.cpp:477
void audio_frame_multiply_channel(struct audio_frame *frame, int new_channel_count)
Definition utils.cpp:328
void demux_channel(char *out, char *in, int bps, int in_len, int in_stream_channels, int pos_in_stream)
Definition utils.cpp:334
void change_bps(char *out, int out_bps, const char *in, int in_bps, int in_len)
Definition utils.cpp:258
double calculate_rms(audio_frame2 *frame, int channel, double *peak)
Calculates mean and peak RMS from audio samples.
Definition utils.cpp:150
void remux_channel(char *out, const char *in, int bps, int in_len, int in_stream_channels, int out_stream_channels, int pos_in_stream, int pos_out_stream)
Definition utils.cpp:352
int32_t downshift_with_dither(int32_t val, int shift)
Definition utils.cpp:227
void format_audio_channel_volume(int chan_idx, double rms, double peak, const char *format_color, char **volume_start, char *volume_end)
format per channel incrementally volume string (eg. "[0]-18.00/-14.99, [1] -18.00/-14....
Definition utils.cpp:828
int parse_audio_format(const char *str, struct audio_desc *ret)
Definition utils.cpp:655
struct audio_frame * audio_frame_copy(const struct audio_frame *src, bool keep_size)
Definition utils.cpp:633
void int2float(char *out, const char *in, int len)
Definition utils.cpp:496
static int32_t load_sample(const char *data)
struct audio_desc audio_desc_from_audio_channel(const audio_channel *channel)
Definition utils.cpp:205
#define NO_DITHER_PARAM
Definition utils.cpp:254
const char * audio_desc_to_cstring(struct audio_desc desc)
Definition utils.cpp:644