]> code.delx.au - pulseaudio/blob - src/pulse/volume.c
libpulse: some minor optimizations when checking equality
[pulseaudio] / src / pulse / volume.c
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
29 #include <pulse/i18n.h>
30
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/macro.h>
33 #include <pulsecore/sample-util.h>
34
35 #include "volume.h"
36
37 int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) {
38 int i;
39 pa_assert(a);
40 pa_assert(b);
41
42 pa_return_val_if_fail(pa_cvolume_valid(a), 0);
43
44 if (PA_UNLIKELY(a == b))
45 return 1;
46
47 pa_return_val_if_fail(pa_cvolume_valid(b), 0);
48
49 if (a->channels != b->channels)
50 return 0;
51
52 for (i = 0; i < a->channels; i++)
53 if (a->values[i] != b->values[i])
54 return 0;
55
56 return 1;
57 }
58
59 pa_cvolume* pa_cvolume_init(pa_cvolume *a) {
60 unsigned c;
61
62 pa_assert(a);
63
64 a->channels = 0;
65
66 for (c = 0; c < PA_CHANNELS_MAX; c++)
67 a->values[c] = (pa_volume_t) -1;
68
69 return a;
70 }
71
72 pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) {
73 int i;
74
75 pa_assert(a);
76 pa_assert(channels > 0);
77 pa_assert(channels <= PA_CHANNELS_MAX);
78
79 a->channels = (uint8_t) channels;
80
81 for (i = 0; i < a->channels; i++)
82 a->values[i] = v;
83
84 return a;
85 }
86
87 pa_volume_t pa_cvolume_avg(const pa_cvolume *a) {
88 uint64_t sum = 0;
89 unsigned c;
90
91 pa_assert(a);
92 pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
93
94 for (c = 0; c < a->channels; c++)
95 sum += a->values[c];
96
97 sum /= a->channels;
98
99 return (pa_volume_t) sum;
100 }
101
102 pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
103 uint64_t sum = 0;
104 unsigned c, n;
105
106 pa_assert(a);
107
108 if (!cm)
109 return pa_cvolume_avg(a);
110
111 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
112
113 for (c = n = 0; c < a->channels; c++) {
114
115 if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
116 continue;
117
118 sum += a->values[c];
119 n ++;
120 }
121
122 if (n > 0)
123 sum /= n;
124
125 return (pa_volume_t) sum;
126 }
127
128 pa_volume_t pa_cvolume_max(const pa_cvolume *a) {
129 pa_volume_t m = 0;
130 unsigned c;
131
132 pa_assert(a);
133 pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
134
135 for (c = 0; c < a->channels; c++)
136 if (a->values[c] > m)
137 m = a->values[c];
138
139 return m;
140 }
141
142 pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
143 pa_volume_t m = 0;
144 unsigned c, n;
145
146 pa_assert(a);
147
148 if (!cm)
149 return pa_cvolume_max(a);
150
151 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
152
153 for (c = n = 0; c < a->channels; c++) {
154
155 if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
156 continue;
157
158 if (a->values[c] > m)
159 m = a->values[c];
160 }
161
162 return m;
163 }
164
165 pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
166 return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) * pa_sw_volume_to_linear(b));
167 }
168
169 pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) {
170 double v = pa_sw_volume_to_linear(b);
171
172 if (v <= 0)
173 return 0;
174
175 return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) / v);
176 }
177
178 /* Amplitude, not power */
179 static double linear_to_dB(double v) {
180 return 20.0 * log10(v);
181 }
182
183 static double dB_to_linear(double v) {
184 return pow(10.0, v / 20.0);
185 }
186
187 pa_volume_t pa_sw_volume_from_dB(double dB) {
188 if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY)
189 return PA_VOLUME_MUTED;
190
191 return pa_sw_volume_from_linear(dB_to_linear(dB));
192 }
193
194 double pa_sw_volume_to_dB(pa_volume_t v) {
195
196 if (v <= PA_VOLUME_MUTED)
197 return PA_DECIBEL_MININFTY;
198
199 return linear_to_dB(pa_sw_volume_to_linear(v));
200 }
201
202 pa_volume_t pa_sw_volume_from_linear(double v) {
203
204 if (v <= 0.0)
205 return PA_VOLUME_MUTED;
206
207 /*
208 * We use a cubic mapping here, as suggested and discussed here:
209 *
210 * http://www.robotplanet.dk/audio/audio_gui_design/
211 * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151
212 *
213 * We make sure that the conversion to linear and back yields the
214 * same volume value! That's why we need the lround() below!
215 */
216
217 return (pa_volume_t) lround(cbrt(v) * PA_VOLUME_NORM);
218 }
219
220 double pa_sw_volume_to_linear(pa_volume_t v) {
221 double f;
222
223 if (v <= PA_VOLUME_MUTED)
224 return 0.0;
225
226 if (v == PA_VOLUME_NORM)
227 return 1.0;
228
229 f = ((double) v / PA_VOLUME_NORM);
230
231 return f*f*f;
232 }
233
234 char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) {
235 unsigned channel;
236 pa_bool_t first = TRUE;
237 char *e;
238
239 pa_assert(s);
240 pa_assert(l > 0);
241 pa_assert(c);
242
243 pa_init_i18n();
244
245 if (!pa_cvolume_valid(c)) {
246 pa_snprintf(s, l, _("(invalid)"));
247 return s;
248 }
249
250 *(e = s) = 0;
251
252 for (channel = 0; channel < c->channels && l > 1; channel++) {
253 l -= pa_snprintf(e, l, "%s%u: %3u%%",
254 first ? "" : " ",
255 channel,
256 (c->values[channel]*100)/PA_VOLUME_NORM);
257
258 e = strchr(e, 0);
259 first = FALSE;
260 }
261
262 return s;
263 }
264
265 char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) {
266 pa_assert(s);
267 pa_assert(l > 0);
268
269 pa_init_i18n();
270
271 if (v == (pa_volume_t) -1) {
272 pa_snprintf(s, l, _("(invalid)"));
273 return s;
274 }
275
276 pa_snprintf(s, l, "%3u%%", (v*100)/PA_VOLUME_NORM);
277 return s;
278 }
279
280 char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) {
281 unsigned channel;
282 pa_bool_t first = TRUE;
283 char *e;
284
285 pa_assert(s);
286 pa_assert(l > 0);
287 pa_assert(c);
288
289 pa_init_i18n();
290
291 if (!pa_cvolume_valid(c)) {
292 pa_snprintf(s, l, _("(invalid)"));
293 return s;
294 }
295
296 *(e = s) = 0;
297
298 for (channel = 0; channel < c->channels && l > 1; channel++) {
299 double f = pa_sw_volume_to_dB(c->values[channel]);
300
301 l -= pa_snprintf(e, l, "%s%u: %0.2f dB",
302 first ? "" : " ",
303 channel,
304 isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
305
306 e = strchr(e, 0);
307 first = FALSE;
308 }
309
310 return s;
311 }
312
313 char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) {
314 double f;
315
316 pa_assert(s);
317 pa_assert(l > 0);
318
319 pa_init_i18n();
320
321 if (v == (pa_volume_t) -1) {
322 pa_snprintf(s, l, _("(invalid)"));
323 return s;
324 }
325
326 f = pa_sw_volume_to_dB(v);
327 pa_snprintf(s, l, "%0.2f dB",
328 isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
329
330 return s;
331 }
332
333 int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
334 unsigned c;
335 pa_assert(a);
336
337 pa_return_val_if_fail(pa_cvolume_valid(a), 0);
338
339 for (c = 0; c < a->channels; c++)
340 if (a->values[c] != v)
341 return 0;
342
343 return 1;
344 }
345
346 pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
347 unsigned i;
348
349 pa_assert(dest);
350 pa_assert(a);
351 pa_assert(b);
352
353 pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
354 pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
355
356 for (i = 0; i < a->channels && i < b->channels; i++)
357 dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
358
359 dest->channels = (uint8_t) i;
360
361 return dest;
362 }
363
364 pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
365 unsigned i;
366
367 pa_assert(dest);
368 pa_assert(a);
369
370 pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
371
372 for (i = 0; i < a->channels; i++)
373 dest->values[i] = pa_sw_volume_multiply(a->values[i], b);
374
375 dest->channels = (uint8_t) i;
376
377 return dest;
378 }
379
380 pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
381 unsigned i;
382
383 pa_assert(dest);
384 pa_assert(a);
385 pa_assert(b);
386
387 pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
388 pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
389
390 for (i = 0; i < a->channels && i < b->channels; i++)
391 dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
392
393 dest->channels = (uint8_t) i;
394
395 return dest;
396 }
397
398 pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
399 unsigned i;
400
401 pa_assert(dest);
402 pa_assert(a);
403
404 pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
405
406 for (i = 0; i < a->channels; i++)
407 dest->values[i] = pa_sw_volume_divide(a->values[i], b);
408
409 dest->channels = (uint8_t) i;
410
411 return dest;
412 }
413
414 int pa_cvolume_valid(const pa_cvolume *v) {
415 unsigned c;
416
417 pa_assert(v);
418
419 if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX)
420 return 0;
421
422 for (c = 0; c < v->channels; c++)
423 if (v->values[c] == (pa_volume_t) -1)
424 return 0;
425
426 return 1;
427 }
428
429 static pa_bool_t on_left(pa_channel_position_t p) {
430 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
431 }
432
433 static pa_bool_t on_right(pa_channel_position_t p) {
434 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
435 }
436
437 static pa_bool_t on_center(pa_channel_position_t p) {
438 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
439 }
440
441 static pa_bool_t on_lfe(pa_channel_position_t p) {
442 return p == PA_CHANNEL_POSITION_LFE;
443 }
444
445 static pa_bool_t on_front(pa_channel_position_t p) {
446 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
447 }
448
449 static pa_bool_t on_rear(pa_channel_position_t p) {
450 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
451 }
452
453 pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) {
454 int a, b;
455 pa_cvolume result;
456
457 pa_assert(v);
458 pa_assert(from);
459 pa_assert(to);
460
461 pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
462 pa_return_val_if_fail(pa_channel_map_valid(from), NULL);
463 pa_return_val_if_fail(pa_channel_map_valid(to), NULL);
464 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
465
466 if (pa_channel_map_equal(from, to))
467 return v;
468
469 result.channels = to->channels;
470
471 for (b = 0; b < to->channels; b++) {
472 pa_volume_t k = 0;
473 int n = 0;
474
475 for (a = 0; a < from->channels; a++)
476 if (from->map[a] == to->map[b]) {
477 k += v->values[a];
478 n ++;
479 }
480
481 if (n <= 0) {
482 for (a = 0; a < from->channels; a++)
483 if ((on_left(from->map[a]) && on_left(to->map[b])) ||
484 (on_right(from->map[a]) && on_right(to->map[b])) ||
485 (on_center(from->map[a]) && on_center(to->map[b])) ||
486 (on_lfe(from->map[a]) && on_lfe(to->map[b]))) {
487
488 k += v->values[a];
489 n ++;
490 }
491 }
492
493 if (n <= 0)
494 k = pa_cvolume_avg(v);
495 else
496 k /= n;
497
498 result.values[b] = k;
499 }
500
501 *v = result;
502 return v;
503 }
504
505 int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) {
506
507 pa_assert(v);
508 pa_assert(ss);
509
510 pa_return_val_if_fail(pa_cvolume_valid(v), 0);
511 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
512
513 return v->channels == ss->channels;
514 }
515
516 int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) {
517 pa_assert(v);
518 pa_assert(cm);
519
520 pa_return_val_if_fail(pa_cvolume_valid(v), 0);
521 pa_return_val_if_fail(pa_channel_map_valid(cm), 0);
522
523 return v->channels == cm->channels;
524 }
525
526 static void get_avg_lr(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r) {
527 int c;
528 pa_volume_t left = 0, right = 0;
529 unsigned n_left = 0, n_right = 0;
530
531 pa_assert(v);
532 pa_assert(map);
533 pa_assert(map->channels == v->channels);
534 pa_assert(l);
535 pa_assert(r);
536
537 for (c = 0; c < map->channels; c++) {
538 if (on_left(map->map[c])) {
539 left += v->values[c];
540 n_left++;
541 } else if (on_right(map->map[c])) {
542 right += v->values[c];
543 n_right++;
544 }
545 }
546
547 if (n_left <= 0)
548 *l = PA_VOLUME_NORM;
549 else
550 *l = left / n_left;
551
552 if (n_right <= 0)
553 *r = PA_VOLUME_NORM;
554 else
555 *r = right / n_right;
556 }
557
558 float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) {
559 pa_volume_t left, right;
560
561 pa_assert(v);
562 pa_assert(map);
563
564 pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f);
565 pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f);
566 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
567
568 if (!pa_channel_map_can_balance(map))
569 return 0.0f;
570
571 get_avg_lr(map, v, &left, &right);
572
573 if (left == right)
574 return 0.0f;
575
576 /* 1.0, 0.0 => -1.0
577 0.0, 1.0 => 1.0
578 0.0, 0.0 => 0.0
579 0.5, 0.5 => 0.0
580 1.0, 0.5 => -0.5
581 1.0, 0.25 => -0.75
582 0.75, 0.25 => -0.66
583 0.5, 0.25 => -0.5 */
584
585 if (left > right)
586 return -1.0f + ((float) right / (float) left);
587 else
588 return 1.0f - ((float) left / (float) right);
589 }
590
591 pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
592 pa_volume_t left, nleft, right, nright, m;
593 unsigned c;
594
595 pa_assert(map);
596 pa_assert(v);
597 pa_assert(new_balance >= -1.0f);
598 pa_assert(new_balance <= 1.0f);
599
600 pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
601 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
602 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
603
604 if (!pa_channel_map_can_balance(map))
605 return v;
606
607 get_avg_lr(map, v, &left, &right);
608
609 m = PA_MAX(left, right);
610
611 if (new_balance <= 0) {
612 nright = (new_balance + 1.0f) * m;
613 nleft = m;
614 } else {
615 nleft = (1.0f - new_balance) * m;
616 nright = m;
617 }
618
619 for (c = 0; c < map->channels; c++) {
620 if (on_left(map->map[c])) {
621 if (left == 0)
622 v->values[c] = nleft;
623 else
624 v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left);
625 } else if (on_right(map->map[c])) {
626 if (right == 0)
627 v->values[c] = nright;
628 else
629 v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right);
630 }
631 }
632
633 return v;
634 }
635
636 pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) {
637 unsigned c;
638 pa_volume_t t = 0;
639
640 pa_assert(v);
641
642 pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
643 pa_return_val_if_fail(max != (pa_volume_t) -1, NULL);
644
645 t = pa_cvolume_max(v);
646
647 if (t <= PA_VOLUME_MUTED)
648 return pa_cvolume_set(v, v->channels, max);
649
650 for (c = 0; c < v->channels; c++)
651 v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
652
653 return v;
654 }
655
656 pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) {
657 unsigned c;
658 pa_volume_t t = 0;
659
660 pa_assert(v);
661
662 pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
663 pa_return_val_if_fail(max != (pa_volume_t) -1, NULL);
664
665 t = pa_cvolume_max_mask(v, cm, mask);
666
667 if (t <= PA_VOLUME_MUTED)
668 return pa_cvolume_set(v, v->channels, max);
669
670 for (c = 0; c < v->channels; c++)
671 v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
672
673 return v;
674 }
675
676 static void get_avg_fr(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *f, pa_volume_t *r) {
677 int c;
678 pa_volume_t front = 0, rear = 0;
679 unsigned n_front = 0, n_rear = 0;
680
681 pa_assert(v);
682 pa_assert(map);
683 pa_assert(map->channels == v->channels);
684 pa_assert(f);
685 pa_assert(r);
686
687 for (c = 0; c < map->channels; c++) {
688 if (on_front(map->map[c])) {
689 front += v->values[c];
690 n_front++;
691 } else if (on_rear(map->map[c])) {
692 rear += v->values[c];
693 n_rear++;
694 }
695 }
696
697 if (n_front <= 0)
698 *f = PA_VOLUME_NORM;
699 else
700 *f = front / n_front;
701
702 if (n_rear <= 0)
703 *r = PA_VOLUME_NORM;
704 else
705 *r = rear / n_rear;
706 }
707
708 float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) {
709 pa_volume_t front, rear;
710
711 pa_assert(v);
712 pa_assert(map);
713
714 pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f);
715 pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f);
716 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
717
718 if (!pa_channel_map_can_fade(map))
719 return 0.0f;
720
721 get_avg_fr(map, v, &front, &rear);
722
723 if (front == rear)
724 return 0.0f;
725
726 if (rear > front)
727 return -1.0f + ((float) front / (float) rear);
728 else
729 return 1.0f - ((float) rear / (float) front);
730 }
731
732 pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) {
733 pa_volume_t front, nfront, rear, nrear, m;
734 unsigned c;
735
736 pa_assert(map);
737 pa_assert(v);
738 pa_assert(new_fade >= -1.0f);
739 pa_assert(new_fade <= 1.0f);
740
741 pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
742 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
743 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
744
745 if (!pa_channel_map_can_fade(map))
746 return v;
747
748 get_avg_fr(map, v, &front, &rear);
749
750 m = PA_MAX(front, rear);
751
752 if (new_fade <= 0) {
753 nfront = (new_fade + 1.0f) * m;
754 nrear = m;
755 } else {
756 nrear = (1.0f - new_fade) * m;
757 nfront = m;
758 }
759
760 for (c = 0; c < map->channels; c++) {
761 if (on_front(map->map[c])) {
762 if (front == 0)
763 v->values[c] = nfront;
764 else
765 v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) nfront) / (uint64_t) front);
766 } else if (on_rear(map->map[c])) {
767 if (rear == 0)
768 v->values[c] = nrear;
769 else
770 v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) nrear) / (uint64_t) rear);
771 }
772 }
773
774 return v;
775 }
776
777 pa_cvolume* pa_cvolume_set_position(
778 pa_cvolume *cv,
779 const pa_channel_map *map,
780 pa_channel_position_t t,
781 pa_volume_t v) {
782
783 unsigned c;
784 pa_bool_t good = FALSE;
785
786 pa_assert(cv);
787 pa_assert(map);
788
789 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
790 pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
791
792 for (c = 0; c < map->channels; c++)
793 if (map->map[c] == t) {
794 cv->values[c] = v;
795 good = TRUE;
796 }
797
798 return good ? cv : NULL;
799 }
800
801 pa_volume_t pa_cvolume_get_position(
802 pa_cvolume *cv,
803 const pa_channel_map *map,
804 pa_channel_position_t t) {
805
806 unsigned c;
807 pa_volume_t v = PA_VOLUME_MUTED;
808
809 pa_assert(cv);
810 pa_assert(map);
811
812 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
813 pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
814
815 for (c = 0; c < map->channels; c++)
816 if (map->map[c] == t)
817 if (cv->values[c] > v)
818 v = cv->values[c];
819
820 return v;
821 }
822
823 pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
824 unsigned i;
825
826 pa_assert(dest);
827 pa_assert(a);
828 pa_assert(b);
829
830 pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
831 pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
832
833 for (i = 0; i < a->channels && i < b->channels; i++)
834 dest->values[i] = PA_MAX(a->values[i], b->values[i]);
835
836 dest->channels = (uint8_t) i;
837
838 return dest;
839 }