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