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_channels_matrix_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
77 n_ic
= m
->i_ss
.channels
;
78 n_oc
= m
->o_ss
.channels
;
80 memset(dst
, 0, n
* sizeof(int16_t) * n_oc
);
82 for (oc
= 0; oc
< n_oc
; oc
++) {
84 for (ic
= 0; ic
< n_ic
; ic
++) {
85 int16_t *d
= dst
+ oc
;
86 const int16_t *s
= src
+ ic
;
87 int32_t vol
= m
->map_table_i
[oc
][ic
];
93 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
96 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
97 *d
+= (int16_t) (((int32_t)*s
* vol
) >> 16);
103 static void remap_channels_matrix_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
107 n_ic
= m
->i_ss
.channels
;
108 n_oc
= m
->o_ss
.channels
;
110 memset(dst
, 0, n
* sizeof(float) * n_oc
);
112 for (oc
= 0; oc
< n_oc
; oc
++) {
114 for (ic
= 0; ic
< n_ic
; ic
++) {
116 const float *s
= src
+ ic
;
117 float vol
= m
->map_table_f
[oc
][ic
];
123 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
126 for (i
= n
; i
> 0; i
--, s
+= n_ic
, d
+= n_oc
)
133 bool pa_setup_remap_arrange(const pa_remap_t
*m
, int8_t arrange
[PA_CHANNELS_MAX
]) {
139 n_ic
= m
->i_ss
.channels
;
140 n_oc
= m
->o_ss
.channels
;
142 for (oc
= 0; oc
< n_oc
; oc
++) {
144 for (ic
= 0; ic
< n_ic
; ic
++) {
145 int32_t vol
= m
->map_table_i
[oc
][ic
];
147 /* input channel is not used */
151 /* if mixing this channel, we cannot just rearrange */
152 if (vol
!= 0x10000 || arrange
[oc
] >= 0)
162 static void remap_arrange_stereo_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
163 const unsigned n_ic
= m
->i_ss
.channels
;
164 const int8_t *arrange
= m
->state
;
165 const int8_t ic0
= arrange
[0], ic1
= arrange
[1];
168 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0;
169 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0;
174 static void remap_arrange_ch4_s16ne_c(pa_remap_t
*m
, int16_t *dst
, const int16_t *src
, unsigned n
) {
175 const unsigned n_ic
= m
->i_ss
.channels
;
176 const int8_t *arrange
= m
->state
;
177 const int8_t ic0
= arrange
[0], ic1
= arrange
[1],
178 ic2
= arrange
[2], ic3
= arrange
[3];
181 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0;
182 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0;
183 *dst
++ = (ic2
>= 0) ? *(src
+ ic2
) : 0;
184 *dst
++ = (ic3
>= 0) ? *(src
+ ic3
) : 0;
189 static void remap_arrange_stereo_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
190 const unsigned n_ic
= m
->i_ss
.channels
;
191 const int8_t *arrange
= m
->state
;
192 const int ic0
= arrange
[0], ic1
= arrange
[1];
195 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0.0f
;
196 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0.0f
;
201 static void remap_arrange_ch4_float32ne_c(pa_remap_t
*m
, float *dst
, const float *src
, unsigned n
) {
202 const unsigned n_ic
= m
->i_ss
.channels
;
203 const int8_t *arrange
= m
->state
;
204 const int ic0
= arrange
[0], ic1
= arrange
[1],
205 ic2
= arrange
[2], ic3
= arrange
[3];
208 *dst
++ = (ic0
>= 0) ? *(src
+ ic0
) : 0.0f
;
209 *dst
++ = (ic1
>= 0) ? *(src
+ ic1
) : 0.0f
;
210 *dst
++ = (ic2
>= 0) ? *(src
+ ic2
) : 0.0f
;
211 *dst
++ = (ic3
>= 0) ? *(src
+ ic3
) : 0.0f
;
216 void pa_set_remap_func(pa_remap_t
*m
, pa_do_remap_func_t func_s16
,
217 pa_do_remap_func_t func_float
) {
221 if (m
->format
== PA_SAMPLE_S16NE
)
222 m
->do_remap
= func_s16
;
223 else if (m
->format
== PA_SAMPLE_FLOAT32NE
)
224 m
->do_remap
= func_float
;
226 pa_assert_not_reached();
229 /* set the function that will execute the remapping based on the matrices */
230 static void init_remap_c(pa_remap_t
*m
) {
232 int8_t arrange
[PA_CHANNELS_MAX
];
234 n_oc
= m
->o_ss
.channels
;
235 n_ic
= m
->i_ss
.channels
;
237 /* find some common channel remappings, fall back to full matrix operation. */
238 if (n_ic
== 1 && n_oc
== 2 &&
239 m
->map_table_i
[0][0] == 0x10000 && m
->map_table_i
[1][0] == 0x10000) {
241 pa_log_info("Using mono to stereo remapping");
242 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_mono_to_stereo_s16ne_c
,
243 (pa_do_remap_func_t
) remap_mono_to_stereo_float32ne_c
);
244 } else if (pa_setup_remap_arrange(m
, arrange
) && n_oc
== 2) {
246 pa_log_info("Using stereo arrange remapping");
247 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_arrange_stereo_s16ne_c
,
248 (pa_do_remap_func_t
) remap_arrange_stereo_float32ne_c
);
251 m
->state
= pa_xnewdup(int8_t, arrange
, PA_CHANNELS_MAX
);
252 } else if (pa_setup_remap_arrange(m
, arrange
) && n_oc
== 4) {
254 pa_log_info("Using 4-channel arrange remapping");
255 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_arrange_ch4_s16ne_c
,
256 (pa_do_remap_func_t
) remap_arrange_ch4_float32ne_c
);
259 m
->state
= pa_xnewdup(int8_t, arrange
, PA_CHANNELS_MAX
);
262 pa_log_info("Using generic matrix remapping");
263 pa_set_remap_func(m
, (pa_do_remap_func_t
) remap_channels_matrix_s16ne_c
,
264 (pa_do_remap_func_t
) remap_channels_matrix_float32ne_c
);
268 /* default C implementation */
269 static pa_init_remap_func_t init_remap_func
= init_remap_c
;
271 void pa_init_remap_func(pa_remap_t
*m
) {
272 pa_assert(init_remap_func
);
276 /* call the installed remap init function */
279 if (m
->do_remap
== NULL
) {
280 /* nothing was installed, fallback to C version */
285 pa_init_remap_func_t
pa_get_init_remap_func(void) {
286 return init_remap_func
;
289 void pa_set_init_remap_func(pa_init_remap_func_t func
) {
290 init_remap_func
= func
;