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