]> code.delx.au - pulseaudio/blob - src/pulse/channelmap.c
big s/polyp/pulse/g
[pulseaudio] / src / pulse / channelmap.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <pulse/xmalloc.h>
32 #include <pulsecore/core-util.h>
33
34 #include "channelmap.h"
35
36 const char *const table[] = {
37 [PA_CHANNEL_POSITION_MONO] = "mono",
38
39 [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center",
40 [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left",
41 [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right",
42
43 [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center",
44 [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left",
45 [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right",
46
47 [PA_CHANNEL_POSITION_LFE] = "lfe",
48
49 [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center",
50 [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center",
51
52 [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left",
53 [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right",
54
55 [PA_CHANNEL_POSITION_AUX0] = "aux0",
56 [PA_CHANNEL_POSITION_AUX1] = "aux1",
57 [PA_CHANNEL_POSITION_AUX2] = "aux2",
58 [PA_CHANNEL_POSITION_AUX3] = "aux3",
59 [PA_CHANNEL_POSITION_AUX4] = "aux4",
60 [PA_CHANNEL_POSITION_AUX5] = "aux5",
61 [PA_CHANNEL_POSITION_AUX6] = "aux6",
62 [PA_CHANNEL_POSITION_AUX7] = "aux7",
63 [PA_CHANNEL_POSITION_AUX8] = "aux8",
64 [PA_CHANNEL_POSITION_AUX9] = "aux9",
65 [PA_CHANNEL_POSITION_AUX10] = "aux10",
66 [PA_CHANNEL_POSITION_AUX11] = "aux11",
67 [PA_CHANNEL_POSITION_AUX12] = "aux12",
68 [PA_CHANNEL_POSITION_AUX13] = "aux13",
69 [PA_CHANNEL_POSITION_AUX14] = "aux14",
70 [PA_CHANNEL_POSITION_AUX15] = "aux15",
71
72 [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center",
73
74 [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left",
75 [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right",
76 [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center",
77
78 [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left",
79 [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right",
80 [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center"
81 };
82
83 pa_channel_map* pa_channel_map_init(pa_channel_map *m) {
84 unsigned c;
85 assert(m);
86
87 m->channels = 0;
88
89 for (c = 0; c < PA_CHANNELS_MAX; c++)
90 m->map[c] = PA_CHANNEL_POSITION_INVALID;
91
92 return m;
93 }
94
95 pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) {
96 assert(m);
97
98 pa_channel_map_init(m);
99
100 m->channels = 1;
101 m->map[0] = PA_CHANNEL_POSITION_MONO;
102 return m;
103 }
104
105 pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) {
106 assert(m);
107
108 pa_channel_map_init(m);
109
110 m->channels = 2;
111 m->map[0] = PA_CHANNEL_POSITION_LEFT;
112 m->map[1] = PA_CHANNEL_POSITION_RIGHT;
113 return m;
114 }
115
116 pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
117 assert(m);
118 assert(channels > 0);
119 assert(channels <= PA_CHANNELS_MAX);
120
121 pa_channel_map_init(m);
122
123 m->channels = channels;
124
125 switch (def) {
126 case PA_CHANNEL_MAP_AIFF:
127
128 /* This is somewhat compatible with RFC3551 */
129
130 switch (channels) {
131 case 1:
132 m->map[0] = PA_CHANNEL_POSITION_MONO;
133 return m;
134
135 case 6:
136 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
137 m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT;
138 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
139 m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT;
140 m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT;
141 m->map[5] = PA_CHANNEL_POSITION_LFE;
142 return m;
143
144 case 5:
145 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
146 m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT;
147 m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT;
148 /* Fall through */
149
150 case 2:
151 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
152 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
153 return m;
154
155 case 3:
156 m->map[0] = PA_CHANNEL_POSITION_LEFT;
157 m->map[1] = PA_CHANNEL_POSITION_RIGHT;
158 m->map[2] = PA_CHANNEL_POSITION_CENTER;
159 return m;
160
161 case 4:
162 m->map[0] = PA_CHANNEL_POSITION_LEFT;
163 m->map[1] = PA_CHANNEL_POSITION_CENTER;
164 m->map[2] = PA_CHANNEL_POSITION_RIGHT;
165 m->map[3] = PA_CHANNEL_POSITION_LFE;
166 return m;
167
168 default:
169 return NULL;
170 }
171
172 case PA_CHANNEL_MAP_ALSA:
173
174 switch (channels) {
175 case 1:
176 m->map[0] = PA_CHANNEL_POSITION_MONO;
177 return m;
178
179 case 8:
180 m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
181 m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
182 /* Fall through */
183
184 case 6:
185 m->map[5] = PA_CHANNEL_POSITION_LFE;
186 /* Fall through */
187
188 case 5:
189 m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
190 /* Fall through */
191
192 case 4:
193 m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
194 m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
195 /* Fall through */
196
197 case 2:
198 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
199 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
200 return m;
201
202 default:
203 return NULL;
204 }
205
206 case PA_CHANNEL_MAP_AUX: {
207 unsigned i;
208
209 if (channels >= PA_CHANNELS_MAX)
210 return NULL;
211
212 for (i = 0; i < channels; i++)
213 m->map[i] = PA_CHANNEL_POSITION_AUX0 + i;
214
215 return m;
216 }
217
218 case PA_CHANNEL_MAP_WAVEEX:
219
220 switch (channels) {
221 case 1:
222 m->map[0] = PA_CHANNEL_POSITION_MONO;
223 return m;
224
225 case 18:
226 m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
227 m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
228 m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
229 /* Fall through */
230
231 case 15:
232 m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
233 m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
234 m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
235 /* Fall through */
236
237 case 12:
238 m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER;
239 /* Fall through */
240
241 case 11:
242 m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT;
243 m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT;
244 /* Fall through */
245
246 case 9:
247 m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER;
248 /* Fall through */
249
250 case 8:
251 m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
252 m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
253 /* Fall through */
254
255 case 6:
256 m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
257 m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
258 /* Fall through */
259
260 case 4:
261 m->map[3] = PA_CHANNEL_POSITION_LFE;
262 /* Fall through */
263
264 case 3:
265 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
266 /* Fall through */
267
268 case 2:
269 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
270 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
271 return m;
272
273 default:
274 return NULL;
275 }
276
277 case PA_CHANNEL_MAP_OSS:
278
279 switch (channels) {
280 case 1:
281 m->map[0] = PA_CHANNEL_POSITION_MONO;
282 return m;
283
284 case 8:
285 m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
286 m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
287 /* Fall through */
288
289 case 6:
290 m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
291 m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
292 /* Fall through */
293
294 case 4:
295 m->map[3] = PA_CHANNEL_POSITION_LFE;
296 /* Fall through */
297
298 case 3:
299 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
300 /* Fall through */
301
302 case 2:
303 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
304 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
305 return m;
306
307 default:
308 return NULL;
309 }
310
311
312 default:
313 return NULL;
314 }
315 }
316
317
318 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
319
320 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
321 return NULL;
322
323 return table[pos];
324 }
325
326 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
327 unsigned c;
328
329 assert(a);
330 assert(b);
331
332 if (a->channels != b->channels)
333 return 0;
334
335 for (c = 0; c < a->channels; c++)
336 if (a->map[c] != b->map[c])
337 return 0;
338
339 return 1;
340 }
341
342 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
343 unsigned channel;
344 int first = 1;
345 char *e;
346
347 assert(s);
348 assert(l > 0);
349 assert(map);
350
351 *(e = s) = 0;
352
353 for (channel = 0; channel < map->channels && l > 1; channel++) {
354 l -= snprintf(e, l, "%s%s",
355 first ? "" : ",",
356 pa_channel_position_to_string(map->map[channel]));
357
358 e = strchr(e, 0);
359 first = 0;
360 }
361
362 return s;
363 }
364
365 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
366 const char *state;
367 pa_channel_map map;
368 char *p;
369
370 assert(rmap);
371 assert(s);
372
373 memset(&map, 0, sizeof(map));
374
375 if (strcmp(s, "stereo") == 0) {
376 map.channels = 2;
377 map.map[0] = PA_CHANNEL_POSITION_LEFT;
378 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
379 goto finish;
380 }
381
382 state = NULL;
383 map.channels = 0;
384
385 while ((p = pa_split(s, ",", &state))) {
386
387 if (map.channels >= PA_CHANNELS_MAX) {
388 pa_xfree(p);
389 return NULL;
390 }
391
392 /* Some special aliases */
393 if (strcmp(p, "left") == 0)
394 map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT;
395 else if (strcmp(p, "right") == 0)
396 map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT;
397 else if (strcmp(p, "center") == 0)
398 map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER;
399 else if (strcmp(p, "subwoofer") == 0)
400 map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER;
401 else {
402 pa_channel_position_t i;
403
404 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
405 if (strcmp(p, table[i]) == 0) {
406 map.map[map.channels++] = i;
407 break;
408 }
409
410 if (i >= PA_CHANNEL_POSITION_MAX) {
411 pa_xfree(p);
412 return NULL;
413 }
414 }
415
416 pa_xfree(p);
417 }
418
419 finish:
420
421 if (!pa_channel_map_valid(&map))
422 return NULL;
423
424 *rmap = map;
425 return rmap;
426 }
427
428 int pa_channel_map_valid(const pa_channel_map *map) {
429 unsigned c;
430
431 assert(map);
432
433 if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
434 return 0;
435
436 for (c = 0; c < map->channels; c++) {
437
438 if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX)
439 return 0;
440
441 }
442
443 return 1;
444 }
445