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