1 /****************************************************************************** 2 * 3 * Copyright 2022 Google LLC 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #include <stdint.h> 20 #include "wave.h" 21 22 23 /** 24 * Id formatting 25 */ 26 27 #define __WAVE_ID(s) \ 28 (uint32_t)( s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) ) 29 30 31 /** 32 * File format statement 33 * | type_id WAVE_FILE_TYPE_ID 34 * | size File size - 8 bytes 35 * | type_id WAVE_FILE_FMT_ID 36 */ 37 38 #define WAVE_FILE_TYPE_ID __WAVE_ID("RIFF") 39 #define WAVE_FILE_FMT_ID __WAVE_ID("WAVE") 40 41 struct wave_file { 42 uint32_t type_id; 43 uint32_t size; 44 uint32_t fmt_id; 45 }; 46 47 48 /** 49 * Audio format statement 50 * | id WAVE_FORMAT_ID 51 * | size Size of the block - 8 bytes (= 16 bytes) 52 * | format WAVE_FORMAT_PCM or WAVE_FORMAT_EXT 53 * | channels Number of channels 54 * | samplerate Sampling rate 55 * | byterate Bytes per secondes = `samplerate * framesize` 56 * | framesize Bytes per sampling time = `channels * bitdepth / 8` 57 * | bitdepth Number of bits per sample 58 */ 59 60 #define WAVE_FORMAT_ID __WAVE_ID("fmt ") 61 #define WAVE_FORMAT_PCM 0x0001 62 #define WAVE_FORMAT_EXT 0xfffe 63 64 struct wave_format { 65 uint32_t id; 66 uint32_t size; 67 uint16_t fmt; 68 uint16_t channels; 69 uint32_t samplerate; 70 uint32_t byterate; 71 uint16_t framesize; 72 uint16_t bitdepth; 73 }; 74 75 76 /** 77 * Audio data statement 78 * | id WAV_DATA_ID 79 * | size Size of the data following 80 */ 81 82 #define WAVE_DATA_ID __WAVE_ID("data") 83 84 struct wave_data { 85 uint32_t id; 86 uint32_t size; 87 }; 88 89 90 /** 91 * Read WAVE file header 92 */ 93 int wave_read_header(FILE *fp, int *bitdepth, int *samplesize, 94 int *samplerate, int *nchannels, int *nframes) 95 { 96 struct wave_file file; 97 struct wave_format format; 98 struct wave_data data; 99 100 if (fread(&file, sizeof(file), 1, fp) != 1 101 || file.type_id != WAVE_FILE_TYPE_ID 102 || file.fmt_id != WAVE_FILE_FMT_ID) 103 return -1; 104 105 if (fread(&format, sizeof(format), 1, fp) != 1 106 || format.id != WAVE_FORMAT_ID 107 || ( format.fmt != WAVE_FORMAT_PCM && 108 format.fmt != WAVE_FORMAT_EXT ) 109 || format.channels <= 0 110 || format.samplerate <= 0 111 || format.framesize <= 0 112 || format.byterate != format.samplerate * format.framesize) 113 return -1; 114 115 fseek(fp, sizeof(format) - (8 + format.size), SEEK_CUR); 116 117 for ( ; fread(&data, sizeof(data), 1, fp) == 1 && data.id != WAVE_DATA_ID 118 ; fseek(fp, data.size, SEEK_CUR) ); 119 120 if (feof(fp)) 121 return -1; 122 123 *bitdepth = format.bitdepth; 124 *samplesize = format.framesize / format.channels; 125 *samplerate = format.samplerate; 126 *nchannels = format.channels; 127 *nframes = data.size / format.framesize; 128 129 return 0; 130 } 131 132 /** 133 * Read PCM samples from wave file 134 */ 135 int wave_read_pcm(FILE *fp, int samplesize, 136 int nch, int count, void *buffer) 137 { 138 return fread(buffer, nch * samplesize, count, fp); 139 } 140 141 /** 142 * Write WAVE file header 143 */ 144 void wave_write_header(FILE *fp, int bitdepth, int samplesize, 145 int samplerate, int nchannels, int nframes) 146 { 147 struct { 148 struct wave_file file; 149 struct wave_format format; 150 struct wave_data data; 151 } header; 152 153 long data_size = nchannels * nframes * samplesize; 154 long file_size = sizeof(header) + data_size; 155 156 header.file = (struct wave_file){ 157 WAVE_FILE_TYPE_ID, file_size - 8, 158 .fmt_id = WAVE_FILE_FMT_ID 159 }; 160 161 header.format = (struct wave_format){ 162 WAVE_FORMAT_ID, sizeof(header.format) - 8, 163 .fmt = WAVE_FORMAT_PCM, 164 .channels = nchannels, 165 .samplerate = samplerate, 166 .byterate = samplerate * nchannels * samplesize, 167 .framesize = nchannels * samplesize, 168 .bitdepth = bitdepth, 169 }; 170 171 header.data = (struct wave_data){ 172 WAVE_DATA_ID, data_size 173 }; 174 175 fwrite(&header, sizeof(header), 1, fp); 176 } 177 178 /** 179 * Write PCM samples to wave file 180 */ 181 void wave_write_pcm(FILE *fp, int samplesize, 182 const void *_pcm, int nch, int off, int count) 183 { 184 const int8_t *pcm = _pcm; 185 fwrite(pcm + nch * off * samplesize, nch * samplesize, count, fp); 186 } 187