tge/engine/audio/audioDataBlock.cc
2025-02-17 23:17:30 -06:00

527 lines
21 KiB
C++
Executable File

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