Initial commit
This commit is contained in:
334
Torque/SDK/engine/audio/wavStreamSource.cc
Normal file
334
Torque/SDK/engine/audio/wavStreamSource.cc
Normal file
@@ -0,0 +1,334 @@
|
||||
//--------------------------------------
|
||||
// audioStreamSource.cc
|
||||
// implementation of streaming audio source
|
||||
//
|
||||
// Kurtis Seebaldt
|
||||
//--------------------------------------
|
||||
|
||||
#include "audio/wavStreamSource.h"
|
||||
|
||||
#define BUFFERSIZE 32768
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ALubyte riff[4]; // 'RIFF'
|
||||
ALsizei riffSize;
|
||||
ALubyte wave[4]; // 'WAVE'
|
||||
ALubyte fmt[4]; // 'fmt '
|
||||
ALuint fmtSize;
|
||||
ALushort Format;
|
||||
ALushort Channels;
|
||||
ALuint SamplesPerSec;
|
||||
ALuint BytesPerSec;
|
||||
ALushort BlockAlign;
|
||||
ALushort BitsPerSample;
|
||||
ALubyte data[4]; // 'data'
|
||||
ALuint dataSize;
|
||||
} WAVE_Struct;
|
||||
|
||||
/// WAV File-header
|
||||
struct WAVFileHdr
|
||||
{
|
||||
ALubyte id[4];
|
||||
ALsizei size;
|
||||
ALubyte type[4];
|
||||
};
|
||||
|
||||
//// WAV Fmt-header
|
||||
struct WAVFmtHdr
|
||||
{
|
||||
ALushort format;
|
||||
ALushort channels;
|
||||
ALuint samplesPerSec;
|
||||
ALuint bytesPerSec;
|
||||
ALushort blockAlign;
|
||||
ALushort bitsPerSample;
|
||||
};
|
||||
|
||||
/// WAV FmtEx-header
|
||||
struct WAVFmtExHdr
|
||||
{
|
||||
ALushort size;
|
||||
ALushort samplesPerBlock;
|
||||
};
|
||||
|
||||
/// WAV Smpl-header
|
||||
struct WAVSmplHdr
|
||||
{
|
||||
ALuint manufacturer;
|
||||
ALuint product;
|
||||
ALuint samplePeriod;
|
||||
ALuint note;
|
||||
ALuint fineTune;
|
||||
ALuint SMPTEFormat;
|
||||
ALuint SMPTEOffest;
|
||||
ALuint loops;
|
||||
ALuint samplerData;
|
||||
struct
|
||||
{
|
||||
ALuint identifier;
|
||||
ALuint type;
|
||||
ALuint start;
|
||||
ALuint end;
|
||||
ALuint fraction;
|
||||
ALuint count;
|
||||
} loop[1];
|
||||
};
|
||||
|
||||
/// WAV Chunk-header
|
||||
struct WAVChunkHdr
|
||||
{
|
||||
ALubyte id[4];
|
||||
ALuint size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
WavStreamSource::WavStreamSource(const char *filename) {
|
||||
stream = NULL;
|
||||
bIsValid = false;
|
||||
bBuffersAllocated = false;
|
||||
mBufferList[0] = 0;
|
||||
clear();
|
||||
|
||||
mFilename = filename;
|
||||
mPosition = Point3F(0.f,0.f,0.f);
|
||||
}
|
||||
|
||||
WavStreamSource::~WavStreamSource() {
|
||||
if(bReady && bIsValid)
|
||||
freeStream();
|
||||
}
|
||||
|
||||
void WavStreamSource::clear()
|
||||
{
|
||||
if(stream)
|
||||
freeStream();
|
||||
|
||||
mHandle = NULL_AUDIOHANDLE;
|
||||
mSource = NULL;
|
||||
|
||||
if(mBufferList[0] != 0)
|
||||
alDeleteBuffers(NUMBUFFERS, mBufferList);
|
||||
for(int i = 0; i < NUMBUFFERS; i++)
|
||||
mBufferList[i] = 0;
|
||||
|
||||
dMemset(&mDescription, 0, sizeof(Audio::Description));
|
||||
mEnvironment = 0;
|
||||
mPosition.set(0.f,0.f,0.f);
|
||||
mDirection.set(0.f,1.f,0.f);
|
||||
mPitch = 1.f;
|
||||
mScore = 0.f;
|
||||
mCullTime = 0;
|
||||
|
||||
bReady = false;
|
||||
bFinishedPlaying = false;
|
||||
bIsValid = false;
|
||||
bBuffersAllocated = false;
|
||||
}
|
||||
|
||||
bool WavStreamSource::initStream() {
|
||||
WAVChunkHdr chunkHdr;
|
||||
WAVFmtExHdr fmtExHdr;
|
||||
WAVFileHdr fileHdr;
|
||||
WAVSmplHdr smplHdr;
|
||||
WAVFmtHdr fmtHdr;
|
||||
|
||||
WAVE_Struct wave;
|
||||
|
||||
ALint error;
|
||||
|
||||
bFinished = false;
|
||||
|
||||
char data[BUFFERSIZE];
|
||||
|
||||
alSourceStop(mSource);
|
||||
alSourcei(mSource, AL_BUFFER, 0);
|
||||
|
||||
stream = ResourceManager->openStream(mFilename);
|
||||
if(stream != NULL) {
|
||||
stream->read(4, &fileHdr.id[0]);
|
||||
stream->read(&fileHdr.size);
|
||||
stream->read(4, &fileHdr.type[0]);
|
||||
|
||||
stream->read(4, &chunkHdr.id[0]);
|
||||
stream->read(&chunkHdr.size);
|
||||
|
||||
// WAV Format header
|
||||
stream->read(&fmtHdr.format);
|
||||
stream->read(&fmtHdr.channels);
|
||||
stream->read(&fmtHdr.samplesPerSec);
|
||||
stream->read(&fmtHdr.bytesPerSec);
|
||||
stream->read(&fmtHdr.blockAlign);
|
||||
stream->read(&fmtHdr.bitsPerSample);
|
||||
|
||||
format=(fmtHdr.channels==1?
|
||||
(fmtHdr.bitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16):
|
||||
(fmtHdr.bitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16));
|
||||
freq=fmtHdr.samplesPerSec;
|
||||
|
||||
stream->read(4, &chunkHdr.id[0]);
|
||||
stream->read(&chunkHdr.size);
|
||||
|
||||
DataSize = chunkHdr.size;
|
||||
DataLeft = DataSize;
|
||||
dataStart = stream->getPosition();
|
||||
|
||||
// Clear Error Code
|
||||
alGetError();
|
||||
|
||||
alGenBuffers(NUMBUFFERS, mBufferList);
|
||||
if ((error = alGetError()) != AL_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bBuffersAllocated = true;
|
||||
|
||||
int numBuffers = 0;
|
||||
for(int loop = 0; loop < NUMBUFFERS; loop++)
|
||||
{
|
||||
ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
|
||||
|
||||
if (DataToRead == DataLeft)
|
||||
bFinished = AL_TRUE;
|
||||
stream->read(DataToRead, data);
|
||||
DataLeft -= DataToRead;
|
||||
alBufferData(mBufferList[loop], format, data, DataToRead, freq);
|
||||
if ((error = alGetError()) != AL_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
++numBuffers;
|
||||
if(bFinished)
|
||||
break;
|
||||
}
|
||||
|
||||
// Queue the buffers on the source
|
||||
alSourceQueueBuffers(mSource, numBuffers, mBufferList);
|
||||
if ((error = alGetError()) != AL_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buffersinqueue = numBuffers;
|
||||
alSourcei(mSource, AL_LOOPING, AL_FALSE);
|
||||
bReady = true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
bIsValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WavStreamSource::updateBuffers() {
|
||||
|
||||
ALint processed;
|
||||
ALuint BufferID;
|
||||
ALint error;
|
||||
char data[BUFFERSIZE];
|
||||
|
||||
// don't do anything if buffer isn't initialized
|
||||
if(!bIsValid)
|
||||
return false;
|
||||
|
||||
if(bFinished && mDescription.mIsLooping) {
|
||||
resetStream();
|
||||
}
|
||||
|
||||
// reset AL error code
|
||||
alGetError();
|
||||
|
||||
// Get status
|
||||
alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
|
||||
|
||||
// If some buffers have been played, unqueue them and load new audio into them, then add them to the queue
|
||||
if (processed > 0)
|
||||
{
|
||||
|
||||
while (processed)
|
||||
{
|
||||
alSourceUnqueueBuffers(mSource, 1, &BufferID);
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
return false;
|
||||
|
||||
if (!bFinished)
|
||||
{
|
||||
ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
|
||||
|
||||
if (DataToRead == DataLeft) {
|
||||
bFinished = AL_TRUE;
|
||||
}
|
||||
|
||||
stream->read(DataToRead, data);
|
||||
DataLeft -= DataToRead;
|
||||
|
||||
alBufferData(BufferID, format, data, DataToRead, freq);
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
return false;
|
||||
|
||||
// Queue buffer
|
||||
alSourceQueueBuffers(mSource, 1, &BufferID);
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
return false;
|
||||
|
||||
processed--;
|
||||
|
||||
if(bFinished && mDescription.mIsLooping) {
|
||||
resetStream();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffersinqueue--;
|
||||
processed--;
|
||||
|
||||
if (buffersinqueue == 0)
|
||||
{
|
||||
bFinishedPlaying = AL_TRUE;
|
||||
return AL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
void WavStreamSource::freeStream() {
|
||||
bReady = false;
|
||||
|
||||
|
||||
if(stream != NULL)
|
||||
ResourceManager->closeStream(stream);
|
||||
stream = NULL;
|
||||
|
||||
if(bBuffersAllocated) {
|
||||
if(mBufferList[0] != 0)
|
||||
alDeleteBuffers(NUMBUFFERS, mBufferList);
|
||||
for(int i = 0; i < NUMBUFFERS; i++)
|
||||
mBufferList[i] = 0;
|
||||
|
||||
bBuffersAllocated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WavStreamSource::resetStream() {
|
||||
stream->setPosition(dataStart);
|
||||
DataLeft = DataSize;
|
||||
bFinished = AL_FALSE;
|
||||
}
|
||||
|
||||
#include "console/console.h"
|
||||
|
||||
F32 WavStreamSource::getElapsedTime()
|
||||
{
|
||||
Con::warnf( "GetElapsedTime not implemented in WaveStreams yet" );
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
F32 WavStreamSource::getTotalTime()
|
||||
{
|
||||
Con::warnf( "GetTotalTime not implemented in WaveStreams yet" );
|
||||
return -1.f;
|
||||
}
|
||||
Reference in New Issue
Block a user