source: roaraudio/libroardsp/channels.c @ 5908:66940b2023ee

Last change on this file since 5908:66940b2023ee was 5862:560033570a60, checked in by phi, 11 years ago

avoid linker warning on openbsd, also harden against string buffer overflows by using strlcat()

File size: 14.2 KB
Line 
1//channels.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2013
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 size_t i;
96 char * name;
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 *str = 0;
112
113 for (i = 0; i < len; i++) {
114  if ( i != 0 )
115   roar_mm_strlcat(str, ",", strlen);
116
117  name = roardsp_chan2str(list[i]);
118
119  if ( name == NULL ) {
120   roar_mm_strlcat(str, "<<<INVALID>>>", strlen);
121  } else {
122   roar_mm_strlcat(str, name, strlen);
123  }
124 }
125
126 return 0;
127}
128
129int    roardsp_chanlist_init(char * list, int channels, int map) {
130 int i;
131
132 if ( channels == 0 )
133  return 0;
134
135 if ( list == NULL )
136  return -1;
137
138 if ( channels > ROAR_MAX_CHANNELS )
139  return -1;
140
141 if ( map == ROARDSP_CHANLIST_MAP_MIDI ) {
142  for (i = 0; i < channels; i++) {
143   list[i] = i+ROARDSP_CHAN_MIDI0;
144  }
145 }
146
147 // test for common maps:
148 if ( channels == 1 ) {
149  list[0] = ROARDSP_CHAN_MONO;
150  return 0;
151 }
152
153 if ( channels == 2 ) {
154  list[0] = ROARDSP_CHAN_LEFT;
155  list[1] = ROARDSP_CHAN_RIGHT;
156  return 0;
157 }
158
159 // test for specific maps:
160 switch (map) {
161  case ROARDSP_CHANLIST_MAP_ROARAUDIO:
162  case ROARDSP_CHANLIST_MAP_FLAC:
163    if ( map == ROARDSP_CHANLIST_MAP_FLAC && channels > 6 ) {
164     // FLAC only has a fixed mapping for up to 6 channels.
165     return -1;
166    }
167
168    switch (channels) {
169     // FLAC or RoarAudio:
170     case 3:
171       list[0] = ROARDSP_CHAN_LEFT;
172       list[1] = ROARDSP_CHAN_RIGHT;
173       list[2] = ROARDSP_CHAN_CENTER;
174      break;
175     case 4:
176       list[0] = ROARDSP_CHAN_FRONT_LEFT;
177       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
178       list[2] = ROARDSP_CHAN_BACK_LEFT;
179       list[3] = ROARDSP_CHAN_BACK_RIGHT;
180      break;
181     case 5:
182       list[0] = ROARDSP_CHAN_FRONT_LEFT;
183       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
184       list[2] = ROARDSP_CHAN_CENTER;
185       list[3] = ROARDSP_CHAN_BACK_LEFT;
186       list[4] = ROARDSP_CHAN_BACK_RIGHT;
187      break;
188     case 6:
189       list[0] = ROARDSP_CHAN_FRONT_LEFT;
190       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
191       list[2] = ROARDSP_CHAN_CENTER;
192       list[3] = ROARDSP_CHAN_LFE;
193       list[4] = ROARDSP_CHAN_BACK_LEFT;
194       list[5] = ROARDSP_CHAN_BACK_RIGHT;
195      break;
196     // RoarAudio:
197     case 7:
198       list[0] = ROARDSP_CHAN_FRONT_LEFT;
199       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
200       list[2] = ROARDSP_CHAN_CENTER;
201       list[3] = ROARDSP_CHAN_LFE;
202       list[4] = ROARDSP_CHAN_SIDE_LEFT;
203       list[5] = ROARDSP_CHAN_SIDE_RIGHT;
204       list[6] = ROARDSP_CHAN_BACK_CENTER;
205      break;
206     case 8:
207       list[0] = ROARDSP_CHAN_FRONT_LEFT;
208       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
209       list[2] = ROARDSP_CHAN_CENTER;
210       list[3] = ROARDSP_CHAN_LFE;
211       list[4] = ROARDSP_CHAN_SIDE_LEFT;
212       list[5] = ROARDSP_CHAN_SIDE_RIGHT;
213       list[6] = ROARDSP_CHAN_BACK_LEFT;
214       list[7] = ROARDSP_CHAN_BACK_RIGHT;
215      break;
216     default:
217       return -1;
218      break;
219    }
220   break;
221  case ROARDSP_CHANLIST_MAP_VORBIS:
222    switch (channels) {
223     case 3:
224       list[0] = ROARDSP_CHAN_LEFT;
225       list[1] = ROARDSP_CHAN_CENTER;
226       list[2] = ROARDSP_CHAN_RIGHT;
227      break;
228     case 4:
229       list[0] = ROARDSP_CHAN_FRONT_LEFT;
230       list[1] = ROARDSP_CHAN_FRONT_RIGHT;
231       list[2] = ROARDSP_CHAN_BACK_LEFT;
232       list[3] = ROARDSP_CHAN_BACK_RIGHT;
233      break;
234     case 5:
235       list[0] = ROARDSP_CHAN_FRONT_LEFT;
236       list[1] = ROARDSP_CHAN_CENTER;
237       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
238       list[3] = ROARDSP_CHAN_BACK_LEFT;
239       list[4] = ROARDSP_CHAN_BACK_RIGHT;
240      break;
241     case 6:
242       list[0] = ROARDSP_CHAN_FRONT_LEFT;
243       list[1] = ROARDSP_CHAN_CENTER;
244       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
245       list[3] = ROARDSP_CHAN_BACK_LEFT;
246       list[4] = ROARDSP_CHAN_BACK_RIGHT;
247       list[5] = ROARDSP_CHAN_LFE;
248      break;
249     case 7:
250       list[0] = ROARDSP_CHAN_FRONT_LEFT;
251       list[1] = ROARDSP_CHAN_CENTER;
252       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
253       list[3] = ROARDSP_CHAN_SIDE_LEFT;
254       list[4] = ROARDSP_CHAN_SIDE_RIGHT;
255       list[5] = ROARDSP_CHAN_BACK_CENTER;
256       list[6] = ROARDSP_CHAN_LFE;
257      break;
258     case 8:
259       list[0] = ROARDSP_CHAN_FRONT_LEFT;
260       list[1] = ROARDSP_CHAN_CENTER;
261       list[2] = ROARDSP_CHAN_FRONT_RIGHT;
262       list[3] = ROARDSP_CHAN_SIDE_LEFT;
263       list[4] = ROARDSP_CHAN_SIDE_RIGHT;
264       list[5] = ROARDSP_CHAN_BACK_LEFT;
265       list[6] = ROARDSP_CHAN_BACK_RIGHT;
266       list[7] = ROARDSP_CHAN_LFE;
267      break;
268     default:
269       return -1;
270      break;
271    }
272   break;
273  case ROARDSP_CHANLIST_MAP_OSS:
274    switch (channels) {
275     case 8:
276       list[7] = ROARDSP_CHAN_BACK_RIGHT;
277     case 7:
278       list[6] = ROARDSP_CHAN_BACK_LEFT;
279     case 6:
280       list[5] = ROARDSP_CHAN_SIDE_RIGHT;
281     case 5:
282       list[4] = ROARDSP_CHAN_SIDE_LEFT;
283     case 4:
284       list[3] = ROARDSP_CHAN_LFE;
285     case 3:
286       list[2] = ROARDSP_CHAN_CENTER;
287       list[1] = ROARDSP_CHAN_RIGHT;
288       list[0] = ROARDSP_CHAN_LEFT;
289      break;
290     default:
291       return -1;
292      break;
293    }
294   break;
295  case ROARDSP_CHANLIST_MAP_ALSA:
296    // we guess: L,R,BL,BR,C,LFE,SL,SR (really, just guessing, see ALSA plugin of libao)
297    switch (channels) {
298     case 8:
299       list[7] = ROARDSP_CHAN_BACK_RIGHT;
300     case 7:
301       list[6] = ROARDSP_CHAN_BACK_LEFT;
302     case 6:
303       list[5] = ROARDSP_CHAN_LFE;
304     case 5:
305       list[4] = ROARDSP_CHAN_CENTER;
306     case 4:
307       list[3] = ROARDSP_CHAN_BACK_RIGHT;
308     case 3:
309       list[2] = ROARDSP_CHAN_BACK_LEFT;
310       list[1] = ROARDSP_CHAN_RIGHT;
311       list[0] = ROARDSP_CHAN_LEFT;
312      break;
313     default:
314       return -1;
315      break;
316    }
317   break;
318  case ROARDSP_CHANLIST_MAP_RIFF_WAVE:
319    // here we are again, guessing:  L,R,C,LFE,BL,BR,CL,CR,BC,SL,SR
320    // strange, C, LFE on 4 channel file?
321    // return -1 to be sure....
322    switch (channels) {
323     default:
324       return -1;
325      break;
326    }
327   break;
328  default:
329    return -1;
330   break;
331 }
332
333 return 0;
334}
335
336int roardsp_chanmap_calc(struct roardsp_chanmap * map, int what, int err_on_none) {
337 int a, b;
338
339 if ( map == NULL )
340  return -1;
341
342 switch (what) {
343  case ROARDSP_CHANMAP_MAP:
344    memset(map->map, (char)-1, sizeof(map->map));
345
346    for (a = 0; a < ROAR_MAX_CHANNELS; a++) {
347     if ( map->in[a] == ROARDSP_CHAN_NONE )
348      continue;
349
350     for (b = 0; b < ROAR_MAX_CHANNELS; b++) {
351      if ( map->in[a] == map->out[b] ) {
352       map->map[a] = b;
353       break;
354      }
355     }
356     if ( b == ROAR_MAX_CHANNELS ) { // src not found in dest
357      if ( err_on_none )
358       return -1;
359
360      map->map[a] = -1;
361     }
362    }
363   break;
364  case ROARDSP_CHANMAP_INVMAP:
365    memset(map->map, (char)-1, sizeof(map->map));
366
367    for (a = 0; a < ROAR_MAX_CHANNELS; a++) {
368     if ( map->out[a] == ROARDSP_CHAN_NONE )
369      continue;
370
371     for (b = 0; b < ROAR_MAX_CHANNELS; b++) {
372      if ( map->out[a] == map->in[b] ) {
373       map->map[a] = b;
374       break;
375      }
376     }
377     if ( b == ROAR_MAX_CHANNELS ) { // src not found in dest
378      if ( err_on_none )
379       return -1;
380
381      map->map[a] = -1;
382     }
383    }
384   break;
385  case ROARDSP_CHANMAP_IN:
386  case ROARDSP_CHANMAP_OUT:
387  default:
388    return -1;
389   break;
390 }
391
392 return 0;
393}
394
395int roardsp_chanmap_mappcm8 (char    * out, char    * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
396 char buf[ROAR_MAX_CHANNELS];
397 size_t frame;
398 size_t c;
399
400 if ( len == 0 )
401  return 0;
402
403 if ( out == NULL || in == NULL || map == NULL )
404  return -1;
405
406 if ( chans > ROAR_MAX_CHANNELS )
407  return -1;
408
409 if ( in == out ) {
410  for (frame = 0; frame < len/(chans*_8BIT); frame++) {
411   memset(buf, 0, sizeof(buf));
412
413   for (c = 0; c < chans; c++) {
414    buf[(int)map->map[c]] = in[c];
415   }
416
417   memcpy(out, buf, chans*_8BIT);
418
419   in  += chans;
420   out += chans;
421  }
422 } else {
423  memset(out, 0, len); // silance channels we do not use
424  for (frame = 0; frame < len/(chans*_8BIT); frame++) {
425   for (c = 0; c < chans; c++) {
426    out[(int)map->map[c]] = in[c];
427   }
428   in  += chans;
429   out += chans;
430  }
431 }
432
433 return 0;
434}
435
436int roardsp_chanmap_mappcm16(int16_t * out, int16_t * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
437 int16_t buf[ROAR_MAX_CHANNELS];
438 size_t frame;
439 size_t c;
440
441 if ( len == 0 )
442  return 0;
443
444 if ( out == NULL || in == NULL || map == NULL )
445  return -1;
446
447 if ( chans > ROAR_MAX_CHANNELS )
448  return -1;
449
450 if ( in == out ) {
451  for (frame = 0; frame < len/(chans*_16BIT); frame++) {
452   memset(buf, 0, sizeof(buf));
453
454   for (c = 0; c < chans; c++) {
455    buf[(int)map->map[c]] = in[c];
456   }
457
458   memcpy(out, buf, chans*_16BIT);
459
460   in  += chans;
461   out += chans;
462  }
463 } else {
464  memset(out, 0, len); // silance channels we do not use
465  for (frame = 0; frame < len/(chans*_16BIT); frame++) {
466   for (c = 0; c < chans; c++) {
467    out[(int)map->map[c]] = in[c];
468   }
469   in  += chans;
470   out += chans;
471  }
472 }
473
474 return 0;
475}
476
477int roardsp_chanmap_mappcm24(void    * out, void    * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
478 return -1;
479}
480
481int roardsp_chanmap_mappcm32(int32_t * out, int32_t * in, size_t len, size_t chans, struct roardsp_chanmap * map) {
482 int32_t buf[ROAR_MAX_CHANNELS];
483 size_t frame;
484 size_t c;
485
486 if ( len == 0 )
487  return 0;
488
489 if ( out == NULL || in == NULL || map == NULL )
490  return -1;
491
492 if ( chans > ROAR_MAX_CHANNELS )
493  return -1;
494
495 if ( in == out ) {
496  for (frame = 0; frame < len/(chans*_32BIT); frame++) {
497   memset(buf, 0, sizeof(buf));
498
499   for (c = 0; c < chans; c++) {
500    buf[(int)map->map[c]] = in[c];
501   }
502
503   memcpy(out, buf, chans*_32BIT);
504
505   in  += chans;
506   out += chans;
507  }
508 } else {
509  memset(out, 0, len); // silance channels we do not use
510  for (frame = 0; frame < len/(chans*_32BIT); frame++) {
511   for (c = 0; c < chans; c++) {
512    out[(int)map->map[c]] = in[c];
513   }
514   in  += chans;
515   out += chans;
516  }
517 }
518
519 return 0;
520}
521
522int roardsp_chanmap_mappcm  (void    * out, void    * in, size_t len, size_t chans, struct roardsp_chanmap * map, int bits) {
523 if ( len == 0 )
524  return 0;
525
526 if ( out == NULL || in == NULL || map == NULL )
527  return -1;
528
529 if ( chans > ROAR_MAX_CHANNELS )
530  return -1;
531
532#if 0
533 { int i;
534  printf("---- BEGIN MAP ----\n");
535  for (i = 0; i < chans; i++) {
536   printf("MAP: %i->%i\n", i, map[i]);
537  }
538  printf("---- END MAP ----\n");
539 }
540#endif
541
542 switch (bits) {
543  case  8: return roardsp_chanmap_mappcm8(out, in, len, chans, map);  break;
544  case 16: return roardsp_chanmap_mappcm16(out, in, len, chans, map); break;
545  case 24: return roardsp_chanmap_mappcm24(out, in, len, chans, map); break;
546  case 32: return roardsp_chanmap_mappcm32(out, in, len, chans, map); break;
547  default:
548    return -1;
549   break;
550 }
551}
552
553//ll
Note: See TracBrowser for help on using the repository browser.