1ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox/* Sonic library 2ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox Copyright 2010 3ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox Bill Cox 4ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox This file is part of the Sonic Library. 5ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 660eeb064f62a106069d2ce148fabd724f9df9780Bill Cox This file is licensed under the Apache 2.0 license. 760eeb064f62a106069d2ce148fabd724f9df9780Bill Cox*/ 8ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 9ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox/* 10ca02d872cc6cb963d438ceae6d011bd04c658b3Bill CoxThis file supports read/write wave files. 11ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox*/ 12ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox#include <stdio.h> 13ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox#include <stdlib.h> 140c4c06089176345f408613c8da6a5585a9af9615Bill Cox#include <string.h> 15ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox#include "wave.h" 16ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 17ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox#define WAVE_BUF_LEN 4096 18ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 19ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Coxstruct waveFileStruct { 202081ea488f9b07d61efc7c9106c43cb1c6cea1a5Bill Cox int numChannels; 21ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int sampleRate; 22ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox FILE *soundFile; 23ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int bytesWritten; /* The number of bytes written so far, including header */ 24ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int failed; 25ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int isInput; 26ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox}; 27ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 28ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Write a string to a file. */ 29ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void writeBytes( 30ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 31ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox void *bytes, 32ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int length) 33ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 34ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox size_t bytesWritten; 35ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 36ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(file->failed) { 37ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return; 38ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 39ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytesWritten = fwrite(bytes, sizeof(char), length, file->soundFile); 40ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(bytesWritten != length) { 41ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Unable to write to output file"); 42ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->failed = 1; 43ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 44ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->bytesWritten += bytesWritten; 45ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 46ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 47ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Write a string to a file. */ 48ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void writeString( 49ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 50ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox char *string) 51ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 52ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeBytes(file, string, strlen(string)); 53ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 54ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 55ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Write an integer to a file in little endian order. */ 56ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void writeInt( 57ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 58ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int value) 59ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 60ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox char bytes[4]; 61ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int i; 62ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 63ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox for(i = 0; i < 4; i++) { 64ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytes[i] = value; 65ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox value >>= 8; 66ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 67ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeBytes(file, bytes, 4); 68ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 69ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 70ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Write a short integer to a file in little endian order. */ 71ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void writeShort( 72ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 73ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox short value) 74ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 75ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox char bytes[2]; 76ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int i; 77ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 78ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox for(i = 0; i < 2; i++) { 79ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytes[i] = value; 80ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox value >>= 8; 81ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 82ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeBytes(file, bytes, 2); 83ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 84ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 85ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read bytes from the input file. Return the number of bytes actually read. */ 86ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic int readBytes( 87ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 88ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox void *bytes, 89ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int length) 90ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 91ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(file->failed) { 92ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return 0; 93ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 94ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return fread(bytes, sizeof(char), length, file->soundFile); 95ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 96ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 97ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read an exact number of bytes from the input file. */ 98ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void readExactBytes( 99ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 100ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox void *bytes, 101ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int length) 102ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 103ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int numRead; 104ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 105ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(file->failed) { 106ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return; 107ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 108ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox numRead = fread(bytes, sizeof(char), length, file->soundFile); 109ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(numRead != length) { 110ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Failed to read requested bytes from input file\n"); 111ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->failed = 1; 112ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 113ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 114ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 115ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read an integer from the input file */ 116ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic int readInt( 117ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file) 118ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 119ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox unsigned char bytes[4]; 120ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int value = 0, i; 121ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 122ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox readExactBytes(file, bytes, 4); 123ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox for(i = 3; i >= 0; i--) { 124ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox value <<= 8; 125ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox value |= bytes[i]; 126ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 127ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return value; 128ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 129ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 130ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read a short from the input file */ 131ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic int readShort( 132ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file) 133ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 134ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox unsigned char bytes[2]; 135ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int value = 0, i; 136ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 137ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox readExactBytes(file, bytes, 2); 138ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox for(i = 1; i >= 0; i--) { 139ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox value <<= 8; 140ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox value |= bytes[i]; 141ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 142ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return value; 143ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 144ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 145ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read a string from the input and compare it to an expected string. */ 146ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void expectString( 147ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 148ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox char *expectedString) 149ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 150ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox char buf[11]; /* Be sure that we never call with a longer string */ 151ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int length = strlen(expectedString); 152ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 153ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(length > 10) { 154ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Internal error: expected string too long\n"); 155ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->failed = 1; 156ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } else { 157ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox readExactBytes(file, buf, length); 158ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox buf[length] = '\0'; 159ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(strcmp(expectedString, buf)) { 160ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Unsupported wave file format\n"); 161ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->failed = 1; 162ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 163ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 164ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 165ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 166ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Write the header of the wave file. */ 167ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void writeHeader( 168ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file, 169ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int sampleRate) 170ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 171ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox /* write the wav file per the wav file format */ 172ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeString(file, "RIFF"); /* 00 - RIFF */ 173ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox /* We have to fseek and overwrite this later when we close the file because */ 174ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox /* we don't know how big it is until then. */ 175ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, 36 /* + dataLength */); /* 04 - how big is the rest of this file? */ 176ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeString(file, "WAVE"); /* 08 - WAVE */ 177ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeString(file, "fmt "); /* 12 - fmt */ 178ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, 16); /* 16 - size of this chunk */ 179ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeShort(file, 1); /* 20 - what is the audio format? 1 for PCM = Pulse Code Modulation */ 180ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeShort(file, 1); /* 22 - mono or stereo? 1 or 2? (or 5 or ???) */ 181ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, sampleRate); /* 24 - samples per second (numbers per second) */ 182ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, sampleRate * 2); /* 28 - bytes per second */ 183ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeShort(file, 2); /* 32 - # of bytes in one sample, for all channels */ 184ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeShort(file, 16); /* 34 - how many bits in a sample(number)? usually 16 or 24 */ 185ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeString(file, "data"); /* 36 - data */ 186ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, 0); /* 40 - how big is this data chunk */ 187ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 188ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 189ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read the header of the wave file. */ 190ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic int readHeader( 191ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file) 192ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 193ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int data; 194ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 195ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox expectString(file, "RIFF"); 196ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox data = readInt(file); /* 04 - how big is the rest of this file? */ 197ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox expectString(file, "WAVE"); /* 08 - WAVE */ 198ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox expectString(file, "fmt "); /* 12 - fmt */ 19972ae545d51c561613f57cf87e05016179042e87aMatthew Albright int chunkSize = readInt(file); /* 16 or 18 - size of this chunk */ 20072ae545d51c561613f57cf87e05016179042e87aMatthew Albright if(chunkSize != 16 && chunkSize != 18) { 201ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Only basic wave files are supported\n"); 202ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return 0; 203ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 204ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox data = readShort(file); /* 20 - what is the audio format? 1 for PCM = Pulse Code Modulation */ 205ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(data != 1) { 206ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Only PCM wave files are supported\n"); 207ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return 0; 208ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 209ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->numChannels = readShort(file); /* 22 - mono or stereo? 1 or 2? (or 5 or ???) */ 210ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->sampleRate = readInt(file); /* 24 - samples per second (numbers per second) */ 211ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox readInt(file); /* 28 - bytes per second */ 212ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox readShort(file); /* 32 - # of bytes in one sample, for all channels */ 213ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox data = readShort(file); /* 34 - how many bits in a sample(number)? usually 16 or 24 */ 214ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(data != 16) { 215ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Only 16 bit PCM wave files are supported\n"); 216ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return 0; 217ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 21872ae545d51c561613f57cf87e05016179042e87aMatthew Albright if (chunkSize == 18) { /* ffmpeg writes 18, and so has 2 extra bytes here */ 21972ae545d51c561613f57cf87e05016179042e87aMatthew Albright data = readShort(file); 22072ae545d51c561613f57cf87e05016179042e87aMatthew Albright } 221ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox expectString(file, "data"); /* 36 - data */ 222ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox readInt(file); /* 40 - how big is this data chunk */ 223ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return 1; 224ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 225ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 226ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Close the input or output file and free the waveFile. */ 227ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxstatic void closeFile( 228ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox waveFile file) 229ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox{ 230ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox FILE *soundFile = file->soundFile; 231ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 232ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(soundFile != NULL) { 233ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fclose(soundFile); 234ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->soundFile = NULL; 235ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 236ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox free(file); 237ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox} 238ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox 239ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Open a 16-bit little-endian wav file for reading. It may be mono or stereo. */ 240ca02d872cc6cb963d438ceae6d011bd04c658b3Bill CoxwaveFile openInputWaveFile( 241ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox char *fileName, 2421a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox int *sampleRate, 2431a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox int *numChannels) 244ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{ 245ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox waveFile file; 246ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox FILE *soundFile = fopen(fileName, "rb"); 247ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 248ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox if(soundFile == NULL) { 249ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Unable to open wave file %s for reading\n", fileName); 250ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox return NULL; 251ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox } 252ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox file = (waveFile)calloc(1, sizeof(struct waveFileStruct)); 253ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox file->soundFile = soundFile; 254ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->isInput = 1; 255ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(!readHeader(file)) { 256ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox closeFile(file); 257ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return NULL; 258ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 259ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox *sampleRate = file->sampleRate; 260ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox *numChannels = file->numChannels; 261ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox return file; 262ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox} 263ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 264ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Open a 16-bit little-endian wav file for writing. It may be mono or stereo. */ 265ca02d872cc6cb963d438ceae6d011bd04c658b3Bill CoxwaveFile openOutputWaveFile( 266ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox char *fileName, 2671a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox int sampleRate, 2681a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox int numChannels) 269ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{ 270ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox waveFile file; 271ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox FILE *soundFile = fopen(fileName, "wb"); 272ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 273ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox if(soundFile == NULL) { 274ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Unable to open wave file %s for writing\n", fileName); 275ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox return NULL; 276ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox } 277ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox file = (waveFile)calloc(1, sizeof(struct waveFileStruct)); 278ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox file->soundFile = soundFile; 279ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox file->sampleRate = sampleRate; 280f80718975932650b6f366d6e4b4455b253aa00feBill Cox file->numChannels = numChannels; 281ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeHeader(file, sampleRate); 282ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(file->failed) { 283ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox closeFile(file); 284ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return NULL; 285ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 286ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox return file; 287ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox} 288ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 289ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox/* Close the sound file. */ 290ec23ae004aa4dbe018a443b60cd57791d883be6cBill Coxint closeWaveFile( 291ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox waveFile file) 292ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{ 293ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox FILE *soundFile = file->soundFile; 294ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int passed = 1; 295ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 296ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(!file->isInput) { 297ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(fseek(soundFile, 4, SEEK_SET) != 0) { 298ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Failed to seek on input file.\n"); 299ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox passed = 0; 300ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } else { 301ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox /* Now update the file to have the correct size. */ 302ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, file->bytesWritten - 8); 303ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(file->failed) { 304ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Failed to write wave file size.\n"); 305ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox passed = 0; 306ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 307ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(fseek(soundFile, 40, SEEK_SET) != 0) { 308ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Failed to seek on input file.\n"); 309ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox passed = 0; 310ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } else { 311ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox /* Now update the file to have the correct size. */ 312ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeInt(file, file->bytesWritten - 48); 313ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(file->failed) { 314ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox fprintf(stderr, "Failed to write wave file size.\n"); 315ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox passed = 0; 316ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 317ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 318ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 319ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 320ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox closeFile(file); 321ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return passed; 322ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox} 323ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 324ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox/* Read from the wave file. Return the number of samples read. */ 325ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Coxint readFromWaveFile( 326ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox waveFile file, 3270c4c06089176345f408613c8da6a5585a9af9615Bill Cox short *buffer, 328ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox int maxSamples) 329ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{ 330ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int i, bytesRead, samplesRead; 331ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int bytePos = 0; 332ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox unsigned char bytes[WAVE_BUF_LEN]; 333ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox short sample; 334ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 335ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(maxSamples*file->numChannels*2 > WAVE_BUF_LEN) { 336ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox maxSamples = WAVE_BUF_LEN/(file->numChannels*2); 337ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 338ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytesRead = readBytes(file, bytes, maxSamples*file->numChannels*2); 339ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox samplesRead = bytesRead/(file->numChannels*2); 340ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox for(i = 0; i < samplesRead*file->numChannels; i++) { 341ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox sample = bytes[bytePos++]; 342ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox sample |= (unsigned int)bytes[bytePos++] << 8; 343ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox *buffer++ = sample; 344ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox } 345ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return samplesRead; 346ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox} 347ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 348ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox/* Write to the wave file. */ 349ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Coxint writeToWaveFile( 350ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox waveFile file, 3510c4c06089176345f408613c8da6a5585a9af9615Bill Cox short *buffer, 352ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox int numSamples) 353ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{ 354ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int i; 355ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int bytePos = 0; 356ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox unsigned char bytes[WAVE_BUF_LEN]; 357ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox short sample; 358ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox int total = numSamples*file->numChannels; 359ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox 360ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox for(i = 0; i < total; i++) { 361ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(bytePos == WAVE_BUF_LEN) { 362ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeBytes(file, bytes, bytePos); 363ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytePos = 0; 364ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 365ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox sample = buffer[i]; 366ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytes[bytePos++] = sample; 367ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox bytes[bytePos++] = sample >> 8; 368ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox } 369ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox if(bytePos != 0) { 370ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox writeBytes(file, bytes, bytePos); 371ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox } 372ec23ae004aa4dbe018a443b60cd57791d883be6cBill Cox return file->failed; 373ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox} 374