Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as published
8 : : by the Free Software Foundation; either version 2.1 of the License,
9 : : or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public License
17 : : along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <stdio.h>
27 : : #include <string.h>
28 : : #include <math.h>
29 : :
30 : : #include <pulsecore/core-util.h>
31 : : #include <pulsecore/i18n.h>
32 : : #include <pulsecore/macro.h>
33 : : #include <pulsecore/sample-util.h>
34 : :
35 : : #include "volume.h"
36 : :
37 : 0 : int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) {
38 : : int i;
39 [ # # ]: 0 : pa_assert(a);
40 [ # # ]: 0 : pa_assert(b);
41 : :
42 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), 0);
43 : :
44 [ # # ]: 0 : if (PA_UNLIKELY(a == b))
45 : : return 1;
46 : :
47 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(b), 0);
48 : :
49 [ # # ]: 0 : if (a->channels != b->channels)
50 : : return 0;
51 : :
52 [ # # ]: 0 : for (i = 0; i < a->channels; i++)
53 [ # # ]: 0 : if (a->values[i] != b->values[i])
54 : : return 0;
55 : :
56 : : return 1;
57 : : }
58 : :
59 : 0 : pa_cvolume* pa_cvolume_init(pa_cvolume *a) {
60 : : unsigned c;
61 : :
62 [ # # ]: 0 : pa_assert(a);
63 : :
64 : 0 : a->channels = 0;
65 : :
66 [ # # ]: 0 : for (c = 0; c < PA_CHANNELS_MAX; c++)
67 : 0 : a->values[c] = PA_VOLUME_INVALID;
68 : :
69 : 0 : return a;
70 : : }
71 : :
72 : 526 : pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) {
73 : : int i;
74 : :
75 [ - + ]: 526 : pa_assert(a);
76 [ - + ]: 526 : pa_assert(channels > 0);
77 [ - + ]: 526 : pa_assert(channels <= PA_CHANNELS_MAX);
78 : :
79 : 526 : a->channels = (uint8_t) channels;
80 : :
81 [ + + ]: 1565 : for (i = 0; i < a->channels; i++)
82 : : /* Clamp in case there is stale data that exceeds the current
83 : : * PA_VOLUME_MAX */
84 [ + - ]: 1039 : a->values[i] = PA_CLAMP_VOLUME(v);
85 : :
86 : 526 : return a;
87 : : }
88 : :
89 : 0 : pa_volume_t pa_cvolume_avg(const pa_cvolume *a) {
90 : 0 : uint64_t sum = 0;
91 : : unsigned c;
92 : :
93 [ # # ]: 0 : pa_assert(a);
94 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
95 : :
96 [ # # ]: 0 : for (c = 0; c < a->channels; c++)
97 : 0 : sum += a->values[c];
98 : :
99 : 0 : sum /= a->channels;
100 : :
101 : 0 : return (pa_volume_t) sum;
102 : : }
103 : :
104 : 0 : pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
105 : 0 : uint64_t sum = 0;
106 : : unsigned c, n;
107 : :
108 [ # # ]: 0 : pa_assert(a);
109 : :
110 [ # # ]: 0 : if (!cm)
111 : 0 : return pa_cvolume_avg(a);
112 : :
113 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
114 : :
115 [ # # ]: 0 : for (c = n = 0; c < a->channels; c++) {
116 : :
117 [ # # ]: 0 : if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
118 : 0 : continue;
119 : :
120 : 0 : sum += a->values[c];
121 : 0 : n ++;
122 : : }
123 : :
124 [ # # ]: 0 : if (n > 0)
125 : 0 : sum /= n;
126 : :
127 : 0 : return (pa_volume_t) sum;
128 : : }
129 : :
130 : 0 : pa_volume_t pa_cvolume_max(const pa_cvolume *a) {
131 : 0 : pa_volume_t m = PA_VOLUME_MUTED;
132 : : unsigned c;
133 : :
134 [ # # ]: 0 : pa_assert(a);
135 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
136 : :
137 [ # # ]: 0 : for (c = 0; c < a->channels; c++)
138 [ # # ]: 0 : if (a->values[c] > m)
139 : 0 : m = a->values[c];
140 : :
141 : : return m;
142 : : }
143 : :
144 : 0 : pa_volume_t pa_cvolume_min(const pa_cvolume *a) {
145 : 0 : pa_volume_t m = PA_VOLUME_MAX;
146 : : unsigned c;
147 : :
148 [ # # ]: 0 : pa_assert(a);
149 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
150 : :
151 [ # # ]: 0 : for (c = 0; c < a->channels; c++)
152 [ # # ]: 0 : if (a->values[c] < m)
153 : 0 : m = a->values[c];
154 : :
155 : : return m;
156 : : }
157 : :
158 : 0 : pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
159 : 0 : pa_volume_t m = PA_VOLUME_MUTED;
160 : : unsigned c;
161 : :
162 [ # # ]: 0 : pa_assert(a);
163 : :
164 [ # # ]: 0 : if (!cm)
165 : 0 : return pa_cvolume_max(a);
166 : :
167 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
168 : :
169 [ # # ]: 0 : for (c = 0; c < a->channels; c++) {
170 : :
171 [ # # ]: 0 : if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
172 : 0 : continue;
173 : :
174 [ # # ]: 0 : if (a->values[c] > m)
175 : 0 : m = a->values[c];
176 : : }
177 : :
178 : : return m;
179 : : }
180 : :
181 : 0 : pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
182 : 0 : pa_volume_t m = PA_VOLUME_MAX;
183 : : unsigned c;
184 : :
185 [ # # ]: 0 : pa_assert(a);
186 : :
187 [ # # ]: 0 : if (!cm)
188 : 0 : return pa_cvolume_min(a);
189 : :
190 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
191 : :
192 [ # # ]: 0 : for (c = 0; c < a->channels; c++) {
193 : :
194 [ # # ]: 0 : if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
195 : 0 : continue;
196 : :
197 [ # # ]: 0 : if (a->values[c] < m)
198 : 0 : m = a->values[c];
199 : : }
200 : :
201 : : return m;
202 : : }
203 : :
204 : 9109053 : pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
205 : :
206 [ - + ]: 9109053 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID);
207 [ - + ]: 9109053 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID);
208 : :
209 : : /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */
210 : :
211 [ + - ]: 9109053 : return (pa_volume_t) PA_CLAMP_VOLUME((((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM));
212 : : }
213 : :
214 : 0 : pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) {
215 : :
216 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID);
217 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID);
218 : :
219 [ # # ]: 0 : if (b <= PA_VOLUME_MUTED)
220 : : return 0;
221 : :
222 : 0 : return (pa_volume_t) (((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b);
223 : : }
224 : :
225 : : /* Amplitude, not power */
226 : : static double linear_to_dB(double v) {
227 : 9110588 : return 20.0 * log10(v);
228 : : }
229 : :
230 : : static double dB_to_linear(double v) {
231 : 9106022 : return pow(10.0, v / 20.0);
232 : : }
233 : :
234 : 9112137 : pa_volume_t pa_sw_volume_from_dB(double dB) {
235 [ + + ][ + - ]: 9112137 : if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY)
236 : : return PA_VOLUME_MUTED;
237 : :
238 : 9112137 : return pa_sw_volume_from_linear(dB_to_linear(dB));
239 : : }
240 : :
241 : 9113163 : double pa_sw_volume_to_dB(pa_volume_t v) {
242 : :
243 [ - + ]: 9113163 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY);
244 : :
245 [ + + ]: 9113163 : if (v <= PA_VOLUME_MUTED)
246 : : return PA_DECIBEL_MININFTY;
247 : :
248 : 9113163 : return linear_to_dB(pa_sw_volume_to_linear(v));
249 : : }
250 : :
251 : 18218160 : pa_volume_t pa_sw_volume_from_linear(double v) {
252 : :
253 [ + + ]: 18218160 : if (v <= 0.0)
254 : : return PA_VOLUME_MUTED;
255 : :
256 : : /*
257 : : * We use a cubic mapping here, as suggested and discussed here:
258 : : *
259 : : * http://www.robotplanet.dk/audio/audio_gui_design/
260 : : * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151
261 : : *
262 : : * We make sure that the conversion to linear and back yields the
263 : : * same volume value! That's why we need the lround() below!
264 : : */
265 : :
266 [ + - ]: 18218160 : return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM));
267 : : }
268 : :
269 : 18222778 : double pa_sw_volume_to_linear(pa_volume_t v) {
270 : : double f;
271 : :
272 [ - + ]: 18222778 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0);
273 : :
274 [ + + ]: 18222778 : if (v <= PA_VOLUME_MUTED)
275 : : return 0.0;
276 : :
277 [ + + ]: 18220205 : if (v == PA_VOLUME_NORM)
278 : : return 1.0;
279 : :
280 : 18220162 : f = ((double) v / PA_VOLUME_NORM);
281 : :
282 : 18222778 : return f*f*f;
283 : : }
284 : :
285 : 24834 : char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) {
286 : : unsigned channel;
287 : 24834 : pa_bool_t first = TRUE;
288 : : char *e;
289 : :
290 [ - + ]: 24834 : pa_assert(s);
291 [ - + ]: 24834 : pa_assert(l > 0);
292 [ - + ]: 24834 : pa_assert(c);
293 : :
294 : 24834 : pa_init_i18n();
295 : :
296 [ - + ]: 24834 : if (!pa_cvolume_valid(c)) {
297 : 0 : pa_snprintf(s, l, _("(invalid)"));
298 : 0 : return s;
299 : : }
300 : :
301 : 24834 : *(e = s) = 0;
302 : :
303 [ + + ]: 74502 : for (channel = 0; channel < c->channels && l > 1; channel++) {
304 [ + + ]: 49668 : l -= pa_snprintf(e, l, "%s%u: %3u%%",
305 : : first ? "" : " ",
306 : : channel,
307 : 49668 : (c->values[channel]*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM);
308 : :
309 : 49668 : e = strchr(e, 0);
310 : 49668 : first = FALSE;
311 : : }
312 : :
313 : : return s;
314 : : }
315 : :
316 : 0 : char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) {
317 [ # # ]: 0 : pa_assert(s);
318 [ # # ]: 0 : pa_assert(l > 0);
319 : :
320 : 0 : pa_init_i18n();
321 : :
322 [ # # ]: 0 : if (!PA_VOLUME_IS_VALID(v)) {
323 : 0 : pa_snprintf(s, l, _("(invalid)"));
324 : 0 : return s;
325 : : }
326 : :
327 : 0 : pa_snprintf(s, l, "%3u%%", (v*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM);
328 : 0 : return s;
329 : : }
330 : :
331 : 513 : char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) {
332 : : unsigned channel;
333 : 513 : pa_bool_t first = TRUE;
334 : : char *e;
335 : :
336 [ - + ]: 513 : pa_assert(s);
337 [ - + ]: 513 : pa_assert(l > 0);
338 [ - + ]: 513 : pa_assert(c);
339 : :
340 : 513 : pa_init_i18n();
341 : :
342 [ - + ]: 513 : if (!pa_cvolume_valid(c)) {
343 : 0 : pa_snprintf(s, l, _("(invalid)"));
344 : 0 : return s;
345 : : }
346 : :
347 : 513 : *(e = s) = 0;
348 : :
349 [ + + ]: 1539 : for (channel = 0; channel < c->channels && l > 1; channel++) {
350 : 1026 : double f = pa_sw_volume_to_dB(c->values[channel]);
351 : :
352 [ + + ][ + + ]: 2050 : l -= pa_snprintf(e, l, "%s%u: %0.2f dB",
353 : : first ? "" : " ",
354 : : channel,
355 [ + - ]: 2050 : isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
356 : :
357 : 1026 : e = strchr(e, 0);
358 : 1026 : first = FALSE;
359 : : }
360 : :
361 : : return s;
362 : : }
363 : :
364 : 0 : char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) {
365 : : double f;
366 : :
367 [ # # ]: 0 : pa_assert(s);
368 [ # # ]: 0 : pa_assert(l > 0);
369 : :
370 : 0 : pa_init_i18n();
371 : :
372 [ # # ]: 0 : if (!PA_VOLUME_IS_VALID(v)) {
373 : 0 : pa_snprintf(s, l, _("(invalid)"));
374 : 0 : return s;
375 : : }
376 : :
377 : 0 : f = pa_sw_volume_to_dB(v);
378 [ # # ][ # # ]: 0 : pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
379 : :
380 : 0 : return s;
381 : : }
382 : :
383 : 39 : int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
384 : : unsigned c;
385 [ - + ]: 39 : pa_assert(a);
386 : :
387 [ - + ]: 39 : pa_return_val_if_fail(pa_cvolume_valid(a), 0);
388 [ + - ]: 39 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0);
389 : :
390 [ + - ]: 78 : for (c = 0; c < a->channels; c++)
391 [ - + ]: 39 : if (a->values[c] != v)
392 : : return 0;
393 : :
394 : : return 1;
395 : : }
396 : :
397 : 0 : pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
398 : : unsigned i;
399 : :
400 [ # # ]: 0 : pa_assert(dest);
401 [ # # ]: 0 : pa_assert(a);
402 [ # # ]: 0 : pa_assert(b);
403 : :
404 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
405 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
406 : :
407 [ # # ][ # # ]: 0 : for (i = 0; i < a->channels && i < b->channels; i++)
408 : 0 : dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
409 : :
410 : 0 : dest->channels = (uint8_t) i;
411 : :
412 : 0 : return dest;
413 : : }
414 : :
415 : 0 : pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
416 : : unsigned i;
417 : :
418 [ # # ]: 0 : pa_assert(dest);
419 [ # # ]: 0 : pa_assert(a);
420 : :
421 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
422 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL);
423 : :
424 [ # # ]: 0 : for (i = 0; i < a->channels; i++)
425 : 0 : dest->values[i] = pa_sw_volume_multiply(a->values[i], b);
426 : :
427 : 0 : dest->channels = (uint8_t) i;
428 : :
429 : 0 : return dest;
430 : : }
431 : :
432 : 0 : pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
433 : : unsigned i;
434 : :
435 [ # # ]: 0 : pa_assert(dest);
436 [ # # ]: 0 : pa_assert(a);
437 [ # # ]: 0 : pa_assert(b);
438 : :
439 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
440 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
441 : :
442 [ # # ][ # # ]: 0 : for (i = 0; i < a->channels && i < b->channels; i++)
443 : 0 : dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
444 : :
445 : 0 : dest->channels = (uint8_t) i;
446 : :
447 : 0 : return dest;
448 : : }
449 : :
450 : 0 : pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
451 : : unsigned i;
452 : :
453 [ # # ]: 0 : pa_assert(dest);
454 [ # # ]: 0 : pa_assert(a);
455 : :
456 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
457 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL);
458 : :
459 [ # # ]: 0 : for (i = 0; i < a->channels; i++)
460 : 0 : dest->values[i] = pa_sw_volume_divide(a->values[i], b);
461 : :
462 : 0 : dest->channels = (uint8_t) i;
463 : :
464 : 0 : return dest;
465 : : }
466 : :
467 : 61323 : int pa_cvolume_valid(const pa_cvolume *v) {
468 : : unsigned c;
469 : :
470 [ - + ]: 61323 : pa_assert(v);
471 : :
472 [ + - ]: 61323 : if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX)
473 : : return 0;
474 : :
475 [ + + ]: 183930 : for (c = 0; c < v->channels; c++)
476 [ + - ]: 122607 : if (!PA_VOLUME_IS_VALID(v->values[c]))
477 : : return 0;
478 : :
479 : : return 1;
480 : : }
481 : :
482 : : static pa_bool_t on_left(pa_channel_position_t p) {
483 : 95106 : return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
484 : : }
485 : :
486 : : static pa_bool_t on_right(pa_channel_position_t p) {
487 : 47553 : return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
488 : : }
489 : :
490 : : static pa_bool_t on_center(pa_channel_position_t p) {
491 : 0 : return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
492 : : }
493 : :
494 : : static pa_bool_t on_lfe(pa_channel_position_t p) {
495 : : return p == PA_CHANNEL_POSITION_LFE;
496 : : }
497 : :
498 : : static pa_bool_t on_front(pa_channel_position_t p) {
499 : 0 : return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
500 : : }
501 : :
502 : : static pa_bool_t on_rear(pa_channel_position_t p) {
503 : 0 : return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
504 : : }
505 : :
506 : 0 : pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) {
507 : : int a, b;
508 : : pa_cvolume result;
509 : :
510 [ # # ]: 0 : pa_assert(v);
511 [ # # ]: 0 : pa_assert(from);
512 [ # # ]: 0 : pa_assert(to);
513 : :
514 [ # # ]: 0 : pa_return_val_if_fail(pa_channel_map_valid(to), NULL);
515 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
516 : :
517 [ # # ]: 0 : if (pa_channel_map_equal(from, to))
518 : : return v;
519 : :
520 : 0 : result.channels = to->channels;
521 : :
522 [ # # ]: 0 : for (b = 0; b < to->channels; b++) {
523 : : pa_volume_t k = 0;
524 : : int n = 0;
525 : :
526 [ # # ]: 0 : for (a = 0; a < from->channels; a++)
527 [ # # ]: 0 : if (from->map[a] == to->map[b]) {
528 : 0 : k += v->values[a];
529 : 0 : n ++;
530 : : }
531 : :
532 [ # # ]: 0 : if (n <= 0) {
533 [ # # ]: 0 : for (a = 0; a < from->channels; a++)
534 [ # # ][ # # ]: 0 : if ((on_left(from->map[a]) && on_left(to->map[b])) ||
[ # # ]
535 [ # # ][ # # ]: 0 : (on_right(from->map[a]) && on_right(to->map[b])) ||
536 [ # # ][ # # ]: 0 : (on_center(from->map[a]) && on_center(to->map[b])) ||
537 [ # # ]: 0 : (on_lfe(from->map[a]) && on_lfe(to->map[b]))) {
538 : :
539 : 0 : k += v->values[a];
540 : 0 : n ++;
541 : : }
542 : : }
543 : :
544 [ # # ]: 0 : if (n <= 0)
545 : 0 : k = pa_cvolume_avg(v);
546 : : else
547 : 0 : k /= n;
548 : :
549 : 0 : result.values[b] = k;
550 : : }
551 : :
552 : 0 : *v = result;
553 : 0 : return v;
554 : : }
555 : :
556 : 0 : int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) {
557 : :
558 [ # # ]: 0 : pa_assert(v);
559 [ # # ]: 0 : pa_assert(ss);
560 : :
561 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(v), 0);
562 [ # # ]: 0 : pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
563 : :
564 : 0 : return v->channels == ss->channels;
565 : : }
566 : :
567 : 35937 : int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) {
568 [ - + ]: 35937 : pa_assert(v);
569 [ - + ]: 35937 : pa_assert(cm);
570 : :
571 [ - + ]: 35937 : pa_return_val_if_fail(pa_cvolume_valid(v), 0);
572 [ - + ]: 35937 : pa_return_val_if_fail(pa_channel_map_valid(cm), 0);
573 : :
574 : 35937 : return v->channels == cm->channels;
575 : : }
576 : :
577 : 35937 : static void get_avg_lr(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r) {
578 : : int c;
579 : 35937 : pa_volume_t left = 0, right = 0;
580 : 35937 : unsigned n_left = 0, n_right = 0;
581 : :
582 [ - + ]: 35937 : pa_assert(v);
583 [ - + ]: 35937 : pa_assert(map);
584 [ - + ]: 35937 : pa_assert(map->channels == v->channels);
585 [ - + ]: 35937 : pa_assert(l);
586 [ + - ]: 35937 : pa_assert(r);
587 : :
588 [ + + ]: 107811 : for (c = 0; c < map->channels; c++) {
589 [ + + ]: 71874 : if (on_left(map->map[c])) {
590 : 35937 : left += v->values[c];
591 : 35937 : n_left++;
592 [ + - ]: 35937 : } else if (on_right(map->map[c])) {
593 : 35937 : right += v->values[c];
594 : 35937 : n_right++;
595 : : }
596 : : }
597 : :
598 [ - + ]: 35937 : if (n_left <= 0)
599 : 0 : *l = PA_VOLUME_NORM;
600 : : else
601 : 35937 : *l = left / n_left;
602 : :
603 [ - + ]: 35937 : if (n_right <= 0)
604 : 0 : *r = PA_VOLUME_NORM;
605 : : else
606 : 35937 : *r = right / n_right;
607 : 35937 : }
608 : :
609 : 24321 : float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) {
610 : : pa_volume_t left, right;
611 : :
612 [ - + ]: 24321 : pa_assert(v);
613 [ - + ]: 24321 : pa_assert(map);
614 : :
615 [ - + ]: 24321 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
616 : :
617 [ + - ]: 24321 : if (!pa_channel_map_can_balance(map))
618 : : return 0.0f;
619 : :
620 : 24321 : get_avg_lr(map, v, &left, &right);
621 : :
622 [ + + ]: 24321 : if (left == right)
623 : : return 0.0f;
624 : :
625 : : /* 1.0, 0.0 => -1.0
626 : : 0.0, 1.0 => 1.0
627 : : 0.0, 0.0 => 0.0
628 : : 0.5, 0.5 => 0.0
629 : : 1.0, 0.5 => -0.5
630 : : 1.0, 0.25 => -0.75
631 : : 0.75, 0.25 => -0.66
632 : : 0.5, 0.25 => -0.5 */
633 : :
634 [ + + ]: 22880 : if (left > right)
635 : 11616 : return -1.0f + ((float) right / (float) left);
636 : : else
637 : 24321 : return 1.0f - ((float) left / (float) right);
638 : : }
639 : :
640 : 11616 : pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
641 : : pa_volume_t left, nleft, right, nright, m;
642 : : unsigned c;
643 : :
644 [ - + ]: 11616 : pa_assert(map);
645 [ - + ]: 11616 : pa_assert(v);
646 : :
647 [ - + ]: 11616 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
648 [ - + ]: 11616 : pa_return_val_if_fail(new_balance >= -1.0f, NULL);
649 [ - + ]: 11616 : pa_return_val_if_fail(new_balance <= 1.0f, NULL);
650 : :
651 [ + - ]: 11616 : if (!pa_channel_map_can_balance(map))
652 : : return v;
653 : :
654 : 11616 : get_avg_lr(map, v, &left, &right);
655 : :
656 : 11616 : m = PA_MAX(left, right);
657 : :
658 [ + + ]: 11616 : if (new_balance <= 0) {
659 : 6336 : nright = (new_balance + 1.0f) * m;
660 : 6336 : nleft = m;
661 : : } else {
662 : 5280 : nleft = (1.0f - new_balance) * m;
663 : 5280 : nright = m;
664 : : }
665 : :
666 [ + + ]: 34848 : for (c = 0; c < map->channels; c++) {
667 [ + + ]: 23232 : if (on_left(map->map[c])) {
668 [ - + ]: 11616 : if (left == 0)
669 : 0 : v->values[c] = nleft;
670 : : else
671 [ + - ]: 11616 : v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left);
672 [ + - ]: 11616 : } else if (on_right(map->map[c])) {
673 [ + + ]: 11616 : if (right == 0)
674 : 352 : v->values[c] = nright;
675 : : else
676 [ + - ]: 11264 : v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right);
677 : : }
678 : : }
679 : :
680 : : return v;
681 : : }
682 : :
683 : 0 : pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) {
684 : : unsigned c;
685 : 0 : pa_volume_t t = 0;
686 : :
687 [ # # ]: 0 : pa_assert(v);
688 : :
689 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
690 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
691 : :
692 : 0 : t = pa_cvolume_max(v);
693 : :
694 [ # # ]: 0 : if (t <= PA_VOLUME_MUTED)
695 : 0 : return pa_cvolume_set(v, v->channels, max);
696 : :
697 [ # # ]: 0 : for (c = 0; c < v->channels; c++)
698 [ # # ]: 0 : v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
699 : :
700 : : return v;
701 : : }
702 : :
703 : 0 : pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) {
704 : : unsigned c;
705 : 0 : pa_volume_t t = 0;
706 : :
707 [ # # ]: 0 : pa_assert(v);
708 : :
709 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
710 : :
711 [ # # ]: 0 : if (!cm)
712 : 0 : return pa_cvolume_scale(v, max);
713 : :
714 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL);
715 : :
716 : 0 : t = pa_cvolume_max_mask(v, cm, mask);
717 : :
718 [ # # ]: 0 : if (t <= PA_VOLUME_MUTED)
719 : 0 : return pa_cvolume_set(v, v->channels, max);
720 : :
721 [ # # ]: 0 : for (c = 0; c < v->channels; c++)
722 [ # # ]: 0 : v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
723 : :
724 : : return v;
725 : : }
726 : :
727 : 0 : static void get_avg_fr(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *f, pa_volume_t *r) {
728 : : int c;
729 : 0 : pa_volume_t front = 0, rear = 0;
730 : 0 : unsigned n_front = 0, n_rear = 0;
731 : :
732 [ # # ]: 0 : pa_assert(v);
733 [ # # ]: 0 : pa_assert(map);
734 [ # # ]: 0 : pa_assert(map->channels == v->channels);
735 [ # # ]: 0 : pa_assert(f);
736 [ # # ]: 0 : pa_assert(r);
737 : :
738 [ # # ]: 0 : for (c = 0; c < map->channels; c++) {
739 [ # # ]: 0 : if (on_front(map->map[c])) {
740 : 0 : front += v->values[c];
741 : 0 : n_front++;
742 [ # # ]: 0 : } else if (on_rear(map->map[c])) {
743 : 0 : rear += v->values[c];
744 : 0 : n_rear++;
745 : : }
746 : : }
747 : :
748 [ # # ]: 0 : if (n_front <= 0)
749 : 0 : *f = PA_VOLUME_NORM;
750 : : else
751 : 0 : *f = front / n_front;
752 : :
753 [ # # ]: 0 : if (n_rear <= 0)
754 : 0 : *r = PA_VOLUME_NORM;
755 : : else
756 : 0 : *r = rear / n_rear;
757 : 0 : }
758 : :
759 : 0 : float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) {
760 : : pa_volume_t front, rear;
761 : :
762 [ # # ]: 0 : pa_assert(v);
763 [ # # ]: 0 : pa_assert(map);
764 : :
765 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
766 : :
767 [ # # ]: 0 : if (!pa_channel_map_can_fade(map))
768 : : return 0.0f;
769 : :
770 : 0 : get_avg_fr(map, v, &front, &rear);
771 : :
772 [ # # ]: 0 : if (front == rear)
773 : : return 0.0f;
774 : :
775 [ # # ]: 0 : if (rear > front)
776 : 0 : return -1.0f + ((float) front / (float) rear);
777 : : else
778 : 0 : return 1.0f - ((float) rear / (float) front);
779 : : }
780 : :
781 : 0 : pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) {
782 : : pa_volume_t front, nfront, rear, nrear, m;
783 : : unsigned c;
784 : :
785 [ # # ]: 0 : pa_assert(map);
786 [ # # ]: 0 : pa_assert(v);
787 : :
788 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
789 [ # # ]: 0 : pa_return_val_if_fail(new_fade >= -1.0f, NULL);
790 [ # # ]: 0 : pa_return_val_if_fail(new_fade <= 1.0f, NULL);
791 : :
792 [ # # ]: 0 : if (!pa_channel_map_can_fade(map))
793 : : return v;
794 : :
795 : 0 : get_avg_fr(map, v, &front, &rear);
796 : :
797 : 0 : m = PA_MAX(front, rear);
798 : :
799 [ # # ]: 0 : if (new_fade <= 0) {
800 : 0 : nfront = (new_fade + 1.0f) * m;
801 : 0 : nrear = m;
802 : : } else {
803 : 0 : nrear = (1.0f - new_fade) * m;
804 : 0 : nfront = m;
805 : : }
806 : :
807 [ # # ]: 0 : for (c = 0; c < map->channels; c++) {
808 [ # # ]: 0 : if (on_front(map->map[c])) {
809 [ # # ]: 0 : if (front == 0)
810 : 0 : v->values[c] = nfront;
811 : : else
812 [ # # ]: 0 : v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nfront) / (uint64_t) front);
813 [ # # ]: 0 : } else if (on_rear(map->map[c])) {
814 [ # # ]: 0 : if (rear == 0)
815 : 0 : v->values[c] = nrear;
816 : : else
817 [ # # ]: 0 : v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nrear) / (uint64_t) rear);
818 : : }
819 : : }
820 : :
821 : : return v;
822 : : }
823 : :
824 : 0 : pa_cvolume* pa_cvolume_set_position(
825 : : pa_cvolume *cv,
826 : : const pa_channel_map *map,
827 : : pa_channel_position_t t,
828 : : pa_volume_t v) {
829 : :
830 : : unsigned c;
831 : 0 : pa_bool_t good = FALSE;
832 : :
833 [ # # ]: 0 : pa_assert(cv);
834 [ # # ]: 0 : pa_assert(map);
835 : :
836 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
837 [ # # ]: 0 : pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
838 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL);
839 : :
840 [ # # ]: 0 : for (c = 0; c < map->channels; c++)
841 [ # # ]: 0 : if (map->map[c] == t) {
842 : 0 : cv->values[c] = v;
843 : 0 : good = TRUE;
844 : : }
845 : :
846 [ # # ]: 0 : return good ? cv : NULL;
847 : : }
848 : :
849 : 0 : pa_volume_t pa_cvolume_get_position(
850 : : pa_cvolume *cv,
851 : : const pa_channel_map *map,
852 : : pa_channel_position_t t) {
853 : :
854 : : unsigned c;
855 : 0 : pa_volume_t v = PA_VOLUME_MUTED;
856 : :
857 [ # # ]: 0 : pa_assert(cv);
858 [ # # ]: 0 : pa_assert(map);
859 : :
860 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
861 [ # # ]: 0 : pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
862 : :
863 [ # # ]: 0 : for (c = 0; c < map->channels; c++)
864 [ # # ]: 0 : if (map->map[c] == t)
865 [ # # ]: 0 : if (cv->values[c] > v)
866 : 0 : v = cv->values[c];
867 : :
868 : : return v;
869 : : }
870 : :
871 : 0 : pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
872 : : unsigned i;
873 : :
874 [ # # ]: 0 : pa_assert(dest);
875 [ # # ]: 0 : pa_assert(a);
876 [ # # ]: 0 : pa_assert(b);
877 : :
878 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
879 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
880 : :
881 [ # # ][ # # ]: 0 : for (i = 0; i < a->channels && i < b->channels; i++)
882 : 0 : dest->values[i] = PA_MAX(a->values[i], b->values[i]);
883 : :
884 : 0 : dest->channels = (uint8_t) i;
885 : :
886 : 0 : return dest;
887 : : }
888 : :
889 : 0 : pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) {
890 : : pa_volume_t m;
891 : :
892 [ # # ]: 0 : pa_assert(v);
893 : :
894 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
895 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL);
896 : :
897 : 0 : m = pa_cvolume_max(v);
898 : :
899 [ # # ]: 0 : if (m >= limit - inc)
900 : : m = limit;
901 : : else
902 : 0 : m += inc;
903 : :
904 : 0 : return pa_cvolume_scale(v, m);
905 : : }
906 : :
907 : 0 : pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc){
908 : 0 : return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX);
909 : : }
910 : :
911 : 0 : pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) {
912 : : pa_volume_t m;
913 : :
914 [ # # ]: 0 : pa_assert(v);
915 : :
916 [ # # ]: 0 : pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
917 [ # # ]: 0 : pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL);
918 : :
919 : 0 : m = pa_cvolume_max(v);
920 : :
921 [ # # ]: 0 : if (m <= PA_VOLUME_MUTED + dec)
922 : : m = PA_VOLUME_MUTED;
923 : : else
924 : 0 : m -= dec;
925 : :
926 : 0 : return pa_cvolume_scale(v, m);
927 : : }
|