2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
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 of the License,
9 or (at your option) any later version.
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.
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
29 #include <pulse/i18n.h>
30 #include <pulsecore/core-util.h>
31 #include <pulsecore/macro.h>
35 int pa_cvolume_equal(const pa_cvolume
*a
, const pa_cvolume
*b
) {
40 if (a
->channels
!= b
->channels
)
43 for (i
= 0; i
< a
->channels
; i
++)
44 if (a
->values
[i
] != b
->values
[i
])
50 pa_cvolume
* pa_cvolume_init(pa_cvolume
*a
) {
57 for (c
= 0; c
< PA_CHANNELS_MAX
; c
++)
58 a
->values
[c
] = (pa_volume_t
) -1;
63 pa_cvolume
* pa_cvolume_set(pa_cvolume
*a
, unsigned channels
, pa_volume_t v
) {
67 pa_assert(channels
> 0);
68 pa_assert(channels
<= PA_CHANNELS_MAX
);
70 a
->channels
= (uint8_t) channels
;
72 for (i
= 0; i
< a
->channels
; i
++)
78 pa_volume_t
pa_cvolume_avg(const pa_cvolume
*a
) {
83 for (i
= 0; i
< a
->channels
; i
++)
88 return (pa_volume_t
) sum
;
91 pa_volume_t
pa_cvolume_max(const pa_cvolume
*a
) {
96 for (i
= 0; i
< a
->channels
; i
++)
103 pa_volume_t
pa_sw_volume_multiply(pa_volume_t a
, pa_volume_t b
) {
104 return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a
) * pa_sw_volume_to_linear(b
));
107 pa_volume_t
pa_sw_volume_divide(pa_volume_t a
, pa_volume_t b
) {
108 double v
= pa_sw_volume_to_linear(b
);
113 return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a
) / v
);
116 #define USER_DECIBEL_RANGE 60
118 pa_volume_t
pa_sw_volume_from_dB(double dB
) {
119 if (isinf(dB
) < 0 || dB
<= -USER_DECIBEL_RANGE
)
120 return PA_VOLUME_MUTED
;
122 return (pa_volume_t
) lrint((dB
/USER_DECIBEL_RANGE
+1)*PA_VOLUME_NORM
);
125 double pa_sw_volume_to_dB(pa_volume_t v
) {
126 if (v
== PA_VOLUME_MUTED
)
127 return PA_DECIBEL_MININFTY
;
129 return ((double) v
/PA_VOLUME_NORM
-1)*USER_DECIBEL_RANGE
;
132 pa_volume_t
pa_sw_volume_from_linear(double v
) {
135 return PA_VOLUME_MUTED
;
137 if (v
> .999 && v
< 1.001)
138 return PA_VOLUME_NORM
;
140 return pa_sw_volume_from_dB(20*log10(v
));
143 double pa_sw_volume_to_linear(pa_volume_t v
) {
145 if (v
== PA_VOLUME_MUTED
)
148 return pow(10.0, pa_sw_volume_to_dB(v
)/20.0);
151 char *pa_cvolume_snprint(char *s
, size_t l
, const pa_cvolume
*c
) {
153 pa_bool_t first
= TRUE
;
162 if (!pa_cvolume_valid(c
)) {
163 pa_snprintf(s
, l
, _("(invalid)"));
169 for (channel
= 0; channel
< c
->channels
&& l
> 1; channel
++) {
170 l
-= pa_snprintf(e
, l
, "%s%u: %3u%%",
173 (c
->values
[channel
]*100)/PA_VOLUME_NORM
);
182 char *pa_sw_cvolume_snprint_dB(char *s
, size_t l
, const pa_cvolume
*c
) {
184 pa_bool_t first
= TRUE
;
193 if (!pa_cvolume_valid(c
)) {
194 pa_snprintf(s
, l
, _("(invalid)"));
200 for (channel
= 0; channel
< c
->channels
&& l
> 1; channel
++) {
201 l
-= pa_snprintf(e
, l
, "%s%u: %0.2f dB",
204 pa_sw_volume_to_dB(c
->values
[channel
]));
213 /** Return non-zero if the volume of all channels is equal to the specified value */
214 int pa_cvolume_channels_equal_to(const pa_cvolume
*a
, pa_volume_t v
) {
218 for (c
= 0; c
< a
->channels
; c
++)
219 if (a
->values
[c
] != v
)
225 pa_cvolume
*pa_sw_cvolume_multiply(pa_cvolume
*dest
, const pa_cvolume
*a
, const pa_cvolume
*b
) {
232 for (i
= 0; i
< a
->channels
&& i
< b
->channels
&& i
< PA_CHANNELS_MAX
; i
++)
233 dest
->values
[i
] = pa_sw_volume_multiply(a
->values
[i
], b
->values
[i
]);
235 dest
->channels
= (uint8_t) i
;
240 pa_cvolume
*pa_sw_cvolume_divide(pa_cvolume
*dest
, const pa_cvolume
*a
, const pa_cvolume
*b
) {
247 for (i
= 0; i
< a
->channels
&& i
< b
->channels
&& i
< PA_CHANNELS_MAX
; i
++)
248 dest
->values
[i
] = pa_sw_volume_divide(a
->values
[i
], b
->values
[i
]);
250 dest
->channels
= (uint8_t) i
;
255 int pa_cvolume_valid(const pa_cvolume
*v
) {
260 if (v
->channels
<= 0 || v
->channels
> PA_CHANNELS_MAX
)
263 for (c
= 0; c
< v
->channels
; c
++)
264 if (v
->values
[c
] == (pa_volume_t
) -1)
270 static pa_bool_t
on_left(pa_channel_position_t p
) {
273 p
== PA_CHANNEL_POSITION_FRONT_LEFT
||
274 p
== PA_CHANNEL_POSITION_REAR_LEFT
||
275 p
== PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
||
276 p
== PA_CHANNEL_POSITION_SIDE_LEFT
||
277 p
== PA_CHANNEL_POSITION_TOP_FRONT_LEFT
||
278 p
== PA_CHANNEL_POSITION_TOP_REAR_LEFT
;
281 static pa_bool_t
on_right(pa_channel_position_t p
) {
284 p
== PA_CHANNEL_POSITION_FRONT_RIGHT
||
285 p
== PA_CHANNEL_POSITION_REAR_RIGHT
||
286 p
== PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
||
287 p
== PA_CHANNEL_POSITION_SIDE_RIGHT
||
288 p
== PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
||
289 p
== PA_CHANNEL_POSITION_TOP_REAR_RIGHT
;
292 static pa_bool_t
on_center(pa_channel_position_t p
) {
295 p
== PA_CHANNEL_POSITION_FRONT_CENTER
||
296 p
== PA_CHANNEL_POSITION_REAR_CENTER
||
297 p
== PA_CHANNEL_POSITION_TOP_CENTER
||
298 p
== PA_CHANNEL_POSITION_TOP_FRONT_CENTER
||
299 p
== PA_CHANNEL_POSITION_TOP_REAR_CENTER
;
302 static pa_bool_t
on_lfe(pa_channel_position_t p
) {
304 p
== PA_CHANNEL_POSITION_LFE
;
307 pa_cvolume
*pa_cvolume_remap(pa_cvolume
*v
, pa_channel_map
*from
, pa_channel_map
*to
) {
314 pa_assert(v
->channels
== from
->channels
);
316 if (pa_channel_map_equal(from
, to
))
319 result
.channels
= to
->channels
;
321 for (b
= 0; b
< to
->channels
; b
++) {
325 for (a
= 0; a
< from
->channels
; a
++)
326 if (from
->map
[a
] == to
->map
[b
]) {
332 for (a
= 0; a
< from
->channels
; a
++)
333 if ((on_left(from
->map
[a
]) && on_left(to
->map
[b
])) ||
334 (on_right(from
->map
[a
]) && on_right(to
->map
[b
])) ||
335 (on_center(from
->map
[a
]) && on_center(to
->map
[b
])) ||
336 (on_lfe(from
->map
[a
]) && on_lfe(to
->map
[b
]))) {
344 k
= pa_cvolume_avg(v
);
348 result
.values
[b
] = k
;
355 int pa_cvolume_compatible(const pa_cvolume
*v
, const pa_sample_spec
*ss
) {
360 if (!pa_cvolume_valid(v
))
363 if (!pa_sample_spec_valid(ss
))
366 return v
->channels
== ss
->channels
;