added everything

This commit is contained in:
Metario
2017-04-17 06:17:10 -06:00
commit 9c6ff74f19
6121 changed files with 1625704 additions and 0 deletions

2503
engine/audio/audio.cc Executable file

File diff suppressed because it is too large Load Diff

16
engine/audio/audio.h Executable file
View File

@ -0,0 +1,16 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _AUDIO_H_
#define _AUDIO_H_
#ifndef _PLATFORMAUDIO_H_
#include "platform/platformAudio.h"
#endif
#ifndef _AUDIODATABLOCK_H_
#include "audio/audioDataBlock.h"
#endif
#endif // _H_AUDIO_

429
engine/audio/audioBuffer.cc Executable file
View File

@ -0,0 +1,429 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platformAL.h"
#include "audio/audioBuffer.h"
#include "core/stream.h"
#include "console/console.h"
#include "core/frameAllocator.h"
#ifndef TORQUE_NO_OGGVORBIS
#include "vorbis/codec.h"
#endif
//#define LOG_SOUND_LOADS
/// 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;
};
#define CHUNKSIZE 4096
//--------------------------------------
AudioBuffer::AudioBuffer(StringTableEntry filename)
{
AssertFatal(StringTable->lookup(filename), "AudioBuffer:: filename is not a string table entry");
mFilename = filename;
mLoading = false;
malBuffer = 0;
}
AudioBuffer::~AudioBuffer()
{
if( malBuffer != 0 ) {
alDeleteBuffers( 1, &malBuffer );
}
}
//--------------------------------------
Resource<AudioBuffer> AudioBuffer::find(const char *filename)
{
U32 mark = FrameAllocator::getWaterMark();
char * f2 = NULL;
Resource<AudioBuffer> buffer = ResourceManager->load(filename);
if (bool(buffer) == false)
{
// wav file doesn't exist, try ogg file instead
S32 len = dStrlen(filename);
if (len>3 && !dStricmp(filename+len-4,".wav"))
{
f2 = (char*)FrameAllocator::alloc(len+1);
dStrcpy(f2,filename);
f2[len-3] = 'o';
f2[len-2] = 'g';
f2[len-1] = 'g';
buffer = ResourceManager->load(f2);
}
}
// if resource still not there, try to create it if file exists
if (bool(buffer) == false)
{
// see if the file exists -- first try default, then try ogg
if (ResourceManager->getPathOf(filename))
{
AudioBuffer *temp = new AudioBuffer(StringTable->insert(filename));
ResourceManager->add(filename, temp);
buffer = ResourceManager->load(filename);
}
else if (f2 && ResourceManager->getPathOf(f2))
{
AudioBuffer *temp = new AudioBuffer(StringTable->insert(f2));
ResourceManager->add(f2, temp);
buffer = ResourceManager->load(f2);
}
}
FrameAllocator::setWaterMark(mark);
return buffer;
}
ResourceInstance* AudioBuffer::construct(Stream &)
{
return NULL;
}
//-----------------------------------------------------------------
ALuint AudioBuffer::getALBuffer()
{
if (!alcGetCurrentContext())
return 0;
// clear the error state
alGetError();
// Intangir> fix for newest openAL from creative (it returns true, yea right 0 is not a valid buffer)
// it MIGHT not work at all for all i know.
if (malBuffer && alIsBuffer(malBuffer))
return malBuffer;
alGenBuffers(1, &malBuffer);
if(alGetError() != AL_NO_ERROR)
return 0;
ResourceObject * obj = ResourceManager->find(mFilename);
if(obj)
{
bool readSuccess = false;
S32 len = dStrlen(mFilename);
if(len > 3 && !dStricmp(mFilename + len - 4, ".wav"))
{
#ifdef LOG_SOUND_LOADS
Con::printf("Reading WAV: %s\n", mFilename);
#endif
readSuccess = readWAV(obj);
}
#ifndef TORQUE_NO_OGGVORBIS
else if(len > 3 && !dStricmp(mFilename + len - 4, ".ogg"))
{
# ifdef LOG_SOUND_LOADS
Con::printf("Reading Ogg: %s\n", mFilename);
# endif
readSuccess = readOgg(obj);
}
#endif
if(readSuccess)
return(malBuffer);
}
alDeleteBuffers(1, &malBuffer);
malBuffer = NULL;
return 0;
}
/*! The Read a WAV file from the given ResourceObject and initialize
an alBuffer with it.
*/
bool AudioBuffer::readWAV(ResourceObject *obj)
{
WAVChunkHdr chunkHdr;
WAVFmtExHdr fmtExHdr;
WAVFileHdr fileHdr;
WAVSmplHdr smplHdr;
WAVFmtHdr fmtHdr;
ALenum format = AL_FORMAT_MONO16;
char *data = NULL;
ALsizei size = 0;
ALsizei freq = 22050;
ALboolean loop = AL_FALSE;
Stream *stream = ResourceManager->openStream(obj);
if (!stream)
return false;
stream->read(4, &fileHdr.id[0]);
stream->read(&fileHdr.size);
stream->read(4, &fileHdr.type[0]);
fileHdr.size=((fileHdr.size+1)&~1)-4;
stream->read(4, &chunkHdr.id[0]);
stream->read(&chunkHdr.size);
// unread chunk data rounded up to nearest WORD
S32 chunkRemaining = chunkHdr.size + (chunkHdr.size&1);
while ((fileHdr.size!=0) && (stream->getStatus() != Stream::EOS))
{
// WAV Format header
if (!dStrncmp((const char*)chunkHdr.id,"fmt ",4))
{
stream->read(&fmtHdr.format);
stream->read(&fmtHdr.channels);
stream->read(&fmtHdr.samplesPerSec);
stream->read(&fmtHdr.bytesPerSec);
stream->read(&fmtHdr.blockAlign);
stream->read(&fmtHdr.bitsPerSample);
if (fmtHdr.format==0x0001)
{
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;
chunkRemaining -= sizeof(WAVFmtHdr);
}
else
{
stream->read(sizeof(WAVFmtExHdr), &fmtExHdr);
chunkRemaining -= sizeof(WAVFmtExHdr);
}
}
// WAV Format header
else if (!dStrncmp((const char*)chunkHdr.id,"data",4))
{
if (fmtHdr.format==0x0001)
{
size=chunkHdr.size;
data=new char[chunkHdr.size];
if (data)
{
stream->read(chunkHdr.size, data);
#if defined(TORQUE_OS_MAC)
// need to endian-flip the 16-bit data.
if (fmtHdr.bitsPerSample==16) // !!!TBD we don't handle stereo, so may be RL flipped.
{
U16 *ds = (U16*)data;
U16 *de = (U16*)(data+size);
while (ds<de)
{
#if defined(TORQUE_BIG_ENDIAN)
*ds = convertLEndianToHost(*ds);
#else
*ds = convertBEndianToHost(*ds);
#endif
ds++;
}
}
#endif
chunkRemaining -= chunkHdr.size;
}
else
break;
}
else if (fmtHdr.format==0x0011)
{
//IMA ADPCM
}
else if (fmtHdr.format==0x0055)
{
//MP3 WAVE
}
}
// WAV Loop header
else if (!dStrncmp((const char*)chunkHdr.id,"smpl",4))
{
// this struct read is NOT endian safe but it is ok because
// we are only testing the loops field against ZERO
stream->read(sizeof(WAVSmplHdr), &smplHdr);
loop = (smplHdr.loops ? AL_TRUE : AL_FALSE);
chunkRemaining -= sizeof(WAVSmplHdr);
}
// either we have unread chunk data or we found an unknown chunk type
// loop and read up to 1K bytes at a time until we have
// read to the end of this chunk
char buffer[1024];
AssertFatal(chunkRemaining >= 0, "AudioBuffer::readWAV: remaining chunk data should never be less than zero.");
while (chunkRemaining > 0)
{
S32 readSize = getMin(1024, chunkRemaining);
stream->read(readSize, buffer);
chunkRemaining -= readSize;
}
fileHdr.size-=(((chunkHdr.size+1)&~1)+8);
// read next chunk header...
stream->read(4, &chunkHdr.id[0]);
stream->read(&chunkHdr.size);
// unread chunk data rounded up to nearest WORD
chunkRemaining = chunkHdr.size + (chunkHdr.size&1);
}
ResourceManager->closeStream(stream);
if (data)
{
alBufferData(malBuffer, format, data, size, freq);
delete [] data;
return (alGetError() == AL_NO_ERROR);
}
return false;
}
#ifndef TORQUE_NO_OGGVORBIS
/*! The Read an Ogg Vorbis file from the given ResourceObject and initialize
an alBuffer with it.
*/
bool AudioBuffer::readOgg(ResourceObject *obj)
{
OggVorbisFile vf;
vorbis_info *vi;
ALenum format = AL_FORMAT_MONO16;
char *data = NULL;
ALsizei size = 0;
ALsizei freq = 22050;
ALboolean loop = AL_FALSE;
int current_section = 0;
#if defined(TORQUE_BIG_ENDIAN)
int endian = 1;
#else
int endian = 0;
#endif
int eof = 0;
Stream *stream = ResourceManager->openStream(obj);
if (!stream)
return false;
if(vf.ov_open(stream, NULL, 0) < 0) {
return false;
}
//Read Vorbis File Info
vi = vf.ov_info(-1);
freq = vi->rate;
long samples = (long)vf.ov_pcm_total(-1);
if(vi->channels == 1) {
format = AL_FORMAT_MONO16;
size = 2 * samples;
} else {
format = AL_FORMAT_STEREO16;
size = 4 * samples;
}
data=new char[size];
if (data)
{
long ret = oggRead(&vf, data, size, endian, &current_section);
}
/* cleanup */
vf.ov_clear();
ResourceManager->closeStream(stream);
if (data)
{
alBufferData(malBuffer, format, data, size, freq);
delete [] data;
return (alGetError() == AL_NO_ERROR);
}
return false;
}
// ov_read() only returns a maximum of one page worth of data
// this helper function will repeat the read until buffer is full
long AudioBuffer::oggRead(OggVorbisFile* vf, char *buffer,int length,
int bigendianp,int *bitstream)
{
long bytesRead = 0;
long totalBytes = 0;
long offset = 0;
long bytesToRead = 0;
//while((offset + CHUNKSIZE) < length) {
while((offset) < length)
{
if((length - offset) < CHUNKSIZE)
bytesToRead = length - offset;
else
bytesToRead = CHUNKSIZE;
bytesRead = vf->ov_read(buffer, bytesToRead, bigendianp, bitstream);
if(bytesRead <= 0)
break;
offset += bytesRead;
buffer += bytesRead;
}
return offset;
}
#endif

56
engine/audio/audioBuffer.h Executable file
View File

@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _AUDIOBUFFER_H_
#define _AUDIOBUFFER_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _PLATFORMAL_H_
#include "platform/platformAL.h"
#endif
#ifndef _RESMANAGER_H_
#include "core/resManager.h"
#endif
// MLH - don't need oggbvorbis in tools
#ifndef TORQUE_NO_OGGVORBIS
#include "audio/vorbisStream.h"
#endif
//--------------------------------------------------------------------------
class AudioBuffer: public ResourceInstance
{
friend class AudioThread;
private:
StringTableEntry mFilename;
bool mLoading;
ALuint malBuffer;
bool readRIFFchunk(Stream &s, const char *seekLabel, U32 *size);
bool readWAV(ResourceObject *obj);
#ifndef TORQUE_NO_OGGVORBIS
bool readOgg(ResourceObject *obj);
long oggRead(OggVorbisFile* vf, char *buffer,int length,
int bigendianp,int *bitstream);
#endif
public:
AudioBuffer(StringTableEntry filename);
~AudioBuffer();
ALuint getALBuffer();
bool isLoading() {return(mLoading);}
static Resource<AudioBuffer> find(const char *filename);
static ResourceInstance* construct(Stream& stream);
};
#endif // _H_AUDIOBUFFER_

532
engine/audio/audioDataBlock.cc Executable file
View File

@ -0,0 +1,532 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "audio/audioDataBlock.h"
#include "console/consoleTypes.h"
#include "platform/platformAL.h"
#include "sim/netConnection.h"
//--------------------------------------------------------------------------
namespace
{
void writeRangedF32(BitStream * bstream, F32 val, F32 min, F32 max, U32 numBits)
{
val = (mClampF(val, min, max) - min) / (max - min);
bstream->writeInt(val * ((1 << numBits) - 1), numBits);
}
F32 readRangedF32(BitStream * bstream, F32 min, F32 max, U32 numBits)
{
return(min + (F32(bstream->readInt(numBits)) / F32((1 << numBits) - 1)) * (max - min));
}
void writeRangedS32(BitStream * bstream, S32 val, S32 min, S32 max)
{
bstream->writeRangedU32((val - min), 0, (max - min));
}
S32 readRangedS32(BitStream * bstream, S32 min, S32 max)
{
return(bstream->readRangedU32(0, (max - min)) + min);
}
}
//--------------------------------------------------------------------------
// Class AudioEnvironment:
//--------------------------------------------------------------------------
IMPLEMENT_CO_DATABLOCK_V1(AudioEnvironment);
AudioEnvironment::AudioEnvironment()
{
mUseRoom = true;
mRoom = EAX_ENVIRONMENT_GENERIC;
mRoomHF = 0;
mReflections = 0;
mReverb = 0;
mRoomRolloffFactor = 0.1f;
mDecayTime = 0.1f;
mDecayHFRatio = 0.1f;
mReflectionsDelay = 0.f;
mReverbDelay = 0.f;
mRoomVolume = 0;
mEffectVolume = 0.f;
mDamping = 0.f;
mEnvironmentSize = 10.f;
mEnvironmentDiffusion = 1.f;
mAirAbsorption = 0.f;
mFlags = 0;
}
static EnumTable::Enums roomEnums[] =
{
{ EAX_ENVIRONMENT_GENERIC, "GENERIC" }, // 0
{ EAX_ENVIRONMENT_PADDEDCELL, "PADDEDCELL" },
{ EAX_ENVIRONMENT_ROOM, "ROOM" },
{ EAX_ENVIRONMENT_BATHROOM, "BATHROOM" },
{ EAX_ENVIRONMENT_LIVINGROOM, "LIVINGROOM" },
{ EAX_ENVIRONMENT_STONEROOM, "STONEROOM" }, // 5
{ EAX_ENVIRONMENT_AUDITORIUM, "AUDITORIUM" },
{ EAX_ENVIRONMENT_CONCERTHALL, "CONCERTHALL" },
{ EAX_ENVIRONMENT_CAVE, "CAVE" },
{ EAX_ENVIRONMENT_ARENA, "ARENA" },
{ EAX_ENVIRONMENT_HANGAR, "HANGAR" }, // 10
{ EAX_ENVIRONMENT_CARPETEDHALLWAY, "CARPETEDHALLWAY" },
{ EAX_ENVIRONMENT_HALLWAY, "HALLWAY" },
{ EAX_ENVIRONMENT_STONECORRIDOR, "STONECORRIDOR" },
{ EAX_ENVIRONMENT_ALLEY, "ALLEY" },
{ EAX_ENVIRONMENT_FOREST, "FOREST" }, // 15
{ EAX_ENVIRONMENT_CITY, "CITY" },
{ EAX_ENVIRONMENT_MOUNTAINS, "MOUNTAINS" },
{ EAX_ENVIRONMENT_QUARRY, "QUARRY" },
{ EAX_ENVIRONMENT_PLAIN, "PLAIN" },
{ EAX_ENVIRONMENT_PARKINGLOT, "PARKINGLOT" }, // 20
{ EAX_ENVIRONMENT_SEWERPIPE, "SEWERPIPE" },
{ EAX_ENVIRONMENT_UNDERWATER, "UNDERWATER" },
{ EAX_ENVIRONMENT_DRUGGED, "DRUGGED" },
{ EAX_ENVIRONMENT_DIZZY, "DIZZY" },
{ EAX_ENVIRONMENT_PSYCHOTIC, "PSYCHOTIC" } // 25
};
static EnumTable gAudioEnvironmentRoomTypes(sizeof(roomEnums) / sizeof(roomEnums[0]), &roomEnums[0]);
//--------------------------------------------------------------------------
IMPLEMENT_CONSOLETYPE(AudioEnvironment)
IMPLEMENT_GETDATATYPE(AudioEnvironment)
IMPLEMENT_SETDATATYPE(AudioEnvironment)
void AudioEnvironment::initPersistFields()
{
Parent::initPersistFields();
addField("useRoom", TypeBool, Offset(mUseRoom, AudioEnvironment));
addField("room", TypeEnum, Offset(mRoom, AudioEnvironment), 1, &gAudioEnvironmentRoomTypes);
addField("roomHF", TypeS32, Offset(mRoomHF, AudioEnvironment));
addField("reflections", TypeS32, Offset(mReflections, AudioEnvironment));
addField("reverb", TypeS32, Offset(mReverb, AudioEnvironment));
addField("roomRolloffFactor", TypeF32, Offset(mRoomRolloffFactor, AudioEnvironment));
addField("decayTime", TypeF32, Offset(mDecayTime, AudioEnvironment));
addField("decayHFRatio", TypeF32, Offset(mDecayHFRatio, AudioEnvironment));
addField("reflectionsDelay", TypeF32, Offset(mReflectionsDelay, AudioEnvironment));
addField("reverbDelay", TypeF32, Offset(mReverbDelay, AudioEnvironment));
addField("roomVolume", TypeS32, Offset(mRoomVolume, AudioEnvironment));
addField("effectVolume", TypeF32, Offset(mEffectVolume, AudioEnvironment));
addField("damping", TypeF32, Offset(mDamping, AudioEnvironment));
addField("environmentSize", TypeF32, Offset(mEnvironmentSize, AudioEnvironment));
addField("environmentDiffusion", TypeF32, Offset(mEnvironmentDiffusion, AudioEnvironment));
addField("airAbsorption", TypeF32, Offset(mAirAbsorption, AudioEnvironment));
addField("flags", TypeS32, Offset(mFlags, AudioEnvironment));
}
void AudioEnvironment::packData(BitStream* stream)
{
Parent::packData(stream);
if(stream->writeFlag(mUseRoom))
stream->writeRangedU32(mRoom, EAX_ENVIRONMENT_GENERIC, EAX_ENVIRONMENT_COUNT);
else
{
writeRangedS32(stream, mRoomHF, -10000, 0);
writeRangedS32(stream, mReflections, -10000, 10000);
writeRangedS32(stream, mReverb, -10000, 2000);
writeRangedF32(stream, mRoomRolloffFactor, 0.1f, 10.f, 8);
writeRangedF32(stream, mDecayTime, 0.1f, 20.f, 8);
writeRangedF32(stream, mDecayHFRatio, 0.1f, 20.f, 8);
writeRangedF32(stream, mReflectionsDelay, 0.f, 0.3f, 9);
writeRangedF32(stream, mReverbDelay, 0.f, 0.1f, 7);
writeRangedS32(stream, mRoomVolume, -10000, 0);
writeRangedF32(stream, mEffectVolume, 0.f, 1.f, 8);
writeRangedF32(stream, mDamping, 0.f, 2.f, 9);
writeRangedF32(stream, mEnvironmentSize, 1.f, 100.f, 10);
writeRangedF32(stream, mEnvironmentDiffusion, 0.f, 1.f, 8);
writeRangedF32(stream, mAirAbsorption, -100.f, 0.f, 10);
stream->writeInt(mFlags, 6);
}
}
void AudioEnvironment::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
mUseRoom = stream->readFlag();
if(mUseRoom)
mRoom = stream->readRangedU32(EAX_ENVIRONMENT_GENERIC, EAX_ENVIRONMENT_COUNT);
else
{
mRoomHF = readRangedS32(stream, -10000, 0);
mReflections = readRangedS32(stream, -10000, 10000);
mReverb = readRangedS32(stream, -10000, 2000);
mRoomRolloffFactor = readRangedF32(stream, 0.1f, 10.f, 8);
mDecayTime = readRangedF32(stream, 0.1f, 20.f, 8);
mDecayHFRatio = readRangedF32(stream, 0.1f, 20.f, 8);
mReflectionsDelay = readRangedF32(stream, 0.f, 0.3f, 9);
mReverbDelay = readRangedF32(stream, 0.f, 0.1f, 7);
mRoomVolume = readRangedS32(stream, -10000, 0);
mEffectVolume = readRangedF32(stream, 0.f, 1.f, 8);
mDamping = readRangedF32(stream, 0.f, 2.f, 9);
mEnvironmentSize = readRangedF32(stream, 1.f, 100.f, 10);
mEnvironmentDiffusion = readRangedF32(stream, 0.f, 1.f, 8);
mAirAbsorption = readRangedF32(stream, -100.f, 0.f, 10);
mFlags = stream->readInt(6);
}
}
//--------------------------------------------------------------------------
// Class AudioEnvironmentProfile:
//--------------------------------------------------------------------------
IMPLEMENT_CO_DATABLOCK_V1(AudioSampleEnvironment);
AudioSampleEnvironment::AudioSampleEnvironment()
{
mDirect = 0;
mDirectHF = 0;
mRoom = 0;
mRoomHF = 0;
mObstruction = 0.f;
mObstructionLFRatio = 0.f;
mOcclusion = 0.f;
mOcclusionLFRatio = 0.f;
mOcclusionRoomRatio = 0.f;
mRoomRolloff = 0.f;
mAirAbsorption = 0.f;
mOutsideVolumeHF = 0.f;
mFlags = 0;
}
//--------------------------------------------------------------------------
IMPLEMENT_CONSOLETYPE(AudioSampleEnvironment)
IMPLEMENT_GETDATATYPE(AudioSampleEnvironment)
IMPLEMENT_SETDATATYPE(AudioSampleEnvironment)
void AudioSampleEnvironment::initPersistFields()
{
Parent::initPersistFields();
addField("direct", TypeS32, Offset(mDirect, AudioSampleEnvironment));
addField("directHF", TypeS32, Offset(mDirectHF, AudioSampleEnvironment));
addField("room", TypeS32, Offset(mRoom, AudioSampleEnvironment));
addField("obstruction", TypeF32, Offset(mObstruction, AudioSampleEnvironment));
addField("obstructionLFRatio", TypeF32, Offset(mObstructionLFRatio, AudioSampleEnvironment));
addField("occlusion", TypeF32, Offset(mOcclusion, AudioSampleEnvironment));
addField("occlusionLFRatio", TypeF32, Offset(mOcclusionLFRatio, AudioSampleEnvironment));
addField("occlusionRoomRatio", TypeF32, Offset(mOcclusionRoomRatio, AudioSampleEnvironment));
addField("roomRolloff", TypeF32, Offset(mRoomRolloff, AudioSampleEnvironment));
addField("airAbsorption", TypeF32, Offset(mAirAbsorption, AudioSampleEnvironment));
addField("outsideVolumeHF", TypeS32, Offset(mOutsideVolumeHF, AudioSampleEnvironment));
addField("flags", TypeS32, Offset(mFlags, AudioSampleEnvironment));
}
void AudioSampleEnvironment::packData(BitStream* stream)
{
Parent::packData(stream);
writeRangedS32(stream, mDirect, -10000, 1000);
writeRangedS32(stream, mDirectHF, -10000, 0);
writeRangedS32(stream, mRoom, -10000, 1000);
writeRangedS32(stream, mRoomHF, -10000, 0);
writeRangedF32(stream, mObstruction, 0.f, 1.f, 9);
writeRangedF32(stream, mObstructionLFRatio, 0.f, 1.f, 8);
writeRangedF32(stream, mOcclusion, 0.f, 1.f, 9);
writeRangedF32(stream, mOcclusionLFRatio, 0.f, 1.f, 8);
writeRangedF32(stream, mOcclusionRoomRatio, 0.f, 10.f, 9);
writeRangedF32(stream, mRoomRolloff, 0.f, 10.f, 9);
writeRangedF32(stream, mAirAbsorption, 0.f, 10.f, 9);
writeRangedS32(stream, mOutsideVolumeHF, -10000, 0);
stream->writeInt(mFlags, 3);
}
void AudioSampleEnvironment::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
mDirect = readRangedS32(stream, -10000, 1000);
mDirectHF = readRangedS32(stream, -10000, 0);
mRoom = readRangedS32(stream, -10000, 1000);
mRoomHF = readRangedS32(stream, -10000, 0);
mObstruction = readRangedF32(stream, 0.f, 1.f, 9);
mObstructionLFRatio = readRangedF32(stream, 0.f, 1.f, 8);
mOcclusion = readRangedF32(stream, 0.f, 1.f, 9);
mOcclusionLFRatio = readRangedF32(stream, 0.f, 1.f, 8);
mOcclusionRoomRatio = readRangedF32(stream, 0.f, 10.f, 9);
mRoomRolloff = readRangedF32(stream, 0.f, 10.f, 9);
mAirAbsorption = readRangedF32(stream, 0.f, 10.f, 9);
mOutsideVolumeHF = readRangedS32(stream, -10000, 0);
mFlags = stream->readInt(3);
}
//--------------------------------------------------------------------------
// Class AudioDescription:
//--------------------------------------------------------------------------
IMPLEMENT_CO_DATABLOCK_V1(AudioDescription);
AudioDescription::AudioDescription()
{
mDescription.mVolume = 1.0f;
mDescription.mIsLooping = false;
mDescription.mIsStreaming = false;
mDescription.mIs3D = false;
mDescription.mReferenceDistance = 1.0f;
mDescription.mMaxDistance = 100.0f;
mDescription.mConeInsideAngle = 360;
mDescription.mConeOutsideAngle = 360;
mDescription.mConeOutsideVolume = 1.0f;
mDescription.mConeVector.set(0, 0, 1);
mDescription.mEnvironmentLevel = 0.f;
mDescription.mLoopCount = -1;
mDescription.mMinLoopGap = 0;
mDescription.mMaxLoopGap = 0;
mDescription.mType = 0;
}
//--------------------------------------------------------------------------
IMPLEMENT_CONSOLETYPE(AudioDescription)
IMPLEMENT_GETDATATYPE(AudioDescription)
IMPLEMENT_SETDATATYPE(AudioDescription)
void AudioDescription::initPersistFields()
{
Parent::initPersistFields();
addField("volume", TypeF32, Offset(mDescription.mVolume, AudioDescription));
addField("isLooping", TypeBool, Offset(mDescription.mIsLooping, AudioDescription));
addField("isStreaming", TypeBool, Offset(mDescription.mIsStreaming, AudioDescription));
addField("is3D", TypeBool, Offset(mDescription.mIs3D, AudioDescription));
addField("referenceDistance", TypeF32, Offset(mDescription.mReferenceDistance, AudioDescription));
addField("maxDistance", TypeF32, Offset(mDescription.mMaxDistance, AudioDescription));
addField("coneInsideAngle", TypeS32, Offset(mDescription.mConeInsideAngle, AudioDescription));
addField("coneOutsideAngle", TypeS32, Offset(mDescription.mConeOutsideAngle, AudioDescription));
addField("coneOutsideVolume", TypeF32, Offset(mDescription.mConeOutsideVolume, AudioDescription));
addField("coneVector", TypePoint3F, Offset(mDescription.mConeVector, AudioDescription));
addField("environmentLevel", TypeF32, Offset(mDescription.mEnvironmentLevel, AudioDescription));
addField("loopCount", TypeS32, Offset(mDescription.mLoopCount, AudioDescription));
addField("minLoopGap", TypeS32, Offset(mDescription.mMinLoopGap, AudioDescription));
addField("maxLoopGap", TypeS32, Offset(mDescription.mMaxLoopGap, AudioDescription));
addField("type", TypeS32, Offset(mDescription.mType, AudioDescription));
}
//--------------------------------------------------------------------------
bool AudioDescription::onAdd()
{
if (!Parent::onAdd())
return false;
// validate the data
mDescription.mVolume = mClampF(mDescription.mVolume, 0.0f, 1.0f);
mDescription.mLoopCount = mClamp(mDescription.mLoopCount, -1, mDescription.mLoopCount);
mDescription.mMaxLoopGap = mClamp(mDescription.mMaxLoopGap, mDescription.mMinLoopGap, mDescription.mMaxLoopGap);
mDescription.mMinLoopGap = mClamp(mDescription.mMinLoopGap, 0, mDescription.mMaxLoopGap);
if (mDescription.mIs3D)
{
// validate the data
mDescription.mReferenceDistance = mClampF(mDescription.mReferenceDistance, 0.f, mDescription.mReferenceDistance);
mDescription.mMaxDistance = (mDescription.mMaxDistance > mDescription.mReferenceDistance) ? mDescription.mMaxDistance : (mDescription.mReferenceDistance+0.01f);
mDescription.mConeInsideAngle = mClamp(mDescription.mConeInsideAngle, 0, 360);
mDescription.mConeOutsideAngle = mClamp(mDescription.mConeOutsideAngle, mDescription.mConeInsideAngle, 360);
mDescription.mConeOutsideVolume = mClampF(mDescription.mConeOutsideVolume, 0.0f, 1.0f);
mDescription.mConeVector.normalize();
mDescription.mEnvironmentLevel = mClampF(mDescription.mEnvironmentLevel, 0.f, 1.f);
}
if(mDescription.mType >= Audio::NumAudioTypes)
mDescription.mType = 0;
return true;
}
//--------------------------------------------------------------------------
void AudioDescription::packData(BitStream* stream)
{
Parent::packData(stream);
stream->writeFloat(mDescription.mVolume, 6);
if(stream->writeFlag(mDescription.mIsLooping))
{
stream->write(mDescription.mLoopCount);
stream->write(mDescription.mMinLoopGap);
stream->write(mDescription.mMaxLoopGap);
}
stream->writeFlag(mDescription.mIsStreaming);
stream->writeFlag(mDescription.mIs3D);
if (mDescription.mIs3D)
{
stream->write(mDescription.mReferenceDistance);
stream->write(mDescription.mMaxDistance);
stream->writeInt(mDescription.mConeInsideAngle, 9);
stream->writeInt(mDescription.mConeOutsideAngle, 9);
stream->writeInt(mDescription.mConeOutsideVolume, 6);
stream->writeNormalVector(mDescription.mConeVector, 8);
stream->write(mDescription.mEnvironmentLevel);
}
stream->writeInt(mDescription.mType, 3);
}
//--------------------------------------------------------------------------
void AudioDescription::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
mDescription.mVolume = stream->readFloat(6);
mDescription.mIsLooping = stream->readFlag();
if(mDescription.mIsLooping)
{
stream->read(&mDescription.mLoopCount);
stream->read(&mDescription.mMinLoopGap);
stream->read(&mDescription.mMaxLoopGap);
}
mDescription.mIsStreaming = stream->readFlag();
mDescription.mIs3D = stream->readFlag();
if ( mDescription.mIs3D )
{
stream->read(&mDescription.mReferenceDistance);
stream->read(&mDescription.mMaxDistance);
mDescription.mConeInsideAngle = stream->readInt(9);
mDescription.mConeOutsideAngle = stream->readInt(9);
mDescription.mConeOutsideVolume = stream->readFloat(6);
stream->readNormalVector(&mDescription.mConeVector, 8);
stream->read(&mDescription.mEnvironmentLevel);
}
mDescription.mType = stream->readInt(3);
}
//--------------------------------------------------------------------------
// Class AudioProfile:
//--------------------------------------------------------------------------
IMPLEMENT_CO_DATABLOCK_V1(AudioProfile);
AudioProfile::AudioProfile()
{
mFilename = NULL;
mDescriptionObjectID = 0;
mDescriptionObject = NULL;
mSampleEnvironment = 0;
mPreload = false;
}
//--------------------------------------------------------------------------
IMPLEMENT_CONSOLETYPE(AudioProfile)
IMPLEMENT_GETDATATYPE(AudioProfile)
IMPLEMENT_SETDATATYPE(AudioProfile)
void AudioProfile::initPersistFields()
{
Parent::initPersistFields();
addField("filename", TypeFilename, Offset(mFilename, AudioProfile));
addField("description", TypeAudioDescriptionPtr, Offset(mDescriptionObject, AudioProfile));
addField("environment", TypeAudioSampleEnvironmentPtr, Offset(mSampleEnvironment, AudioProfile));
addField("preload", TypeBool, Offset(mPreload, AudioProfile));
}
bool AudioProfile::preload(bool server, char errorBuffer[256])
{
if(!Parent::preload(server, errorBuffer))
return false;
if(!server && NetConnection::filesWereDownloaded() && !bool(AudioBuffer::find(mFilename)))
return false;
return true;
}
//--------------------------------------------------------------------------
bool AudioProfile::onAdd()
{
if (!Parent::onAdd())
return false;
if (!mDescriptionObject && mDescriptionObjectID)
Sim::findObject(mDescriptionObjectID , mDescriptionObject);
// if this is client side, make sure that description is as well
if(mDescriptionObject)
{ // client side dataBlock id's are not in the dataBlock id range
if (getId() >= DataBlockObjectIdFirst && getId() <= DataBlockObjectIdLast)
{
SimObjectId pid = mDescriptionObject->getId();
if (pid < DataBlockObjectIdFirst || pid > DataBlockObjectIdLast)
{
Con::errorf(ConsoleLogEntry::General,"AudioProfile: data dataBlock not networkable (use datablock to create).");
return false;
}
}
}
if(mPreload && mFilename != NULL && alcGetCurrentContext())
{
mBuffer = AudioBuffer::find(mFilename);
if(bool(mBuffer))
{
ALuint bufferId = mBuffer->getALBuffer();
}
}
return(true);
}
//--------------------------------------------------------------------------
void AudioProfile::packData(BitStream* stream)
{
Parent::packData(stream);
// audio description:
if (stream->writeFlag(mDescriptionObject))
stream->writeRangedU32(mDescriptionObject->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
// environmental info:
if (stream->writeFlag(mSampleEnvironment))
stream->writeRangedU32(mSampleEnvironment->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
//
char buffer[256];
if(!mFilename)
buffer[0] = 0;
else
dStrcpy(buffer, mFilename);
// S32 len = dStrlen(buffer);
// if(len > 3 && !dStricmp(buffer + len - 4, ".wav"))
// buffer[len-4] = 0;
stream->writeString(buffer);
}
//--------------------------------------------------------------------------
void AudioProfile::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
// audio datablock:
if (stream->readFlag()) {
SimObjectId id = stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
mDescriptionObjectID = id;
Sim::findObject(id, mDescriptionObject);
}
// sample environment:
if (stream->readFlag()) {
SimObjectId id = stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
Sim::findObject(id, mSampleEnvironment);
}
char buffer[256];
stream->readString(buffer);
// dStrcat(buffer, ".wav");
mFilename = StringTable->insert(buffer);
// Doh! Something missing from the unpackData...don't want to break
// network protocol, so set it to true always here. This is good for
// ThinkTanks only. In the future, simply send the preload bit.
mPreload = true;
}

140
engine/audio/audioDataBlock.h Executable file
View File

@ -0,0 +1,140 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _AUDIODATABLOCK_H_
#define _AUDIODATABLOCK_H_
#ifndef _PLATFORMAUDIO_H_
#include "platform/platformAudio.h"
#endif
#ifndef _AUDIOBUFFER_H_
#include "audio/audioBuffer.h"
#endif
#ifndef _BITSTREAM_H_
#include "core/bitStream.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
//--------------------------------------------------------------------------
class AudioEnvironment : public SimDataBlock
{
typedef SimDataBlock Parent;
public:
bool mUseRoom;
S32 mRoom;
S32 mRoomHF;
S32 mReflections;
S32 mReverb;
F32 mRoomRolloffFactor;
F32 mDecayTime;
F32 mDecayHFRatio;
F32 mReflectionsDelay;
F32 mReverbDelay;
S32 mRoomVolume;
F32 mEffectVolume;
F32 mDamping;
F32 mEnvironmentSize;
F32 mEnvironmentDiffusion;
F32 mAirAbsorption;
S32 mFlags;
AudioEnvironment();
static void initPersistFields();
void packData(BitStream* stream);
void unpackData(BitStream* stream);
DECLARE_CONOBJECT(AudioEnvironment);
};
DECLARE_CONSOLETYPE(AudioEnvironment)
//--------------------------------------------------------------------------
class AudioSampleEnvironment : public SimDataBlock
{
typedef SimDataBlock Parent;
public:
S32 mDirect;
S32 mDirectHF;
S32 mRoom;
S32 mRoomHF;
F32 mObstruction;
F32 mObstructionLFRatio;
F32 mOcclusion;
F32 mOcclusionLFRatio;
F32 mOcclusionRoomRatio;
F32 mRoomRolloff;
F32 mAirAbsorption;
S32 mOutsideVolumeHF;
S32 mFlags;
AudioSampleEnvironment();
static void initPersistFields();
void packData(BitStream* stream);
void unpackData(BitStream* stream);
DECLARE_CONOBJECT(AudioSampleEnvironment);
};
DECLARE_CONSOLETYPE(AudioSampleEnvironment)
//--------------------------------------------------------------------------
class AudioDescription: public SimDataBlock
{
private:
typedef SimDataBlock Parent;
public:
// field info
Audio::Description mDescription;
AudioDescription();
DECLARE_CONOBJECT(AudioDescription);
static void initPersistFields();
virtual bool onAdd();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
const Audio::Description* getDescription() const { return &mDescription; }
};
DECLARE_CONSOLETYPE(AudioDescription)
//----------------------------------------------------------------------------
class AudioProfile: public SimDataBlock
{
private:
typedef SimDataBlock Parent;
Resource<AudioBuffer> mBuffer;
public:
// field info
U32 mDescriptionObjectID;
AudioDescription *mDescriptionObject;
AudioSampleEnvironment *mSampleEnvironment;
StringTableEntry mFilename;
bool mPreload;
AudioProfile();
DECLARE_CONOBJECT(AudioProfile);
static void initPersistFields();
virtual bool onAdd();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
virtual bool preload(bool server, char errorBuffer[256]);
const Audio::Description* getDescription() const { return mDescriptionObject ? mDescriptionObject->getDescription() : NULL; }
bool isPreload() { return mPreload; }
};
DECLARE_CONSOLETYPE(AudioProfile)
#endif // _H_AUDIODATABLOCK_

554
engine/audio/audioFunctions.cc Executable file
View File

@ -0,0 +1,554 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "platform/platformAudio.h"
#include "console/simBase.h"
#include "audio/audioDataBlock.h"
extern ALuint alxGetWaveLen(ALuint buffer);
extern F32 mAudioTypeVolume[Audio::NumAudioTypes];
//--------------------------------------------------------------------------
// Expose all al get/set methods...
//--------------------------------------------------------------------------
enum AL_GetSetBits{
Source = BIT(0),
Listener = BIT(1),
Context = BIT(2),
Environment = BIT(3),
Get = BIT(4),
Set = BIT(5),
Int = BIT(6),
Float = BIT(7),
Float3 = BIT(8),
Float6 = BIT(9)
};
static ALenum getEnum(const char * name, U32 flags)
{
AssertFatal(name, "Audio getEnum: bad param");
static struct {
char * mName;
ALenum mAlenum;
U32 mFlags;
} table[] = {
//-----------------------------------------------------------------------------------------------------------------
// "name" ENUM Flags
//-----------------------------------------------------------------------------------------------------------------
{ "AL_GAIN", AL_GAIN, (Source|Listener|Get|Set|Float) },
{ "AL_GAIN_LINEAR", AL_GAIN_LINEAR, (Source|Listener|Get|Set|Float) },
{ "AL_PITCH", AL_PITCH, (Source|Get|Set|Float) },
{ "AL_REFERENCE_DISTANCE", AL_REFERENCE_DISTANCE, (Source|Get|Set|Float) },
{ "AL_MAX_DISTANCE", AL_MAX_DISTANCE, (Source|Get|Set|Float) },
{ "AL_CONE_OUTER_GAIN", AL_CONE_OUTER_GAIN, (Source|Get|Set|Float) },
{ "AL_POSITION", AL_POSITION, (Source|Listener|Get|Set|Float3) },
{ "AL_DIRECTION", AL_DIRECTION, (Source|Get|Set|Float3) },
{ "AL_VELOCITY", AL_VELOCITY, (Source|Listener|Get|Set|Float3) },
{ "AL_ORIENTATION", AL_ORIENTATION, (Listener|Set|Float6) },
{ "AL_CONE_INNER_ANGLE", AL_CONE_INNER_ANGLE, (Source|Get|Set|Int) },
{ "AL_CONE_OUTER_ANGLE", AL_CONE_OUTER_ANGLE, (Source|Get|Set|Int) },
{ "AL_LOOPING", AL_LOOPING, (Source|Get|Set|Int) },
//{ "AL_STREAMING", AL_STREAMING, (Source|Get|Set|Int) },
//{ "AL_BUFFER", AL_BUFFER, (Source|Get|Set|Int) },
{ "AL_VENDOR", AL_VENDOR, (Context|Get) },
{ "AL_VERSION", AL_VERSION, (Context|Get) },
{ "AL_RENDERER", AL_RENDERER, (Context|Get) },
{ "AL_EXTENSIONS", AL_EXTENSIONS, (Context|Get) },
/*
// environment
{ "AL_ENV_ROOM_IASIG", AL_ENV_ROOM_IASIG, (Environment|Get|Set|Int) },
{ "AL_ENV_ROOM_HIGH_FREQUENCY_IASIG", AL_ENV_ROOM_HIGH_FREQUENCY_IASIG, (Environment|Get|Set|Int) },
{ "AL_ENV_REFLECTIONS_IASIG", AL_ENV_REFLECTIONS_IASIG, (Environment|Get|Set|Int) },
{ "AL_ENV_REVERB_IASIG", AL_ENV_REVERB_IASIG, (Environment|Get|Set|Int) },
{ "AL_ENV_ROOM_ROLLOFF_FACTOR_IASIG", AL_ENV_ROOM_ROLLOFF_FACTOR_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_DECAY_TIME_IASIG", AL_ENV_DECAY_TIME_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_DECAY_HIGH_FREQUENCY_RATIO_IASIG", AL_ENV_DECAY_HIGH_FREQUENCY_RATIO_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_REFLECTIONS_DELAY_IASIG", AL_ENV_REFLECTIONS_DELAY_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_REVERB_DELAY_IASIG", AL_ENV_REVERB_DELAY_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_DIFFUSION_IASIG", AL_ENV_DIFFUSION_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_DENSITY_IASIG", AL_ENV_DENSITY_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_HIGH_FREQUENCY_REFERENCE_IASIG", AL_ENV_HIGH_FREQUENCY_REFERENCE_IASIG, (Environment|Get|Set|Float) },
{ "AL_ENV_ROOM_VOLUME_EXT", AL_ENV_ROOM_VOLUME_EXT, (Environment|Get|Set|Int) },
{ "AL_ENV_FLAGS_EXT", AL_ENV_FLAGS_EXT, (Environment|Get|Set|Int) },
{ "AL_ENV_EFFECT_VOLUME_EXT", AL_ENV_EFFECT_VOLUME_EXT, (Environment|Get|Set|Float) },
{ "AL_ENV_DAMPING_EXT", AL_ENV_DAMPING_EXT, (Environment|Get|Set|Float) },
{ "AL_ENV_ENVIRONMENT_SIZE_EXT", AL_ENV_ENVIRONMENT_SIZE_EXT, (Environment|Get|Set|Float) },
// sample environment
{ "AL_ENV_SAMPLE_DIRECT_EXT", AL_ENV_SAMPLE_DIRECT_EXT, (Source|Get|Set|Int) },
{ "AL_ENV_SAMPLE_DIRECT_HF_EXT", AL_ENV_SAMPLE_DIRECT_HF_EXT, (Source|Get|Set|Int) },
{ "AL_ENV_SAMPLE_ROOM_EXT", AL_ENV_SAMPLE_ROOM_EXT, (Source|Get|Set|Int) },
{ "AL_ENV_SAMPLE_ROOM_HF_EXT", AL_ENV_SAMPLE_ROOM_HF_EXT, (Source|Get|Set|Int) },
{ "AL_ENV_SAMPLE_OUTSIDE_VOLUME_HF_EXT", AL_ENV_SAMPLE_OUTSIDE_VOLUME_HF_EXT, (Source|Get|Set|Int) },
{ "AL_ENV_SAMPLE_FLAGS_EXT", AL_ENV_SAMPLE_FLAGS_EXT, (Source|Get|Set|Int) },
{ "AL_ENV_SAMPLE_REVERB_MIX_EXT", AL_ENV_SAMPLE_REVERB_MIX_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_OBSTRUCTION_EXT", AL_ENV_SAMPLE_OBSTRUCTION_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_OBSTRUCTION_LF_RATIO_EXT", AL_ENV_SAMPLE_OBSTRUCTION_LF_RATIO_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_OCCLUSION_EXT", AL_ENV_SAMPLE_OCCLUSION_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_OCCLUSION_LF_RATIO_EXT", AL_ENV_SAMPLE_OCCLUSION_LF_RATIO_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_OCCLUSION_ROOM_RATIO_EXT", AL_ENV_SAMPLE_OCCLUSION_ROOM_RATIO_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_ROOM_ROLLOFF_EXT", AL_ENV_SAMPLE_ROOM_ROLLOFF_EXT, (Source|Get|Set|Float) },
{ "AL_ENV_SAMPLE_AIR_ABSORPTION_EXT", AL_ENV_SAMPLE_AIR_ABSORPTION_EXT, (Source|Get|Set|Float) },
*/
};
for(U32 i = 0; i < (sizeof(table) / sizeof(table[0])); i++)
{
if((table[i].mFlags & flags) != flags)
continue;
if(dStricmp(table[i].mName, name) == 0)
return(table[i].mAlenum);
}
return(AL_INVALID);
}
//-----------------------------------------------
ConsoleFunctionGroupBegin(Audio, "Functions dealing with the OpenAL audio layer.\n\n"
"@see www.OpenAL.org for what these functions do. Variances from posted"
" behaviour is described below.");
ConsoleFunction(OpenALInitDriver, bool, 1, 1, "Initializes the OpenAL driver.\n\n"
"@note You must call this before any sounds will work!")
{
if (Audio::OpenALInit())
{
static bool registered = false;
if (!registered) {
ResourceManager->registerExtension(".wav", AudioBuffer::construct);
ResourceManager->registerExtension(".ogg", AudioBuffer::construct);
}
registered = true;
return true;
}
return false;
}
//-----------------------------------------------
ConsoleFunction(OpenALShutdownDriver, void, 1, 1, "OpenALShutdownDriver()")
{
Audio::OpenALShutdown();
}
//-----------------------------------------------
ConsoleFunction(OpenALRegisterExtensions, void, 1, 1, "OpenALRegisterExtensions()")
{
}
//-----------------------------------------------
ConsoleFunction(alGetString, const char *, 2, 2, "(string item)\n\n"
"This wraps alGetString().")
{
argc;
ALenum e = getEnum(argv[1], (Context|Get));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "alGetString: invalid enum name '%s'", argv[1]);
return "";
}
return (const char*)alGetString(e);
}
//--------------------------------------------------------------------------
// Soundfile
//--------------------------------------------------------------------------
ConsoleFunction(alxGetWaveLen, S32, 2, 2, "(string filename)\n\n"
"@param filename File to determine length of.\n"
"@returns Length in milliseconds.")
{
Resource<AudioBuffer> buffer = AudioBuffer::find(argv[1]);
if (bool(buffer)) {
ALuint alBuffer = buffer->getALBuffer();
return alxGetWaveLen(alBuffer);
}
else {
return 0;
}
}
//--------------------------------------------------------------------------
// Source
//--------------------------------------------------------------------------
ConsoleFunction(alxCreateSource, S32, 2, 6,
"(profile) or "
"(profile, x,y,z) or "
"(description, filename) or "
"(description, filename, x,y,z)")
{
AudioDescription *description = NULL;
AudioProfile *profile = dynamic_cast<AudioProfile*>( Sim::findObject( argv[1] ) );
if (profile == NULL)
{
description = dynamic_cast<AudioDescription*>( Sim::findObject( argv[1] ) );
if (description == NULL)
{
Con::printf("Unable to locate audio profile/description '%s'", argv[1]);
return NULL_AUDIOHANDLE;
}
}
if (profile)
{
if (argc == 2)
return alxCreateSource(profile);
MatrixF transform;
transform.set(EulerF(0,0,0), Point3F( dAtof(argv[2]),dAtof(argv[3]),dAtof(argv[4]) ));
return alxCreateSource(profile, &transform);
}
if (description)
{
if (argc == 3)
return alxCreateSource(description, argv[2]);
MatrixF transform;
transform.set(EulerF(0,0,0), Point3F( dAtof(argv[3]),dAtof(argv[4]),dAtof(argv[5]) ));
return alxCreateSource(description, argv[2], &transform);
}
return NULL_AUDIOHANDLE;
}
//-----------------------------------------------
ConsoleFunction(alxSourcef, void, 4, 4, "(handle, ALenum, value)")
{
ALenum e = getEnum(argv[2], (Source|Set|Float));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxSourcef: invalid enum name '%s'", argv[2]);
return;
}
alxSourcef(dAtoi(argv[1]), e, dAtof(argv[3]));
}
//-----------------------------------------------
ConsoleFunction(alxSource3f, void, 3, 6, "(handle, ALenum, x, y, z)\n\n"
"@note You can replace the last three parameters with a string, "
"\"x y z\"")
{
ALenum e = getEnum(argv[2], (Source|Set|Float3));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxSource3f: invalid enum name '%s'", argv[2]);
return;
}
if((argc != 4 && argc != 6))
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxSource3f: wrong number of args");
return;
}
Point3F pos;
if(argc == 4)
dSscanf(argv[3], "%g %g %g", &pos.x, &pos.y, &pos.z);
else
{
pos.x = dAtof(argv[3]);
pos.y = dAtof(argv[4]);
pos.z = dAtof(argv[5]);
}
alxSource3f(dAtoi(argv[1]), e, pos.x, pos.y, pos.z);
}
//-----------------------------------------------
ConsoleFunction(alxSourcei, void, 4, 4, "(handle, ALenum, value)")
{
ALenum e = getEnum(argv[2], (Source|Set|Int));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxSourcei: invalid enum name '%s'", argv[2]);
return;
}
alxSourcei(dAtoi(argv[1]), e, dAtoi(argv[3]));
}
//-----------------------------------------------
ConsoleFunction(alxGetSourcef, F32, 3, 3, "(handle, ALenum)")
{
ALenum e = getEnum(argv[2], (Source|Get|Float));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxGetSourcef: invalid enum name '%s'", argv[2]);
return(0.f);
}
F32 value;
alxGetSourcef(dAtoi(argv[1]), e, &value);
return(value);
}
//-----------------------------------------------
ConsoleFunction(alxGetSource3f, const char *, 3, 3, "(handle, ALenum)" )
{
ALenum e = getEnum(argv[2], (Source|Get|Float));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxGetSource3f: invalid enum name '%s'", argv[2]);
return("0 0 0");
}
F32 value1, value2, value3;
alxGetSource3f(dAtoi(argv[1]), e, &value1, &value2, &value3);
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%7.3f %7.3 %7.3", value1, value2, value3);
return(ret);
}
//-----------------------------------------------
ConsoleFunction(alxGetSourcei, S32, 3, 3, "(handle, ALenum)")
{
ALenum e = getEnum(argv[2], (Source|Get|Int));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "cAudio_alxGetSourcei: invalid enum name '%s'", argv[2]);
return(0);
}
S32 value;
alxGetSourcei(dAtoi(argv[1]), e, &value);
return(value);
}
//-----------------------------------------------
ConsoleFunction(alxPlay, S32, 2, 5, "alxPlay(handle) or "
"alxPlay(profile) or "
"alxPlay(profile, x,y,z)")
{
if (argc == 2)
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if (handle != 0)
return alxPlay(handle);
}
AudioProfile *profile = dynamic_cast<AudioProfile*>( Sim::findObject( argv[1] ) );
if (profile == NULL)
{
Con::printf("Unable to locate audio profile '%s'", argv[1]);
return NULL_AUDIOHANDLE;
}
Point3F pos(0.f, 0.f, 0.f);
if(argc == 3)
dSscanf(argv[2], "%g %g %g", &pos.x, &pos.y, &pos.z);
else if(argc == 5)
pos.set(dAtof(argv[2]), dAtof(argv[3]), dAtof(argv[4]));
MatrixF transform;
transform.set(EulerF(0,0,0), pos);
return alxPlay(profile, &transform, NULL);
}
//-----------------------------------------------
ConsoleFunction(alxStop, void, 2, 2, "(int handle)")
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return;
alxStop(handle);
}
//-----------------------------------------------
ConsoleFunction(alxStopAll, void, 1, 1, "()")
{
alxStopAll();
}
//-----------------------------------------------
ConsoleFunction(alxIsPlaying, bool, 2, 5, "alxIsPlaying(handle)")
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return false;
return alxIsPlaying(handle);
}
//--------------------------------------------------------------------------
// Listener
//--------------------------------------------------------------------------
ConsoleFunction(alxListenerf, void, 3, 3, "alxListener(ALenum, value)")
{
ALenum e = getEnum(argv[1], (Listener|Set|Float));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "alxListenerf: invalid enum name '%s'", argv[1]);
return;
}
alxListenerf(e, dAtof(argv[2]));
}
//-----------------------------------------------
ConsoleFunction(alListener3f, void, 3, 5, "alListener3f(ALenum, \"x y z\") or "
"alListener3f(ALenum, x, y, z)")
{
ALenum e = getEnum(argv[1], (Listener|Set|Float3));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "alListener3f: invalid enum name '%s'", argv[1]);
return;
}
if(argc != 3 && argc != 5)
{
Con::errorf(ConsoleLogEntry::General, "alListener3f: wrong number of arguments");
return;
}
Point3F pos;
if(argc == 3)
dSscanf(argv[2], "%g %g %g", &pos.x, &pos.y, &pos.z);
else
{
pos.x = dAtof(argv[2]);
pos.y = dAtof(argv[3]);
pos.z = dAtof(argv[4]);
}
alListener3f(e, pos.x, pos.y, pos.z);
}
//-----------------------------------------------
ConsoleFunction(alxGetListenerf, F32, 2, 2, "alxGetListenerf(Alenum)")
{
ALenum e = getEnum(argv[1], (Source|Get|Float));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "alxGetListenerf: invalid enum name '%s'", argv[1]);
return(0.f);
}
F32 value;
alxGetListenerf(e, &value);
return(value);
}
//-----------------------------------------------
ConsoleFunction(alGetListener3f, const char *, 2, 2, "alGetListener3f(Alenum)")
{
ALenum e = getEnum(argv[2], (Source|Get|Float));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "alGetListener3f: invalid enum name '%s'", argv[1]);
return("0 0 0");
}
F32 value1, value2, value3;
alGetListener3f(e, &value1, &value2, &value3);
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%7.3f %7.3 %7.3", value1, value2, value3);
return(ret);
}
//-----------------------------------------------
ConsoleFunction(alGetListeneri, S32, 2, 2, "alGetListeneri(Alenum)")
{
ALenum e = getEnum(argv[1], (Source|Get|Int));
if(e == AL_INVALID)
{
Con::errorf(ConsoleLogEntry::General, "alGetListeneri: invalid enum name '%s'", argv[1]);
return(0);
}
S32 value;
alGetListeneri(e, &value);
return(value);
}
//--------------------------------------------------------------------------
// Channel Volumes
//--------------------------------------------------------------------------
ConsoleFunction(alxGetChannelVolume, F32, 2, 2, "(int channel_id)\n\n"
"@param channel_id ID of channel to fetch volume from.\n"
"@return Volume of channel.")
{
U32 type = dAtoi(argv[1]);
if(type >= Audio::NumAudioTypes)
{
Con::errorf(ConsoleLogEntry::General, "alxGetChannelVolume: invalid channel '%d'", dAtoi(argv[1]));
return(0.f);
}
return(mAudioTypeVolume[type]);
}
//-----------------------------------------------
ConsoleFunction(alxSetChannelVolume, bool, 3, 3, "(int channel_id, float volume)\n\n"
"@param channel_id ID of channel to set volume on.\n"
"@param volume New volume of channel, from 0.0f-1.0f"
)
{
U32 type = dAtoi(argv[1]);
F32 volume = mClampF(dAtof(argv[2]), 0.f, 1.f);
if(type >= Audio::NumAudioTypes)
{
Con::errorf(ConsoleLogEntry::General, "alxSetChannelVolume: channel '%d' out of range [0, %d]", dAtoi(argv[1]), Audio::NumAudioTypes);
return false;
}
mAudioTypeVolume[type] = volume;
alxUpdateTypeGain(type);
return true;
}
//-----------------------------------------------
ConsoleFunction(alxGetStreamPosition, F32, 2, 2, "alxGetStreamPosition(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return -1;
return alxGetStreamPosition( handle );
}
//-----------------------------------------------
ConsoleFunction(alxGetStreamDuration, F32, 2, 2, "alxGetStreamDuration(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return -1;
return alxGetStreamDuration( handle );
}
ConsoleFunctionGroupEnd(Audio);

View File

@ -0,0 +1,64 @@
//--------------------------------------------
// audioStreamSource.h
// header for streaming audio source
//
// Kurtis Seebaldt
//--------------------------------------------
#ifndef _AUDIOSTREAMSOURCE_H_
#define _AUDIOSTREAMSOURCE_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _PLATFORMAUDIO_H_
#include "platform/platformAudio.h"
#endif
#ifndef _PLATFORMAL_H_
#include "platform/platformAL.h"
#endif
#ifndef _AUDIOBUFFER_H_
#include "audio/audioBuffer.h"
#endif
#ifndef _RESMANAGER_H_
#include "core/resManager.h"
#endif
#define NUMBUFFERS 16
class AudioStreamSource
{
public:
//need this because subclasses are deleted through base pointer
virtual ~AudioStreamSource() {}
virtual bool initStream() = 0;
virtual bool updateBuffers() = 0;
virtual void freeStream() = 0;
virtual F32 getElapsedTime() = 0;
virtual F32 getTotalTime() = 0;
//void clear();
AUDIOHANDLE mHandle;
ALuint mSource;
Audio::Description mDescription;
AudioSampleEnvironment *mEnvironment;
Point3F mPosition;
Point3F mDirection;
F32 mPitch;
F32 mScore;
U32 mCullTime;
bool bFinishedPlaying;
bool bIsValid;
#ifdef TORQUE_OS_LINUX
void checkPosition();
#endif
protected:
const char* mFilename;
};
#endif // _AUDIOSTREAMSOURCE_H_

View File

@ -0,0 +1,33 @@
//--------------------------------------
// audioStreamSource.cc
// implementation of streaming audio source
//
// Kurtis Seebaldt
//--------------------------------------
#include "audio/audioStreamSourceFactory.h"
#include "audio/wavStreamSource.h"
#ifndef TORQUE_NO_OGGVORBIS
#include "audio/vorbisStreamSource.h"
#include "audio/oggMixedStreamSource.h"
#endif
AudioStreamSource* AudioStreamSourceFactory::getNewInstance(const char *filename)
{
#ifndef TORQUE_NO_OGGVORBIS
if(!dStricmp(filename, "oggMixedStream"))
return new OggMixedStreamSource(filename);
S32 len = dStrlen(filename);
// Check filename extension and guess filetype from that
if(len > 3 && !dStricmp(filename + len - 4, ".wav"))
return new WavStreamSource(filename);
if(len > 3 && !dStricmp(filename + len - 4, ".ogg"))
return new VorbisStreamSource(filename);
#endif
return NULL;
}

View File

@ -0,0 +1,30 @@
//--------------------------------------------
// audioStreamSource.h
// header for streaming audio source
//
// Kurtis Seebaldt
//--------------------------------------------
#ifndef _AUDIOSTREAMSOURCEFACTORY_H_
#define _AUDIOSTREAMSOURCEFACTORY_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _PLATFORMAUDIO_H_
#include "platform/platformAudio.h"
#endif
#ifndef _PLATFORMAL_H_
#include "platform/platformAL.h"
#endif
#ifndef _AUDIOSTREAMSOURCE_H_
#include "audio/audioStreamSource.h"
#endif
class AudioStreamSourceFactory
{
public:
static AudioStreamSource* getNewInstance(const char* filename);
};
#endif // _AUDIOSTREAMSOURCEFACTORY_H_

View File

@ -0,0 +1,133 @@
//--------------------------------------
//
// This class is basically a buffer that is filled from
// the ogg stream the theoraplayer has open
//
//--------------------------------------
#include "audio/oggMixedStreamSource.h"
OggMixedStreamSource::OggMixedStreamSource(const char *filename)
{
bIsValid = false;
bBuffersAllocated = false;
for(int i = 0; i < BUFFERCNT; i++)
{
mBufferList[i] = 0;
m_fBufferInUse[i] = false;
}
mHandle = NULL_AUDIOHANDLE;
mSource = NULL;
mFilename = filename;
mPosition = Point3F(0.f,0.f,0.f);
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;
bFinishedPlaying = false;
bIsValid = false;
bBuffersAllocated = false;
}
OggMixedStreamSource::~OggMixedStreamSource()
{
if(bIsValid)
freeStream();
}
bool OggMixedStreamSource::initStream()
{
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
// Clear Error Code
alGetError();
alGenBuffers(BUFFERCNT, mBufferList);
if (alGetError() != AL_NO_ERROR)
return false;
bBuffersAllocated = true;
alSourcei(mSource, AL_LOOPING, AL_FALSE);
bIsValid = true;
return true;
}
bool OggMixedStreamSource::updateBuffers()
{
// buffers are updated from theora player
return true;
}
void OggMixedStreamSource::freeStream()
{
// free the al buffers
if(bBuffersAllocated)
{
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
alDeleteBuffers(BUFFERCNT, mBufferList);
alGetError();
for(int i = 0; i < BUFFERCNT; i++)
{
mBufferList[i] = 0;
m_fBufferInUse[i] = false;
}
bBuffersAllocated = false;
}
}
ALuint OggMixedStreamSource::GetAvailableBuffer()
{
if(!bBuffersAllocated)
return 0;
// test for unused buffers
for(int i = 0; i < BUFFERCNT; i++)
{
if(!m_fBufferInUse[i])
{
m_fBufferInUse[i] = true;
return mBufferList[i];
}
}
alGetError();
// test for processed buffers
ALint processed;
alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
if(!processed)
return 0; // no available buffers
ALuint BufferID;
alSourceUnqueueBuffers(mSource, 1, &BufferID);
if (alGetError() != AL_NO_ERROR)
return 0; // something went wrong..
return BufferID;
}
bool OggMixedStreamSource::QueueBuffer(ALuint BufferID)
{
alSourceQueueBuffers(mSource, 1, &BufferID);
if (alGetError() != AL_NO_ERROR)
return false;
return true;
}

View File

@ -0,0 +1,50 @@
//--------------------------------------------
// oggMixedStreamSource.h
// header for audio stream dummy class, basicly
// an audio buffer filled remotely
//
//--------------------------------------------
#ifndef _OGGMIXEDSTREAMSOURCE_H_
#define _OGGMIXEDSTREAMSOURCE_H_
#ifndef _AUDIOSTREAMSOURCE_H_
#include "audio/audioStreamSource.h"
#endif
#define BUFFERCNT 128
class OggMixedStreamSource: public AudioStreamSource
{
public:
OggMixedStreamSource(const char *filename);
virtual ~OggMixedStreamSource();
virtual bool initStream();
virtual bool updateBuffers();
virtual void freeStream();
ALuint GetAvailableBuffer();
bool QueueBuffer(ALuint BufferID);
void PlayStream();
virtual F32 getElapsedTime()
{
return 0.0;
}
virtual F32 getTotalTime()
{
return 1.0f;
}
private:
ALuint mBufferList[BUFFERCNT];
bool m_fBufferInUse[BUFFERCNT];
bool bBuffersAllocated;
void clear();
};
#endif // _OGGMIXEDSTREAMSOURCE_H_

1541
engine/audio/vorbisStream.cc Executable file

File diff suppressed because it is too large Load Diff

157
engine/audio/vorbisStream.h Executable file
View File

@ -0,0 +1,157 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
* by the XIPHOPHORUS Company http://www.xiph.org/ *
* *
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
********************************************************************/
// modified vorbisfile to use Torque Streams
// Kurtis Seebaldt
#ifndef _OV_FILE_H_
#define _OV_FILE_H_
#include <stdio.h>
#include "vorbis/codec.h"
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _RESMANAGER_H_
#include "core/resManager.h"
#endif
/* The function prototypes for the callbacks are basically the same as for
* the stdio functions fread, fseek, fclose, ftell.
* The one difference is that the FILE * arguments have been replaced with
* a void * - this is to be used as a pointer to whatever internal data these
* functions might need. In the stdio case, it's just a FILE * cast to a void *
*
* If you use other functions, check the docs for these functions and return
* the right values. For seek_func(), you *MUST* return -1 if the stream is
* unseekable
*/
//typedef struct {
// size_t (*read_func) (Stream *ptr, size_t size, size_t nmemb, void *datasource);
// int (*seek_func) (Stream *datasource, ogg_int64_t offset, int whence);
// int (*close_func) (void *datasource);
// long (*tell_func) (void *datasource);
//} ov_callbacks;
#define NOTOPEN 0
#define PARTOPEN 1
#define OPENED 2
#define STREAMSET 3
#define INITSET 4
class OggVorbis_File {
public:
Stream *datasource; /* Pointer to a FILE *, etc. */
int seekable;
ogg_int64_t offset;
ogg_int64_t end;
ogg_sync_state oy;
/* If the FILE handle isn't seekable (eg, a pipe), only the current
stream appears */
int links;
ogg_int64_t *offsets;
ogg_int64_t *dataoffsets;
long *serialnos;
ogg_int64_t *pcmlengths;
vorbis_info *vi;
vorbis_comment *vc;
/* Decoding working state local storage */
ogg_int64_t pcm_offset;
int ready_state;
long current_serialno;
int current_link;
double bittrack;
double samptrack;
ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
// ov_callbacks callbacks;
};
class OggVorbisFile {
public:
OggVorbisFile();
~OggVorbisFile();
int ov_clear();
int ov_open(Stream *stream,char *initial,long ibytes);
int ov_open_callbacks(Stream *datasource,
char *initial, long ibytes);
int ov_test(Stream *stream,char *initial,long ibytes);
int ov_test_callbacks(Stream *datasource,
char *initial, long ibytes);
int ov_test_open();
long ov_bitrate(int i);
long ov_bitrate_instant();
long ov_streams();
long ov_seekable();
long ov_serialnumber(int i);
ogg_int64_t ov_raw_total(int i);
ogg_int64_t ov_pcm_total(int i);
double ov_time_total(int i);
int ov_raw_seek(long pos);
int ov_pcm_seek(ogg_int64_t pos);
int ov_pcm_seek_page(ogg_int64_t pos);
int ov_time_seek(double pos);
int ov_time_seek_page(double pos);
ogg_int64_t ov_raw_tell();
ogg_int64_t ov_pcm_tell();
double ov_time_tell();
vorbis_info *ov_info(int link);
vorbis_comment *ov_comment(int link);
long ov_read_float(float ***pcm_channels,
int *bitstream);
long ov_read(char *buffer,int length,
int bigendianp,int *bitstream);
private:
OggVorbis_File *vf;
long _get_data();
void _seek_helper(long offset);
long _get_next_page(ogg_page *og,int boundary);
long _get_prev_page(ogg_page *og);
int _bisect_forward_serialno(long begin,long searched,long end,long currentno,long m);
int _fetch_headers(vorbis_info *vi,vorbis_comment *vc,long *serialno,ogg_page *og_ptr);
void _prefetch_all_headers(long dataoffset);
void _make_decode_ready();
int _open_seekable2();
void _decode_clear();
int _process_packet(int readp);
int _fseek64_wrap(Stream *stream,ogg_int64_t off,int whence);
int _ov_open1(Stream *stream,char *initial,long ibytes);
int _ov_open2();
};
#endif

View File

@ -0,0 +1,442 @@
//--------------------------------------
// vorbisStreamSource.cc
// implementation of streaming audio source
//
// Kurtis Seebaldt
//--------------------------------------
#include "audio/vorbisStreamSource.h"
#include "vorbis/codec.h"
#define BUFFERSIZE 32768
#define CHUNKSIZE 4096
#if defined(TORQUE_BIG_ENDIAN)
#define ENDIAN 1
#else
#define ENDIAN 0
#endif
extern const char * MusicPlayerStreamingHook(const AUDIOHANDLE & handle);
VorbisStreamSource::VorbisStreamSource(const char *filename)
{
stream = NULL;
bIsValid = false;
bBuffersAllocated = false;
bVorbisFileInitialized = false;
mBufferList[0] = 0;
clear();
mFilename = filename;
mPosition = Point3F(0.f,0.f,0.f);
}
VorbisStreamSource::~VorbisStreamSource()
{
if(bReady && bIsValid)
freeStream();
}
void VorbisStreamSource::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;
bVorbisFileInitialized = false;
}
bool VorbisStreamSource::initStream()
{
vorbis_info *vi;
ALint error;
bFinished = false;
// JMQ: changed buffer to static and doubled size. workaround for
// https://206.163.64.242/mantis/view_bug_page.php?f_id=0000242
static char data[BUFFERSIZE*2];
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
stream = ResourceManager->openStream(mFilename);
if(stream != NULL)
{
if(vf.ov_open(stream, NULL, 0) < 0)
{
return false;
}
bVorbisFileInitialized = true;
//Read Vorbis File Info
vi = vf.ov_info(-1);
freq = vi->rate;
long samples = (long)vf.ov_pcm_total(-1);
if(vi->channels == 1)
{
format = AL_FORMAT_MONO16;
DataSize = 2 * samples;
}
else
{
format = AL_FORMAT_STEREO16;
DataSize = 4 * samples;
}
DataLeft = DataSize;
// 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;
long ret = oggRead(data, BUFFERSIZE, ENDIAN, &current_section);
if(ret <= 0)
{
bFinished = AL_TRUE;
break;
}
DataLeft -= ret;
alBufferData(mBufferList[loop], format, data, ret, freq);
++numBuffers;
if ((error = alGetError()) != AL_NO_ERROR)
return false;
if(bFinished)
break;
}
// Queue the buffers on the source
alSourceQueueBuffers(mSource, NUMBUFFERS, mBufferList);
if ((error = alGetError()) != AL_NO_ERROR)
return false;
alSourcei(mSource, AL_LOOPING, AL_FALSE);
bReady = true;
}
else
{
return false;
}
bIsValid = true;
return true;
}
bool VorbisStreamSource::updateBuffers()
{
ALint processed;
ALuint BufferID;
ALint error;
// JMQ: changed buffer to static and doubled size. workaround for
// https://206.163.64.242/mantis/view_bug_page.php?f_id=0000242
static char data[BUFFERSIZE*2];
// don't do anything if stream not loaded properly
if(!bIsValid)
return false;
if(bFinished && mDescription.mIsLooping)
resetStream();
// reset AL error code
alGetError();
#if 1 //def TORQUE_OS_LINUX
// JMQ: this doesn't really help on linux. it may make things worse.
// if it doesn't help on mac/win either, could disable it.
ALint state;
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
if (state == AL_STOPPED)
{
// um, yeah. you should be playing
// restart
alSourcePlay(mSource);
//#ifdef TORQUE_DEBUG
//Con::errorf(">><<>><< THE MUSIC STOPPED >><<>><<");
//#endif
return true;
}
#endif
#ifdef TORQUE_OS_LINUX
checkPosition();
#endif
// 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;
long ret = oggRead(data, BUFFERSIZE, ENDIAN, &current_section);
if(ret > 0)
{
DataLeft -= ret;
alBufferData(BufferID, format, data, ret, 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 true;
}
void VorbisStreamSource::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;
}
if(bVorbisFileInitialized)
{
vf.ov_clear();
bVorbisFileInitialized = false;
}
}
void VorbisStreamSource::resetStream()
{
// MusicPlayerStreamingHook allow you to create a handler
// where you can rotate through streaming files
// Comment in and provide hook if desired.
//
//const char * newFile = MusicPlayerStreamingHook(mHandle);
//if (newFile)
//{
// setNewFile(newFile);
// return;
//}
//else
{
vf.ov_pcm_seek(0);
DataLeft = DataSize;
bFinished = AL_FALSE;
}
}
void VorbisStreamSource::setNewFile(const char * file)
{
//---------------------
// close down old file...
//---------------------
if(stream != NULL)
{
ResourceManager->closeStream(stream);
stream = NULL;
}
if(bVorbisFileInitialized)
{
vf.ov_clear();
bVorbisFileInitialized = false;
}
//---------------------
// open up new file...
//---------------------
mFilename = file;
stream = ResourceManager->openStream(mFilename);
if(stream != NULL)
{
if(vf.ov_open(stream, NULL, 0) < 0)
{
bFinished = AL_TRUE;
bVorbisFileInitialized = false;
bIsValid = false;
return;
}
//Read Vorbis File Info
vorbis_info * vi = vf.ov_info(-1);
freq = vi->rate;
long samples = (long)vf.ov_pcm_total(-1);
if(vi->channels == 1)
{
format = AL_FORMAT_MONO16;
DataSize = 2 * samples;
}
else
{
format = AL_FORMAT_STEREO16;
DataSize = 4 * samples;
}
DataLeft = DataSize;
// Clear Error Code
alGetError();
bFinished = AL_FALSE;
bVorbisFileInitialized = true;
bIsValid = true;
}
}
// ov_read() only returns a maximum of one page worth of data
// this helper function will repeat the read until buffer is full
long VorbisStreamSource::oggRead(char *buffer,int length,
int bigendianp,int *bitstream)
{
long bytesRead = 0;
long totalBytes = 0;
long offset = 0;
long bytesToRead = 0;
while((offset) < length)
{
if((length - offset) < CHUNKSIZE)
bytesToRead = length - offset;
else
bytesToRead = CHUNKSIZE;
bytesRead = vf.ov_read(buffer, bytesToRead, bigendianp, bitstream);
//#ifdef TORQUE_OS_LINUX
#if 1 // Might fix mac audio issue and possibly others...based on references, this looks like correct action
// linux ver will hang on exit after a stream loop if we don't
// do this
if (bytesRead == OV_HOLE)
// retry, see:
// http://www.xiph.org/archives/vorbis-dev/200102/0163.html
// http://www.mit.edu/afs/sipb/user/xiphmont/ogg-sandbox/vorbis/doc/vorbis-errors.txt
continue;
#endif
if(bytesRead <= 0)
break;
offset += bytesRead;
buffer += bytesRead;
}
return offset;
}
#ifdef TORQUE_OS_LINUX
// JMQ: OpenAL sometimes replaces the stream source's position with its own
// nifty value, causing the music to pan around the listener. how nice.
// this function checks to see if the current source position in openal
// is near the initial position, and slams it to the correct value if it
// is wrong.
// This is a bad place to put this, but I don't feel like adding a new
// .cc file. And since this is an incredibly lame hack to
// workaround a stupid OpenAL bug, I see no point in overengineering it.
void AudioStreamSource::checkPosition()
{
ALfloat pos[3];
alGetSourcefv(mSource, AL_POSITION, pos);
// just compute the difference between the openal pos and the
// correct pos. it better be pretty friggin small.
Point3F openalPos(pos[0], pos[1], pos[2]);
F32 slopDist = 0.0001f;
F32 dist = mFabs((openalPos - mPosition).len());
if (dist > slopDist)
// slam!
alSource3f(mSource, AL_POSITION, mPosition.x, mPosition.y, mPosition.z);
}
#endif
F32 VorbisStreamSource::getElapsedTime()
{
return vf.ov_time_tell();
}
F32 VorbisStreamSource::getTotalTime()
{
return vf.ov_time_total(-1);
}

View File

@ -0,0 +1,58 @@
//--------------------------------------------
// vorbisStreamSource.h
// header for streaming audio source for Ogg Vorbis
//
// Kurtis Seebaldt
//--------------------------------------------
#ifndef _VORBISSTREAMSOURCE_H_
#define _VORBISSTREAMSOURCE_H_
#ifndef _AUDIOSTREAMSOURCE_H_
#include "audio/audioStreamSource.h"
#endif
#include "audio/vorbisStream.h"
class VorbisStreamSource: public AudioStreamSource
{
public:
VorbisStreamSource(const char *filename);
virtual ~VorbisStreamSource();
virtual bool initStream();
virtual bool updateBuffers();
virtual void freeStream();
virtual F32 getElapsedTime();
virtual F32 getTotalTime();
private:
ALuint mBufferList[NUMBUFFERS];
S32 mNumBuffers;
S32 mBufferSize;
Stream *stream;
bool bReady;
bool bFinished;
ALenum format;
ALsizei size;
ALsizei freq;
ALuint DataSize;
ALuint DataLeft;
ALuint buffersinqueue;
bool bBuffersAllocated;
bool bVorbisFileInitialized;
int current_section;
OggVorbisFile vf;
void clear();
long oggRead(char *buffer,int length, int bigendianp,int *bitstream);
void resetStream();
void setNewFile(const char * file);
};
#endif // _VORBISSTREAMSOURCE_H_

334
engine/audio/wavStreamSource.cc Executable file
View 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;
}

49
engine/audio/wavStreamSource.h Executable file
View File

@ -0,0 +1,49 @@
//--------------------------------------------
// wavStreamSource.h
// header for streaming audio source for WAV
//--------------------------------------------
#ifndef _WAVSTREAMSOURCE_H_
#define _WAVSTREAMSOURCE_H_
#ifndef _AUDIOSTREAMSOURCE_H_
#include "audio/audioStreamSource.h"
#endif
class WavStreamSource: public AudioStreamSource
{
public:
WavStreamSource(const char *filename);
virtual ~WavStreamSource();
virtual bool initStream();
virtual bool updateBuffers();
virtual void freeStream();
virtual F32 getElapsedTime();
virtual F32 getTotalTime();
private:
ALuint mBufferList[NUMBUFFERS];
S32 mNumBuffers;
S32 mBufferSize;
Stream *stream;
bool bReady;
bool bFinished;
ALenum format;
ALsizei size;
ALsizei freq;
ALuint DataSize;
ALuint DataLeft;
ALuint dataStart;
ALuint buffersinqueue;
bool bBuffersAllocated;
void clear();
void resetStream();
};
#endif // _AUDIOSTREAMSOURCE_H_