Add default-monitor-time-sec
[platform/upstream/pulseaudio.git] / 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, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <string.h>
26
27 #include <pulse/xmalloc.h>
28 #include <pulse/sample.h>
29 #include <pulse/volume.h>
30 #include <pulsecore/log.h>
31 #include <pulsecore/macro.h>
32
33 #include "cpu.h"
34 #include "remap.h"
35
36 static void remap_mono_to_stereo_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
37     unsigned i;
38
39     for (i = n >> 2; i; i--) {
40         dst[0] = dst[1] = src[0];
41         dst[2] = dst[3] = src[1];
42         dst[4] = dst[5] = src[2];
43         dst[6] = dst[7] = src[3];
44         src += 4;
45         dst += 8;
46     }
47     for (i = n & 3; i; i--) {
48         dst[0] = dst[1] = src[0];
49         src++;
50         dst += 2;
51     }
52 }
53
54 static void remap_mono_to_stereo_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
55     unsigned i;
56
57     for (i = n >> 2; i; i--) {
58         dst[0] = dst[1] = src[0];
59         dst[2] = dst[3] = src[1];
60         dst[4] = dst[5] = src[2];
61         dst[6] = dst[7] = src[3];
62         src += 4;
63         dst += 8;
64     }
65     for (i = n & 3; i; i--) {
66         dst[0] = dst[1] = src[0];
67         src++;
68         dst += 2;
69     }
70 }
71
72 static void remap_mono_to_stereo_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
73     unsigned i;
74
75     for (i = n >> 2; i; i--) {
76         dst[0] = dst[1] = src[0];
77         dst[2] = dst[3] = src[1];
78         dst[4] = dst[5] = src[2];
79         dst[6] = dst[7] = src[3];
80         src += 4;
81         dst += 8;
82     }
83     for (i = n & 3; i; i--) {
84         dst[0] = dst[1] = src[0];
85         src++;
86         dst += 2;
87     }
88 }
89
90 static void remap_stereo_to_mono_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
91     unsigned i;
92
93     for (i = n >> 2; i > 0; i--) {
94         dst[0] = (src[0] + src[1])/2;
95         dst[1] = (src[2] + src[3])/2;
96         dst[2] = (src[4] + src[5])/2;
97         dst[3] = (src[6] + src[7])/2;
98         src += 8;
99         dst += 4;
100     }
101     for (i = n & 3; i; i--) {
102         dst[0] = (src[0] + src[1])/2;
103         src += 2;
104         dst += 1;
105     }
106 }
107
108 static void remap_stereo_to_mono_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
109     unsigned i;
110
111     for (i = n >> 2; i > 0; i--) {
112         /* Avoid overflow by performing division first. We accept a
113          * difference of +/- 1 to the ideal result. */
114         dst[0] = (src[0]/2 + src[1]/2);
115         dst[1] = (src[2]/2 + src[3]/2);
116         dst[2] = (src[4]/2 + src[5]/2);
117         dst[3] = (src[6]/2 + src[7]/2);
118         src += 8;
119         dst += 4;
120     }
121     for (i = n & 3; i; i--) {
122         /* Avoid overflow by performing division first. We accept a
123          * difference of +/- 1 to the ideal result. */
124         dst[0] = (src[0]/2 + src[1]/2);
125         src += 2;
126         dst += 1;
127     }
128 }
129
130 static void remap_stereo_to_mono_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
131     unsigned i;
132
133     for (i = n >> 2; i > 0; i--) {
134         dst[0] = (src[0] + src[1])*0.5f;
135         dst[1] = (src[2] + src[3])*0.5f;
136         dst[2] = (src[4] + src[5])*0.5f;
137         dst[3] = (src[6] + src[7])*0.5f;
138         src += 8;
139         dst += 4;
140     }
141     for (i = n & 3; i; i--) {
142         dst[0] = (src[0] + src[1])*0.5f;
143         src += 2;
144         dst += 1;
145     }
146 }
147
148 static void remap_mono_to_ch4_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
149     unsigned i;
150
151     for (i = n >> 2; i; i--) {
152         dst[0] = dst[1] = dst[2] = dst[3] = src[0];
153         dst[4] = dst[5] = dst[6] = dst[7] = src[1];
154         dst[8] = dst[9] = dst[10] = dst[11] = src[2];
155         dst[12] = dst[13] = dst[14] = dst[15] = src[3];
156         src += 4;
157         dst += 16;
158     }
159     for (i = n & 3; i; i--) {
160         dst[0] = dst[1] = dst[2] = dst[3] = src[0];
161         src++;
162         dst += 4;
163     }
164 }
165
166 static void remap_mono_to_ch4_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
167     unsigned i;
168
169     for (i = n >> 2; i; i--) {
170         dst[0] = dst[1] = dst[2] = dst[3] = src[0];
171         dst[4] = dst[5] = dst[6] = dst[7] = src[1];
172         dst[8] = dst[9] = dst[10] = dst[11] = src[2];
173         dst[12] = dst[13] = dst[14] = dst[15] = src[3];
174         src += 4;
175         dst += 16;
176     }
177     for (i = n & 3; i; i--) {
178         dst[0] = dst[1] = dst[2] = dst[3] = src[0];
179         src++;
180         dst += 4;
181     }
182 }
183
184 static void remap_mono_to_ch4_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
185     unsigned i;
186
187     for (i = n >> 2; i; i--) {
188         dst[0] = dst[1] = dst[2] = dst[3] = src[0];
189         dst[4] = dst[5] = dst[6] = dst[7] = src[1];
190         dst[8] = dst[9] = dst[10] = dst[11] = src[2];
191         dst[12] = dst[13] = dst[14] = dst[15] = src[3];
192         src += 4;
193         dst += 16;
194     }
195     for (i = n & 3; i; i--) {
196         dst[0] = dst[1] = dst[2] = dst[3] = src[0];
197         src++;
198         dst += 4;
199     }
200 }
201
202 static void remap_ch4_to_mono_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
203     unsigned i;
204
205     for (i = n >> 2; i > 0; i--) {
206         dst[0] = (src[0] + src[1] + src[2] + src[3])/4;
207         dst[1] = (src[4] + src[5] + src[6] + src[7])/4;
208         dst[2] = (src[8] + src[9] + src[10] + src[11])/4;
209         dst[3] = (src[12] + src[13] + src[14] + src[15])/4;
210         src += 16;
211         dst += 4;
212     }
213     for (i = n & 3; i; i--) {
214         dst[0] = (src[0] + src[1] + src[2] + src[3])/4;
215         src += 4;
216         dst += 1;
217     }
218 }
219
220 static void remap_ch4_to_mono_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
221     unsigned i;
222
223     for (i = n >> 2; i > 0; i--) {
224         /* Avoid overflow by performing division first. We accept a
225          * difference of +/- 3 to the ideal result. */
226         dst[0] = (src[0]/4 + src[1]/4 + src[2]/4 + src[3]/4);
227         dst[1] = (src[4]/4 + src[5]/4 + src[6]/4 + src[7]/4);
228         dst[2] = (src[8]/4 + src[9]/4 + src[10]/4 + src[11]/4);
229         dst[3] = (src[12]/4 + src[13]/4 + src[14]/4 + src[15]/4);
230         src += 16;
231         dst += 4;
232     }
233     for (i = n & 3; i; i--) {
234         /* Avoid overflow by performing division first. We accept a
235          * difference of +/- 3 to the ideal result. */
236         dst[0] = (src[0]/4 + src[1]/4 + src[2]/4 + src[3]/4);
237         src += 4;
238         dst += 1;
239     }
240 }
241
242 static void remap_ch4_to_mono_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
243     unsigned i;
244
245     for (i = n >> 2; i > 0; i--) {
246         dst[0] = (src[0] + src[1] + src[2] + src[3])*0.25f;
247         dst[1] = (src[4] + src[5] + src[6] + src[7])*0.25f;
248         dst[2] = (src[8] + src[9] + src[10] + src[11])*0.25f;
249         dst[3] = (src[12] + src[13] + src[14] + src[15])*0.25f;
250         src += 16;
251         dst += 4;
252     }
253     for (i = n & 3; i; i--) {
254         dst[0] = (src[0] + src[1] + src[2] + src[3])*0.25f;
255         src += 4;
256         dst += 1;
257     }
258 }
259
260 static void remap_channels_matrix_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
261
262     unsigned oc, ic, i;
263     unsigned n_ic, n_oc;
264
265     n_ic = m->i_ss.channels;
266     n_oc = m->o_ss.channels;
267
268     memset(dst, 0, n * sizeof(int16_t) * n_oc);
269
270     for (oc = 0; oc < n_oc; oc++) {
271
272         for (ic = 0; ic < n_ic; ic++) {
273             int16_t *d = dst + oc;
274             const int16_t *s = src + ic;
275             int32_t vol = m->map_table_i[oc][ic];
276
277             if (vol <= 0)
278                 continue;
279
280             if (vol >= 0x10000) {
281                 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
282                     *d += *s;
283             } else {
284                 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
285                     *d += (int16_t) (((int32_t)*s * vol) >> 16);
286             }
287         }
288     }
289 }
290
291 static void remap_channels_matrix_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
292     unsigned oc, ic, i;
293     unsigned n_ic, n_oc;
294
295     n_ic = m->i_ss.channels;
296     n_oc = m->o_ss.channels;
297
298     memset(dst, 0, n * sizeof(int32_t) * n_oc);
299
300     for (oc = 0; oc < n_oc; oc++) {
301
302         for (ic = 0; ic < n_ic; ic++) {
303             int32_t *d = dst + oc;
304             const int32_t *s = src + ic;
305             int32_t vol = m->map_table_i[oc][ic];
306
307             if (vol <= 0)
308                 continue;
309
310             if (vol >= 0x10000) {
311                 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
312                     *d += *s;
313             } else {
314                 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
315                     *d += (int32_t) (((int64_t)*s * vol) >> 16);
316             }
317         }
318     }
319 }
320
321 static void remap_channels_matrix_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
322     unsigned oc, ic, i;
323     unsigned n_ic, n_oc;
324
325     n_ic = m->i_ss.channels;
326     n_oc = m->o_ss.channels;
327
328     memset(dst, 0, n * sizeof(float) * n_oc);
329
330     for (oc = 0; oc < n_oc; oc++) {
331
332         for (ic = 0; ic < n_ic; ic++) {
333             float *d = dst + oc;
334             const float *s = src + ic;
335             float vol = m->map_table_f[oc][ic];
336
337             if (vol <= 0.0f)
338                 continue;
339
340             if (vol >= 1.0f) {
341                 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
342                     *d += *s;
343             } else {
344                 for (i = n; i > 0; i--, s += n_ic, d += n_oc)
345                     *d += *s * vol;
346             }
347         }
348     }
349 }
350
351 /* Produce an array containing input channel indices to map to output channels.
352  * If the output channel is empty, the array element is -1. */
353 bool pa_setup_remap_arrange(const pa_remap_t *m, int8_t arrange[PA_CHANNELS_MAX]) {
354     unsigned ic, oc;
355     unsigned n_ic, n_oc;
356     unsigned count_output = 0;
357
358     pa_assert(m);
359
360     n_ic = m->i_ss.channels;
361     n_oc = m->o_ss.channels;
362
363     for (oc = 0; oc < n_oc; oc++) {
364         arrange[oc] = -1;
365         for (ic = 0; ic < n_ic; ic++) {
366             int32_t vol = m->map_table_i[oc][ic];
367
368             /* input channel is not used */
369             if (vol == 0)
370                 continue;
371
372             /* if mixing this channel, we cannot just rearrange */
373             if (vol != 0x10000 || arrange[oc] >= 0)
374                 return false;
375
376             arrange[oc] = ic;
377             count_output++;
378         }
379     }
380
381     return count_output > 0;
382 }
383
384 static void remap_arrange_mono_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
385     const unsigned n_ic = m->i_ss.channels;
386     const int8_t *arrange = m->state;
387
388     src += arrange[0];
389     for (; n > 0; n--) {
390         *dst++ = *src;
391         src += n_ic;
392     }
393 }
394
395 static void remap_arrange_stereo_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
396     const unsigned n_ic = m->i_ss.channels;
397     const int8_t *arrange = m->state;
398     const int8_t ic0 = arrange[0], ic1 = arrange[1];
399
400     for (; n > 0; n--) {
401         *dst++ = (ic0 >= 0) ? *(src + ic0) : 0;
402         *dst++ = (ic1 >= 0) ? *(src + ic1) : 0;
403         src += n_ic;
404     }
405 }
406
407 static void remap_arrange_ch4_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) {
408     const unsigned n_ic = m->i_ss.channels;
409     const int8_t *arrange = m->state;
410     const int8_t ic0 = arrange[0], ic1 = arrange[1],
411         ic2 = arrange[2], ic3 = arrange[3];
412
413     for (; n > 0; n--) {
414         *dst++ = (ic0 >= 0) ? *(src + ic0) : 0;
415         *dst++ = (ic1 >= 0) ? *(src + ic1) : 0;
416         *dst++ = (ic2 >= 0) ? *(src + ic2) : 0;
417         *dst++ = (ic3 >= 0) ? *(src + ic3) : 0;
418         src += n_ic;
419     }
420 }
421
422 static void remap_arrange_mono_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
423     const unsigned n_ic = m->i_ss.channels;
424     const int8_t *arrange = m->state;
425
426     src += arrange[0];
427     for (; n > 0; n--) {
428         *dst++ = *src;
429         src += n_ic;
430     }
431 }
432
433 static void remap_arrange_stereo_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
434     const unsigned n_ic = m->i_ss.channels;
435     const int8_t *arrange = m->state;
436     const int ic0 = arrange[0], ic1 = arrange[1];
437
438     for (; n > 0; n--) {
439         *dst++ = (ic0 >= 0) ? *(src + ic0) : 0;
440         *dst++ = (ic1 >= 0) ? *(src + ic1) : 0;
441         src += n_ic;
442     }
443 }
444
445 static void remap_arrange_ch4_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) {
446     const unsigned n_ic = m->i_ss.channels;
447     const int8_t *arrange = m->state;
448     const int ic0 = arrange[0], ic1 = arrange[1],
449         ic2 = arrange[2], ic3 = arrange[3];
450
451     for (; n > 0; n--) {
452         *dst++ = (ic0 >= 0) ? *(src + ic0) : 0;
453         *dst++ = (ic1 >= 0) ? *(src + ic1) : 0;
454         *dst++ = (ic2 >= 0) ? *(src + ic2) : 0;
455         *dst++ = (ic3 >= 0) ? *(src + ic3) : 0;
456         src += n_ic;
457     }
458 }
459
460 static void remap_arrange_mono_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
461     const unsigned n_ic = m->i_ss.channels;
462     const int8_t *arrange = m->state;
463
464     src += arrange[0];
465     for (; n > 0; n--) {
466         *dst++ = *src;
467         src += n_ic;
468     }
469 }
470
471 static void remap_arrange_stereo_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
472     const unsigned n_ic = m->i_ss.channels;
473     const int8_t *arrange = m->state;
474     const int ic0 = arrange[0], ic1 = arrange[1];
475
476     for (; n > 0; n--) {
477         *dst++ = (ic0 >= 0) ? *(src + ic0) : 0.0f;
478         *dst++ = (ic1 >= 0) ? *(src + ic1) : 0.0f;
479         src += n_ic;
480     }
481 }
482
483 static void remap_arrange_ch4_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) {
484     const unsigned n_ic = m->i_ss.channels;
485     const int8_t *arrange = m->state;
486     const int ic0 = arrange[0], ic1 = arrange[1],
487         ic2 = arrange[2], ic3 = arrange[3];
488
489     for (; n > 0; n--) {
490         *dst++ = (ic0 >= 0) ? *(src + ic0) : 0.0f;
491         *dst++ = (ic1 >= 0) ? *(src + ic1) : 0.0f;
492         *dst++ = (ic2 >= 0) ? *(src + ic2) : 0.0f;
493         *dst++ = (ic3 >= 0) ? *(src + ic3) : 0.0f;
494         src += n_ic;
495     }
496 }
497
498 void pa_set_remap_func(pa_remap_t *m, pa_do_remap_func_t func_s16,
499     pa_do_remap_func_t func_s32, pa_do_remap_func_t func_float) {
500
501     pa_assert(m);
502
503     if (m->format == PA_SAMPLE_S16NE)
504         m->do_remap = func_s16;
505     else if (m->format == PA_SAMPLE_S32NE)
506         m->do_remap = func_s32;
507     else if (m->format == PA_SAMPLE_FLOAT32NE)
508         m->do_remap = func_float;
509     else
510         pa_assert_not_reached();
511     pa_assert(m->do_remap);
512 }
513
514 static bool force_generic_code = false;
515
516 /* set the function that will execute the remapping based on the matrices */
517 static void init_remap_c(pa_remap_t *m) {
518     unsigned n_oc, n_ic;
519     int8_t arrange[PA_CHANNELS_MAX];
520
521     n_oc = m->o_ss.channels;
522     n_ic = m->i_ss.channels;
523
524     /* find some common channel remappings, fall back to full matrix operation. */
525     if (force_generic_code) {
526         pa_log_info("Forced to use generic matrix remapping");
527         pa_set_remap_func(m, (pa_do_remap_func_t) remap_channels_matrix_s16ne_c,
528             (pa_do_remap_func_t) remap_channels_matrix_s32ne_c,
529             (pa_do_remap_func_t) remap_channels_matrix_float32ne_c);
530         return;
531     }
532
533     if (n_ic == 1 && n_oc == 2 &&
534             m->map_table_i[0][0] == 0x10000 && m->map_table_i[1][0] == 0x10000) {
535
536         pa_log_info("Using mono to stereo remapping");
537         pa_set_remap_func(m, (pa_do_remap_func_t) remap_mono_to_stereo_s16ne_c,
538             (pa_do_remap_func_t) remap_mono_to_stereo_s32ne_c,
539             (pa_do_remap_func_t) remap_mono_to_stereo_float32ne_c);
540     } else if (n_ic == 2 && n_oc == 1 &&
541             m->map_table_i[0][0] == 0x8000 && m->map_table_i[0][1] == 0x8000) {
542
543         pa_log_info("Using stereo to mono remapping");
544         pa_set_remap_func(m, (pa_do_remap_func_t) remap_stereo_to_mono_s16ne_c,
545             (pa_do_remap_func_t) remap_stereo_to_mono_s32ne_c,
546             (pa_do_remap_func_t) remap_stereo_to_mono_float32ne_c);
547     } else if (n_ic == 1 && n_oc == 4 &&
548             m->map_table_i[0][0] == 0x10000 && m->map_table_i[1][0] == 0x10000 &&
549             m->map_table_i[2][0] == 0x10000 && m->map_table_i[3][0] == 0x10000) {
550
551         pa_log_info("Using mono to 4-channel remapping");
552         pa_set_remap_func(m, (pa_do_remap_func_t)remap_mono_to_ch4_s16ne_c,
553             (pa_do_remap_func_t) remap_mono_to_ch4_s32ne_c,
554             (pa_do_remap_func_t) remap_mono_to_ch4_float32ne_c);
555     } else if (n_ic == 4 && n_oc == 1 &&
556             m->map_table_i[0][0] == 0x4000 && m->map_table_i[0][1] == 0x4000 &&
557             m->map_table_i[0][2] == 0x4000 && m->map_table_i[0][3] == 0x4000) {
558
559         pa_log_info("Using 4-channel to mono remapping");
560         pa_set_remap_func(m, (pa_do_remap_func_t) remap_ch4_to_mono_s16ne_c,
561             (pa_do_remap_func_t) remap_ch4_to_mono_s32ne_c,
562             (pa_do_remap_func_t) remap_ch4_to_mono_float32ne_c);
563     } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 1) {
564
565         pa_log_info("Using mono arrange remapping");
566         pa_set_remap_func(m, (pa_do_remap_func_t) remap_arrange_mono_s16ne_c,
567             (pa_do_remap_func_t) remap_arrange_mono_s32ne_c,
568             (pa_do_remap_func_t) remap_arrange_mono_float32ne_c);
569
570         /* setup state */
571         m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX);
572     } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 2) {
573
574         pa_log_info("Using stereo arrange remapping");
575         pa_set_remap_func(m, (pa_do_remap_func_t) remap_arrange_stereo_s16ne_c,
576             (pa_do_remap_func_t) remap_arrange_stereo_s32ne_c,
577             (pa_do_remap_func_t) remap_arrange_stereo_float32ne_c);
578
579         /* setup state */
580         m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX);
581     } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 4) {
582
583         pa_log_info("Using 4-channel arrange remapping");
584         pa_set_remap_func(m, (pa_do_remap_func_t) remap_arrange_ch4_s16ne_c,
585             (pa_do_remap_func_t) remap_arrange_ch4_s32ne_c,
586             (pa_do_remap_func_t) remap_arrange_ch4_float32ne_c);
587
588         /* setup state */
589         m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX);
590     } else {
591
592         pa_log_info("Using generic matrix remapping");
593         pa_set_remap_func(m, (pa_do_remap_func_t) remap_channels_matrix_s16ne_c,
594             (pa_do_remap_func_t) remap_channels_matrix_s32ne_c,
595             (pa_do_remap_func_t) remap_channels_matrix_float32ne_c);
596     }
597 }
598
599 /* default C implementation */
600 static pa_init_remap_func_t init_remap_func = init_remap_c;
601
602 void pa_init_remap_func(pa_remap_t *m) {
603     pa_assert(init_remap_func);
604
605     m->do_remap = NULL;
606
607     /* call the installed remap init function */
608     init_remap_func(m);
609
610     if (m->do_remap == NULL) {
611         /* nothing was installed, fallback to C version */
612         init_remap_c(m);
613     }
614 }
615
616 pa_init_remap_func_t pa_get_init_remap_func(void) {
617     return init_remap_func;
618 }
619
620 void pa_set_init_remap_func(pa_init_remap_func_t func) {
621     init_remap_func = func;
622 }
623
624 void pa_remap_func_init(const pa_cpu_info *cpu_info) {
625     force_generic_code = cpu_info->force_generic_code;
626 }