summaryrefslogtreecommitdiffstats
path: root/audio/out/ao.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out/ao.c')
-rw-r--r--audio/out/ao.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c
index da2dacdcae..c40eae1b92 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#include <assert.h>
#include "mpv_talloc.h"
@@ -159,6 +160,7 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global,
ao->priv = m_config_group_from_desc(ao, ao->log, global, &desc, name);
if (!ao->priv)
goto error;
+ ao_set_gain(ao, 1.0f);
return ao;
error:
talloc_free(ao);
@@ -638,6 +640,70 @@ void ao_print_devices(struct mpv_global *global, struct mp_log *log)
ao_hotplug_destroy(hp);
}
+void ao_set_gain(struct ao *ao, float gain)
+{
+ uint_least32_t v = 0;
+ assert(sizeof(gain) <= sizeof(v));
+ memcpy(&v, &gain, sizeof(gain));
+ atomic_store(&ao->gain_fi, v);
+}
+
+static float ao_get_gain(struct ao *ao)
+{
+ uint_least32_t v = atomic_load_explicit(&ao->gain_fi, memory_order_relaxed);
+ float gain;
+ assert(sizeof(gain) <= sizeof(v));
+ memcpy(&gain, &v, sizeof(gain));
+ return gain;
+}
+
+#define MUL_GAIN_i(d, num_samples, gain, low, center, high) \
+ for (int n = 0; n < (num_samples); n++) \
+ (d)[n] = MPCLAMP( \
+ ((((int64_t)((d)[n]) - (center)) * (gain) + 128) >> 8) + (center), \
+ (low), (high))
+
+#define MUL_GAIN_f(d, num_samples, gain) \
+ for (int n = 0; n < (num_samples); n++) \
+ (d)[n] = MPCLAMP(((d)[n]) * (gain), -1.0, 1.0)
+
+static void process_plane(struct ao *ao, void *data, int num_samples)
+{
+ float gain = ao_get_gain(ao);
+ int format = af_fmt_from_planar(ao->format);
+ if (gain == 1.0f)
+ return;
+ int gi = lrint(256.0 * gain);
+ switch (format) {
+ case AF_FORMAT_U8:
+ MUL_GAIN_i((uint8_t *)data, num_samples, gi, 0, 128, 255);
+ break;
+ case AF_FORMAT_S16:
+ MUL_GAIN_i((int16_t *)data, num_samples, gi, INT16_MIN, 0, INT16_MAX);
+ break;
+ case AF_FORMAT_S32:
+ MUL_GAIN_i((int32_t *)data, num_samples, gi, INT32_MIN, 0, INT32_MAX);
+ break;
+ case AF_FORMAT_FLOAT:
+ MUL_GAIN_f((float *)data, num_samples, gain);
+ break;
+ case AF_FORMAT_DOUBLE:
+ MUL_GAIN_f((double *)data, num_samples, gain);
+ break;
+ default:;
+ // all other sample formats are simply not supported
+ }
+}
+
+void ao_post_process_data(struct ao *ao, void **data, int num_samples)
+{
+ bool planar = af_fmt_is_planar(ao->format);
+ int planes = planar ? ao->channels.num : 1;
+ int plane_samples = num_samples * (planar ? 1: ao->channels.num);
+ for (int n = 0; n < planes; n++)
+ process_plane(ao, data[n], plane_samples);
+}
+
static int get_conv_type(struct ao_convert_fmt *fmt)
{
if (af_fmt_to_bytes(fmt->src_fmt) * 8 == fmt->dst_bits && !fmt->pad_msb)