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 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 1 62 63 struct wave_format { 64 uint32_t id; 65 uint32_t size; 66 uint16_t fmt; 67 uint16_t channels; 68 uint32_t samplerate; 69 uint32_t byterate; 70 uint16_t framesize; 71 uint16_t bitdepth; 72 }; 73 74 75 /** 76 * Audio data statement 77 * | id WAV_DATA_ID 78 * | size Size of the data following 79 */ 80 81 #define WAVE_DATA_ID __WAVE_ID("data") 82 83 struct wave_data { 84 uint32_t id; 85 uint32_t size; 86 }; 87 88 89 /** 90 * Read WAVE file header 91 */ 92 int wave_read_header(FILE *fp, int *bitdepth, int *samplesize, 93 int *samplerate, int *nchannels, int *nframes) 94 { 95 struct wave_file file; 96 struct wave_format format; 97 struct wave_data data; 98 99 if (fread(&file, sizeof(file), 1, fp) != 1 100 || file.type_id != WAVE_FILE_TYPE_ID 101 || file.fmt_id != WAVE_FILE_FMT_ID) 102 return -1; 103 104 if (fread(&format, sizeof(format), 1, fp) != 1 105 || format.id != WAVE_FORMAT_ID 106 || format.fmt != WAVE_FORMAT_PCM 107 || format.channels <= 0 108 || format.samplerate <= 0 109 || format.framesize <= 0 110 || format.byterate != format.samplerate * format.framesize) 111 return -1; 112 113 fseek(fp, sizeof(format) - (8 + format.size), SEEK_CUR); 114 115 if (fread(&data, sizeof(data), 1, fp) != 1 116 || data.id != WAVE_DATA_ID) 117 return -1; 118 119 *bitdepth = format.bitdepth; 120 *samplesize = format.framesize / format.channels; 121 *samplerate = format.samplerate; 122 *nchannels = format.channels; 123 *nframes = data.size / format.framesize; 124 125 return 0; 126 } 127 128 /** 129 * Read PCM samples from wave file 130 */ 131 int wave_read_pcm(FILE *fp, int samplesize, 132 int nch, int count, void *buffer) 133 { 134 return fread(buffer, nch * samplesize, count, fp); 135 } 136 137 /** 138 * Write WAVE file header 139 */ 140 void wave_write_header(FILE *fp, int bitdepth, int samplesize, 141 int samplerate, int nchannels, int nframes) 142 { 143 struct { 144 struct wave_file file; 145 struct wave_format format; 146 struct wave_data data; 147 } header; 148 149 long data_size = nchannels * nframes * samplesize; 150 long file_size = sizeof(header) + data_size; 151 152 header.file = (struct wave_file){ 153 WAVE_FILE_TYPE_ID, file_size - 8, 154 .fmt_id = WAVE_FILE_FMT_ID 155 }; 156 157 header.format = (struct wave_format){ 158 WAVE_FORMAT_ID, sizeof(header.format) - 8, 159 .fmt = WAVE_FORMAT_PCM, 160 .channels = nchannels, 161 .samplerate = samplerate, 162 .byterate = samplerate * nchannels * samplesize, 163 .framesize = nchannels * samplesize, 164 .bitdepth = bitdepth, 165 }; 166 167 header.data = (struct wave_data){ 168 WAVE_DATA_ID, data_size 169 }; 170 171 fwrite(&header, sizeof(header), 1, fp); 172 } 173 174 /** 175 * Write PCM samples to wave file 176 */ 177 void wave_write_pcm(FILE *fp, int samplesize, 178 const void *_pcm, int nch, int off, int count) 179 { 180 const int8_t *pcm = _pcm; 181 fwrite(pcm + nch * off * samplesize, nch * samplesize, count, fp); 182 } 183