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