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