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