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