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