/* Copyright (C) 2010-2012 Florian Jung This file is part of flo's FM synth. flo's FM synth is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. flo's FM synth is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with flo's FM synth. If not, see . */ #include #include #include #include "readwave.h" #include "util.h" #include "fixed.h" using namespace std; unsigned long int le_dword(unsigned char *b) { return b[0]+256*b[1]+256*256*b[2]+256*256*256*b[3]; } unsigned int le_word(unsigned char *b) { return b[0]+256*b[1]; } signed int le_sword(unsigned char *b) { int x=le_word(b); if (x & (1<<15) ) return - ((~(x-1))&0xFFFF); else return x; } void safe_fread(void* buf, int size, int n, FILE* f) { int x=fread(buf,size,n,f); if (x!=n) throw string("got end-of-file or error while reading from file"); } void read_wave(const char *fn, custom_wave_t *result) { try { int fmt=0, chans=0, sr=0, bits=0, bytes=0, filelen=0; unsigned char buf[100]; FILE *f=fopen(fn,"r"); if (f==NULL) throw string("could not open file"); safe_fread(buf, 1, 12, f); if ((memcmp(buf,"RIFF",4)==0) && (memcmp(buf+8,"WAVE",4)==0)) { filelen=le_dword(buf+4); while (!feof(f)) { int chunklen; safe_fread(buf,1,8,f); //read chunk name and chunk size if (memcmp(buf,"fmt ",4)==0) //it's the fmt-chunk! { chunklen=le_dword(buf+4); safe_fread(buf,1,chunklen,f); fmt=le_word(buf); //should be 1 for PCM chans=le_word(buf+2); //number of channels sr=le_dword(buf+4); //sampling rate bits=le_word(buf+14); //bits per sample (8 or 16) if (fmt!=1) throw string("invalid format, expected PCM"); if ((bits!=8) && (bits!=16)) throw string("invalid format, expected 8 or 16 bits"); if (chans==0) throw string("invalid format, n_channels may not be zero"); if (chans>=2) output_note("NOTE: wavefile '"+string(fn)+"' is multichannel, using the left\nchannel and ignoring the rest..."); if (sr==0) throw string("sampling rate may not be zero"); } else if (memcmp(buf,"data",4)==0) //it's the data-chunk! { chunklen=le_dword(buf+4); if (sr==0) throw string("found data chunk before the fmt chunk"); if (bits==8) bytes=1; else if (bits==16) bytes=2; int n_samples=chunklen/(bytes * chans); result->samp_rate=fixed_t(sr)<wave_len=n_samples; result->wave=new fixed_t[n_samples]; double sample; for (int i=0;iwave[i]=sample*ONE; } break; } else //unknown chunk, skip it { chunklen=le_dword(buf+4); safe_fread(buf,1,chunklen,f); } } } else { //not a valid wave file! throw string("not a valid RIFF-WAVE file"); } } catch (string err) { output_warning("ERROR: could not read '"+string(fn)+"': "+err+"\n a default waveform (sine) will be loaded"); } }