From 63c43b649dbaeeecbbef27b7aa9340bea6fd9417 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sun, 28 Dec 2014 00:34:35 -0800 Subject: [PATCH] libobs: Add flag to force source audio to mono This flag is actually useful under a number of circumstances, and has been requested a number of times. --- libobs/obs-source.c | 56 ++++++++++++++++++++++++++++++++++++++++++++- libobs/obs.h | 2 ++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/libobs/obs-source.c b/libobs/obs-source.c index b11378336..813e33c99 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -1471,10 +1471,58 @@ static inline void copy_audio_data(obs_source_t *source, source->audio_storage_size = size; } +/* TODO: SSE optimization */ +static void downmix_to_mono_planar(struct obs_source *source, uint32_t frames) +{ + uint32_t channels = get_audio_channels(source->sample_info.speakers); + const float channels_i = 1.0f / (float)channels; + float **data = (float**)source->audio_data.data; + + for (uint32_t channel = 1; channel < channels; channel++) { + for (uint32_t frame = 0; frame < frames; frame++) + data[0][frame] += data[channel][frame]; + } + + for (uint32_t frame = 0; frame < frames; frame++) + data[0][frame] *= channels_i; + + for (uint32_t channel = 1; channel < channels; channel++) { + for (uint32_t frame = 0; frame < frames; frame++) + data[channel][frame] = data[0][frame]; + } +} + +static void downmix_to_mono_interleaved(struct obs_source *source, + uint32_t frames) +{ + uint32_t channels = get_audio_channels(source->sample_info.speakers); + const float channels_i = 1.0f / (float)channels; + float *data = (float*)source->audio_data.data[0]; + + for (uint32_t frame = 0; frame < frames; frame++) { + uint32_t pos = frame * channels; + + for (uint32_t channel = 1; channel < channels; channel++) + data[pos] += data[pos + channel]; + } + + for (uint32_t frame = 0; frame < frames; frame++) + data[frame * channels] *= channels_i; + + for (uint32_t frame = 0; frame < frames; frame++) { + uint32_t pos = frame * channels; + + for (uint32_t channel = 1; channel < channels; channel++) + data[pos + channel] = data[pos]; + } +} + /* resamples/remixes new audio to the designated main audio output format */ static void process_audio(obs_source_t *source, const struct obs_source_audio *audio) { + uint32_t frames = audio->frames; + if (source->sample_info.samples_per_sec != audio->samples_per_sec || source->sample_info.format != audio->format || source->sample_info.speakers != audio->speakers) @@ -1485,7 +1533,6 @@ static void process_audio(obs_source_t *source, if (source->resampler) { uint8_t *output[MAX_AV_PLANES]; - uint32_t frames; uint64_t offset; memset(output, 0, sizeof(output)); @@ -1500,6 +1547,13 @@ static void process_audio(obs_source_t *source, copy_audio_data(source, audio->data, audio->frames, audio->timestamp); } + + if ((source->flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0) { + if (is_audio_planar(source->sample_info.format)) + downmix_to_mono_planar(source, frames); + else + downmix_to_mono_interleaved(source, frames); + } } void obs_source_output_audio(obs_source_t *source, diff --git a/libobs/obs.h b/libobs/obs.h index f0305cdf9..f03adcac0 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -753,6 +753,8 @@ EXPORT void obs_source_load(obs_source_t *source); /** Specifies that async video frames should be played as soon as possible */ #define OBS_SOURCE_FLAG_UNBUFFERED (1<<0) +/** Specifies to force audio to mono */ +#define OBS_SOURCE_FLAG_FORCE_MONO (1<<1) /** Sets source flags. Note that these are different from the main output * flags. */