2 * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
3 * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
5 * audio-channel-mixer.c: setup of channel conversion matrices
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
30 #include "audio-channel-mixer.h"
32 #ifndef GST_DISABLE_GST_DEBUG
33 #define GST_CAT_DEFAULT ensure_debug_category()
34 static GstDebugCategory *
35 ensure_debug_category (void)
37 static gsize cat_gonce = 0;
39 if (g_once_init_enter (&cat_gonce)) {
42 cat_done = (gsize) _gst_debug_category_new ("audio-channel-mixer", 0,
43 "audio-channel-mixer object");
45 g_once_init_leave (&cat_gonce, cat_done);
48 return (GstDebugCategory *) cat_gonce;
51 #define ensure_debug_category() /* NOOP */
52 #endif /* GST_DISABLE_GST_DEBUG */
55 #define PRECISION_INT 10
57 typedef void (*MixerFunc) (GstAudioChannelMixer * mix, const gpointer src[],
58 gpointer dst[], gint samples);
60 struct _GstAudioChannelMixer
65 /* channel conversion matrix, m[in_channels][out_channels].
66 * If identity matrix, passthrough applies. */
69 /* channel conversion matrix with int values, m[in_channels][out_channels].
70 * this is matrix * (2^10) as integers */
77 * gst_audio_channel_mixer_free:
78 * @mix: a #GstAudioChannelMixer
80 * Free memory allocated by @mix.
83 gst_audio_channel_mixer_free (GstAudioChannelMixer * mix)
88 for (i = 0; i < mix->in_channels; i++)
89 g_free (mix->matrix[i]);
93 for (i = 0; i < mix->in_channels; i++)
94 g_free (mix->matrix_int[i]);
95 g_free (mix->matrix_int);
96 mix->matrix_int = NULL;
98 g_slice_free (GstAudioChannelMixer, mix);
102 * Detect and fill in identical channels. E.g.
103 * forward the left/right front channels in a
104 * 5.1 to 2.0 conversion.
108 gst_audio_channel_mixer_fill_identical (gfloat ** matrix,
109 gint in_channels, GstAudioChannelPosition * in_position, gint out_channels,
110 GstAudioChannelPosition * out_position, GstAudioChannelMixerFlags flags)
114 /* Apart from the compatible channel assignments, we can also have
115 * same channel assignments. This is much simpler, we simply copy
116 * the value from source to dest! */
117 for (co = 0; co < out_channels; co++) {
118 /* find a channel in input with same position */
119 for (ci = 0; ci < in_channels; ci++) {
120 /* If the input was unpositioned, we're simply building
121 * an identity matrix */
122 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN) {
123 matrix[ci][co] = ci == co ? 1.0 : 0.0;
124 } else if (in_position[ci] == out_position[co]) {
125 matrix[ci][co] = 1.0;
132 * Detect and fill in compatible channels. E.g.
133 * forward left/right front to mono (or the other
134 * way around) when going from 2.0 to 1.0.
138 gst_audio_channel_mixer_fill_compatible (gfloat ** matrix, gint in_channels,
139 GstAudioChannelPosition * in_position, gint out_channels,
140 GstAudioChannelPosition * out_position)
142 /* Conversions from one-channel to compatible two-channel configs */
145 GstAudioChannelPosition pos1[2];
146 GstAudioChannelPosition pos2[1];
148 /* front: mono <-> stereo */
150 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
151 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
152 GST_AUDIO_CHANNEL_POSITION_MONO}},
153 /* front center: 2 <-> 1 */
155 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
156 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
157 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}},
160 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
161 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
162 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { {
163 GST_AUDIO_CHANNEL_POSITION_INVALID}}
167 /* conversions from compatible (but not the same) channel schemes */
168 for (c = 0; conv[c].pos1[0] != GST_AUDIO_CHANNEL_POSITION_INVALID; c++) {
169 gint pos1_0 = -1, pos1_1 = -1, pos1_2 = -1;
170 gint pos2_0 = -1, pos2_1 = -1, pos2_2 = -1;
173 for (n = 0; n < in_channels; n++) {
174 if (in_position[n] == conv[c].pos1[0])
176 else if (in_position[n] == conv[c].pos1[1])
178 else if (in_position[n] == conv[c].pos2[0])
181 for (n = 0; n < out_channels; n++) {
182 if (out_position[n] == conv[c].pos1[0])
184 else if (out_position[n] == conv[c].pos1[1])
186 else if (out_position[n] == conv[c].pos2[0])
190 /* The general idea here is to fill in channels from the same position
191 * as good as possible. This means mixing left<->center and right<->center.
195 if (pos1_0 != -1 && pos1_2 == -1 && pos2_0 == -1 && pos2_2 != -1)
196 matrix[pos1_0][pos2_2] = 1.0;
197 else if (pos1_0 != -1 && pos1_2 != -1 && pos2_0 == -1 && pos2_2 != -1)
198 matrix[pos1_0][pos2_2] = 0.5;
199 else if (pos1_0 != -1 && pos1_2 == -1 && pos2_0 != -1 && pos2_2 != -1)
200 matrix[pos1_0][pos2_2] = 1.0;
202 /* right -> center */
203 if (pos1_1 != -1 && pos1_2 == -1 && pos2_1 == -1 && pos2_2 != -1)
204 matrix[pos1_1][pos2_2] = 1.0;
205 else if (pos1_1 != -1 && pos1_2 != -1 && pos2_1 == -1 && pos2_2 != -1)
206 matrix[pos1_1][pos2_2] = 0.5;
207 else if (pos1_1 != -1 && pos1_2 == -1 && pos2_1 != -1 && pos2_2 != -1)
208 matrix[pos1_1][pos2_2] = 1.0;
211 if (pos1_2 != -1 && pos1_0 == -1 && pos2_2 == -1 && pos2_0 != -1)
212 matrix[pos1_2][pos2_0] = 1.0;
213 else if (pos1_2 != -1 && pos1_0 != -1 && pos2_2 == -1 && pos2_0 != -1)
214 matrix[pos1_2][pos2_0] = 0.5;
215 else if (pos1_2 != -1 && pos1_0 == -1 && pos2_2 != -1 && pos2_0 != -1)
216 matrix[pos1_2][pos2_0] = 1.0;
218 /* center -> right */
219 if (pos1_2 != -1 && pos1_1 == -1 && pos2_2 == -1 && pos2_1 != -1)
220 matrix[pos1_2][pos2_1] = 1.0;
221 else if (pos1_2 != -1 && pos1_1 != -1 && pos2_2 == -1 && pos2_1 != -1)
222 matrix[pos1_2][pos2_1] = 0.5;
223 else if (pos1_2 != -1 && pos1_1 == -1 && pos2_2 != -1 && pos2_1 != -1)
224 matrix[pos1_2][pos2_1] = 1.0;
229 * Detect and fill in channels not handled by the
230 * above two, e.g. center to left/right front in
231 * 5.1 to 2.0 (or the other way around).
233 * Unfortunately, limited to static conversions
238 gst_audio_channel_mixer_detect_pos (gint channels,
239 GstAudioChannelPosition position[64], gint * f, gboolean * has_f, gint * c,
240 gboolean * has_c, gint * r, gboolean * has_r, gint * s, gboolean * has_s,
241 gint * b, gboolean * has_b)
245 for (n = 0; n < channels; n++) {
246 switch (position[n]) {
247 case GST_AUDIO_CHANNEL_POSITION_MONO:
251 case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
255 case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
259 case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
263 case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
267 case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
271 case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
275 case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
279 case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
283 case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
287 case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
291 case GST_AUDIO_CHANNEL_POSITION_LFE1:
302 gst_audio_channel_mixer_fill_one_other (gfloat ** matrix,
303 gint * from_idx, gint * to_idx, gfloat ratio)
306 /* src & dst have center => passthrough */
307 if (from_idx[1] != -1 && to_idx[1] != -1) {
308 matrix[from_idx[1]][to_idx[1]] = ratio;
311 /* src & dst have left => passthrough */
312 if (from_idx[0] != -1 && to_idx[0] != -1) {
313 matrix[from_idx[0]][to_idx[0]] = ratio;
316 /* src & dst have right => passthrough */
317 if (from_idx[2] != -1 && to_idx[2] != -1) {
318 matrix[from_idx[2]][to_idx[2]] = ratio;
321 /* src has left & dst has center => put into center */
322 if (from_idx[0] != -1 && to_idx[1] != -1 && from_idx[1] != -1) {
323 matrix[from_idx[0]][to_idx[1]] = 0.5 * ratio;
324 } else if (from_idx[0] != -1 && to_idx[1] != -1 && from_idx[1] == -1) {
325 matrix[from_idx[0]][to_idx[1]] = ratio;
328 /* src has right & dst has center => put into center */
329 if (from_idx[2] != -1 && to_idx[1] != -1 && from_idx[1] != -1) {
330 matrix[from_idx[2]][to_idx[1]] = 0.5 * ratio;
331 } else if (from_idx[2] != -1 && to_idx[1] != -1 && from_idx[1] == -1) {
332 matrix[from_idx[2]][to_idx[1]] = ratio;
335 /* src has center & dst has left => passthrough */
336 if (from_idx[1] != -1 && to_idx[0] != -1 && from_idx[0] != -1) {
337 matrix[from_idx[1]][to_idx[0]] = 0.5 * ratio;
338 } else if (from_idx[1] != -1 && to_idx[0] != -1 && from_idx[0] == -1) {
339 matrix[from_idx[1]][to_idx[0]] = ratio;
342 /* src has center & dst has right => passthrough */
343 if (from_idx[1] != -1 && to_idx[2] != -1 && from_idx[2] != -1) {
344 matrix[from_idx[1]][to_idx[2]] = 0.5 * ratio;
345 } else if (from_idx[1] != -1 && to_idx[2] != -1 && from_idx[2] == -1) {
346 matrix[from_idx[1]][to_idx[2]] = ratio;
350 #define RATIO_CENTER_FRONT (1.0 / sqrt (2.0))
351 #define RATIO_CENTER_SIDE (1.0 / 2.0)
352 #define RATIO_CENTER_REAR (1.0 / sqrt (8.0))
354 #define RATIO_FRONT_CENTER (1.0 / sqrt (2.0))
355 #define RATIO_FRONT_SIDE (1.0 / sqrt (2.0))
356 #define RATIO_FRONT_REAR (1.0 / 2.0)
358 #define RATIO_SIDE_CENTER (1.0 / 2.0)
359 #define RATIO_SIDE_FRONT (1.0 / sqrt (2.0))
360 #define RATIO_SIDE_REAR (1.0 / sqrt (2.0))
362 #define RATIO_CENTER_BASS (1.0 / sqrt (2.0))
363 #define RATIO_FRONT_BASS (1.0)
364 #define RATIO_SIDE_BASS (1.0 / sqrt (2.0))
365 #define RATIO_REAR_BASS (1.0 / sqrt (2.0))
368 gst_audio_channel_mixer_fill_others (gfloat ** matrix, gint in_channels,
369 GstAudioChannelPosition * in_position, gint out_channels,
370 GstAudioChannelPosition * out_position)
372 gboolean in_has_front = FALSE, out_has_front = FALSE,
373 in_has_center = FALSE, out_has_center = FALSE,
374 in_has_rear = FALSE, out_has_rear = FALSE,
375 in_has_side = FALSE, out_has_side = FALSE,
376 in_has_bass = FALSE, out_has_bass = FALSE;
377 /* LEFT, RIGHT, MONO */
378 gint in_f[3] = { -1, -1, -1 };
379 gint out_f[3] = { -1, -1, -1 };
380 /* LOC, ROC, CENTER */
381 gint in_c[3] = { -1, -1, -1 };
382 gint out_c[3] = { -1, -1, -1 };
383 /* RLEFT, RRIGHT, RCENTER */
384 gint in_r[3] = { -1, -1, -1 };
385 gint out_r[3] = { -1, -1, -1 };
386 /* SLEFT, INVALID, SRIGHT */
387 gint in_s[3] = { -1, -1, -1 };
388 gint out_s[3] = { -1, -1, -1 };
389 /* INVALID, LFE, INVALID */
390 gint in_b[3] = { -1, -1, -1 };
391 gint out_b[3] = { -1, -1, -1 };
393 /* First see where (if at all) the various channels from/to
394 * which we want to convert are located in our matrix/array. */
395 gst_audio_channel_mixer_detect_pos (in_channels, in_position,
397 in_c, &in_has_center, in_r, &in_has_rear,
398 in_s, &in_has_side, in_b, &in_has_bass);
399 gst_audio_channel_mixer_detect_pos (out_channels, out_position,
400 out_f, &out_has_front,
401 out_c, &out_has_center, out_r, &out_has_rear,
402 out_s, &out_has_side, out_b, &out_has_bass);
404 /* The general idea here is:
405 * - if the source has a channel that the destination doesn't have mix
406 * it into the nearest available destination channel
407 * - if the destination has a channel that the source doesn't have mix
408 * the nearest source channel into the destination channel
410 * The ratio for the mixing becomes lower as the distance between the
411 * channels gets larger
414 /* center <-> front/side/rear */
415 if (!in_has_center && in_has_front && out_has_center) {
416 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_c,
418 } else if (!in_has_center && !in_has_front && in_has_side && out_has_center) {
419 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_c,
421 } else if (!in_has_center && !in_has_front && !in_has_side && in_has_rear
423 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_c,
425 } else if (in_has_center && !out_has_center && out_has_front) {
426 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_f,
428 } else if (in_has_center && !out_has_center && !out_has_front && out_has_side) {
429 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_s,
431 } else if (in_has_center && !out_has_center && !out_has_front && !out_has_side
433 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_r,
437 /* front <-> center/side/rear */
438 if (!in_has_front && in_has_center && !in_has_side && out_has_front) {
439 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_f,
441 } else if (!in_has_front && !in_has_center && in_has_side && out_has_front) {
442 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_f,
444 } else if (!in_has_front && in_has_center && in_has_side && out_has_front) {
445 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_f,
446 0.5 * RATIO_CENTER_FRONT);
447 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_f,
448 0.5 * RATIO_FRONT_SIDE);
449 } else if (!in_has_front && !in_has_center && !in_has_side && in_has_rear
451 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_f,
453 } else if (in_has_front && out_has_center && !out_has_side && !out_has_front) {
454 gst_audio_channel_mixer_fill_one_other (matrix,
455 in_f, out_c, RATIO_CENTER_FRONT);
456 } else if (in_has_front && !out_has_center && out_has_side && !out_has_front) {
457 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_s,
459 } else if (in_has_front && out_has_center && out_has_side && !out_has_front) {
460 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_c,
461 0.5 * RATIO_CENTER_FRONT);
462 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_s,
463 0.5 * RATIO_FRONT_SIDE);
464 } else if (in_has_front && !out_has_center && !out_has_side && !out_has_front
466 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_r,
470 /* side <-> center/front/rear */
471 if (!in_has_side && in_has_front && !in_has_rear && out_has_side) {
472 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_s,
474 } else if (!in_has_side && !in_has_front && in_has_rear && out_has_side) {
475 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_s,
477 } else if (!in_has_side && in_has_front && in_has_rear && out_has_side) {
478 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_s,
479 0.5 * RATIO_FRONT_SIDE);
480 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_s,
481 0.5 * RATIO_SIDE_REAR);
482 } else if (!in_has_side && !in_has_front && !in_has_rear && in_has_center
484 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_s,
486 } else if (in_has_side && out_has_front && !out_has_rear && !out_has_side) {
487 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_f,
489 } else if (in_has_side && !out_has_front && out_has_rear && !out_has_side) {
490 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_r,
492 } else if (in_has_side && out_has_front && out_has_rear && !out_has_side) {
493 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_f,
494 0.5 * RATIO_FRONT_SIDE);
495 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_r,
496 0.5 * RATIO_SIDE_REAR);
497 } else if (in_has_side && !out_has_front && !out_has_rear && out_has_center
499 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_c,
503 /* rear <-> center/front/side */
504 if (!in_has_rear && in_has_side && out_has_rear) {
505 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_r,
507 } else if (!in_has_rear && !in_has_side && in_has_front && out_has_rear) {
508 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_r,
510 } else if (!in_has_rear && !in_has_side && !in_has_front && in_has_center
512 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_r,
514 } else if (in_has_rear && !out_has_rear && out_has_side) {
515 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_s,
517 } else if (in_has_rear && !out_has_rear && !out_has_side && out_has_front) {
518 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_f,
520 } else if (in_has_rear && !out_has_rear && !out_has_side && !out_has_front
522 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_c,
527 if (in_has_bass && !out_has_bass) {
528 if (out_has_center) {
529 gst_audio_channel_mixer_fill_one_other (matrix, in_b, out_c,
533 gst_audio_channel_mixer_fill_one_other (matrix, in_b, out_f,
537 gst_audio_channel_mixer_fill_one_other (matrix, in_b, out_s,
541 gst_audio_channel_mixer_fill_one_other (matrix, in_b, out_r,
544 } else if (!in_has_bass && out_has_bass) {
546 gst_audio_channel_mixer_fill_one_other (matrix, in_c, out_b,
550 gst_audio_channel_mixer_fill_one_other (matrix, in_f, out_b,
554 gst_audio_channel_mixer_fill_one_other (matrix, in_s, out_b,
558 gst_audio_channel_mixer_fill_one_other (matrix, in_r, out_b,
565 * Normalize output values.
569 gst_audio_channel_mixer_fill_normalize (gfloat ** matrix, gint in_channels,
575 for (j = 0; j < out_channels; j++) {
578 for (i = 0; i < in_channels; i++) {
579 sum += fabs (matrix[i][j]);
586 /* normalize to mix */
590 for (j = 0; j < out_channels; j++) {
591 for (i = 0; i < in_channels; i++) {
598 gst_audio_channel_mixer_fill_special (gfloat ** matrix, gint in_channels,
599 GstAudioChannelPosition * in_position, gint out_channels,
600 GstAudioChannelPosition * out_position)
602 /* Special, standard conversions here */
604 /* Mono<->Stereo, just a fast-path */
605 if (in_channels == 2 && out_channels == 1 &&
606 ((in_position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT &&
607 in_position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) ||
608 (in_position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &&
609 in_position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) &&
610 out_position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
614 } else if (in_channels == 1 && out_channels == 2 &&
615 ((out_position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT &&
616 out_position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) ||
617 (out_position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &&
618 out_position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) &&
619 in_position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
625 /* TODO: 5.1 <-> Stereo and other standard conversions */
631 * Automagically generate conversion matrix.
635 gst_audio_channel_mixer_fill_matrix (gfloat ** matrix,
636 GstAudioChannelMixerFlags flags, gint in_channels,
637 GstAudioChannelPosition * in_position, gint out_channels,
638 GstAudioChannelPosition * out_position)
640 if (gst_audio_channel_mixer_fill_special (matrix, in_channels, in_position,
641 out_channels, out_position))
644 gst_audio_channel_mixer_fill_identical (matrix, in_channels, in_position,
645 out_channels, out_position, flags);
647 if (!(flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN)) {
648 gst_audio_channel_mixer_fill_compatible (matrix, in_channels, in_position,
649 out_channels, out_position);
650 gst_audio_channel_mixer_fill_others (matrix, in_channels, in_position,
651 out_channels, out_position);
652 gst_audio_channel_mixer_fill_normalize (matrix, in_channels, out_channels);
656 /* only call mix after mix->matrix is fully set up and normalized */
658 gst_audio_channel_mixer_setup_matrix_int (GstAudioChannelMixer * mix)
662 gfloat factor = (1 << PRECISION_INT);
664 mix->matrix_int = g_new0 (gint *, mix->in_channels);
666 for (i = 0; i < mix->in_channels; i++) {
667 mix->matrix_int[i] = g_new (gint, mix->out_channels);
669 for (j = 0; j < mix->out_channels; j++) {
670 tmp = mix->matrix[i][j] * factor;
671 mix->matrix_int[i][j] = (gint) tmp;
677 gst_audio_channel_mixer_setup_matrix (GstAudioChannelMixerFlags flags,
678 gint in_channels, GstAudioChannelPosition * in_position,
679 gint out_channels, GstAudioChannelPosition * out_position)
682 gfloat **matrix = g_new0 (gfloat *, in_channels);
684 for (i = 0; i < in_channels; i++) {
685 matrix[i] = g_new (gfloat, out_channels);
686 for (j = 0; j < out_channels; j++)
690 /* setup the matrix' internal values */
691 gst_audio_channel_mixer_fill_matrix (matrix, flags, in_channels, in_position,
692 out_channels, out_position);
697 #define DEFINE_GET_DATA_FUNCS(type) \
699 _get_in_data_interleaved_##type (const type * in_data[], \
700 gint sample, gint channel, gint total_channels) \
702 return in_data[0][sample * total_channels + channel]; \
705 static inline type * \
706 _get_out_data_interleaved_##type (type * out_data[], \
707 gint sample, gint channel, gint total_channels) \
709 return &out_data[0][sample * total_channels + channel]; \
713 _get_in_data_planar_##type (const type * in_data[], \
714 gint sample, gint channel, gint total_channels) \
716 (void) total_channels; \
717 return in_data[channel][sample]; \
720 static inline type * \
721 _get_out_data_planar_##type (type * out_data[], \
722 gint sample, gint channel, gint total_channels) \
724 (void) total_channels; \
725 return &out_data[channel][sample]; \
728 #define DEFINE_INTEGER_MIX_FUNC(bits, resbits, inlayout, outlayout) \
730 gst_audio_channel_mixer_mix_int##bits##_##inlayout##_##outlayout ( \
731 GstAudioChannelMixer * mix, const gint##bits * in_data[], \
732 gint##bits * out_data[], gint samples) \
736 gint inchannels, outchannels; \
738 inchannels = mix->in_channels; \
739 outchannels = mix->out_channels; \
741 for (n = 0; n < samples; n++) { \
742 for (out = 0; out < outchannels; out++) { \
745 for (in = 0; in < inchannels; in++) \
747 _get_in_data_##inlayout##_gint##bits (in_data, n, in, inchannels) * \
748 (gint##resbits) mix->matrix_int[in][out]; \
750 /* remove factor from int matrix */ \
751 res = (res + (1 << (PRECISION_INT - 1))) >> PRECISION_INT; \
752 *_get_out_data_##outlayout##_gint##bits (out_data, n, out, outchannels) = \
753 CLAMP (res, G_MININT##bits, G_MAXINT##bits); \
758 #define DEFINE_FLOAT_MIX_FUNC(type, inlayout, outlayout) \
760 gst_audio_channel_mixer_mix_##type##_##inlayout##_##outlayout ( \
761 GstAudioChannelMixer * mix, const g##type * in_data[], \
762 g##type * out_data[], gint samples) \
766 gint inchannels, outchannels; \
768 inchannels = mix->in_channels; \
769 outchannels = mix->out_channels; \
771 for (n = 0; n < samples; n++) { \
772 for (out = 0; out < outchannels; out++) { \
775 for (in = 0; in < inchannels; in++) \
777 _get_in_data_##inlayout##_g##type (in_data, n, in, inchannels) * \
778 mix->matrix[in][out]; \
780 *_get_out_data_##outlayout##_g##type (out_data, n, out, outchannels) = res; \
785 DEFINE_GET_DATA_FUNCS (gint16);
786 DEFINE_INTEGER_MIX_FUNC (16, 32, interleaved, interleaved);
787 DEFINE_INTEGER_MIX_FUNC (16, 32, interleaved, planar);
788 DEFINE_INTEGER_MIX_FUNC (16, 32, planar, interleaved);
789 DEFINE_INTEGER_MIX_FUNC (16, 32, planar, planar);
791 DEFINE_GET_DATA_FUNCS (gint32);
792 DEFINE_INTEGER_MIX_FUNC (32, 64, interleaved, interleaved);
793 DEFINE_INTEGER_MIX_FUNC (32, 64, interleaved, planar);
794 DEFINE_INTEGER_MIX_FUNC (32, 64, planar, interleaved);
795 DEFINE_INTEGER_MIX_FUNC (32, 64, planar, planar);
797 DEFINE_GET_DATA_FUNCS (gfloat);
798 DEFINE_FLOAT_MIX_FUNC (float, interleaved, interleaved);
799 DEFINE_FLOAT_MIX_FUNC (float, interleaved, planar);
800 DEFINE_FLOAT_MIX_FUNC (float, planar, interleaved);
801 DEFINE_FLOAT_MIX_FUNC (float, planar, planar);
803 DEFINE_GET_DATA_FUNCS (gdouble);
804 DEFINE_FLOAT_MIX_FUNC (double, interleaved, interleaved);
805 DEFINE_FLOAT_MIX_FUNC (double, interleaved, planar);
806 DEFINE_FLOAT_MIX_FUNC (double, planar, interleaved);
807 DEFINE_FLOAT_MIX_FUNC (double, planar, planar);
810 * gst_audio_channel_mixer_new_with_matrix: (skip):
811 * @flags: #GstAudioChannelMixerFlags
812 * @in_channels: number of input channels
813 * @out_channels: number of output channels
814 * @matrix: (transfer full) (nullable): channel conversion matrix, m[@in_channels][@out_channels].
815 * If identity matrix, passthrough applies. If %NULL, a (potentially truncated)
816 * identity matrix is generated.
818 * Create a new channel mixer object for the given parameters.
820 * Returns: a new #GstAudioChannelMixer object, or %NULL if @format isn't supported,
821 * @matrix is invalid, or @matrix is %NULL and @in_channels != @out_channels.
822 * Free with gst_audio_channel_mixer_free() after usage.
826 GstAudioChannelMixer *
827 gst_audio_channel_mixer_new_with_matrix (GstAudioChannelMixerFlags flags,
828 GstAudioFormat format,
829 gint in_channels, gint out_channels, gfloat ** matrix)
831 GstAudioChannelMixer *mix;
833 g_return_val_if_fail (format == GST_AUDIO_FORMAT_S16
834 || format == GST_AUDIO_FORMAT_S32
835 || format == GST_AUDIO_FORMAT_F32
836 || format == GST_AUDIO_FORMAT_F64, NULL);
837 g_return_val_if_fail (in_channels > 0 && in_channels < 64, NULL);
838 g_return_val_if_fail (out_channels > 0 && out_channels < 64, NULL);
840 mix = g_slice_new0 (GstAudioChannelMixer);
841 mix->in_channels = in_channels;
842 mix->out_channels = out_channels;
845 /* Generate (potentially truncated) identity matrix */
848 mix->matrix = g_new0 (gfloat *, in_channels);
850 for (i = 0; i < in_channels; i++) {
851 mix->matrix[i] = g_new (gfloat, out_channels);
852 for (j = 0; j < out_channels; j++) {
853 mix->matrix[i][j] = i == j ? 1.0 : 0.0;
857 mix->matrix = matrix;
860 gst_audio_channel_mixer_setup_matrix_int (mix);
862 #ifndef GST_DISABLE_GST_DEBUG
868 s = g_string_new ("Matrix for");
869 g_string_append_printf (s, " %d -> %d: ",
870 mix->in_channels, mix->out_channels);
871 g_string_append (s, "{");
872 for (i = 0; i < mix->in_channels; i++) {
874 g_string_append (s, ",");
875 g_string_append (s, " {");
876 for (j = 0; j < mix->out_channels; j++) {
878 g_string_append (s, ",");
879 g_string_append_printf (s, " %f", mix->matrix[i][j]);
881 g_string_append (s, " }");
883 g_string_append (s, " }");
884 GST_DEBUG ("%s", s->str);
885 g_string_free (s, TRUE);
890 case GST_AUDIO_FORMAT_S16:
891 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
892 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
893 mix->func = (MixerFunc)
894 gst_audio_channel_mixer_mix_int16_planar_planar;
896 mix->func = (MixerFunc)
897 gst_audio_channel_mixer_mix_int16_planar_interleaved;
900 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
901 mix->func = (MixerFunc)
902 gst_audio_channel_mixer_mix_int16_interleaved_planar;
904 mix->func = (MixerFunc)
905 gst_audio_channel_mixer_mix_int16_interleaved_interleaved;
909 case GST_AUDIO_FORMAT_S32:
910 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
911 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
912 mix->func = (MixerFunc)
913 gst_audio_channel_mixer_mix_int32_planar_planar;
915 mix->func = (MixerFunc)
916 gst_audio_channel_mixer_mix_int32_planar_interleaved;
919 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
920 mix->func = (MixerFunc)
921 gst_audio_channel_mixer_mix_int32_interleaved_planar;
923 mix->func = (MixerFunc)
924 gst_audio_channel_mixer_mix_int32_interleaved_interleaved;
928 case GST_AUDIO_FORMAT_F32:
929 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
930 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
931 mix->func = (MixerFunc)
932 gst_audio_channel_mixer_mix_float_planar_planar;
934 mix->func = (MixerFunc)
935 gst_audio_channel_mixer_mix_float_planar_interleaved;
938 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
939 mix->func = (MixerFunc)
940 gst_audio_channel_mixer_mix_float_interleaved_planar;
942 mix->func = (MixerFunc)
943 gst_audio_channel_mixer_mix_float_interleaved_interleaved;
947 case GST_AUDIO_FORMAT_F64:
948 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN) {
949 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
950 mix->func = (MixerFunc)
951 gst_audio_channel_mixer_mix_double_planar_planar;
953 mix->func = (MixerFunc)
954 gst_audio_channel_mixer_mix_double_planar_interleaved;
957 if (flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT) {
958 mix->func = (MixerFunc)
959 gst_audio_channel_mixer_mix_double_interleaved_planar;
961 mix->func = (MixerFunc)
962 gst_audio_channel_mixer_mix_double_interleaved_interleaved;
967 g_assert_not_reached ();
974 * gst_audio_channel_mixer_new: (skip):
975 * @flags: #GstAudioChannelMixerFlags
976 * @in_channels: number of input channels
977 * @in_position: positions of input channels
978 * @out_channels: number of output channels
979 * @out_position: positions of output channels
981 * Create a new channel mixer object for the given parameters.
983 * Returns: a new #GstAudioChannelMixer object, or %NULL if @format isn't supported.
984 * Free with gst_audio_channel_mixer_free() after usage.
986 GstAudioChannelMixer *
987 gst_audio_channel_mixer_new (GstAudioChannelMixerFlags flags,
988 GstAudioFormat format,
990 GstAudioChannelPosition * in_position,
991 gint out_channels, GstAudioChannelPosition * out_position)
995 g_return_val_if_fail (format == GST_AUDIO_FORMAT_S16
996 || format == GST_AUDIO_FORMAT_S32
997 || format == GST_AUDIO_FORMAT_F32
998 || format == GST_AUDIO_FORMAT_F64, NULL);
999 g_return_val_if_fail (in_channels > 0 && in_channels < 64, NULL);
1000 g_return_val_if_fail (out_channels > 0 && out_channels < 64, NULL);
1003 gst_audio_channel_mixer_setup_matrix (flags, in_channels, in_position,
1004 out_channels, out_position);
1005 return gst_audio_channel_mixer_new_with_matrix (flags, format, in_channels,
1006 out_channels, matrix);
1010 * gst_audio_channel_mixer_is_passthrough:
1011 * @mix: a #GstAudioChannelMixer
1013 * Check if @mix is in passthrough.
1015 * Only N x N mix identity matrices are considered passthrough,
1016 * this is determined by comparing the contents of the matrix
1019 * As this is floating point comparisons, if the values have been
1020 * generated, they should be rounded up or down by explicit
1021 * assignment of 0.0 or 1.0 to values within a user-defined
1022 * epsilon, this code doesn't make assumptions as to what may
1023 * constitute an appropriate epsilon.
1025 * Returns: %TRUE is @mix is passthrough.
1028 gst_audio_channel_mixer_is_passthrough (GstAudioChannelMixer * mix)
1033 /* only NxN matrices can be identities */
1034 if (mix->in_channels != mix->out_channels)
1039 for (i = 0; i < mix->in_channels; i++) {
1040 for (j = 0; j < mix->out_channels; j++) {
1041 if ((i == j && mix->matrix[i][j] != 1.0f) ||
1042 (i != j && mix->matrix[i][j] != 0.0f)) {
1053 * gst_audio_channel_mixer_samples:
1054 * @mix: a #GstAudioChannelMixer
1055 * @in: input samples
1056 * @out: output samples
1057 * @samples: number of samples
1059 * In case the samples are interleaved, @in and @out must point to an
1060 * array with a single element pointing to a block of interleaved samples.
1062 * If non-interleaved samples are used, @in and @out must point to an
1063 * array with pointers to memory blocks, one for each channel.
1065 * Perform channel mixing on @in_data and write the result to @out_data.
1066 * @in_data and @out_data need to be in @format and @layout.
1069 gst_audio_channel_mixer_samples (GstAudioChannelMixer * mix,
1070 const gpointer in[], gpointer out[], gint samples)
1072 g_return_if_fail (mix != NULL);
1073 g_return_if_fail (mix->matrix != NULL);
1075 mix->func (mix, in, out, samples);