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