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