// Copyright (c) 2008-2010 Raynaldo (Wildicv) Rivera, Joshua (Dark_Kilauea) Jones // This file is part of the "cAudio Engine" // For conditions of distribution and use, see copyright notice in cAudio.h #include "../Headers/cWavDecoder.h" #include #ifdef CAUDIO_COMPILE_WITH_WAV_DECODER namespace cAudio { cWavDecoder::cWavDecoder(IDataSource* stream) : IAudioDecoder(stream), Valid(false) { const char* RIFFTAG = "RIFF"; const char* WAVETAG = "WAVE"; const char* FORMATTAG = "fmt "; const char* DATATAG = "data"; char ident[4]; int tempint32 = 0; short tempint16 = 0; char tempint8 = 0; unsigned int startOffset = 0; //Read the first 4 bytes Stream->seek(0, false); Stream->read(ident, 4); //Check to see if it is a valid RIFF file if(strncmp(ident, RIFFTAG, 4) == 0) { Stream->read(&tempint32, 4); //Check to see if the file is big enough to be valid (not completely accurate) if(tempint32 >= 44) { Stream->read(ident, 4); //Check that it is a wave file if(strncmp(ident, WAVETAG, 4) == 0) { //Save our position startOffset = Stream->getCurrentPos(); //Scan for the first fmt chuck (not necessarily right after) do { Stream->read(ident, 4); } while((strncmp(ident, FORMATTAG, 4) != 0) && (Stream->getCurrentPos() < Stream->getSize())); //Did we find it? if(Stream->getCurrentPos() < (Stream->getSize() - 16)) { //Yes, read it in Stream->read(&tempint32, 4); if(tempint32 >= 16) { //Check that it is in PCM format, we don't support compressed wavs Stream->read(&tempint16, 2); if(tempint16 == 1) { Stream->read(&tempint16, 2); Channels = tempint16; //We only support mono or stereo wavs if(Channels == 1 || Channels == 2) { Stream->read(&tempint32, 4); SampleRate = tempint32; Stream->read(&tempint32, 4); ByteRate = tempint32; Stream->read(&tempint16, 2); BlockAlign = tempint16; Stream->read(&tempint16, 2); BitsPerSample = tempint16; //We only support 8 bit or 16 bit wavs if(BitsPerSample == 8 || BitsPerSample == 16) { //Reset our pointer to start scanning for the data block Stream->seek(startOffset, false); //Scan for the first data chuck (not necessarily right after) do { Stream->read(ident, 4); } while((strncmp(ident, DATATAG, 4) != 0) && (Stream->getCurrentPos() < Stream->getSize())); //Did we find it? if(Stream->getCurrentPos() < Stream->getSize()) { //Get size of data block Stream->read(&tempint32, 4); DataSize = tempint32; DataOffset = Stream->getCurrentPos(); Valid = true; } } } } } } } } } } cWavDecoder::~cWavDecoder() { Channels = 0; SampleRate = 0; ByteRate = 0; BlockAlign = 0; BitsPerSample = 0; DataSize = 0; DataOffset = 0; Valid = false; } AudioFormats cWavDecoder::getFormat() { if(Channels == 1 && BitsPerSample == 8) return EAF_8BIT_MONO; else if(Channels == 1 && BitsPerSample == 16) return EAF_16BIT_MONO; else if(Channels == 2 && BitsPerSample == 8) return EAF_8BIT_STEREO; else return EAF_16BIT_STEREO; } int cWavDecoder::getFrequency() { return SampleRate; } bool cWavDecoder::isSeekingSupported() { return true; } bool cWavDecoder::isValid() { return Valid; } int cWavDecoder::readAudioData(void* output, int amount) { int currentPos = Stream->getCurrentPos(); int startPos = DataOffset; int endPos = DataOffset + DataSize; int amountToRead = amount; //Bounds checks (and adjustments if possible) if(currentPos > endPos) return 0; if(currentPos < startPos) { Stream->seek(startPos, false); currentPos = Stream->getCurrentPos(); } if((currentPos + amountToRead) > endPos) amountToRead = endPos - currentPos; if(amountToRead < 0) amountToRead = 0; return Stream->read(output,amountToRead); } bool cWavDecoder::setPosition(int position, bool relative) { int currentPos = Stream->getCurrentPos(); int startPos = DataOffset; int endPos = DataOffset + DataSize; //Bounds checks (and adjustments if possible) if(!relative && position < startPos) position = startPos; if(!relative && position > endPos) position = endPos; if(relative && currentPos + position < startPos) position = startPos - currentPos; if(relative && currentPos + position > startPos) position = endPos - currentPos; Stream->seek(position,relative); return true; } bool cWavDecoder::seek(float seconds,bool relative) { int amountToSeek = seconds * (float)SampleRate * (float)Channels * (float)(BitsPerSample/8); return setPosition(amountToSeek, relative); } float cWavDecoder::getTotalTime() { return (float)Stream->getSize() / ((float)SampleRate * (float)Channels * (float)(BitsPerSample/8)); } int cWavDecoder::getTotalSize() { return Stream->getSize(); } int cWavDecoder::getCompressedSize() { return Stream->getSize(); } float cWavDecoder::getCurrentTime() { return (float)Stream->getCurrentPos() / ((float)SampleRate * (float)Channels * (float)(BitsPerSample/8)); } int cWavDecoder::getCurrentPosition() { return Stream->getCurrentPos(); } int cWavDecoder::getCurrentCompressedPosition() { return Stream->getCurrentPos(); } }; #endif