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.byterate != format.samplerate * format.framesize) 108 return -1; 109 110 fseek(fp, sizeof(format) - (8 + format.size), SEEK_CUR); 111 112 if (fread(&data, sizeof(data), 1, fp) != 1 113 || data.id != WAVE_DATA_ID) 114 return -1; 115 116 *bitdepth = format.bitdepth; 117 *samplesize = format.framesize / format.channels; 118 *samplerate = format.samplerate; 119 *nchannels = format.channels; 120 *nframes = data.size / format.framesize; 121 122 return 0; 123 } 124 125 /** 126 * Read PCM samples from wave file 127 */ 128 int wave_read_pcm(FILE *fp, int samplesize, 129 int nch, int count, void *buffer) 130 { 131 return fread(buffer, nch * samplesize, count, fp); 132 } 133 134 /** 135 * Write WAVE file header 136 */ 137 void wave_write_header(FILE *fp, int bitdepth, int samplesize, 138 int samplerate, int nchannels, int nframes) 139 { 140 struct { 141 struct wave_file file; 142 struct wave_format format; 143 struct wave_data data; 144 } header; 145 146 long data_size = nchannels * nframes * samplesize; 147 long file_size = sizeof(header) + data_size; 148 149 header.file = (struct wave_file){ 150 WAVE_FILE_TYPE_ID, file_size - 8, 151 .fmt_id = WAVE_FILE_FMT_ID 152 }; 153 154 header.format = (struct wave_format){ 155 WAVE_FORMAT_ID, sizeof(header.format) - 8, 156 .fmt = WAVE_FORMAT_PCM, 157 .channels = nchannels, 158 .samplerate = samplerate, 159 .byterate = samplerate * nchannels * samplesize, 160 .framesize = nchannels * samplesize, 161 .bitdepth = bitdepth, 162 }; 163 164 header.data = (struct wave_data){ 165 WAVE_DATA_ID, data_size 166 }; 167 168 fwrite(&header, sizeof(header), 1, fp); 169 } 170 171 /** 172 * Write PCM samples to wave file 173 */ 174 void wave_write_pcm(FILE *fp, int samplesize, 175 const void *_pcm, int nch, int off, int count) 176 { 177 const int8_t *pcm = _pcm; 178 fwrite(pcm + nch * off * samplesize, nch * samplesize, count, fp); 179 } 180