|
61
|
1 /*
|
|
|
2 * Copyright (C) 2001 Haavard Kvaalen
|
|
|
3 *
|
|
|
4 * This program is free software; you can redistribute it and/or modify
|
|
|
5 * it under the terms of the GNU General Public License as published by
|
|
|
6 * the Free Software Foundation; either version 2 of the License, or
|
|
|
7 * (at your option) any later version.
|
|
|
8 *
|
|
|
9 * This program is distributed in the hope that it will be useful,
|
|
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
12 * GNU General Public License for more details.
|
|
|
13 *
|
|
|
14 * You should have received a copy of the GNU General Public License
|
|
|
15 * along with this program; if not, write to the Free Software
|
|
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
17 */
|
|
|
18
|
|
|
19 #include "OSS.h"
|
|
|
20
|
|
|
21 struct buffer {
|
|
|
22 void *buffer;
|
|
|
23 int size;
|
|
|
24 } format_buffer, stereo_buffer;
|
|
|
25
|
|
|
26
|
|
|
27 static void *
|
|
|
28 oss_get_convert_buffer(struct buffer *buffer, size_t size)
|
|
|
29 {
|
|
|
30 if (size > 0 && size <= buffer->size)
|
|
|
31 return buffer->buffer;
|
|
|
32
|
|
|
33 buffer->size = size;
|
|
|
34 buffer->buffer = g_realloc(buffer->buffer, size);
|
|
|
35 return buffer->buffer;
|
|
|
36 }
|
|
|
37
|
|
|
38 void
|
|
|
39 oss_free_convert_buffer(void)
|
|
|
40 {
|
|
|
41 oss_get_convert_buffer(&format_buffer, 0);
|
|
|
42 oss_get_convert_buffer(&stereo_buffer, 0);
|
|
|
43 }
|
|
|
44
|
|
|
45
|
|
|
46 static int
|
|
|
47 convert_swap_endian(void **data, int length)
|
|
|
48 {
|
|
|
49 guint16 *ptr = *data;
|
|
|
50 int i;
|
|
|
51 for (i = 0; i < length; i += 2, ptr++)
|
|
|
52 *ptr = GUINT16_SWAP_LE_BE(*ptr);
|
|
|
53
|
|
|
54 return i;
|
|
|
55 }
|
|
|
56
|
|
|
57 static int
|
|
|
58 convert_swap_sign_and_endian_to_native(void **data, int length)
|
|
|
59 {
|
|
|
60 guint16 *ptr = *data;
|
|
|
61 int i;
|
|
|
62 for (i = 0; i < length; i += 2, ptr++)
|
|
|
63 *ptr = GUINT16_SWAP_LE_BE(*ptr) ^ 1 << 15;
|
|
|
64
|
|
|
65 return i;
|
|
|
66 }
|
|
|
67
|
|
|
68 static int
|
|
|
69 convert_swap_sign_and_endian_to_alien(void **data, int length)
|
|
|
70 {
|
|
|
71 guint16 *ptr = *data;
|
|
|
72 int i;
|
|
|
73 for (i = 0; i < length; i += 2, ptr++)
|
|
|
74 *ptr = GUINT16_SWAP_LE_BE(*ptr ^ 1 << 15);
|
|
|
75
|
|
|
76 return i;
|
|
|
77 }
|
|
|
78
|
|
|
79 static int
|
|
|
80 convert_swap_sign16(void **data, int length)
|
|
|
81 {
|
|
|
82 gint16 *ptr = *data;
|
|
|
83 int i;
|
|
|
84 for (i = 0; i < length; i += 2, ptr++)
|
|
|
85 *ptr ^= 1 << 15;
|
|
|
86
|
|
|
87 return i;
|
|
|
88 }
|
|
|
89
|
|
|
90 static int
|
|
|
91 convert_swap_sign8(void **data, int length)
|
|
|
92 {
|
|
|
93 gint8 *ptr = *data;
|
|
|
94 int i;
|
|
|
95 for (i = 0; i < length; i++)
|
|
|
96 *ptr++ ^= 1 << 7;
|
|
|
97
|
|
|
98 return i;
|
|
|
99 }
|
|
|
100
|
|
|
101 static int
|
|
|
102 convert_to_8_native_endian(void **data, int length)
|
|
|
103 {
|
|
|
104 gint8 *output = *data;
|
|
|
105 gint16 *input = *data;
|
|
|
106 int i;
|
|
|
107 for (i = 0; i < length / 2; i++)
|
|
|
108 *output++ = *input++ >> 8;
|
|
|
109
|
|
|
110 return i;
|
|
|
111 }
|
|
|
112
|
|
|
113 static int
|
|
|
114 convert_to_8_native_endian_swap_sign(void **data, int length)
|
|
|
115 {
|
|
|
116 gint8 *output = *data;
|
|
|
117 gint16 *input = *data;
|
|
|
118 int i;
|
|
|
119 for (i = 0; i < length / 2; i++)
|
|
|
120 *output++ = (*input++ >> 8) ^ (1 << 7);
|
|
|
121
|
|
|
122 return i;
|
|
|
123 }
|
|
|
124
|
|
|
125
|
|
|
126 static int
|
|
|
127 convert_to_8_alien_endian(void **data, int length)
|
|
|
128 {
|
|
|
129 gint8 *output = *data;
|
|
|
130 gint16 *input = *data;
|
|
|
131 int i;
|
|
|
132 for (i = 0; i < length / 2; i++)
|
|
|
133 *output++ = *input++ & 0xff;
|
|
|
134
|
|
|
135 return i;
|
|
|
136 }
|
|
|
137
|
|
|
138 static int
|
|
|
139 convert_to_8_alien_endian_swap_sign(void **data, int length)
|
|
|
140 {
|
|
|
141 gint8 *output = *data;
|
|
|
142 gint16 *input = *data;
|
|
|
143 int i;
|
|
|
144 for (i = 0; i < length / 2; i++)
|
|
|
145 *output++ = (*input++ & 0xff) ^ (1 << 7);
|
|
|
146
|
|
|
147 return i;
|
|
|
148 }
|
|
|
149
|
|
|
150 static int
|
|
|
151 convert_to_16_native_endian(void **data, int length)
|
|
|
152 {
|
|
|
153 guint8 *input = *data;
|
|
|
154 guint16 *output;
|
|
|
155 int i;
|
|
|
156 *data = oss_get_convert_buffer(&format_buffer, length * 2);
|
|
|
157 output = *data;
|
|
|
158 for (i = 0; i < length; i++)
|
|
|
159 *output++ = *input++ << 8;
|
|
|
160
|
|
|
161 return i * 2;
|
|
|
162 }
|
|
|
163
|
|
|
164 static int
|
|
|
165 convert_to_16_native_endian_swap_sign(void **data, int length)
|
|
|
166 {
|
|
|
167 guint8 *input = *data;
|
|
|
168 guint16 *output;
|
|
|
169 int i;
|
|
|
170 *data = oss_get_convert_buffer(&format_buffer, length * 2);
|
|
|
171 output = *data;
|
|
|
172 for (i = 0; i < length; i++)
|
|
|
173 *output++ = (*input++ << 8) ^ (1 << 15);
|
|
|
174
|
|
|
175 return i * 2;
|
|
|
176 }
|
|
|
177
|
|
|
178
|
|
|
179 static int
|
|
|
180 convert_to_16_alien_endian(void **data, int length)
|
|
|
181 {
|
|
|
182 guint8 *input = *data;
|
|
|
183 guint16 *output;
|
|
|
184 int i;
|
|
|
185 *data = oss_get_convert_buffer(&format_buffer, length * 2);
|
|
|
186 output = *data;
|
|
|
187 for (i = 0; i < length; i++)
|
|
|
188 *output++ = *input++;
|
|
|
189
|
|
|
190 return i * 2;
|
|
|
191 }
|
|
|
192
|
|
|
193 static int
|
|
|
194 convert_to_16_alien_endian_swap_sign(void **data, int length)
|
|
|
195 {
|
|
|
196 guint8 *input = *data;
|
|
|
197 guint16 *output;
|
|
|
198 int i;
|
|
|
199 *data = oss_get_convert_buffer(&format_buffer, length * 2);
|
|
|
200 output = *data;
|
|
|
201 for (i = 0; i < length; i++)
|
|
|
202 *output++ = *input++ ^ (1 << 7);
|
|
|
203
|
|
|
204 return i * 2;
|
|
|
205 }
|
|
|
206
|
|
|
207 int (*oss_get_convert_func(int output, int input)) (void **, int) {
|
|
|
208 if (output == input)
|
|
|
209 return NULL;
|
|
|
210
|
|
|
211 if ((output == AFMT_U16_BE && input == AFMT_U16_LE) ||
|
|
|
212 (output == AFMT_U16_LE && input == AFMT_U16_BE) ||
|
|
|
213 (output == AFMT_S16_BE && input == AFMT_S16_LE) ||
|
|
|
214 (output == AFMT_S16_LE && input == AFMT_S16_BE))
|
|
|
215 return convert_swap_endian;
|
|
|
216
|
|
|
217 if ((output == AFMT_U16_BE && input == AFMT_S16_BE) ||
|
|
|
218 (output == AFMT_U16_LE && input == AFMT_S16_LE) ||
|
|
|
219 (output == AFMT_S16_BE && input == AFMT_U16_BE) ||
|
|
|
220 (output == AFMT_S16_LE && input == AFMT_U16_LE))
|
|
|
221 return convert_swap_sign16;
|
|
|
222
|
|
|
223 if ((IS_BIG_ENDIAN &&
|
|
|
224 ((output == AFMT_U16_BE && input == AFMT_S16_LE) ||
|
|
|
225 (output == AFMT_S16_BE && input == AFMT_U16_LE))) ||
|
|
|
226 (!IS_BIG_ENDIAN &&
|
|
|
227 ((output == AFMT_U16_LE && input == AFMT_S16_BE) ||
|
|
|
228 (output == AFMT_S16_LE && input == AFMT_U16_BE))))
|
|
|
229 return convert_swap_sign_and_endian_to_native;
|
|
|
230
|
|
|
231 if ((!IS_BIG_ENDIAN &&
|
|
|
232 ((output == AFMT_U16_BE && input == AFMT_S16_LE) ||
|
|
|
233 (output == AFMT_S16_BE && input == AFMT_U16_LE))) ||
|
|
|
234 (IS_BIG_ENDIAN &&
|
|
|
235 ((output == AFMT_U16_LE && input == AFMT_S16_BE) ||
|
|
|
236 (output == AFMT_S16_LE && input == AFMT_U16_BE))))
|
|
|
237 return convert_swap_sign_and_endian_to_alien;
|
|
|
238
|
|
|
239 if ((IS_BIG_ENDIAN &&
|
|
|
240 ((output == AFMT_U8 && input == AFMT_U16_BE) ||
|
|
|
241 (output == AFMT_S8 && input == AFMT_S16_BE))) ||
|
|
|
242 (!IS_BIG_ENDIAN &&
|
|
|
243 ((output == AFMT_U8 && input == AFMT_U16_LE) ||
|
|
|
244 (output == AFMT_S8 && input == AFMT_S16_LE))))
|
|
|
245 return convert_to_8_native_endian;
|
|
|
246
|
|
|
247 if ((IS_BIG_ENDIAN &&
|
|
|
248 ((output == AFMT_U8 && input == AFMT_S16_BE) ||
|
|
|
249 (output == AFMT_S8 && input == AFMT_U16_BE))) ||
|
|
|
250 (!IS_BIG_ENDIAN &&
|
|
|
251 ((output == AFMT_U8 && input == AFMT_S16_LE) ||
|
|
|
252 (output == AFMT_S8 && input == AFMT_U16_LE))))
|
|
|
253 return convert_to_8_native_endian_swap_sign;
|
|
|
254
|
|
|
255 if ((!IS_BIG_ENDIAN &&
|
|
|
256 ((output == AFMT_U8 && input == AFMT_U16_BE) ||
|
|
|
257 (output == AFMT_S8 && input == AFMT_S16_BE))) ||
|
|
|
258 (IS_BIG_ENDIAN &&
|
|
|
259 ((output == AFMT_U8 && input == AFMT_U16_LE) ||
|
|
|
260 (output == AFMT_S8 && input == AFMT_S16_LE))))
|
|
|
261 return convert_to_8_alien_endian;
|
|
|
262
|
|
|
263 if ((!IS_BIG_ENDIAN &&
|
|
|
264 ((output == AFMT_U8 && input == AFMT_S16_BE) ||
|
|
|
265 (output == AFMT_S8 && input == AFMT_U16_BE))) ||
|
|
|
266 (IS_BIG_ENDIAN &&
|
|
|
267 ((output == AFMT_U8 && input == AFMT_S16_LE) ||
|
|
|
268 (output == AFMT_S8 && input == AFMT_U16_LE))))
|
|
|
269 return convert_to_8_alien_endian_swap_sign;
|
|
|
270
|
|
|
271 if ((output == AFMT_U8 && input == AFMT_S8) ||
|
|
|
272 (output == AFMT_S8 && input == AFMT_U8))
|
|
|
273 return convert_swap_sign8;
|
|
|
274
|
|
|
275 if ((IS_BIG_ENDIAN &&
|
|
|
276 ((output == AFMT_U16_BE && input == AFMT_U8) ||
|
|
|
277 (output == AFMT_S16_BE && input == AFMT_S8))) ||
|
|
|
278 (!IS_BIG_ENDIAN &&
|
|
|
279 ((output == AFMT_U16_LE && input == AFMT_U8) ||
|
|
|
280 (output == AFMT_S16_LE && input == AFMT_S8))))
|
|
|
281 return convert_to_16_native_endian;
|
|
|
282
|
|
|
283 if ((IS_BIG_ENDIAN &&
|
|
|
284 ((output == AFMT_U16_BE && input == AFMT_S8) ||
|
|
|
285 (output == AFMT_S16_BE && input == AFMT_U8))) ||
|
|
|
286 (!IS_BIG_ENDIAN &&
|
|
|
287 ((output == AFMT_U16_LE && input == AFMT_S8) ||
|
|
|
288 (output == AFMT_S16_LE && input == AFMT_U8))))
|
|
|
289 return convert_to_16_native_endian_swap_sign;
|
|
|
290
|
|
|
291 if ((!IS_BIG_ENDIAN &&
|
|
|
292 ((output == AFMT_U16_BE && input == AFMT_U8) ||
|
|
|
293 (output == AFMT_S16_BE && input == AFMT_S8))) ||
|
|
|
294 (IS_BIG_ENDIAN &&
|
|
|
295 ((output == AFMT_U16_LE && input == AFMT_U8) ||
|
|
|
296 (output == AFMT_S16_LE && input == AFMT_S8))))
|
|
|
297 return convert_to_16_alien_endian;
|
|
|
298
|
|
|
299 if ((!IS_BIG_ENDIAN &&
|
|
|
300 ((output == AFMT_U16_BE && input == AFMT_S8) ||
|
|
|
301 (output == AFMT_S16_BE && input == AFMT_U8))) ||
|
|
|
302 (IS_BIG_ENDIAN &&
|
|
|
303 ((output == AFMT_U16_LE && input == AFMT_S8) ||
|
|
|
304 (output == AFMT_S16_LE && input == AFMT_U8))))
|
|
|
305 return convert_to_16_alien_endian_swap_sign;
|
|
|
306
|
|
|
307 g_warning("Translation needed, but not available.\n"
|
|
|
308 "Input: %d; Output %d.", input, output);
|
|
|
309 return NULL;
|
|
|
310 }
|
|
|
311
|
|
|
312 static int
|
|
|
313 convert_mono_to_stereo(void **data, int length, int fmt)
|
|
|
314 {
|
|
|
315 int i;
|
|
|
316 void *outbuf = oss_get_convert_buffer(&stereo_buffer, length * 2);
|
|
|
317
|
|
|
318 if (fmt == AFMT_U8 || fmt == AFMT_S8) {
|
|
|
319 guint8 *output = outbuf, *input = *data;
|
|
|
320 for (i = 0; i < length; i++) {
|
|
|
321 *output++ = *input;
|
|
|
322 *output++ = *input;
|
|
|
323 input++;
|
|
|
324 }
|
|
|
325 }
|
|
|
326 else {
|
|
|
327 guint16 *output = outbuf, *input = *data;
|
|
|
328 for (i = 0; i < length / 2; i++) {
|
|
|
329 *output++ = *input;
|
|
|
330 *output++ = *input;
|
|
|
331 input++;
|
|
|
332 }
|
|
|
333 }
|
|
|
334 *data = outbuf;
|
|
|
335
|
|
|
336 return length * 2;
|
|
|
337 }
|
|
|
338
|
|
|
339 static int
|
|
|
340 convert_stereo_to_mono(void **data, int length, int fmt)
|
|
|
341 {
|
|
|
342 int i;
|
|
|
343
|
|
|
344 switch (fmt) {
|
|
|
345 case AFMT_U8:
|
|
|
346 {
|
|
|
347 guint8 *output = *data, *input = *data;
|
|
|
348 for (i = 0; i < length / 2; i++) {
|
|
|
349 guint16 tmp;
|
|
|
350 tmp = *input++;
|
|
|
351 tmp += *input++;
|
|
|
352 *output++ = tmp / 2;
|
|
|
353 }
|
|
|
354 }
|
|
|
355 break;
|
|
|
356 case AFMT_S8:
|
|
|
357 {
|
|
|
358 gint8 *output = *data, *input = *data;
|
|
|
359 for (i = 0; i < length / 2; i++) {
|
|
|
360 gint16 tmp;
|
|
|
361 tmp = *input++;
|
|
|
362 tmp += *input++;
|
|
|
363 *output++ = tmp / 2;
|
|
|
364 }
|
|
|
365 }
|
|
|
366 break;
|
|
|
367 case AFMT_U16_LE:
|
|
|
368 {
|
|
|
369 guint16 *output = *data, *input = *data;
|
|
|
370 for (i = 0; i < length / 4; i++) {
|
|
|
371 guint32 tmp;
|
|
|
372 guint16 stmp;
|
|
|
373 tmp = GUINT16_FROM_LE(*input);
|
|
|
374 input++;
|
|
|
375 tmp += GUINT16_FROM_LE(*input);
|
|
|
376 input++;
|
|
|
377 stmp = tmp / 2;
|
|
|
378 *output++ = GUINT16_TO_LE(stmp);
|
|
|
379 }
|
|
|
380 }
|
|
|
381 break;
|
|
|
382 case AFMT_U16_BE:
|
|
|
383 {
|
|
|
384 guint16 *output = *data, *input = *data;
|
|
|
385 for (i = 0; i < length / 4; i++) {
|
|
|
386 guint32 tmp;
|
|
|
387 guint16 stmp;
|
|
|
388 tmp = GUINT16_FROM_BE(*input);
|
|
|
389 input++;
|
|
|
390 tmp += GUINT16_FROM_BE(*input);
|
|
|
391 input++;
|
|
|
392 stmp = tmp / 2;
|
|
|
393 *output++ = GUINT16_TO_BE(stmp);
|
|
|
394 }
|
|
|
395 }
|
|
|
396 break;
|
|
|
397 case AFMT_S16_LE:
|
|
|
398 {
|
|
|
399 gint16 *output = *data, *input = *data;
|
|
|
400 for (i = 0; i < length / 4; i++) {
|
|
|
401 gint32 tmp;
|
|
|
402 gint16 stmp;
|
|
|
403 tmp = GINT16_FROM_LE(*input);
|
|
|
404 input++;
|
|
|
405 tmp += GINT16_FROM_LE(*input);
|
|
|
406 input++;
|
|
|
407 stmp = tmp / 2;
|
|
|
408 *output++ = GINT16_TO_LE(stmp);
|
|
|
409 }
|
|
|
410 }
|
|
|
411 break;
|
|
|
412 case AFMT_S16_BE:
|
|
|
413 {
|
|
|
414 gint16 *output = *data, *input = *data;
|
|
|
415 for (i = 0; i < length / 4; i++) {
|
|
|
416 gint32 tmp;
|
|
|
417 gint16 stmp;
|
|
|
418 tmp = GINT16_FROM_BE(*input);
|
|
|
419 input++;
|
|
|
420 tmp += GINT16_FROM_BE(*input);
|
|
|
421 input++;
|
|
|
422 stmp = tmp / 2;
|
|
|
423 *output++ = GINT16_TO_BE(stmp);
|
|
|
424 }
|
|
|
425 }
|
|
|
426 break;
|
|
|
427 default:
|
|
|
428 g_error("unknown format");
|
|
|
429 }
|
|
|
430
|
|
|
431 return length / 2;
|
|
|
432 }
|
|
|
433
|
|
|
434 int (*oss_get_stereo_convert_func(int output, int input)) (void **, int, int) {
|
|
|
435 if (output == input)
|
|
|
436 return NULL;
|
|
|
437
|
|
|
438 if (input == 1 && output == 2)
|
|
|
439 return convert_mono_to_stereo;
|
|
|
440 if (input == 2 && output == 1)
|
|
|
441 return convert_stereo_to_mono;
|
|
|
442
|
|
|
443 g_warning("Input has %d channels, soundcard uses %d channels\n"
|
|
|
444 "No conversion is available", input, output);
|
|
|
445 return NULL;
|
|
|
446 }
|