]> code.delx.au - pulseaudio/blob - src/pulsecore/remap.c
80194a41f57d30793c4f11b9d68ec07fb3c8decd
[pulseaudio] / src / pulsecore / remap.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk.com>
6
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.
11
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.
16
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
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
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>
34
35 #include "remap.h"
36
37 static void remap_mono_to_stereo_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
38 unsigned i;
39
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];
45 src += 4;
46 dst += 8;
47 }
48 for (i = n & 3; i; i--) {
49 dst[0] = dst[1] = src[0];
50 src++;
51 dst += 2;
52 }
53 }
54
55 static void remap_mono_to_stereo_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
56 unsigned i;
57
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];
63 src += 4;
64 dst += 8;
65 }
66 for (i = n & 3; i; i--) {
67 dst[0] = dst[1] = src[0];
68 src++;
69 dst += 2;
70 }
71 }
72
73 static void remap_channels_matrix_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
74 unsigned oc, ic, i;
75 unsigned n_ic, n_oc;
76
77 n_ic = m->i_ss.channels;
78 n_oc = m->o_ss.channels;
79
80 memset(dst, 0, n * sizeof(int16_t) * n_oc);
81
82 for (oc = 0; oc < n_oc; oc++) {
83
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];
88
89 if (vol <= 0)
90 continue;
91
92 if (vol >= 0x10000) {
93 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
94 *d += *s;
95 } else {
96 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
97 *d += (int16_t) (((int32_t)*s * vol) >> 16);
98 }
99 }
100 }
101 }
102
103 static void remap_channels_matrix_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
104 unsigned oc, ic, i;
105 unsigned n_ic, n_oc;
106
107 n_ic = m->i_ss.channels;
108 n_oc = m->o_ss.channels;
109
110 memset(dst, 0, n * sizeof(float) * n_oc);
111
112 for (oc = 0; oc < n_oc; oc++) {
113
114 for (ic = 0; ic < n_ic; ic++) {
115 float *d = dst + oc;
116 const float *s = src + ic;
117 float vol = m->map_table_f[oc][ic];
118
119 if (vol <= 0.0f)
120 continue;
121
122 if (vol >= 1.0f) {
123 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
124 *d += *s;
125 } else {
126 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
127 *d += *s * vol;
128 }
129 }
130 }
131 }
132
133 bool pa_setup_remap_arrange(const pa_remap_t *m, int8_t arrange[PA_CHANNELS_MAX]) {
134 unsigned ic, oc;
135 unsigned n_ic, n_oc;
136
137 pa_assert(m);
138
139 n_ic = m->i_ss.channels;
140 n_oc = m->o_ss.channels;
141
142 for (oc = 0; oc < n_oc; oc++) {
143 arrange[oc] = -1;
144 for (ic = 0; ic < n_ic; ic++) {
145 int32_t vol = m->map_table_i[oc][ic];
146
147 /* input channel is not used */
148 if (vol == 0)
149 continue;
150
151 /* if mixing this channel, we cannot just rearrange */
152 if (vol != 0x10000 || arrange[oc] >= 0)
153 return false;
154
155 arrange[oc] = ic;
156 }
157 }
158
159 return true;
160 }
161
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];
166
167 for (; n > 0; n--) {
168 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0;
169 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0;
170 src += n_ic;
171 }
172 }
173
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];
179
180 for (; n > 0; n--) {
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;
185 src += n_ic;
186 }
187 }
188
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];
193
194 for (; n > 0; n--) {
195 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0.0f;
196 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0.0f;
197 src += n_ic;
198 }
199 }
200
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];
206
207 for (; n > 0; n--) {
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;
212 src += n_ic;
213 }
214 }
215
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) {
218
219 pa_assert(m);
220
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;
225 else
226 pa_assert_not_reached();
227 }
228
229 /* set the function that will execute the remapping based on the matrices */
230 static void init_remap_c(pa_remap_t *m) {
231 unsigned n_oc, n_ic;
232 int8_t arrange[PA_CHANNELS_MAX];
233
234 n_oc = m->o_ss.channels;
235 n_ic = m->i_ss.channels;
236
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) {
240
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) {
245
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);
249
250 /* setup state */
251 m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX);
252 } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 4) {
253
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);
257
258 /* setup state */
259 m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX);
260 } else {
261
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);
265 }
266 }
267
268 /* default C implementation */
269 static pa_init_remap_func_t init_remap_func = init_remap_c;
270
271 void pa_init_remap_func(pa_remap_t *m) {
272 pa_assert(init_remap_func);
273
274 m->do_remap = NULL;
275
276 /* call the installed remap init function */
277 init_remap_func(m);
278
279 if (m->do_remap == NULL) {
280 /* nothing was installed, fallback to C version */
281 init_remap_c(m);
282 }
283 }
284
285 pa_init_remap_func_t pa_get_init_remap_func(void) {
286 return init_remap_func;
287 }
288
289 void pa_set_init_remap_func(pa_init_remap_func_t func) {
290 init_remap_func = func;
291 }