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::
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::
53 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::
93 char2dbl(char B)
94 {
95 	return ((unsigned char)B == 0x80 ? -1. : (double)B / 127.);
96 }
97 inline double AudioTypePcm::
98 short2dbl(short S)
99 {
100 	return ((unsigned short)S == 0x8000 ? -1. : (double)S / 32767.);
101 }
102 inline double AudioTypePcm::
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::
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::
116 char2short(char *&F, short *&T) { *T++ = ((short)*F++) << 8; }
117 inline void AudioTypePcm::
118 char2long(char *&F, long *&T) { *T++ = ((long)*F++) << 24; }
119 inline void AudioTypePcm::
120 char2float(char *&F, float *&T) { *T++ = char2dbl(*F++); }
121 inline void AudioTypePcm::
122 char2double(char *&F, double *&T) { *T++ = char2dbl(*F++); }
123 inline void AudioTypePcm::
124 char2ulaw(char *&F, ulaw *&T) { *T++ = audio_c2u(*F); F++; }
125 inline void AudioTypePcm::
126 char2alaw(char *&F, alaw *&T) { *T++ = audio_c2a(*F); F++; }
127 
128 inline void AudioTypePcm::
129 short2char(short *&F, char *&T) { *T++ = (char)(*F++ >> 8); }
130 inline void AudioTypePcm::
131 short2long(short *&F, long *&T) { *T++ = ((long)*F++) << 16; }
132 inline void AudioTypePcm::
133 short2float(short *&F, float *&T) { *T++ = short2dbl(*F++); }
134 inline void AudioTypePcm::
135 short2double(short *&F, double *&T) { *T++ = short2dbl(*F++); }
136 inline void AudioTypePcm::
137 short2ulaw(short *&F, ulaw *&T) { *T++ = audio_s2u(*F); F++; }
138 inline void AudioTypePcm::
139 short2alaw(short *&F, alaw *&T) { *T++ = audio_s2a(*F); F++; }
140 
141 inline void AudioTypePcm::
142 long2char(long *&F, char *&T) { *T++ = (char)(*F++ >> 24); }
143 inline void AudioTypePcm::
144 long2short(long *&F, short *&T) { *T++ = (short)(*F++ >> 16); }
145 inline void AudioTypePcm::
146 long2float(long *&F, float *&T) { *T++ = long2dbl(*F++); }
147 inline void AudioTypePcm::
148 long2double(long *&F, double *&T) { *T++ = long2dbl(*F++); }
149 inline void AudioTypePcm::
150 long2ulaw(long *&F, ulaw *&T) { *T++ = audio_l2u(*F); F++; }
151 inline void AudioTypePcm::
152 long2alaw(long *&F, alaw *&T) { *T++ = audio_l2a(*F); F++; }
153 
154 inline void AudioTypePcm::
155 float2char(float *&F, char *&T) { *T++ = (char)dbl2long(*F++, 127); }
156 inline void AudioTypePcm::
157 float2short(float *&F, short *&T) { *T++ = (short)dbl2long(*F++, 32767); }
158 inline void AudioTypePcm::
159 float2long(float *&F, long *&T) { *T++ = dbl2long(*F++, 2147483647); }
160 inline void AudioTypePcm::
161 float2double(float *&F, double *&T) { *T++ = *F++; }
162 inline void AudioTypePcm::
163 float2ulaw(float *&F, ulaw *&T) { *T++ = audio_s2u(dbl2long(*F++, 32767)); }
164 inline void AudioTypePcm::
165 float2alaw(float *&F, alaw *&T) { *T++ = audio_s2a(dbl2long(*F++, 32767)); }
166 
167 inline void AudioTypePcm::
168 double2char(double *&F, char *&T) { *T++ = (char)dbl2long(*F++, 127); }
169 inline void AudioTypePcm::
170 double2short(double *&F, short *&T) { *T++ = (short)dbl2long(*F++, 32767); }
171 inline void AudioTypePcm::
172 double2long(double *&F, long *&T) { *T++ = dbl2long(*F++, 2147483647); }
173 inline void AudioTypePcm::
174 double2float(double *&F, float *&T) { *T++ = *F++; }
175 inline void AudioTypePcm::
176 double2ulaw(double *&F, ulaw *&T) { *T++ = audio_s2u(dbl2long(*F++, 32767)); }
177 inline void AudioTypePcm::
178 double2alaw(double *&F, alaw *&T) { *T++ = audio_s2a(dbl2long(*F++, 32767)); }
179 
180 inline void AudioTypePcm::
181 ulaw2char(ulaw *&F, char *&T) { *T++ = audio_u2c(*F); F++; }
182 inline void AudioTypePcm::
183 ulaw2alaw(ulaw *&F, alaw *&T) { *T++ = audio_u2a(*F); F++; }
184 inline void AudioTypePcm::
185 ulaw2short(ulaw *&F, short *&T) { *T++ = audio_u2s(*F); F++; }
186 inline void AudioTypePcm::
187 ulaw2long(ulaw *&F, long *&T) { *T++ = audio_u2l(*F); F++; }
188 inline void AudioTypePcm::
189 ulaw2float(ulaw *&F, float *&T) { *T++ = short2dbl(audio_u2s(*F)); F++; }
190 inline void AudioTypePcm::
191 ulaw2double(ulaw *&F, double *&T) { *T++ = short2dbl(audio_u2s(*F)); F++; }
192 
193 inline void AudioTypePcm::
194 alaw2char(alaw *&F, char *&T) { *T++ = audio_a2c(*F); F++; }
195 inline void AudioTypePcm::
196 alaw2short(alaw *&F, short *&T) { *T++ = audio_a2s(*F); F++; }
197 inline void AudioTypePcm::
198 alaw2long(alaw *&F, long *&T) { *T++ = audio_a2l(*F); F++; }
199 inline void AudioTypePcm::
200 alaw2float(alaw *&F, float *&T) { *T++ = short2dbl(audio_a2s(*F)); F++; }
201 inline void AudioTypePcm::
202 alaw2double(alaw *&F, double *&T) { *T++ = short2dbl(audio_a2s(*F)); F++; }
203 inline void AudioTypePcm::
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::
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::
496 Flush(
497 	AudioBuffer*&	/* buf */)
498 {
499 	return (AUDIO_SUCCESS);
500 }
501