2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk.com>
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <pulse/xmalloc.h>
30 #include <pulse/sample.h>
31 #include <pulse/volume.h>
32 #include <pulsecore/log.h>
33 #include <pulsecore/macro.h>
37 static void remap_mono_to_stereo_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
40 for (i
= n
>> 2; i
; i
--) {
41 dst
[0] = dst
[1] = src
[0];
42 dst
[2] = dst
[3] = src
[1];
43 dst
[4] = dst
[5] = src
[2];
44 dst
[6] = dst
[7] = src
[3];
48 for (i
= n
& 3; i
; i
--) {
49 dst
[0] = dst
[1] = src
[0];
55 static void remap_mono_to_stereo_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
58 for (i
= n
>> 2; i
; i
--) {
59 dst
[0] = dst
[1] = src
[0];
60 dst
[2] = dst
[3] = src
[1];
61 dst
[4] = dst
[5] = src
[2];
62 dst
[6] = dst
[7] = src
[3];
66 for (i
= n
& 3; i
; i
--) {
67 dst
[0] = dst
[1] = src
[0];
73 static void remap_stereo_to_mono_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
76 for (i
= n
>> 2; i
> 0; i
--) {
77 dst
[0] = (src
[0] + src
[1])/2;
78 dst
[1] = (src
[2] + src
[3])/2;
79 dst
[2] = (src
[4] + src
[5])/2;
80 dst
[3] = (src
[6] + src
[7])/2;
84 for (i
= n
& 3; i
; i
--) {
85 dst
[0] = (src
[0] + src
[1])/2;
91 static void remap_stereo_to_mono_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
94 for (i
= n
>> 2; i
> 0; i
--) {
95 dst
[0] = (src
[0] + src
[1])*0.5f
;
96 dst
[1] = (src
[2] + src
[3])*0.5f
;
97 dst
[2] = (src
[4] + src
[5])*0.5f
;
98 dst
[3] = (src
[6] + src
[7])*0.5f
;
102 for (i
= n
& 3; i
; i
--) {
103 dst
[0] = (src
[0] + src
[1])*0.5f
;
109 static void remap_mono_to_ch4_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
112 for (i
= n
>> 2; i
; i
--) {
113 dst
[0] = dst
[1] = dst
[2] = dst
[3] = src
[0];
114 dst
[4] = dst
[5] = dst
[6] = dst
[7] = src
[1];
115 dst
[8] = dst
[9] = dst
[10] = dst
[11] = src
[2];
116 dst
[12] = dst
[13] = dst
[14] = dst
[15] = src
[3];
120 for (i
= n
& 3; i
; i
--) {
121 dst
[0] = dst
[1] = dst
[2] = dst
[3] = src
[0];
127 static void remap_mono_to_ch4_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
130 for (i
= n
>> 2; i
; i
--) {
131 dst
[0] = dst
[1] = dst
[2] = dst
[3] = src
[0];
132 dst
[4] = dst
[5] = dst
[6] = dst
[7] = src
[1];
133 dst
[8] = dst
[9] = dst
[10] = dst
[11] = src
[2];
134 dst
[12] = dst
[13] = dst
[14] = dst
[15] = src
[3];
138 for (i
= n
& 3; i
; i
--) {
139 dst
[0] = dst
[1] = dst
[2] = dst
[3] = src
[0];
145 static void remap_ch4_to_mono_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
148 for (i
= n
>> 2; i
> 0; i
--) {
149 dst
[0] = (src
[0] + src
[1] + src
[2] + src
[3])/4;
150 dst
[1] = (src
[4] + src
[5] + src
[6] + src
[7])/4;
151 dst
[2] = (src
[8] + src
[9] + src
[10] + src
[11])/4;
152 dst
[3] = (src
[12] + src
[13] + src
[14] + src
[15])/4;
156 for (i
= n
& 3; i
; i
--) {
157 dst
[0] = (src
[0] + src
[1] + src
[2] + src
[3])/4;
163 static void remap_ch4_to_mono_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
166 for (i
= n
>> 2; i
> 0; i
--) {
167 dst
[0] = (src
[0] + src
[1] + src
[2] + src
[3])*0.25f
;
168 dst
[1] = (src
[4] + src
[5] + src
[6] + src
[7])*0.25f
;
169 dst
[2] = (src
[8] + src
[9] + src
[10] + src
[11])*0.25f
;
170 dst
[3] = (src
[12] + src
[13] + src
[14] + src
[15])*0.25f
;
174 for (i
= n
& 3; i
; i
--) {
175 dst
[0] = (src
[0] + src
[1] + src
[2] + src
[3])*0.25f
;
181 static void remap_channels_matrix_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
186 n_ic
= m
->i_ss
.channels
;
187 n_oc
= m
->o_ss
.channels
;
189 memset(dst
, 0, n
* sizeof(int16_t) * n_oc
);
191 for (oc
= 0; oc
< n_oc
; oc
++) {
193 for (ic
= 0; ic
< n_ic
; ic
++) {
194 int16_t *d
= dst
+ oc
;
195 const int16_t *s
= src
+ ic
;
196 int32_t vol
= m
->map_table_i
[oc
][ic
];
201 if (vol
>= 0x10000) {
202 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
205 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
206 *d
+= (int16_t) (((int32_t)*s
* vol
) >> 16);
212 static void remap_channels_matrix_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
216 n_ic
= m
->i_ss
.channels
;
217 n_oc
= m
->o_ss
.channels
;
219 memset(dst
, 0, n
* sizeof(float) * n_oc
);
221 for (oc
= 0; oc
< n_oc
; oc
++) {
223 for (ic
= 0; ic
< n_ic
; ic
++) {
225 const float *s
= src
+ ic
;
226 float vol
= m
->map_table_f
[oc
][ic
];
232 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
235 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
242 bool pa_setup_remap_arrange(const pa_remap_t
*m
, int8_t arrange
[PA_CHANNELS_MAX
]) {
248 n_ic
= m
->i_ss
.channels
;
249 n_oc
= m
->o_ss
.channels
;
251 for (oc
= 0; oc
< n_oc
; oc
++) {
253 for (ic
= 0; ic
< n_ic
; ic
++) {
254 int32_t vol
= m
->map_table_i
[oc
][ic
];
256 /* input channel is not used */
260 /* if mixing this channel, we cannot just rearrange */
261 if (vol
!= 0x10000 || arrange
[oc
] >= 0)
271 static void remap_arrange_stereo_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
272 const unsigned n_ic
= m
->i_ss
.channels
;
273 const int8_t *arrange
= m
->state
;
274 const int8_t ic0
= arrange
[0], ic1
= arrange
[1];
277 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0;
278 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0;
283 static void remap_arrange_ch4_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
284 const unsigned n_ic
= m
->i_ss
.channels
;
285 const int8_t *arrange
= m
->state
;
286 const int8_t ic0
= arrange
[0], ic1
= arrange
[1],
287 ic2
= arrange
[2], ic3
= arrange
[3];
290 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0;
291 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0;
292 *dst
++ = (ic2
>= 0) ? *(src
+ ic2
) : 0;
293 *dst
++ = (ic3
>= 0) ? *(src
+ ic3
) : 0;
298 static void remap_arrange_stereo_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
299 const unsigned n_ic
= m
->i_ss
.channels
;
300 const int8_t *arrange
= m
->state
;
301 const int ic0
= arrange
[0], ic1
= arrange
[1];
304 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0.0f
;
305 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0.0f
;
310 static void remap_arrange_ch4_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
311 const unsigned n_ic
= m
->i_ss
.channels
;
312 const int8_t *arrange
= m
->state
;
313 const int ic0
= arrange
[0], ic1
= arrange
[1],
314 ic2
= arrange
[2], ic3
= arrange
[3];
317 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0.0f
;
318 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0.0f
;
319 *dst
++ = (ic2
>= 0) ? *(src
+ ic2
) : 0.0f
;
320 *dst
++ = (ic3
>= 0) ? *(src
+ ic3
) : 0.0f
;
325 void pa_set_remap_func(pa_remap_t
*m
, pa_do_remap_func_t func_s16
,
326 pa_do_remap_func_t func_float
) {
330 if (m
->format
== PA_SAMPLE_S16NE
)
331 m
->do_remap
= func_s16
;
332 else if (m
->format
== PA_SAMPLE_FLOAT32NE
)
333 m
->do_remap
= func_float
;
335 pa_assert_not_reached();
338 /* set the function that will execute the remapping based on the matrices */
339 static void init_remap_c(pa_remap_t
*m
) {
341 int8_t arrange
[PA_CHANNELS_MAX
];
343 n_oc
= m
->o_ss
.channels
;
344 n_ic
= m
->i_ss
.channels
;
346 /* find some common channel remappings, fall back to full matrix operation. */
347 if (n_ic
== 1 && n_oc
== 2 &&
348 m
->map_table_i
[0][0] == 0x10000 && m
->map_table_i
[1][0] == 0x10000) {
350 pa_log_info("Using mono to stereo remapping");
351 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_mono_to_stereo_s16ne_c
,
352 (pa_do_remap_func_t
) remap_mono_to_stereo_float32ne_c
);
353 } else if (n_ic
== 2 && n_oc
== 1 &&
354 m
->map_table_i
[0][0] == 0x8000 && m
->map_table_i
[0][1] == 0x8000) {
356 pa_log_info("Using stereo to mono remapping");
357 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_stereo_to_mono_s16ne_c
,
358 (pa_do_remap_func_t
) remap_stereo_to_mono_float32ne_c
);
359 } else if (n_ic
== 1 && n_oc
== 4 &&
360 m
->map_table_i
[0][0] == 0x10000 && m
->map_table_i
[1][0] == 0x10000 &&
361 m
->map_table_i
[2][0] == 0x10000 && m
->map_table_i
[3][0] == 0x10000) {
363 pa_log_info("Using mono to 4-channel remapping");
364 pa_set_remap_func(m
, (pa_do_remap_func_t
)remap_mono_to_ch4_s16ne_c
,
365 (pa_do_remap_func_t
) remap_mono_to_ch4_float32ne_c
);
366 } else if (n_ic
== 4 && n_oc
== 1 &&
367 m
->map_table_i
[0][0] == 0x4000 && m
->map_table_i
[0][1] == 0x4000 &&
368 m
->map_table_i
[0][2] == 0x4000 && m
->map_table_i
[0][3] == 0x4000) {
370 pa_log_info("Using 4-channel to mono remapping");
371 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_ch4_to_mono_s16ne_c
,
372 (pa_do_remap_func_t
) remap_ch4_to_mono_float32ne_c
);
373 } else if (pa_setup_remap_arrange(m
, arrange
) && n_oc
== 2) {
375 pa_log_info("Using stereo arrange remapping");
376 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_arrange_stereo_s16ne_c
,
377 (pa_do_remap_func_t
) remap_arrange_stereo_float32ne_c
);
380 m
->state
= pa_xnewdup(int8_t, arrange
, PA_CHANNELS_MAX
);
381 } else if (pa_setup_remap_arrange(m
, arrange
) && n_oc
== 4) {
383 pa_log_info("Using 4-channel arrange remapping");
384 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_arrange_ch4_s16ne_c
,
385 (pa_do_remap_func_t
) remap_arrange_ch4_float32ne_c
);
388 m
->state
= pa_xnewdup(int8_t, arrange
, PA_CHANNELS_MAX
);
391 pa_log_info("Using generic matrix remapping");
392 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_channels_matrix_s16ne_c
,
393 (pa_do_remap_func_t
) remap_channels_matrix_float32ne_c
);
397 /* default C implementation */
398 static pa_init_remap_func_t init_remap_func
= init_remap_c
;
400 void pa_init_remap_func(pa_remap_t
*m
) {
401 pa_assert(init_remap_func
);
405 /* call the installed remap init function */
408 if (m
->do_remap
== NULL
) {
409 /* nothing was installed, fallback to C version */
414 pa_init_remap_func_t
pa_get_init_remap_func(void) {
415 return init_remap_func
;
418 void pa_set_init_remap_func(pa_init_remap_func_t func
) {
419 init_remap_func
= func
;