1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <stdlib.h>
28 #include <memory.h>
29 #include <math.h>
30 #include <AudioTypePcm.h>
31 #include <libaudio.h>
32
33 #define irint(d) ((int)d)
34
35 // class AudioTypePcm methods
36
37
38 // Constructor
39 AudioTypePcm::
AudioTypePcm()40 AudioTypePcm()
41 {
42 // Set up fixed header values; the rest are negotiable
43 hdr.Clear();
44 hdr.samples_per_unit = 1;
45 hdr.encoding = LINEAR;
46 }
47
48 // Test conversion possibilities.
49 // Return TRUE if conversion to/from the specified type is possible.
50 Boolean AudioTypePcm::
CanConvert(AudioHdr h) const51 CanConvert(
52 AudioHdr h) const // target header
53 {
54 if (h.samples_per_unit != 1)
55 return (FALSE);
56
57 switch (h.encoding) {
58 case LINEAR:
59 switch (h.bytes_per_unit) {
60 case 1: case 2: case 4:
61 break;
62 default:
63 return (FALSE);
64 }
65 break;
66 case FLOAT:
67 switch (h.bytes_per_unit) {
68 case 4: case 8:
69 break;
70 default:
71 return (FALSE);
72 }
73 break;
74 case ULAW:
75 case ALAW:
76 switch (h.bytes_per_unit) {
77 case 1:
78 break;
79 default:
80 return (FALSE);
81 }
82 break;
83 default:
84 return (FALSE);
85 }
86 return (TRUE);
87 }
88
89 // Clip most negative values and convert to floating-point
90 inline double AudioTypePcm::
char2dbl(char B)91 char2dbl(char B)
92 {
93 return ((unsigned char)B == 0x80 ? -1. : (double)B / 127.);
94 }
95 inline double AudioTypePcm::
short2dbl(short S)96 short2dbl(short S)
97 {
98 return ((unsigned short)S == 0x8000 ? -1. : (double)S / 32767.);
99 }
100 inline double AudioTypePcm::
long2dbl(long L)101 long2dbl(long L)
102 {
103 return ((unsigned long)L == 0x80000000 ? -1. : (double)L / 2147483647.);
104 }
105 // Convert floating-point to integer, scaled by the appropriate constant
106 inline long AudioTypePcm::
dbl2long(double D,long C)107 dbl2long(double D, long C)
108 {
109 return (D >= 1. ? C : D <= -1. ? -C : (long)irint(D * (double)C));
110 }
111
112 // Simple type conversions
113 inline void AudioTypePcm::
char2short(char * & F,short * & T)114 char2short(char *&F, short *&T) { *T++ = ((short)*F++) << 8; }
115 inline void AudioTypePcm::
char2long(char * & F,long * & T)116 char2long(char *&F, long *&T) { *T++ = ((long)*F++) << 24; }
117 inline void AudioTypePcm::
char2float(char * & F,float * & T)118 char2float(char *&F, float *&T) { *T++ = char2dbl(*F++); }
119 inline void AudioTypePcm::
char2double(char * & F,double * & T)120 char2double(char *&F, double *&T) { *T++ = char2dbl(*F++); }
121 inline void AudioTypePcm::
char2ulaw(char * & F,ulaw * & T)122 char2ulaw(char *&F, ulaw *&T) { *T++ = audio_c2u(*F); F++; }
123 inline void AudioTypePcm::
char2alaw(char * & F,alaw * & T)124 char2alaw(char *&F, alaw *&T) { *T++ = audio_c2a(*F); F++; }
125
126 inline void AudioTypePcm::
short2char(short * & F,char * & T)127 short2char(short *&F, char *&T) { *T++ = (char)(*F++ >> 8); }
128 inline void AudioTypePcm::
short2long(short * & F,long * & T)129 short2long(short *&F, long *&T) { *T++ = ((long)*F++) << 16; }
130 inline void AudioTypePcm::
short2float(short * & F,float * & T)131 short2float(short *&F, float *&T) { *T++ = short2dbl(*F++); }
132 inline void AudioTypePcm::
short2double(short * & F,double * & T)133 short2double(short *&F, double *&T) { *T++ = short2dbl(*F++); }
134 inline void AudioTypePcm::
short2ulaw(short * & F,ulaw * & T)135 short2ulaw(short *&F, ulaw *&T) { *T++ = audio_s2u(*F); F++; }
136 inline void AudioTypePcm::
short2alaw(short * & F,alaw * & T)137 short2alaw(short *&F, alaw *&T) { *T++ = audio_s2a(*F); F++; }
138
139 inline void AudioTypePcm::
long2char(long * & F,char * & T)140 long2char(long *&F, char *&T) { *T++ = (char)(*F++ >> 24); }
141 inline void AudioTypePcm::
long2short(long * & F,short * & T)142 long2short(long *&F, short *&T) { *T++ = (short)(*F++ >> 16); }
143 inline void AudioTypePcm::
long2float(long * & F,float * & T)144 long2float(long *&F, float *&T) { *T++ = long2dbl(*F++); }
145 inline void AudioTypePcm::
long2double(long * & F,double * & T)146 long2double(long *&F, double *&T) { *T++ = long2dbl(*F++); }
147 inline void AudioTypePcm::
long2ulaw(long * & F,ulaw * & T)148 long2ulaw(long *&F, ulaw *&T) { *T++ = audio_l2u(*F); F++; }
149 inline void AudioTypePcm::
long2alaw(long * & F,alaw * & T)150 long2alaw(long *&F, alaw *&T) { *T++ = audio_l2a(*F); F++; }
151
152 inline void AudioTypePcm::
float2char(float * & F,char * & T)153 float2char(float *&F, char *&T) { *T++ = (char)dbl2long(*F++, 127); }
154 inline void AudioTypePcm::
float2short(float * & F,short * & T)155 float2short(float *&F, short *&T) { *T++ = (short)dbl2long(*F++, 32767); }
156 inline void AudioTypePcm::
float2long(float * & F,long * & T)157 float2long(float *&F, long *&T) { *T++ = dbl2long(*F++, 2147483647); }
158 inline void AudioTypePcm::
float2double(float * & F,double * & T)159 float2double(float *&F, double *&T) { *T++ = *F++; }
160 inline void AudioTypePcm::
float2ulaw(float * & F,ulaw * & T)161 float2ulaw(float *&F, ulaw *&T) { *T++ = audio_s2u(dbl2long(*F++, 32767)); }
162 inline void AudioTypePcm::
float2alaw(float * & F,alaw * & T)163 float2alaw(float *&F, alaw *&T) { *T++ = audio_s2a(dbl2long(*F++, 32767)); }
164
165 inline void AudioTypePcm::
double2char(double * & F,char * & T)166 double2char(double *&F, char *&T) { *T++ = (char)dbl2long(*F++, 127); }
167 inline void AudioTypePcm::
double2short(double * & F,short * & T)168 double2short(double *&F, short *&T) { *T++ = (short)dbl2long(*F++, 32767); }
169 inline void AudioTypePcm::
double2long(double * & F,long * & T)170 double2long(double *&F, long *&T) { *T++ = dbl2long(*F++, 2147483647); }
171 inline void AudioTypePcm::
double2float(double * & F,float * & T)172 double2float(double *&F, float *&T) { *T++ = *F++; }
173 inline void AudioTypePcm::
double2ulaw(double * & F,ulaw * & T)174 double2ulaw(double *&F, ulaw *&T) { *T++ = audio_s2u(dbl2long(*F++, 32767)); }
175 inline void AudioTypePcm::
double2alaw(double * & F,alaw * & T)176 double2alaw(double *&F, alaw *&T) { *T++ = audio_s2a(dbl2long(*F++, 32767)); }
177
178 inline void AudioTypePcm::
ulaw2char(ulaw * & F,char * & T)179 ulaw2char(ulaw *&F, char *&T) { *T++ = audio_u2c(*F); F++; }
180 inline void AudioTypePcm::
ulaw2alaw(ulaw * & F,alaw * & T)181 ulaw2alaw(ulaw *&F, alaw *&T) { *T++ = audio_u2a(*F); F++; }
182 inline void AudioTypePcm::
ulaw2short(ulaw * & F,short * & T)183 ulaw2short(ulaw *&F, short *&T) { *T++ = audio_u2s(*F); F++; }
184 inline void AudioTypePcm::
ulaw2long(ulaw * & F,long * & T)185 ulaw2long(ulaw *&F, long *&T) { *T++ = audio_u2l(*F); F++; }
186 inline void AudioTypePcm::
ulaw2float(ulaw * & F,float * & T)187 ulaw2float(ulaw *&F, float *&T) { *T++ = short2dbl(audio_u2s(*F)); F++; }
188 inline void AudioTypePcm::
ulaw2double(ulaw * & F,double * & T)189 ulaw2double(ulaw *&F, double *&T) { *T++ = short2dbl(audio_u2s(*F)); F++; }
190
191 inline void AudioTypePcm::
alaw2char(alaw * & F,char * & T)192 alaw2char(alaw *&F, char *&T) { *T++ = audio_a2c(*F); F++; }
193 inline void AudioTypePcm::
alaw2short(alaw * & F,short * & T)194 alaw2short(alaw *&F, short *&T) { *T++ = audio_a2s(*F); F++; }
195 inline void AudioTypePcm::
alaw2long(alaw * & F,long * & T)196 alaw2long(alaw *&F, long *&T) { *T++ = audio_a2l(*F); F++; }
197 inline void AudioTypePcm::
alaw2float(alaw * & F,float * & T)198 alaw2float(alaw *&F, float *&T) { *T++ = short2dbl(audio_a2s(*F)); F++; }
199 inline void AudioTypePcm::
alaw2double(alaw * & F,double * & T)200 alaw2double(alaw *&F, double *&T) { *T++ = short2dbl(audio_a2s(*F)); F++; }
201 inline void AudioTypePcm::
alaw2ulaw(alaw * & F,ulaw * & T)202 alaw2ulaw(alaw*& F, ulaw*& T) { *T++ = audio_a2u(*F); F++; }
203
204
205 // Convert buffer to the specified type
206 // May replace the buffer with a new one, if necessary
207 AudioError AudioTypePcm::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)208 Convert(
209 AudioBuffer*& inbuf, // data buffer to process
210 AudioHdr outhdr) // target header
211 {
212 AudioBuffer* outbuf;
213 AudioHdr inhdr;
214 Double length;
215 size_t frames;
216 void* inptr;
217 void* outptr;
218 AudioError err;
219
220 inhdr = inbuf->GetHeader();
221 length = inbuf->GetLength();
222
223 if (Undefined(length))
224 return (AUDIO_ERR_BADARG);
225
226 // Make sure we're not being asked to do the impossible
227 // XXX - how do we deal with multi-channel data??
228 // XXX - need a better error code
229 if ((err = inhdr.Validate()) || (err = outhdr.Validate()))
230 return (err);
231 if ((inhdr.sample_rate != outhdr.sample_rate) ||
232 (inhdr.samples_per_unit != outhdr.samples_per_unit) ||
233 (inhdr.samples_per_unit != 1) ||
234 (inhdr.channels != outhdr.channels))
235 return (AUDIO_ERR_HDRINVAL);
236
237 // If the buffer is not referenced, and the target size is no bigger
238 // than the current size, the conversion can be done in place
239 if (!inbuf->isReferenced() &&
240 (outhdr.bytes_per_unit <= inhdr.bytes_per_unit)) {
241 outbuf = inbuf;
242 } else {
243 // Allocate a new buffer
244 outbuf = new AudioBuffer(length, "(PCM conversion buffer)");
245 if (outbuf == 0)
246 return (AUDIO_UNIXERROR);
247 if (err = outbuf->SetHeader(outhdr)) {
248 delete outbuf;
249 return (err);
250 }
251 }
252
253 // Convert from the input type to the output type
254 inptr = inbuf->GetAddress();
255 outptr = outbuf->GetAddress();
256 frames = (size_t)inhdr.Time_to_Samples(length)
257 * inhdr.channels;
258
259 // Define macro to copy with no data conversion
260 #define COPY(N) if (inptr != outptr) memcpy(outptr, inptr, frames * N)
261 // Define macro to translate a buffer
262 // XXX - The temporary pointers are necessary to get the updates
263
264 // token catenation different for ANSI cpp v.s. old cpp.
265 #ifdef __STDC__
266 #define MOVE(F, T) { \
267 F* ip = (F*)inptr; T* op = (T*)outptr; \
268 while (frames-- > 0) F ## 2 ## T(ip, op); \
269 }
270 #else
271 #define MOVE(F, T) { \
272 F* ip = (F*)inptr; T* op = (T*)outptr; \
273 while (frames-- > 0) F /* */ 2 /* */ T(ip, op);\
274 }
275 #endif
276 switch (inhdr.encoding) {
277 case LINEAR:
278 switch (outhdr.encoding) {
279 case LINEAR: // Convert linear to linear
280 switch (inhdr.bytes_per_unit) {
281 case 1:
282 switch (outhdr.bytes_per_unit) {
283 case 1: COPY(1); break;
284 case 2: MOVE(char, short); break;
285 case 4: MOVE(char, long); break;
286 default: err = AUDIO_ERR_HDRINVAL; break;
287 }
288 break;
289 case 2:
290 switch (outhdr.bytes_per_unit) {
291 case 1: MOVE(short, char); break;
292 case 2: COPY(2); break;
293 case 4: MOVE(short, long); break;
294 default: err = AUDIO_ERR_HDRINVAL; break;
295 }
296 break;
297 case 4:
298 switch (outhdr.bytes_per_unit) {
299 case 1: MOVE(long, char); break;
300 case 2: MOVE(long, short); break;
301 case 4: COPY(4); break;
302 default: err = AUDIO_ERR_HDRINVAL; break;
303 }
304 break;
305 default:
306 err = AUDIO_ERR_HDRINVAL; break;
307 }
308 break;
309 case FLOAT: // Convert linear to float
310 switch (inhdr.bytes_per_unit) {
311 case 1:
312 switch (outhdr.bytes_per_unit) {
313 case 4: MOVE(char, float); break;
314 case 8: MOVE(char, double); break;
315 default: err = AUDIO_ERR_HDRINVAL; break;
316 }
317 break;
318 case 2:
319 switch (outhdr.bytes_per_unit) {
320 case 4: MOVE(short, float); break;
321 case 8: MOVE(short, double); break;
322 default: err = AUDIO_ERR_HDRINVAL; break;
323 }
324 break;
325 case 4:
326 switch (outhdr.bytes_per_unit) {
327 case 4: MOVE(long, float); break;
328 case 8: MOVE(long, double); break;
329 default: err = AUDIO_ERR_HDRINVAL; break;
330 }
331 break;
332 default:
333 err = AUDIO_ERR_HDRINVAL; break;
334 }
335 break;
336 case ULAW: // Convert linear to u-law
337 switch (inhdr.bytes_per_unit) {
338 case 1: MOVE(char, ulaw); break;
339 case 2: MOVE(short, ulaw); break;
340 case 4: MOVE(long, ulaw); break;
341 default: err = AUDIO_ERR_HDRINVAL; break;
342 }
343 break;
344 case ALAW: // Convert linear to a-law
345 switch (inhdr.bytes_per_unit) {
346 case 1: MOVE(char, alaw); break;
347 case 2: MOVE(short, alaw); break;
348 case 4: MOVE(long, alaw); break;
349 default: err = AUDIO_ERR_HDRINVAL; break;
350 }
351 break;
352 default:
353 err = AUDIO_ERR_HDRINVAL; break;
354 }
355 break;
356 case FLOAT:
357 switch (outhdr.encoding) {
358 case LINEAR: // Convert float to linear
359 switch (inhdr.bytes_per_unit) {
360 case 4:
361 switch (outhdr.bytes_per_unit) {
362 case 1: MOVE(float, char); break;
363 case 2: MOVE(float, short); break;
364 case 4: MOVE(float, long); break;
365 default: err = AUDIO_ERR_HDRINVAL; break;
366 }
367 break;
368 case 8:
369 switch (outhdr.bytes_per_unit) {
370 case 1: MOVE(double, char); break;
371 case 2: MOVE(double, short); break;
372 case 4: MOVE(double, long); break;
373 default: err = AUDIO_ERR_HDRINVAL; break;
374 }
375 break;
376 default:
377 err = AUDIO_ERR_HDRINVAL; break;
378 }
379 break;
380 case FLOAT: // Convert float to float
381 switch (inhdr.bytes_per_unit) {
382 case 4:
383 switch (outhdr.bytes_per_unit) {
384 case 4: COPY(4); break;
385 case 8: MOVE(float, double); break;
386 default: err = AUDIO_ERR_HDRINVAL; break;
387 }
388 break;
389 case 8:
390 switch (outhdr.bytes_per_unit) {
391 case 4: MOVE(double, float); break;
392 case 8: COPY(8); break;
393 default: err = AUDIO_ERR_HDRINVAL; break;
394 }
395 break;
396 default:
397 err = AUDIO_ERR_HDRINVAL; break;
398 }
399 break;
400 case ULAW: // Convert float to u-law
401 switch (inhdr.bytes_per_unit) {
402 case 4: MOVE(float, ulaw); break;
403 case 8: MOVE(double, ulaw); break;
404 default: err = AUDIO_ERR_HDRINVAL; break;
405 }
406 break;
407 case ALAW: // Convert float to a-law
408 switch (inhdr.bytes_per_unit) {
409 case 4: MOVE(float, alaw); break;
410 case 8: MOVE(double, alaw); break;
411 default: err = AUDIO_ERR_HDRINVAL; break;
412 }
413 break;
414 default:
415 err = AUDIO_ERR_HDRINVAL; break;
416 }
417 break;
418 case ULAW:
419 switch (outhdr.encoding) {
420 case LINEAR: // Convert ulaw to linear
421 switch (outhdr.bytes_per_unit) {
422 case 1: MOVE(ulaw, char); break;
423 case 2: MOVE(ulaw, short); break;
424 case 4: MOVE(ulaw, long); break;
425 default: err = AUDIO_ERR_HDRINVAL; break;
426 }
427 break;
428 case FLOAT: // Convert ulaw to float
429 switch (outhdr.bytes_per_unit) {
430 case 4: MOVE(ulaw, float); break;
431 case 8: MOVE(ulaw, double); break;
432 default: err = AUDIO_ERR_HDRINVAL; break;
433 }
434 break;
435 case ULAW: // Convert ulaw to u-law
436 COPY(1); break;
437 case ALAW: // Convert ulaw to a-law
438 MOVE(ulaw, alaw); break;
439 default:
440 err = AUDIO_ERR_HDRINVAL; break;
441 }
442 break;
443 case ALAW:
444 switch (outhdr.encoding) {
445 case LINEAR: // Convert alaw to linear
446 switch (outhdr.bytes_per_unit) {
447 case 1: MOVE(alaw, char); break;
448 case 2: MOVE(alaw, short); break;
449 case 4: MOVE(alaw, long); break;
450 default: err = AUDIO_ERR_HDRINVAL; break;
451 }
452 break;
453 case FLOAT: // Convert alaw to float
454 switch (outhdr.bytes_per_unit) {
455 case 4: MOVE(alaw, float); break;
456 case 8: MOVE(alaw, double); break;
457 default: err = AUDIO_ERR_HDRINVAL; break;
458 }
459 break;
460 case ALAW: // Convert alaw to a-law
461 COPY(1); break;
462 case ULAW: // Convert alaw to u-law
463 MOVE(alaw, ulaw); break;
464 default:
465 err = AUDIO_ERR_HDRINVAL; break;
466 }
467 break;
468 default:
469 err = AUDIO_ERR_HDRINVAL; break;
470 }
471 if (err) {
472 if (outbuf != inbuf)
473 delete outbuf;
474 return (err);
475 }
476
477 // Finish up
478 if (outbuf == inbuf) {
479 // If the conversion was in-place, set the new header
480 (void) inbuf->SetHeader(outhdr);
481 } else {
482 // This will delete the buffer
483 inbuf->Reference();
484 inbuf->Dereference();
485
486 // Set the valid data length and replace the pointer
487 outbuf->SetLength(length);
488 inbuf = outbuf;
489 }
490 return (AUDIO_SUCCESS);
491 }
492
493 AudioError AudioTypePcm::
Flush(AudioBuffer * &)494 Flush(
495 AudioBuffer*& /* buf */)
496 {
497 return (AUDIO_SUCCESS);
498 }
499