//===========================================================================// // 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 "SpatializedCommand.hpp" #include "AudioRenderer.hpp" #include "SpatializedChannel.hpp" #include "AudioSample.hpp" #include "Interface.hpp" //########################################################################## //######################### SpatializedCommand ####################### //########################################################################## SpatializedCommand::ClassData* SpatializedCommand::DefaultData = NULL; MemoryBlock* SpatializedCommand::s_AllocatedMemory = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SpatializedCommand::InitializeClass( size_t block_count, size_t block_delta ) { Verify(!s_AllocatedMemory); s_AllocatedMemory = new MemoryBlock( sizeof(SpatializedCommand), block_count, block_delta, "SpatializedCommand", g_LibraryHeap ); Register_Object(s_AllocatedMemory); Verify(!DefaultData); DefaultData = new ClassData( SpatializedCommandClassID, "Adept::SpatializedCommand", BaseClass::DefaultData ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SpatializedCommand::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; Unregister_Object(s_AllocatedMemory); delete s_AllocatedMemory; s_AllocatedMemory = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SpatializedCommand::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SpatializedCommand* SpatializedCommand::Create( int type, const ResourceID &hint_ID, Stuff::Scalar priority, Stuff::Scalar volume, Stuff::Scalar min_restart, Stuff::Scalar min_replace, const Point3D &position, const Vector3D &velocity, Stuff::Scalar min_deviation, Stuff::Scalar near_clip, Stuff::Scalar min_range, Stuff::Scalar max_range, Stuff::Scalar far_clip ) { return new SpatializedCommand( DefaultData, type, hint_ID, priority, volume, min_restart, min_replace, position, velocity, min_deviation, near_clip, min_range, max_range, far_clip ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SpatializedCommand::SpatializedCommand( ClassData *class_data, int type, const ResourceID &sample_ID, Stuff::Scalar priority, Stuff::Scalar volume, Stuff::Scalar min_restart, Stuff::Scalar min_replace, const Point3D &position, const Vector3D &velocity, Stuff::Scalar min_deviation, Stuff::Scalar near_clip, Stuff::Scalar min_range, Stuff::Scalar max_range, Stuff::Scalar far_clip ): AudioCommand(class_data, type, sample_ID, priority, volume, min_restart, min_replace), m_position(position), m_velocity(velocity), m_minDeviation(min_deviation), m_nearClip(near_clip), m_minRange(min_range), m_maxRange(max_range), m_farClip(far_clip) { Check_Pointer(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SpatializedCommand::~SpatializedCommand() { Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool SpatializedCommand::ConnectToChannel(AudioSample *sample) { Check_Object(this); Check_Object(sample); AUDIO_RENDER("Execute::NewCommands::SpatializedCommand"); // //--------------------------- // Compute the command energy //--------------------------- // SpatializedChannel *candidate = NULL; Scalar energy = m_energy = ComputeEnergy(NULL); Time now = gos_GetElapsedTime(); // //----------------------------------------------------------------- // If we aren't going to loop, see if we can be immediately clipped //----------------------------------------------------------------- // if (m_bearing.rangem_farClip) { if (m_playMode == gosAudio_PlayOnce) delete this; return false; } // //---------------------------------------------------------------------------- // First look through the active channels to see if we can ignore this command //---------------------------------------------------------------------------- // ChainIteratorOf active_channels(&sample->m_activeChannels); AudioChannel *channel; if (m_playMode == gosAudio_PlayOnce) { while ((channel = active_channels.ReadAndNext()) != NULL) { SpatializedChannel *spatial = Cast_Object(SpatializedChannel*, channel); // //---------------------------------------------------------------------------------- // We now need to calculate the angles to the ear from the old site and the new one. // If the sound is too different from the one we are looking at, just go on to the // next sound //---------------------------------------------------------------------------------- // Scalar bear_diff = Fabs(spatial->m_bearing.yaw - m_bearing.yaw); SpatializedCommand *existing_command = Cast_Object(SpatializedCommand*, spatial->m_command); Check_Object(existing_command); if (bear_diff > existing_command->m_minDeviation) continue; // //----------------------------------------------- // If the existing sound could replace us, let it //----------------------------------------------- // Verify(m_playMode != gosAudio_Loop); if (channel->m_startTime + existing_command->m_minRestartDelay >= now) { delete this; return false; } // //------------------------------------------------------------------------------ // If we are not lower priority than the existing sound, check to see if it is a // candidate for replacement //------------------------------------------------------------------------------ // if (existing_command->m_priority >= m_priority) { if (channel->m_startTime + existing_command->m_minReplaceDelay <= now) { Scalar temp = channel->m_energy; if (temp <= energy) { candidate = spatial; energy = temp; } } } } } // //------------------------------------------------------ // Look for an inactive spatial hooked up to this sample //------------------------------------------------------ // ChainIteratorOf inactive_channels(&sample->m_inactiveChannels); if ((channel = inactive_channels.GetCurrent()) != NULL) { Verify(channel->m_playMode != gosAudio_Loop); channel->Activate(this); Verify(channel->m_startTime == now); return true; } // //------------------------------------------- // Replace the best candidate if there is one //------------------------------------------- // if (candidate) { Check_Object(candidate); Verify(candidate->m_playMode != gosAudio_Loop); candidate->Stop(); candidate->Activate(this); Verify(candidate->m_startTime == now); return true; } // //------------------------------------------------------------------------------------ // Now we search the inactive channel list for our sound type and use the earliest one //------------------------------------------------------------------------------------ // Check_Object(AudioRenderer::Instance); ChannelType &type = AudioRenderer::Instance->m_channelTypes[m_type]; ChainIteratorOf free_channels(&type.m_inactiveChannels); if ((channel = free_channels.GetCurrent()) != NULL) { Check_Object(channel); Verify(channel->m_playMode != gosAudio_Loop); channel->SetSample(sample); channel->Activate(this); Verify(channel->m_startTime == now); return true; } // //---------------------------------------------------------------------------------- // Now we search the active channel list for our sound type and use the earliest one // that also matches the playmode - loops steal loops and one-shots steal one-shots //---------------------------------------------------------------------------------- // ChainIteratorOf used_channels(&type.m_activeChannels); while ((channel = used_channels.ReadAndNext()) != NULL) { Check_Object(channel); if (channel->m_playMode == m_playMode) { channel->Stop(); Verify(channel->m_playMode != gosAudio_Loop); if (channel->m_sample != sample) channel->SetSample(sample); channel->Activate(this); Verify(channel->m_startTime == now); return true; } } // //---------------------------------------------------------------------------------- // Now we search the active channel list for our sound type and use the earliest one //---------------------------------------------------------------------------------- // used_channels.First(); channel = used_channels.GetCurrent(); Check_Object(channel); Verify(channel->m_playMode != gosAudio_Loop); channel->Stop(); if (channel->m_sample != sample) channel->SetSample(sample); channel->Activate(this); Verify(channel->m_startTime == now); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool SpatializedCommand::AddLoop() { Check_Object(this); // //------------------------------------------------- // Hook us up to the loop chain of our channel type //------------------------------------------------- // Check_Object(AudioRenderer::Instance); ChannelType &type = AudioRenderer::Instance->m_channelTypes[m_type]; type.m_loopCommands.Add(this); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Stuff::Scalar SpatializedCommand::ComputeEnergy(AudioChannel *channel) { Check_Object(this); // //---------------------------------------------------------------------------- // If we haven't been assigned a channel yet, only distance affects our energy //---------------------------------------------------------------------------- // Scalar energy = 0.0f; if (!channel) { LinearMatrix4D ear_to_world = AudioRenderer::Instance->GetInterface()->GetLocalToWorld(); Point3D ear_in_world(ear_to_world); Vector3D ear_to_command; ear_to_command.Subtract(m_position, ear_in_world); m_bearing = ear_to_command; Scalar energy = 0.0f; if (m_bearing.range >= m_nearClip && m_bearing.range <= m_farClip) { if (m_bearing.range >= m_minRange) { if (m_bearing.range >= m_maxRange) energy = 1.0f; else energy = (m_maxRange - m_minRange - m_bearing.range) / (m_maxRange - m_minRange); } } return energy; } // //---------------------------------------------------------------- // Otherwise, our energy decreases over the lifetime of the sample //---------------------------------------------------------------- // SpatializedChannel *spatial = Cast_Object(SpatializedChannel*, channel); m_bearing = spatial->m_bearing; if (m_bearing.range >= m_nearClip && m_bearing.range <= m_farClip) { if (m_bearing.range >= m_minRange) { if (m_bearing.range >= m_maxRange) energy = 1.0f; else energy = (m_maxRange - m_minRange - m_bearing.range) / (m_maxRange - m_minRange); } } AudioSample *sample = spatial->m_sample; Check_Object(sample); energy *= 1.0f - (static_cast(gos_GetElapsedTime() - channel->m_startTime)/sample->m_sampleInfo.fDuration); return energy; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SpatializedCommand::SetPosition(const Point3D &position) { Check_Object(this); m_position = position; if (m_channel) { SpatializedChannel *channel = Cast_Object(SpatializedChannel*, m_channel); channel->SetPosition(position); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SpatializedCommand::SetVelocity(const Vector3D &velocity) { Check_Object(this); m_velocity = velocity; if (m_channel) { SpatializedChannel *channel = Cast_Object(SpatializedChannel*, m_channel); channel->SetVelocity(velocity); } }