//===========================================================================// // File: AudioRenderer.cpp // // Project: MUNGA Brick: Video Renderer // // Contents: Abstracted Base Video Renderer // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 03/04/97 JTR Initial coding. // //---------------------------------------------------------------------------// // Copyright (C) 1997, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "AdeptHeaders.hpp" #include "ComponentHeaders.hpp" #include "RendererManager.hpp" #include "AudioRenderer.hpp" #include "Application.hpp" #include "Interface.hpp" #include "Map.hpp" #include "Application.hpp" #include "SpatializedChannel.hpp" #include "AudioCommand.hpp" #include "AudioSample.hpp" #include "AudioFXComponent.hpp" #include "EarComponent.hpp" #include "VOChannel.hpp" Stuff::Scalar ChannelType::s_musicVolume = 1.0f; Stuff::Scalar ChannelType::s_sfxVolume = 1.0f; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ChannelType::ChannelType(): m_queued(false), m_volume(1.0f) { m_type = -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ChannelType::SetChannelActive(AudioChannel *channel) { Check_Object(this); Check_Object(channel); Verify(m_type != -1); Verify(m_inactiveChannels.IsPlugMember(channel)); m_inactiveChannels.RemovePlug(channel); Verify(!m_activeChannels.IsPlugMember(channel)); m_activeChannels.Add(channel); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ChannelType::SetChannelInactive(AudioChannel *channel) { Check_Object(this); Check_Object(channel); Verify(m_type != -1); Verify(m_activeChannels.IsPlugMember(channel)); m_activeChannels.RemovePlug(channel); Verify(!m_inactiveChannels.IsPlugMember(channel)); m_inactiveChannels.Add(channel); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ChannelType::SetVolume(Scalar volume) { Check_Object(this); Verify(m_type != -1); if (m_type == AudioRenderer::MusicType) volume *= s_musicVolume; else if (m_type == AudioRenderer::GeneralType) volume *= s_sfxVolume; m_volume = volume; ChainIteratorOf actives(&m_activeChannels); AudioChannel *channel; while ((channel = actives.ReadAndNext()) != NULL) { Check_Object(channel); channel->SetVolume(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ChannelType::StopAll() { Check_Object(this); Verify(m_type != -1); ChainIteratorOf actives(&m_activeChannels); AudioChannel *channel; while ((channel = actives.ReadAndNext()) != NULL) { Check_Object(channel); channel->Stop(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ChannelType::PauseAll() { Check_Object(this); ChainIteratorOf actives(&m_activeChannels); AudioChannel *channel; while ((channel = actives.ReadAndNext()) != NULL) { Check_Object(channel); gosAudio_SetChannelPlayMode(channel->m_channel, gosAudio_Pause); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ChannelType::ResumeAll() { Check_Object(this); ChainIteratorOf actives(&m_activeChannels); AudioChannel *channel; while ((channel = actives.ReadAndNext()) != NULL) { Check_Object(channel); gosAudio_SetChannelPlayMode(channel->m_channel, gosAudio_Continue); } } //########################################################################## //########################### AudioRenderer ########################## //########################################################################## AudioRenderer::ClassData* AudioRenderer::DefaultData = NULL; AudioRenderer *AudioRenderer::Instance = NULL; HGOSHEAP AudioRenderer::s_Heap = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::InitializeClass() { Verify(!s_Heap); s_Heap = gos_CreateMemoryHeap("Audio Renderer", 0, g_LibraryHeap); Check_Pointer(s_Heap); Verify(!DefaultData); DefaultData = new ClassData( AudioRendererClassID, "Adept::AudioRenderer", BaseClass::DefaultData, 0, NULL ); Check_Object(DefaultData); ChannelType::s_musicVolume = 1.0f; ChannelType::s_sfxVolume = 1.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; Check_Pointer(s_Heap); gos_DestroyMemoryHeap(s_Heap); s_Heap = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AudioRenderer::AudioRenderer(): Renderer( DefaultData, RendererManager::AudioRendererType, "AudioRenderer" ), m_channels(Environment.soundChannels), m_sampleCache(101,NULL,true), m_channelTypes(TypeCount), iface(NULL) { Check_Pointer(this); // //---------------------------- // Zero out the channel arrays //---------------------------- // memset(m_channels.GetData(), 0, m_channels.GetSize()); Verify(m_channels.GetLength() >= 32); m_cacheSize = 0; Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AudioRenderer::~AudioRenderer() { Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::SetRendererStatus(RendererStatus status) { Check_Object(this); switch (status) { case ActiveRendererStatus: { // //---------------- // Setup the mixer //---------------- // gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Rolloff, 1.0f); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Reverb, 1.0f); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Decay, 0.1f); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Distance, 1.0f); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Doppler, 1.0f); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Volume, 1.0f); // //--------------------------- // Make the voiceover channel //--------------------------- // int channel_id = 0; AudioChannel *channel; m_channelTypes[VOType].m_queued = true; m_channelTypes[VOType].m_volume = 0.0f; m_channelTypes[VOType].m_type = VOType; channel = new VOChannel(channel_id, VOType); Check_Object(channel); m_channels[channel_id] = channel; m_channelTypes[VOType].m_inactiveChannels.Add(channel); channel_id = 2; // //-------------------------------- // Allocate the two music channels //-------------------------------- // m_channelTypes[MusicType].m_type = MusicType; m_channelTypes[MusicType].m_volume = ChannelType::s_musicVolume; for (int i=0; i<2; ++i) { channel = new AudioChannel( AudioChannel::DefaultData, channel_id, MusicType, gosAudio_Volume ); Check_Object(channel); m_channels[channel_id++] = channel; m_channelTypes[MusicType].m_inactiveChannels.Add(channel); } Verify(channel_id == 4); // //----------------------- // Make the betty channel //----------------------- // m_channelTypes[BettyType].m_queued = true; m_channelTypes[BettyType].m_type = BettyType; m_channelTypes[BettyType].m_volume = 1.0f; channel = new AudioChannel( AudioChannel::DefaultData, channel_id, BettyType, gosAudio_Common|gosAudio_Volume ); Check_Object(channel); m_channels[channel_id++] = channel; m_channelTypes[BettyType].m_inactiveChannels.Add(channel); Verify(channel_id == 5); // //--------------------------------- // Make the six mechanical channels //--------------------------------- // m_channelTypes[MechanicalType].m_type = MechanicalType; m_channelTypes[MechanicalType].m_volume = 1.0f; for (i=0; i<6; ++i) { channel = new AudioChannel( AudioChannel::DefaultData, channel_id, MechanicalType, gosAudio_Common|gosAudio_Volume ); Check_Object(channel); m_channels[channel_id++] = channel; m_channelTypes[MechanicalType].m_inactiveChannels.Add(channel); } Verify(channel_id == 11); // //------------------------------ // Allocate the general channels //------------------------------ // m_channelTypes[GeneralType].m_type = GeneralType; m_channelTypes[GeneralType].m_volume = ChannelType::s_sfxVolume; int remainder = Environment.soundChannels - channel_id; for (i=0; im_command) m_channels[i]->Stop(); delete m_channels[i]; m_channels[i] = NULL; } } Verify(m_channelTypes.GetLength() == TypeCount); for (i=0; iGetLocalToWorld(); Point3D ear_in_world(ear_to_world); UnitVector3D ear_foward_in_world; ear_to_world.GetLocalForwardInWorld(&ear_foward_in_world); UnitVector3D ear_up_in_world; ear_to_world.GetLocalUpInWorld(&ear_up_in_world); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_Position, -ear_in_world.x, ear_in_world.y, ear_in_world.z); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_FrontOrientation, -ear_foward_in_world.x, ear_foward_in_world.y, ear_foward_in_world.z); gosAudio_SetChannelSlider(gosAudio_Mixer, gosAudio_TopOrientation, -ear_up_in_world.x, ear_up_in_world.y, ear_up_in_world.z); // //---------------------------- // Execute the existing sounds //---------------------------- // { AUDIO_RENDER("Execute"); ChainIteratorOf commands(&m_executingCommands); AudioCommand *command; while ((command = commands.ReadAndNext()) != NULL) { Check_Object(command); AudioChannel *channel = command->m_channel; Check_Object(channel); channel->Execute(target_render_time); } } // //--------------------------- // Process the audio commands //--------------------------- // { AUDIO_RENDER("Execute::NewCommands"); ChainIteratorOf commands(&m_newCommands); AudioCommand *command; while ((command = commands.GetCurrent()) != NULL) { Check_Object(command); commands.Remove(); AudioSample *sample = m_sampleCache.Find(command->m_handleResourceID); Check_Object(sample); if (command->ConnectToChannel(sample)) { m_executingCommands.Add(command); command->m_minRestartDelay *= sample->m_sampleInfo.fDuration; command->m_minReplaceDelay *= sample->m_sampleInfo.fDuration; } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::FlushUnusedCache() { Check_Object(this); ChainIteratorOf oldies(&m_unusedSamples); AudioSample *sample; while ((sample = oldies.ReadAndNext()) != NULL && m_cacheSize > 0x200000) { Check_Object(sample); m_cacheSize -= sample->m_sampleInfo.dwSizeInBytes; delete sample; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Component* AudioRenderer::CreateComponent( ClassID component_class, MemoryStream *stream, RendererComponentWeb *rend_web, Entity *entity ) { AudioComponentWeb *web = Cast_Object(AudioComponentWeb*, rend_web); Component *component; switch (component_class) { case EarComponentClassID: component = EarComponent::Make(stream, rend_web); break; case AudioFXComponentClassID: component = AudioFXComponent::Make(stream, web); break; default: component = BaseClass::CreateComponent( component_class, stream, rend_web, entity ); break; } return component; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::EntityIsInteresting( Entity *entity, bool render_me) { Check_Object(this); Check_Object(entity); AUDIO_LOAD("EntityIsInteresting"); // //---------------------------------------------------------------------- // If this object already has a web, we just have to turn the web on/off //---------------------------------------------------------------------- // AudioComponentWeb *current_web = static_cast(entity->GetComponentWeb(rendererType)); if (current_web) { Check_Object(current_web); current_web->SetInterest(render_me); if (!render_me) return; } // //-------------------------------------- // Create a component web for the entity //-------------------------------------- // const ResourceID &resources = entity->GetRendererDataResourceID(rendererType); if (!resources || !render_me) return; gos_PushCurrentHeap(s_Heap); AudioComponentWeb* web = new AudioComponentWeb( AudioComponentWeb::DefaultData, entity, this, resources, NULL ); Check_Object(web); entity->SetComponentWeb(rendererType, web); // //------------------------------------------------- // Now, load up the web from the specified resource //------------------------------------------------- // Resource script(resources); web->LoadFromStream(&script); // //----------------------- // Execute the components //----------------------- // { AUDIO_LOAD("EntityIsInteresting::Execute"); web->ExecuteWatcherComponents(); } gos_PopCurrentHeap(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AudioRenderer::EntityIsUninteresting(Entity *entity) { }