/*
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");
}
}