xref: /btstack/3rd-party/lc3-google/tools/wave.c (revision 4c4eb519208b4224604d94b3ed1931841ddd93bb)
14930cef6SMatthias Ringwald /******************************************************************************
24930cef6SMatthias Ringwald  *
34930cef6SMatthias Ringwald  *  Copyright 2022 Google LLC
44930cef6SMatthias Ringwald  *
54930cef6SMatthias Ringwald  *  Licensed under the Apache License, Version 2.0 (the "License");
64930cef6SMatthias Ringwald  *  you may not use this file except in compliance with the License.
74930cef6SMatthias Ringwald  *  You may obtain a copy of the License at:
84930cef6SMatthias Ringwald  *
94930cef6SMatthias Ringwald  *  http://www.apache.org/licenses/LICENSE-2.0
104930cef6SMatthias Ringwald  *
114930cef6SMatthias Ringwald  *  Unless required by applicable law or agreed to in writing, software
124930cef6SMatthias Ringwald  *  distributed under the License is distributed on an "AS IS" BASIS,
134930cef6SMatthias Ringwald  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144930cef6SMatthias Ringwald  *  See the License for the specific language governing permissions and
154930cef6SMatthias Ringwald  *  limitations under the License.
164930cef6SMatthias Ringwald  *
174930cef6SMatthias Ringwald  ******************************************************************************/
184930cef6SMatthias Ringwald 
194930cef6SMatthias Ringwald #include <stdint.h>
204930cef6SMatthias Ringwald #include "wave.h"
214930cef6SMatthias Ringwald 
224930cef6SMatthias Ringwald 
234930cef6SMatthias Ringwald /**
244930cef6SMatthias Ringwald  * Id formatting
254930cef6SMatthias Ringwald  */
264930cef6SMatthias Ringwald 
274930cef6SMatthias Ringwald #define __WAVE_ID(s) \
284930cef6SMatthias Ringwald     (uint32_t)( s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) )
294930cef6SMatthias Ringwald 
304930cef6SMatthias Ringwald 
314930cef6SMatthias Ringwald /**
324930cef6SMatthias Ringwald  * File format statement
334930cef6SMatthias Ringwald  * | type_id     WAVE_FILE_TYPE_ID
344930cef6SMatthias Ringwald  * | size        File size - 8 bytes
354930cef6SMatthias Ringwald  * | type_id     WAVE_FILE_FMT_ID
364930cef6SMatthias Ringwald  */
374930cef6SMatthias Ringwald 
384930cef6SMatthias Ringwald #define WAVE_FILE_TYPE_ID  __WAVE_ID("RIFF")
394930cef6SMatthias Ringwald #define WAVE_FILE_FMT_ID   __WAVE_ID("WAVE")
404930cef6SMatthias Ringwald 
414930cef6SMatthias Ringwald struct wave_file {
424930cef6SMatthias Ringwald     uint32_t type_id;
434930cef6SMatthias Ringwald     uint32_t size;
444930cef6SMatthias Ringwald     uint32_t fmt_id;
454930cef6SMatthias Ringwald };
464930cef6SMatthias Ringwald 
474930cef6SMatthias Ringwald 
484930cef6SMatthias Ringwald /**
494930cef6SMatthias Ringwald  * Audio format statement
504930cef6SMatthias Ringwald  * | id          WAVE_FORMAT_ID
514930cef6SMatthias Ringwald  * | size        Size of the block - 8 bytes (= 16 bytes)
524930cef6SMatthias Ringwald  * | format      WAVE_FORMAT_PCM
534930cef6SMatthias Ringwald  * | channels    Number of channels
544930cef6SMatthias Ringwald  * | samplerate  Sampling rate
554930cef6SMatthias Ringwald  * | byterate    Bytes per secondes = `samplerate * framesize`
564930cef6SMatthias Ringwald  * | framesize   Bytes per sampling time = `channels * bitdepth / 8`
574930cef6SMatthias Ringwald  * | bitdepth    Number of bits per sample
584930cef6SMatthias Ringwald  */
594930cef6SMatthias Ringwald 
604930cef6SMatthias Ringwald #define WAVE_FORMAT_ID   __WAVE_ID("fmt ")
614930cef6SMatthias Ringwald #define WAVE_FORMAT_PCM  1
624930cef6SMatthias Ringwald 
634930cef6SMatthias Ringwald struct wave_format {
644930cef6SMatthias Ringwald     uint32_t id;
654930cef6SMatthias Ringwald     uint32_t size;
664930cef6SMatthias Ringwald     uint16_t fmt;
674930cef6SMatthias Ringwald     uint16_t channels;
684930cef6SMatthias Ringwald     uint32_t samplerate;
694930cef6SMatthias Ringwald     uint32_t byterate;
704930cef6SMatthias Ringwald     uint16_t framesize;
714930cef6SMatthias Ringwald     uint16_t bitdepth;
724930cef6SMatthias Ringwald };
734930cef6SMatthias Ringwald 
744930cef6SMatthias Ringwald 
754930cef6SMatthias Ringwald /**
764930cef6SMatthias Ringwald  * Audio data statement
774930cef6SMatthias Ringwald  * | id          WAV_DATA_ID
784930cef6SMatthias Ringwald  * | size        Size of the data following
794930cef6SMatthias Ringwald  */
804930cef6SMatthias Ringwald 
814930cef6SMatthias Ringwald #define WAVE_DATA_ID  __WAVE_ID("data")
824930cef6SMatthias Ringwald 
834930cef6SMatthias Ringwald struct wave_data {
844930cef6SMatthias Ringwald     uint32_t id;
854930cef6SMatthias Ringwald     uint32_t size;
864930cef6SMatthias Ringwald };
874930cef6SMatthias Ringwald 
884930cef6SMatthias Ringwald 
894930cef6SMatthias Ringwald /**
904930cef6SMatthias Ringwald  * Read WAVE file header
914930cef6SMatthias Ringwald  */
924930cef6SMatthias Ringwald int wave_read_header(FILE *fp, int *bitdepth, int *samplesize,
934930cef6SMatthias Ringwald     int *samplerate, int *nchannels, int *nframes)
944930cef6SMatthias Ringwald {
954930cef6SMatthias Ringwald     struct wave_file file;
964930cef6SMatthias Ringwald     struct wave_format format;
974930cef6SMatthias Ringwald     struct wave_data data;
984930cef6SMatthias Ringwald 
994930cef6SMatthias Ringwald     if (fread(&file, sizeof(file), 1, fp) != 1
1004930cef6SMatthias Ringwald             || file.type_id != WAVE_FILE_TYPE_ID
1014930cef6SMatthias Ringwald             || file.fmt_id  != WAVE_FILE_FMT_ID)
1024930cef6SMatthias Ringwald         return -1;
1034930cef6SMatthias Ringwald 
1044930cef6SMatthias Ringwald     if (fread(&format, sizeof(format), 1, fp) != 1
1054930cef6SMatthias Ringwald             || format.id         != WAVE_FORMAT_ID
1064930cef6SMatthias Ringwald             || format.fmt        != WAVE_FORMAT_PCM
107*4c4eb519SMatthias Ringwald             || format.channels   <= 0
108*4c4eb519SMatthias Ringwald             || format.samplerate <= 0
109*4c4eb519SMatthias Ringwald             || format.framesize  <= 0
1104930cef6SMatthias Ringwald             || format.byterate   != format.samplerate * format.framesize)
1114930cef6SMatthias Ringwald         return -1;
1124930cef6SMatthias Ringwald 
1134930cef6SMatthias Ringwald     fseek(fp, sizeof(format) - (8 + format.size), SEEK_CUR);
1144930cef6SMatthias Ringwald 
1154930cef6SMatthias Ringwald     if (fread(&data, sizeof(data), 1, fp) != 1
1164930cef6SMatthias Ringwald             || data.id != WAVE_DATA_ID)
1174930cef6SMatthias Ringwald         return -1;
1184930cef6SMatthias Ringwald 
1194930cef6SMatthias Ringwald     *bitdepth = format.bitdepth;
1204930cef6SMatthias Ringwald     *samplesize = format.framesize / format.channels;
1214930cef6SMatthias Ringwald     *samplerate = format.samplerate;
1224930cef6SMatthias Ringwald     *nchannels = format.channels;
1234930cef6SMatthias Ringwald     *nframes = data.size / format.framesize;
1244930cef6SMatthias Ringwald 
1254930cef6SMatthias Ringwald     return 0;
1264930cef6SMatthias Ringwald }
1274930cef6SMatthias Ringwald 
1284930cef6SMatthias Ringwald /**
1294930cef6SMatthias Ringwald  * Read PCM samples from wave file
1304930cef6SMatthias Ringwald  */
1314930cef6SMatthias Ringwald int wave_read_pcm(FILE *fp, int samplesize,
1324930cef6SMatthias Ringwald     int nch, int count, void *buffer)
1334930cef6SMatthias Ringwald {
1344930cef6SMatthias Ringwald     return fread(buffer, nch * samplesize, count, fp);
1354930cef6SMatthias Ringwald }
1364930cef6SMatthias Ringwald 
1374930cef6SMatthias Ringwald /**
1384930cef6SMatthias Ringwald  * Write WAVE file header
1394930cef6SMatthias Ringwald  */
1404930cef6SMatthias Ringwald void wave_write_header(FILE *fp, int bitdepth, int samplesize,
1414930cef6SMatthias Ringwald     int samplerate, int nchannels, int nframes)
1424930cef6SMatthias Ringwald {
1434930cef6SMatthias Ringwald     struct {
1444930cef6SMatthias Ringwald         struct wave_file file;
1454930cef6SMatthias Ringwald         struct wave_format format;
1464930cef6SMatthias Ringwald         struct wave_data data;
1474930cef6SMatthias Ringwald     } header;
1484930cef6SMatthias Ringwald 
1494930cef6SMatthias Ringwald     long data_size = nchannels * nframes * samplesize;
1504930cef6SMatthias Ringwald     long file_size = sizeof(header) + data_size;
1514930cef6SMatthias Ringwald 
1524930cef6SMatthias Ringwald     header.file = (struct wave_file){
1534930cef6SMatthias Ringwald         WAVE_FILE_TYPE_ID, file_size - 8,
1544930cef6SMatthias Ringwald         .fmt_id = WAVE_FILE_FMT_ID
1554930cef6SMatthias Ringwald     };
1564930cef6SMatthias Ringwald 
1574930cef6SMatthias Ringwald     header.format = (struct wave_format){
1584930cef6SMatthias Ringwald         WAVE_FORMAT_ID, sizeof(header.format) - 8,
1594930cef6SMatthias Ringwald         .fmt = WAVE_FORMAT_PCM,
1604930cef6SMatthias Ringwald         .channels = nchannels,
1614930cef6SMatthias Ringwald         .samplerate = samplerate,
1624930cef6SMatthias Ringwald         .byterate = samplerate * nchannels * samplesize,
1634930cef6SMatthias Ringwald         .framesize = nchannels * samplesize,
1644930cef6SMatthias Ringwald         .bitdepth = bitdepth,
1654930cef6SMatthias Ringwald     };
1664930cef6SMatthias Ringwald 
1674930cef6SMatthias Ringwald     header.data = (struct wave_data){
1684930cef6SMatthias Ringwald         WAVE_DATA_ID, data_size
1694930cef6SMatthias Ringwald     };
1704930cef6SMatthias Ringwald 
1714930cef6SMatthias Ringwald     fwrite(&header, sizeof(header), 1, fp);
1724930cef6SMatthias Ringwald }
1734930cef6SMatthias Ringwald 
1744930cef6SMatthias Ringwald /**
1754930cef6SMatthias Ringwald  * Write PCM samples to wave file
1764930cef6SMatthias Ringwald  */
1774930cef6SMatthias Ringwald void wave_write_pcm(FILE *fp, int samplesize,
1784930cef6SMatthias Ringwald     const void *_pcm, int nch, int off, int count)
1794930cef6SMatthias Ringwald {
1804930cef6SMatthias Ringwald     const int8_t *pcm = _pcm;
1814930cef6SMatthias Ringwald     fwrite(pcm + nch * off * samplesize, nch * samplesize, count, fp);
1824930cef6SMatthias Ringwald }
183