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

Committer:
shintamainjp
Date:
Sat Apr 14 02:13:30 2012 +0000
Revision:
0:c853ba46d0b9
Initial version of the tiny wav I/O module for mbed.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shintamainjp 0:c853ba46d0b9 1 /**
shintamainjp 0:c853ba46d0b9 2 * @file wavfile.cpp
shintamainjp 0:c853ba46d0b9 3 * @author Shinichiro Nakamura
shintamainjp 0:c853ba46d0b9 4 */
shintamainjp 0:c853ba46d0b9 5
shintamainjp 0:c853ba46d0b9 6 /*
shintamainjp 0:c853ba46d0b9 7 * ===============================================================
shintamainjp 0:c853ba46d0b9 8 * Tiny WAV I/O Module
shintamainjp 0:c853ba46d0b9 9 * Version 0.0.1
shintamainjp 0:c853ba46d0b9 10 * ===============================================================
shintamainjp 0:c853ba46d0b9 11 * Copyright (c) 2011-2012 Shinichiro Nakamura
shintamainjp 0:c853ba46d0b9 12 *
shintamainjp 0:c853ba46d0b9 13 * Permission is hereby granted, free of charge, to any person
shintamainjp 0:c853ba46d0b9 14 * obtaining a copy of this software and associated documentation
shintamainjp 0:c853ba46d0b9 15 * files (the "Software"), to deal in the Software without
shintamainjp 0:c853ba46d0b9 16 * restriction, including without limitation the rights to use,
shintamainjp 0:c853ba46d0b9 17 * copy, modify, merge, publish, distribute, sublicense, and/or
shintamainjp 0:c853ba46d0b9 18 * sell copies of the Software, and to permit persons to whom the
shintamainjp 0:c853ba46d0b9 19 * Software is furnished to do so, subject to the following
shintamainjp 0:c853ba46d0b9 20 * conditions:
shintamainjp 0:c853ba46d0b9 21 *
shintamainjp 0:c853ba46d0b9 22 * The above copyright notice and this permission notice shall be
shintamainjp 0:c853ba46d0b9 23 * included in all copies or substantial portions of the Software.
shintamainjp 0:c853ba46d0b9 24 *
shintamainjp 0:c853ba46d0b9 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
shintamainjp 0:c853ba46d0b9 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
shintamainjp 0:c853ba46d0b9 27 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
shintamainjp 0:c853ba46d0b9 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
shintamainjp 0:c853ba46d0b9 29 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
shintamainjp 0:c853ba46d0b9 30 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
shintamainjp 0:c853ba46d0b9 31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
shintamainjp 0:c853ba46d0b9 32 * OTHER DEALINGS IN THE SOFTWARE.
shintamainjp 0:c853ba46d0b9 33 * ===============================================================
shintamainjp 0:c853ba46d0b9 34 */
shintamainjp 0:c853ba46d0b9 35
shintamainjp 0:c853ba46d0b9 36 #include <stdio.h>
shintamainjp 0:c853ba46d0b9 37 #include <stdlib.h>
shintamainjp 0:c853ba46d0b9 38 #include <string.h>
shintamainjp 0:c853ba46d0b9 39 #include "wavfile.h"
shintamainjp 0:c853ba46d0b9 40
shintamainjp 0:c853ba46d0b9 41 #define DEBUG printf
shintamainjp 0:c853ba46d0b9 42
shintamainjp 0:c853ba46d0b9 43 #define CHUNK_ID_RIFF (('R' << 24) | ('I' << 16) | ('F' << 8) | ('F' << 0))
shintamainjp 0:c853ba46d0b9 44 #define CHUNK_ID_FMT (('f' << 24) | ('m' << 16) | ('t' << 8) | (' ' << 0))
shintamainjp 0:c853ba46d0b9 45 #define CHUNK_ID_DATA (('d' << 24) | ('a' << 16) | ('t' << 8) | ('a' << 0))
shintamainjp 0:c853ba46d0b9 46
shintamainjp 0:c853ba46d0b9 47 #define RIFF_CHUNK_FORMAT_WAVE (('W' << 24) | ('A' << 16) | ('V' << 8) | ('E' << 0))
shintamainjp 0:c853ba46d0b9 48
shintamainjp 0:c853ba46d0b9 49 #define BITS_PER_SAMPLE_8 (8)
shintamainjp 0:c853ba46d0b9 50 #define BITS_PER_SAMPLE_16 (16)
shintamainjp 0:c853ba46d0b9 51 #define BITS_PER_SAMPLE_24 (24)
shintamainjp 0:c853ba46d0b9 52
shintamainjp 0:c853ba46d0b9 53 #define CHUNK_SIZE_FMT_PCM (16)
shintamainjp 0:c853ba46d0b9 54 #define CHUNK_SIZE_FMT_EXTENSIBLE (40)
shintamainjp 0:c853ba46d0b9 55
shintamainjp 0:c853ba46d0b9 56 #define CHANNEL_MASK_SPEAKER_FRONT_LEFT (0x00000001)
shintamainjp 0:c853ba46d0b9 57 #define CHANNEL_MASK_SPEAKER_FRONT_RIGHT (0x00000002)
shintamainjp 0:c853ba46d0b9 58 #define CHANNEL_MASK_SPEAKER_FRONT_CENTER (0x00000004)
shintamainjp 0:c853ba46d0b9 59 #define CHANNEL_MASK_SPEAKER_LOW_FREQUENCY (0x00000008)
shintamainjp 0:c853ba46d0b9 60 #define CHANNEL_MASK_SPEAKER_BACK_LEFT (0x00000010)
shintamainjp 0:c853ba46d0b9 61 #define CHANNEL_MASK_SPEAKER_BACK_RIGHT (0x00000020)
shintamainjp 0:c853ba46d0b9 62 #define CHANNEL_MASK_SPEAKER_FRONT_LEFT_OF_CENTER (0x00000040)
shintamainjp 0:c853ba46d0b9 63 #define CHANNEL_MASK_SPEAKER_FRONT_RIGHT_OF_CENTER (0x00000080)
shintamainjp 0:c853ba46d0b9 64 #define CHANNEL_MASK_SPEAKER_BACK_CENTER (0x00000100)
shintamainjp 0:c853ba46d0b9 65 #define CHANNEL_MASK_SPEAKER_SIDE_LEFT (0x00000200)
shintamainjp 0:c853ba46d0b9 66 #define CHANNEL_MASK_SPEAKER_SIDE_RIGHT (0x00000400)
shintamainjp 0:c853ba46d0b9 67 #define CHANNEL_MASK_SPEAKER_TOP_CENTER (0x00000800)
shintamainjp 0:c853ba46d0b9 68 #define CHANNEL_MASK_SPEAKER_TOP_FRONT_LEFT (0x00001000)
shintamainjp 0:c853ba46d0b9 69 #define CHANNEL_MASK_SPEAKER_TOP_FRONT_CENTER (0x00002000)
shintamainjp 0:c853ba46d0b9 70 #define CHANNEL_MASK_SPEAKER_TOP_FRONT_RIGHT (0x00004000)
shintamainjp 0:c853ba46d0b9 71 #define CHANNEL_MASK_SPEAKER_TOP_BACK_LEFT (0x00008000)
shintamainjp 0:c853ba46d0b9 72 #define CHANNEL_MASK_SPEAKER_TOP_BACK_CENTER (0x00010000)
shintamainjp 0:c853ba46d0b9 73 #define CHANNEL_MASK_SPEAKER_TOP_BACK_RIGHT (0x00020000)
shintamainjp 0:c853ba46d0b9 74 #define CHANNEL_MASK_SPEAKER_RESERVED (0x80000000)
shintamainjp 0:c853ba46d0b9 75
shintamainjp 0:c853ba46d0b9 76 struct WAVFILE {
shintamainjp 0:c853ba46d0b9 77 FILE *fp;
shintamainjp 0:c853ba46d0b9 78 char filename[BUFSIZ];
shintamainjp 0:c853ba46d0b9 79 WavFileMode mode;
shintamainjp 0:c853ba46d0b9 80 bool info_checked;
shintamainjp 0:c853ba46d0b9 81 bool data_checked;
shintamainjp 0:c853ba46d0b9 82 uint32_t data_byte_count;
shintamainjp 0:c853ba46d0b9 83 wavfile_info_t info;
shintamainjp 0:c853ba46d0b9 84 };
shintamainjp 0:c853ba46d0b9 85
shintamainjp 0:c853ba46d0b9 86 static int WRITE_U32_BE(FILE *fp, const uint32_t value) {
shintamainjp 0:c853ba46d0b9 87 for (int i = 0; i < 4; i++) {
shintamainjp 0:c853ba46d0b9 88 if (fputc((value >> (8 * (3 - i))), fp) == EOF) {
shintamainjp 0:c853ba46d0b9 89 return -1;
shintamainjp 0:c853ba46d0b9 90 }
shintamainjp 0:c853ba46d0b9 91 }
shintamainjp 0:c853ba46d0b9 92 return 0;
shintamainjp 0:c853ba46d0b9 93 }
shintamainjp 0:c853ba46d0b9 94
shintamainjp 0:c853ba46d0b9 95 static int WRITE_U32_LE(FILE *fp, const uint32_t value) {
shintamainjp 0:c853ba46d0b9 96 for (int i = 0; i < 4; i++) {
shintamainjp 0:c853ba46d0b9 97 if (fputc((value >> (8 * i)), fp) == EOF) {
shintamainjp 0:c853ba46d0b9 98 return -1;
shintamainjp 0:c853ba46d0b9 99 }
shintamainjp 0:c853ba46d0b9 100 }
shintamainjp 0:c853ba46d0b9 101 return 0;
shintamainjp 0:c853ba46d0b9 102 }
shintamainjp 0:c853ba46d0b9 103
shintamainjp 0:c853ba46d0b9 104 static int WRITE_U16_LE(FILE *fp, const uint16_t value) {
shintamainjp 0:c853ba46d0b9 105 for (int i = 0; i < 2; i++) {
shintamainjp 0:c853ba46d0b9 106 if (fputc((value >> (8 * i)), fp) == EOF) {
shintamainjp 0:c853ba46d0b9 107 return -1;
shintamainjp 0:c853ba46d0b9 108 }
shintamainjp 0:c853ba46d0b9 109 }
shintamainjp 0:c853ba46d0b9 110 return 0;
shintamainjp 0:c853ba46d0b9 111 }
shintamainjp 0:c853ba46d0b9 112
shintamainjp 0:c853ba46d0b9 113 static int READ_U32_BE(FILE *fp, uint32_t *value) {
shintamainjp 0:c853ba46d0b9 114 int raw[4];
shintamainjp 0:c853ba46d0b9 115 for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) {
shintamainjp 0:c853ba46d0b9 116 raw[i] = fgetc(fp);
shintamainjp 0:c853ba46d0b9 117 if (raw[i] == EOF) {
shintamainjp 0:c853ba46d0b9 118 *value = 0x00000000;
shintamainjp 0:c853ba46d0b9 119 return -1;
shintamainjp 0:c853ba46d0b9 120 }
shintamainjp 0:c853ba46d0b9 121 }
shintamainjp 0:c853ba46d0b9 122 *value =
shintamainjp 0:c853ba46d0b9 123 ((uint32_t)raw[0] << 24) |
shintamainjp 0:c853ba46d0b9 124 ((uint32_t)raw[1] << 16) |
shintamainjp 0:c853ba46d0b9 125 ((uint32_t)raw[2] << 8) |
shintamainjp 0:c853ba46d0b9 126 ((uint32_t)raw[3] << 0);
shintamainjp 0:c853ba46d0b9 127 return 0;
shintamainjp 0:c853ba46d0b9 128 }
shintamainjp 0:c853ba46d0b9 129
shintamainjp 0:c853ba46d0b9 130 static int READ_U32_LE(FILE *fp, uint32_t *value) {
shintamainjp 0:c853ba46d0b9 131 int raw[4];
shintamainjp 0:c853ba46d0b9 132 for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) {
shintamainjp 0:c853ba46d0b9 133 raw[i] = fgetc(fp);
shintamainjp 0:c853ba46d0b9 134 if (raw[i] == EOF) {
shintamainjp 0:c853ba46d0b9 135 *value = 0x00000000;
shintamainjp 0:c853ba46d0b9 136 return -1;
shintamainjp 0:c853ba46d0b9 137 }
shintamainjp 0:c853ba46d0b9 138 }
shintamainjp 0:c853ba46d0b9 139 *value =
shintamainjp 0:c853ba46d0b9 140 ((uint32_t)raw[3] << 24) |
shintamainjp 0:c853ba46d0b9 141 ((uint32_t)raw[2] << 16) |
shintamainjp 0:c853ba46d0b9 142 ((uint32_t)raw[1] << 8) |
shintamainjp 0:c853ba46d0b9 143 ((uint32_t)raw[0] << 0);
shintamainjp 0:c853ba46d0b9 144 return 0;
shintamainjp 0:c853ba46d0b9 145 }
shintamainjp 0:c853ba46d0b9 146
shintamainjp 0:c853ba46d0b9 147 static int READ_U16_LE(FILE *fp, uint16_t *value) {
shintamainjp 0:c853ba46d0b9 148 int raw[2];
shintamainjp 0:c853ba46d0b9 149 for (int i = 0; i < (int)(sizeof(raw) / sizeof(raw[0])); i++) {
shintamainjp 0:c853ba46d0b9 150 raw[i] = fgetc(fp);
shintamainjp 0:c853ba46d0b9 151 if (raw[i] == EOF) {
shintamainjp 0:c853ba46d0b9 152 *value = 0x00000000;
shintamainjp 0:c853ba46d0b9 153 return -1;
shintamainjp 0:c853ba46d0b9 154 }
shintamainjp 0:c853ba46d0b9 155 }
shintamainjp 0:c853ba46d0b9 156 *value =
shintamainjp 0:c853ba46d0b9 157 ((uint16_t)raw[1] << 8) |
shintamainjp 0:c853ba46d0b9 158 ((uint16_t)raw[0] << 0);
shintamainjp 0:c853ba46d0b9 159 return 0;
shintamainjp 0:c853ba46d0b9 160 }
shintamainjp 0:c853ba46d0b9 161
shintamainjp 0:c853ba46d0b9 162 static WavFileResult chunk_reader_unknown(
shintamainjp 0:c853ba46d0b9 163 const uint32_t chunk_id,
shintamainjp 0:c853ba46d0b9 164 const uint32_t chunk_size,
shintamainjp 0:c853ba46d0b9 165 FILE *fp) {
shintamainjp 0:c853ba46d0b9 166 for (int i = 0; i < (int)chunk_size; i++) {
shintamainjp 0:c853ba46d0b9 167 int c = fgetc(fp);
shintamainjp 0:c853ba46d0b9 168 if (c == EOF) {
shintamainjp 0:c853ba46d0b9 169 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 170 }
shintamainjp 0:c853ba46d0b9 171 }
shintamainjp 0:c853ba46d0b9 172 return WavFileResultOK;
shintamainjp 0:c853ba46d0b9 173 }
shintamainjp 0:c853ba46d0b9 174
shintamainjp 0:c853ba46d0b9 175 static WavFileResult chunk_reader_riff(
shintamainjp 0:c853ba46d0b9 176 const uint32_t chunk_id,
shintamainjp 0:c853ba46d0b9 177 const uint32_t chunk_size,
shintamainjp 0:c853ba46d0b9 178 FILE *fp,
shintamainjp 0:c853ba46d0b9 179 uint32_t *format_id) {
shintamainjp 0:c853ba46d0b9 180 if (READ_U32_BE(fp, format_id) != 0) {
shintamainjp 0:c853ba46d0b9 181 return WavFileResultErrorBrokenFormatId;
shintamainjp 0:c853ba46d0b9 182 }
shintamainjp 0:c853ba46d0b9 183 return WavFileResultOK;
shintamainjp 0:c853ba46d0b9 184 }
shintamainjp 0:c853ba46d0b9 185
shintamainjp 0:c853ba46d0b9 186 static WavFileResult chunk_reader_fmt(
shintamainjp 0:c853ba46d0b9 187 const uint32_t chunk_id,
shintamainjp 0:c853ba46d0b9 188 const uint32_t chunk_size,
shintamainjp 0:c853ba46d0b9 189 FILE *fp,
shintamainjp 0:c853ba46d0b9 190 uint16_t *audio_format,
shintamainjp 0:c853ba46d0b9 191 uint16_t *num_channels,
shintamainjp 0:c853ba46d0b9 192 uint32_t *sample_rate,
shintamainjp 0:c853ba46d0b9 193 uint32_t *byte_rate,
shintamainjp 0:c853ba46d0b9 194 uint16_t *block_align,
shintamainjp 0:c853ba46d0b9 195 uint16_t *bits_per_sample) {
shintamainjp 0:c853ba46d0b9 196 uint32_t read_byte_count = 0;
shintamainjp 0:c853ba46d0b9 197
shintamainjp 0:c853ba46d0b9 198 /*
shintamainjp 0:c853ba46d0b9 199 * 2
shintamainjp 0:c853ba46d0b9 200 */
shintamainjp 0:c853ba46d0b9 201 if (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 202 if (READ_U16_LE(fp, audio_format) != 0) {
shintamainjp 0:c853ba46d0b9 203 return WavFileResultErrorBrokenAudioFormat;
shintamainjp 0:c853ba46d0b9 204 }
shintamainjp 0:c853ba46d0b9 205 }
shintamainjp 0:c853ba46d0b9 206 read_byte_count+=2;
shintamainjp 0:c853ba46d0b9 207
shintamainjp 0:c853ba46d0b9 208 /*
shintamainjp 0:c853ba46d0b9 209 * 2 + 2
shintamainjp 0:c853ba46d0b9 210 */
shintamainjp 0:c853ba46d0b9 211 if (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 212 if (READ_U16_LE(fp, num_channels) != 0) {
shintamainjp 0:c853ba46d0b9 213 return WavFileResultErrorBrokenNumChannels;
shintamainjp 0:c853ba46d0b9 214 }
shintamainjp 0:c853ba46d0b9 215 }
shintamainjp 0:c853ba46d0b9 216 read_byte_count+=2;
shintamainjp 0:c853ba46d0b9 217
shintamainjp 0:c853ba46d0b9 218 /*
shintamainjp 0:c853ba46d0b9 219 * 2 + 2 + 4
shintamainjp 0:c853ba46d0b9 220 */
shintamainjp 0:c853ba46d0b9 221 if (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 222 if (READ_U32_LE(fp, sample_rate) != 0) {
shintamainjp 0:c853ba46d0b9 223 return WavFileResultErrorBrokenSampleRate;
shintamainjp 0:c853ba46d0b9 224 }
shintamainjp 0:c853ba46d0b9 225 }
shintamainjp 0:c853ba46d0b9 226 read_byte_count+=4;
shintamainjp 0:c853ba46d0b9 227
shintamainjp 0:c853ba46d0b9 228 /*
shintamainjp 0:c853ba46d0b9 229 * 2 + 2 + 4 + 4
shintamainjp 0:c853ba46d0b9 230 */
shintamainjp 0:c853ba46d0b9 231 if (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 232 if (READ_U32_LE(fp, byte_rate) != 0) {
shintamainjp 0:c853ba46d0b9 233 return WavFileResultErrorBrokenByteRate;
shintamainjp 0:c853ba46d0b9 234 }
shintamainjp 0:c853ba46d0b9 235 }
shintamainjp 0:c853ba46d0b9 236 read_byte_count+=4;
shintamainjp 0:c853ba46d0b9 237
shintamainjp 0:c853ba46d0b9 238 /*
shintamainjp 0:c853ba46d0b9 239 * 2 + 2 + 4 + 4 + 2
shintamainjp 0:c853ba46d0b9 240 */
shintamainjp 0:c853ba46d0b9 241 if (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 242 if (READ_U16_LE(fp, block_align) != 0) {
shintamainjp 0:c853ba46d0b9 243 return WavFileResultErrorBrokenBlockAlign;
shintamainjp 0:c853ba46d0b9 244 }
shintamainjp 0:c853ba46d0b9 245 }
shintamainjp 0:c853ba46d0b9 246 read_byte_count+=2;
shintamainjp 0:c853ba46d0b9 247
shintamainjp 0:c853ba46d0b9 248 /*
shintamainjp 0:c853ba46d0b9 249 * 2 + 2 + 4 + 4 + 2 + 2
shintamainjp 0:c853ba46d0b9 250 */
shintamainjp 0:c853ba46d0b9 251 if (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 252 if (READ_U16_LE(fp, bits_per_sample) != 0) {
shintamainjp 0:c853ba46d0b9 253 return WavFileResultErrorBrokenBitsPerSample;
shintamainjp 0:c853ba46d0b9 254 }
shintamainjp 0:c853ba46d0b9 255 }
shintamainjp 0:c853ba46d0b9 256 read_byte_count+=2;
shintamainjp 0:c853ba46d0b9 257
shintamainjp 0:c853ba46d0b9 258 /*
shintamainjp 0:c853ba46d0b9 259 * 2 + 2 + 4 + 4 + 2 + 2
shintamainjp 0:c853ba46d0b9 260 */
shintamainjp 0:c853ba46d0b9 261 while (read_byte_count < chunk_size) {
shintamainjp 0:c853ba46d0b9 262 if (fgetc(fp) == EOF) {
shintamainjp 0:c853ba46d0b9 263 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 264 }
shintamainjp 0:c853ba46d0b9 265 read_byte_count++;
shintamainjp 0:c853ba46d0b9 266 }
shintamainjp 0:c853ba46d0b9 267
shintamainjp 0:c853ba46d0b9 268 return WavFileResultOK;
shintamainjp 0:c853ba46d0b9 269 }
shintamainjp 0:c853ba46d0b9 270
shintamainjp 0:c853ba46d0b9 271 WAVFILE *wavfile_open(const char *filename, WavFileMode mode, WavFileResult *result) {
shintamainjp 0:c853ba46d0b9 272 /*
shintamainjp 0:c853ba46d0b9 273 * Verify the filename.
shintamainjp 0:c853ba46d0b9 274 */
shintamainjp 0:c853ba46d0b9 275 if (filename == NULL) {
shintamainjp 0:c853ba46d0b9 276 *result = WavFileResultErrorInvalidFileName;
shintamainjp 0:c853ba46d0b9 277 return NULL;
shintamainjp 0:c853ba46d0b9 278 }
shintamainjp 0:c853ba46d0b9 279
shintamainjp 0:c853ba46d0b9 280 /*
shintamainjp 0:c853ba46d0b9 281 * Open the file.
shintamainjp 0:c853ba46d0b9 282 */
shintamainjp 0:c853ba46d0b9 283 FILE *fp = NULL;
shintamainjp 0:c853ba46d0b9 284 switch (mode) {
shintamainjp 0:c853ba46d0b9 285 case WavFileModeRead:
shintamainjp 0:c853ba46d0b9 286 fp = fopen(filename, "rb");
shintamainjp 0:c853ba46d0b9 287 break;
shintamainjp 0:c853ba46d0b9 288 case WavFileModeWrite:
shintamainjp 0:c853ba46d0b9 289 fp = fopen(filename, "wb");
shintamainjp 0:c853ba46d0b9 290 break;
shintamainjp 0:c853ba46d0b9 291 default:
shintamainjp 0:c853ba46d0b9 292 fp = NULL;
shintamainjp 0:c853ba46d0b9 293 break;
shintamainjp 0:c853ba46d0b9 294 }
shintamainjp 0:c853ba46d0b9 295 if (fp == NULL) {
shintamainjp 0:c853ba46d0b9 296 *result = WavFileResultErrorFileOpen;
shintamainjp 0:c853ba46d0b9 297 return NULL;
shintamainjp 0:c853ba46d0b9 298 }
shintamainjp 0:c853ba46d0b9 299
shintamainjp 0:c853ba46d0b9 300 /*
shintamainjp 0:c853ba46d0b9 301 * Allocate the handler.
shintamainjp 0:c853ba46d0b9 302 */
shintamainjp 0:c853ba46d0b9 303 WAVFILE *p = (WAVFILE *)malloc(sizeof(WAVFILE));
shintamainjp 0:c853ba46d0b9 304 if (p == NULL) {
shintamainjp 0:c853ba46d0b9 305 *result = WavFileResultErrorMemoryAllocation;
shintamainjp 0:c853ba46d0b9 306 return NULL;
shintamainjp 0:c853ba46d0b9 307 }
shintamainjp 0:c853ba46d0b9 308
shintamainjp 0:c853ba46d0b9 309 /*
shintamainjp 0:c853ba46d0b9 310 * Fill the fields.
shintamainjp 0:c853ba46d0b9 311 */
shintamainjp 0:c853ba46d0b9 312 p->fp = fp;
shintamainjp 0:c853ba46d0b9 313 strcpy(p->filename, filename);
shintamainjp 0:c853ba46d0b9 314 p->mode = mode;
shintamainjp 0:c853ba46d0b9 315 p->info_checked = false;
shintamainjp 0:c853ba46d0b9 316 p->data_checked = false;
shintamainjp 0:c853ba46d0b9 317 p->data_byte_count = 0;
shintamainjp 0:c853ba46d0b9 318 WAVFILE_INFO_AUDIO_FORMAT(&(p->info)) = 0;
shintamainjp 0:c853ba46d0b9 319 WAVFILE_INFO_NUM_CHANNELS(&(p->info)) = 0;
shintamainjp 0:c853ba46d0b9 320 WAVFILE_INFO_SAMPLE_RATE(&(p->info)) = 0;
shintamainjp 0:c853ba46d0b9 321 WAVFILE_INFO_BYTE_RATE(&(p->info)) = 0;
shintamainjp 0:c853ba46d0b9 322 WAVFILE_INFO_BLOCK_ALIGN(&(p->info)) = 0;
shintamainjp 0:c853ba46d0b9 323 WAVFILE_INFO_BITS_PER_SAMPLE(&(p->info)) = 0;
shintamainjp 0:c853ba46d0b9 324
shintamainjp 0:c853ba46d0b9 325 *result = WavFileResultOK;
shintamainjp 0:c853ba46d0b9 326 return p;
shintamainjp 0:c853ba46d0b9 327 }
shintamainjp 0:c853ba46d0b9 328
shintamainjp 0:c853ba46d0b9 329 WavFileResult wavfile_read_info(WAVFILE *p, wavfile_info_t *info) {
shintamainjp 0:c853ba46d0b9 330 WavFileResult result = WavFileResultOK;
shintamainjp 0:c853ba46d0b9 331
shintamainjp 0:c853ba46d0b9 332 if (p == NULL) {
shintamainjp 0:c853ba46d0b9 333 result = WavFileResultErrorInvalidHandler;
shintamainjp 0:c853ba46d0b9 334 goto finalize;
shintamainjp 0:c853ba46d0b9 335 }
shintamainjp 0:c853ba46d0b9 336
shintamainjp 0:c853ba46d0b9 337 if (p->info_checked) {
shintamainjp 0:c853ba46d0b9 338 result = WavFileResultErrorAlreadyInfoChecked;
shintamainjp 0:c853ba46d0b9 339 goto finalize;
shintamainjp 0:c853ba46d0b9 340 }
shintamainjp 0:c853ba46d0b9 341 if (p->data_checked) {
shintamainjp 0:c853ba46d0b9 342 result = WavFileResultErrorAlreadyDataChecked;
shintamainjp 0:c853ba46d0b9 343 goto finalize;
shintamainjp 0:c853ba46d0b9 344 }
shintamainjp 0:c853ba46d0b9 345 if (p->mode != WavFileModeRead) {
shintamainjp 0:c853ba46d0b9 346 result = WavFileResultErrorInvalidMode;
shintamainjp 0:c853ba46d0b9 347 goto finalize;
shintamainjp 0:c853ba46d0b9 348 }
shintamainjp 0:c853ba46d0b9 349
shintamainjp 0:c853ba46d0b9 350 while (1) {
shintamainjp 0:c853ba46d0b9 351 uint32_t chunk_id;
shintamainjp 0:c853ba46d0b9 352 uint32_t chunk_size;
shintamainjp 0:c853ba46d0b9 353
shintamainjp 0:c853ba46d0b9 354 /*
shintamainjp 0:c853ba46d0b9 355 * Get the chunk ID.
shintamainjp 0:c853ba46d0b9 356 */
shintamainjp 0:c853ba46d0b9 357 if (READ_U32_BE(p->fp, &chunk_id) != 0) {
shintamainjp 0:c853ba46d0b9 358 if (feof(p->fp)) {
shintamainjp 0:c853ba46d0b9 359 /*
shintamainjp 0:c853ba46d0b9 360 *
shintamainjp 0:c853ba46d0b9 361 */
shintamainjp 0:c853ba46d0b9 362 result = WavFileResultErrorNoDataChunk;
shintamainjp 0:c853ba46d0b9 363 goto finalize;
shintamainjp 0:c853ba46d0b9 364 } else {
shintamainjp 0:c853ba46d0b9 365 result = WavFileResultErrorBrokenChunkId;
shintamainjp 0:c853ba46d0b9 366 goto finalize;
shintamainjp 0:c853ba46d0b9 367 }
shintamainjp 0:c853ba46d0b9 368 }
shintamainjp 0:c853ba46d0b9 369
shintamainjp 0:c853ba46d0b9 370 /*
shintamainjp 0:c853ba46d0b9 371 * Verify the chunk size.
shintamainjp 0:c853ba46d0b9 372 */
shintamainjp 0:c853ba46d0b9 373 if (READ_U32_LE(p->fp, &chunk_size) != 0) {
shintamainjp 0:c853ba46d0b9 374 result = WavFileResultErrorBrokenChunkSize;
shintamainjp 0:c853ba46d0b9 375 goto finalize;
shintamainjp 0:c853ba46d0b9 376 }
shintamainjp 0:c853ba46d0b9 377
shintamainjp 0:c853ba46d0b9 378 #if WAVFILE_DEBUG_ENABLED
shintamainjp 0:c853ba46d0b9 379 /*
shintamainjp 0:c853ba46d0b9 380 *
shintamainjp 0:c853ba46d0b9 381 */
shintamainjp 0:c853ba46d0b9 382 DEBUG("chunk_id(0x%04X-%c%c%c%c), chunk_size(%d bytes)\n",
shintamainjp 0:c853ba46d0b9 383 chunk_id,
shintamainjp 0:c853ba46d0b9 384 (chunk_id >> (8 * 3)),
shintamainjp 0:c853ba46d0b9 385 (chunk_id >> (8 * 2)),
shintamainjp 0:c853ba46d0b9 386 (chunk_id >> (8 * 1)),
shintamainjp 0:c853ba46d0b9 387 (chunk_id >> (8 * 0)),
shintamainjp 0:c853ba46d0b9 388 chunk_size);
shintamainjp 0:c853ba46d0b9 389 #endif
shintamainjp 0:c853ba46d0b9 390
shintamainjp 0:c853ba46d0b9 391 /*
shintamainjp 0:c853ba46d0b9 392 */
shintamainjp 0:c853ba46d0b9 393 switch (chunk_id) {
shintamainjp 0:c853ba46d0b9 394 case CHUNK_ID_RIFF: {
shintamainjp 0:c853ba46d0b9 395 uint32_t format_id;
shintamainjp 0:c853ba46d0b9 396 result = chunk_reader_riff(
shintamainjp 0:c853ba46d0b9 397 chunk_id,
shintamainjp 0:c853ba46d0b9 398 chunk_size,
shintamainjp 0:c853ba46d0b9 399 p->fp,
shintamainjp 0:c853ba46d0b9 400 &format_id);
shintamainjp 0:c853ba46d0b9 401
shintamainjp 0:c853ba46d0b9 402 #if WAVFILE_DEBUG_ENABLED
shintamainjp 0:c853ba46d0b9 403 /*
shintamainjp 0:c853ba46d0b9 404 */
shintamainjp 0:c853ba46d0b9 405 DEBUG("\tformat_id(%d)\n", format_id);
shintamainjp 0:c853ba46d0b9 406 #endif
shintamainjp 0:c853ba46d0b9 407
shintamainjp 0:c853ba46d0b9 408 if (format_id != RIFF_CHUNK_FORMAT_WAVE) {
shintamainjp 0:c853ba46d0b9 409 return WavFileResultErrorInvalidFormatId;
shintamainjp 0:c853ba46d0b9 410 }
shintamainjp 0:c853ba46d0b9 411 if (result != WavFileResultOK) {
shintamainjp 0:c853ba46d0b9 412 goto finalize;
shintamainjp 0:c853ba46d0b9 413 }
shintamainjp 0:c853ba46d0b9 414 }
shintamainjp 0:c853ba46d0b9 415 break;
shintamainjp 0:c853ba46d0b9 416 case CHUNK_ID_FMT: {
shintamainjp 0:c853ba46d0b9 417 result = chunk_reader_fmt(
shintamainjp 0:c853ba46d0b9 418 chunk_id,
shintamainjp 0:c853ba46d0b9 419 chunk_size,
shintamainjp 0:c853ba46d0b9 420 p->fp,
shintamainjp 0:c853ba46d0b9 421 &(p->info.audio_format),
shintamainjp 0:c853ba46d0b9 422 &(p->info.num_channels),
shintamainjp 0:c853ba46d0b9 423 &(p->info.sample_rate),
shintamainjp 0:c853ba46d0b9 424 &(p->info.byte_rate),
shintamainjp 0:c853ba46d0b9 425 &(p->info.block_align),
shintamainjp 0:c853ba46d0b9 426 &(p->info.bits_per_sample));
shintamainjp 0:c853ba46d0b9 427
shintamainjp 0:c853ba46d0b9 428 info->audio_format = p->info.audio_format;
shintamainjp 0:c853ba46d0b9 429 info->num_channels = p->info.num_channels;
shintamainjp 0:c853ba46d0b9 430 info->sample_rate = p->info.sample_rate;
shintamainjp 0:c853ba46d0b9 431 info->byte_rate = p->info.byte_rate;
shintamainjp 0:c853ba46d0b9 432 info->block_align = p->info.block_align;
shintamainjp 0:c853ba46d0b9 433 info->bits_per_sample = p->info.bits_per_sample;
shintamainjp 0:c853ba46d0b9 434
shintamainjp 0:c853ba46d0b9 435 #if WAVFILE_DEBUG_ENABLED
shintamainjp 0:c853ba46d0b9 436 /*
shintamainjp 0:c853ba46d0b9 437 */
shintamainjp 0:c853ba46d0b9 438 DEBUG("\taudio_format(%d)\n", p->info.audio_format);
shintamainjp 0:c853ba46d0b9 439 DEBUG("\tnum_channels(%d)\n", p->info.num_channels);
shintamainjp 0:c853ba46d0b9 440 DEBUG("\tsample_rate(%d)\n", p->info.sample_rate);
shintamainjp 0:c853ba46d0b9 441 DEBUG("\tbyte_rate(%d)\n", p->info.byte_rate);
shintamainjp 0:c853ba46d0b9 442 DEBUG("\tblock_align(%d)\n", p->info.block_align);
shintamainjp 0:c853ba46d0b9 443 DEBUG("\tbits_per_sample(%d)\n", p->info.bits_per_sample);
shintamainjp 0:c853ba46d0b9 444 #endif
shintamainjp 0:c853ba46d0b9 445
shintamainjp 0:c853ba46d0b9 446 if ((p->info.audio_format != WAVFILE_AUDIO_FORMAT_PCM) && (info->audio_format != WAVFILE_AUDIO_FORMAT_EXTENSIBLE)) {
shintamainjp 0:c853ba46d0b9 447 return WavFileResultErrorInvalidAudioFormat;
shintamainjp 0:c853ba46d0b9 448 }
shintamainjp 0:c853ba46d0b9 449 if (result != WavFileResultOK) {
shintamainjp 0:c853ba46d0b9 450 goto finalize;
shintamainjp 0:c853ba46d0b9 451 }
shintamainjp 0:c853ba46d0b9 452 }
shintamainjp 0:c853ba46d0b9 453 break;
shintamainjp 0:c853ba46d0b9 454 case CHUNK_ID_DATA: {
shintamainjp 0:c853ba46d0b9 455 p->info_checked = true;
shintamainjp 0:c853ba46d0b9 456 p->data_byte_count = chunk_size;
shintamainjp 0:c853ba46d0b9 457 goto finalize;
shintamainjp 0:c853ba46d0b9 458 }
shintamainjp 0:c853ba46d0b9 459 break;
shintamainjp 0:c853ba46d0b9 460 default: {
shintamainjp 0:c853ba46d0b9 461 result = chunk_reader_unknown(chunk_id, chunk_size, p->fp);
shintamainjp 0:c853ba46d0b9 462 if (result != WavFileResultOK) {
shintamainjp 0:c853ba46d0b9 463 goto finalize;
shintamainjp 0:c853ba46d0b9 464 }
shintamainjp 0:c853ba46d0b9 465 }
shintamainjp 0:c853ba46d0b9 466 break;
shintamainjp 0:c853ba46d0b9 467 }
shintamainjp 0:c853ba46d0b9 468 }
shintamainjp 0:c853ba46d0b9 469
shintamainjp 0:c853ba46d0b9 470 finalize:
shintamainjp 0:c853ba46d0b9 471 return result;
shintamainjp 0:c853ba46d0b9 472 }
shintamainjp 0:c853ba46d0b9 473
shintamainjp 0:c853ba46d0b9 474 /**
shintamainjp 0:c853ba46d0b9 475 */
shintamainjp 0:c853ba46d0b9 476 WavFileResult wavfile_read_data(WAVFILE *p, wavfile_data_t *data) {
shintamainjp 0:c853ba46d0b9 477 if (p == NULL) {
shintamainjp 0:c853ba46d0b9 478 return WavFileResultErrorInvalidHandler;
shintamainjp 0:c853ba46d0b9 479 }
shintamainjp 0:c853ba46d0b9 480
shintamainjp 0:c853ba46d0b9 481 if (!p->info_checked) {
shintamainjp 0:c853ba46d0b9 482 return WavFileResultErrorNeedInfoChecked;
shintamainjp 0:c853ba46d0b9 483 }
shintamainjp 0:c853ba46d0b9 484
shintamainjp 0:c853ba46d0b9 485 if (p->mode != WavFileModeRead) {
shintamainjp 0:c853ba46d0b9 486 return WavFileResultErrorInvalidMode;
shintamainjp 0:c853ba46d0b9 487 }
shintamainjp 0:c853ba46d0b9 488
shintamainjp 0:c853ba46d0b9 489 if (p->data_byte_count == 0) {
shintamainjp 0:c853ba46d0b9 490 data->num_channels = 0;
shintamainjp 0:c853ba46d0b9 491 for (int i = 0; i < p->info.num_channels; i++) {
shintamainjp 0:c853ba46d0b9 492 data->channel_data[i] = 0.5;
shintamainjp 0:c853ba46d0b9 493 }
shintamainjp 0:c853ba46d0b9 494 return WavFileResultOK;
shintamainjp 0:c853ba46d0b9 495 }
shintamainjp 0:c853ba46d0b9 496
shintamainjp 0:c853ba46d0b9 497 data->num_channels = p->info.num_channels;
shintamainjp 0:c853ba46d0b9 498 for (int i = 0; i < p->info.num_channels; i++) {
shintamainjp 0:c853ba46d0b9 499 switch (p->info.bits_per_sample) {
shintamainjp 0:c853ba46d0b9 500 case BITS_PER_SAMPLE_8: {
shintamainjp 0:c853ba46d0b9 501 int c = fgetc(p->fp);
shintamainjp 0:c853ba46d0b9 502 if (c == EOF) {
shintamainjp 0:c853ba46d0b9 503 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 504 }
shintamainjp 0:c853ba46d0b9 505 data->channel_data[i] = (double)c / 0xFF;
shintamainjp 0:c853ba46d0b9 506 }
shintamainjp 0:c853ba46d0b9 507 p->data_byte_count-=1;
shintamainjp 0:c853ba46d0b9 508 break;
shintamainjp 0:c853ba46d0b9 509 case BITS_PER_SAMPLE_16: {
shintamainjp 0:c853ba46d0b9 510 #if 0
shintamainjp 0:c853ba46d0b9 511 int c1 = fgetc(p->fp);
shintamainjp 0:c853ba46d0b9 512 if (c1 == EOF) {
shintamainjp 0:c853ba46d0b9 513 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 514 }
shintamainjp 0:c853ba46d0b9 515 int c2 = fgetc(p->fp);
shintamainjp 0:c853ba46d0b9 516 if (c2 == EOF) {
shintamainjp 0:c853ba46d0b9 517 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 518 }
shintamainjp 0:c853ba46d0b9 519 uint16_t n = (((uint16_t)c2 << 8) | ((uint16_t)c1 << 0)) ^ (1 << 15);
shintamainjp 0:c853ba46d0b9 520 data->channel_data[i] = (double)n / 0xFFFF;
shintamainjp 0:c853ba46d0b9 521 #else
shintamainjp 0:c853ba46d0b9 522 char tmp[2];
shintamainjp 0:c853ba46d0b9 523 fread(tmp, 2, 1, p->fp);
shintamainjp 0:c853ba46d0b9 524 uint16_t n = (((uint16_t)tmp[1] << 8) | ((uint16_t)tmp[0] << 0)) ^ (1 << 15);
shintamainjp 0:c853ba46d0b9 525 data->channel_data[i] = (double)n / 0xFFFF;
shintamainjp 0:c853ba46d0b9 526 #endif
shintamainjp 0:c853ba46d0b9 527 }
shintamainjp 0:c853ba46d0b9 528 p->data_byte_count-=2;
shintamainjp 0:c853ba46d0b9 529 break;
shintamainjp 0:c853ba46d0b9 530 case BITS_PER_SAMPLE_24: {
shintamainjp 0:c853ba46d0b9 531 #if 0
shintamainjp 0:c853ba46d0b9 532 int c1 = fgetc(p->fp);
shintamainjp 0:c853ba46d0b9 533 if (c1 == EOF) {
shintamainjp 0:c853ba46d0b9 534 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 535 }
shintamainjp 0:c853ba46d0b9 536 int c2 = fgetc(p->fp);
shintamainjp 0:c853ba46d0b9 537 if (c2 == EOF) {
shintamainjp 0:c853ba46d0b9 538 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 539 }
shintamainjp 0:c853ba46d0b9 540 int c3 = fgetc(p->fp);
shintamainjp 0:c853ba46d0b9 541 if (c3 == EOF) {
shintamainjp 0:c853ba46d0b9 542 return WavFileResultErrorBrokenChunkData;
shintamainjp 0:c853ba46d0b9 543 }
shintamainjp 0:c853ba46d0b9 544 uint32_t n = (((uint32_t)c3 << 16) | ((uint32_t)c2 << 8) | ((uint32_t)c1 << 0)) ^ (1 << 23);
shintamainjp 0:c853ba46d0b9 545 data->channel_data[i] = (double)n / 0xFFFFFF;
shintamainjp 0:c853ba46d0b9 546 #else
shintamainjp 0:c853ba46d0b9 547 char tmp[3];
shintamainjp 0:c853ba46d0b9 548 fread(tmp, 3, 1, p->fp);
shintamainjp 0:c853ba46d0b9 549 uint32_t n = (((uint32_t)tmp[2] << 16) | ((uint32_t)tmp[1] << 8) | ((uint32_t)tmp[0] << 0)) ^ (1 << 23);
shintamainjp 0:c853ba46d0b9 550 data->channel_data[i] = (double)n / 0xFFFFFF;
shintamainjp 0:c853ba46d0b9 551 #endif
shintamainjp 0:c853ba46d0b9 552 }
shintamainjp 0:c853ba46d0b9 553 p->data_byte_count-=3;
shintamainjp 0:c853ba46d0b9 554 break;
shintamainjp 0:c853ba46d0b9 555 default:
shintamainjp 0:c853ba46d0b9 556 return WavFileResultErrorUnsupportedBitsPerSample;
shintamainjp 0:c853ba46d0b9 557 }
shintamainjp 0:c853ba46d0b9 558 }
shintamainjp 0:c853ba46d0b9 559 return WavFileResultOK;
shintamainjp 0:c853ba46d0b9 560 }
shintamainjp 0:c853ba46d0b9 561
shintamainjp 0:c853ba46d0b9 562 WavFileResult wavfile_write_info(WAVFILE *p, const wavfile_info_t *info) {
shintamainjp 0:c853ba46d0b9 563 WavFileResult result = WavFileResultOK;
shintamainjp 0:c853ba46d0b9 564
shintamainjp 0:c853ba46d0b9 565 if (p == NULL) {
shintamainjp 0:c853ba46d0b9 566 result = WavFileResultErrorInvalidHandler;
shintamainjp 0:c853ba46d0b9 567 goto finalize;
shintamainjp 0:c853ba46d0b9 568 }
shintamainjp 0:c853ba46d0b9 569
shintamainjp 0:c853ba46d0b9 570 if (p->info_checked) {
shintamainjp 0:c853ba46d0b9 571 result = WavFileResultErrorAlreadyInfoChecked;
shintamainjp 0:c853ba46d0b9 572 goto finalize;
shintamainjp 0:c853ba46d0b9 573 }
shintamainjp 0:c853ba46d0b9 574
shintamainjp 0:c853ba46d0b9 575 if (p->mode != WavFileModeWrite) {
shintamainjp 0:c853ba46d0b9 576 result = WavFileResultErrorInvalidMode;
shintamainjp 0:c853ba46d0b9 577 goto finalize;
shintamainjp 0:c853ba46d0b9 578 }
shintamainjp 0:c853ba46d0b9 579
shintamainjp 0:c853ba46d0b9 580 p->info.audio_format = info->audio_format;
shintamainjp 0:c853ba46d0b9 581 p->info.num_channels = info->num_channels;
shintamainjp 0:c853ba46d0b9 582 p->info.sample_rate = info->sample_rate;
shintamainjp 0:c853ba46d0b9 583 p->info.byte_rate = info->byte_rate;
shintamainjp 0:c853ba46d0b9 584 p->info.block_align = info->block_align;
shintamainjp 0:c853ba46d0b9 585 p->info.bits_per_sample = info->bits_per_sample;
shintamainjp 0:c853ba46d0b9 586
shintamainjp 0:c853ba46d0b9 587 /*
shintamainjp 0:c853ba46d0b9 588 *
shintamainjp 0:c853ba46d0b9 589 */
shintamainjp 0:c853ba46d0b9 590
shintamainjp 0:c853ba46d0b9 591 if ((info->audio_format != WAVFILE_AUDIO_FORMAT_PCM) && (info->audio_format != WAVFILE_AUDIO_FORMAT_EXTENSIBLE)) {
shintamainjp 0:c853ba46d0b9 592 result = WavFileResultErrorInvalidAudioFormat;
shintamainjp 0:c853ba46d0b9 593 goto finalize;
shintamainjp 0:c853ba46d0b9 594 }
shintamainjp 0:c853ba46d0b9 595
shintamainjp 0:c853ba46d0b9 596 if ((info->bits_per_sample != BITS_PER_SAMPLE_8)
shintamainjp 0:c853ba46d0b9 597 && (info->bits_per_sample != BITS_PER_SAMPLE_16)
shintamainjp 0:c853ba46d0b9 598 && (info->bits_per_sample != BITS_PER_SAMPLE_24)) {
shintamainjp 0:c853ba46d0b9 599 result = WavFileResultErrorUnsupportedBitsPerSample;
shintamainjp 0:c853ba46d0b9 600 goto finalize;
shintamainjp 0:c853ba46d0b9 601 }
shintamainjp 0:c853ba46d0b9 602
shintamainjp 0:c853ba46d0b9 603 if ((info->num_channels * info->sample_rate * (info->bits_per_sample / 8)) != info->byte_rate) {
shintamainjp 0:c853ba46d0b9 604 result = WavFileResultErrorInvalidByteRate;
shintamainjp 0:c853ba46d0b9 605 goto finalize;
shintamainjp 0:c853ba46d0b9 606 }
shintamainjp 0:c853ba46d0b9 607
shintamainjp 0:c853ba46d0b9 608 /*
shintamainjp 0:c853ba46d0b9 609 * [RIFF]
shintamainjp 0:c853ba46d0b9 610 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 611 * Big endian 4 bytes : Chunk ID
shintamainjp 0:c853ba46d0b9 612 * Little endian 4 bytes : Chunk size
shintamainjp 0:c853ba46d0b9 613 * Big endian 4 bytes : Format
shintamainjp 0:c853ba46d0b9 614 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 615 */
shintamainjp 0:c853ba46d0b9 616 if (WRITE_U32_BE(p->fp, CHUNK_ID_RIFF) != 0) {
shintamainjp 0:c853ba46d0b9 617 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 618 goto finalize;
shintamainjp 0:c853ba46d0b9 619 }
shintamainjp 0:c853ba46d0b9 620 if (WRITE_U32_LE(p->fp, 0x00000000) != 0) {
shintamainjp 0:c853ba46d0b9 621 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 622 goto finalize;
shintamainjp 0:c853ba46d0b9 623 }
shintamainjp 0:c853ba46d0b9 624 if (WRITE_U32_BE(p->fp, RIFF_CHUNK_FORMAT_WAVE) != 0) {
shintamainjp 0:c853ba46d0b9 625 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 626 goto finalize;
shintamainjp 0:c853ba46d0b9 627 }
shintamainjp 0:c853ba46d0b9 628
shintamainjp 0:c853ba46d0b9 629 /*
shintamainjp 0:c853ba46d0b9 630 * [fmt]
shintamainjp 0:c853ba46d0b9 631 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 632 * Big endian 4 bytes : Sub chunk ID
shintamainjp 0:c853ba46d0b9 633 * Little endian 4 bytes : Sub chunk size
shintamainjp 0:c853ba46d0b9 634 * Little endian 2 bytes : Audio format
shintamainjp 0:c853ba46d0b9 635 * Little endian 2 bytes : Number of channels
shintamainjp 0:c853ba46d0b9 636 * Little endian 4 bytes : Sample rate
shintamainjp 0:c853ba46d0b9 637 * Little endian 4 bytes : Byte rate
shintamainjp 0:c853ba46d0b9 638 * Little endian 2 bytes : Block align
shintamainjp 0:c853ba46d0b9 639 * Little endian 2 bytes : Bits per sample
shintamainjp 0:c853ba46d0b9 640 * . .
shintamainjp 0:c853ba46d0b9 641 * . Additional bytes here (extensible) .
shintamainjp 0:c853ba46d0b9 642 * . .
shintamainjp 0:c853ba46d0b9 643 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 644 */
shintamainjp 0:c853ba46d0b9 645 switch (info->audio_format) {
shintamainjp 0:c853ba46d0b9 646 case WAVFILE_AUDIO_FORMAT_PCM: {
shintamainjp 0:c853ba46d0b9 647 if (WRITE_U32_BE(p->fp, CHUNK_ID_FMT) != 0) {
shintamainjp 0:c853ba46d0b9 648 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 649 goto finalize;
shintamainjp 0:c853ba46d0b9 650 }
shintamainjp 0:c853ba46d0b9 651 if (WRITE_U32_LE(p->fp, CHUNK_SIZE_FMT_PCM) != 0) {
shintamainjp 0:c853ba46d0b9 652 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 653 goto finalize;
shintamainjp 0:c853ba46d0b9 654 }
shintamainjp 0:c853ba46d0b9 655 if (WRITE_U16_LE(p->fp, info->audio_format) != 0) {
shintamainjp 0:c853ba46d0b9 656 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 657 goto finalize;
shintamainjp 0:c853ba46d0b9 658 }
shintamainjp 0:c853ba46d0b9 659 if (WRITE_U16_LE(p->fp, info->num_channels) != 0) {
shintamainjp 0:c853ba46d0b9 660 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 661 goto finalize;
shintamainjp 0:c853ba46d0b9 662 }
shintamainjp 0:c853ba46d0b9 663 if (WRITE_U32_LE(p->fp, info->sample_rate) != 0) {
shintamainjp 0:c853ba46d0b9 664 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 665 goto finalize;
shintamainjp 0:c853ba46d0b9 666 }
shintamainjp 0:c853ba46d0b9 667 if (WRITE_U32_LE(p->fp, info->byte_rate) != 0) {
shintamainjp 0:c853ba46d0b9 668 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 669 goto finalize;
shintamainjp 0:c853ba46d0b9 670 }
shintamainjp 0:c853ba46d0b9 671 if (WRITE_U16_LE(p->fp, info->block_align) != 0) {
shintamainjp 0:c853ba46d0b9 672 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 673 goto finalize;
shintamainjp 0:c853ba46d0b9 674 }
shintamainjp 0:c853ba46d0b9 675 if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) {
shintamainjp 0:c853ba46d0b9 676 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 677 goto finalize;
shintamainjp 0:c853ba46d0b9 678 }
shintamainjp 0:c853ba46d0b9 679 }
shintamainjp 0:c853ba46d0b9 680 break;
shintamainjp 0:c853ba46d0b9 681 case WAVFILE_AUDIO_FORMAT_EXTENSIBLE: {
shintamainjp 0:c853ba46d0b9 682 if (WRITE_U32_BE(p->fp, CHUNK_ID_FMT) != 0) {
shintamainjp 0:c853ba46d0b9 683 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 684 goto finalize;
shintamainjp 0:c853ba46d0b9 685 }
shintamainjp 0:c853ba46d0b9 686 if (WRITE_U32_LE(p->fp, CHUNK_SIZE_FMT_EXTENSIBLE) != 0) {
shintamainjp 0:c853ba46d0b9 687 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 688 goto finalize;
shintamainjp 0:c853ba46d0b9 689 }
shintamainjp 0:c853ba46d0b9 690 if (WRITE_U16_LE(p->fp, info->audio_format) != 0) {
shintamainjp 0:c853ba46d0b9 691 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 692 goto finalize;
shintamainjp 0:c853ba46d0b9 693 }
shintamainjp 0:c853ba46d0b9 694 if (WRITE_U16_LE(p->fp, info->num_channels) != 0) {
shintamainjp 0:c853ba46d0b9 695 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 696 goto finalize;
shintamainjp 0:c853ba46d0b9 697 }
shintamainjp 0:c853ba46d0b9 698 if (WRITE_U32_LE(p->fp, info->sample_rate) != 0) {
shintamainjp 0:c853ba46d0b9 699 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 700 goto finalize;
shintamainjp 0:c853ba46d0b9 701 }
shintamainjp 0:c853ba46d0b9 702 if (WRITE_U32_LE(p->fp, info->byte_rate) != 0) {
shintamainjp 0:c853ba46d0b9 703 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 704 goto finalize;
shintamainjp 0:c853ba46d0b9 705 }
shintamainjp 0:c853ba46d0b9 706 if (WRITE_U16_LE(p->fp, info->block_align) != 0) {
shintamainjp 0:c853ba46d0b9 707 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 708 goto finalize;
shintamainjp 0:c853ba46d0b9 709 }
shintamainjp 0:c853ba46d0b9 710 if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) {
shintamainjp 0:c853ba46d0b9 711 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 712 goto finalize;
shintamainjp 0:c853ba46d0b9 713 }
shintamainjp 0:c853ba46d0b9 714 /*
shintamainjp 0:c853ba46d0b9 715 * Additional bytes for the extensible format.
shintamainjp 0:c853ba46d0b9 716 *
shintamainjp 0:c853ba46d0b9 717 * 2 bytes : Size of the extension (0 or 22)
shintamainjp 0:c853ba46d0b9 718 * 2 bytes : Number of valid bits
shintamainjp 0:c853ba46d0b9 719 * 4 bytes : Speaker position mask
shintamainjp 0:c853ba46d0b9 720 * 16 bytes : GUID, including the data format code
shintamainjp 0:c853ba46d0b9 721 */
shintamainjp 0:c853ba46d0b9 722 if (WRITE_U16_LE(p->fp, 22) != 0) {
shintamainjp 0:c853ba46d0b9 723 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 724 goto finalize;
shintamainjp 0:c853ba46d0b9 725 }
shintamainjp 0:c853ba46d0b9 726 if (WRITE_U16_LE(p->fp, info->bits_per_sample) != 0) {
shintamainjp 0:c853ba46d0b9 727 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 728 goto finalize;
shintamainjp 0:c853ba46d0b9 729 }
shintamainjp 0:c853ba46d0b9 730 if (WRITE_U32_LE(p->fp, 0x00000000) != 0) {
shintamainjp 0:c853ba46d0b9 731 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 732 goto finalize;
shintamainjp 0:c853ba46d0b9 733 }
shintamainjp 0:c853ba46d0b9 734 static const unsigned char sub_format[16] = {
shintamainjp 0:c853ba46d0b9 735 0x01, 0x00, 0x00, 0x00,
shintamainjp 0:c853ba46d0b9 736 0x00, 0x00, 0x10, 0x00,
shintamainjp 0:c853ba46d0b9 737 0x80, 0x00, 0x00, 0xAA,
shintamainjp 0:c853ba46d0b9 738 0x00, 0x38, 0x9B, 0x71
shintamainjp 0:c853ba46d0b9 739 };
shintamainjp 0:c853ba46d0b9 740 for (int i = 0; i < sizeof(sub_format); i++) {
shintamainjp 0:c853ba46d0b9 741 fputc((char)sub_format[i], p->fp);
shintamainjp 0:c853ba46d0b9 742 }
shintamainjp 0:c853ba46d0b9 743 }
shintamainjp 0:c853ba46d0b9 744 break;
shintamainjp 0:c853ba46d0b9 745 default:
shintamainjp 0:c853ba46d0b9 746 result = WavFileResultErrorInvalidAudioFormat;
shintamainjp 0:c853ba46d0b9 747 goto finalize;
shintamainjp 0:c853ba46d0b9 748 }
shintamainjp 0:c853ba46d0b9 749
shintamainjp 0:c853ba46d0b9 750 /*
shintamainjp 0:c853ba46d0b9 751 * [data]
shintamainjp 0:c853ba46d0b9 752 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 753 * Big endian 4 bytes : Sub chunk ID
shintamainjp 0:c853ba46d0b9 754 * Little endian 4 bytes : Sub chunk size
shintamainjp 0:c853ba46d0b9 755 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 756 * Little endian 2 bytes : Sample 1 (Ch.1)
shintamainjp 0:c853ba46d0b9 757 * Little endian 2 bytes : Sample 1 (Ch.2)
shintamainjp 0:c853ba46d0b9 758 * .
shintamainjp 0:c853ba46d0b9 759 * .
shintamainjp 0:c853ba46d0b9 760 * .
shintamainjp 0:c853ba46d0b9 761 * Little endian 2 bytes : Sample 1 (Ch.N)
shintamainjp 0:c853ba46d0b9 762 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 763 * Little endian 2 bytes : Sample 2 (Ch.1)
shintamainjp 0:c853ba46d0b9 764 * Little endian 2 bytes : Sample 2 (Ch.2)
shintamainjp 0:c853ba46d0b9 765 * .
shintamainjp 0:c853ba46d0b9 766 * .
shintamainjp 0:c853ba46d0b9 767 * .
shintamainjp 0:c853ba46d0b9 768 * Little endian 2 bytes : Sample 2 (Ch.N)
shintamainjp 0:c853ba46d0b9 769 * ------------------------------------------
shintamainjp 0:c853ba46d0b9 770 */
shintamainjp 0:c853ba46d0b9 771 if (WRITE_U32_BE(p->fp, CHUNK_ID_DATA) != 0) {
shintamainjp 0:c853ba46d0b9 772 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 773 goto finalize;
shintamainjp 0:c853ba46d0b9 774 }
shintamainjp 0:c853ba46d0b9 775 if (WRITE_U32_LE(p->fp, 0x00000000) != 0) {
shintamainjp 0:c853ba46d0b9 776 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 777 goto finalize;
shintamainjp 0:c853ba46d0b9 778 }
shintamainjp 0:c853ba46d0b9 779
shintamainjp 0:c853ba46d0b9 780 finalize:
shintamainjp 0:c853ba46d0b9 781 if (WavFileResultOK == result) {
shintamainjp 0:c853ba46d0b9 782 p->info_checked = true;
shintamainjp 0:c853ba46d0b9 783 }
shintamainjp 0:c853ba46d0b9 784 return result;
shintamainjp 0:c853ba46d0b9 785 }
shintamainjp 0:c853ba46d0b9 786
shintamainjp 0:c853ba46d0b9 787 /**
shintamainjp 0:c853ba46d0b9 788 */
shintamainjp 0:c853ba46d0b9 789 WavFileResult wavfile_write_data(WAVFILE *p, const wavfile_data_t *data) {
shintamainjp 0:c853ba46d0b9 790 WavFileResult result = WavFileResultOK;
shintamainjp 0:c853ba46d0b9 791
shintamainjp 0:c853ba46d0b9 792 if (p == NULL) {
shintamainjp 0:c853ba46d0b9 793 result = WavFileResultErrorInvalidHandler;
shintamainjp 0:c853ba46d0b9 794 goto finalize;
shintamainjp 0:c853ba46d0b9 795 }
shintamainjp 0:c853ba46d0b9 796
shintamainjp 0:c853ba46d0b9 797 if (!p->info_checked) {
shintamainjp 0:c853ba46d0b9 798 result = WavFileResultErrorNeedInfoChecked;
shintamainjp 0:c853ba46d0b9 799 goto finalize;
shintamainjp 0:c853ba46d0b9 800 }
shintamainjp 0:c853ba46d0b9 801
shintamainjp 0:c853ba46d0b9 802 if (p->mode != WavFileModeWrite) {
shintamainjp 0:c853ba46d0b9 803 result = WavFileResultErrorInvalidMode;
shintamainjp 0:c853ba46d0b9 804 goto finalize;
shintamainjp 0:c853ba46d0b9 805 }
shintamainjp 0:c853ba46d0b9 806
shintamainjp 0:c853ba46d0b9 807 if (p->info.num_channels != data->num_channels) {
shintamainjp 0:c853ba46d0b9 808 result = WavFileResultErrorInvalidNumChannels;
shintamainjp 0:c853ba46d0b9 809 goto finalize;
shintamainjp 0:c853ba46d0b9 810 }
shintamainjp 0:c853ba46d0b9 811
shintamainjp 0:c853ba46d0b9 812 for (int i = 0; i < p->info.num_channels; i++) {
shintamainjp 0:c853ba46d0b9 813 switch (p->info.bits_per_sample) {
shintamainjp 0:c853ba46d0b9 814 case BITS_PER_SAMPLE_8: {
shintamainjp 0:c853ba46d0b9 815 int n = (int)((double)data->channel_data[i] * 0xFF);
shintamainjp 0:c853ba46d0b9 816 if (n < 0x00) {
shintamainjp 0:c853ba46d0b9 817 n = 0x00;
shintamainjp 0:c853ba46d0b9 818 }
shintamainjp 0:c853ba46d0b9 819 if (0xFF < n) {
shintamainjp 0:c853ba46d0b9 820 n = 0xFF;
shintamainjp 0:c853ba46d0b9 821 }
shintamainjp 0:c853ba46d0b9 822 fputc((char)n, p->fp);
shintamainjp 0:c853ba46d0b9 823 }
shintamainjp 0:c853ba46d0b9 824 p->data_byte_count+=1;
shintamainjp 0:c853ba46d0b9 825 break;
shintamainjp 0:c853ba46d0b9 826 case BITS_PER_SAMPLE_16: {
shintamainjp 0:c853ba46d0b9 827 int n = (int)((double)(data->channel_data[i] * 0xFFFF) - 0x8000);
shintamainjp 0:c853ba46d0b9 828 if (0x7FFF < n) {
shintamainjp 0:c853ba46d0b9 829 n = 0x7FFF;
shintamainjp 0:c853ba46d0b9 830 }
shintamainjp 0:c853ba46d0b9 831 if (n < -0x8000) {
shintamainjp 0:c853ba46d0b9 832 n = -0x8000;
shintamainjp 0:c853ba46d0b9 833 }
shintamainjp 0:c853ba46d0b9 834 fputc(((uint16_t)n >> 0) & 0xff, p->fp);
shintamainjp 0:c853ba46d0b9 835 fputc(((uint16_t)n >> 8) & 0xff, p->fp);
shintamainjp 0:c853ba46d0b9 836 }
shintamainjp 0:c853ba46d0b9 837 p->data_byte_count+=2;
shintamainjp 0:c853ba46d0b9 838 break;
shintamainjp 0:c853ba46d0b9 839 case BITS_PER_SAMPLE_24: {
shintamainjp 0:c853ba46d0b9 840 int n = (int)((double)(data->channel_data[i] * 0xFFFFFF) - 0x800000);
shintamainjp 0:c853ba46d0b9 841 if (0x7FFFFF < n) {
shintamainjp 0:c853ba46d0b9 842 n = 0x7FFFFF;
shintamainjp 0:c853ba46d0b9 843 }
shintamainjp 0:c853ba46d0b9 844 if (n < -0x800000) {
shintamainjp 0:c853ba46d0b9 845 n = -0x800000;
shintamainjp 0:c853ba46d0b9 846 }
shintamainjp 0:c853ba46d0b9 847 fputc(((uint32_t)n >> 0) & 0xff, p->fp);
shintamainjp 0:c853ba46d0b9 848 fputc(((uint32_t)n >> 8) & 0xff, p->fp);
shintamainjp 0:c853ba46d0b9 849 fputc(((uint32_t)n >> 16) & 0xff, p->fp);
shintamainjp 0:c853ba46d0b9 850 }
shintamainjp 0:c853ba46d0b9 851 p->data_byte_count+=3;
shintamainjp 0:c853ba46d0b9 852 break;
shintamainjp 0:c853ba46d0b9 853 }
shintamainjp 0:c853ba46d0b9 854 }
shintamainjp 0:c853ba46d0b9 855 p->data_checked = true;
shintamainjp 0:c853ba46d0b9 856
shintamainjp 0:c853ba46d0b9 857 finalize:
shintamainjp 0:c853ba46d0b9 858 return result;
shintamainjp 0:c853ba46d0b9 859 }
shintamainjp 0:c853ba46d0b9 860
shintamainjp 0:c853ba46d0b9 861 WavFileResult wavfile_close(WAVFILE *p) {
shintamainjp 0:c853ba46d0b9 862 WavFileResult result = WavFileResultOK;
shintamainjp 0:c853ba46d0b9 863
shintamainjp 0:c853ba46d0b9 864 switch (p->mode) {
shintamainjp 0:c853ba46d0b9 865 case WavFileModeRead:
shintamainjp 0:c853ba46d0b9 866 break;
shintamainjp 0:c853ba46d0b9 867 case WavFileModeWrite:
shintamainjp 0:c853ba46d0b9 868 if (p->info_checked && p->data_checked) {
shintamainjp 0:c853ba46d0b9 869 switch (p->info.audio_format) {
shintamainjp 0:c853ba46d0b9 870 case WAVFILE_AUDIO_FORMAT_PCM: {
shintamainjp 0:c853ba46d0b9 871 /*
shintamainjp 0:c853ba46d0b9 872 * Fill the RIFF chunk size.
shintamainjp 0:c853ba46d0b9 873 */
shintamainjp 0:c853ba46d0b9 874 if (fseek(p->fp, 4L, SEEK_SET) == -1) {
shintamainjp 0:c853ba46d0b9 875 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 876 goto finalize;
shintamainjp 0:c853ba46d0b9 877 }
shintamainjp 0:c853ba46d0b9 878 if (WRITE_U32_LE(p->fp, 4 + (8 + CHUNK_SIZE_FMT_PCM) + (8 + p->data_byte_count)) != 0) {
shintamainjp 0:c853ba46d0b9 879 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 880 goto finalize;
shintamainjp 0:c853ba46d0b9 881 }
shintamainjp 0:c853ba46d0b9 882
shintamainjp 0:c853ba46d0b9 883 /*
shintamainjp 0:c853ba46d0b9 884 * Fill the data sub chunk size.
shintamainjp 0:c853ba46d0b9 885 */
shintamainjp 0:c853ba46d0b9 886 if (fseek(p->fp, 12 + (8 + CHUNK_SIZE_FMT_PCM) + 4, SEEK_SET) == -1) {
shintamainjp 0:c853ba46d0b9 887 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 888 goto finalize;
shintamainjp 0:c853ba46d0b9 889 }
shintamainjp 0:c853ba46d0b9 890 if (WRITE_U32_LE(p->fp, p->data_byte_count) != 0) {
shintamainjp 0:c853ba46d0b9 891 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 892 goto finalize;
shintamainjp 0:c853ba46d0b9 893 }
shintamainjp 0:c853ba46d0b9 894 }
shintamainjp 0:c853ba46d0b9 895 break;
shintamainjp 0:c853ba46d0b9 896 case WAVFILE_AUDIO_FORMAT_EXTENSIBLE: {
shintamainjp 0:c853ba46d0b9 897 /*
shintamainjp 0:c853ba46d0b9 898 * Fill the RIFF chunk size.
shintamainjp 0:c853ba46d0b9 899 */
shintamainjp 0:c853ba46d0b9 900 if (fseek(p->fp, 4L, SEEK_SET) == -1) {
shintamainjp 0:c853ba46d0b9 901 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 902 goto finalize;
shintamainjp 0:c853ba46d0b9 903 }
shintamainjp 0:c853ba46d0b9 904 if (WRITE_U32_LE(p->fp, 4 + (8 + CHUNK_SIZE_FMT_EXTENSIBLE) + (8 + p->data_byte_count)) != 0) {
shintamainjp 0:c853ba46d0b9 905 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 906 goto finalize;
shintamainjp 0:c853ba46d0b9 907 }
shintamainjp 0:c853ba46d0b9 908
shintamainjp 0:c853ba46d0b9 909 /*
shintamainjp 0:c853ba46d0b9 910 * Fill the data sub chunk size.
shintamainjp 0:c853ba46d0b9 911 */
shintamainjp 0:c853ba46d0b9 912 if (fseek(p->fp, 12 + (8 + CHUNK_SIZE_FMT_EXTENSIBLE) + 4, SEEK_SET) == -1) {
shintamainjp 0:c853ba46d0b9 913 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 914 goto finalize;
shintamainjp 0:c853ba46d0b9 915 }
shintamainjp 0:c853ba46d0b9 916 if (WRITE_U32_LE(p->fp, p->data_byte_count) != 0) {
shintamainjp 0:c853ba46d0b9 917 result = WavFileResultErrorFileWrite;
shintamainjp 0:c853ba46d0b9 918 goto finalize;
shintamainjp 0:c853ba46d0b9 919 }
shintamainjp 0:c853ba46d0b9 920 }
shintamainjp 0:c853ba46d0b9 921 break;
shintamainjp 0:c853ba46d0b9 922 }
shintamainjp 0:c853ba46d0b9 923 }
shintamainjp 0:c853ba46d0b9 924 break;
shintamainjp 0:c853ba46d0b9 925 }
shintamainjp 0:c853ba46d0b9 926
shintamainjp 0:c853ba46d0b9 927 finalize:
shintamainjp 0:c853ba46d0b9 928 fclose(p->fp);
shintamainjp 0:c853ba46d0b9 929 free(p);
shintamainjp 0:c853ba46d0b9 930 return result;
shintamainjp 0:c853ba46d0b9 931 }
shintamainjp 0:c853ba46d0b9 932
shintamainjp 0:c853ba46d0b9 933 void wavfile_result_string(const WavFileResult result, char *buf, size_t siz) {
shintamainjp 0:c853ba46d0b9 934 switch (result) {
shintamainjp 0:c853ba46d0b9 935 case WavFileResultOK:
shintamainjp 0:c853ba46d0b9 936 strcpy(buf, "OK.");
shintamainjp 0:c853ba46d0b9 937 break;
shintamainjp 0:c853ba46d0b9 938 case WavFileResultErrorInvalidFileName:
shintamainjp 0:c853ba46d0b9 939 strcpy(buf, "Invalid file name found.");
shintamainjp 0:c853ba46d0b9 940 break;
shintamainjp 0:c853ba46d0b9 941 case WavFileResultErrorMemoryAllocation:
shintamainjp 0:c853ba46d0b9 942 strcpy(buf, "Memory allocation error.");
shintamainjp 0:c853ba46d0b9 943 break;
shintamainjp 0:c853ba46d0b9 944 case WavFileResultErrorFileOpen:
shintamainjp 0:c853ba46d0b9 945 strcpy(buf, "File open error found.");
shintamainjp 0:c853ba46d0b9 946 break;
shintamainjp 0:c853ba46d0b9 947 case WavFileResultErrorFileWrite:
shintamainjp 0:c853ba46d0b9 948 strcpy(buf, "File write error found.");
shintamainjp 0:c853ba46d0b9 949 break;
shintamainjp 0:c853ba46d0b9 950 case WavFileResultErrorBrokenChunkId:
shintamainjp 0:c853ba46d0b9 951 strcpy(buf, "Broken chunk ID found.");
shintamainjp 0:c853ba46d0b9 952 break;
shintamainjp 0:c853ba46d0b9 953 case WavFileResultErrorBrokenChunkSize:
shintamainjp 0:c853ba46d0b9 954 strcpy(buf, "Borken chunk size found.");
shintamainjp 0:c853ba46d0b9 955 break;
shintamainjp 0:c853ba46d0b9 956 case WavFileResultErrorBrokenChunkData:
shintamainjp 0:c853ba46d0b9 957 strcpy(buf, "Borken chunk data found.");
shintamainjp 0:c853ba46d0b9 958 break;
shintamainjp 0:c853ba46d0b9 959 case WavFileResultErrorBrokenFormatId:
shintamainjp 0:c853ba46d0b9 960 strcpy(buf, "Broken format ID found.");
shintamainjp 0:c853ba46d0b9 961 break;
shintamainjp 0:c853ba46d0b9 962 case WavFileResultErrorInvalidFormatId:
shintamainjp 0:c853ba46d0b9 963 strcpy(buf, "Invalid format ID found.");
shintamainjp 0:c853ba46d0b9 964 break;
shintamainjp 0:c853ba46d0b9 965 case WavFileResultErrorBrokenAudioFormat:
shintamainjp 0:c853ba46d0b9 966 strcpy(buf, "Broken audio format found.");
shintamainjp 0:c853ba46d0b9 967 break;
shintamainjp 0:c853ba46d0b9 968 case WavFileResultErrorInvalidAudioFormat:
shintamainjp 0:c853ba46d0b9 969 strcpy(buf, "Invalid audio format found.");
shintamainjp 0:c853ba46d0b9 970 break;
shintamainjp 0:c853ba46d0b9 971 case WavFileResultErrorInvalidNumChannels:
shintamainjp 0:c853ba46d0b9 972 strcpy(buf, "Invalid number of channels found.");
shintamainjp 0:c853ba46d0b9 973 break;
shintamainjp 0:c853ba46d0b9 974 case WavFileResultErrorBrokenNumChannels:
shintamainjp 0:c853ba46d0b9 975 strcpy(buf, "Broken number of channels found.");
shintamainjp 0:c853ba46d0b9 976 break;
shintamainjp 0:c853ba46d0b9 977 case WavFileResultErrorBrokenSampleRate:
shintamainjp 0:c853ba46d0b9 978 strcpy(buf, "Broken sample rate found.");
shintamainjp 0:c853ba46d0b9 979 break;
shintamainjp 0:c853ba46d0b9 980 case WavFileResultErrorBrokenByteRate:
shintamainjp 0:c853ba46d0b9 981 strcpy(buf, "Broken byte rate found.");
shintamainjp 0:c853ba46d0b9 982 break;
shintamainjp 0:c853ba46d0b9 983 case WavFileResultErrorInvalidByteRate:
shintamainjp 0:c853ba46d0b9 984 strcpy(buf, "Invalid byte rate found.");
shintamainjp 0:c853ba46d0b9 985 break;
shintamainjp 0:c853ba46d0b9 986 case WavFileResultErrorBrokenBlockAlign:
shintamainjp 0:c853ba46d0b9 987 strcpy(buf, "Broken block alignment found.");
shintamainjp 0:c853ba46d0b9 988 break;
shintamainjp 0:c853ba46d0b9 989 case WavFileResultErrorBrokenBitsPerSample:
shintamainjp 0:c853ba46d0b9 990 strcpy(buf, "Broken bits per sample found.");
shintamainjp 0:c853ba46d0b9 991 break;
shintamainjp 0:c853ba46d0b9 992 case WavFileResultErrorUnsupportedBitsPerSample:
shintamainjp 0:c853ba46d0b9 993 strcpy(buf, "Unsupported bits per sample found.");
shintamainjp 0:c853ba46d0b9 994 break;
shintamainjp 0:c853ba46d0b9 995 case WavFileResultErrorAlreadyInfoChecked:
shintamainjp 0:c853ba46d0b9 996 strcpy(buf, "Already checked info.");
shintamainjp 0:c853ba46d0b9 997 break;
shintamainjp 0:c853ba46d0b9 998 case WavFileResultErrorAlreadyDataChecked:
shintamainjp 0:c853ba46d0b9 999 strcpy(buf, "Already checked data.");
shintamainjp 0:c853ba46d0b9 1000 break;
shintamainjp 0:c853ba46d0b9 1001 case WavFileResultErrorNoDataChunk:
shintamainjp 0:c853ba46d0b9 1002 strcpy(buf, "No data chunk.");
shintamainjp 0:c853ba46d0b9 1003 break;
shintamainjp 0:c853ba46d0b9 1004 case WavFileResultErrorInvalidMode:
shintamainjp 0:c853ba46d0b9 1005 strcpy(buf, "Invalid mode.");
shintamainjp 0:c853ba46d0b9 1006 break;
shintamainjp 0:c853ba46d0b9 1007 case WavFileResultErrorNeedInfoChecked:
shintamainjp 0:c853ba46d0b9 1008 strcpy(buf, "Need check info.");
shintamainjp 0:c853ba46d0b9 1009 break;
shintamainjp 0:c853ba46d0b9 1010 case WavFileResultErrorNeedDataChecked:
shintamainjp 0:c853ba46d0b9 1011 strcpy(buf, "Need check data.");
shintamainjp 0:c853ba46d0b9 1012 break;
shintamainjp 0:c853ba46d0b9 1013 case WavFileResultErrorInvalidHandler:
shintamainjp 0:c853ba46d0b9 1014 strcpy(buf, "Invalid handler.");
shintamainjp 0:c853ba46d0b9 1015 break;
shintamainjp 0:c853ba46d0b9 1016 default:
shintamainjp 0:c853ba46d0b9 1017 strcpy(buf, "Unkonwn error found.");
shintamainjp 0:c853ba46d0b9 1018 break;
shintamainjp 0:c853ba46d0b9 1019 }
shintamainjp 0:c853ba46d0b9 1020 }
shintamainjp 0:c853ba46d0b9 1021