153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <stdio.h>
2553a5a1b3Sopenharmony_ci#include <string.h>
2653a5a1b3Sopenharmony_ci#include <math.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
2953a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h>
3053a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3153a5a1b3Sopenharmony_ci#include <pulsecore/sample-util.h>
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_ci#include "volume.h"
3453a5a1b3Sopenharmony_ci
3553a5a1b3Sopenharmony_ciint pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) {
3653a5a1b3Sopenharmony_ci    int i;
3753a5a1b3Sopenharmony_ci    pa_assert(a);
3853a5a1b3Sopenharmony_ci    pa_assert(b);
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), 0);
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(a == b))
4353a5a1b3Sopenharmony_ci        return 1;
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), 0);
4653a5a1b3Sopenharmony_ci
4753a5a1b3Sopenharmony_ci    if (a->channels != b->channels)
4853a5a1b3Sopenharmony_ci        return 0;
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ci    for (i = 0; i < a->channels; i++)
5153a5a1b3Sopenharmony_ci        if (a->values[i] != b->values[i])
5253a5a1b3Sopenharmony_ci            return 0;
5353a5a1b3Sopenharmony_ci
5453a5a1b3Sopenharmony_ci    return 1;
5553a5a1b3Sopenharmony_ci}
5653a5a1b3Sopenharmony_ci
5753a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_init(pa_cvolume *a) {
5853a5a1b3Sopenharmony_ci    unsigned c;
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci    pa_assert(a);
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ci    a->channels = 0;
6353a5a1b3Sopenharmony_ci
6453a5a1b3Sopenharmony_ci    for (c = 0; c < PA_CHANNELS_MAX; c++)
6553a5a1b3Sopenharmony_ci        a->values[c] = PA_VOLUME_INVALID;
6653a5a1b3Sopenharmony_ci
6753a5a1b3Sopenharmony_ci    return a;
6853a5a1b3Sopenharmony_ci}
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) {
7153a5a1b3Sopenharmony_ci    int i;
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci    pa_assert(a);
7453a5a1b3Sopenharmony_ci    pa_assert(pa_channels_valid(channels));
7553a5a1b3Sopenharmony_ci
7653a5a1b3Sopenharmony_ci    a->channels = (uint8_t) channels;
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ci    for (i = 0; i < a->channels; i++)
7953a5a1b3Sopenharmony_ci        /* Clamp in case there is stale data that exceeds the current
8053a5a1b3Sopenharmony_ci         * PA_VOLUME_MAX */
8153a5a1b3Sopenharmony_ci        a->values[i] = PA_CLAMP_VOLUME(v);
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_ci    return a;
8453a5a1b3Sopenharmony_ci}
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_avg(const pa_cvolume *a) {
8753a5a1b3Sopenharmony_ci    uint64_t sum = 0;
8853a5a1b3Sopenharmony_ci    unsigned c;
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_ci    pa_assert(a);
9153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
9253a5a1b3Sopenharmony_ci
9353a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++)
9453a5a1b3Sopenharmony_ci        sum += a->values[c];
9553a5a1b3Sopenharmony_ci
9653a5a1b3Sopenharmony_ci    sum /= a->channels;
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci    return (pa_volume_t) sum;
9953a5a1b3Sopenharmony_ci}
10053a5a1b3Sopenharmony_ci
10153a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
10253a5a1b3Sopenharmony_ci    uint64_t sum = 0;
10353a5a1b3Sopenharmony_ci    unsigned c, n;
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    pa_assert(a);
10653a5a1b3Sopenharmony_ci
10753a5a1b3Sopenharmony_ci    if (!cm)
10853a5a1b3Sopenharmony_ci        return pa_cvolume_avg(a);
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    for (c = n = 0; c < a->channels; c++) {
11353a5a1b3Sopenharmony_ci
11453a5a1b3Sopenharmony_ci        if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
11553a5a1b3Sopenharmony_ci            continue;
11653a5a1b3Sopenharmony_ci
11753a5a1b3Sopenharmony_ci        sum += a->values[c];
11853a5a1b3Sopenharmony_ci        n ++;
11953a5a1b3Sopenharmony_ci    }
12053a5a1b3Sopenharmony_ci
12153a5a1b3Sopenharmony_ci    if (n > 0)
12253a5a1b3Sopenharmony_ci        sum /= n;
12353a5a1b3Sopenharmony_ci
12453a5a1b3Sopenharmony_ci    return (pa_volume_t) sum;
12553a5a1b3Sopenharmony_ci}
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_max(const pa_cvolume *a) {
12853a5a1b3Sopenharmony_ci    pa_volume_t m = PA_VOLUME_MUTED;
12953a5a1b3Sopenharmony_ci    unsigned c;
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_ci    pa_assert(a);
13253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++)
13553a5a1b3Sopenharmony_ci        if (a->values[c] > m)
13653a5a1b3Sopenharmony_ci            m = a->values[c];
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_ci    return m;
13953a5a1b3Sopenharmony_ci}
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_min(const pa_cvolume *a) {
14253a5a1b3Sopenharmony_ci    pa_volume_t m = PA_VOLUME_MAX;
14353a5a1b3Sopenharmony_ci    unsigned c;
14453a5a1b3Sopenharmony_ci
14553a5a1b3Sopenharmony_ci    pa_assert(a);
14653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++)
14953a5a1b3Sopenharmony_ci        if (a->values[c] < m)
15053a5a1b3Sopenharmony_ci            m = a->values[c];
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_ci    return m;
15353a5a1b3Sopenharmony_ci}
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
15653a5a1b3Sopenharmony_ci    pa_volume_t m = PA_VOLUME_MUTED;
15753a5a1b3Sopenharmony_ci    unsigned c;
15853a5a1b3Sopenharmony_ci
15953a5a1b3Sopenharmony_ci    pa_assert(a);
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_ci    if (!cm)
16253a5a1b3Sopenharmony_ci        return pa_cvolume_max(a);
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
16553a5a1b3Sopenharmony_ci
16653a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++) {
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ci        if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
16953a5a1b3Sopenharmony_ci            continue;
17053a5a1b3Sopenharmony_ci
17153a5a1b3Sopenharmony_ci        if (a->values[c] > m)
17253a5a1b3Sopenharmony_ci            m = a->values[c];
17353a5a1b3Sopenharmony_ci    }
17453a5a1b3Sopenharmony_ci
17553a5a1b3Sopenharmony_ci    return m;
17653a5a1b3Sopenharmony_ci}
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
17953a5a1b3Sopenharmony_ci    pa_volume_t m = PA_VOLUME_MAX;
18053a5a1b3Sopenharmony_ci    unsigned c;
18153a5a1b3Sopenharmony_ci
18253a5a1b3Sopenharmony_ci    pa_assert(a);
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci    if (!cm)
18553a5a1b3Sopenharmony_ci        return pa_cvolume_min(a);
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED);
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++) {
19053a5a1b3Sopenharmony_ci
19153a5a1b3Sopenharmony_ci        if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
19253a5a1b3Sopenharmony_ci            continue;
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci        if (a->values[c] < m)
19553a5a1b3Sopenharmony_ci            m = a->values[c];
19653a5a1b3Sopenharmony_ci    }
19753a5a1b3Sopenharmony_ci
19853a5a1b3Sopenharmony_ci    return m;
19953a5a1b3Sopenharmony_ci}
20053a5a1b3Sopenharmony_ci
20153a5a1b3Sopenharmony_cipa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
20253a5a1b3Sopenharmony_ci    uint64_t result;
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID);
20553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID);
20653a5a1b3Sopenharmony_ci
20753a5a1b3Sopenharmony_ci    /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */
20853a5a1b3Sopenharmony_ci
20953a5a1b3Sopenharmony_ci    result = ((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM;
21053a5a1b3Sopenharmony_ci
21153a5a1b3Sopenharmony_ci    if (result > (uint64_t)PA_VOLUME_MAX)
21253a5a1b3Sopenharmony_ci        pa_log_warn("pa_sw_volume_multiply: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings.");
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_ci    return (pa_volume_t) PA_CLAMP_VOLUME(result);
21553a5a1b3Sopenharmony_ci}
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_cipa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) {
21853a5a1b3Sopenharmony_ci    uint64_t result;
21953a5a1b3Sopenharmony_ci
22053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID);
22153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID);
22253a5a1b3Sopenharmony_ci
22353a5a1b3Sopenharmony_ci    if (b <= PA_VOLUME_MUTED)
22453a5a1b3Sopenharmony_ci        return 0;
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci    result = ((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b;
22753a5a1b3Sopenharmony_ci
22853a5a1b3Sopenharmony_ci    if (result > (uint64_t)PA_VOLUME_MAX)
22953a5a1b3Sopenharmony_ci        pa_log_warn("pa_sw_volume_divide: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings.");
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci    return (pa_volume_t) PA_CLAMP_VOLUME(result);
23253a5a1b3Sopenharmony_ci}
23353a5a1b3Sopenharmony_ci
23453a5a1b3Sopenharmony_ci/* Amplitude, not power */
23553a5a1b3Sopenharmony_cistatic double linear_to_dB(double v) {
23653a5a1b3Sopenharmony_ci    return 20.0 * log10(v);
23753a5a1b3Sopenharmony_ci}
23853a5a1b3Sopenharmony_ci
23953a5a1b3Sopenharmony_cistatic double dB_to_linear(double v) {
24053a5a1b3Sopenharmony_ci    return pow(10.0, v / 20.0);
24153a5a1b3Sopenharmony_ci}
24253a5a1b3Sopenharmony_ci
24353a5a1b3Sopenharmony_cipa_volume_t pa_sw_volume_from_dB(double dB) {
24453a5a1b3Sopenharmony_ci    if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY)
24553a5a1b3Sopenharmony_ci        return PA_VOLUME_MUTED;
24653a5a1b3Sopenharmony_ci
24753a5a1b3Sopenharmony_ci    return pa_sw_volume_from_linear(dB_to_linear(dB));
24853a5a1b3Sopenharmony_ci}
24953a5a1b3Sopenharmony_ci
25053a5a1b3Sopenharmony_cidouble pa_sw_volume_to_dB(pa_volume_t v) {
25153a5a1b3Sopenharmony_ci
25253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY);
25353a5a1b3Sopenharmony_ci
25453a5a1b3Sopenharmony_ci    if (v <= PA_VOLUME_MUTED)
25553a5a1b3Sopenharmony_ci        return PA_DECIBEL_MININFTY;
25653a5a1b3Sopenharmony_ci
25753a5a1b3Sopenharmony_ci    return linear_to_dB(pa_sw_volume_to_linear(v));
25853a5a1b3Sopenharmony_ci}
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_cipa_volume_t pa_sw_volume_from_linear(double v) {
26153a5a1b3Sopenharmony_ci
26253a5a1b3Sopenharmony_ci    if (v <= 0.0)
26353a5a1b3Sopenharmony_ci        return PA_VOLUME_MUTED;
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_ci    /*
26653a5a1b3Sopenharmony_ci     * We use a cubic mapping here, as suggested and discussed here:
26753a5a1b3Sopenharmony_ci     *
26853a5a1b3Sopenharmony_ci     * http://www.robotplanet.dk/audio/audio_gui_design/
26953a5a1b3Sopenharmony_ci     * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151
27053a5a1b3Sopenharmony_ci     *
27153a5a1b3Sopenharmony_ci     * We make sure that the conversion to linear and back yields the
27253a5a1b3Sopenharmony_ci     * same volume value! That's why we need the lround() below!
27353a5a1b3Sopenharmony_ci     */
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ci    return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM));
27653a5a1b3Sopenharmony_ci}
27753a5a1b3Sopenharmony_ci
27853a5a1b3Sopenharmony_cidouble pa_sw_volume_to_linear(pa_volume_t v) {
27953a5a1b3Sopenharmony_ci    double f;
28053a5a1b3Sopenharmony_ci
28153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0);
28253a5a1b3Sopenharmony_ci
28353a5a1b3Sopenharmony_ci    if (v <= PA_VOLUME_MUTED)
28453a5a1b3Sopenharmony_ci        return 0.0;
28553a5a1b3Sopenharmony_ci
28653a5a1b3Sopenharmony_ci    if (v == PA_VOLUME_NORM)
28753a5a1b3Sopenharmony_ci        return 1.0;
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci    f = ((double) v / PA_VOLUME_NORM);
29053a5a1b3Sopenharmony_ci
29153a5a1b3Sopenharmony_ci    return f*f*f;
29253a5a1b3Sopenharmony_ci}
29353a5a1b3Sopenharmony_ci
29453a5a1b3Sopenharmony_cichar *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) {
29553a5a1b3Sopenharmony_ci    unsigned channel;
29653a5a1b3Sopenharmony_ci    bool first = true;
29753a5a1b3Sopenharmony_ci    char *e;
29853a5a1b3Sopenharmony_ci
29953a5a1b3Sopenharmony_ci    pa_assert(s);
30053a5a1b3Sopenharmony_ci    pa_assert(l > 0);
30153a5a1b3Sopenharmony_ci    pa_assert(c);
30253a5a1b3Sopenharmony_ci
30353a5a1b3Sopenharmony_ci    pa_init_i18n();
30453a5a1b3Sopenharmony_ci
30553a5a1b3Sopenharmony_ci    if (!pa_cvolume_valid(c)) {
30653a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
30753a5a1b3Sopenharmony_ci        return s;
30853a5a1b3Sopenharmony_ci    }
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci    *(e = s) = 0;
31153a5a1b3Sopenharmony_ci
31253a5a1b3Sopenharmony_ci    for (channel = 0; channel < c->channels && l > 1; channel++) {
31353a5a1b3Sopenharmony_ci        l -= pa_snprintf(e, l, "%s%u: %3u%%",
31453a5a1b3Sopenharmony_ci                      first ? "" : " ",
31553a5a1b3Sopenharmony_ci                      channel,
31653a5a1b3Sopenharmony_ci                      (unsigned)(((uint64_t)c->values[channel] * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM));
31753a5a1b3Sopenharmony_ci
31853a5a1b3Sopenharmony_ci        e = strchr(e, 0);
31953a5a1b3Sopenharmony_ci        first = false;
32053a5a1b3Sopenharmony_ci    }
32153a5a1b3Sopenharmony_ci
32253a5a1b3Sopenharmony_ci    return s;
32353a5a1b3Sopenharmony_ci}
32453a5a1b3Sopenharmony_ci
32553a5a1b3Sopenharmony_cichar *pa_volume_snprint(char *s, size_t l, pa_volume_t v) {
32653a5a1b3Sopenharmony_ci    pa_assert(s);
32753a5a1b3Sopenharmony_ci    pa_assert(l > 0);
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci    pa_init_i18n();
33053a5a1b3Sopenharmony_ci
33153a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(v)) {
33253a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
33353a5a1b3Sopenharmony_ci        return s;
33453a5a1b3Sopenharmony_ci    }
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%3u%%", (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM));
33753a5a1b3Sopenharmony_ci    return s;
33853a5a1b3Sopenharmony_ci}
33953a5a1b3Sopenharmony_ci
34053a5a1b3Sopenharmony_cichar *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) {
34153a5a1b3Sopenharmony_ci    unsigned channel;
34253a5a1b3Sopenharmony_ci    bool first = true;
34353a5a1b3Sopenharmony_ci    char *e;
34453a5a1b3Sopenharmony_ci
34553a5a1b3Sopenharmony_ci    pa_assert(s);
34653a5a1b3Sopenharmony_ci    pa_assert(l > 0);
34753a5a1b3Sopenharmony_ci    pa_assert(c);
34853a5a1b3Sopenharmony_ci
34953a5a1b3Sopenharmony_ci    pa_init_i18n();
35053a5a1b3Sopenharmony_ci
35153a5a1b3Sopenharmony_ci    if (!pa_cvolume_valid(c)) {
35253a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
35353a5a1b3Sopenharmony_ci        return s;
35453a5a1b3Sopenharmony_ci    }
35553a5a1b3Sopenharmony_ci
35653a5a1b3Sopenharmony_ci    *(e = s) = 0;
35753a5a1b3Sopenharmony_ci
35853a5a1b3Sopenharmony_ci    for (channel = 0; channel < c->channels && l > 1; channel++) {
35953a5a1b3Sopenharmony_ci        double f = pa_sw_volume_to_dB(c->values[channel]);
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_ci        l -= pa_snprintf(e, l, "%s%u: %0.2f dB",
36253a5a1b3Sopenharmony_ci                         first ? "" : " ",
36353a5a1b3Sopenharmony_ci                         channel,
36453a5a1b3Sopenharmony_ci                         isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
36553a5a1b3Sopenharmony_ci
36653a5a1b3Sopenharmony_ci        e = strchr(e, 0);
36753a5a1b3Sopenharmony_ci        first = false;
36853a5a1b3Sopenharmony_ci    }
36953a5a1b3Sopenharmony_ci
37053a5a1b3Sopenharmony_ci    return s;
37153a5a1b3Sopenharmony_ci}
37253a5a1b3Sopenharmony_ci
37353a5a1b3Sopenharmony_cichar *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) {
37453a5a1b3Sopenharmony_ci    char *current = s;
37553a5a1b3Sopenharmony_ci    bool first = true;
37653a5a1b3Sopenharmony_ci
37753a5a1b3Sopenharmony_ci    pa_assert(s);
37853a5a1b3Sopenharmony_ci    pa_assert(l > 0);
37953a5a1b3Sopenharmony_ci    pa_assert(c);
38053a5a1b3Sopenharmony_ci
38153a5a1b3Sopenharmony_ci    pa_init_i18n();
38253a5a1b3Sopenharmony_ci
38353a5a1b3Sopenharmony_ci    if (!pa_cvolume_valid(c)) {
38453a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
38553a5a1b3Sopenharmony_ci        return s;
38653a5a1b3Sopenharmony_ci    }
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_ci    pa_assert(!map || (map->channels == c->channels));
38953a5a1b3Sopenharmony_ci    pa_assert(!map || pa_channel_map_valid(map));
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    current[0] = 0;
39253a5a1b3Sopenharmony_ci
39353a5a1b3Sopenharmony_ci    for (unsigned channel = 0; channel < c->channels && l > 1; channel++) {
39453a5a1b3Sopenharmony_ci        char channel_position[32];
39553a5a1b3Sopenharmony_ci        size_t bytes_printed;
39653a5a1b3Sopenharmony_ci        char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX];
39753a5a1b3Sopenharmony_ci
39853a5a1b3Sopenharmony_ci        if (map)
39953a5a1b3Sopenharmony_ci            pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel]));
40053a5a1b3Sopenharmony_ci        else
40153a5a1b3Sopenharmony_ci            pa_snprintf(channel_position, sizeof(channel_position), "%u", channel);
40253a5a1b3Sopenharmony_ci
40353a5a1b3Sopenharmony_ci        bytes_printed = pa_snprintf(current, l, "%s%s: %s",
40453a5a1b3Sopenharmony_ci                                    first ? "" : ",   ",
40553a5a1b3Sopenharmony_ci                                    channel_position,
40653a5a1b3Sopenharmony_ci                                    pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB));
40753a5a1b3Sopenharmony_ci        l -= bytes_printed;
40853a5a1b3Sopenharmony_ci        current += bytes_printed;
40953a5a1b3Sopenharmony_ci        first = false;
41053a5a1b3Sopenharmony_ci    }
41153a5a1b3Sopenharmony_ci
41253a5a1b3Sopenharmony_ci    return s;
41353a5a1b3Sopenharmony_ci}
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_cichar *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) {
41653a5a1b3Sopenharmony_ci    double f;
41753a5a1b3Sopenharmony_ci
41853a5a1b3Sopenharmony_ci    pa_assert(s);
41953a5a1b3Sopenharmony_ci    pa_assert(l > 0);
42053a5a1b3Sopenharmony_ci
42153a5a1b3Sopenharmony_ci    pa_init_i18n();
42253a5a1b3Sopenharmony_ci
42353a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(v)) {
42453a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
42553a5a1b3Sopenharmony_ci        return s;
42653a5a1b3Sopenharmony_ci    }
42753a5a1b3Sopenharmony_ci
42853a5a1b3Sopenharmony_ci    f = pa_sw_volume_to_dB(v);
42953a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
43053a5a1b3Sopenharmony_ci
43153a5a1b3Sopenharmony_ci    return s;
43253a5a1b3Sopenharmony_ci}
43353a5a1b3Sopenharmony_ci
43453a5a1b3Sopenharmony_cichar *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) {
43553a5a1b3Sopenharmony_ci    char dB[PA_SW_VOLUME_SNPRINT_DB_MAX];
43653a5a1b3Sopenharmony_ci
43753a5a1b3Sopenharmony_ci    pa_assert(s);
43853a5a1b3Sopenharmony_ci    pa_assert(l > 0);
43953a5a1b3Sopenharmony_ci
44053a5a1b3Sopenharmony_ci    pa_init_i18n();
44153a5a1b3Sopenharmony_ci
44253a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(v)) {
44353a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
44453a5a1b3Sopenharmony_ci        return s;
44553a5a1b3Sopenharmony_ci    }
44653a5a1b3Sopenharmony_ci
44753a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s",
44853a5a1b3Sopenharmony_ci                v,
44953a5a1b3Sopenharmony_ci                (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM),
45053a5a1b3Sopenharmony_ci                print_dB ? " / " : "",
45153a5a1b3Sopenharmony_ci                print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : "");
45253a5a1b3Sopenharmony_ci
45353a5a1b3Sopenharmony_ci    return s;
45453a5a1b3Sopenharmony_ci}
45553a5a1b3Sopenharmony_ci
45653a5a1b3Sopenharmony_ciint pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
45753a5a1b3Sopenharmony_ci    unsigned c;
45853a5a1b3Sopenharmony_ci    pa_assert(a);
45953a5a1b3Sopenharmony_ci
46053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), 0);
46153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0);
46253a5a1b3Sopenharmony_ci
46353a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++)
46453a5a1b3Sopenharmony_ci        if (a->values[c] != v)
46553a5a1b3Sopenharmony_ci            return 0;
46653a5a1b3Sopenharmony_ci
46753a5a1b3Sopenharmony_ci    return 1;
46853a5a1b3Sopenharmony_ci}
46953a5a1b3Sopenharmony_ci
47053a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
47153a5a1b3Sopenharmony_ci    unsigned i;
47253a5a1b3Sopenharmony_ci
47353a5a1b3Sopenharmony_ci    pa_assert(dest);
47453a5a1b3Sopenharmony_ci    pa_assert(a);
47553a5a1b3Sopenharmony_ci    pa_assert(b);
47653a5a1b3Sopenharmony_ci
47753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
47853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
47953a5a1b3Sopenharmony_ci
48053a5a1b3Sopenharmony_ci    dest->channels = PA_MIN(a->channels, b->channels);
48153a5a1b3Sopenharmony_ci
48253a5a1b3Sopenharmony_ci    for (i = 0; i < dest->channels; i++)
48353a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
48453a5a1b3Sopenharmony_ci
48553a5a1b3Sopenharmony_ci    return dest;
48653a5a1b3Sopenharmony_ci}
48753a5a1b3Sopenharmony_ci
48853a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
48953a5a1b3Sopenharmony_ci    unsigned i;
49053a5a1b3Sopenharmony_ci
49153a5a1b3Sopenharmony_ci    pa_assert(dest);
49253a5a1b3Sopenharmony_ci    pa_assert(a);
49353a5a1b3Sopenharmony_ci
49453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
49553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL);
49653a5a1b3Sopenharmony_ci
49753a5a1b3Sopenharmony_ci    for (i = 0; i < a->channels; i++)
49853a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_multiply(a->values[i], b);
49953a5a1b3Sopenharmony_ci
50053a5a1b3Sopenharmony_ci    dest->channels = (uint8_t) i;
50153a5a1b3Sopenharmony_ci
50253a5a1b3Sopenharmony_ci    return dest;
50353a5a1b3Sopenharmony_ci}
50453a5a1b3Sopenharmony_ci
50553a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
50653a5a1b3Sopenharmony_ci    unsigned i;
50753a5a1b3Sopenharmony_ci
50853a5a1b3Sopenharmony_ci    pa_assert(dest);
50953a5a1b3Sopenharmony_ci    pa_assert(a);
51053a5a1b3Sopenharmony_ci    pa_assert(b);
51153a5a1b3Sopenharmony_ci
51253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
51353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
51453a5a1b3Sopenharmony_ci
51553a5a1b3Sopenharmony_ci    dest->channels = PA_MIN(a->channels, b->channels);
51653a5a1b3Sopenharmony_ci
51753a5a1b3Sopenharmony_ci    for (i = 0; i < dest->channels; i++)
51853a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
51953a5a1b3Sopenharmony_ci
52053a5a1b3Sopenharmony_ci    return dest;
52153a5a1b3Sopenharmony_ci}
52253a5a1b3Sopenharmony_ci
52353a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
52453a5a1b3Sopenharmony_ci    unsigned i;
52553a5a1b3Sopenharmony_ci
52653a5a1b3Sopenharmony_ci    pa_assert(dest);
52753a5a1b3Sopenharmony_ci    pa_assert(a);
52853a5a1b3Sopenharmony_ci
52953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
53053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL);
53153a5a1b3Sopenharmony_ci
53253a5a1b3Sopenharmony_ci    for (i = 0; i < a->channels; i++)
53353a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_divide(a->values[i], b);
53453a5a1b3Sopenharmony_ci
53553a5a1b3Sopenharmony_ci    dest->channels = (uint8_t) i;
53653a5a1b3Sopenharmony_ci
53753a5a1b3Sopenharmony_ci    return dest;
53853a5a1b3Sopenharmony_ci}
53953a5a1b3Sopenharmony_ci
54053a5a1b3Sopenharmony_ciint pa_cvolume_valid(const pa_cvolume *v) {
54153a5a1b3Sopenharmony_ci    unsigned c;
54253a5a1b3Sopenharmony_ci
54353a5a1b3Sopenharmony_ci    pa_assert(v);
54453a5a1b3Sopenharmony_ci
54553a5a1b3Sopenharmony_ci    if (!pa_channels_valid(v->channels))
54653a5a1b3Sopenharmony_ci        return 0;
54753a5a1b3Sopenharmony_ci
54853a5a1b3Sopenharmony_ci    for (c = 0; c < v->channels; c++)
54953a5a1b3Sopenharmony_ci        if (!PA_VOLUME_IS_VALID(v->values[c]))
55053a5a1b3Sopenharmony_ci            return 0;
55153a5a1b3Sopenharmony_ci
55253a5a1b3Sopenharmony_ci    return 1;
55353a5a1b3Sopenharmony_ci}
55453a5a1b3Sopenharmony_ci
55553a5a1b3Sopenharmony_cistatic bool on_left(pa_channel_position_t p) {
55653a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
55753a5a1b3Sopenharmony_ci}
55853a5a1b3Sopenharmony_ci
55953a5a1b3Sopenharmony_cistatic bool on_right(pa_channel_position_t p) {
56053a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
56153a5a1b3Sopenharmony_ci}
56253a5a1b3Sopenharmony_ci
56353a5a1b3Sopenharmony_cistatic bool on_center(pa_channel_position_t p) {
56453a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
56553a5a1b3Sopenharmony_ci}
56653a5a1b3Sopenharmony_ci
56753a5a1b3Sopenharmony_cistatic bool on_hfe(pa_channel_position_t p) {
56853a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_HFE);
56953a5a1b3Sopenharmony_ci}
57053a5a1b3Sopenharmony_ci
57153a5a1b3Sopenharmony_cistatic bool on_lfe(pa_channel_position_t p) {
57253a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LFE);
57353a5a1b3Sopenharmony_ci}
57453a5a1b3Sopenharmony_ci
57553a5a1b3Sopenharmony_cistatic bool on_front(pa_channel_position_t p) {
57653a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
57753a5a1b3Sopenharmony_ci}
57853a5a1b3Sopenharmony_ci
57953a5a1b3Sopenharmony_cistatic bool on_rear(pa_channel_position_t p) {
58053a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
58153a5a1b3Sopenharmony_ci}
58253a5a1b3Sopenharmony_ci
58353a5a1b3Sopenharmony_cipa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) {
58453a5a1b3Sopenharmony_ci    int a, b;
58553a5a1b3Sopenharmony_ci    pa_cvolume result;
58653a5a1b3Sopenharmony_ci
58753a5a1b3Sopenharmony_ci    pa_assert(v);
58853a5a1b3Sopenharmony_ci    pa_assert(from);
58953a5a1b3Sopenharmony_ci    pa_assert(to);
59053a5a1b3Sopenharmony_ci
59153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_channel_map_valid(to), NULL);
59253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
59353a5a1b3Sopenharmony_ci
59453a5a1b3Sopenharmony_ci    if (pa_channel_map_equal(from, to))
59553a5a1b3Sopenharmony_ci        return v;
59653a5a1b3Sopenharmony_ci
59753a5a1b3Sopenharmony_ci    result.channels = to->channels;
59853a5a1b3Sopenharmony_ci
59953a5a1b3Sopenharmony_ci    for (b = 0; b < to->channels; b++) {
60053a5a1b3Sopenharmony_ci        pa_volume_t k = 0;
60153a5a1b3Sopenharmony_ci        int n = 0;
60253a5a1b3Sopenharmony_ci
60353a5a1b3Sopenharmony_ci        for (a = 0; a < from->channels; a++)
60453a5a1b3Sopenharmony_ci            if (from->map[a] == to->map[b]) {
60553a5a1b3Sopenharmony_ci                k += v->values[a];
60653a5a1b3Sopenharmony_ci                n ++;
60753a5a1b3Sopenharmony_ci            }
60853a5a1b3Sopenharmony_ci
60953a5a1b3Sopenharmony_ci        if (n <= 0) {
61053a5a1b3Sopenharmony_ci            for (a = 0; a < from->channels; a++)
61153a5a1b3Sopenharmony_ci                if ((on_left(from->map[a]) && on_left(to->map[b])) ||
61253a5a1b3Sopenharmony_ci                    (on_right(from->map[a]) && on_right(to->map[b])) ||
61353a5a1b3Sopenharmony_ci                    (on_center(from->map[a]) && on_center(to->map[b])) ||
61453a5a1b3Sopenharmony_ci                    (on_lfe(from->map[a]) && on_lfe(to->map[b]))) {
61553a5a1b3Sopenharmony_ci
61653a5a1b3Sopenharmony_ci                    k += v->values[a];
61753a5a1b3Sopenharmony_ci                    n ++;
61853a5a1b3Sopenharmony_ci                }
61953a5a1b3Sopenharmony_ci        }
62053a5a1b3Sopenharmony_ci
62153a5a1b3Sopenharmony_ci        if (n <= 0)
62253a5a1b3Sopenharmony_ci            k = pa_cvolume_avg(v);
62353a5a1b3Sopenharmony_ci        else
62453a5a1b3Sopenharmony_ci            k /= n;
62553a5a1b3Sopenharmony_ci
62653a5a1b3Sopenharmony_ci        result.values[b] = k;
62753a5a1b3Sopenharmony_ci    }
62853a5a1b3Sopenharmony_ci
62953a5a1b3Sopenharmony_ci    *v = result;
63053a5a1b3Sopenharmony_ci    return v;
63153a5a1b3Sopenharmony_ci}
63253a5a1b3Sopenharmony_ci
63353a5a1b3Sopenharmony_ciint pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) {
63453a5a1b3Sopenharmony_ci
63553a5a1b3Sopenharmony_ci    pa_assert(v);
63653a5a1b3Sopenharmony_ci    pa_assert(ss);
63753a5a1b3Sopenharmony_ci
63853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), 0);
63953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
64053a5a1b3Sopenharmony_ci
64153a5a1b3Sopenharmony_ci    return v->channels == ss->channels;
64253a5a1b3Sopenharmony_ci}
64353a5a1b3Sopenharmony_ci
64453a5a1b3Sopenharmony_ciint pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) {
64553a5a1b3Sopenharmony_ci    pa_assert(v);
64653a5a1b3Sopenharmony_ci    pa_assert(cm);
64753a5a1b3Sopenharmony_ci
64853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), 0);
64953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_channel_map_valid(cm), 0);
65053a5a1b3Sopenharmony_ci
65153a5a1b3Sopenharmony_ci    return v->channels == cm->channels;
65253a5a1b3Sopenharmony_ci}
65353a5a1b3Sopenharmony_ci
65453a5a1b3Sopenharmony_ci/*
65553a5a1b3Sopenharmony_ci * Returns the average volume of l and r, where l and r are two disjoint sets of channels
65653a5a1b3Sopenharmony_ci * (e g left and right, or front and rear).
65753a5a1b3Sopenharmony_ci */
65853a5a1b3Sopenharmony_cistatic void get_avg(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r,
65953a5a1b3Sopenharmony_ci                    bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) {
66053a5a1b3Sopenharmony_ci    int c;
66153a5a1b3Sopenharmony_ci    pa_volume_t left = 0, right = 0;
66253a5a1b3Sopenharmony_ci    unsigned n_left = 0, n_right = 0;
66353a5a1b3Sopenharmony_ci
66453a5a1b3Sopenharmony_ci    pa_assert(v);
66553a5a1b3Sopenharmony_ci    pa_assert(map);
66653a5a1b3Sopenharmony_ci    pa_assert(map->channels == v->channels);
66753a5a1b3Sopenharmony_ci    pa_assert(l);
66853a5a1b3Sopenharmony_ci    pa_assert(r);
66953a5a1b3Sopenharmony_ci
67053a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++) {
67153a5a1b3Sopenharmony_ci        if (on_l(map->map[c])) {
67253a5a1b3Sopenharmony_ci            left += v->values[c];
67353a5a1b3Sopenharmony_ci            n_left++;
67453a5a1b3Sopenharmony_ci        } else if (on_r(map->map[c])) {
67553a5a1b3Sopenharmony_ci            right += v->values[c];
67653a5a1b3Sopenharmony_ci            n_right++;
67753a5a1b3Sopenharmony_ci        }
67853a5a1b3Sopenharmony_ci    }
67953a5a1b3Sopenharmony_ci
68053a5a1b3Sopenharmony_ci    if (n_left <= 0)
68153a5a1b3Sopenharmony_ci        *l = PA_VOLUME_NORM;
68253a5a1b3Sopenharmony_ci    else
68353a5a1b3Sopenharmony_ci        *l = left / n_left;
68453a5a1b3Sopenharmony_ci
68553a5a1b3Sopenharmony_ci    if (n_right <= 0)
68653a5a1b3Sopenharmony_ci        *r = PA_VOLUME_NORM;
68753a5a1b3Sopenharmony_ci    else
68853a5a1b3Sopenharmony_ci        *r = right / n_right;
68953a5a1b3Sopenharmony_ci}
69053a5a1b3Sopenharmony_ci
69153a5a1b3Sopenharmony_cifloat pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) {
69253a5a1b3Sopenharmony_ci    pa_volume_t left, right;
69353a5a1b3Sopenharmony_ci
69453a5a1b3Sopenharmony_ci    pa_assert(v);
69553a5a1b3Sopenharmony_ci    pa_assert(map);
69653a5a1b3Sopenharmony_ci
69753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
69853a5a1b3Sopenharmony_ci
69953a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_balance(map))
70053a5a1b3Sopenharmony_ci        return 0.0f;
70153a5a1b3Sopenharmony_ci
70253a5a1b3Sopenharmony_ci    get_avg(map, v, &left, &right, on_left, on_right);
70353a5a1b3Sopenharmony_ci
70453a5a1b3Sopenharmony_ci    if (left == right)
70553a5a1b3Sopenharmony_ci        return 0.0f;
70653a5a1b3Sopenharmony_ci
70753a5a1b3Sopenharmony_ci    /*   1.0,  0.0  =>  -1.0
70853a5a1b3Sopenharmony_ci         0.0,  1.0  =>   1.0
70953a5a1b3Sopenharmony_ci         0.0,  0.0  =>   0.0
71053a5a1b3Sopenharmony_ci         0.5,  0.5  =>   0.0
71153a5a1b3Sopenharmony_ci         1.0,  0.5  =>  -0.5
71253a5a1b3Sopenharmony_ci         1.0,  0.25 => -0.75
71353a5a1b3Sopenharmony_ci         0.75, 0.25 => -0.66
71453a5a1b3Sopenharmony_ci         0.5,  0.25 => -0.5   */
71553a5a1b3Sopenharmony_ci
71653a5a1b3Sopenharmony_ci    if (left > right)
71753a5a1b3Sopenharmony_ci        return -1.0f + ((float) right / (float) left);
71853a5a1b3Sopenharmony_ci    else
71953a5a1b3Sopenharmony_ci        return 1.0f - ((float) left / (float) right);
72053a5a1b3Sopenharmony_ci}
72153a5a1b3Sopenharmony_ci
72253a5a1b3Sopenharmony_cistatic pa_cvolume* set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance,
72353a5a1b3Sopenharmony_ci                               bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) {
72453a5a1b3Sopenharmony_ci
72553a5a1b3Sopenharmony_ci    pa_volume_t left, nleft, right, nright, m;
72653a5a1b3Sopenharmony_ci    unsigned c;
72753a5a1b3Sopenharmony_ci
72853a5a1b3Sopenharmony_ci    get_avg(map, v, &left, &right, on_l, on_r);
72953a5a1b3Sopenharmony_ci
73053a5a1b3Sopenharmony_ci    m = PA_MAX(left, right);
73153a5a1b3Sopenharmony_ci
73253a5a1b3Sopenharmony_ci    if (new_balance <= 0) {
73353a5a1b3Sopenharmony_ci        nright = (new_balance + 1.0f) * m;
73453a5a1b3Sopenharmony_ci        nleft = m;
73553a5a1b3Sopenharmony_ci    } else {
73653a5a1b3Sopenharmony_ci        nleft = (1.0f - new_balance) * m;
73753a5a1b3Sopenharmony_ci        nright = m;
73853a5a1b3Sopenharmony_ci    }
73953a5a1b3Sopenharmony_ci
74053a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++) {
74153a5a1b3Sopenharmony_ci        if (on_l(map->map[c])) {
74253a5a1b3Sopenharmony_ci            if (left == 0)
74353a5a1b3Sopenharmony_ci                v->values[c] = nleft;
74453a5a1b3Sopenharmony_ci            else
74553a5a1b3Sopenharmony_ci                v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left);
74653a5a1b3Sopenharmony_ci        } else if (on_r(map->map[c])) {
74753a5a1b3Sopenharmony_ci            if (right == 0)
74853a5a1b3Sopenharmony_ci                v->values[c] = nright;
74953a5a1b3Sopenharmony_ci            else
75053a5a1b3Sopenharmony_ci                v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right);
75153a5a1b3Sopenharmony_ci        }
75253a5a1b3Sopenharmony_ci    }
75353a5a1b3Sopenharmony_ci
75453a5a1b3Sopenharmony_ci    return v;
75553a5a1b3Sopenharmony_ci}
75653a5a1b3Sopenharmony_ci
75753a5a1b3Sopenharmony_ci
75853a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
75953a5a1b3Sopenharmony_ci    pa_assert(map);
76053a5a1b3Sopenharmony_ci    pa_assert(v);
76153a5a1b3Sopenharmony_ci
76253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
76353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance >= -1.0f, NULL);
76453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance <= 1.0f, NULL);
76553a5a1b3Sopenharmony_ci
76653a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_balance(map))
76753a5a1b3Sopenharmony_ci        return v;
76853a5a1b3Sopenharmony_ci
76953a5a1b3Sopenharmony_ci    return set_balance(v, map, new_balance, on_left, on_right);
77053a5a1b3Sopenharmony_ci}
77153a5a1b3Sopenharmony_ci
77253a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) {
77353a5a1b3Sopenharmony_ci    unsigned c;
77453a5a1b3Sopenharmony_ci    pa_volume_t t = 0;
77553a5a1b3Sopenharmony_ci
77653a5a1b3Sopenharmony_ci    pa_assert(v);
77753a5a1b3Sopenharmony_ci
77853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
77953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
78053a5a1b3Sopenharmony_ci
78153a5a1b3Sopenharmony_ci    t = pa_cvolume_max(v);
78253a5a1b3Sopenharmony_ci
78353a5a1b3Sopenharmony_ci    if (t <= PA_VOLUME_MUTED)
78453a5a1b3Sopenharmony_ci        return pa_cvolume_set(v, v->channels, max);
78553a5a1b3Sopenharmony_ci
78653a5a1b3Sopenharmony_ci    for (c = 0; c < v->channels; c++)
78753a5a1b3Sopenharmony_ci        v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
78853a5a1b3Sopenharmony_ci
78953a5a1b3Sopenharmony_ci    return v;
79053a5a1b3Sopenharmony_ci}
79153a5a1b3Sopenharmony_ci
79253a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
79353a5a1b3Sopenharmony_ci    unsigned c;
79453a5a1b3Sopenharmony_ci    pa_volume_t t = 0;
79553a5a1b3Sopenharmony_ci
79653a5a1b3Sopenharmony_ci    pa_assert(v);
79753a5a1b3Sopenharmony_ci
79853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
79953a5a1b3Sopenharmony_ci
80053a5a1b3Sopenharmony_ci    if (!cm)
80153a5a1b3Sopenharmony_ci        return pa_cvolume_scale(v, max);
80253a5a1b3Sopenharmony_ci
80353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL);
80453a5a1b3Sopenharmony_ci
80553a5a1b3Sopenharmony_ci    t = pa_cvolume_max_mask(v, cm, mask);
80653a5a1b3Sopenharmony_ci
80753a5a1b3Sopenharmony_ci    if (t <= PA_VOLUME_MUTED)
80853a5a1b3Sopenharmony_ci        return pa_cvolume_set(v, v->channels, max);
80953a5a1b3Sopenharmony_ci
81053a5a1b3Sopenharmony_ci    for (c = 0; c < v->channels; c++)
81153a5a1b3Sopenharmony_ci        v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
81253a5a1b3Sopenharmony_ci
81353a5a1b3Sopenharmony_ci    return v;
81453a5a1b3Sopenharmony_ci}
81553a5a1b3Sopenharmony_ci
81653a5a1b3Sopenharmony_cifloat pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) {
81753a5a1b3Sopenharmony_ci    pa_volume_t rear, front;
81853a5a1b3Sopenharmony_ci
81953a5a1b3Sopenharmony_ci    pa_assert(v);
82053a5a1b3Sopenharmony_ci    pa_assert(map);
82153a5a1b3Sopenharmony_ci
82253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
82353a5a1b3Sopenharmony_ci
82453a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_fade(map))
82553a5a1b3Sopenharmony_ci        return 0.0f;
82653a5a1b3Sopenharmony_ci
82753a5a1b3Sopenharmony_ci    get_avg(map, v, &rear, &front, on_rear, on_front);
82853a5a1b3Sopenharmony_ci
82953a5a1b3Sopenharmony_ci    if (front == rear)
83053a5a1b3Sopenharmony_ci        return 0.0f;
83153a5a1b3Sopenharmony_ci
83253a5a1b3Sopenharmony_ci    if (rear > front)
83353a5a1b3Sopenharmony_ci        return -1.0f + ((float) front / (float) rear);
83453a5a1b3Sopenharmony_ci    else
83553a5a1b3Sopenharmony_ci        return 1.0f - ((float) rear / (float) front);
83653a5a1b3Sopenharmony_ci}
83753a5a1b3Sopenharmony_ci
83853a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) {
83953a5a1b3Sopenharmony_ci    pa_assert(map);
84053a5a1b3Sopenharmony_ci    pa_assert(v);
84153a5a1b3Sopenharmony_ci
84253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
84353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_fade >= -1.0f, NULL);
84453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_fade <= 1.0f, NULL);
84553a5a1b3Sopenharmony_ci
84653a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_fade(map))
84753a5a1b3Sopenharmony_ci        return v;
84853a5a1b3Sopenharmony_ci
84953a5a1b3Sopenharmony_ci    return set_balance(v, map, new_fade, on_rear, on_front);
85053a5a1b3Sopenharmony_ci}
85153a5a1b3Sopenharmony_ci
85253a5a1b3Sopenharmony_cifloat pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) {
85353a5a1b3Sopenharmony_ci    pa_volume_t hfe, lfe;
85453a5a1b3Sopenharmony_ci
85553a5a1b3Sopenharmony_ci    pa_assert(v);
85653a5a1b3Sopenharmony_ci    pa_assert(map);
85753a5a1b3Sopenharmony_ci
85853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
85953a5a1b3Sopenharmony_ci
86053a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_lfe_balance(map))
86153a5a1b3Sopenharmony_ci        return 0.0f;
86253a5a1b3Sopenharmony_ci
86353a5a1b3Sopenharmony_ci    get_avg(map, v, &hfe, &lfe, on_hfe, on_lfe);
86453a5a1b3Sopenharmony_ci
86553a5a1b3Sopenharmony_ci    if (hfe == lfe)
86653a5a1b3Sopenharmony_ci        return 0.0f;
86753a5a1b3Sopenharmony_ci
86853a5a1b3Sopenharmony_ci    if (hfe > lfe)
86953a5a1b3Sopenharmony_ci        return -1.0f + ((float) lfe / (float) hfe);
87053a5a1b3Sopenharmony_ci    else
87153a5a1b3Sopenharmony_ci        return 1.0f - ((float) hfe / (float) lfe);
87253a5a1b3Sopenharmony_ci}
87353a5a1b3Sopenharmony_ci
87453a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
87553a5a1b3Sopenharmony_ci    pa_assert(map);
87653a5a1b3Sopenharmony_ci    pa_assert(v);
87753a5a1b3Sopenharmony_ci
87853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
87953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance >= -1.0f, NULL);
88053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance <= 1.0f, NULL);
88153a5a1b3Sopenharmony_ci
88253a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_lfe_balance(map))
88353a5a1b3Sopenharmony_ci        return v;
88453a5a1b3Sopenharmony_ci
88553a5a1b3Sopenharmony_ci    return set_balance(v, map, new_balance, on_hfe, on_lfe);
88653a5a1b3Sopenharmony_ci}
88753a5a1b3Sopenharmony_ci
88853a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_position(
88953a5a1b3Sopenharmony_ci        pa_cvolume *cv,
89053a5a1b3Sopenharmony_ci        const pa_channel_map *map,
89153a5a1b3Sopenharmony_ci        pa_channel_position_t t,
89253a5a1b3Sopenharmony_ci        pa_volume_t v) {
89353a5a1b3Sopenharmony_ci
89453a5a1b3Sopenharmony_ci    unsigned c;
89553a5a1b3Sopenharmony_ci    bool good = false;
89653a5a1b3Sopenharmony_ci
89753a5a1b3Sopenharmony_ci    pa_assert(cv);
89853a5a1b3Sopenharmony_ci    pa_assert(map);
89953a5a1b3Sopenharmony_ci
90053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
90153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
90253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL);
90353a5a1b3Sopenharmony_ci
90453a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++)
90553a5a1b3Sopenharmony_ci        if (map->map[c] == t) {
90653a5a1b3Sopenharmony_ci            cv->values[c] = v;
90753a5a1b3Sopenharmony_ci            good = true;
90853a5a1b3Sopenharmony_ci        }
90953a5a1b3Sopenharmony_ci
91053a5a1b3Sopenharmony_ci    return good ? cv : NULL;
91153a5a1b3Sopenharmony_ci}
91253a5a1b3Sopenharmony_ci
91353a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_get_position(
91453a5a1b3Sopenharmony_ci        const pa_cvolume *cv,
91553a5a1b3Sopenharmony_ci        const pa_channel_map *map,
91653a5a1b3Sopenharmony_ci        pa_channel_position_t t) {
91753a5a1b3Sopenharmony_ci
91853a5a1b3Sopenharmony_ci    unsigned c;
91953a5a1b3Sopenharmony_ci    pa_volume_t v = PA_VOLUME_MUTED;
92053a5a1b3Sopenharmony_ci
92153a5a1b3Sopenharmony_ci    pa_assert(cv);
92253a5a1b3Sopenharmony_ci    pa_assert(map);
92353a5a1b3Sopenharmony_ci
92453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
92553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
92653a5a1b3Sopenharmony_ci
92753a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++)
92853a5a1b3Sopenharmony_ci        if (map->map[c] == t)
92953a5a1b3Sopenharmony_ci            if (cv->values[c] > v)
93053a5a1b3Sopenharmony_ci                v = cv->values[c];
93153a5a1b3Sopenharmony_ci
93253a5a1b3Sopenharmony_ci    return v;
93353a5a1b3Sopenharmony_ci}
93453a5a1b3Sopenharmony_ci
93553a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
93653a5a1b3Sopenharmony_ci    unsigned i;
93753a5a1b3Sopenharmony_ci
93853a5a1b3Sopenharmony_ci    pa_assert(dest);
93953a5a1b3Sopenharmony_ci    pa_assert(a);
94053a5a1b3Sopenharmony_ci    pa_assert(b);
94153a5a1b3Sopenharmony_ci
94253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
94353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
94453a5a1b3Sopenharmony_ci
94553a5a1b3Sopenharmony_ci    dest->channels = PA_MIN(a->channels, b->channels);
94653a5a1b3Sopenharmony_ci
94753a5a1b3Sopenharmony_ci    for (i = 0; i < dest->channels; i++)
94853a5a1b3Sopenharmony_ci        dest->values[i] = PA_MAX(a->values[i], b->values[i]);
94953a5a1b3Sopenharmony_ci
95053a5a1b3Sopenharmony_ci    return dest;
95153a5a1b3Sopenharmony_ci}
95253a5a1b3Sopenharmony_ci
95353a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) {
95453a5a1b3Sopenharmony_ci    pa_volume_t m;
95553a5a1b3Sopenharmony_ci
95653a5a1b3Sopenharmony_ci    pa_assert(v);
95753a5a1b3Sopenharmony_ci
95853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
95953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL);
96053a5a1b3Sopenharmony_ci
96153a5a1b3Sopenharmony_ci    m = pa_cvolume_max(v);
96253a5a1b3Sopenharmony_ci
96353a5a1b3Sopenharmony_ci    if (m >= limit - inc)
96453a5a1b3Sopenharmony_ci        m = limit;
96553a5a1b3Sopenharmony_ci    else
96653a5a1b3Sopenharmony_ci        m += inc;
96753a5a1b3Sopenharmony_ci
96853a5a1b3Sopenharmony_ci    return pa_cvolume_scale(v, m);
96953a5a1b3Sopenharmony_ci}
97053a5a1b3Sopenharmony_ci
97153a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) {
97253a5a1b3Sopenharmony_ci    return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX);
97353a5a1b3Sopenharmony_ci}
97453a5a1b3Sopenharmony_ci
97553a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) {
97653a5a1b3Sopenharmony_ci    pa_volume_t m;
97753a5a1b3Sopenharmony_ci
97853a5a1b3Sopenharmony_ci    pa_assert(v);
97953a5a1b3Sopenharmony_ci
98053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
98153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL);
98253a5a1b3Sopenharmony_ci
98353a5a1b3Sopenharmony_ci    m = pa_cvolume_max(v);
98453a5a1b3Sopenharmony_ci
98553a5a1b3Sopenharmony_ci    if (m <= PA_VOLUME_MUTED + dec)
98653a5a1b3Sopenharmony_ci        m = PA_VOLUME_MUTED;
98753a5a1b3Sopenharmony_ci    else
98853a5a1b3Sopenharmony_ci        m -= dec;
98953a5a1b3Sopenharmony_ci
99053a5a1b3Sopenharmony_ci    return pa_cvolume_scale(v, m);
99153a5a1b3Sopenharmony_ci}
992