xref: /btstack/3rd-party/lc3-google/tools/wave.c (revision 6897da5c53aac5b1f90f41b5b15d0bd43d61dfff)
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)
52*6897da5cSDirk Helbig  * | format      WAVE_FORMAT_PCM or WAVE_FORMAT_EXT
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 ")
61*6897da5cSDirk Helbig #define WAVE_FORMAT_PCM  0x0001
62*6897da5cSDirk Helbig #define WAVE_FORMAT_EXT  0xfffe
634930cef6SMatthias Ringwald 
644930cef6SMatthias Ringwald struct wave_format {
654930cef6SMatthias Ringwald     uint32_t id;
664930cef6SMatthias Ringwald     uint32_t size;
674930cef6SMatthias Ringwald     uint16_t fmt;
684930cef6SMatthias Ringwald     uint16_t channels;
694930cef6SMatthias Ringwald     uint32_t samplerate;
704930cef6SMatthias Ringwald     uint32_t byterate;
714930cef6SMatthias Ringwald     uint16_t framesize;
724930cef6SMatthias Ringwald     uint16_t bitdepth;
734930cef6SMatthias Ringwald };
744930cef6SMatthias Ringwald 
754930cef6SMatthias Ringwald 
764930cef6SMatthias Ringwald /**
774930cef6SMatthias Ringwald  * Audio data statement
784930cef6SMatthias Ringwald  * | id          WAV_DATA_ID
794930cef6SMatthias Ringwald  * | size        Size of the data following
804930cef6SMatthias Ringwald  */
814930cef6SMatthias Ringwald 
824930cef6SMatthias Ringwald #define WAVE_DATA_ID  __WAVE_ID("data")
834930cef6SMatthias Ringwald 
844930cef6SMatthias Ringwald struct wave_data {
854930cef6SMatthias Ringwald     uint32_t id;
864930cef6SMatthias Ringwald     uint32_t size;
874930cef6SMatthias Ringwald };
884930cef6SMatthias Ringwald 
894930cef6SMatthias Ringwald 
904930cef6SMatthias Ringwald /**
914930cef6SMatthias Ringwald  * Read WAVE file header
924930cef6SMatthias Ringwald  */
wave_read_header(FILE * fp,int * bitdepth,int * samplesize,int * samplerate,int * nchannels,int * nframes)934930cef6SMatthias Ringwald int wave_read_header(FILE *fp, int *bitdepth, int *samplesize,
944930cef6SMatthias Ringwald     int *samplerate, int *nchannels, int *nframes)
954930cef6SMatthias Ringwald {
964930cef6SMatthias Ringwald     struct wave_file file;
974930cef6SMatthias Ringwald     struct wave_format format;
984930cef6SMatthias Ringwald     struct wave_data data;
994930cef6SMatthias Ringwald 
1004930cef6SMatthias Ringwald     if (fread(&file, sizeof(file), 1, fp) != 1
1014930cef6SMatthias Ringwald             || file.type_id != WAVE_FILE_TYPE_ID
1024930cef6SMatthias Ringwald             || file.fmt_id  != WAVE_FILE_FMT_ID)
1034930cef6SMatthias Ringwald         return -1;
1044930cef6SMatthias Ringwald 
1054930cef6SMatthias Ringwald     if (fread(&format, sizeof(format), 1, fp) != 1
1064930cef6SMatthias Ringwald             || format.id         != WAVE_FORMAT_ID
107*6897da5cSDirk Helbig             || ( format.fmt      != WAVE_FORMAT_PCM &&
108*6897da5cSDirk Helbig                  format.fmt      != WAVE_FORMAT_EXT   )
1094c4eb519SMatthias Ringwald             || format.channels   <= 0
1104c4eb519SMatthias Ringwald             || format.samplerate <= 0
1114c4eb519SMatthias Ringwald             || format.framesize  <= 0
1124930cef6SMatthias Ringwald             || format.byterate   != format.samplerate * format.framesize)
1134930cef6SMatthias Ringwald         return -1;
1144930cef6SMatthias Ringwald 
1154930cef6SMatthias Ringwald     fseek(fp, sizeof(format) - (8 + format.size), SEEK_CUR);
1164930cef6SMatthias Ringwald 
117*6897da5cSDirk Helbig     for ( ; fread(&data, sizeof(data), 1, fp) == 1 && data.id != WAVE_DATA_ID
118*6897da5cSDirk Helbig           ; fseek(fp, data.size, SEEK_CUR) );
119*6897da5cSDirk Helbig 
120*6897da5cSDirk Helbig     if (feof(fp))
1214930cef6SMatthias Ringwald       return -1;
1224930cef6SMatthias Ringwald 
1234930cef6SMatthias Ringwald     *bitdepth = format.bitdepth;
1244930cef6SMatthias Ringwald     *samplesize = format.framesize / format.channels;
1254930cef6SMatthias Ringwald     *samplerate = format.samplerate;
1264930cef6SMatthias Ringwald     *nchannels = format.channels;
1274930cef6SMatthias Ringwald     *nframes = data.size / format.framesize;
1284930cef6SMatthias Ringwald 
1294930cef6SMatthias Ringwald     return 0;
1304930cef6SMatthias Ringwald }
1314930cef6SMatthias Ringwald 
1324930cef6SMatthias Ringwald /**
1334930cef6SMatthias Ringwald  * Read PCM samples from wave file
1344930cef6SMatthias Ringwald  */
wave_read_pcm(FILE * fp,int samplesize,int nch,int count,void * buffer)1354930cef6SMatthias Ringwald int wave_read_pcm(FILE *fp, int samplesize,
1364930cef6SMatthias Ringwald     int nch, int count, void *buffer)
1374930cef6SMatthias Ringwald {
1384930cef6SMatthias Ringwald     return fread(buffer, nch * samplesize, count, fp);
1394930cef6SMatthias Ringwald }
1404930cef6SMatthias Ringwald 
1414930cef6SMatthias Ringwald /**
1424930cef6SMatthias Ringwald  * Write WAVE file header
1434930cef6SMatthias Ringwald  */
wave_write_header(FILE * fp,int bitdepth,int samplesize,int samplerate,int nchannels,int nframes)1444930cef6SMatthias Ringwald void wave_write_header(FILE *fp, int bitdepth, int samplesize,
1454930cef6SMatthias Ringwald     int samplerate, int nchannels, int nframes)
1464930cef6SMatthias Ringwald {
1474930cef6SMatthias Ringwald     struct {
1484930cef6SMatthias Ringwald         struct wave_file file;
1494930cef6SMatthias Ringwald         struct wave_format format;
1504930cef6SMatthias Ringwald         struct wave_data data;
1514930cef6SMatthias Ringwald     } header;
1524930cef6SMatthias Ringwald 
1534930cef6SMatthias Ringwald     long data_size = nchannels * nframes * samplesize;
1544930cef6SMatthias Ringwald     long file_size = sizeof(header) + data_size;
1554930cef6SMatthias Ringwald 
1564930cef6SMatthias Ringwald     header.file = (struct wave_file){
1574930cef6SMatthias Ringwald         WAVE_FILE_TYPE_ID, file_size - 8,
1584930cef6SMatthias Ringwald         .fmt_id = WAVE_FILE_FMT_ID
1594930cef6SMatthias Ringwald     };
1604930cef6SMatthias Ringwald 
1614930cef6SMatthias Ringwald     header.format = (struct wave_format){
1624930cef6SMatthias Ringwald         WAVE_FORMAT_ID, sizeof(header.format) - 8,
1634930cef6SMatthias Ringwald         .fmt = WAVE_FORMAT_PCM,
1644930cef6SMatthias Ringwald         .channels = nchannels,
1654930cef6SMatthias Ringwald         .samplerate = samplerate,
1664930cef6SMatthias Ringwald         .byterate = samplerate * nchannels * samplesize,
1674930cef6SMatthias Ringwald         .framesize = nchannels * samplesize,
1684930cef6SMatthias Ringwald         .bitdepth = bitdepth,
1694930cef6SMatthias Ringwald     };
1704930cef6SMatthias Ringwald 
1714930cef6SMatthias Ringwald     header.data = (struct wave_data){
1724930cef6SMatthias Ringwald         WAVE_DATA_ID, data_size
1734930cef6SMatthias Ringwald     };
1744930cef6SMatthias Ringwald 
1754930cef6SMatthias Ringwald     fwrite(&header, sizeof(header), 1, fp);
1764930cef6SMatthias Ringwald }
1774930cef6SMatthias Ringwald 
1784930cef6SMatthias Ringwald /**
1794930cef6SMatthias Ringwald  * Write PCM samples to wave file
1804930cef6SMatthias Ringwald  */
wave_write_pcm(FILE * fp,int samplesize,const void * _pcm,int nch,int off,int count)1814930cef6SMatthias Ringwald void wave_write_pcm(FILE *fp, int samplesize,
1824930cef6SMatthias Ringwald     const void *_pcm, int nch, int off, int count)
1834930cef6SMatthias Ringwald {
1844930cef6SMatthias Ringwald     const int8_t *pcm = _pcm;
1854930cef6SMatthias Ringwald     fwrite(pcm + nch * off * samplesize, nch * samplesize, count, fp);
1864930cef6SMatthias Ringwald }
187