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 err = outbuf->SetHeader(outhdr);
248 if (err != AUDIO_SUCCESS) {
249 delete outbuf;
250 return (err);
251 }
252 }
253
254 // Convert from the input type to the output type
255 inptr = inbuf->GetAddress();
256 outptr = outbuf->GetAddress();
257 frames = (size_t)inhdr.Time_to_Samples(length)
258 * inhdr.channels;
259
260 // Define macro to copy with no data conversion
261 #define COPY(N) if (inptr != outptr) memcpy(outptr, inptr, frames * N)
262 // Define macro to translate a buffer
263 // XXX - The temporary pointers are necessary to get the updates
264
265 // token catenation different for ANSI cpp v.s. old cpp.
266 #ifdef __STDC__
267 #define MOVE(F, T) { \
268 F* ip = (F*)inptr; T* op = (T*)outptr; \
269 while (frames-- > 0) F ## 2 ## T(ip, op); \
270 }
271 #else
272 #define MOVE(F, T) { \
273 F* ip = (F*)inptr; T* op = (T*)outptr; \
274 while (frames-- > 0) F /* */ 2 /* */ T(ip, op);\
275 }
276 #endif
277 switch (inhdr.encoding) {
278 case LINEAR:
279 switch (outhdr.encoding) {
280 case LINEAR: // Convert linear to linear
281 switch (inhdr.bytes_per_unit) {
282 case 1:
283 switch (outhdr.bytes_per_unit) {
284 case 1: COPY(1); break;
285 case 2: MOVE(char, short); break;
286 case 4: MOVE(char, long); break;
287 default: err = AUDIO_ERR_HDRINVAL; break;
288 }
289 break;
290 case 2:
291 switch (outhdr.bytes_per_unit) {
292 case 1: MOVE(short, char); break;
293 case 2: COPY(2); break;
294 case 4: MOVE(short, long); break;
295 default: err = AUDIO_ERR_HDRINVAL; break;
296 }
297 break;
298 case 4:
299 switch (outhdr.bytes_per_unit) {
300 case 1: MOVE(long, char); break;
301 case 2: MOVE(long, short); break;
302 case 4: COPY(4); break;
303 default: err = AUDIO_ERR_HDRINVAL; break;
304 }
305 break;
306 default:
307 err = AUDIO_ERR_HDRINVAL; break;
308 }
309 break;
310 case FLOAT: // Convert linear to float
311 switch (inhdr.bytes_per_unit) {
312 case 1:
313 switch (outhdr.bytes_per_unit) {
314 case 4: MOVE(char, float); break;
315 case 8: MOVE(char, double); break;
316 default: err = AUDIO_ERR_HDRINVAL; break;
317 }
318 break;
319 case 2:
320 switch (outhdr.bytes_per_unit) {
321 case 4: MOVE(short, float); break;
322 case 8: MOVE(short, double); break;
323 default: err = AUDIO_ERR_HDRINVAL; break;
324 }
325 break;
326 case 4:
327 switch (outhdr.bytes_per_unit) {
328 case 4: MOVE(long, float); break;
329 case 8: MOVE(long, double); break;
330 default: err = AUDIO_ERR_HDRINVAL; break;
331 }
332 break;
333 default:
334 err = AUDIO_ERR_HDRINVAL; break;
335 }
336 break;
337 case ULAW: // Convert linear to u-law
338 switch (inhdr.bytes_per_unit) {
339 case 1: MOVE(char, ulaw); break;
340 case 2: MOVE(short, ulaw); break;
341 case 4: MOVE(long, ulaw); break;
342 default: err = AUDIO_ERR_HDRINVAL; break;
343 }
344 break;
345 case ALAW: // Convert linear to a-law
346 switch (inhdr.bytes_per_unit) {
347 case 1: MOVE(char, alaw); break;
348 case 2: MOVE(short, alaw); break;
349 case 4: MOVE(long, alaw); break;
350 default: err = AUDIO_ERR_HDRINVAL; break;
351 }
352 break;
353 default:
354 err = AUDIO_ERR_HDRINVAL; break;
355 }
356 break;
357 case FLOAT:
358 switch (outhdr.encoding) {
359 case LINEAR: // Convert float to linear
360 switch (inhdr.bytes_per_unit) {
361 case 4:
362 switch (outhdr.bytes_per_unit) {
363 case 1: MOVE(float, char); break;
364 case 2: MOVE(float, short); break;
365 case 4: MOVE(float, long); break;
366 default: err = AUDIO_ERR_HDRINVAL; break;
367 }
368 break;
369 case 8:
370 switch (outhdr.bytes_per_unit) {
371 case 1: MOVE(double, char); break;
372 case 2: MOVE(double, short); break;
373 case 4: MOVE(double, long); break;
374 default: err = AUDIO_ERR_HDRINVAL; break;
375 }
376 break;
377 default:
378 err = AUDIO_ERR_HDRINVAL; break;
379 }
380 break;
381 case FLOAT: // Convert float to float
382 switch (inhdr.bytes_per_unit) {
383 case 4:
384 switch (outhdr.bytes_per_unit) {
385 case 4: COPY(4); break;
386 case 8: MOVE(float, double); break;
387 default: err = AUDIO_ERR_HDRINVAL; break;
388 }
389 break;
390 case 8:
391 switch (outhdr.bytes_per_unit) {
392 case 4: MOVE(double, float); break;
393 case 8: COPY(8); break;
394 default: err = AUDIO_ERR_HDRINVAL; break;
395 }
396 break;
397 default:
398 err = AUDIO_ERR_HDRINVAL; break;
399 }
400 break;
401 case ULAW: // Convert float to u-law
402 switch (inhdr.bytes_per_unit) {
403 case 4: MOVE(float, ulaw); break;
404 case 8: MOVE(double, ulaw); break;
405 default: err = AUDIO_ERR_HDRINVAL; break;
406 }
407 break;
408 case ALAW: // Convert float to a-law
409 switch (inhdr.bytes_per_unit) {
410 case 4: MOVE(float, alaw); break;
411 case 8: MOVE(double, alaw); break;
412 default: err = AUDIO_ERR_HDRINVAL; break;
413 }
414 break;
415 default:
416 err = AUDIO_ERR_HDRINVAL; break;
417 }
418 break;
419 case ULAW:
420 switch (outhdr.encoding) {
421 case LINEAR: // Convert ulaw to linear
422 switch (outhdr.bytes_per_unit) {
423 case 1: MOVE(ulaw, char); break;
424 case 2: MOVE(ulaw, short); break;
425 case 4: MOVE(ulaw, long); break;
426 default: err = AUDIO_ERR_HDRINVAL; break;
427 }
428 break;
429 case FLOAT: // Convert ulaw to float
430 switch (outhdr.bytes_per_unit) {
431 case 4: MOVE(ulaw, float); break;
432 case 8: MOVE(ulaw, double); break;
433 default: err = AUDIO_ERR_HDRINVAL; break;
434 }
435 break;
436 case ULAW: // Convert ulaw to u-law
437 COPY(1); break;
438 case ALAW: // Convert ulaw to a-law
439 MOVE(ulaw, alaw); break;
440 default:
441 err = AUDIO_ERR_HDRINVAL; break;
442 }
443 break;
444 case ALAW:
445 switch (outhdr.encoding) {
446 case LINEAR: // Convert alaw to linear
447 switch (outhdr.bytes_per_unit) {
448 case 1: MOVE(alaw, char); break;
449 case 2: MOVE(alaw, short); break;
450 case 4: MOVE(alaw, long); break;
451 default: err = AUDIO_ERR_HDRINVAL; break;
452 }
453 break;
454 case FLOAT: // Convert alaw to float
455 switch (outhdr.bytes_per_unit) {
456 case 4: MOVE(alaw, float); break;
457 case 8: MOVE(alaw, double); break;
458 default: err = AUDIO_ERR_HDRINVAL; break;
459 }
460 break;
461 case ALAW: // Convert alaw to a-law
462 COPY(1); break;
463 case ULAW: // Convert alaw to u-law
464 MOVE(alaw, ulaw); break;
465 default:
466 err = AUDIO_ERR_HDRINVAL; break;
467 }
468 break;
469 default:
470 err = AUDIO_ERR_HDRINVAL; break;
471 }
472 if (err) {
473 if (outbuf != inbuf)
474 delete outbuf;
475 return (err);
476 }
477
478 // Finish up
479 if (outbuf == inbuf) {
480 // If the conversion was in-place, set the new header
481 (void) inbuf->SetHeader(outhdr);
482 } else {
483 // This will delete the buffer
484 inbuf->Reference();
485 inbuf->Dereference();
486
487 // Set the valid data length and replace the pointer
488 outbuf->SetLength(length);
489 inbuf = outbuf;
490 }
491 return (AUDIO_SUCCESS);
492 }
493
494 AudioError AudioTypePcm::
Flush(AudioBuffer * &)495 Flush(
496 AudioBuffer*& /* buf */)
497 {
498 return (AUDIO_SUCCESS);
499 }
500