From 1ceb902b765be779fb542aae8798afd0153f943d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 23 Oct 2020 09:36:01 +0200 Subject: [PATCH] pulse-server: convert between client cubic volume and linear --- src/modules/module-protocol-pulse/format.c | 2 +- src/modules/module-protocol-pulse/message.c | 39 ++++++++++++++----- .../module-protocol-pulse/pulse-server.c | 16 ++++---- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/modules/module-protocol-pulse/format.c b/src/modules/module-protocol-pulse/format.c index aba61733c..0fc0a70f4 100644 --- a/src/modules/module-protocol-pulse/format.c +++ b/src/modules/module-protocol-pulse/format.c @@ -283,7 +283,7 @@ static void channel_map_to_positions(const struct channel_map *map, uint32_t *po pos[i] = channel_pa2id(map->map[i]); } -struct cvolume { +struct volume { uint8_t channels; float values[CHANNELS_MAX]; }; diff --git a/src/modules/module-protocol-pulse/message.c b/src/modules/module-protocol-pulse/message.c index f539e2944..6577c4ae1 100644 --- a/src/modules/module-protocol-pulse/message.c +++ b/src/modules/module-protocol-pulse/message.c @@ -22,6 +22,27 @@ * DEALINGS IN THE SOFTWARE. */ +#define VOLUME_MUTED ((uint32_t) 0U) +#define VOLUME_NORM ((uint32_t) 0x10000U) +#define VOLUME_MAX ((uint32_t) UINT32_MAX/2) + +static inline uint32_t volume_from_linear(float vol) +{ + uint32_t v; + if (vol <= 0.0f) + v = VOLUME_MUTED; + else + v = SPA_CLAMP((uint64_t) lround(cbrt(vol) * VOLUME_NORM), + VOLUME_MUTED, VOLUME_MAX); + return v; +} + +static inline float volume_to_linear(uint32_t vol) +{ + float v = ((float)vol) / VOLUME_NORM; + return v * v * v; +} + struct descriptor { uint32_t length; uint32_t channel; @@ -203,11 +224,11 @@ static int read_volume(struct message *m, float *vol) uint32_t v; if ((res = read_u32(m, &v)) < 0) return res; - *vol = ((float)v) / 0x10000U; + *vol = volume_to_linear(v); return 0; } -static int read_cvolume(struct message *m, struct cvolume *vol) +static int read_cvolume(struct message *m, struct volume *vol) { int res; uint8_t i; @@ -336,7 +357,7 @@ static int message_get(struct message *m, ...) case TAG_CVOLUME: if (dtag != tag) return -EINVAL; - if ((res = read_cvolume(m, va_arg(va, struct cvolume*))) < 0) + if ((res = read_cvolume(m, va_arg(va, struct volume*))) < 0) return res; break; case TAG_PROPLIST: @@ -462,16 +483,16 @@ static void write_channel_map(struct message *m, struct channel_map *map) static void write_volume(struct message *m, float vol) { write_8(m, TAG_VOLUME); - write_32(m, vol * 0x10000U); + write_32(m, volume_from_linear(vol)); } -static void write_cvolume(struct message *m, struct cvolume *cvol) +static void write_cvolume(struct message *m, struct volume *vol) { uint8_t i; write_8(m, TAG_CVOLUME); - write_8(m, cvol->channels); - for (i = 0; i < cvol->channels; i ++) - write_32(m, cvol->values[i] * 0x10000U); + write_8(m, vol->channels); + for (i = 0; i < vol->channels; i ++) + write_32(m, volume_from_linear(vol->values[i])); } static void write_props(struct message *m, struct pw_properties *props) @@ -545,7 +566,7 @@ static int message_put(struct message *m, ...) write_channel_map(m, va_arg(va, struct channel_map*)); break; case TAG_CVOLUME: - write_cvolume(m, va_arg(va, struct cvolume*)); + write_cvolume(m, va_arg(va, struct volume*)); break; case TAG_PROPLIST: write_props(m, va_arg(va, struct pw_properties*)); diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index c2851caa2..624f0f985 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -97,7 +97,7 @@ struct device { enum pw_direction direction; struct pw_properties *props; struct sample_spec ss; - struct cvolume volume; + struct volume volume; struct channel_map map; bool muted; struct device *monitor; @@ -139,7 +139,7 @@ struct stream { struct buffer_attr attr; uint32_t frame_size; - struct cvolume volume; + struct volume volume; bool muted; struct device *dev; @@ -1178,7 +1178,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui fail_on_suspend = false, relative_volume = false, passthrough = false; - struct cvolume volume; + struct volume volume; struct pw_properties *props = NULL; uint8_t n_formats = 0; struct stream *stream = NULL; @@ -1413,7 +1413,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint relative_volume = false, passthrough = false; uint32_t direct_on_input_idx; - struct cvolume volume; + struct volume volume; struct pw_properties *props = NULL; uint8_t n_formats = 0; struct stream *stream = NULL; @@ -1795,7 +1795,7 @@ static int do_set_stream_volume(struct client *client, uint32_t command, uint32_ uint32_t channel; struct stream *stream; int res; - struct cvolume volume; + struct volume volume; if ((res = message_get(m, TAG_U32, &channel, @@ -3146,7 +3146,7 @@ struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context, .format = SAMPLE_FLOAT32LE, .rate = 44100, .channels = 2, }, - .volume = (struct cvolume) { + .volume = (struct volume) { .channels = 2, .values[0] = 1.0f, .values[1] = 1.0f, }, @@ -3169,7 +3169,7 @@ struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context, .format = SAMPLE_FLOAT32LE, .rate = 44100, .channels = 2, }, - .volume = (struct cvolume) { + .volume = (struct volume) { .channels = 2, .values[0] = 1.0f, .values[1] = 1.0f, }, @@ -3191,7 +3191,7 @@ struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context, .format = SAMPLE_FLOAT32LE, .rate = 44100, .channels = 2, }, - .volume = (struct cvolume) { + .volume = (struct volume) { .channels = 2, .values[0] = 1.0f, .values[1] = 1.0f, },