#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);
		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(&notation_file);

	//
	//----------------------------------------------------------------------
	// Build the static audio object stream
	//----------------------------------------------------------------------
	//
	AudioObjectStream audio_object_stream;

   Check(&audio_object_stream);
   audio_object_stream.BuildFromNotationFile(&notation_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;
}
