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