source: roaraudio/libroardsp/channels.c @ 4708:c9d40761088a

Last change on this file since 4708:c9d40761088a was 4708:c9d40761088a, checked in by phi, 13 years ago

updated copyright statements

File size: 14.2 KB
Line 
1//channels.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
5 *
6 *  This file is part of libroardsp a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroardsp is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "libroardsp.h"
27#include "roaraudio/units.h"
28
29static struct {
30 int id;
31 char * name;
32 char * sn;
33} _g_chans[] = {
34 // general:
35 {ROARDSP_CHAN_NONE,           "NONE",           "NONE"           },
36 // waveform:
37 {ROARDSP_CHAN_FRONT_LEFT,     "FRONT_LEFT",     "FL"             },
38 {ROARDSP_CHAN_FRONT_RIGHT,    "FRONT_RIGHT",    "FR"             },
39 {ROARDSP_CHAN_SIDE_LEFT,      "SIDE_LEFT",      "SL"             },
40 {ROARDSP_CHAN_SIDE_RIGHT,     "SIDE_RIGHT",     "SR"             },
41 {ROARDSP_CHAN_BACK_LEFT,      "BACK_LEFT",      "BL"             },
42 {ROARDSP_CHAN_BACK_RIGHT,     "BACK_RIGHT",     "BR"             },
43 {ROARDSP_CHAN_FRONT_CENTER,   "FRONT_CENTER",   "FC"             },
44 {ROARDSP_CHAN_SIDE_CENTER,    "SIDE_CENTER",    "SC"             },
45 {ROARDSP_CHAN_BACK_CENTER,    "BACK_CENTER",    "BC"             },
46 {ROARDSP_CHAN_LEFT,           "LEFT",           "L"              }, // alias
47 {ROARDSP_CHAN_RIGHT,          "RIGHT",          "R"              }, // alias
48 {ROARDSP_CHAN_CENTER,         "CENTER",         "C"              }, // alias
49 {ROARDSP_CHAN_MONO,           "MONO",           "M"              }, // alias
50 {ROARDSP_CHAN_MS_MID,         "MS_MID",         "MID"            },
51 {ROARDSP_CHAN_MS_SIDE,        "MS_SIDE",        "SIDE"           },
52 {ROARDSP_CHAN_LFE,            "LFE",            "LFE"            },
53 // midi:
54 {ROARDSP_CHAN_MIDI0,           "MIDI0",         NULL             },
55 {ROARDSP_CHAN_MIDI1,           "MIDI1",         NULL             },
56 {ROARDSP_CHAN_MIDI2,           "MIDI2",         NULL             },
57 {ROARDSP_CHAN_MIDI3,           "MIDI3",         NULL             },
58 {ROARDSP_CHAN_MIDI4,           "MIDI4",         NULL             },
59 {ROARDSP_CHAN_MIDI5,           "MIDI5",         NULL             },
60 {ROARDSP_CHAN_MIDI6,           "MIDI6",         NULL             },
61 {ROARDSP_CHAN_MIDI7,           "MIDI7",         NULL             },
62 {ROARDSP_CHAN_MIDI8,           "MIDI8",         NULL             },
63 {ROARDSP_CHAN_MIDI9,           "MIDI9",         NULL             },
64 {ROARDSP_CHAN_MIDI10,          "MIDI10",        NULL             },
65 {ROARDSP_CHAN_MIDI11,          "MIDI11",        NULL             },
66 {ROARDSP_CHAN_MIDI12,          "MIDI12",        NULL             },
67 {ROARDSP_CHAN_MIDI13,          "MIDI13",        NULL             },
68 {ROARDSP_CHAN_MIDI14,          "MIDI14",        NULL             },
69 {ROARDSP_CHAN_MIDI15,          "MIDI15",        NULL             },
70 {ROARDSP_CHAN_EOL, NULL, NULL}
71};
72
73char * roardsp_chan2str (int chan) {
74 int i;
75
76 for (i = 0; _g_chans[i].id != ROARDSP_CHAN_EOL; i++)
77  if ( _g_chans[i].id == chan )
78   return _g_chans[i].name;
79
80 return NULL;
81}
82
83int roardsp_str2chan(char * str) {
84 int i;
85
86 for (i = 0; _g_chans[i].id != ROARDSP_CHAN_EOL; i++)
87  if ( !strcasecmp(_g_chans[i].name, str) ||
88       (_g_chans[i].sn != NULL && !strcasecmp(_g_chans[i].sn, str)) )
89   return _g_chans[i].id;
90
91 return -1;
92}
93
94int    roardsp_chanlist2str(char * list, size_t len, char * str, size_t strlen) {
95 char * name;
96 int i;
97
98 if ( list == NULL && len > 0 )
99  return -1;
100
101 if ( (str == NULL || strlen == 0) && len > 0 )
102  return -1;
103
104 if ( len == 0 ) {
105  if ( str != NULL && strlen > 0 )
106   *str = 0;
107
108  return 0;
109 }
110
111 // TODO: FIXME: do not ignore strlen from here
112 *str = 0;
113
114 for (i = 0; i < len; i++) {
115  if ( i != 0 )
116   strcat(str, ",");
117
118  name = roardsp_chan2str(list[i]);
119
120  if ( name == NULL ) {
121   strcat(str, "<<<INVALID>>>");
122  } else {
123   strcat(str, name);
124  }
125 }
126
127 return 0;
128}
129
130int    roardsp_chanlist_init(char * list, int channels, int map) {
131 int i;
132
133 if ( channels == 0 )
134  return 0;
135
136 if ( list == NULL )
137  return -1;
138
139 if ( channels > ROAR_MAX_CHANNELS )
140  return -1;
141
142 if ( map == ROARDSP_CHANLIST_MAP_MIDI ) {
143  for (i = 0; i < channels; i++) {
144   list[i] = i+ROARDSP_CHAN_MIDI0;
145  }
146 }
147
148 // test for common maps:
149 if ( channels == 1 ) {
150  list[0] = ROARDSP_CHAN_MONO;
151  return 0;
152 }
153
154 if ( channels == 2 ) {
155  list[0] = ROARDSP_CHAN_LEFT;
156  list[1] = ROARDSP_CHAN_RIGHT;
157  return 0;
158 }
159
160 // test for specific maps:
161 switch (map) {
162  case ROARDSP_CHANLIST_MAP_ROARAUDIO:
163  case ROARDSP_CHANLIST_MAP_FLAC:
164    if ( map == ROARDSP_CHANLIST_MAP_FLAC && channels > 6 ) {
165     // FLAC only has a fixed mapping for up to 6 channels.
166     return -1;
167    }
168
169    switch (channels) {
170     // FLAC or RoarAudio:
171     case 3:
172       list[0] = ROARDSP_CHAN_LEFT;
173       list[1] = ROARDSP_CHAN_RIGHT;
174       list[2] = ROARDSP_CHAN_CENTER;
175      break;
176     case 4:
177       list[0] = ROARDSP_CHAN_FRONT_LEFT;
178       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
179       list[2] = ROARDSP_CHAN_BACK_LEFT;
180       list[3] = ROARDSP_CHAN_BACK_RIGHT;
181      break;
182     case 5:
183       list[0] = ROARDSP_CHAN_FRONT_LEFT;
184       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
185       list[2] = ROARDSP_CHAN_CENTER;
186       list[3] = ROARDSP_CHAN_BACK_LEFT;
187       list[4] = ROARDSP_CHAN_BACK_RIGHT;
188      break;
189     case 6:
190       list[0] = ROARDSP_CHAN_FRONT_LEFT;
191       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
192       list[2] = ROARDSP_CHAN_CENTER;
193       list[3] = ROARDSP_CHAN_LFE;
194       list[4] = ROARDSP_CHAN_BACK_LEFT;
195       list[5] = ROARDSP_CHAN_BACK_RIGHT;
196      break;
197     // RoarAudio:
198     case 7:
199       list[0] = ROARDSP_CHAN_FRONT_LEFT;
200       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
201       list[2] = ROARDSP_CHAN_CENTER;
202       list[3] = ROARDSP_CHAN_LFE;
203       list[4] = ROARDSP_CHAN_SIDE_LEFT;
204       list[5] = ROARDSP_CHAN_SIDE_RIGHT;
205       list[6] = ROARDSP_CHAN_BACK_CENTER;
206      break;
207     case 8:
208       list[0] = ROARDSP_CHAN_FRONT_LEFT;
209       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
210       list[2] = ROARDSP_CHAN_CENTER;
211       list[3] = ROARDSP_CHAN_LFE;
212       list[4] = ROARDSP_CHAN_SIDE_LEFT;
213       list[5] = ROARDSP_CHAN_SIDE_RIGHT;
214       list[6] = ROARDSP_CHAN_BACK_LEFT;
215       list[7] = ROARDSP_CHAN_BACK_RIGHT;
216      break;
217     default:
218       return -1;
219      break;
220    }
221   break;
222  case ROARDSP_CHANLIST_MAP_VORBIS:
223    switch (channels) {
224     case 3:
225       list[0] = ROARDSP_CHAN_LEFT;
226       list[1] = ROARDSP_CHAN_CENTER;
227       list[2] = ROARDSP_CHAN_RIGHT;
228      break;
229     case 4:
230       list[0] = ROARDSP_CHAN_FRONT_LEFT;
231       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
232       list[2] = ROARDSP_CHAN_BACK_LEFT;
233       list[3] = ROARDSP_CHAN_BACK_RIGHT;
234      break;
235     case 5:
236       list[0] = ROARDSP_CHAN_FRONT_LEFT;
237       list[1] = ROARDSP_CHAN_CENTER;
238       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
239       list[3] = ROARDSP_CHAN_BACK_LEFT;
240       list[4] = ROARDSP_CHAN_BACK_RIGHT;
241      break;
242     case 6:
243       list[0] = ROARDSP_CHAN_FRONT_LEFT;
244       list[1] = ROARDSP_CHAN_CENTER;
245       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
246       list[3] = ROARDSP_CHAN_BACK_LEFT;
247       list[4] = ROARDSP_CHAN_BACK_RIGHT;
248       list[5] = ROARDSP_CHAN_LFE;
249      break;
250     case 7:
251       list[0] = ROARDSP_CHAN_FRONT_LEFT;
252       list[1] = ROARDSP_CHAN_CENTER;
253       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
254       list[3] = ROARDSP_CHAN_SIDE_LEFT;
255       list[4] = ROARDSP_CHAN_SIDE_RIGHT;
256       list[5] = ROARDSP_CHAN_BACK_CENTER;
257       list[6] = ROARDSP_CHAN_LFE;
258      break;
259     case 8:
260       list[0] = ROARDSP_CHAN_FRONT_LEFT;
261       list[1] = ROARDSP_CHAN_CENTER;
262       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
263       list[3] = ROARDSP_CHAN_SIDE_LEFT;
264       list[4] = ROARDSP_CHAN_SIDE_RIGHT;
265       list[5] = ROARDSP_CHAN_BACK_LEFT;
266       list[6] = ROARDSP_CHAN_BACK_RIGHT;
267       list[7] = ROARDSP_CHAN_LFE;
268      break;
269     default:
270       return -1;
271      break;
272    }
273   break;
274  case ROARDSP_CHANLIST_MAP_OSS:
275    switch (channels) {
276     case 8:
277       list[7] = ROARDSP_CHAN_BACK_RIGHT;
278     case 7:
279       list[6] = ROARDSP_CHAN_BACK_LEFT;
280     case 6:
281       list[5] = ROARDSP_CHAN_SIDE_RIGHT;
282     case 5:
283       list[4] = ROARDSP_CHAN_SIDE_LEFT;
284     case 4:
285       list[3] = ROARDSP_CHAN_LFE;
286     case 3:
287       list[2] = ROARDSP_CHAN_CENTER;
288       list[1] = ROARDSP_CHAN_RIGHT;
289       list[0] = ROARDSP_CHAN_LEFT;
290      break;
291     default:
292       return -1;
293      break;
294    }
295   break;
296  case ROARDSP_CHANLIST_MAP_ALSA:
297    // we guess: L,R,BL,BR,C,LFE,SL,SR (really, just guessing, see ALSA plugin of libao)
298    switch (channels) {
299     case 8:
300       list[7] = ROARDSP_CHAN_BACK_RIGHT;
301     case 7:
302       list[6] = ROARDSP_CHAN_BACK_LEFT;
303     case 6:
304       list[5] = ROARDSP_CHAN_LFE;
305     case 5:
306       list[4] = ROARDSP_CHAN_CENTER;
307     case 4:
308       list[3] = ROARDSP_CHAN_BACK_RIGHT;
309     case 3:
310       list[2] = ROARDSP_CHAN_BACK_LEFT;
311       list[1] = ROARDSP_CHAN_RIGHT;
312       list[0] = ROARDSP_CHAN_LEFT;
313      break;
314     default:
315       return -1;
316      break;
317    }
318   break;
319  case ROARDSP_CHANLIST_MAP_RIFF_WAVE:
320    // here we are again, guessing:  L,R,C,LFE,BL,BR,CL,CR,BC,SL,SR
321    // strange, C, LFE on 4 channel file?
322    // return -1 to be sure....
323    switch (channels) {
324     default:
325       return -1;
326      break;
327    }
328   break;
329  default:
330    return -1;
331   break;
332 }
333
334 return 0;
335}
336
337int roardsp_chanmap_calc(struct roardsp_chanmap * map, int what, int err_on_none) {
338 int a, b;
339
340 if ( map == NULL )
341  return -1;
342
343 switch (what) {
344  case ROARDSP_CHANMAP_MAP:
345    memset(map->map, (char)-1, sizeof(map->map));
346
347    for (a = 0; a < ROAR_MAX_CHANNELS; a++) {
348     if ( map->in[a] == ROARDSP_CHAN_NONE )
349      continue;
350
351     for (b = 0; b < ROAR_MAX_CHANNELS; b++) {
352      if ( map->in[a] == map->out[b] ) {
353       map->map[a] = b;
354       break;
355      }
356     }
357     if ( b == ROAR_MAX_CHANNELS ) { // src not found in dest
358      if ( err_on_none )
359       return -1;
360
361      map->map[a] = -1;
362     }
363    }
364   break;
365  case ROARDSP_CHANMAP_INVMAP:
366    memset(map->map, (char)-1, sizeof(map->map));
367
368    for (a = 0; a < ROAR_MAX_CHANNELS; a++) {
369     if ( map->out[a] == ROARDSP_CHAN_NONE )
370      continue;
371
372     for (b = 0; b < ROAR_MAX_CHANNELS; b++) {
373      if ( map->out[a] == map->in[b] ) {
374       map->map[a] = b;
375       break;
376      }
377     }
378     if ( b == ROAR_MAX_CHANNELS ) { // src not found in dest
379      if ( err_on_none )
380       return -1;
381
382      map->map[a] = -1;
383     }
384    }
385   break;
386  case ROARDSP_CHANMAP_IN:
387  case ROARDSP_CHANMAP_OUT:
388  default:
389    return -1;
390   break;
391 }
392
393 return 0;
394}
395
396int roardsp_chanmap_mappcm8 (char    * out, char    * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
397 char buf[ROAR_MAX_CHANNELS];
398 size_t frame;
399 size_t c;
400
401 if ( len == 0 )
402  return 0;
403
404 if ( out == NULL || in == NULL || map == NULL )
405  return -1;
406
407 if ( chans > ROAR_MAX_CHANNELS )
408  return -1;
409
410 if ( in == out ) {
411  for (frame = 0; frame < len/(chans*_8BIT); frame++) {
412   memset(buf, 0, sizeof(buf));
413
414   for (c = 0; c < chans; c++) {
415    buf[(int)map->map[c]] = in[c];
416   }
417
418   memcpy(out, buf, chans*_8BIT);
419
420   in  += chans;
421   out += chans;
422  }
423 } else {
424  memset(out, 0, len); // silance channels we do not use
425  for (frame = 0; frame < len/(chans*_8BIT); frame++) {
426   for (c = 0; c < chans; c++) {
427    out[(int)map->map[c]] = in[c];
428   }
429   in  += chans;
430   out += chans;
431  }
432 }
433
434 return 0;
435}
436
437int roardsp_chanmap_mappcm16(int16_t * out, int16_t * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
438 int16_t buf[ROAR_MAX_CHANNELS];
439 size_t frame;
440 size_t c;
441
442 if ( len == 0 )
443  return 0;
444
445 if ( out == NULL || in == NULL || map == NULL )
446  return -1;
447
448 if ( chans > ROAR_MAX_CHANNELS )
449  return -1;
450
451 if ( in == out ) {
452  for (frame = 0; frame < len/(chans*_16BIT); frame++) {
453   memset(buf, 0, sizeof(buf));
454
455   for (c = 0; c < chans; c++) {
456    buf[(int)map->map[c]] = in[c];
457   }
458
459   memcpy(out, buf, chans*_16BIT);
460
461   in  += chans;
462   out += chans;
463  }
464 } else {
465  memset(out, 0, len); // silance channels we do not use
466  for (frame = 0; frame < len/(chans*_16BIT); frame++) {
467   for (c = 0; c < chans; c++) {
468    out[(int)map->map[c]] = in[c];
469   }
470   in  += chans;
471   out += chans;
472  }
473 }
474
475 return 0;
476}
477
478int roardsp_chanmap_mappcm24(void    * out, void    * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
479 return -1;
480}
481
482int roardsp_chanmap_mappcm32(int32_t * out, int32_t * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
483 int32_t buf[ROAR_MAX_CHANNELS];
484 size_t frame;
485 size_t c;
486
487 if ( len == 0 )
488  return 0;
489
490 if ( out == NULL || in == NULL || map == NULL )
491  return -1;
492
493 if ( chans > ROAR_MAX_CHANNELS )
494  return -1;
495
496 if ( in == out ) {
497  for (frame = 0; frame < len/(chans*_32BIT); frame++) {
498   memset(buf, 0, sizeof(buf));
499
500   for (c = 0; c < chans; c++) {
501    buf[(int)map->map[c]] = in[c];
502   }
503
504   memcpy(out, buf, chans*_32BIT);
505
506   in  += chans;
507   out += chans;
508  }
509 } else {
510  memset(out, 0, len); // silance channels we do not use
511  for (frame = 0; frame < len/(chans*_32BIT); frame++) {
512   for (c = 0; c < chans; c++) {
513    out[(int)map->map[c]] = in[c];
514   }
515   in  += chans;
516   out += chans;
517  }
518 }
519
520 return 0;
521}
522
523int roardsp_chanmap_mappcm  (void    * out, void    * in, size_t len, size_t chans, struct roardsp_chanmap * map, int bits) {
524 if ( len == 0 )
525  return 0;
526
527 if ( out == NULL || in == NULL || map == NULL )
528  return -1;
529
530 if ( chans > ROAR_MAX_CHANNELS )
531  return -1;
532
533#if 0
534 { int i;
535  printf("---- BEGIN MAP ----\n");
536  for (i = 0; i < chans; i++) {
537   printf("MAP: %i->%i\n", i, map[i]);
538  }
539  printf("---- END MAP ----\n");
540 }
541#endif
542
543 switch (bits) {
544  case  8: return roardsp_chanmap_mappcm8(out, in, len, chans, map);  break;
545  case 16: return roardsp_chanmap_mappcm16(out, in, len, chans, map); break;
546  case 24: return roardsp_chanmap_mappcm24(out, in, len, chans, map); break;
547  case 32: return roardsp_chanmap_mappcm32(out, in, len, chans, map); break;
548  default:
549    return -1;
550   break;
551 }
552}
553
554//ll
Note: See TracBrowser for help on using the repository browser.