diff options
author | Wim Taymans <wtaymans@redhat.com> | 2020-05-15 21:15:25 +0200 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2020-07-03 17:33:07 +0200 |
commit | 819549beba71ae61ae67e48f3b5ecc55fa2a5ccb (patch) | |
tree | e24db3b607aee16919f31e5996e436ada63eab63 | |
parent | 0eb2edabd24a505606dd9c920c72db14342df00e (diff) |
moe wip
-rw-r--r-- | config.h.meson | 3 | ||||
-rw-r--r-- | meson.build | 3 | ||||
-rw-r--r-- | spa/plugins/pulse/alsa-mixer.c | 36 | ||||
-rw-r--r-- | spa/plugins/pulse/compat.h | 12 | ||||
-rw-r--r-- | spa/plugins/pulse/volume.h | 168 |
5 files changed, 198 insertions, 24 deletions
diff --git a/config.h.meson b/config.h.meson index ad0b79d0..3c6cf4bb 100644 --- a/config.h.meson +++ b/config.h.meson @@ -453,3 +453,6 @@ #mesondefine PIPEWIRE_VERSION_MAJOR #mesondefine PIPEWIRE_VERSION_MINOR #mesondefine PIPEWIRE_VERSION_MICRO + +#mesondefine PA_ALSA_PATHS_DIR +#mesondefine PA_ALSA_PROFILE_SETS_DIR diff --git a/meson.build b/meson.build index 088e43e6..777dcbd8 100644 --- a/meson.build +++ b/meson.build @@ -52,6 +52,7 @@ else endif spa_plugindir = join_paths(pipewire_libdir, spa_name) +alsadatadir = join_paths(pipewire_datadir, 'pulseaudio', 'alsa-mixer') pipewire_headers_dir = join_paths(pipewire_name, 'pipewire') @@ -179,6 +180,8 @@ cdata.set('VERSION', '"@0@"'.format(pipewire_version)) cdata.set('PLUGINDIR', '"@0@"'.format(spa_plugindir)) # FIXME: --with-memory-alignment],[8,N,malloc,pagesize (default is 32)]) option cdata.set('MEMORY_ALIGNMENT_MALLOC', 1) +cdata.set_quoted('PA_ALSA_PATHS_DIR', join_paths(alsadatadir, 'paths')) +cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', join_paths(alsadatadir, 'profile-sets')) check_headers = [['dlfcn.h','HAVE_DLFCN_H'], diff --git a/spa/plugins/pulse/alsa-mixer.c b/spa/plugins/pulse/alsa-mixer.c index ebfcdebd..8ba1813d 100644 --- a/spa/plugins/pulse/alsa-mixer.c +++ b/spa/plugins/pulse/alsa-mixer.c @@ -4468,29 +4468,31 @@ static int profile_verify(pa_alsa_profile *p) { PA_ELEMENTSOF(well_known_descriptions))); if (!p->description) { - pa_strbuf *sb; uint32_t idx; pa_alsa_mapping *m; + char *ptr; + size_t size; + FILE *f; + int count = 0; - sb = pa_strbuf_new(); + f = open_memstream(&ptr, &size); if (p->output_mappings) PA_IDXSET_FOREACH(m, p->output_mappings, idx) { - if (!pa_strbuf_isempty(sb)) - pa_strbuf_puts(sb, " + "); - - pa_strbuf_printf(sb, _("%s Output"), m->description); + if (count++ > 0) + fprintf(f, " + "); + fprintf(f, _("%s Output"), m->description); } if (p->input_mappings) PA_IDXSET_FOREACH(m, p->input_mappings, idx) { - if (!pa_strbuf_isempty(sb)) - pa_strbuf_puts(sb, " + "); - - pa_strbuf_printf(sb, _("%s Input"), m->description); + if (count++ > 0) + fprintf(f, " + "); + fprintf(f, _("%s Input"), m->description); } - p->description = pa_strbuf_to_string_free(sb); + fclose(f); + p->description = ptr; } return 0; @@ -4542,17 +4544,21 @@ void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix) { pa_assert(db_fix); if (db_fix->db_values) { - pa_strbuf *buf; unsigned long i, nsteps; + FILE *f; + char *ptr; + size_t size; + + f = open_memstream(&ptr, &size); pa_assert(db_fix->min_step <= db_fix->max_step); nsteps = db_fix->max_step - db_fix->min_step + 1; - buf = pa_strbuf_new(); for (i = 0; i < nsteps; ++i) - pa_strbuf_printf(buf, "[%li]:%0.2f ", i + db_fix->min_step, db_fix->db_values[i] / 100.0); + fprintf(f, "[%li]:%0.2f ", i + db_fix->min_step, db_fix->db_values[i] / 100.0); - db_values = pa_strbuf_to_string_free(buf); + fclose(f); + db_values = ptr; } pa_log_debug("Decibel fix %s, min_step=%li, max_step=%li, db_values=%s", diff --git a/spa/plugins/pulse/compat.h b/spa/plugins/pulse/compat.h index 61e20a7a..35be524e 100644 --- a/spa/plugins/pulse/compat.h +++ b/spa/plugins/pulse/compat.h @@ -45,9 +45,7 @@ typedef void (*pa_free_cb_t)(void *p); #include "dynarray.h" #include "idxset.h" #include "proplist.h" -#include "channelmap.h" -typedef struct pa_idxset pa_idxset; typedef struct pa_card pa_card; typedef struct pa_card_profile pa_card_profile; @@ -69,13 +67,6 @@ typedef enum pa_available { PA_AVAILABLE_YES = 2, } pa_available_t; -typedef uint32_t pa_volume_t; - -typedef struct pa_cvolume { - uint32_t channels; /**< Number of channels */ - pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ -} pa_cvolume; - typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ @@ -295,6 +286,9 @@ static inline const char *pa_strna(const char *x) { #define _(...) (__VA_ARGS__) #define N_(...) (__VA_ARGS__) +#include "channelmap.h" +#include "volume.h" + #ifdef __cplusplus } #endif diff --git a/spa/plugins/pulse/volume.h b/spa/plugins/pulse/volume.h new file mode 100644 index 00000000..fb8661c3 --- /dev/null +++ b/spa/plugins/pulse/volume.h @@ -0,0 +1,168 @@ +/* PipeWire + * + * Copyright © 2020 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef PA_VOLUME_H +#define PA_VOLUME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <math.h> + +typedef uint32_t pa_volume_t; + +#define PA_VOLUME_MUTED ((pa_volume_t) 0U) +#define PA_VOLUME_NORM ((pa_volume_t) 0x10000U) +#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX/2) + +#ifdef INFINITY +#define PA_DECIBEL_MININFTY ((double) -INFINITY) +#else +#define PA_DECIBEL_MININFTY ((double) -200.0) +#endif + +#define PA_CLAMP_VOLUME(v) (PA_CLAMP_UNLIKELY((v), PA_VOLUME_MUTED, PA_VOLUME_MAX)) + +typedef struct pa_cvolume { + uint32_t channels; /**< Number of channels */ + pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ +} pa_cvolume; + +static inline double pa_volume_linear_to_dB(double v) +{ + return 20.0 * log10(v); +} + +static inline double pa_sw_volume_to_linear(pa_volume_t v) +{ + double f; + if (v <= PA_VOLUME_MUTED) + return 0.0; + if (v == PA_VOLUME_NORM) + return 1.0; + f = ((double) v / PA_VOLUME_NORM); + return f*f*f; +} + +static inline double pa_sw_volume_to_dB(pa_volume_t v) +{ + if (v <= PA_VOLUME_MUTED) + return PA_DECIBEL_MININFTY; + return pa_volume_linear_to_dB(pa_sw_volume_to_linear(v)); +} + +static inline double pa_volume_dB_to_linear(double v) +{ + return pow(10.0, v / 20.0); +} + +static inline pa_volume_t pa_sw_volume_from_linear(double v) +{ + if (v <= 0.0) + return PA_VOLUME_MUTED; + return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM)); +} + +static inline pa_volume_t pa_sw_volume_from_dB(double dB) +{ + if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY) + return PA_VOLUME_MUTED; + return pa_sw_volume_from_linear(pa_volume_dB_to_linear(dB)); +} + +static inline pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) +{ + uint32_t i; + a->channels = (uint8_t) channels; + for (i = 0; i < a->channels; i++) + a->values[i] = PA_CLAMP_VOLUME(v); + return a; +} + +static inline pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) +{ + uint64_t result; + result = ((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / + (uint64_t) PA_VOLUME_NORM; + if (result > (uint64_t)PA_VOLUME_MAX) + pa_log_warn("pa_sw_volume_multiply: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); + return (pa_volume_t) PA_CLAMP_VOLUME(result); +} + +static inline pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, + const pa_cvolume *a, const pa_cvolume *b) +{ + unsigned i; + dest->channels = PA_MIN(a->channels, b->channels); + for (i = 0; i < dest->channels; i++) + dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]); + return dest; +} + +static inline pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) +{ + uint64_t result; + if (b <= PA_VOLUME_MUTED) + return 0; + result = ((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b; + if (result > (uint64_t)PA_VOLUME_MAX) + pa_log_warn("pa_sw_volume_divide: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); + return (pa_volume_t) PA_CLAMP_VOLUME(result); +} + +static inline pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, + const pa_cvolume *a, const pa_cvolume *b) +{ + unsigned i; + dest->channels = PA_MIN(a->channels, b->channels); + for (i = 0; i < dest->channels; i++) + dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]); + return dest; +} + +#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) +#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) + +static inline int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, + const pa_channel_map *cm) +{ + return v->channels == cm->channels; +} + +static inline pa_volume_t pa_cvolume_max(const pa_cvolume *a) +{ + pa_volume_t m = PA_VOLUME_MUTED; + unsigned c; + for (c = 0; c < a->channels; c++) + if (a->values[c] > m) + m = a->values[c]; + return m; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PA_VOLUME_H */ |