Files
starruler-linux/source/sound/source/CSSWave.cpp
T
2018-07-17 14:15:37 +02:00

141 lines
3.5 KiB
C++

#include "CSSWave.h"
#include "al.h"
#include "SLoadError.h"
#include "SAutoDrop.h"
#include <string.h>
#define read(v, s) fread(v, 1, s, file)
namespace audio {
CSSWave::CSSWave(FILE* file, ISoundDevice* device) : CSoundSource(device), length_ms(-1) {
soundBuffer = device->getFreeBufferID();
if(!alIsBuffer(soundBuffer))
throw SLoadError("No free buffers");
char dwordTxt[5]; dwordTxt[4] = '\0';
unsigned int dwordData;
//Check for 'RIFF' identifier
read(dwordTxt, 4);
if(strcmp(dwordTxt, "RIFF") != 0)
throw NotThisType();
//Skip over ChunkSize
fseek(file, 4, SEEK_CUR);
//Check for the 'WAVE' identifier
read(dwordTxt, 4);
if(strcmp(dwordTxt, "WAVE") != 0)
throw SLoadError("Can only load WAVE formats");
//Check for the 'fmt ' identifier
read(dwordTxt, 4);
if(strcmp(dwordTxt, "fmt ") != 0)
throw SLoadError("Can only load WAVE formats");
unsigned int chunkSize;
read(&chunkSize, 4);
unsigned short format;
read(&format, 2); //1 for PCM, 0xFFFE for extensible
fseek(file, -2, SEEK_CUR);
if(format != 1 && format != 0xFFFE)
throw SLoadError("Can only load WAVE files with PCM encoded data");
struct {
unsigned short format;
unsigned short numChannels;
unsigned int sampleRate;
unsigned int byteRate;
unsigned short blockAlign;
unsigned short bitsPerSample;
unsigned short extensionSize;
} PCMData;
if(format == 1) {
read(&PCMData, 16);
PCMData.extensionSize = 0;
if(chunkSize > 16)
fseek(file, (long)(chunkSize - 16), SEEK_CUR);
}
else {
read(&PCMData, 18);
if(PCMData.extensionSize != 22)
throw SLoadError("Can only load WAVE files with PCM encoded data");
//Skip over valid bits/sample and speaker mask sections
fseek(file, 6, SEEK_CUR);
//Read true format and skip remaining data
read(&format, 2);
fseek(file, 14, SEEK_CUR);
}
if(format != 1)
throw SLoadError("Can only load uncompressed PCM-formatted WAVE files", true);
if(PCMData.numChannels > 2)
throw SLoadError("Can only load 1 or 2 channel WAVE files", true);
if(PCMData.bitsPerSample != 8 && PCMData.bitsPerSample != 16)
throw SLoadError("Can only load 8 or 16 bit sampled WAVE files", true);
read(dwordTxt, 4);
if(strcmp(dwordTxt, "fact") == 0) {
//Skip over the 'fact' section, if it exists
read(&dwordData, 4);
fseek(file, (long)dwordData, SEEK_CUR);
read(dwordTxt, 4);
}
if(strcmp(dwordTxt, "data") != 0)
throw SLoadError("WAVE file missing data portion", true);
read(&dwordData, 4);
if(dwordData > 16000000)
throw SLoadError("WAVE files greater than 16MB not supported", true);
unsigned char* data = new unsigned char[dwordData];
if(read(data, dwordData) != dwordData) {
delete[] data;
throw SLoadError("File did not contain sufficient samples", true);
}
length_ms = int(dwordData / (PCMData.numChannels * (PCMData.bitsPerSample/8) * PCMData.sampleRate));
alBufferData(soundBuffer,
PCMData.numChannels == 2 ? ( PCMData.bitsPerSample == 8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16 ) : (PCMData.bitsPerSample == 8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16),
data, (ALsizei)dwordData, (ALsizei)PCMData.sampleRate);
delete[] data;
}
int CSSWave::getLength_ms() const {
return length_ms;
}
bool CSSWave::isStreaming() const {
return false;
}
bufferID CSSWave::getBuffer() const {
return soundBuffer;
}
bufferID CSSWave::getStreamBuffer(long& point) const {
return invalidBuffer;
}
CSSWave::~CSSWave() {
}
CSoundSource* load_wav(FILE* file, ISoundDevice* device) {
return new CSSWave(file, device);
}
};