The tiny wav I/O module is the most simple wav file I/O module you've ever seen.
Dependents: SimpleWaveRecorderPlayer USBMSD_SD_HelloWorld_FRDM-KL25Z Application-SimpleWaveRecorderPlayerGenerator MbedClock ... more
wavfile.cpp
00001 /** 00002 * @file wavfile.cpp 00003 * @author Shinichiro Nakamura 00004 */ 00005 00006 /* 00007 * =============================================================== 00008 * Tiny WAV I/O Module 00009 * Version 0.0.1 00010 * =============================================================== 00011 * Copyright (c) 2011-2012 Shinichiro Nakamura 00012 * 00013 * Permission is hereby granted, free of charge, to any person 00014 * obtaining a copy of this software and associated documentation 00015 * files (the "Software"), to deal in the Software without 00016 * restriction, including without limitation the rights to use, 00017 * copy, modify, merge, publish, distribute, sublicense, and/or 00018 * sell copies of the Software, and to permit persons to whom the 00019 * Software is furnished to do so, subject to the following 00020 * conditions: 00021 * 00022 * The above copyright notice and this permission notice shall be 00023 * included in all copies or substantial portions of the Software. 00024 * 00025 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00026 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 00027 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00028 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 00029 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 00030 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00031 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00032 * OTHER DEALINGS IN THE SOFTWARE. 00033 * =============================================================== 00034 */ 00035 00036 #include <stdio.h> 00037 #include <stdlib.h> 00038 #include <string.h> 00039 #include "wavfile.h " 00040 00041 #define DEBUG printf 00042 00043 #define CHUNK_ID_RIFF (('R' << 24) | ('I' << 16) | ('F' << 8) | ('F' << 0)) 00044 #define CHUNK_ID_FMT (('f' << 24) | ('m' << 16) | ('t' << 8) | (' ' << 0)) 00045 #define CHUNK_ID_DATA (('d' << 24) | ('a' << 16) | ('t' << 8) | ('a' << 0)) 00046 00047 #define RIFF_CHUNK_FORMAT_WAVE (('W' << 24) | ('A' << 16) | ('V' << 8) | ('E' << 0)) 00048 00049 #define BITS_PER_SAMPLE_8 (8) 00050 #define BITS_PER_SAMPLE_16 (16) 00051 #define BITS_PER_SAMPLE_24 (24) 00052 00053 #define CHUNK_SIZE_FMT_PCM (16) 00054 #define CHUNK_SIZE_FMT_EXTENSIBLE (40) 00055 00056 #define CHANNEL_MASK_SPEAKER_FRONT_LEFT (0x00000001) 00057 #define CHANNEL_MASK_SPEAKER_FRONT_RIGHT (0x00000002) 00058 #define CHANNEL_MASK_SPEAKER_FRONT_CENTER (0x00000004) 00059 #define CHANNEL_MASK_SPEAKER_LOW_FREQUENCY (0x00000008) 00060 #define CHANNEL_MASK_SPEAKER_BACK_LEFT (0x00000010) 00061 #define CHANNEL_MASK_SPEAKER_BACK_RIGHT (0x00000020) 00062 #define CHANNEL_MASK_SPEAKER_FRONT_LEFT_OF_CENTER (0x00000040) 00063 #define CHANNEL_MASK_SPEAKER_FRONT_RIGHT_OF_CENTER (0x00000080) 00064 #define CHANNEL_MASK_SPEAKER_BACK_CENTER (0x00000100) 00065 #define CHANNEL_MASK_SPEAKER_SIDE_LEFT (0x00000200) 00066 #define CHANNEL_MASK_SPEAKER_SIDE_RIGHT (0x00000400) 00067 #define CHANNEL_MASK_SPEAKER_TOP_CENTER (0x00000800) 00068 #define CHANNEL_MASK_SPEAKER_TOP_FRONT_LEFT (0x00001000) 00069 #define CHANNEL_MASK_SPEAKER_TOP_FRONT_CENTER (0x00002000) 00070 #define CHANNEL_MASK_SPEAKER_TOP_FRONT_RIGHT (0x00004000) 00071 #define CHANNEL_MASK_SPEAKER_TOP_BACK_LEFT (0x00008000) 00072 #define CHANNEL_MASK_SPEAKER_TOP_BACK_CENTER (0x00010000) 00073 #define CHANNEL_MASK_SPEAKER_TOP_BACK_RIGHT (0x00020000) 00074 #define CHANNEL_MASK_SPEAKER_RESERVED (0x80000000) 00075 00076 struct WAVFILE { 00077 FILE *fp; 00078 char filename[BUFSIZ]; 00079 WavFileMode mode; 00080 bool info_checked; 00081 bool data_checked; 00082 uint32_t data_byte_count; 00083 wavfile_info_t info; 00084 }; 00085 00086 static int WRITE_U32_BE(FILE *fp, const uint32_t value) { 00087 for (int i = 0; i < 4; i++) { 00088 if (fputc((value >> (8 * (3 - i))), fp) == EOF) { 00089 return -1; 00090 } 00091 } 00092 return 0; 00093 } 00094 00095 static int WRITE_U32_LE(FILE *fp, const uint32_t value) { 00096 for (int i = 0; i < 4; i++) { 00097 if (fputc((value >> (8 * i)), fp) == EOF) { 00098 return -1; 00099 } 00100 } 00101 return 0; 00102 } 00103 00104 static int WRITE_U16_LE(FILE *fp, const uint16_t value) { 00105 for (int i = 0; i < 2; i++) { 00106 if (fputc((value >> (8 * i)), fp) == EOF) { 00107 return -1; 00108 } 00109 } 00110 return 0; 00111 } 00112 00113 static int READ_U32_BE(FILE *fp, uint32_t *value) { 00114 int raw[4]; 00115 for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) { 00116 raw[i] = fgetc(fp); 00117 if (raw[i] == EOF) { 00118 *value = 0x00000000; 00119 return -1; 00120 } 00121 } 00122 *value = 00123 ((uint32_t)raw[0] << 24) | 00124 ((uint32_t)raw[1] << 16) | 00125 ((uint32_t)raw[2] << 8) | 00126 ((uint32_t)raw[3] << 0); 00127 return 0; 00128 } 00129 00130 static int READ_U32_LE(FILE *fp, uint32_t *value) { 00131 int raw[4]; 00132 for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) { 00133 raw[i] = fgetc(fp); 00134 if (raw[i] == EOF) { 00135 *value = 0x00000000; 00136 return -1; 00137 } 00138 } 00139 *value = 00140 ((uint32_t)raw[3] << 24) | 00141 ((uint32_t)raw[2] << 16) | 00142 ((uint32_t)raw[1] << 8) | 00143 ((uint32_t)raw[0] << 0); 00144 return 0; 00145 } 00146 00147 static int READ_U16_LE(FILE *fp, uint16_t *value) { 00148 int raw[2]; 00149 for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) { 00150 raw[i] = fgetc(fp); 00151 if (raw[i] == EOF) { 00152 *value = 0x00000000; 00153 return -1; 00154 } 00155 } 00156 *value = 00157 ((uint16_t)raw[1] << 8) | 00158 ((uint16_t)raw[0] << 0); 00159 return 0; 00160 } 00161 00162 static WavFileResult chunk_reader_unknown( 00163 const uint32_t chunk_id, 00164 const uint32_t chunk_size, 00165 FILE *fp) { 00166 for (int i = 0; i < (int)chunk_size; i++) { 00167 int c = fgetc(fp); 00168 if (c == EOF) { 00169 return WavFileResultErrorBrokenChunkData; 00170 } 00171 } 00172 return WavFileResultOK; 00173 } 00174 00175 static WavFileResult chunk_reader_riff( 00176 const uint32_t chunk_id, 00177 const uint32_t chunk_size, 00178 FILE *fp, 00179 uint32_t *format_id) { 00180 if (READ_U32_BE(fp, format_id) != 0) { 00181 return WavFileResultErrorBrokenFormatId; 00182 } 00183 return WavFileResultOK; 00184 } 00185 00186 static WavFileResult chunk_reader_fmt( 00187 const uint32_t chunk_id, 00188 const uint32_t chunk_size, 00189 FILE *fp, 00190 uint16_t *audio_format, 00191 uint16_t *num_channels, 00192 uint32_t *sample_rate, 00193 uint32_t *byte_rate, 00194 uint16_t *block_align, 00195 uint16_t *bits_per_sample) { 00196 uint32_t read_byte_count = 0; 00197 00198 /* 00199 * 2 00200 */ 00201 if (read_byte_count < chunk_size) { 00202 if (READ_U16_LE(fp, audio_format) != 0) { 00203 return WavFileResultErrorBrokenAudioFormat; 00204 } 00205 } 00206 read_byte_count+=2; 00207 00208 /* 00209 * 2 + 2 00210 */ 00211 if (read_byte_count < chunk_size) { 00212 if (READ_U16_LE(fp, num_channels) != 0) { 00213 return WavFileResultErrorBrokenNumChannels; 00214 } 00215 } 00216 read_byte_count+=2; 00217 00218 /* 00219 * 2 + 2 + 4 00220 */ 00221 if (read_byte_count < chunk_size) { 00222 if (READ_U32_LE(fp, sample_rate) != 0) { 00223 return WavFileResultErrorBrokenSampleRate; 00224 } 00225 } 00226 read_byte_count+=4; 00227 00228 /* 00229 * 2 + 2 + 4 + 4 00230 */ 00231 if (read_byte_count < chunk_size) { 00232 if (READ_U32_LE(fp, byte_rate) != 0) { 00233 return WavFileResultErrorBrokenByteRate; 00234 } 00235 } 00236 read_byte_count+=4; 00237 00238 /* 00239 * 2 + 2 + 4 + 4 + 2 00240 */ 00241 if (read_byte_count < chunk_size) { 00242 if (READ_U16_LE(fp, block_align) != 0) { 00243 return WavFileResultErrorBrokenBlockAlign; 00244 } 00245 } 00246 read_byte_count+=2; 00247 00248 /* 00249 * 2 + 2 + 4 + 4 + 2 + 2 00250 */ 00251 if (read_byte_count < chunk_size) { 00252 if (READ_U16_LE(fp, bits_per_sample) != 0) { 00253 return WavFileResultErrorBrokenBitsPerSample; 00254 } 00255 } 00256 read_byte_count+=2; 00257 00258 /* 00259 * 2 + 2 + 4 + 4 + 2 + 2 00260 */ 00261 while (read_byte_count < chunk_size) { 00262 if (fgetc(fp) == EOF) { 00263 return WavFileResultErrorBrokenChunkData; 00264 } 00265 read_byte_count++; 00266 } 00267 00268 return WavFileResultOK; 00269 } 00270 00271 WAVFILE *wavfile_open(const char *filename, WavFileMode mode, WavFileResult *result) { 00272 /* 00273 * Verify the filename. 00274 */ 00275 if (filename == NULL) { 00276 *result = WavFileResultErrorInvalidFileName; 00277 return NULL; 00278 } 00279 00280 /* 00281 * Open the file. 00282 */ 00283 FILE *fp = NULL; 00284 switch (mode) { 00285 case WavFileModeRead: 00286 fp = fopen(filename, "rb"); 00287 break; 00288 case WavFileModeWrite: 00289 fp = fopen(filename, "wb"); 00290 break; 00291 default: 00292 fp = NULL; 00293 break; 00294 } 00295 if (fp == NULL) { 00296 *result = WavFileResultErrorFileOpen; 00297 return NULL; 00298 } 00299 00300 /* 00301 * Allocate the handler. 00302 */ 00303 WAVFILE *p = (WAVFILE *)malloc(sizeof(WAVFILE)); 00304 if (p == NULL) { 00305 *result = WavFileResultErrorMemoryAllocation; 00306 return NULL; 00307 } 00308 00309 /* 00310 * Fill the fields. 00311 */ 00312 p->fp = fp; 00313 strcpy(p->filename, filename); 00314 p->mode = mode; 00315 p->info_checked = false; 00316 p->data_checked = false; 00317 p->data_byte_count = 0; 00318 WAVFILE_INFO_AUDIO_FORMAT(&(p->info)) = 0; 00319 WAVFILE_INFO_NUM_CHANNELS(&(p->info)) = 0; 00320 WAVFILE_INFO_SAMPLE_RATE(&(p->info)) = 0; 00321 WAVFILE_INFO_BYTE_RATE(&(p->info)) = 0; 00322 WAVFILE_INFO_BLOCK_ALIGN(&(p->info)) = 0; 00323 WAVFILE_INFO_BITS_PER_SAMPLE(&(p->info)) = 0; 00324 00325 *result = WavFileResultOK; 00326 return p; 00327 } 00328 00329 WavFileResult wavfile_read_info(WAVFILE *p, wavfile_info_t *info) { 00330 WavFileResult result = WavFileResultOK; 00331 00332 if (p == NULL) { 00333 result = WavFileResultErrorInvalidHandler; 00334 goto finalize; 00335 } 00336 00337 if (p->info_checked) { 00338 result = WavFileResultErrorAlreadyInfoChecked; 00339 goto finalize; 00340 } 00341 if (p->data_checked) { 00342 result = WavFileResultErrorAlreadyDataChecked; 00343 goto finalize; 00344 } 00345 if (p->mode != WavFileModeRead) { 00346 result = WavFileResultErrorInvalidMode; 00347 goto finalize; 00348 } 00349 00350 while (1) { 00351 uint32_t chunk_id; 00352 uint32_t chunk_size; 00353 00354 /* 00355 * Get the chunk ID. 00356 */ 00357 if (READ_U32_BE(p->fp, &chunk_id) != 0) { 00358 if (feof(p->fp)) { 00359 /* 00360 * 00361 */ 00362 result = WavFileResultErrorNoDataChunk; 00363 goto finalize; 00364 } else { 00365 result = WavFileResultErrorBrokenChunkId; 00366 goto finalize; 00367 } 00368 } 00369 00370 /* 00371 * Verify the chunk size. 00372 */ 00373 if (READ_U32_LE(p->fp, &chunk_size) != 0) { 00374 result = WavFileResultErrorBrokenChunkSize; 00375 goto finalize; 00376 } 00377 00378 #if WAVFILE_DEBUG_ENABLED 00379 /* 00380 * 00381 */ 00382 DEBUG("chunk_id(0x%04X-%c%c%c%c), chunk_size(%d bytes)\n", 00383 chunk_id, 00384 (chunk_id >> (8 * 3)), 00385 (chunk_id >> (8 * 2)), 00386 (chunk_id >> (8 * 1)), 00387 (chunk_id >> (8 * 0)), 00388 chunk_size); 00389 #endif 00390 00391 /* 00392 */ 00393 switch (chunk_id) { 00394 case CHUNK_ID_RIFF: { 00395 uint32_t format_id; 00396 result = chunk_reader_riff( 00397 chunk_id, 00398 chunk_size, 00399 p->fp, 00400 &format_id); 00401 00402 #if WAVFILE_DEBUG_ENABLED 00403 /* 00404 */ 00405 DEBUG("\tformat_id(%d)\n", format_id); 00406 #endif 00407 00408 if (format_id != RIFF_CHUNK_FORMAT_WAVE) { 00409 return WavFileResultErrorInvalidFormatId; 00410 } 00411 if (result != WavFileResultOK) { 00412 goto finalize; 00413 } 00414 } 00415 break; 00416 case CHUNK_ID_FMT: { 00417 result = chunk_reader_fmt( 00418 chunk_id, 00419 chunk_size, 00420 p->fp, 00421 &(p->info.audio_format), 00422 &(p->info.num_channels), 00423 &(p->info.sample_rate), 00424 &(p->info.byte_rate), 00425 &(p->info.block_align), 00426 &(p->info.bits_per_sample)); 00427 00428 info->audio_format = p->info.audio_format; 00429 info->num_channels = p->info.num_channels; 00430 info->sample_rate = p->info.sample_rate; 00431 info->byte_rate = p->info.byte_rate; 00432 info->block_align = p->info.block_align; 00433 info->bits_per_sample = p->info.bits_per_sample; 00434 00435 #if WAVFILE_DEBUG_ENABLED 00436 /* 00437 */ 00438 DEBUG("\taudio_format(%d)\n", p->info.audio_format); 00439 DEBUG("\tnum_channels(%d)\n", p->info.num_channels); 00440 DEBUG("\tsample_rate(%d)\n", p->info.sample_rate); 00441 DEBUG("\tbyte_rate(%d)\n", p->info.byte_rate); 00442 DEBUG("\tblock_align(%d)\n", p->info.block_align); 00443 DEBUG("\tbits_per_sample(%d)\n", p->info.bits_per_sample); 00444 #endif 00445 00446 if ((p->info.audio_format != WAVFILE_AUDIO_FORMAT_PCM) && (info->audio_format != WAVFILE_AUDIO_FORMAT_EXTENSIBLE)) { 00447 return WavFileResultErrorInvalidAudioFormat; 00448 } 00449 if (result != WavFileResultOK) { 00450 goto finalize; 00451 } 00452 } 00453 break; 00454 case CHUNK_ID_DATA: { 00455 p->info_checked = true; 00456 p->data_byte_count = chunk_size; 00457 goto finalize; 00458 } 00459 break; 00460 default: { 00461 result = chunk_reader_unknown(chunk_id, chunk_size, p->fp); 00462 if (result != WavFileResultOK) { 00463 goto finalize; 00464 } 00465 } 00466 break; 00467 } 00468 } 00469 00470 finalize: 00471 return result; 00472 } 00473 00474 /** 00475 */ 00476 WavFileResult wavfile_read_data(WAVFILE *p, wavfile_data_t *data) { 00477 if (p == NULL) { 00478 return WavFileResultErrorInvalidHandler; 00479 } 00480 00481 if (!p->info_checked) { 00482 return WavFileResultErrorNeedInfoChecked; 00483 } 00484 00485 if (p->mode != WavFileModeRead) { 00486 return WavFileResultErrorInvalidMode; 00487 } 00488 00489 if (p->data_byte_count == 0) { 00490 data->num_channels = 0; 00491 for (int i = 0; i < p->info.num_channels; i++) { 00492 data->channel_data[i] = 0.5; 00493 } 00494 return WavFileResultOK; 00495 } 00496 00497 data->num_channels = p->info.num_channels; 00498 for (int i = 0; i < p->info.num_channels; i++) { 00499 switch (p->info.bits_per_sample) { 00500 case BITS_PER_SAMPLE_8: { 00501 int c = fgetc(p->fp); 00502 if (c == EOF) { 00503 return WavFileResultErrorBrokenChunkData; 00504 } 00505 data->channel_data[i] = (double)c / 0xFF; 00506 } 00507 p->data_byte_count-=1; 00508 break; 00509 case BITS_PER_SAMPLE_16: { 00510 #if 0 00511 int c1 = fgetc(p->fp); 00512 if (c1 == EOF) { 00513 return WavFileResultErrorBrokenChunkData; 00514 } 00515 int c2 = fgetc(p->fp); 00516 if (c2 == EOF) { 00517 return WavFileResultErrorBrokenChunkData; 00518 } 00519 uint16_t n = (((uint16_t)c2 << 8) | ((uint16_t)c1 << 0)) ^ (1 << 15); 00520 data->channel_data[i] = (double)n / 0xFFFF; 00521 #else 00522 char tmp[2]; 00523 fread(tmp, 2, 1, p->fp); 00524 uint16_t n = (((uint16_t)tmp[1] << 8) | ((uint16_t)tmp[0] << 0)) ^ (1 << 15); 00525 data->channel_data[i] = (double)n / 0xFFFF; 00526 #endif 00527 } 00528 p->data_byte_count-=2; 00529 break; 00530 case BITS_PER_SAMPLE_24: { 00531 #if 0 00532 int c1 = fgetc(p->fp); 00533 if (c1 == EOF) { 00534 return WavFileResultErrorBrokenChunkData; 00535 } 00536 int c2 = fgetc(p->fp); 00537 if (c2 == EOF) { 00538 return WavFileResultErrorBrokenChunkData; 00539 } 00540 int c3 = fgetc(p->fp); 00541 if (c3 == EOF) { 00542 return WavFileResultErrorBrokenChunkData; 00543 } 00544 uint32_t n = (((uint32_t)c3 << 16) | ((uint32_t)c2 << 8) | ((uint32_t)c1 << 0)) ^ (1 << 23); 00545 data->channel_data[i] = (double)n / 0xFFFFFF; 00546 #else 00547 char tmp[3]; 00548 fread(tmp, 3, 1, p->fp); 00549 uint32_t n = (((uint32_t)tmp[2] << 16) | ((uint32_t)tmp[1] << 8) | ((uint32_t)tmp[0] << 0)) ^ (1 << 23); 00550 data->channel_data[i] = (double)n / 0xFFFFFF; 00551 #endif 00552 } 00553 p->data_byte_count-=3; 00554 break; 00555 default: 00556 return WavFileResultErrorUnsupportedBitsPerSample; 00557 } 00558 } 00559 return WavFileResultOK; 00560 } 00561 00562 WavFileResult wavfile_write_info(WAVFILE *p, const wavfile_info_t *info) { 00563 WavFileResult result = WavFileResultOK; 00564 00565 if (p == NULL) { 00566 result = WavFileResultErrorInvalidHandler; 00567 goto finalize; 00568 } 00569 00570 if (p->info_checked) { 00571 result = WavFileResultErrorAlreadyInfoChecked; 00572 goto finalize; 00573 } 00574 00575 if (p->mode != WavFileModeWrite) { 00576 result = WavFileResultErrorInvalidMode; 00577 goto finalize; 00578 } 00579 00580 p->info.audio_format = info->audio_format; 00581 p->info.num_channels = info->num_channels; 00582 p->info.sample_rate = info->sample_rate; 00583 p->info.byte_rate = info->byte_rate; 00584 p->info.block_align = info->block_align; 00585 p->info.bits_per_sample = info->bits_per_sample; 00586 00587 /* 00588 * 00589 */ 00590 00591 if ((info->audio_format != WAVFILE_AUDIO_FORMAT_PCM) && (info->audio_format != WAVFILE_AUDIO_FORMAT_EXTENSIBLE)) { 00592 result = WavFileResultErrorInvalidAudioFormat; 00593 goto finalize; 00594 } 00595 00596 if ((info->bits_per_sample != BITS_PER_SAMPLE_8) 00597 && (info->bits_per_sample != BITS_PER_SAMPLE_16) 00598 && (info->bits_per_sample != BITS_PER_SAMPLE_24)) { 00599 result = WavFileResultErrorUnsupportedBitsPerSample; 00600 goto finalize; 00601 } 00602 00603 if ((info->num_channels * info->sample_rate * (info->bits_per_sample / 8)) != info->byte_rate) { 00604 result = WavFileResultErrorInvalidByteRate; 00605 goto finalize; 00606 } 00607 00608 /* 00609 * [RIFF] 00610 * ------------------------------------------ 00611 * Big endian 4 bytes : Chunk ID 00612 * Little endian 4 bytes : Chunk size 00613 * Big endian 4 bytes : Format 00614 * ------------------------------------------ 00615 */ 00616 if (WRITE_U32_BE(p->fp, CHUNK_ID_RIFF) != 0) { 00617 result = WavFileResultErrorFileWrite; 00618 goto finalize; 00619 } 00620 if (WRITE_U32_LE(p->fp, 0x00000000) != 0) { 00621 result = WavFileResultErrorFileWrite; 00622 goto finalize; 00623 } 00624 if (WRITE_U32_BE(p->fp, RIFF_CHUNK_FORMAT_WAVE) != 0) { 00625 result = WavFileResultErrorFileWrite; 00626 goto finalize; 00627 } 00628 00629 /* 00630 * [fmt] 00631 * ------------------------------------------ 00632 * Big endian 4 bytes : Sub chunk ID 00633 * Little endian 4 bytes : Sub chunk size 00634 * Little endian 2 bytes : Audio format 00635 * Little endian 2 bytes : Number of channels 00636 * Little endian 4 bytes : Sample rate 00637 * Little endian 4 bytes : Byte rate 00638 * Little endian 2 bytes : Block align 00639 * Little endian 2 bytes : Bits per sample 00640 * . . 00641 * . Additional bytes here (extensible) . 00642 * . . 00643 * ------------------------------------------ 00644 */ 00645 switch (info->audio_format) { 00646 case WAVFILE_AUDIO_FORMAT_PCM: { 00647 if (WRITE_U32_BE(p->fp, CHUNK_ID_FMT) != 0) { 00648 result = WavFileResultErrorFileWrite; 00649 goto finalize; 00650 } 00651 if (WRITE_U32_LE(p->fp, CHUNK_SIZE_FMT_PCM) != 0) { 00652 result = WavFileResultErrorFileWrite; 00653 goto finalize; 00654 } 00655 if (WRITE_U16_LE(p->fp, info->audio_format) != 0) { 00656 result = WavFileResultErrorFileWrite; 00657 goto finalize; 00658 } 00659 if (WRITE_U16_LE(p->fp, info->num_channels) != 0) { 00660 result = WavFileResultErrorFileWrite; 00661 goto finalize; 00662 } 00663 if (WRITE_U32_LE(p->fp, info->sample_rate) != 0) { 00664 result = WavFileResultErrorFileWrite; 00665 goto finalize; 00666 } 00667 if (WRITE_U32_LE(p->fp, info->byte_rate) != 0) { 00668 result = WavFileResultErrorFileWrite; 00669 goto finalize; 00670 } 00671 if (WRITE_U16_LE(p->fp, info->block_align) != 0) { 00672 result = WavFileResultErrorFileWrite; 00673 goto finalize; 00674 } 00675 if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) { 00676 result = WavFileResultErrorFileWrite; 00677 goto finalize; 00678 } 00679 } 00680 break; 00681 case WAVFILE_AUDIO_FORMAT_EXTENSIBLE: { 00682 if (WRITE_U32_BE(p->fp, CHUNK_ID_FMT) != 0) { 00683 result = WavFileResultErrorFileWrite; 00684 goto finalize; 00685 } 00686 if (WRITE_U32_LE(p->fp, CHUNK_SIZE_FMT_EXTENSIBLE) != 0) { 00687 result = WavFileResultErrorFileWrite; 00688 goto finalize; 00689 } 00690 if (WRITE_U16_LE(p->fp, info->audio_format) != 0) { 00691 result = WavFileResultErrorFileWrite; 00692 goto finalize; 00693 } 00694 if (WRITE_U16_LE(p->fp, info->num_channels) != 0) { 00695 result = WavFileResultErrorFileWrite; 00696 goto finalize; 00697 } 00698 if (WRITE_U32_LE(p->fp, info->sample_rate) != 0) { 00699 result = WavFileResultErrorFileWrite; 00700 goto finalize; 00701 } 00702 if (WRITE_U32_LE(p->fp, info->byte_rate) != 0) { 00703 result = WavFileResultErrorFileWrite; 00704 goto finalize; 00705 } 00706 if (WRITE_U16_LE(p->fp, info->block_align) != 0) { 00707 result = WavFileResultErrorFileWrite; 00708 goto finalize; 00709 } 00710 if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) { 00711 result = WavFileResultErrorFileWrite; 00712 goto finalize; 00713 } 00714 /* 00715 * Additional bytes for the extensible format. 00716 * 00717 * 2 bytes : Size of the extension (0 or 22) 00718 * 2 bytes : Number of valid bits 00719 * 4 bytes : Speaker position mask 00720 * 16 bytes : GUID, including the data format code 00721 */ 00722 if (WRITE_U16_LE(p->fp, 22) != 0) { 00723 result = WavFileResultErrorFileWrite; 00724 goto finalize; 00725 } 00726 if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) { 00727 result = WavFileResultErrorFileWrite; 00728 goto finalize; 00729 } 00730 if (WRITE_U32_LE(p->fp, 0x00000000) != 0) { 00731 result = WavFileResultErrorFileWrite; 00732 goto finalize; 00733 } 00734 static const unsigned char sub_format[16] = { 00735 0x01, 0x00, 0x00, 0x00, 00736 0x00, 0x00, 0x10, 0x00, 00737 0x80, 0x00, 0x00, 0xAA, 00738 0x00, 0x38, 0x9B, 0x71 00739 }; 00740 for (int i = 0; i < sizeof(sub_format); i++) { 00741 fputc((char)sub_format[i], p->fp); 00742 } 00743 } 00744 break; 00745 default: 00746 result = WavFileResultErrorInvalidAudioFormat; 00747 goto finalize; 00748 } 00749 00750 /* 00751 * [data] 00752 * ------------------------------------------ 00753 * Big endian 4 bytes : Sub chunk ID 00754 * Little endian 4 bytes : Sub chunk size 00755 * ------------------------------------------ 00756 * Little endian 2 bytes : Sample 1 (Ch.1) 00757 * Little endian 2 bytes : Sample 1 (Ch.2) 00758 * . 00759 * . 00760 * . 00761 * Little endian 2 bytes : Sample 1 (Ch.N) 00762 * ------------------------------------------ 00763 * Little endian 2 bytes : Sample 2 (Ch.1) 00764 * Little endian 2 bytes : Sample 2 (Ch.2) 00765 * . 00766 * . 00767 * . 00768 * Little endian 2 bytes : Sample 2 (Ch.N) 00769 * ------------------------------------------ 00770 */ 00771 if (WRITE_U32_BE(p->fp, CHUNK_ID_DATA) != 0) { 00772 result = WavFileResultErrorFileWrite; 00773 goto finalize; 00774 } 00775 if (WRITE_U32_LE(p->fp, 0x00000000) != 0) { 00776 result = WavFileResultErrorFileWrite; 00777 goto finalize; 00778 } 00779 00780 finalize: 00781 if (WavFileResultOK == result) { 00782 p->info_checked = true; 00783 } 00784 return result; 00785 } 00786 00787 /** 00788 */ 00789 WavFileResult wavfile_write_data(WAVFILE *p, const wavfile_data_t *data) { 00790 WavFileResult result = WavFileResultOK; 00791 00792 if (p == NULL) { 00793 result = WavFileResultErrorInvalidHandler; 00794 goto finalize; 00795 } 00796 00797 if (!p->info_checked) { 00798 result = WavFileResultErrorNeedInfoChecked; 00799 goto finalize; 00800 } 00801 00802 if (p->mode != WavFileModeWrite) { 00803 result = WavFileResultErrorInvalidMode; 00804 goto finalize; 00805 } 00806 00807 if (p->info.num_channels != data->num_channels) { 00808 result = WavFileResultErrorInvalidNumChannels; 00809 goto finalize; 00810 } 00811 00812 for (int i = 0; i < p->info.num_channels; i++) { 00813 switch (p->info.bits_per_sample) { 00814 case BITS_PER_SAMPLE_8: { 00815 int n = (int)((double)data->channel_data[i] * 0xFF); 00816 if (n < 0x00) { 00817 n = 0x00; 00818 } 00819 if (0xFF < n) { 00820 n = 0xFF; 00821 } 00822 fputc((char)n, p->fp); 00823 } 00824 p->data_byte_count+=1; 00825 break; 00826 case BITS_PER_SAMPLE_16: { 00827 int n = (int)((double)(data->channel_data[i] * 0xFFFF) - 0x8000); 00828 if (0x7FFF < n) { 00829 n = 0x7FFF; 00830 } 00831 if (n < -0x8000) { 00832 n = -0x8000; 00833 } 00834 fputc(((uint16_t)n >> 0) & 0xff, p->fp); 00835 fputc(((uint16_t)n >> 8) & 0xff, p->fp); 00836 } 00837 p->data_byte_count+=2; 00838 break; 00839 case BITS_PER_SAMPLE_24: { 00840 int n = (int)((double)(data->channel_data[i] * 0xFFFFFF) - 0x800000); 00841 if (0x7FFFFF < n) { 00842 n = 0x7FFFFF; 00843 } 00844 if (n < -0x800000) { 00845 n = -0x800000; 00846 } 00847 fputc(((uint32_t)n >> 0) & 0xff, p->fp); 00848 fputc(((uint32_t)n >> 8) & 0xff, p->fp); 00849 fputc(((uint32_t)n >> 16) & 0xff, p->fp); 00850 } 00851 p->data_byte_count+=3; 00852 break; 00853 } 00854 } 00855 p->data_checked = true; 00856 00857 finalize: 00858 return result; 00859 } 00860 00861 WavFileResult wavfile_close(WAVFILE *p) { 00862 WavFileResult result = WavFileResultOK; 00863 00864 switch (p->mode) { 00865 case WavFileModeRead: 00866 break; 00867 case WavFileModeWrite: 00868 if (p->info_checked && p->data_checked) { 00869 switch (p->info.audio_format) { 00870 case WAVFILE_AUDIO_FORMAT_PCM: { 00871 /* 00872 * Fill the RIFF chunk size. 00873 */ 00874 if (fseek(p->fp, 4L, SEEK_SET) == -1) { 00875 result = WavFileResultErrorFileWrite; 00876 goto finalize; 00877 } 00878 if (WRITE_U32_LE(p->fp, 4 + (8 + CHUNK_SIZE_FMT_PCM) + (8 + p->data_byte_count)) != 0) { 00879 result = WavFileResultErrorFileWrite; 00880 goto finalize; 00881 } 00882 00883 /* 00884 * Fill the data sub chunk size. 00885 */ 00886 if (fseek(p->fp, 12 + (8 + CHUNK_SIZE_FMT_PCM) + 4, SEEK_SET) == -1) { 00887 result = WavFileResultErrorFileWrite; 00888 goto finalize; 00889 } 00890 if (WRITE_U32_LE(p->fp, p->data_byte_count) != 0) { 00891 result = WavFileResultErrorFileWrite; 00892 goto finalize; 00893 } 00894 } 00895 break; 00896 case WAVFILE_AUDIO_FORMAT_EXTENSIBLE: { 00897 /* 00898 * Fill the RIFF chunk size. 00899 */ 00900 if (fseek(p->fp, 4L, SEEK_SET) == -1) { 00901 result = WavFileResultErrorFileWrite; 00902 goto finalize; 00903 } 00904 if (WRITE_U32_LE(p->fp, 4 + (8 + CHUNK_SIZE_FMT_EXTENSIBLE) + (8 + p->data_byte_count)) != 0) { 00905 result = WavFileResultErrorFileWrite; 00906 goto finalize; 00907 } 00908 00909 /* 00910 * Fill the data sub chunk size. 00911 */ 00912 if (fseek(p->fp, 12 + (8 + CHUNK_SIZE_FMT_EXTENSIBLE) + 4, SEEK_SET) == -1) { 00913 result = WavFileResultErrorFileWrite; 00914 goto finalize; 00915 } 00916 if (WRITE_U32_LE(p->fp, p->data_byte_count) != 0) { 00917 result = WavFileResultErrorFileWrite; 00918 goto finalize; 00919 } 00920 } 00921 break; 00922 } 00923 } 00924 break; 00925 } 00926 00927 finalize: 00928 fclose(p->fp); 00929 free(p); 00930 return result; 00931 } 00932 00933 void wavfile_result_string(const WavFileResult result, char *buf, size_t siz) { 00934 switch (result) { 00935 case WavFileResultOK: 00936 strcpy(buf, "OK."); 00937 break; 00938 case WavFileResultErrorInvalidFileName: 00939 strcpy(buf, "Invalid file name found."); 00940 break; 00941 case WavFileResultErrorMemoryAllocation: 00942 strcpy(buf, "Memory allocation error."); 00943 break; 00944 case WavFileResultErrorFileOpen: 00945 strcpy(buf, "File open error found."); 00946 break; 00947 case WavFileResultErrorFileWrite: 00948 strcpy(buf, "File write error found."); 00949 break; 00950 case WavFileResultErrorBrokenChunkId: 00951 strcpy(buf, "Broken chunk ID found."); 00952 break; 00953 case WavFileResultErrorBrokenChunkSize: 00954 strcpy(buf, "Borken chunk size found."); 00955 break; 00956 case WavFileResultErrorBrokenChunkData: 00957 strcpy(buf, "Borken chunk data found."); 00958 break; 00959 case WavFileResultErrorBrokenFormatId: 00960 strcpy(buf, "Broken format ID found."); 00961 break; 00962 case WavFileResultErrorInvalidFormatId: 00963 strcpy(buf, "Invalid format ID found."); 00964 break; 00965 case WavFileResultErrorBrokenAudioFormat: 00966 strcpy(buf, "Broken audio format found."); 00967 break; 00968 case WavFileResultErrorInvalidAudioFormat: 00969 strcpy(buf, "Invalid audio format found."); 00970 break; 00971 case WavFileResultErrorInvalidNumChannels: 00972 strcpy(buf, "Invalid number of channels found."); 00973 break; 00974 case WavFileResultErrorBrokenNumChannels: 00975 strcpy(buf, "Broken number of channels found."); 00976 break; 00977 case WavFileResultErrorBrokenSampleRate: 00978 strcpy(buf, "Broken sample rate found."); 00979 break; 00980 case WavFileResultErrorBrokenByteRate: 00981 strcpy(buf, "Broken byte rate found."); 00982 break; 00983 case WavFileResultErrorInvalidByteRate: 00984 strcpy(buf, "Invalid byte rate found."); 00985 break; 00986 case WavFileResultErrorBrokenBlockAlign: 00987 strcpy(buf, "Broken block alignment found."); 00988 break; 00989 case WavFileResultErrorBrokenBitsPerSample: 00990 strcpy(buf, "Broken bits per sample found."); 00991 break; 00992 case WavFileResultErrorUnsupportedBitsPerSample: 00993 strcpy(buf, "Unsupported bits per sample found."); 00994 break; 00995 case WavFileResultErrorAlreadyInfoChecked: 00996 strcpy(buf, "Already checked info."); 00997 break; 00998 case WavFileResultErrorAlreadyDataChecked: 00999 strcpy(buf, "Already checked data."); 01000 break; 01001 case WavFileResultErrorNoDataChunk: 01002 strcpy(buf, "No data chunk."); 01003 break; 01004 case WavFileResultErrorInvalidMode: 01005 strcpy(buf, "Invalid mode."); 01006 break; 01007 case WavFileResultErrorNeedInfoChecked: 01008 strcpy(buf, "Need check info."); 01009 break; 01010 case WavFileResultErrorNeedDataChecked: 01011 strcpy(buf, "Need check data."); 01012 break; 01013 case WavFileResultErrorInvalidHandler: 01014 strcpy(buf, "Invalid handler."); 01015 break; 01016 default: 01017 strcpy(buf, "Unkonwn error found."); 01018 break; 01019 } 01020 } 01021
Generated on Wed Jul 13 2022 05:38:00 by 1.7.2