1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <audio_utils/sndfile.h> 18 #include <audio_utils/primitives.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <errno.h> 22 23 #define WAVE_FORMAT_PCM 1 24 #define WAVE_FORMAT_IEEE_FLOAT 3 25 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE 26 27 struct SNDFILE_ { 28 int mode; 29 uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping 30 FILE *stream; 31 size_t bytesPerFrame; 32 size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE 33 SF_INFO info; 34 }; 35 36 static unsigned little2u(unsigned char *ptr) 37 { 38 return (ptr[1] << 8) + ptr[0]; 39 } 40 41 static unsigned little4u(unsigned char *ptr) 42 { 43 return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0]; 44 } 45 46 static int isLittleEndian(void) 47 { 48 static const short one = 1; 49 return *((const char *) &one) == 1; 50 } 51 52 // "swab" conflicts with OS X <string.h> 53 static void my_swab(short *ptr, size_t numToSwap) 54 { 55 while (numToSwap > 0) { 56 *ptr = little2u((unsigned char *) ptr); 57 --numToSwap; 58 ++ptr; 59 } 60 } 61 62 static SNDFILE *sf_open_read(const char *path, SF_INFO *info) 63 { 64 FILE *stream = fopen(path, "rb"); 65 if (stream == NULL) { 66 fprintf(stderr, "fopen %s failed errno %d\n", path, errno); 67 return NULL; 68 } 69 70 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE)); 71 handle->mode = SFM_READ; 72 handle->temp = NULL; 73 handle->stream = stream; 74 handle->info.format = SF_FORMAT_WAV; 75 76 // don't attempt to parse all valid forms, just the most common ones 77 unsigned char wav[12]; 78 size_t actual; 79 actual = fread(wav, sizeof(char), sizeof(wav), stream); 80 if (actual < 12) { 81 fprintf(stderr, "actual %zu < 44\n", actual); 82 goto close; 83 } 84 if (memcmp(wav, "RIFF", 4)) { 85 fprintf(stderr, "wav != RIFF\n"); 86 goto close; 87 } 88 unsigned riffSize = little4u(&wav[4]); 89 if (riffSize < 4) { 90 fprintf(stderr, "riffSize %u < 4\n", riffSize); 91 goto close; 92 } 93 if (memcmp(&wav[8], "WAVE", 4)) { 94 fprintf(stderr, "missing WAVE\n"); 95 goto close; 96 } 97 size_t remaining = riffSize - 4; 98 int hadFmt = 0; 99 int hadData = 0; 100 while (remaining >= 8) { 101 unsigned char chunk[8]; 102 actual = fread(chunk, sizeof(char), sizeof(chunk), stream); 103 if (actual != sizeof(chunk)) { 104 fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk)); 105 goto close; 106 } 107 remaining -= 8; 108 unsigned chunkSize = little4u(&chunk[4]); 109 if (chunkSize > remaining) { 110 fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining); 111 goto close; 112 } 113 if (!memcmp(&chunk[0], "fmt ", 4)) { 114 if (hadFmt) { 115 fprintf(stderr, "multiple fmt\n"); 116 goto close; 117 } 118 if (chunkSize < 2) { 119 fprintf(stderr, "chunkSize %u < 2\n", chunkSize); 120 goto close; 121 } 122 unsigned char fmt[40]; 123 actual = fread(fmt, sizeof(char), 2, stream); 124 if (actual != 2) { 125 fprintf(stderr, "actual %zu != 2\n", actual); 126 goto close; 127 } 128 unsigned format = little2u(&fmt[0]); 129 size_t minSize = 0; 130 switch (format) { 131 case WAVE_FORMAT_PCM: 132 case WAVE_FORMAT_IEEE_FLOAT: 133 minSize = 16; 134 break; 135 case WAVE_FORMAT_EXTENSIBLE: 136 minSize = 40; 137 break; 138 default: 139 fprintf(stderr, "unsupported format %u\n", format); 140 goto close; 141 } 142 if (chunkSize < minSize) { 143 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize); 144 goto close; 145 } 146 actual = fread(&fmt[2], sizeof(char), minSize - 2, stream); 147 if (actual != minSize - 2) { 148 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16); 149 goto close; 150 } 151 if (chunkSize > minSize) { 152 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR); 153 } 154 unsigned channels = little2u(&fmt[2]); 155 if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) { 156 fprintf(stderr, "unsupported channels %u\n", channels); 157 goto close; 158 } 159 unsigned samplerate = little4u(&fmt[4]); 160 if (samplerate == 0) { 161 fprintf(stderr, "samplerate %u == 0\n", samplerate); 162 goto close; 163 } 164 // ignore byte rate 165 // ignore block alignment 166 unsigned bitsPerSample = little2u(&fmt[14]); 167 if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) { 168 fprintf(stderr, "bitsPerSample %u != 8 or 16 or 32\n", bitsPerSample); 169 goto close; 170 } 171 unsigned bytesPerFrame = (bitsPerSample >> 3) * channels; 172 handle->bytesPerFrame = bytesPerFrame; 173 handle->info.samplerate = samplerate; 174 handle->info.channels = channels; 175 switch (bitsPerSample) { 176 case 8: 177 handle->info.format |= SF_FORMAT_PCM_U8; 178 break; 179 case 16: 180 handle->info.format |= SF_FORMAT_PCM_16; 181 break; 182 case 32: 183 if (format == WAVE_FORMAT_IEEE_FLOAT) 184 handle->info.format |= SF_FORMAT_FLOAT; 185 else 186 handle->info.format |= SF_FORMAT_PCM_32; 187 break; 188 } 189 hadFmt = 1; 190 } else if (!memcmp(&chunk[0], "data", 4)) { 191 if (!hadFmt) { 192 fprintf(stderr, "data not preceded by fmt\n"); 193 goto close; 194 } 195 if (hadData) { 196 fprintf(stderr, "multiple data\n"); 197 goto close; 198 } 199 handle->remaining = chunkSize / handle->bytesPerFrame; 200 handle->info.frames = handle->remaining; 201 hadData = 1; 202 } else if (!memcmp(&chunk[0], "fact", 4)) { 203 // ignore fact 204 if (chunkSize > 0) { 205 fseek(stream, (long) chunkSize, SEEK_CUR); 206 } 207 } else { 208 // ignore unknown chunk 209 fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n", 210 chunk[0], chunk[1], chunk[2], chunk[3]); 211 if (chunkSize > 0) { 212 fseek(stream, (long) chunkSize, SEEK_CUR); 213 } 214 } 215 remaining -= chunkSize; 216 } 217 if (remaining > 0) { 218 fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining); 219 goto close; 220 } 221 if (!hadData) { 222 fprintf(stderr, "missing data\n"); 223 goto close; 224 } 225 *info = handle->info; 226 return handle; 227 228 close: 229 free(handle); 230 fclose(stream); 231 return NULL; 232 } 233 234 static void write4u(unsigned char *ptr, unsigned u) 235 { 236 ptr[0] = u; 237 ptr[1] = u >> 8; 238 ptr[2] = u >> 16; 239 ptr[3] = u >> 24; 240 } 241 242 static SNDFILE *sf_open_write(const char *path, SF_INFO *info) 243 { 244 int sub = info->format & SF_FORMAT_SUBMASK; 245 if (!( 246 (info->samplerate > 0) && 247 (info->channels > 0 && info->channels <= 8) && 248 ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) && 249 (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT) 250 )) { 251 return NULL; 252 } 253 FILE *stream = fopen(path, "w+b"); 254 if (stream == NULL) { 255 fprintf(stderr, "fopen %s failed errno %d\n", path, errno); 256 return NULL; 257 } 258 unsigned char wav[58]; 259 memset(wav, 0, sizeof(wav)); 260 memcpy(wav, "RIFF", 4); 261 memcpy(&wav[8], "WAVEfmt ", 8); 262 if (sub == SF_FORMAT_FLOAT) { 263 wav[4] = 50; // riffSize 264 wav[16] = 18; // fmtSize 265 wav[20] = WAVE_FORMAT_IEEE_FLOAT; 266 } else { 267 wav[4] = 36; // riffSize 268 wav[16] = 16; // fmtSize 269 wav[20] = WAVE_FORMAT_PCM; 270 } 271 wav[22] = info->channels; 272 write4u(&wav[24], info->samplerate); 273 unsigned bitsPerSample; 274 switch (sub) { 275 case SF_FORMAT_PCM_16: 276 bitsPerSample = 16; 277 break; 278 case SF_FORMAT_PCM_U8: 279 bitsPerSample = 8; 280 break; 281 case SF_FORMAT_FLOAT: 282 bitsPerSample = 32; 283 break; 284 default: // not reachable 285 bitsPerSample = 0; 286 break; 287 } 288 unsigned blockAlignment = (bitsPerSample >> 3) * info->channels; 289 unsigned byteRate = info->samplerate * blockAlignment; 290 write4u(&wav[28], byteRate); 291 wav[32] = blockAlignment; 292 wav[34] = bitsPerSample; 293 size_t extra = 0; 294 if (sub == SF_FORMAT_FLOAT) { 295 memcpy(&wav[38], "fact", 4); 296 wav[42] = 4; 297 memcpy(&wav[50], "data", 4); 298 extra = 14; 299 } else 300 memcpy(&wav[36], "data", 4); 301 // dataSize is initially zero 302 (void) fwrite(wav, 44 + extra, 1, stream); 303 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE)); 304 handle->mode = SFM_WRITE; 305 handle->temp = NULL; 306 handle->stream = stream; 307 handle->bytesPerFrame = blockAlignment; 308 handle->remaining = 0; 309 handle->info = *info; 310 return handle; 311 } 312 313 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info) 314 { 315 if (path == NULL || info == NULL) { 316 fprintf(stderr, "path=%p info=%p\n", path, info); 317 return NULL; 318 } 319 switch (mode) { 320 case SFM_READ: 321 return sf_open_read(path, info); 322 case SFM_WRITE: 323 return sf_open_write(path, info); 324 default: 325 fprintf(stderr, "mode=%d\n", mode); 326 return NULL; 327 } 328 } 329 330 void sf_close(SNDFILE *handle) 331 { 332 if (handle == NULL) 333 return; 334 free(handle->temp); 335 if (handle->mode == SFM_WRITE) { 336 (void) fflush(handle->stream); 337 rewind(handle->stream); 338 unsigned char wav[58]; 339 size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0; 340 (void) fread(wav, 44 + extra, 1, handle->stream); 341 unsigned dataSize = handle->remaining * handle->bytesPerFrame; 342 write4u(&wav[4], dataSize + 36 + extra); // riffSize 343 write4u(&wav[40 + extra], dataSize); // dataSize 344 rewind(handle->stream); 345 (void) fwrite(wav, 44 + extra, 1, handle->stream); 346 } 347 (void) fclose(handle->stream); 348 free(handle); 349 } 350 351 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames) 352 { 353 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 354 desiredFrames <= 0) { 355 return 0; 356 } 357 if (handle->remaining < (size_t) desiredFrames) { 358 desiredFrames = handle->remaining; 359 } 360 // does not check for numeric overflow 361 size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 362 size_t actualBytes; 363 void *temp = NULL; 364 unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 365 if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) { 366 temp = malloc(desiredBytes); 367 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 368 } else { 369 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 370 } 371 size_t actualFrames = actualBytes / handle->bytesPerFrame; 372 handle->remaining -= actualFrames; 373 switch (format) { 374 case SF_FORMAT_PCM_U8: 375 memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels); 376 break; 377 case SF_FORMAT_PCM_16: 378 if (!isLittleEndian()) 379 my_swab(ptr, actualFrames * handle->info.channels); 380 break; 381 case SF_FORMAT_PCM_32: 382 memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels); 383 free(temp); 384 break; 385 case SF_FORMAT_FLOAT: 386 memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels); 387 free(temp); 388 break; 389 default: 390 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short)); 391 break; 392 } 393 return actualFrames; 394 } 395 396 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames) 397 { 398 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 399 desiredFrames <= 0) { 400 return 0; 401 } 402 if (handle->remaining < (size_t) desiredFrames) { 403 desiredFrames = handle->remaining; 404 } 405 // does not check for numeric overflow 406 size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 407 size_t actualBytes; 408 void *temp = NULL; 409 unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 410 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) { 411 temp = malloc(desiredBytes); 412 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 413 } else { 414 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 415 } 416 size_t actualFrames = actualBytes / handle->bytesPerFrame; 417 handle->remaining -= actualFrames; 418 switch (format) { 419 case SF_FORMAT_PCM_U8: 420 #if 0 421 // TODO - implement 422 memcpy_to_float_from_u8(ptr, (const unsigned char *) temp, 423 actualFrames * handle->info.channels); 424 #endif 425 free(temp); 426 break; 427 case SF_FORMAT_PCM_16: 428 memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels); 429 free(temp); 430 break; 431 case SF_FORMAT_PCM_32: 432 memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels); 433 break; 434 case SF_FORMAT_FLOAT: 435 break; 436 default: 437 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float)); 438 break; 439 } 440 return actualFrames; 441 } 442 443 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames) 444 { 445 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 446 desiredFrames <= 0) { 447 return 0; 448 } 449 if (handle->remaining < (size_t) desiredFrames) { 450 desiredFrames = handle->remaining; 451 } 452 // does not check for numeric overflow 453 size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 454 void *temp = NULL; 455 unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 456 size_t actualBytes; 457 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) { 458 temp = malloc(desiredBytes); 459 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 460 } else { 461 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 462 } 463 size_t actualFrames = actualBytes / handle->bytesPerFrame; 464 handle->remaining -= actualFrames; 465 switch (format) { 466 case SF_FORMAT_PCM_U8: 467 #if 0 468 // TODO - implement 469 memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp, 470 actualFrames * handle->info.channels); 471 #endif 472 free(temp); 473 break; 474 case SF_FORMAT_PCM_16: 475 memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels); 476 free(temp); 477 break; 478 case SF_FORMAT_PCM_32: 479 break; 480 case SF_FORMAT_FLOAT: 481 memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels); 482 break; 483 default: 484 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int)); 485 break; 486 } 487 return actualFrames; 488 } 489 490 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames) 491 { 492 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0) 493 return 0; 494 size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 495 size_t actualBytes = 0; 496 switch (handle->info.format & SF_FORMAT_SUBMASK) { 497 case SF_FORMAT_PCM_U8: 498 handle->temp = realloc(handle->temp, desiredBytes); 499 memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes); 500 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 501 break; 502 case SF_FORMAT_PCM_16: 503 // does not check for numeric overflow 504 if (isLittleEndian()) { 505 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream); 506 } else { 507 handle->temp = realloc(handle->temp, desiredBytes); 508 memcpy(handle->temp, ptr, desiredBytes); 509 my_swab((short *) handle->temp, desiredFrames * handle->info.channels); 510 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 511 } 512 break; 513 case SF_FORMAT_FLOAT: 514 handle->temp = realloc(handle->temp, desiredBytes); 515 memcpy_to_float_from_i16((float *) handle->temp, ptr, 516 desiredFrames * handle->info.channels); 517 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 518 break; 519 default: 520 break; 521 } 522 size_t actualFrames = actualBytes / handle->bytesPerFrame; 523 handle->remaining += actualFrames; 524 return actualFrames; 525 } 526 527 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames) 528 { 529 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0) 530 return 0; 531 size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 532 size_t actualBytes = 0; 533 switch (handle->info.format & SF_FORMAT_SUBMASK) { 534 case SF_FORMAT_FLOAT: 535 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream); 536 break; 537 case SF_FORMAT_PCM_16: 538 handle->temp = realloc(handle->temp, desiredBytes); 539 memcpy_to_i16_from_float((short *) handle->temp, ptr, 540 desiredFrames * handle->info.channels); 541 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 542 break; 543 case SF_FORMAT_PCM_U8: // transcoding from float to byte not yet implemented 544 default: 545 break; 546 } 547 size_t actualFrames = actualBytes / handle->bytesPerFrame; 548 handle->remaining += actualFrames; 549 return actualFrames; 550 } 551