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 */
wave_read_header(FILE * fp,int * bitdepth,int * samplesize,int * samplerate,int * nchannels,int * nframes)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 */
wave_read_pcm(FILE * fp,int samplesize,int nch,int count,void * buffer)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 */
wave_write_header(FILE * fp,int bitdepth,int samplesize,int samplerate,int nchannels,int nframes)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 */
wave_write_pcm(FILE * fp,int samplesize,const void * _pcm,int nch,int off,int count)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