User reported never hearing any audio. Root-caused: the KB "Audio: DONE" was wrong. The OpenAL playback chain IS fully implemented (device/buffers/sources; PlayNote really calls alSourcePlay), but three gaps kept it silent: 1. GATED OFF (the "no sound" root cause): BTL4Application::MakeAudioRenderer returned NULL unless the pod's AWE_FRONT/AWE_REAR AWE32-card env vars were set -- authentic 1995 pod behavior, dead on modern hardware, so the renderer was NEVER created. FIXED: default audio ON (BT_NO_AUDIO=1 restores silence; AWE vars still force-on). Verified: the OpenAL device now opens with no env vars ([audio] device OPENED). 2. Soundbank STUB: allPresets[2][100] (btstubs.cpp) is zero-init -> PRESET_isImplemented false -> 0 buffers load. Sample data exists (AUDIO1/2.RES: EnginePower/LaserAFire/...) but the event->sample map is gone (not in the decomp). STILL OPEN. 3. No triggering: the reconstructed game never creates AudioEntities on events. STILL OPEN. So the device opens but nothing loads/plays yet -- enabling real sound needs the soundbank reconstructed + the game triggers wired (a proper audio wave). Added a BT_AUDIO_LOG trace harness across L4AUDRND/L4AUDRES/L4AUDLVL. KB corrected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1118 lines
30 KiB
C++
1118 lines
30 KiB
C++
#include <cstdlib>
|
|
#include "mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4audres.h"
|
|
#include "l4audhdw.h"
|
|
#include "l4audio.h"
|
|
#include "l4audlvl.h"
|
|
#include "l4audwtr.h"
|
|
#include "..\munga\audcmp.h"
|
|
#include "..\munga\audseq.h"
|
|
#include "..\munga\audrend.h"
|
|
#include "..\munga\namelist.h"
|
|
#include "..\munga\app.h"
|
|
#include "..\munga\notation.h"
|
|
#include "openal\al.h"
|
|
#include "sndfile.h"
|
|
|
|
ALuint *g_buffers;
|
|
int g_numBuffers;
|
|
|
|
//#############################################################################
|
|
//####################### AudioObjectStream #############################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
// AudioObjectStream
|
|
//#############################################################################
|
|
//
|
|
AudioObjectStream::AudioObjectStream(
|
|
ResourceDescription *resource_description,
|
|
Entity *the_entity
|
|
):
|
|
PlugStream(resource_description)
|
|
{
|
|
entity = the_entity;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AudioObjectStream
|
|
//#############################################################################
|
|
//
|
|
AudioObjectStream::AudioObjectStream()
|
|
{
|
|
entity = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~AudioObjectStream
|
|
//#############################################################################
|
|
//
|
|
AudioObjectStream::~AudioObjectStream()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
AudioObjectStream::TestInstance() const
|
|
{
|
|
PlugStream::TestInstance();
|
|
if (entity != NULL)
|
|
{
|
|
Check(entity);
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeObjectImplementation
|
|
//#############################################################################
|
|
//
|
|
RegisteredClass*
|
|
AudioObjectStream::MakeObjectImplementation(Enumeration class_ID)
|
|
{
|
|
Check(this);
|
|
Verify(class_ID != RegisteredClass::NullClassID);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// HACK - Constructors should be referenced through registration, for
|
|
// now just use a switch statement
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
RegisteredClass *object;
|
|
|
|
switch (class_ID)
|
|
{
|
|
//
|
|
// Static resources ...
|
|
//
|
|
case RegisteredClass::PatchLevelOfDetailClassID:
|
|
object = new PatchLevelOfDetail(this);
|
|
break;
|
|
|
|
case RegisteredClass::PatchResourceClassID:
|
|
object = new PatchResource(this);
|
|
break;
|
|
|
|
case RegisteredClass::AudioResourceIndexClassID:
|
|
object = new AudioResourceIndex(this);
|
|
break;
|
|
|
|
//
|
|
// Location and sources ...
|
|
//
|
|
case RegisteredClass::L4AudioLocationClassID:
|
|
object = new L4AudioLocation(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::DirectPatchSourceClassID:
|
|
object = new DirectPatchSource(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::Dynamic3DPatchSourceClassID:
|
|
object = new Dynamic3DPatchSource(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::Static3DPatchSourceClassID:
|
|
object = new Static3DPatchSource(this, entity);
|
|
break;
|
|
|
|
//
|
|
// Audio components ...
|
|
//
|
|
case RegisteredClass::AudioControlMixerClassID:
|
|
object = new AudioControlMixer(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlMultiplierClassID:
|
|
object = new AudioControlMultiplier(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioResourceSelectorClassID:
|
|
object = new AudioResourceSelector(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSmootherClassID:
|
|
object = new AudioControlSmoother(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioSampleAndHoldClassID:
|
|
object = new AudioSampleAndHold(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSendClassID:
|
|
object = new AudioControlSend(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSequenceClassID:
|
|
object = new AudioControlSequence(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSplitterClassID:
|
|
object = new AudioControlSplitter(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioLFOClassID:
|
|
object = new AudioLFO(this, entity);
|
|
break;
|
|
|
|
//
|
|
// Audio watchers ...
|
|
//
|
|
case RegisteredClass::AudioMotionTriggerClassID:
|
|
object = new AudioMotionTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioMotionScaleClassID:
|
|
object = new AudioMotionScale(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioHingeScaleClassID:
|
|
object = new AudioHingeScale(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioScalarTriggerClassID:
|
|
object = new AudioScalarTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioScalarScaleClassID:
|
|
object = new AudioScalarScale(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioLogicalTriggerClassID:
|
|
object = new AudioLogicalTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioEnumerationTriggerClassID:
|
|
object = new AudioEnumerationTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioIntegerTriggerClassID:
|
|
object = new AudioIntegerTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlsButtonTriggerClassID:
|
|
object = new AudioControlsButtonTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioStateTriggerClassID:
|
|
object = new AudioStateTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioIdleWatcherClassID:
|
|
object = new AudioIdleWatcher(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioEnumerationDeltaTriggerClassID:
|
|
object = new AudioEnumerationDeltaTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioScalarDeltaTriggerClassID:
|
|
object = new AudioScalarDeltaTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::L4AudioCollisionTriggerClassID:
|
|
object = new L4AudioCollisionTrigger(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioMessageWatcherClassID:
|
|
object = new AudioMessageWatcher(this, entity);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlsButtonMessageWatcherClassID:
|
|
object = new AudioControlsButtonMessageWatcher(this, entity);
|
|
break;
|
|
|
|
//
|
|
// Inherited behavior
|
|
//
|
|
default:
|
|
object = PlugStream::MakeObjectImplementation(class_ID);
|
|
break;
|
|
}
|
|
return object;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreatedObjectImplementation
|
|
//#############################################################################
|
|
//
|
|
void
|
|
AudioObjectStream::CreatedObjectImplementation(
|
|
RegisteredClass *object,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(object);
|
|
Verify(object_ID != NullObjectID);
|
|
|
|
//
|
|
// std::Decide which index to add object to
|
|
//
|
|
switch (object->GetClassID())
|
|
{
|
|
case RegisteredClass::PatchLevelOfDetailClassID:
|
|
case RegisteredClass::PatchResourceClassID:
|
|
case RegisteredClass::AudioResourceIndexClassID:
|
|
AddGlobalPlug(Cast_Object(Plug*, object), object_ID);
|
|
break;
|
|
|
|
default:
|
|
AddLocalPlug(Cast_Object(Plug*, object), object_ID);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuildFromPageImplementation
|
|
//#############################################################################
|
|
//
|
|
void
|
|
AudioObjectStream::BuildFromPageImplementation(
|
|
NameList *name_list,
|
|
Enumeration class_ID_enumeration,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
Check(this);
|
|
Verify(class_ID_enumeration != RegisteredClass::NullClassID);
|
|
Verify(object_ID != NullObjectID);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// HACK - Page interpreters should be referenced through registration,
|
|
// for now just use a switch statement
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
RegisteredClass::ClassID
|
|
class_ID = (RegisteredClass::ClassID)class_ID_enumeration;
|
|
|
|
switch (class_ID)
|
|
{
|
|
//
|
|
// Static resources ...
|
|
//
|
|
case RegisteredClass::PatchLevelOfDetailClassID:
|
|
PatchLevelOfDetail::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::PatchResourceClassID:
|
|
PatchResource::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioResourceIndexClassID:
|
|
AudioResourceIndex::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
//
|
|
// Location and sources ...
|
|
//
|
|
case RegisteredClass::L4AudioLocationClassID:
|
|
L4AudioLocation::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::DirectPatchSourceClassID:
|
|
DirectPatchSource::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::Dynamic3DPatchSourceClassID:
|
|
Dynamic3DPatchSource::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::Static3DPatchSourceClassID:
|
|
Static3DPatchSource::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
//
|
|
// Audio components ...
|
|
//
|
|
case RegisteredClass::AudioControlMixerClassID:
|
|
AudioControlMixer::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlMultiplierClassID:
|
|
AudioControlMultiplier::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioResourceSelectorClassID:
|
|
AudioResourceSelector::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSmootherClassID:
|
|
AudioControlSmoother::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioSampleAndHoldClassID:
|
|
AudioSampleAndHold::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSendClassID:
|
|
AudioControlSend::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSequenceClassID:
|
|
AudioControlSequence::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlSplitterClassID:
|
|
AudioControlSplitter::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioLFOClassID:
|
|
AudioLFO::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
//
|
|
// Audio watchers ...
|
|
//
|
|
case RegisteredClass::AudioMotionTriggerClassID:
|
|
AudioMotionTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioMotionScaleClassID:
|
|
AudioMotionScale::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioHingeScaleClassID:
|
|
AudioHingeScale::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioScalarTriggerClassID:
|
|
AudioScalarTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioScalarScaleClassID:
|
|
AudioScalarScale::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioLogicalTriggerClassID:
|
|
AudioLogicalTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioEnumerationTriggerClassID:
|
|
AudioEnumerationTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioIntegerTriggerClassID:
|
|
AudioIntegerTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlsButtonTriggerClassID:
|
|
AudioControlsButtonTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioStateTriggerClassID:
|
|
AudioStateTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioIdleWatcherClassID:
|
|
AudioIdleWatcher::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioEnumerationDeltaTriggerClassID:
|
|
AudioEnumerationDeltaTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioScalarDeltaTriggerClassID:
|
|
AudioScalarDeltaTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::L4AudioCollisionTriggerClassID:
|
|
L4AudioCollisionTrigger::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioMessageWatcherClassID:
|
|
AudioMessageWatcher::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
case RegisteredClass::AudioControlsButtonMessageWatcherClassID:
|
|
AudioControlsButtonMessageWatcher::BuildFromPage(this, name_list, class_ID, object_ID);
|
|
break;
|
|
|
|
//
|
|
// Inherited behavior
|
|
//
|
|
default:
|
|
PlugStream::BuildFromPageImplementation(name_list, class_ID, object_ID);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuiltFromPageImplementation
|
|
//#############################################################################
|
|
//
|
|
void
|
|
AudioObjectStream::BuiltFromPageImplementation(
|
|
Enumeration class_ID,
|
|
ObjectID object_ID,
|
|
const CString &object_name
|
|
)
|
|
{
|
|
Check(this);
|
|
Verify(class_ID != RegisteredClass::NullClassID);
|
|
Verify(object_ID != NullObjectID);
|
|
Check(&object_name);
|
|
|
|
//
|
|
// std::Decide which index to add object to
|
|
//
|
|
if (object_name.Length() == 0)
|
|
return;
|
|
|
|
switch (class_ID)
|
|
{
|
|
case RegisteredClass::PatchLevelOfDetailClassID:
|
|
case RegisteredClass::PatchResourceClassID:
|
|
case RegisteredClass::AudioResourceIndexClassID:
|
|
AddGlobalObjectID(object_ID, object_name);
|
|
break;
|
|
|
|
default:
|
|
AddLocalObjectID(object_ID, object_name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### L4AudioResourceManager #########################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
// L4AudioResourceManager
|
|
//#############################################################################
|
|
//
|
|
L4AudioResourceManager::L4AudioResourceManager()
|
|
{
|
|
g_buffers = NULL;
|
|
g_numBuffers = 0;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~L4AudioResourceManager
|
|
//#############################################################################
|
|
//
|
|
L4AudioResourceManager::~L4AudioResourceManager()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
L4AudioResourceManager::TestInstance() const
|
|
{
|
|
Node::TestInstance();
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// PreloadResources
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioResourceManager::PreloadResources(
|
|
NotationFile *notation_file
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(notation_file);
|
|
//Check(audio_hardware);
|
|
|
|
//Determine how many loadable samples exist
|
|
g_numBuffers=0;
|
|
|
|
for(int i=1; i <= 2; i++)
|
|
{
|
|
for (int j=0; j < 100; j++)
|
|
{
|
|
if (PRESET_isImplemented(i,j))
|
|
{
|
|
g_numBuffers += PRESET_getNumSamples(i,j);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Generate the buffers
|
|
if (g_numBuffers > 0)
|
|
{
|
|
//Generate buffers
|
|
alGetError();
|
|
g_buffers = new ALuint[g_numBuffers];
|
|
alGenBuffers(g_numBuffers,g_buffers);
|
|
if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] alGenBuffers count=" << g_numBuffers << "\n" << std::flush;
|
|
ALenum error;
|
|
if ((error = alGetError()) != AL_NO_ERROR)
|
|
{
|
|
DEBUG_STREAM << "OpenAL has encountered an error while initializing the buffers." << std::endl;
|
|
delete [] g_buffers;
|
|
g_buffers = NULL;
|
|
g_numBuffers = 0;
|
|
}
|
|
}
|
|
|
|
int bufferInd = 0;
|
|
//Load buffers
|
|
for(int i=1; i<=2 && bufferInd < g_numBuffers; i++)
|
|
{
|
|
for(int j=0; j<100 && bufferInd < g_numBuffers; j++)
|
|
{
|
|
if (PRESET_isImplemented(i,j))
|
|
{
|
|
for (int k=0; k < PRESET_getNumSamples(i,j) && bufferInd < g_numBuffers; k++)
|
|
{
|
|
SAMPLEINFO info = PRESET_getSampleInfo(i,j,k);
|
|
|
|
//Load WAV to buffer
|
|
char *data;
|
|
int size;
|
|
|
|
//Open WAV
|
|
char fullname[50];
|
|
strcpy_s(fullname,50,"AUDIO\\");
|
|
strcat_s(fullname,50,info.file);
|
|
SF_INFO *sfInfo = new SF_INFO[2];
|
|
//SF_INFO is working different than expected!
|
|
sfInfo->format = 0;
|
|
SNDFILE *file = sf_open(fullname,SFM_READ,sfInfo);
|
|
|
|
if (file == NULL)
|
|
{
|
|
DEBUG_STREAM << "Failed to open." << std::endl;
|
|
}
|
|
|
|
unsigned long formatBits = 0;
|
|
unsigned long sampleRate = sfInfo->samplerate;
|
|
size = sfInfo->frames;
|
|
|
|
bool isMono = (sfInfo->channels == 1);
|
|
|
|
if (sfInfo->format & SF_FORMAT_PCM_S8)
|
|
{
|
|
formatBits = 8;
|
|
} else if (sfInfo->format & SF_FORMAT_PCM_16)
|
|
{
|
|
formatBits = 16;
|
|
} else
|
|
{
|
|
DEBUG_STREAM << "BAD FORMAT" << std::endl;
|
|
}
|
|
|
|
ALenum format;
|
|
if (formatBits == 8)
|
|
{
|
|
if (isMono)
|
|
{
|
|
format = AL_FORMAT_MONO8;
|
|
} else
|
|
{
|
|
size *= 2;
|
|
format = AL_FORMAT_STEREO8;
|
|
}
|
|
} else if (formatBits == 16)
|
|
{
|
|
size *= 2;
|
|
if (isMono)
|
|
{
|
|
format = AL_FORMAT_MONO16;
|
|
} else
|
|
{
|
|
size *= 2;
|
|
format = AL_FORMAT_STEREO16;
|
|
}
|
|
}
|
|
|
|
ALsizei alSampleRate = sampleRate;
|
|
|
|
//Load size & data
|
|
delete [] sfInfo;
|
|
data = new char[size];
|
|
sf_read_raw(file,data,size);
|
|
sf_close(file);
|
|
|
|
//Feed the buffer
|
|
alBufferData(g_buffers[bufferInd],format,data,size,alSampleRate);
|
|
PRESET_setBufferIndex(i,j,k,bufferInd);
|
|
bufferInd++;
|
|
|
|
delete [] data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Load the sound banks
|
|
//----------------------------------------------------------------------
|
|
//
|
|
/*NameList *name_list;
|
|
NameList::Entry *entry;
|
|
|
|
Verify(notation_file->EntryCount("AudioResources") >= 2);
|
|
|
|
name_list = notation_file->MakeEntryList("AudioResources");
|
|
Register_Object(name_list);
|
|
entry = name_list->GetFirstEntry();
|
|
Check(entry);
|
|
while (entry != NULL)
|
|
{
|
|
Check(entry);
|
|
if (entry->IsName("front_audio_resource"))
|
|
{
|
|
Check_Pointer(entry->GetChar());
|
|
Check(audio_hardware->GetFrontCard());
|
|
audio_hardware->GetFrontCard()->LoadSBK(entry->GetChar());
|
|
}
|
|
else
|
|
{
|
|
Verify(entry->IsName("rear_audio_resource"));
|
|
Check_Pointer(entry->GetChar());
|
|
Check(audio_hardware->GetRearCard());
|
|
audio_hardware->GetRearCard()->LoadSBK(entry->GetChar());
|
|
}
|
|
entry = entry->GetNextEntry();
|
|
}
|
|
Unregister_Object(name_list);
|
|
delete name_list;*/
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Create static audio objects
|
|
//----------------------------------------------------------------------
|
|
//
|
|
|
|
//
|
|
// Get static audio stream resource
|
|
//
|
|
ResourceDescription *resource_description;
|
|
|
|
Check(application);
|
|
Check(application->GetResourceFile());
|
|
resource_description =
|
|
application->GetResourceFile()->FindResourceDescription(
|
|
"StaticAudioStream",
|
|
ResourceDescription::StaticAudioStreamResourceType
|
|
);
|
|
Check(resource_description);
|
|
resource_description->Lock();
|
|
|
|
//
|
|
// Parse the audio object stream
|
|
//
|
|
AudioObjectStream audio_object_stream(resource_description, NULL);
|
|
|
|
Check(&audio_object_stream);
|
|
audio_object_stream.CreateObjects();
|
|
resource_description->Unlock();
|
|
}
|
|
|
|
ALuint AL_getBuffer(int index)
|
|
{
|
|
return g_buffers[index];
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// UnloadResources
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioResourceManager::UnloadResources(
|
|
)
|
|
{
|
|
Check(this);
|
|
// Check(audio_hardware);
|
|
|
|
//Unload wav data
|
|
if (g_numBuffers > 0)
|
|
{
|
|
alGetError();
|
|
alDeleteBuffers(g_numBuffers,g_buffers);
|
|
ALenum error = alGetError();
|
|
if (error != AL_NO_ERROR)
|
|
{
|
|
DEBUG_STREAM << "OpenAL reached an error when attempting to delete its buffers." << std::endl;
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Release banks
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// Check(audio_hardware->GetFrontCard());
|
|
// audio_hardware->GetFrontCard()->ReleaseAllBanks();
|
|
// Check(audio_hardware->GetRearCard());
|
|
// audio_hardware->GetRearCard()->ReleaseAllBanks();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreateStaticAudioStreamResource
|
|
//#############################################################################
|
|
//
|
|
ResourceDescription::ResourceID
|
|
L4AudioResourceManager::CreateStaticAudioStreamResource(
|
|
ResourceFile *resource_file
|
|
)
|
|
{
|
|
Check(resource_file);
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Open the notation file for the static stream resource
|
|
//----------------------------------------------------------------------
|
|
//
|
|
Tell("Opening Audio Script audio\\static.scp\n");
|
|
NotationFile notation_file("audio\\static.scp");
|
|
Check(¬ation_file);
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Build the static audio object stream
|
|
//----------------------------------------------------------------------
|
|
//
|
|
AudioObjectStream audio_object_stream;
|
|
|
|
Check(&audio_object_stream);
|
|
audio_object_stream.BuildFromNotationFile(¬ation_file, resource_file);
|
|
Tell("Closed Audio Script\n");
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Add the resource
|
|
//----------------------------------------------------------------------
|
|
//
|
|
ResourceDescription *res_description;
|
|
|
|
res_description =
|
|
resource_file->AddResourceMemoryStream(
|
|
"StaticAudioStream",
|
|
ResourceDescription::StaticAudioStreamResourceType,
|
|
1,
|
|
ResourceDescription::Preload,
|
|
&audio_object_stream
|
|
);
|
|
Check(res_description);
|
|
return res_description->resourceID;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreateEntityAudioObjects
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioResourceManager::CreateEntityAudioObjects(
|
|
Entity *entity,
|
|
AudioRepresentation audio_representation
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(entity);
|
|
Verify(
|
|
audio_representation == InternalAudioRepresentation ||
|
|
audio_representation == ExternalAudioRepresentation
|
|
);
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Read the audio resource for this entity
|
|
//------------------------------------------------------------------------
|
|
//
|
|
ResourceDescription *audio_resource_description;
|
|
|
|
Check(application);
|
|
Check(application->GetResourceFile());
|
|
audio_resource_description =
|
|
application->GetResourceFile()->SearchList(
|
|
entity->GetResourceID(),
|
|
ResourceDescription::AudioStreamListResourceType
|
|
);
|
|
if (audio_resource_description == NULL)
|
|
return;
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Read the appropriate resource for an internal or external
|
|
// representation
|
|
//------------------------------------------------------------------------
|
|
//
|
|
ResourceDescription *stream_resource_description;
|
|
|
|
Check(application);
|
|
Check(application->GetResourceFile());
|
|
Check(audio_resource_description);
|
|
stream_resource_description =
|
|
application->GetResourceFile()->SearchList(
|
|
audio_resource_description->resourceID,
|
|
(audio_representation == InternalAudioRepresentation) ?
|
|
ResourceDescription::InternalAudioStreamResourceType :
|
|
ResourceDescription::ExternalAudioStreamResourceType
|
|
);
|
|
if (stream_resource_description == NULL)
|
|
return;
|
|
Check(stream_resource_description);
|
|
stream_resource_description->Lock();
|
|
audio_resource_description->Lock();
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Make the audio object stream
|
|
//------------------------------------------------------------------------
|
|
//
|
|
AudioObjectStream
|
|
audio_object_stream(
|
|
stream_resource_description,
|
|
entity
|
|
);
|
|
|
|
Check(&audio_object_stream);
|
|
audio_object_stream.CreateObjects();
|
|
stream_resource_description->Unlock();
|
|
audio_resource_description->Unlock();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// DestroyEntityAudioObjects
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4AudioResourceManager::DestroyEntityAudioObjects(Entity *entity)
|
|
{
|
|
Check(this);
|
|
Check(entity);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Stop and delete all audio objects
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Entity::AudioSocketIterator
|
|
iterator(entity);
|
|
Component
|
|
*component;
|
|
AudioComponent
|
|
*audio_component;
|
|
|
|
Check(&iterator);
|
|
while ((component = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
audio_component = Cast_Object(AudioComponent*, component);
|
|
Check(audio_component);
|
|
audio_component->ReceiveControl(StopAudioControlID, 0.0f);
|
|
audio_component->ReceiveControl(FlushMessagesAudioControlID, 0.0f);
|
|
}
|
|
iterator.DeletePlugs();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreateModelAudioResource
|
|
//#############################################################################
|
|
//
|
|
ResourceDescription::ResourceID
|
|
L4AudioResourceManager::CreateModelAudioStreamResource(
|
|
ResourceFile *resource_file,
|
|
const char *model_name,
|
|
NotationFile *model_file,
|
|
const ResourceDirectories*
|
|
)
|
|
{
|
|
Check(resource_file);
|
|
Check_Pointer(model_name);
|
|
Check(model_file);
|
|
|
|
const char *script_name = NULL;
|
|
ResourceDescription::ResourceID resource_id_list[3];
|
|
size_t list_length = 0;
|
|
|
|
resource_id_list[0] = ResourceDescription::NullResourceID;
|
|
resource_id_list[1] = ResourceDescription::NullResourceID;
|
|
resource_id_list[2] = ResourceDescription::NullResourceID;
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Check for the external audio script
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (model_file->GetEntry("audio", "external", &script_name))
|
|
{
|
|
//
|
|
// See if the resource already exists
|
|
//
|
|
ResourceDescription *res_description =
|
|
resource_file->FindResourceDescription(
|
|
script_name,
|
|
ResourceDescription::ExternalAudioStreamResourceType
|
|
);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If not, create it
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (res_description == NULL)
|
|
{
|
|
//
|
|
// Make the file name
|
|
//
|
|
CString file_name(script_name);
|
|
CString prefix("audio\\");
|
|
|
|
file_name = prefix + file_name;
|
|
|
|
//
|
|
// Build the memory stream
|
|
//
|
|
Tell("Opening Audio Script " << file_name << "\n");
|
|
NotationFile script_file(file_name);
|
|
AudioObjectStream audio_object_stream;
|
|
|
|
Check(&script_file);
|
|
Check(&audio_object_stream);
|
|
audio_object_stream.BuildFromNotationFile(&script_file, resource_file);
|
|
Tell("Closed Audio Script\n");
|
|
|
|
//
|
|
// Add the resource
|
|
//
|
|
res_description =
|
|
resource_file->AddResourceMemoryStream(
|
|
script_name,
|
|
ResourceDescription::ExternalAudioStreamResourceType,
|
|
1,
|
|
ResourceDescription::Preload,
|
|
&audio_object_stream
|
|
);
|
|
}
|
|
Check(res_description);
|
|
resource_id_list[list_length++] = res_description->resourceID;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Check for the internal audio script
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (model_file->GetEntry("audio", "internal", &script_name))
|
|
{
|
|
//
|
|
// See if the resource already exists
|
|
//
|
|
ResourceDescription *res_description =
|
|
resource_file->FindResourceDescription(
|
|
script_name,
|
|
ResourceDescription::InternalAudioStreamResourceType
|
|
);
|
|
|
|
//
|
|
// If not, create it
|
|
//
|
|
if (res_description == NULL)
|
|
{
|
|
//
|
|
// Make the file name
|
|
//
|
|
CString file_name(script_name);
|
|
CString prefix("audio\\");
|
|
|
|
file_name = prefix + file_name;
|
|
|
|
//
|
|
// Build the memory stream
|
|
//
|
|
Tell("Opening Audio Script " << file_name << "\n");
|
|
NotationFile script_file(file_name);
|
|
AudioObjectStream audio_object_stream;
|
|
|
|
Check(&script_file);
|
|
Check(&audio_object_stream);
|
|
audio_object_stream.BuildFromNotationFile(&script_file, resource_file);
|
|
Tell("Closed Audio Script\n");
|
|
|
|
//
|
|
// Add the resource
|
|
//
|
|
res_description =
|
|
resource_file->AddResourceMemoryStream(
|
|
script_name,
|
|
ResourceDescription::InternalAudioStreamResourceType,
|
|
1,
|
|
ResourceDescription::Preload,
|
|
&audio_object_stream
|
|
);
|
|
}
|
|
Check(res_description);
|
|
resource_id_list[list_length++] = res_description->resourceID;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Check for the audio entity model
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
const char *audio_entity_model = NULL;
|
|
|
|
if (model_file->GetEntry("audio", "model", &audio_entity_model))
|
|
{
|
|
//
|
|
// The resource should already exist
|
|
//
|
|
ResourceDescription *res_description =
|
|
resource_file->FindResourceDescription(
|
|
audio_entity_model,
|
|
ResourceDescription::ModelListResourceType
|
|
);
|
|
if (res_description == NULL)
|
|
{
|
|
std::cout << "audio_entity_model == " << audio_entity_model;
|
|
Fail("L4AudioResourceManager::CreateModelAudioStreamResource - model not found");
|
|
}
|
|
Check(res_description);
|
|
resource_id_list[list_length++] = res_description->resourceID;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If either script has been created, then create the resource list
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (list_length > 0)
|
|
{
|
|
ResourceDescription *res_description =
|
|
resource_file->AddResourceList(
|
|
model_name,
|
|
ResourceDescription::AudioStreamListResourceType,
|
|
1,
|
|
ResourceDescription::Preload,
|
|
resource_id_list,
|
|
list_length
|
|
);
|
|
Check(res_description);
|
|
return res_description->resourceID;
|
|
}
|
|
return ResourceDescription::NullResourceID;
|
|
}
|