From: Peter Meerwald Date: Wed, 13 Feb 2013 16:26:59 +0000 (+0100) Subject: core: Move pa_mix() into new file mix.c X-Git-Tag: v3.99.1~111 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=95b64804ab9d21c6807c25eb3f03afd6bfd35cb6;p=platform%2Fupstream%2Fpulseaudio.git core: Move pa_mix() into new file mix.c idea is to allow optimized code path (similar to volume code) and rework/specialize mixing cases to enable runtime performance improvements no functionality changes in this patch Signed-off-by: Peter Meerwald --- diff --git a/src/Makefile.am b/src/Makefile.am index 1208a35..22b0409 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -856,6 +856,7 @@ libpulsecore_@PA_MAJORMINOR@_la_SOURCES = \ pulsecore/remap_mmx.c pulsecore/remap_sse.c \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ + pulsecore/mix.c pulsecore/mix.h \ pulsecore/cpu.h \ pulsecore/cpu-arm.c pulsecore/cpu-arm.h \ pulsecore/cpu-x86.c pulsecore/cpu-x86.h \ diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c index 4bdcded..be2de5a 100644 --- a/src/modules/module-virtual-source.c +++ b/src/modules/module-virtual-source.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "module-virtual-source-symdef.h" diff --git a/src/pulsecore/mix.c b/src/pulsecore/mix.c new file mode 100644 index 0000000..93978eb --- /dev/null +++ b/src/pulsecore/mix.c @@ -0,0 +1,679 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2013 Peter Meerwald + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "mix.h" + +#define VOLUME_PADDING 32 + +static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) { + unsigned channel, nchannels, padding; + + pa_assert(linear); + pa_assert(volume); + + nchannels = volume->channels; + + for (channel = 0; channel < nchannels; channel++) + linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + + for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) + linear[channel] = linear[padding]; +} + +static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { + unsigned channel, nchannels, padding; + + pa_assert(linear); + pa_assert(volume); + + nchannels = volume->channels; + + for (channel = 0; channel < nchannels; channel++) + linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]); + + for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) + linear[channel] = linear[padding]; +} + +static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { + unsigned k, channel; + float linear[PA_CHANNELS_MAX + VOLUME_PADDING]; + + pa_assert(streams); + pa_assert(spec); + pa_assert(volume); + + calc_linear_float_volume(linear, volume); + + for (k = 0; k < nstreams; k++) { + + for (channel = 0; channel < spec->channels; channel++) { + pa_mix_info *m = streams + k; + m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000); + } + } +} + +static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { + unsigned k, channel; + float linear[PA_CHANNELS_MAX + VOLUME_PADDING]; + + pa_assert(streams); + pa_assert(spec); + pa_assert(volume); + + calc_linear_float_volume(linear, volume); + + for (k = 0; k < nstreams; k++) { + + for (channel = 0; channel < spec->channels; channel++) { + pa_mix_info *m = streams + k; + m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]); + } + } +} + +size_t pa_mix( + pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + pa_bool_t mute) { + + pa_cvolume full_volume; + unsigned k; + unsigned z; + void *end; + + pa_assert(streams); + pa_assert(data); + pa_assert(length); + pa_assert(spec); + + if (!volume) + volume = pa_cvolume_reset(&full_volume, spec->channels); + + if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) { + pa_silence_memory(data, length, spec); + return length; + } + + for (k = 0; k < nstreams; k++) + streams[k].ptr = pa_memblock_acquire_chunk(&streams[k].chunk); + + for (z = 0; z < nstreams; z++) + if (length > streams[z].chunk.length) + length = streams[z].chunk.length; + + end = (uint8_t*) data + length; + + switch (spec->format) { + + case PA_SAMPLE_S16NE:{ + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int32_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, lo, hi, cv = m->linear[channel].i; + + if (PA_LIKELY(cv > 0)) { + + /* Multiplying the 32bit volume factor with the + * 16bit sample might result in an 48bit value. We + * want to do without 64 bit integers and hence do + * the multiplication independently for the HI and + * LO part of the volume. */ + + hi = cv >> 16; + lo = cv & 0xFFFF; + + v = *((int16_t*) m->ptr); + v = ((v * lo) >> 16) + (v * hi); + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + *((int16_t*) data) = (int16_t) sum; + + data = (uint8_t*) data + sizeof(int16_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S16RE:{ + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int32_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, lo, hi, cv = m->linear[channel].i; + + if (PA_LIKELY(cv > 0)) { + + hi = cv >> 16; + lo = cv & 0xFFFF; + + v = PA_INT16_SWAP(*((int16_t*) m->ptr)); + v = ((v * lo) >> 16) + (v * hi); + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); + + data = (uint8_t*) data + sizeof(int16_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S32NE:{ + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_LIKELY(cv > 0)) { + + v = *((int32_t*) m->ptr); + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + *((int32_t*) data) = (int32_t) sum; + + data = (uint8_t*) data + sizeof(int32_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S32RE:{ + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_LIKELY(cv > 0)) { + + v = PA_INT32_SWAP(*((int32_t*) m->ptr)); + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum); + + data = (uint8_t*) data + sizeof(int32_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S24NE: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_LIKELY(cv > 0)) { + + v = (int32_t) (PA_READ24NE(m->ptr) << 8); + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + 3; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(data, ((uint32_t) sum) >> 8); + + data = (uint8_t*) data + 3; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S24RE: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_LIKELY(cv > 0)) { + + v = (int32_t) (PA_READ24RE(m->ptr) << 8); + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + 3; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(data, ((uint32_t) sum) >> 8); + + data = (uint8_t*) data + 3; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S24_32NE: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_LIKELY(cv > 0)) { + + v = (int32_t) (*((uint32_t*)m->ptr) << 8); + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8; + + data = (uint8_t*) data + sizeof(uint32_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S24_32RE: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_LIKELY(cv > 0)) { + + v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8); + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + 3; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8); + + data = (uint8_t*) data + sizeof(uint32_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_U8: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int32_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, cv = m->linear[channel].i; + + if (PA_LIKELY(cv > 0)) { + + v = (int32_t) *((uint8_t*) m->ptr) - 0x80; + v = (v * cv) >> 16; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + 1; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F); + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + + data = (uint8_t*) data + 1; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_ULAW: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int32_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, hi, lo, cv = m->linear[channel].i; + + if (PA_LIKELY(cv > 0)) { + + hi = cv >> 16; + lo = cv & 0xFFFF; + + v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr)); + v = ((v * lo) >> 16) + (v * hi); + sum += v; + } + m->ptr = (uint8_t*) m->ptr + 1; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2); + + data = (uint8_t*) data + 1; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_ALAW: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int32_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, hi, lo, cv = m->linear[channel].i; + + if (PA_LIKELY(cv > 0)) { + + hi = cv >> 16; + lo = cv & 0xFFFF; + + v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr)); + v = ((v * lo) >> 16) + (v * hi); + sum += v; + } + m->ptr = (uint8_t*) m->ptr + 1; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3); + + data = (uint8_t*) data + 1; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_FLOAT32NE: { + unsigned channel = 0; + + calc_linear_float_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + float sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + float v, cv = m->linear[channel].f; + + if (PA_LIKELY(cv > 0)) { + + v = *((float*) m->ptr); + v *= cv; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(float); + } + + *((float*) data) = sum; + + data = (uint8_t*) data + sizeof(float); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_FLOAT32RE: { + unsigned channel = 0; + + calc_linear_float_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + float sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + float v, cv = m->linear[channel].f; + + if (PA_LIKELY(cv > 0)) { + + v = PA_FLOAT32_SWAP(*(float*) m->ptr); + v *= cv; + sum += v; + } + m->ptr = (uint8_t*) m->ptr + sizeof(float); + } + + *((float*) data) = PA_FLOAT32_SWAP(sum); + + data = (uint8_t*) data + sizeof(float); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + default: + pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); + pa_assert_not_reached(); + } + + for (k = 0; k < nstreams; k++) + pa_memblock_release(streams[k].chunk.memblock); + + return length; +} + +typedef union { + float f; + uint32_t i; +} volume_val; + +typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume); + +static const pa_calc_volume_func_t calc_volume_table[] = { + [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume, + [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume, + [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume +}; + +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume) { + + void *ptr; + volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING]; + pa_do_volume_func_t do_volume; + + pa_assert(c); + pa_assert(spec); + pa_assert(pa_sample_spec_valid(spec)); + pa_assert(pa_frame_aligned(c->length, spec)); + pa_assert(volume); + + if (pa_memblock_is_silence(c->memblock)) + return; + + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) + return; + + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { + pa_silence_memchunk(c, spec); + return; + } + + do_volume = pa_get_volume_func(spec->format); + pa_assert(do_volume); + + calc_volume_table[spec->format] ((void *)linear, volume); + + ptr = pa_memblock_acquire_chunk(c); + + do_volume(ptr, (void *)linear, spec->channels, c->length); + + pa_memblock_release(c->memblock); +} diff --git a/src/pulsecore/mix.h b/src/pulsecore/mix.h new file mode 100644 index 0000000..34c998b --- /dev/null +++ b/src/pulsecore/mix.h @@ -0,0 +1,59 @@ +#ifndef foomixhfoo +#define foomixhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2013 Peter Meerwald + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +typedef struct pa_mix_info { + pa_memchunk chunk; + pa_cvolume volume; + void *userdata; + + /* The following fields are used internally by pa_mix(), should + * not be initialised by the caller of pa_mix(). */ + void *ptr; + union { + int32_t i; + float f; + } linear[PA_CHANNELS_MAX]; +} pa_mix_info; + +size_t pa_mix( + pa_mix_info channels[], + unsigned nchannels, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + pa_bool_t mute); + +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume); + +#endif diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index d44e140..26c0a01 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -104,650 +104,6 @@ void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { return p; } -#define VOLUME_PADDING 32 - -static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) { - unsigned channel, nchannels, padding; - - pa_assert(linear); - pa_assert(volume); - - nchannels = volume->channels; - - for (channel = 0; channel < nchannels; channel++) - linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); - - for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) - linear[channel] = linear[padding]; -} - -static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { - unsigned channel, nchannels, padding; - - pa_assert(linear); - pa_assert(volume); - - nchannels = volume->channels; - - for (channel = 0; channel < nchannels; channel++) - linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]); - - for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) - linear[channel] = linear[padding]; -} - -static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { - unsigned k, channel; - float linear[PA_CHANNELS_MAX + VOLUME_PADDING]; - - pa_assert(streams); - pa_assert(spec); - pa_assert(volume); - - calc_linear_float_volume(linear, volume); - - for (k = 0; k < nstreams; k++) { - - for (channel = 0; channel < spec->channels; channel++) { - pa_mix_info *m = streams + k; - m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000); - } - } -} - -static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { - unsigned k, channel; - float linear[PA_CHANNELS_MAX + VOLUME_PADDING]; - - pa_assert(streams); - pa_assert(spec); - pa_assert(volume); - - calc_linear_float_volume(linear, volume); - - for (k = 0; k < nstreams; k++) { - - for (channel = 0; channel < spec->channels; channel++) { - pa_mix_info *m = streams + k; - m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]); - } - } -} - -size_t pa_mix( - pa_mix_info streams[], - unsigned nstreams, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - pa_bool_t mute) { - - pa_cvolume full_volume; - unsigned k; - unsigned z; - void *end; - - pa_assert(streams); - pa_assert(data); - pa_assert(length); - pa_assert(spec); - - if (!volume) - volume = pa_cvolume_reset(&full_volume, spec->channels); - - if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) { - pa_silence_memory(data, length, spec); - return length; - } - - for (k = 0; k < nstreams; k++) - streams[k].ptr = pa_memblock_acquire_chunk(&streams[k].chunk); - - for (z = 0; z < nstreams; z++) - if (length > streams[z].chunk.length) - length = streams[z].chunk.length; - - end = (uint8_t*) data + length; - - switch (spec->format) { - - case PA_SAMPLE_S16NE:{ - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int32_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t v, lo, hi, cv = m->linear[channel].i; - - if (PA_LIKELY(cv > 0)) { - - /* Multiplying the 32bit volume factor with the - * 16bit sample might result in an 48bit value. We - * want to do without 64 bit integers and hence do - * the multiplication independently for the HI and - * LO part of the volume. */ - - hi = cv >> 16; - lo = cv & 0xFFFF; - - v = *((int16_t*) m->ptr); - v = ((v * lo) >> 16) + (v * hi); - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - *((int16_t*) data) = (int16_t) sum; - - data = (uint8_t*) data + sizeof(int16_t); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S16RE:{ - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int32_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t v, lo, hi, cv = m->linear[channel].i; - - if (PA_LIKELY(cv > 0)) { - - hi = cv >> 16; - lo = cv & 0xFFFF; - - v = PA_INT16_SWAP(*((int16_t*) m->ptr)); - v = ((v * lo) >> 16) + (v * hi); - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); - - data = (uint8_t*) data + sizeof(int16_t); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S32NE:{ - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int64_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t cv = m->linear[channel].i; - int64_t v; - - if (PA_LIKELY(cv > 0)) { - - v = *((int32_t*) m->ptr); - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - *((int32_t*) data) = (int32_t) sum; - - data = (uint8_t*) data + sizeof(int32_t); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S32RE:{ - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int64_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t cv = m->linear[channel].i; - int64_t v; - - if (PA_LIKELY(cv > 0)) { - - v = PA_INT32_SWAP(*((int32_t*) m->ptr)); - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum); - - data = (uint8_t*) data + sizeof(int32_t); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S24NE: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int64_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t cv = m->linear[channel].i; - int64_t v; - - if (PA_LIKELY(cv > 0)) { - - v = (int32_t) (PA_READ24NE(m->ptr) << 8); - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + 3; - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24NE(data, ((uint32_t) sum) >> 8); - - data = (uint8_t*) data + 3; - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S24RE: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int64_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t cv = m->linear[channel].i; - int64_t v; - - if (PA_LIKELY(cv > 0)) { - - v = (int32_t) (PA_READ24RE(m->ptr) << 8); - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + 3; - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24RE(data, ((uint32_t) sum) >> 8); - - data = (uint8_t*) data + 3; - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S24_32NE: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int64_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t cv = m->linear[channel].i; - int64_t v; - - if (PA_LIKELY(cv > 0)) { - - v = (int32_t) (*((uint32_t*)m->ptr) << 8); - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8; - - data = (uint8_t*) data + sizeof(uint32_t); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S24_32RE: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int64_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t cv = m->linear[channel].i; - int64_t v; - - if (PA_LIKELY(cv > 0)) { - - v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8); - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + 3; - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8); - - data = (uint8_t*) data + sizeof(uint32_t); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_U8: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int32_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t v, cv = m->linear[channel].i; - - if (PA_LIKELY(cv > 0)) { - - v = (int32_t) *((uint8_t*) m->ptr) - 0x80; - v = (v * cv) >> 16; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + 1; - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F); - *((uint8_t*) data) = (uint8_t) (sum + 0x80); - - data = (uint8_t*) data + 1; - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_ULAW: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int32_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t v, hi, lo, cv = m->linear[channel].i; - - if (PA_LIKELY(cv > 0)) { - - hi = cv >> 16; - lo = cv & 0xFFFF; - - v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr)); - v = ((v * lo) >> 16) + (v * hi); - sum += v; - } - m->ptr = (uint8_t*) m->ptr + 1; - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2); - - data = (uint8_t*) data + 1; - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_ALAW: { - unsigned channel = 0; - - calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - int32_t sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - int32_t v, hi, lo, cv = m->linear[channel].i; - - if (PA_LIKELY(cv > 0)) { - - hi = cv >> 16; - lo = cv & 0xFFFF; - - v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr)); - v = ((v * lo) >> 16) + (v * hi); - sum += v; - } - m->ptr = (uint8_t*) m->ptr + 1; - } - - sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3); - - data = (uint8_t*) data + 1; - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_FLOAT32NE: { - unsigned channel = 0; - - calc_linear_float_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - float sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - float v, cv = m->linear[channel].f; - - if (PA_LIKELY(cv > 0)) { - - v = *((float*) m->ptr); - v *= cv; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(float); - } - - *((float*) data) = sum; - - data = (uint8_t*) data + sizeof(float); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_FLOAT32RE: { - unsigned channel = 0; - - calc_linear_float_stream_volumes(streams, nstreams, volume, spec); - - while (data < end) { - float sum = 0; - unsigned i; - - for (i = 0; i < nstreams; i++) { - pa_mix_info *m = streams + i; - float v, cv = m->linear[channel].f; - - if (PA_LIKELY(cv > 0)) { - - v = PA_FLOAT32_SWAP(*(float*) m->ptr); - v *= cv; - sum += v; - } - m->ptr = (uint8_t*) m->ptr + sizeof(float); - } - - *((float*) data) = PA_FLOAT32_SWAP(sum); - - data = (uint8_t*) data + sizeof(float); - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - default: - pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); - pa_assert_not_reached(); - } - - for (k = 0; k < nstreams; k++) - pa_memblock_release(streams[k].chunk.memblock); - - return length; -} - -typedef union { - float f; - uint32_t i; -} volume_val; - -typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume); - -static const pa_calc_volume_func_t calc_volume_table[] = { - [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume, - [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume, - [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, - [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume -}; - -void pa_volume_memchunk( - pa_memchunk*c, - const pa_sample_spec *spec, - const pa_cvolume *volume) { - - void *ptr; - volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING]; - pa_do_volume_func_t do_volume; - - pa_assert(c); - pa_assert(spec); - pa_assert(pa_sample_spec_valid(spec)); - pa_assert(pa_frame_aligned(c->length, spec)); - pa_assert(volume); - - if (pa_memblock_is_silence(c->memblock)) - return; - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) - return; - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { - pa_silence_memchunk(c, spec); - return; - } - - do_volume = pa_get_volume_func(spec->format); - pa_assert(do_volume); - - calc_volume_table[spec->format] ((void *)linear, volume); - - ptr = pa_memblock_acquire_chunk(c); - - do_volume (ptr, (void *)linear, spec->channels, c->length); - - pa_memblock_release(c->memblock); -} - size_t pa_frame_align(size_t l, const pa_sample_spec *ss) { size_t fs; diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index a6b4600..d308caa 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -44,34 +44,6 @@ pa_memblock* pa_silence_memblock(pa_memblock *b, const pa_sample_spec *spec); pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length); -typedef struct pa_mix_info { - pa_memchunk chunk; - pa_cvolume volume; - void *userdata; - - /* The following fields are used internally by pa_mix(), should - * not be initialised by the caller of pa_mix(). */ - void *ptr; - union { - int32_t i; - float f; - } linear[PA_CHANNELS_MAX]; -} pa_mix_info; - -size_t pa_mix( - pa_mix_info channels[], - unsigned nchannels, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - pa_bool_t mute); - -void pa_volume_memchunk( - pa_memchunk*c, - const pa_sample_spec *spec, - const pa_cvolume *volume); - size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index ae89aed..a6ddb15 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index a8a91d6..175cfe5 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 24d3314..4101dea 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "sound-file-stream.h" diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 8775c1e..0f1a946 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 8c16606..f336119 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include "source.h" diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c index e5190c7..4980dd0 100644 --- a/src/tests/mix-test.c +++ b/src/tests/mix-test.c @@ -33,6 +33,7 @@ #include #include #include +#include /* PA_SAMPLE_U8 */