libs: audio-channel-mixer: add support for non-interleaved audio buffers

https://bugzilla.gnome.org/show_bug.cgi?id=705986
This commit is contained in:
George Kiagiadakis 2018-01-31 19:28:57 +02:00
parent 294bfb7300
commit 108a911610

View file

@ -54,8 +54,8 @@ ensure_debug_category (void)
#define PRECISION_INT 10 #define PRECISION_INT 10
typedef void (*MixerFunc) (GstAudioChannelMixer * mix, const gpointer src, typedef void (*MixerFunc) (GstAudioChannelMixer * mix, const gpointer src[],
gpointer dst, gint samples); gpointer dst[], gint samples);
struct _GstAudioChannelMixer struct _GstAudioChannelMixer
{ {
@ -694,101 +694,117 @@ gst_audio_channel_mixer_setup_matrix (GstAudioChannelMixerFlags flags,
return matrix; return matrix;
} }
static void #define DEFINE_GET_DATA_FUNCS(type) \
gst_audio_channel_mixer_mix_int16 (GstAudioChannelMixer * mix, static inline type \
const gint16 * in_data, gint16 * out_data, gint samples) _get_in_data_interleaved_##type (const type * in_data[], \
{ gint sample, gint channel, gint total_channels) \
gint in, out, n; { \
gint32 res; return in_data[0][sample * total_channels + channel]; \
gint inchannels, outchannels; } \
\
inchannels = mix->in_channels; static inline type * \
outchannels = mix->out_channels; _get_out_data_interleaved_##type (type * out_data[], \
gint sample, gint channel, gint total_channels) \
for (n = 0; n < samples; n++) { { \
for (out = 0; out < outchannels; out++) { return &out_data[0][sample * total_channels + channel]; \
/* convert */ } \
res = 0; \
for (in = 0; in < inchannels; in++) static inline type \
res += in_data[n * inchannels + in] * mix->matrix_int[in][out]; _get_in_data_planar_##type (const type * in_data[], \
gint sample, gint channel, gint total_channels) \
/* remove factor from int matrix */ { \
res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT; (void) total_channels; \
out_data[n * outchannels + out] = CLAMP (res, G_MININT16, G_MAXINT16); return in_data[channel][sample]; \
} } \
} \
static inline type * \
_get_out_data_planar_##type (type * out_data[], \
gint sample, gint channel, gint total_channels) \
{ \
(void) total_channels; \
return &out_data[channel][sample]; \
} }
static void #define DEFINE_INTEGER_MIX_FUNC(bits, resbits, inlayout, outlayout) \
gst_audio_channel_mixer_mix_int32 (GstAudioChannelMixer * mix, static void \
const gint32 * in_data, gint32 * out_data, gint samples) gst_audio_channel_mixer_mix_int##bits##_##inlayout##_##outlayout ( \
{ GstAudioChannelMixer * mix, const gint##bits * in_data[], \
gint in, out, n; gint##bits * out_data[], gint samples) \
gint64 res; { \
gint inchannels, outchannels; gint in, out, n; \
gint##resbits res; \
inchannels = mix->in_channels; gint inchannels, outchannels; \
outchannels = mix->out_channels; \
inchannels = mix->in_channels; \
for (n = 0; n < samples; n++) { outchannels = mix->out_channels; \
for (out = 0; out < outchannels; out++) { \
/* convert */ for (n = 0; n < samples; n++) { \
res = 0; for (out = 0; out < outchannels; out++) { \
for (in = 0; in < inchannels; in++) /* convert */ \
res += in_data[n * inchannels + in] * (gint64) mix->matrix_int[in][out]; res = 0; \
for (in = 0; in < inchannels; in++) \
/* remove factor from int matrix */ res += \
res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT; _get_in_data_##inlayout##_gint##bits (in_data, n, in, inchannels) * \
out_data[n * outchannels + out] = CLAMP (res, G_MININT32, G_MAXINT32); (gint##resbits) mix->matrix_int[in][out]; \
} \
} /* remove factor from int matrix */ \
res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT; \
*_get_out_data_##outlayout##_gint##bits (out_data, n, out, outchannels) = \
CLAMP (res, G_MININT##bits, G_MAXINT##bits); \
} \
} \
} }
static void #define DEFINE_FLOAT_MIX_FUNC(type, inlayout, outlayout) \
gst_audio_channel_mixer_mix_float (GstAudioChannelMixer * mix, static void \
const gfloat * in_data, gfloat * out_data, gint samples) gst_audio_channel_mixer_mix_##type##_##inlayout##_##outlayout ( \
{ GstAudioChannelMixer * mix, const g##type * in_data[], \
gint in, out, n; g##type * out_data[], gint samples) \
gfloat res; { \
gint inchannels, outchannels; gint in, out, n; \
g##type res; \
inchannels = mix->in_channels; gint inchannels, outchannels; \
outchannels = mix->out_channels; \
inchannels = mix->in_channels; \
for (n = 0; n < samples; n++) { outchannels = mix->out_channels; \
for (out = 0; out < outchannels; out++) { \
/* convert */ for (n = 0; n < samples; n++) { \
res = 0.0; for (out = 0; out < outchannels; out++) { \
for (in = 0; in < inchannels; in++) /* convert */ \
res += in_data[n * inchannels + in] * mix->matrix[in][out]; res = 0.0; \
for (in = 0; in < inchannels; in++) \
out_data[n * outchannels + out] = res; res += \
} _get_in_data_##inlayout##_g##type (in_data, n, in, inchannels) * \
} mix->matrix[in][out]; \
\
*_get_out_data_##outlayout##_g##type (out_data, n, out, outchannels) = res; \
} \
} \
} }
static void DEFINE_GET_DATA_FUNCS (gint16);
gst_audio_channel_mixer_mix_double (GstAudioChannelMixer * mix, DEFINE_INTEGER_MIX_FUNC (16, 32, interleaved, interleaved);
const gdouble * in_data, gdouble * out_data, gint samples) DEFINE_INTEGER_MIX_FUNC (16, 32, interleaved, planar);
{ DEFINE_INTEGER_MIX_FUNC (16, 32, planar, interleaved);
gint in, out, n; DEFINE_INTEGER_MIX_FUNC (16, 32, planar, planar);
gdouble res;
gint inchannels, outchannels;
inchannels = mix->in_channels; DEFINE_GET_DATA_FUNCS (gint32);
outchannels = mix->out_channels; DEFINE_INTEGER_MIX_FUNC (32, 64, interleaved, interleaved);
DEFINE_INTEGER_MIX_FUNC (32, 64, interleaved, planar);
DEFINE_INTEGER_MIX_FUNC (32, 64, planar, interleaved);
DEFINE_INTEGER_MIX_FUNC (32, 64, planar, planar);
for (n = 0; n < samples; n++) { DEFINE_GET_DATA_FUNCS (gfloat);
for (out = 0; out < outchannels; out++) { DEFINE_FLOAT_MIX_FUNC (float, interleaved, interleaved);
/* convert */ DEFINE_FLOAT_MIX_FUNC (float, interleaved, planar);
res = 0.0; DEFINE_FLOAT_MIX_FUNC (float, planar, interleaved);
for (in = 0; in < inchannels; in++) DEFINE_FLOAT_MIX_FUNC (float, planar, planar);
res += in_data[n * inchannels + in] * mix->matrix[in][out];
out_data[n * outchannels + out] = res; DEFINE_GET_DATA_FUNCS (gdouble);
} DEFINE_FLOAT_MIX_FUNC (double, interleaved, interleaved);
} DEFINE_FLOAT_MIX_FUNC (double, interleaved, planar);
} DEFINE_FLOAT_MIX_FUNC (double, planar, interleaved);
DEFINE_FLOAT_MIX_FUNC (double, planar, planar);
/** /**
* gst_audio_channel_mixer_new_with_matrix: (skip): * gst_audio_channel_mixer_new_with_matrix: (skip):
@ -872,16 +888,80 @@ gst_audio_channel_mixer_new_with_matrix (GstAudioChannelMixerFlags flags,
switch (format) { switch (format) {
case GST_AUDIO_FORMAT_S16: case GST_AUDIO_FORMAT_S16:
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_int16; if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int16_planar_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int16_planar_interleaved;
}
} else {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int16_interleaved_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int16_interleaved_interleaved;
}
}
break; break;
case GST_AUDIO_FORMAT_S32: case GST_AUDIO_FORMAT_S32:
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_int32; if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int32_planar_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int32_planar_interleaved;
}
} else {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int32_interleaved_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_int32_interleaved_interleaved;
}
}
break; break;
case GST_AUDIO_FORMAT_F32: case GST_AUDIO_FORMAT_F32:
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_float; if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_float_planar_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_float_planar_interleaved;
}
} else {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_float_interleaved_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_float_interleaved_interleaved;
}
}
break; break;
case GST_AUDIO_FORMAT_F64: case GST_AUDIO_FORMAT_F64:
mix->func = (MixerFunc) gst_audio_channel_mixer_mix_double; if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_double_planar_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_double_planar_interleaved;
}
} else {
if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_double_interleaved_planar;
} else {
mix->func = (MixerFunc)
gst_audio_channel_mixer_mix_double_interleaved_interleaved;
}
}
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
@ -992,5 +1072,5 @@ gst_audio_channel_mixer_samples (GstAudioChannelMixer * mix,
g_return_if_fail (mix != NULL); g_return_if_fail (mix != NULL);
g_return_if_fail (mix->matrix != NULL); g_return_if_fail (mix->matrix != NULL);
mix->func (mix, in[0], out[0], samples); mix->func (mix, in, out, samples);
} }