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