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#ifdef __MUSL__
24553a5a1b3Sopenharmony_ci    if (dB == -INFINITY || dB <= PA_DECIBEL_MININFTY)
24653a5a1b3Sopenharmony_ci        return PA_VOLUME_MUTED;
24753a5a1b3Sopenharmony_ci#else
24853a5a1b3Sopenharmony_ci    if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY)
24953a5a1b3Sopenharmony_ci        return PA_VOLUME_MUTED;
25053a5a1b3Sopenharmony_ci#endif // __MUSL__
25153a5a1b3Sopenharmony_ci
25253a5a1b3Sopenharmony_ci    return pa_sw_volume_from_linear(dB_to_linear(dB));
25353a5a1b3Sopenharmony_ci}
25453a5a1b3Sopenharmony_ci
25553a5a1b3Sopenharmony_cidouble pa_sw_volume_to_dB(pa_volume_t v) {
25653a5a1b3Sopenharmony_ci
25753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY);
25853a5a1b3Sopenharmony_ci
25953a5a1b3Sopenharmony_ci    if (v <= PA_VOLUME_MUTED)
26053a5a1b3Sopenharmony_ci        return PA_DECIBEL_MININFTY;
26153a5a1b3Sopenharmony_ci
26253a5a1b3Sopenharmony_ci    return linear_to_dB(pa_sw_volume_to_linear(v));
26353a5a1b3Sopenharmony_ci}
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_cipa_volume_t pa_sw_volume_from_linear(double v) {
26653a5a1b3Sopenharmony_ci
26753a5a1b3Sopenharmony_ci    if (v <= 0.0)
26853a5a1b3Sopenharmony_ci        return PA_VOLUME_MUTED;
26953a5a1b3Sopenharmony_ci
27053a5a1b3Sopenharmony_ci    /*
27153a5a1b3Sopenharmony_ci     * We use a cubic mapping here, as suggested and discussed here:
27253a5a1b3Sopenharmony_ci     *
27353a5a1b3Sopenharmony_ci     * http://www.robotplanet.dk/audio/audio_gui_design/
27453a5a1b3Sopenharmony_ci     * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151
27553a5a1b3Sopenharmony_ci     *
27653a5a1b3Sopenharmony_ci     * We make sure that the conversion to linear and back yields the
27753a5a1b3Sopenharmony_ci     * same volume value! That's why we need the lround() below!
27853a5a1b3Sopenharmony_ci     */
27953a5a1b3Sopenharmony_ci
28053a5a1b3Sopenharmony_ci    return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM));
28153a5a1b3Sopenharmony_ci}
28253a5a1b3Sopenharmony_ci
28353a5a1b3Sopenharmony_cidouble pa_sw_volume_to_linear(pa_volume_t v) {
28453a5a1b3Sopenharmony_ci    double f;
28553a5a1b3Sopenharmony_ci
28653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0);
28753a5a1b3Sopenharmony_ci
28853a5a1b3Sopenharmony_ci    if (v <= PA_VOLUME_MUTED)
28953a5a1b3Sopenharmony_ci        return 0.0;
29053a5a1b3Sopenharmony_ci
29153a5a1b3Sopenharmony_ci    if (v == PA_VOLUME_NORM)
29253a5a1b3Sopenharmony_ci        return 1.0;
29353a5a1b3Sopenharmony_ci
29453a5a1b3Sopenharmony_ci    f = ((double) v / PA_VOLUME_NORM);
29553a5a1b3Sopenharmony_ci
29653a5a1b3Sopenharmony_ci    return f*f*f;
29753a5a1b3Sopenharmony_ci}
29853a5a1b3Sopenharmony_ci
29953a5a1b3Sopenharmony_cichar *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) {
30053a5a1b3Sopenharmony_ci    unsigned channel;
30153a5a1b3Sopenharmony_ci    bool first = true;
30253a5a1b3Sopenharmony_ci    char *e;
30353a5a1b3Sopenharmony_ci
30453a5a1b3Sopenharmony_ci    pa_assert(s);
30553a5a1b3Sopenharmony_ci    pa_assert(l > 0);
30653a5a1b3Sopenharmony_ci    pa_assert(c);
30753a5a1b3Sopenharmony_ci
30853a5a1b3Sopenharmony_ci    pa_init_i18n();
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci    if (!pa_cvolume_valid(c)) {
31153a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
31253a5a1b3Sopenharmony_ci        return s;
31353a5a1b3Sopenharmony_ci    }
31453a5a1b3Sopenharmony_ci
31553a5a1b3Sopenharmony_ci    *(e = s) = 0;
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci    for (channel = 0; channel < c->channels && l > 1; channel++) {
31853a5a1b3Sopenharmony_ci        l -= pa_snprintf(e, l, "%s%u: %3u%%",
31953a5a1b3Sopenharmony_ci                      first ? "" : " ",
32053a5a1b3Sopenharmony_ci                      channel,
32153a5a1b3Sopenharmony_ci                      (unsigned)(((uint64_t)c->values[channel] * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM));
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci        e = strchr(e, 0);
32453a5a1b3Sopenharmony_ci        first = false;
32553a5a1b3Sopenharmony_ci    }
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ci    return s;
32853a5a1b3Sopenharmony_ci}
32953a5a1b3Sopenharmony_ci
33053a5a1b3Sopenharmony_cichar *pa_volume_snprint(char *s, size_t l, pa_volume_t v) {
33153a5a1b3Sopenharmony_ci    pa_assert(s);
33253a5a1b3Sopenharmony_ci    pa_assert(l > 0);
33353a5a1b3Sopenharmony_ci
33453a5a1b3Sopenharmony_ci    pa_init_i18n();
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(v)) {
33753a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
33853a5a1b3Sopenharmony_ci        return s;
33953a5a1b3Sopenharmony_ci    }
34053a5a1b3Sopenharmony_ci
34153a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%3u%%", (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM));
34253a5a1b3Sopenharmony_ci    return s;
34353a5a1b3Sopenharmony_ci}
34453a5a1b3Sopenharmony_ci
34553a5a1b3Sopenharmony_cichar *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) {
34653a5a1b3Sopenharmony_ci    unsigned channel;
34753a5a1b3Sopenharmony_ci    bool first = true;
34853a5a1b3Sopenharmony_ci    char *e;
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci    pa_assert(s);
35153a5a1b3Sopenharmony_ci    pa_assert(l > 0);
35253a5a1b3Sopenharmony_ci    pa_assert(c);
35353a5a1b3Sopenharmony_ci
35453a5a1b3Sopenharmony_ci    pa_init_i18n();
35553a5a1b3Sopenharmony_ci
35653a5a1b3Sopenharmony_ci    if (!pa_cvolume_valid(c)) {
35753a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
35853a5a1b3Sopenharmony_ci        return s;
35953a5a1b3Sopenharmony_ci    }
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_ci    *(e = s) = 0;
36253a5a1b3Sopenharmony_ci
36353a5a1b3Sopenharmony_ci    for (channel = 0; channel < c->channels && l > 1; channel++) {
36453a5a1b3Sopenharmony_ci        double f = pa_sw_volume_to_dB(c->values[channel]);
36553a5a1b3Sopenharmony_ci
36653a5a1b3Sopenharmony_ci#ifdef __MUSL__
36753a5a1b3Sopenharmony_ci	l -= pa_snprintf(e, l, "%s%u: %0.2f dB",
36853a5a1b3Sopenharmony_ci                         first ? "" : " ",
36953a5a1b3Sopenharmony_ci                         channel,
37053a5a1b3Sopenharmony_ci                         f == -INFINITY || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
37153a5a1b3Sopenharmony_ci#else
37253a5a1b3Sopenharmony_ci        l -= pa_snprintf(e, l, "%s%u: %0.2f dB",
37353a5a1b3Sopenharmony_ci	                 first ? "" : " ",
37453a5a1b3Sopenharmony_ci                         channel,
37553a5a1b3Sopenharmony_ci                         isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
37653a5a1b3Sopenharmony_ci#endif // __MUSL__
37753a5a1b3Sopenharmony_ci
37853a5a1b3Sopenharmony_ci        e = strchr(e, 0);
37953a5a1b3Sopenharmony_ci        first = false;
38053a5a1b3Sopenharmony_ci    }
38153a5a1b3Sopenharmony_ci
38253a5a1b3Sopenharmony_ci    return s;
38353a5a1b3Sopenharmony_ci}
38453a5a1b3Sopenharmony_ci
38553a5a1b3Sopenharmony_cichar *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) {
38653a5a1b3Sopenharmony_ci    char *current = s;
38753a5a1b3Sopenharmony_ci    bool first = true;
38853a5a1b3Sopenharmony_ci
38953a5a1b3Sopenharmony_ci    pa_assert(s);
39053a5a1b3Sopenharmony_ci    pa_assert(l > 0);
39153a5a1b3Sopenharmony_ci    pa_assert(c);
39253a5a1b3Sopenharmony_ci
39353a5a1b3Sopenharmony_ci    pa_init_i18n();
39453a5a1b3Sopenharmony_ci
39553a5a1b3Sopenharmony_ci    if (!pa_cvolume_valid(c)) {
39653a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
39753a5a1b3Sopenharmony_ci        return s;
39853a5a1b3Sopenharmony_ci    }
39953a5a1b3Sopenharmony_ci
40053a5a1b3Sopenharmony_ci    pa_assert(!map || (map->channels == c->channels));
40153a5a1b3Sopenharmony_ci    pa_assert(!map || pa_channel_map_valid(map));
40253a5a1b3Sopenharmony_ci
40353a5a1b3Sopenharmony_ci    current[0] = 0;
40453a5a1b3Sopenharmony_ci
40553a5a1b3Sopenharmony_ci    for (unsigned channel = 0; channel < c->channels && l > 1; channel++) {
40653a5a1b3Sopenharmony_ci        char channel_position[32];
40753a5a1b3Sopenharmony_ci        size_t bytes_printed;
40853a5a1b3Sopenharmony_ci        char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX];
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci        if (map)
41153a5a1b3Sopenharmony_ci            pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel]));
41253a5a1b3Sopenharmony_ci        else
41353a5a1b3Sopenharmony_ci            pa_snprintf(channel_position, sizeof(channel_position), "%u", channel);
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_ci        bytes_printed = pa_snprintf(current, l, "%s%s: %s",
41653a5a1b3Sopenharmony_ci                                    first ? "" : ",   ",
41753a5a1b3Sopenharmony_ci                                    channel_position,
41853a5a1b3Sopenharmony_ci                                    pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB));
41953a5a1b3Sopenharmony_ci        l -= bytes_printed;
42053a5a1b3Sopenharmony_ci        current += bytes_printed;
42153a5a1b3Sopenharmony_ci        first = false;
42253a5a1b3Sopenharmony_ci    }
42353a5a1b3Sopenharmony_ci
42453a5a1b3Sopenharmony_ci    return s;
42553a5a1b3Sopenharmony_ci}
42653a5a1b3Sopenharmony_ci
42753a5a1b3Sopenharmony_cichar *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) {
42853a5a1b3Sopenharmony_ci    double f;
42953a5a1b3Sopenharmony_ci
43053a5a1b3Sopenharmony_ci    pa_assert(s);
43153a5a1b3Sopenharmony_ci    pa_assert(l > 0);
43253a5a1b3Sopenharmony_ci
43353a5a1b3Sopenharmony_ci    pa_init_i18n();
43453a5a1b3Sopenharmony_ci
43553a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(v)) {
43653a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
43753a5a1b3Sopenharmony_ci        return s;
43853a5a1b3Sopenharmony_ci    }
43953a5a1b3Sopenharmony_ci
44053a5a1b3Sopenharmony_ci    f = pa_sw_volume_to_dB(v);
44153a5a1b3Sopenharmony_ci#ifdef __MUSL__
44253a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%0.2f dB", f == -INFINITY || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
44353a5a1b3Sopenharmony_ci#else
44453a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
44553a5a1b3Sopenharmony_ci#endif // __MUSL__
44653a5a1b3Sopenharmony_ci
44753a5a1b3Sopenharmony_ci    return s;
44853a5a1b3Sopenharmony_ci}
44953a5a1b3Sopenharmony_ci
45053a5a1b3Sopenharmony_cichar *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) {
45153a5a1b3Sopenharmony_ci    char dB[PA_SW_VOLUME_SNPRINT_DB_MAX];
45253a5a1b3Sopenharmony_ci
45353a5a1b3Sopenharmony_ci    pa_assert(s);
45453a5a1b3Sopenharmony_ci    pa_assert(l > 0);
45553a5a1b3Sopenharmony_ci
45653a5a1b3Sopenharmony_ci    pa_init_i18n();
45753a5a1b3Sopenharmony_ci
45853a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(v)) {
45953a5a1b3Sopenharmony_ci        pa_snprintf(s, l, _("(invalid)"));
46053a5a1b3Sopenharmony_ci        return s;
46153a5a1b3Sopenharmony_ci    }
46253a5a1b3Sopenharmony_ci
46353a5a1b3Sopenharmony_ci    pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s",
46453a5a1b3Sopenharmony_ci                v,
46553a5a1b3Sopenharmony_ci                (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM),
46653a5a1b3Sopenharmony_ci                print_dB ? " / " : "",
46753a5a1b3Sopenharmony_ci                print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : "");
46853a5a1b3Sopenharmony_ci
46953a5a1b3Sopenharmony_ci    return s;
47053a5a1b3Sopenharmony_ci}
47153a5a1b3Sopenharmony_ci
47253a5a1b3Sopenharmony_ciint pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
47353a5a1b3Sopenharmony_ci    unsigned c;
47453a5a1b3Sopenharmony_ci    pa_assert(a);
47553a5a1b3Sopenharmony_ci
47653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), 0);
47753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0);
47853a5a1b3Sopenharmony_ci
47953a5a1b3Sopenharmony_ci    for (c = 0; c < a->channels; c++)
48053a5a1b3Sopenharmony_ci        if (a->values[c] != v)
48153a5a1b3Sopenharmony_ci            return 0;
48253a5a1b3Sopenharmony_ci
48353a5a1b3Sopenharmony_ci    return 1;
48453a5a1b3Sopenharmony_ci}
48553a5a1b3Sopenharmony_ci
48653a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
48753a5a1b3Sopenharmony_ci    unsigned i;
48853a5a1b3Sopenharmony_ci
48953a5a1b3Sopenharmony_ci    pa_assert(dest);
49053a5a1b3Sopenharmony_ci    pa_assert(a);
49153a5a1b3Sopenharmony_ci    pa_assert(b);
49253a5a1b3Sopenharmony_ci
49353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
49453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
49553a5a1b3Sopenharmony_ci
49653a5a1b3Sopenharmony_ci    dest->channels = PA_MIN(a->channels, b->channels);
49753a5a1b3Sopenharmony_ci
49853a5a1b3Sopenharmony_ci    for (i = 0; i < dest->channels; i++)
49953a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
50053a5a1b3Sopenharmony_ci
50153a5a1b3Sopenharmony_ci    return dest;
50253a5a1b3Sopenharmony_ci}
50353a5a1b3Sopenharmony_ci
50453a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
50553a5a1b3Sopenharmony_ci    unsigned i;
50653a5a1b3Sopenharmony_ci
50753a5a1b3Sopenharmony_ci    pa_assert(dest);
50853a5a1b3Sopenharmony_ci    pa_assert(a);
50953a5a1b3Sopenharmony_ci
51053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
51153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL);
51253a5a1b3Sopenharmony_ci
51353a5a1b3Sopenharmony_ci    for (i = 0; i < a->channels; i++)
51453a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_multiply(a->values[i], b);
51553a5a1b3Sopenharmony_ci
51653a5a1b3Sopenharmony_ci    dest->channels = (uint8_t) i;
51753a5a1b3Sopenharmony_ci
51853a5a1b3Sopenharmony_ci    return dest;
51953a5a1b3Sopenharmony_ci}
52053a5a1b3Sopenharmony_ci
52153a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
52253a5a1b3Sopenharmony_ci    unsigned i;
52353a5a1b3Sopenharmony_ci
52453a5a1b3Sopenharmony_ci    pa_assert(dest);
52553a5a1b3Sopenharmony_ci    pa_assert(a);
52653a5a1b3Sopenharmony_ci    pa_assert(b);
52753a5a1b3Sopenharmony_ci
52853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
52953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
53053a5a1b3Sopenharmony_ci
53153a5a1b3Sopenharmony_ci    dest->channels = PA_MIN(a->channels, b->channels);
53253a5a1b3Sopenharmony_ci
53353a5a1b3Sopenharmony_ci    for (i = 0; i < dest->channels; i++)
53453a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
53553a5a1b3Sopenharmony_ci
53653a5a1b3Sopenharmony_ci    return dest;
53753a5a1b3Sopenharmony_ci}
53853a5a1b3Sopenharmony_ci
53953a5a1b3Sopenharmony_cipa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
54053a5a1b3Sopenharmony_ci    unsigned i;
54153a5a1b3Sopenharmony_ci
54253a5a1b3Sopenharmony_ci    pa_assert(dest);
54353a5a1b3Sopenharmony_ci    pa_assert(a);
54453a5a1b3Sopenharmony_ci
54553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
54653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL);
54753a5a1b3Sopenharmony_ci
54853a5a1b3Sopenharmony_ci    for (i = 0; i < a->channels; i++)
54953a5a1b3Sopenharmony_ci        dest->values[i] = pa_sw_volume_divide(a->values[i], b);
55053a5a1b3Sopenharmony_ci
55153a5a1b3Sopenharmony_ci    dest->channels = (uint8_t) i;
55253a5a1b3Sopenharmony_ci
55353a5a1b3Sopenharmony_ci    return dest;
55453a5a1b3Sopenharmony_ci}
55553a5a1b3Sopenharmony_ci
55653a5a1b3Sopenharmony_ciint pa_cvolume_valid(const pa_cvolume *v) {
55753a5a1b3Sopenharmony_ci    unsigned c;
55853a5a1b3Sopenharmony_ci
55953a5a1b3Sopenharmony_ci    pa_assert(v);
56053a5a1b3Sopenharmony_ci
56153a5a1b3Sopenharmony_ci    if (!pa_channels_valid(v->channels))
56253a5a1b3Sopenharmony_ci        return 0;
56353a5a1b3Sopenharmony_ci
56453a5a1b3Sopenharmony_ci    for (c = 0; c < v->channels; c++)
56553a5a1b3Sopenharmony_ci        if (!PA_VOLUME_IS_VALID(v->values[c]))
56653a5a1b3Sopenharmony_ci            return 0;
56753a5a1b3Sopenharmony_ci
56853a5a1b3Sopenharmony_ci    return 1;
56953a5a1b3Sopenharmony_ci}
57053a5a1b3Sopenharmony_ci
57153a5a1b3Sopenharmony_cistatic bool on_left(pa_channel_position_t p) {
57253a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
57353a5a1b3Sopenharmony_ci}
57453a5a1b3Sopenharmony_ci
57553a5a1b3Sopenharmony_cistatic bool on_right(pa_channel_position_t p) {
57653a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
57753a5a1b3Sopenharmony_ci}
57853a5a1b3Sopenharmony_ci
57953a5a1b3Sopenharmony_cistatic bool on_center(pa_channel_position_t p) {
58053a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
58153a5a1b3Sopenharmony_ci}
58253a5a1b3Sopenharmony_ci
58353a5a1b3Sopenharmony_cistatic bool on_hfe(pa_channel_position_t p) {
58453a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_HFE);
58553a5a1b3Sopenharmony_ci}
58653a5a1b3Sopenharmony_ci
58753a5a1b3Sopenharmony_cistatic bool on_lfe(pa_channel_position_t p) {
58853a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LFE);
58953a5a1b3Sopenharmony_ci}
59053a5a1b3Sopenharmony_ci
59153a5a1b3Sopenharmony_cistatic bool on_front(pa_channel_position_t p) {
59253a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
59353a5a1b3Sopenharmony_ci}
59453a5a1b3Sopenharmony_ci
59553a5a1b3Sopenharmony_cistatic bool on_rear(pa_channel_position_t p) {
59653a5a1b3Sopenharmony_ci    return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
59753a5a1b3Sopenharmony_ci}
59853a5a1b3Sopenharmony_ci
59953a5a1b3Sopenharmony_cipa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) {
60053a5a1b3Sopenharmony_ci    int a, b;
60153a5a1b3Sopenharmony_ci    pa_cvolume result;
60253a5a1b3Sopenharmony_ci
60353a5a1b3Sopenharmony_ci    pa_assert(v);
60453a5a1b3Sopenharmony_ci    pa_assert(from);
60553a5a1b3Sopenharmony_ci    pa_assert(to);
60653a5a1b3Sopenharmony_ci
60753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_channel_map_valid(to), NULL);
60853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
60953a5a1b3Sopenharmony_ci
61053a5a1b3Sopenharmony_ci    if (pa_channel_map_equal(from, to))
61153a5a1b3Sopenharmony_ci        return v;
61253a5a1b3Sopenharmony_ci
61353a5a1b3Sopenharmony_ci    result.channels = to->channels;
61453a5a1b3Sopenharmony_ci
61553a5a1b3Sopenharmony_ci    for (b = 0; b < to->channels; b++) {
61653a5a1b3Sopenharmony_ci        pa_volume_t k = 0;
61753a5a1b3Sopenharmony_ci        int n = 0;
61853a5a1b3Sopenharmony_ci
61953a5a1b3Sopenharmony_ci        for (a = 0; a < from->channels; a++)
62053a5a1b3Sopenharmony_ci            if (from->map[a] == to->map[b]) {
62153a5a1b3Sopenharmony_ci                k += v->values[a];
62253a5a1b3Sopenharmony_ci                n ++;
62353a5a1b3Sopenharmony_ci            }
62453a5a1b3Sopenharmony_ci
62553a5a1b3Sopenharmony_ci        if (n <= 0) {
62653a5a1b3Sopenharmony_ci            for (a = 0; a < from->channels; a++)
62753a5a1b3Sopenharmony_ci                if ((on_left(from->map[a]) && on_left(to->map[b])) ||
62853a5a1b3Sopenharmony_ci                    (on_right(from->map[a]) && on_right(to->map[b])) ||
62953a5a1b3Sopenharmony_ci                    (on_center(from->map[a]) && on_center(to->map[b])) ||
63053a5a1b3Sopenharmony_ci                    (on_lfe(from->map[a]) && on_lfe(to->map[b]))) {
63153a5a1b3Sopenharmony_ci
63253a5a1b3Sopenharmony_ci                    k += v->values[a];
63353a5a1b3Sopenharmony_ci                    n ++;
63453a5a1b3Sopenharmony_ci                }
63553a5a1b3Sopenharmony_ci        }
63653a5a1b3Sopenharmony_ci
63753a5a1b3Sopenharmony_ci        if (n <= 0)
63853a5a1b3Sopenharmony_ci            k = pa_cvolume_avg(v);
63953a5a1b3Sopenharmony_ci        else
64053a5a1b3Sopenharmony_ci            k /= n;
64153a5a1b3Sopenharmony_ci
64253a5a1b3Sopenharmony_ci        result.values[b] = k;
64353a5a1b3Sopenharmony_ci    }
64453a5a1b3Sopenharmony_ci
64553a5a1b3Sopenharmony_ci    *v = result;
64653a5a1b3Sopenharmony_ci    return v;
64753a5a1b3Sopenharmony_ci}
64853a5a1b3Sopenharmony_ci
64953a5a1b3Sopenharmony_ciint pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) {
65053a5a1b3Sopenharmony_ci
65153a5a1b3Sopenharmony_ci    pa_assert(v);
65253a5a1b3Sopenharmony_ci    pa_assert(ss);
65353a5a1b3Sopenharmony_ci
65453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), 0);
65553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
65653a5a1b3Sopenharmony_ci
65753a5a1b3Sopenharmony_ci    return v->channels == ss->channels;
65853a5a1b3Sopenharmony_ci}
65953a5a1b3Sopenharmony_ci
66053a5a1b3Sopenharmony_ciint pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) {
66153a5a1b3Sopenharmony_ci    pa_assert(v);
66253a5a1b3Sopenharmony_ci    pa_assert(cm);
66353a5a1b3Sopenharmony_ci
66453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), 0);
66553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_channel_map_valid(cm), 0);
66653a5a1b3Sopenharmony_ci
66753a5a1b3Sopenharmony_ci    return v->channels == cm->channels;
66853a5a1b3Sopenharmony_ci}
66953a5a1b3Sopenharmony_ci
67053a5a1b3Sopenharmony_ci/*
67153a5a1b3Sopenharmony_ci * Returns the average volume of l and r, where l and r are two disjoint sets of channels
67253a5a1b3Sopenharmony_ci * (e g left and right, or front and rear).
67353a5a1b3Sopenharmony_ci */
67453a5a1b3Sopenharmony_cistatic void get_avg(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r,
67553a5a1b3Sopenharmony_ci                    bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) {
67653a5a1b3Sopenharmony_ci    int c;
67753a5a1b3Sopenharmony_ci    pa_volume_t left = 0, right = 0;
67853a5a1b3Sopenharmony_ci    unsigned n_left = 0, n_right = 0;
67953a5a1b3Sopenharmony_ci
68053a5a1b3Sopenharmony_ci    pa_assert(v);
68153a5a1b3Sopenharmony_ci    pa_assert(map);
68253a5a1b3Sopenharmony_ci    pa_assert(map->channels == v->channels);
68353a5a1b3Sopenharmony_ci    pa_assert(l);
68453a5a1b3Sopenharmony_ci    pa_assert(r);
68553a5a1b3Sopenharmony_ci
68653a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++) {
68753a5a1b3Sopenharmony_ci        if (on_l(map->map[c])) {
68853a5a1b3Sopenharmony_ci            left += v->values[c];
68953a5a1b3Sopenharmony_ci            n_left++;
69053a5a1b3Sopenharmony_ci        } else if (on_r(map->map[c])) {
69153a5a1b3Sopenharmony_ci            right += v->values[c];
69253a5a1b3Sopenharmony_ci            n_right++;
69353a5a1b3Sopenharmony_ci        }
69453a5a1b3Sopenharmony_ci    }
69553a5a1b3Sopenharmony_ci
69653a5a1b3Sopenharmony_ci    if (n_left <= 0)
69753a5a1b3Sopenharmony_ci        *l = PA_VOLUME_NORM;
69853a5a1b3Sopenharmony_ci    else
69953a5a1b3Sopenharmony_ci        *l = left / n_left;
70053a5a1b3Sopenharmony_ci
70153a5a1b3Sopenharmony_ci    if (n_right <= 0)
70253a5a1b3Sopenharmony_ci        *r = PA_VOLUME_NORM;
70353a5a1b3Sopenharmony_ci    else
70453a5a1b3Sopenharmony_ci        *r = right / n_right;
70553a5a1b3Sopenharmony_ci}
70653a5a1b3Sopenharmony_ci
70753a5a1b3Sopenharmony_cifloat pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) {
70853a5a1b3Sopenharmony_ci    pa_volume_t left, right;
70953a5a1b3Sopenharmony_ci
71053a5a1b3Sopenharmony_ci    pa_assert(v);
71153a5a1b3Sopenharmony_ci    pa_assert(map);
71253a5a1b3Sopenharmony_ci
71353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
71453a5a1b3Sopenharmony_ci
71553a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_balance(map))
71653a5a1b3Sopenharmony_ci        return 0.0f;
71753a5a1b3Sopenharmony_ci
71853a5a1b3Sopenharmony_ci    get_avg(map, v, &left, &right, on_left, on_right);
71953a5a1b3Sopenharmony_ci
72053a5a1b3Sopenharmony_ci    if (left == right)
72153a5a1b3Sopenharmony_ci        return 0.0f;
72253a5a1b3Sopenharmony_ci
72353a5a1b3Sopenharmony_ci    /*   1.0,  0.0  =>  -1.0
72453a5a1b3Sopenharmony_ci         0.0,  1.0  =>   1.0
72553a5a1b3Sopenharmony_ci         0.0,  0.0  =>   0.0
72653a5a1b3Sopenharmony_ci         0.5,  0.5  =>   0.0
72753a5a1b3Sopenharmony_ci         1.0,  0.5  =>  -0.5
72853a5a1b3Sopenharmony_ci         1.0,  0.25 => -0.75
72953a5a1b3Sopenharmony_ci         0.75, 0.25 => -0.66
73053a5a1b3Sopenharmony_ci         0.5,  0.25 => -0.5   */
73153a5a1b3Sopenharmony_ci
73253a5a1b3Sopenharmony_ci    if (left > right)
73353a5a1b3Sopenharmony_ci        return -1.0f + ((float) right / (float) left);
73453a5a1b3Sopenharmony_ci    else
73553a5a1b3Sopenharmony_ci        return 1.0f - ((float) left / (float) right);
73653a5a1b3Sopenharmony_ci}
73753a5a1b3Sopenharmony_ci
73853a5a1b3Sopenharmony_cistatic pa_cvolume* set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance,
73953a5a1b3Sopenharmony_ci                               bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) {
74053a5a1b3Sopenharmony_ci
74153a5a1b3Sopenharmony_ci    pa_volume_t left, nleft, right, nright, m;
74253a5a1b3Sopenharmony_ci    unsigned c;
74353a5a1b3Sopenharmony_ci
74453a5a1b3Sopenharmony_ci    get_avg(map, v, &left, &right, on_l, on_r);
74553a5a1b3Sopenharmony_ci
74653a5a1b3Sopenharmony_ci    m = PA_MAX(left, right);
74753a5a1b3Sopenharmony_ci
74853a5a1b3Sopenharmony_ci    if (new_balance <= 0) {
74953a5a1b3Sopenharmony_ci        nright = (new_balance + 1.0f) * m;
75053a5a1b3Sopenharmony_ci        nleft = m;
75153a5a1b3Sopenharmony_ci    } else {
75253a5a1b3Sopenharmony_ci        nleft = (1.0f - new_balance) * m;
75353a5a1b3Sopenharmony_ci        nright = m;
75453a5a1b3Sopenharmony_ci    }
75553a5a1b3Sopenharmony_ci
75653a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++) {
75753a5a1b3Sopenharmony_ci        if (on_l(map->map[c])) {
75853a5a1b3Sopenharmony_ci            if (left == 0)
75953a5a1b3Sopenharmony_ci                v->values[c] = nleft;
76053a5a1b3Sopenharmony_ci            else
76153a5a1b3Sopenharmony_ci                v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left);
76253a5a1b3Sopenharmony_ci        } else if (on_r(map->map[c])) {
76353a5a1b3Sopenharmony_ci            if (right == 0)
76453a5a1b3Sopenharmony_ci                v->values[c] = nright;
76553a5a1b3Sopenharmony_ci            else
76653a5a1b3Sopenharmony_ci                v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right);
76753a5a1b3Sopenharmony_ci        }
76853a5a1b3Sopenharmony_ci    }
76953a5a1b3Sopenharmony_ci
77053a5a1b3Sopenharmony_ci    return v;
77153a5a1b3Sopenharmony_ci}
77253a5a1b3Sopenharmony_ci
77353a5a1b3Sopenharmony_ci
77453a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
77553a5a1b3Sopenharmony_ci    pa_assert(map);
77653a5a1b3Sopenharmony_ci    pa_assert(v);
77753a5a1b3Sopenharmony_ci
77853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
77953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance >= -1.0f, NULL);
78053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance <= 1.0f, NULL);
78153a5a1b3Sopenharmony_ci
78253a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_balance(map))
78353a5a1b3Sopenharmony_ci        return v;
78453a5a1b3Sopenharmony_ci
78553a5a1b3Sopenharmony_ci    return set_balance(v, map, new_balance, on_left, on_right);
78653a5a1b3Sopenharmony_ci}
78753a5a1b3Sopenharmony_ci
78853a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) {
78953a5a1b3Sopenharmony_ci    unsigned c;
79053a5a1b3Sopenharmony_ci    pa_volume_t t = 0;
79153a5a1b3Sopenharmony_ci
79253a5a1b3Sopenharmony_ci    pa_assert(v);
79353a5a1b3Sopenharmony_ci
79453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
79553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
79653a5a1b3Sopenharmony_ci
79753a5a1b3Sopenharmony_ci    t = pa_cvolume_max(v);
79853a5a1b3Sopenharmony_ci
79953a5a1b3Sopenharmony_ci    if (t <= PA_VOLUME_MUTED)
80053a5a1b3Sopenharmony_ci        return pa_cvolume_set(v, v->channels, max);
80153a5a1b3Sopenharmony_ci
80253a5a1b3Sopenharmony_ci    for (c = 0; c < v->channels; c++)
80353a5a1b3Sopenharmony_ci        v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
80453a5a1b3Sopenharmony_ci
80553a5a1b3Sopenharmony_ci    return v;
80653a5a1b3Sopenharmony_ci}
80753a5a1b3Sopenharmony_ci
80853a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
80953a5a1b3Sopenharmony_ci    unsigned c;
81053a5a1b3Sopenharmony_ci    pa_volume_t t = 0;
81153a5a1b3Sopenharmony_ci
81253a5a1b3Sopenharmony_ci    pa_assert(v);
81353a5a1b3Sopenharmony_ci
81453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
81553a5a1b3Sopenharmony_ci
81653a5a1b3Sopenharmony_ci    if (!cm)
81753a5a1b3Sopenharmony_ci        return pa_cvolume_scale(v, max);
81853a5a1b3Sopenharmony_ci
81953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL);
82053a5a1b3Sopenharmony_ci
82153a5a1b3Sopenharmony_ci    t = pa_cvolume_max_mask(v, cm, mask);
82253a5a1b3Sopenharmony_ci
82353a5a1b3Sopenharmony_ci    if (t <= PA_VOLUME_MUTED)
82453a5a1b3Sopenharmony_ci        return pa_cvolume_set(v, v->channels, max);
82553a5a1b3Sopenharmony_ci
82653a5a1b3Sopenharmony_ci    for (c = 0; c < v->channels; c++)
82753a5a1b3Sopenharmony_ci        v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
82853a5a1b3Sopenharmony_ci
82953a5a1b3Sopenharmony_ci    return v;
83053a5a1b3Sopenharmony_ci}
83153a5a1b3Sopenharmony_ci
83253a5a1b3Sopenharmony_cifloat pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) {
83353a5a1b3Sopenharmony_ci    pa_volume_t rear, front;
83453a5a1b3Sopenharmony_ci
83553a5a1b3Sopenharmony_ci    pa_assert(v);
83653a5a1b3Sopenharmony_ci    pa_assert(map);
83753a5a1b3Sopenharmony_ci
83853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
83953a5a1b3Sopenharmony_ci
84053a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_fade(map))
84153a5a1b3Sopenharmony_ci        return 0.0f;
84253a5a1b3Sopenharmony_ci
84353a5a1b3Sopenharmony_ci    get_avg(map, v, &rear, &front, on_rear, on_front);
84453a5a1b3Sopenharmony_ci
84553a5a1b3Sopenharmony_ci    if (front == rear)
84653a5a1b3Sopenharmony_ci        return 0.0f;
84753a5a1b3Sopenharmony_ci
84853a5a1b3Sopenharmony_ci    if (rear > front)
84953a5a1b3Sopenharmony_ci        return -1.0f + ((float) front / (float) rear);
85053a5a1b3Sopenharmony_ci    else
85153a5a1b3Sopenharmony_ci        return 1.0f - ((float) rear / (float) front);
85253a5a1b3Sopenharmony_ci}
85353a5a1b3Sopenharmony_ci
85453a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) {
85553a5a1b3Sopenharmony_ci    pa_assert(map);
85653a5a1b3Sopenharmony_ci    pa_assert(v);
85753a5a1b3Sopenharmony_ci
85853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
85953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_fade >= -1.0f, NULL);
86053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_fade <= 1.0f, NULL);
86153a5a1b3Sopenharmony_ci
86253a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_fade(map))
86353a5a1b3Sopenharmony_ci        return v;
86453a5a1b3Sopenharmony_ci
86553a5a1b3Sopenharmony_ci    return set_balance(v, map, new_fade, on_rear, on_front);
86653a5a1b3Sopenharmony_ci}
86753a5a1b3Sopenharmony_ci
86853a5a1b3Sopenharmony_cifloat pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) {
86953a5a1b3Sopenharmony_ci    pa_volume_t hfe, lfe;
87053a5a1b3Sopenharmony_ci
87153a5a1b3Sopenharmony_ci    pa_assert(v);
87253a5a1b3Sopenharmony_ci    pa_assert(map);
87353a5a1b3Sopenharmony_ci
87453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
87553a5a1b3Sopenharmony_ci
87653a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_lfe_balance(map))
87753a5a1b3Sopenharmony_ci        return 0.0f;
87853a5a1b3Sopenharmony_ci
87953a5a1b3Sopenharmony_ci    get_avg(map, v, &hfe, &lfe, on_hfe, on_lfe);
88053a5a1b3Sopenharmony_ci
88153a5a1b3Sopenharmony_ci    if (hfe == lfe)
88253a5a1b3Sopenharmony_ci        return 0.0f;
88353a5a1b3Sopenharmony_ci
88453a5a1b3Sopenharmony_ci    if (hfe > lfe)
88553a5a1b3Sopenharmony_ci        return -1.0f + ((float) lfe / (float) hfe);
88653a5a1b3Sopenharmony_ci    else
88753a5a1b3Sopenharmony_ci        return 1.0f - ((float) hfe / (float) lfe);
88853a5a1b3Sopenharmony_ci}
88953a5a1b3Sopenharmony_ci
89053a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
89153a5a1b3Sopenharmony_ci    pa_assert(map);
89253a5a1b3Sopenharmony_ci    pa_assert(v);
89353a5a1b3Sopenharmony_ci
89453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
89553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance >= -1.0f, NULL);
89653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(new_balance <= 1.0f, NULL);
89753a5a1b3Sopenharmony_ci
89853a5a1b3Sopenharmony_ci    if (!pa_channel_map_can_lfe_balance(map))
89953a5a1b3Sopenharmony_ci        return v;
90053a5a1b3Sopenharmony_ci
90153a5a1b3Sopenharmony_ci    return set_balance(v, map, new_balance, on_hfe, on_lfe);
90253a5a1b3Sopenharmony_ci}
90353a5a1b3Sopenharmony_ci
90453a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_set_position(
90553a5a1b3Sopenharmony_ci        pa_cvolume *cv,
90653a5a1b3Sopenharmony_ci        const pa_channel_map *map,
90753a5a1b3Sopenharmony_ci        pa_channel_position_t t,
90853a5a1b3Sopenharmony_ci        pa_volume_t v) {
90953a5a1b3Sopenharmony_ci
91053a5a1b3Sopenharmony_ci    unsigned c;
91153a5a1b3Sopenharmony_ci    bool good = false;
91253a5a1b3Sopenharmony_ci
91353a5a1b3Sopenharmony_ci    pa_assert(cv);
91453a5a1b3Sopenharmony_ci    pa_assert(map);
91553a5a1b3Sopenharmony_ci
91653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
91753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
91853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL);
91953a5a1b3Sopenharmony_ci
92053a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++)
92153a5a1b3Sopenharmony_ci        if (map->map[c] == t) {
92253a5a1b3Sopenharmony_ci            cv->values[c] = v;
92353a5a1b3Sopenharmony_ci            good = true;
92453a5a1b3Sopenharmony_ci        }
92553a5a1b3Sopenharmony_ci
92653a5a1b3Sopenharmony_ci    return good ? cv : NULL;
92753a5a1b3Sopenharmony_ci}
92853a5a1b3Sopenharmony_ci
92953a5a1b3Sopenharmony_cipa_volume_t pa_cvolume_get_position(
93053a5a1b3Sopenharmony_ci        const pa_cvolume *cv,
93153a5a1b3Sopenharmony_ci        const pa_channel_map *map,
93253a5a1b3Sopenharmony_ci        pa_channel_position_t t) {
93353a5a1b3Sopenharmony_ci
93453a5a1b3Sopenharmony_ci    unsigned c;
93553a5a1b3Sopenharmony_ci    pa_volume_t v = PA_VOLUME_MUTED;
93653a5a1b3Sopenharmony_ci
93753a5a1b3Sopenharmony_ci    pa_assert(cv);
93853a5a1b3Sopenharmony_ci    pa_assert(map);
93953a5a1b3Sopenharmony_ci
94053a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
94153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
94253a5a1b3Sopenharmony_ci
94353a5a1b3Sopenharmony_ci    for (c = 0; c < map->channels; c++)
94453a5a1b3Sopenharmony_ci        if (map->map[c] == t)
94553a5a1b3Sopenharmony_ci            if (cv->values[c] > v)
94653a5a1b3Sopenharmony_ci                v = cv->values[c];
94753a5a1b3Sopenharmony_ci
94853a5a1b3Sopenharmony_ci    return v;
94953a5a1b3Sopenharmony_ci}
95053a5a1b3Sopenharmony_ci
95153a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
95253a5a1b3Sopenharmony_ci    unsigned i;
95353a5a1b3Sopenharmony_ci
95453a5a1b3Sopenharmony_ci    pa_assert(dest);
95553a5a1b3Sopenharmony_ci    pa_assert(a);
95653a5a1b3Sopenharmony_ci    pa_assert(b);
95753a5a1b3Sopenharmony_ci
95853a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
95953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
96053a5a1b3Sopenharmony_ci
96153a5a1b3Sopenharmony_ci    dest->channels = PA_MIN(a->channels, b->channels);
96253a5a1b3Sopenharmony_ci
96353a5a1b3Sopenharmony_ci    for (i = 0; i < dest->channels; i++)
96453a5a1b3Sopenharmony_ci        dest->values[i] = PA_MAX(a->values[i], b->values[i]);
96553a5a1b3Sopenharmony_ci
96653a5a1b3Sopenharmony_ci    return dest;
96753a5a1b3Sopenharmony_ci}
96853a5a1b3Sopenharmony_ci
96953a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) {
97053a5a1b3Sopenharmony_ci    pa_volume_t m;
97153a5a1b3Sopenharmony_ci
97253a5a1b3Sopenharmony_ci    pa_assert(v);
97353a5a1b3Sopenharmony_ci
97453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
97553a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL);
97653a5a1b3Sopenharmony_ci
97753a5a1b3Sopenharmony_ci    m = pa_cvolume_max(v);
97853a5a1b3Sopenharmony_ci
97953a5a1b3Sopenharmony_ci    if (m >= limit - inc)
98053a5a1b3Sopenharmony_ci        m = limit;
98153a5a1b3Sopenharmony_ci    else
98253a5a1b3Sopenharmony_ci        m += inc;
98353a5a1b3Sopenharmony_ci
98453a5a1b3Sopenharmony_ci    return pa_cvolume_scale(v, m);
98553a5a1b3Sopenharmony_ci}
98653a5a1b3Sopenharmony_ci
98753a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) {
98853a5a1b3Sopenharmony_ci    return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX);
98953a5a1b3Sopenharmony_ci}
99053a5a1b3Sopenharmony_ci
99153a5a1b3Sopenharmony_cipa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) {
99253a5a1b3Sopenharmony_ci    pa_volume_t m;
99353a5a1b3Sopenharmony_ci
99453a5a1b3Sopenharmony_ci    pa_assert(v);
99553a5a1b3Sopenharmony_ci
99653a5a1b3Sopenharmony_ci    pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
99753a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL);
99853a5a1b3Sopenharmony_ci
99953a5a1b3Sopenharmony_ci    m = pa_cvolume_max(v);
100053a5a1b3Sopenharmony_ci
100153a5a1b3Sopenharmony_ci    if (m <= PA_VOLUME_MUTED + dec)
100253a5a1b3Sopenharmony_ci        m = PA_VOLUME_MUTED;
100353a5a1b3Sopenharmony_ci    else
100453a5a1b3Sopenharmony_ci        m -= dec;
100553a5a1b3Sopenharmony_ci
100653a5a1b3Sopenharmony_ci    return pa_cvolume_scale(v, m);
100753a5a1b3Sopenharmony_ci}
1008