1 /*
2   This file is part of Deadbeef Player source code
3   http://deadbeef.sourceforge.net
4 
5   routines for converting between wave formats and channel configurations
6 
7   Copyright (C) 2009-2013 Alexey Yakovenko
8 
9   This software is provided 'as-is', without any express or implied
10   warranty.  In no event will the authors be held liable for any damages
11   arising from the use of this software.
12 
13   Permission is granted to anyone to use this software for any purpose,
14   including commercial applications, and to alter it and redistribute it
15   freely, subject to the following restrictions:
16 
17   1. The origin of this software must not be misrepresented; you must not
18      claim that you wrote the original software. If you use this software
19      in a product, an acknowledgment in the product documentation would be
20      appreciated but is not required.
21   2. Altered source versions must be plainly marked as such, and must not be
22      misrepresented as being the original software.
23   3. This notice may not be removed or altered from any source distribution.
24 
25   Alexey Yakovenko waker@users.sourceforge.net
26 */
27 
28 #include <assert.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "deadbeef.h"
32 #include "premix.h"
33 #include "fastftoi.h"
34 
35 #define trace(...) { fprintf(stderr, __VA_ARGS__); }
36 //#define trace(fmt,...)
37 
38 
39 static inline void
pcm_write_samples_8_to_8(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)40 pcm_write_samples_8_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
41     for (int s = 0; s < nsamples; s++) {
42         for (int c = 0; c < outputfmt->channels; c++) {
43             *(output + c) = *(input + channelmap[c]);
44         }
45         input += inputfmt->channels;
46         output += outputsamplesize;
47     }
48 }
49 
50 static inline void
pcm_write_samples_8_to_16(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)51 pcm_write_samples_8_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
52     for (int s = 0; s < nsamples; s++) {
53         for (int c = 0; c < outputfmt->channels; c++) {
54             *((int16_t*)(output + 2 * c)) = (int16_t)(*(input + channelmap[c])) << 8;
55         }
56         input += inputfmt->channels;
57         output += outputsamplesize;
58     }
59 }
60 
61 static inline void
pcm_write_samples_8_to_24(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)62 pcm_write_samples_8_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
63     for (int s = 0; s < nsamples; s++) {
64         for (int c = 0; c < outputfmt->channels; c++) {
65             char *out = output + 3 * c;
66             out[0] = 0;
67             out[1] = 0;
68             out[2] = *(input + channelmap[c]);
69         }
70         input += inputfmt->channels;
71         output += outputsamplesize;
72     }
73 }
74 
75 static inline void
pcm_write_samples_8_to_32(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)76 pcm_write_samples_8_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
77     for (int s = 0; s < nsamples; s++) {
78         for (int c = 0; c < outputfmt->channels; c++) {
79             char *out = output + 4 * c;
80             out[0] = 0;
81             out[1] = 0;
82             out[2] = 0;
83             out[3] = *(input + channelmap[c]);
84         }
85         input += inputfmt->channels;
86         output += outputsamplesize;
87     }
88 }
89 
90 static inline void
pcm_write_samples_8_to_float(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)91 pcm_write_samples_8_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
92     for (int s = 0; s < nsamples; s++) {
93         for (int c = 0; c < outputfmt->channels; c++) {
94             float sample = (*(input+channelmap[c])) / (float)0x80;
95             *((float *)(output + 4 * c)) = sample;
96         }
97         input += inputfmt->channels;
98         output += outputsamplesize;
99     }
100 }
101 
102 static inline void
pcm_write_samples_16_to_16(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)103 pcm_write_samples_16_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
104     for (int s = 0; s < nsamples; s++) {
105         for (int c = 0; c < outputfmt->channels; c++) {
106             *((int16_t*)(output + 2 * c)) = *((int16_t*)(input + channelmap[c]*2));
107         }
108         input += 2 * inputfmt->channels;
109         output += outputsamplesize;
110     }
111 }
112 
113 static inline void
pcm_write_samples_16_to_8(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)114 pcm_write_samples_16_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
115     for (int s = 0; s < nsamples; s++) {
116         for (int c = 0; c < outputfmt->channels; c++) {
117             *((int8_t*)(output + c)) = *((int16_t*)(input + channelmap[c]*2)) >> 8;
118         }
119         input += 2 * inputfmt->channels;
120         output += outputsamplesize;
121     }
122 }
123 
124 static inline void
pcm_write_samples_16_to_24(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)125 pcm_write_samples_16_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
126     for (int s = 0; s < nsamples; s++) {
127         for (int c = 0; c < outputfmt->channels; c++) {
128             char *out = output + 3 * c;
129             const char *in = input + channelmap[c]*2;
130             out[0] = 0;
131             out[1] = in[0];
132             out[2] = in[1];
133         }
134         input += 2 * inputfmt->channels;
135         output += outputsamplesize;
136     }
137 }
138 
139 static inline void
pcm_write_samples_16_to_32(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)140 pcm_write_samples_16_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
141     for (int s = 0; s < nsamples; s++) {
142         for (int c = 0; c < outputfmt->channels; c++) {
143             char *out = output + 4 * c;
144             const char *in = input + channelmap[c]*2;
145             out[0] = 0;
146             out[1] = 0;
147             out[2] = in[0];
148             out[3] = in[1];
149         }
150         input += 2 * inputfmt->channels;
151         output += outputsamplesize;
152     }
153 }
154 
155 static inline void
pcm_write_samples_16_to_float(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)156 pcm_write_samples_16_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
157     for (int s = 0; s < nsamples; s++) {
158         for (int c = 0; c < outputfmt->channels; c++) {
159             float sample = (*((int16_t*)(input + channelmap[c]*2))) / (float)0x8000;
160             *((float *)(output + 4 * c)) = sample;
161         }
162         input += 2 * inputfmt->channels;
163         output += outputsamplesize;
164     }
165 }
166 
167 static inline void
pcm_write_samples_24_to_8(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)168 pcm_write_samples_24_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
169     for (int s = 0; s < nsamples; s++) {
170         for (int c = 0; c < outputfmt->channels; c++) {
171             char *out = output + c;
172             *out = (input + channelmap[c] * 3)[2];
173         }
174         input += 3 * inputfmt->channels;
175         output += outputsamplesize;
176     }
177 }
178 
179 static inline void
pcm_write_samples_24_to_24(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)180 pcm_write_samples_24_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
181     for (int s = 0; s < nsamples; s++) {
182         for (int c = 0; c < outputfmt->channels; c++) {
183             char *out = output + 3 * c;
184             const char *in = input + channelmap[c] * 3;
185             out[0] = in[0];
186             out[1] = in[1];
187             out[2] = in[2];
188         }
189         input += 3 * inputfmt->channels;
190         output += outputsamplesize;
191     }
192 }
193 
194 static inline void
pcm_write_samples_24_to_32(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)195 pcm_write_samples_24_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
196     for (int s = 0; s < nsamples; s++) {
197         for (int c = 0; c < outputfmt->channels; c++) {
198             char *out = output + 4 * c;
199             const char *in = input + 3 * channelmap[c];
200             out[0] = 0;
201             out[1] = in[0];
202             out[2] = in[1];
203             out[3] = in[2];
204         }
205         input += inputfmt->channels * 3;
206         output += outputsamplesize;
207     }
208 }
209 
210 static inline void
pcm_write_samples_24_to_16(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)211 pcm_write_samples_24_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
212     for (int s = 0; s < nsamples; s++) {
213         for (int c = 0; c < outputfmt->channels; c++) {
214             char *out = output + 2 * c;
215             const char *in = input + 3 * channelmap[c];
216             out[0] = in[1];
217             out[1] = in[2];
218         }
219         input += inputfmt->channels * 3;
220         output += outputsamplesize;
221     }
222 }
223 
224 static inline void
pcm_write_samples_24_to_float(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)225 pcm_write_samples_24_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
226     for (int s = 0; s < nsamples; s++) {
227         for (int c = 0; c < outputfmt->channels; c++) {
228             float *out = (float *)(output + 4 * c);
229             const char *in = input + 3 * channelmap[c];
230             int32_t sample = ((unsigned char)in[0]) | ((unsigned char)in[1]<<8) | (in[2]<<16);
231             *out = sample / (float)0x800000;
232         }
233         input += inputfmt->channels * 3;
234         output += outputsamplesize;
235     }
236 }
237 
238 static inline void
pcm_write_samples_32_to_8(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)239 pcm_write_samples_32_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
240     for (int s = 0; s < nsamples; s++) {
241         for (int c = 0; c < outputfmt->channels; c++) {
242             int8_t *out = (int8_t*)(output + c);
243             int32_t sample = *((int32_t*)(input + 4 * channelmap[c]));
244             *out = (int8_t)(sample>>24);
245         }
246         input += 4 * inputfmt->channels;
247         output += outputsamplesize;
248     }
249 }
250 
251 static inline void
pcm_write_samples_32_to_16(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)252 pcm_write_samples_32_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
253     for (int s = 0; s < nsamples; s++) {
254         for (int c = 0; c < outputfmt->channels; c++) {
255             int16_t *out = (int16_t*)(output + 2 * c);
256             int32_t sample = *((int32_t*)(input + 4 * channelmap[c]));
257             *out = (int16_t)(sample>>16);
258         }
259         input += 4 * inputfmt->channels;
260         output += outputsamplesize;
261     }
262 }
263 
264 static inline void
pcm_write_samples_32_to_24(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)265 pcm_write_samples_32_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
266     for (int s = 0; s < nsamples; s++) {
267         for (int c = 0; c < outputfmt->channels; c++) {
268             char *out = output + 3 * c;
269             const char *in = input + 4 * channelmap[c];
270             out[0] = in[1];
271             out[1] = in[2];
272             out[2] = in[3];
273         }
274         input += 4 * inputfmt->channels;
275         output += outputsamplesize;
276     }
277 }
278 
279 static inline void
pcm_write_samples_32_to_32(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)280 pcm_write_samples_32_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
281     for (int s = 0; s < nsamples; s++) {
282         for (int c = 0; c < outputfmt->channels; c++) {
283             *((int32_t*)(output + 4 * c)) = *((int32_t*)(input + channelmap[c] * 4));
284         }
285         input += 4 * inputfmt->channels;
286         output += outputsamplesize;
287     }
288 }
289 
290 
291 static inline void
pcm_write_samples_32_to_float(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)292 pcm_write_samples_32_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
293     for (int s = 0; s < nsamples; s++) {
294         for (int c = 0; c < outputfmt->channels; c++) {
295             float *out = (float *)(output + 4 * c);
296             int32_t sample = *((int32_t*)(input + channelmap[c] * 4));
297             *out = sample / (float)0x80000000;
298         }
299         input += 4 * inputfmt->channels;
300         output += outputsamplesize;
301     }
302 }
303 static inline void
pcm_write_samples_float_to_8(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)304 pcm_write_samples_float_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
305     fpu_control ctl;
306     fpu_setround (&ctl);
307     for (int s = 0; s < nsamples; s++) {
308         for (int c = 0; c < outputfmt->channels; c++) {
309             int8_t *out = (int8_t*)(output + c);
310             float sample = *((float*)(input + channelmap[c] * 4));
311             int isample = sample * 0x80;
312             if (isample > 0x7f) {
313                 isample = 0x7f;
314             }
315             else if (isample < -0x80) {
316                 isample = -0x80;
317             }
318             *out = (int8_t)ftoi (isample);
319         }
320         input += 4 * inputfmt->channels;
321         output += outputsamplesize;
322     }
323     fpu_restore (ctl);
324 }
325 
326 static inline void
pcm_write_samples_float_to_16(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)327 pcm_write_samples_float_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
328     fpu_control ctl;
329     fpu_setround (&ctl);
330     for (int s = 0; s < nsamples; s++) {
331         for (int c = 0; c < outputfmt->channels; c++) {
332             int16_t *out = (int16_t*)(output + 2 * c);
333             float sample = *((float*)(input + 4 * channelmap[c]));
334             int isample = ftoi (sample*0x8000);
335             if (isample > 0x7fff) {
336                 isample = 0x7fff;
337             }
338             else if (isample < -0x8000) {
339                 isample = -0x8000;
340             }
341             *out = (int16_t)isample;
342         }
343         input += 4 * inputfmt->channels;
344         output += outputsamplesize;
345     }
346     fpu_restore (ctl);
347 }
348 
349 static inline void
pcm_write_samples_float_to_24(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)350 pcm_write_samples_float_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
351     fpu_control ctl;
352     fpu_setround (&ctl);
353     for (int s = 0; s < nsamples; s++) {
354         for (int c = 0; c < outputfmt->channels; c++) {
355             char *out = output + 3 * c;
356             float sample = *((float*)(input + channelmap[c] * 4));
357             int32_t outsample = (int32_t)ftoi (sample * 0x800000);
358             if (outsample >= 0x7fffff) {
359                 outsample = 0x7fffff;
360             }
361             else if (outsample < -0x800000) {
362                 outsample = -0x800000;
363             }
364             out[0] = (outsample&0x0000ff);
365             out[1] = (outsample&0x00ff00)>>8;
366             out[2] = (outsample&0xff0000)>>16;
367         }
368         input += 4 * inputfmt->channels;
369         output += outputsamplesize;
370     }
371     fpu_restore (ctl);
372 }
373 
374 
375 static inline void
pcm_write_samples_float_to_32(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int nsamples,int * restrict channelmap,int outputsamplesize)376 pcm_write_samples_float_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
377     for (int s = 0; s < nsamples; s++) {
378         for (int c = 0; c < outputfmt->channels; c++) {
379             float fsample = (*((float*)(input + channelmap[c] * 4)));
380             if (fsample > (float)0x7fffffff/0x80000000) {
381                 fsample = (float)0x7fffffff/0x80000000;
382             }
383             else if (fsample < -1.f) {
384                 fsample = -1.f;
385             }
386             int32_t sample = fsample * (float)0x80000000;
387             *((int32_t *)(output + 4 * c)) = sample;
388         }
389         input += 4 * inputfmt->channels;
390         output += outputsamplesize;
391     }
392 }
393 
394 typedef void (*remap_fn_t) (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize);
395 
396 
397 remap_fn_t remappers[8][8] = {
398     {
399         pcm_write_samples_8_to_8,
400         pcm_write_samples_8_to_16,
401         pcm_write_samples_8_to_24,
402         pcm_write_samples_8_to_32,
403         NULL,
404         NULL,
405         NULL,
406         pcm_write_samples_8_to_float,
407     },
408     {
409         pcm_write_samples_16_to_8,
410         pcm_write_samples_16_to_16,
411         pcm_write_samples_16_to_24,
412         pcm_write_samples_16_to_32,
413         NULL,
414         NULL,
415         NULL,
416         pcm_write_samples_16_to_float,
417     },
418     {
419         pcm_write_samples_24_to_8,
420         pcm_write_samples_24_to_16,
421         pcm_write_samples_24_to_24,
422         pcm_write_samples_24_to_32,
423         NULL,
424         NULL,
425         NULL,
426         pcm_write_samples_24_to_float,
427     },
428     {
429         pcm_write_samples_32_to_8,
430         pcm_write_samples_32_to_16,
431         pcm_write_samples_32_to_24,
432         pcm_write_samples_32_to_32,
433         NULL,
434         NULL,
435         NULL,
436         pcm_write_samples_32_to_float,
437     },
438     {
439     },
440     {
441     },
442     {
443     },
444     {
445         pcm_write_samples_float_to_8,
446         pcm_write_samples_float_to_16,
447         pcm_write_samples_float_to_24,
448         pcm_write_samples_float_to_32,
449         NULL,
450         NULL,
451         NULL,
452         pcm_write_samples_32_to_32,
453     }
454 };
455 
456 int
pcm_convert(const ddb_waveformat_t * restrict inputfmt,const char * restrict input,const ddb_waveformat_t * restrict outputfmt,char * restrict output,int inputsize)457 pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int inputsize) {
458     // calculate output size
459     int inputsamplesize = (inputfmt->bps >> 3) * inputfmt->channels;
460     int outputsamplesize = (outputfmt->bps >> 3) * outputfmt->channels;
461     int nsamples = inputsize / inputsamplesize;
462 
463     uint32_t outchannels = 0;
464 
465     if (output) {
466         // build channelmap
467         int channelmap[32] = {0};
468         uint32_t inputbitmask = 1;
469         for (int i = 0; i < inputfmt->channels; i++) {
470             // find next input channel
471             while (inputbitmask < 0x80000000 && !(inputfmt->channelmask & inputbitmask)) {
472                 inputbitmask <<= 1;
473             }
474             if (!(inputfmt->channelmask & inputbitmask)) {
475                 trace ("pcm_convert: channelmask doesn't correspond inputfmt (channels=%d, channelmask=%X)!\n", inputfmt->channels, inputfmt->channelmask);
476                 break;
477             }
478             if (outputfmt->channelmask & inputbitmask) {
479                 int o = 0;
480                 uint32_t outputbitmask = 1;
481                 while (outputbitmask < 0x80000000 && (outputfmt->channelmask & outputbitmask) != inputbitmask) {
482                     outputbitmask <<= 1;
483                     o++;
484                 }
485                 if (!(inputfmt->channelmask & outputbitmask)) {
486                     // no corresponding output channel -- ignore
487                     continue;
488                 }
489                 outchannels |= outputbitmask;
490                 channelmap[i] = o; // input channel i going to output channel o
491                 //trace ("channelmap[%d]=%d\n", i, o);
492             }
493             inputbitmask <<= 1;
494         }
495 
496         if (outchannels != outputfmt->channelmask) {
497             // some of the channels are not used
498             memset (output, 0, nsamples * outputsamplesize);
499         }
500 
501         int outidx = ((outputfmt->bps >> 3) - 1) | (outputfmt->is_float << 2);
502         int inidx = ((inputfmt->bps >> 3) - 1) | (inputfmt->is_float << 2);
503         if (remappers[inidx][outidx]) {
504             remappers[inidx][outidx] (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
505         }
506         else {
507             trace ("no converter from %d %s to %d %s ([%d][%d])\n", inputfmt->bps, inputfmt->is_float ? "float" : "", outputfmt->bps, outputfmt->is_float ? "float" : "", inidx, outidx);
508         }
509     }
510     return nsamples * outputsamplesize;
511 }
512 
513