comparison Plugins/Output/OSS/convert.c @ 61:fa848bd484d8 trunk

[svn] Move plugins to Plugins/
author nenolod
date Fri, 28 Oct 2005 22:58:11 -0700
parents
children d539e5c5f730
comparison
equal deleted inserted replaced
60:1771f253e1b2 61:fa848bd484d8
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 }