/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : WWAudio * * * * $Archive:: /Commando/Code/WWAudio/AudibleSound.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 12/14/01 11:20a $* * * * $Revision:: 35 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "audiblesound.h" #include "wwaudio.h" #include "ww3d.h" #include "wwdebug.h" #include "soundbuffer.h" #include "utils.h" #include "soundscene.h" #include "filteredsound.h" #include "threads.h" #include "soundchunkids.h" #include "simpledefinitionfactory.h" #include "persistfactory.h" #include "logicalsound.h" #include "definitionclassids.h" #include "soundstreamhandle.h" #include "sound2dhandle.h" #include "systimer.h" ////////////////////////////////////////////////////////////////////////////////// // Static factories ////////////////////////////////////////////////////////////////////////////////// DECLARE_DEFINITION_FACTORY(AudibleSoundDefinitionClass, CLASSID_SOUND_DEF, "Sound") _SoundDefFactory; SimplePersistFactoryClass _AudibleSoundDefPersistFactory; SimplePersistFactoryClass _AudibleSoundPersistFactory; ////////////////////////////////////////////////////////////////////////////////// // Save/Load constants ////////////////////////////////////////////////////////////////////////////////// namespace AUDIBLE_SOUND_SAVELOAD { enum { CHUNKID_VARIABLES = 0x00000100, CHUNKID_BASE_CLASS }; enum { VARID_STATE = 0x01, VARID_TYPE, VARID_PRIORITY, VARID_VOLUME, VARID_PAN, VARID_LOOP_COUNT, VARID_LOOPS_LEFT, VARID_SOUND_LENGTH, VARID_CURR_POS, VARID_TRANSFORM, VARID_PREV_TRANSFORM, VARID_IS_CULLED, VARID_IS_DIRTY, VARID_DROP_OFF, VARID_FILENAME, VARID_THIS_PTR, VARID_START_OFFSET, VARID_LISTENER_TRANSFORM, VARID_PITCH_FACTOR, VARID_PITCH_FACTOR_RND, VARID_VOLUME_RND, VARID_VIRTUAL_CHANNEL }; } namespace AUDIBLE_SOUND_DEF_SAVELOAD { enum { CHUNKID_VARIABLES = 0x00000100, CHUNKID_BASE_CLASS = 0x00000200, }; enum { VARID_UNUSED1 = 0x01, VARID_UNUSED2, VARID_PRIORITY, VARID_VOLUME, VARID_PAN, VARID_LOOP_COUNT, VARID_DROP_OFF, VARID_MAX_VOL, VARID_TYPE, VARID_IS3D, VARID_FILENAME, VARID_DISPLAY_TEXT, VARID_LOGICAL_MASK, VARID_LOGICAL_DELAY, VARID_CREATE_LOGICAL, VARID_LOGICAL_DROP_OFF, VARID_SPHERE_COLOR, VARID_START_OFFSET, VARID_PITCH_FACTOR, VARID_PITCH_FACTOR_RND, VARID_VOLUME_RND, VARID_VIRTUAL_CHANNEL }; } //////////////////////////////////////////////////////////////////////////////////////////////// // // AudibleSoundClass // //////////////////////////////////////////////////////////////////////////////////////////////// AudibleSoundClass::AudibleSoundClass (void) : m_Priority (0.5F), m_RuntimePriority (0), m_SoundHandle (NULL), m_Length (0), m_CurrentPosition (0), m_Timestamp (0), m_State (STATE_STOPPED), m_Buffer (NULL), m_Volume (1.0F), m_RealVolume (1.0F), m_Pan (0.5F), m_LoopCount (1), m_LoopsLeft (0), m_Type (TYPE_SOUND_EFFECT), m_FadeType (FADE_NONE), m_FadeTimer (0), m_FadeTime (0), m_VirtualChannel (0), m_bDirty (true), m_DropOffRadius (1), m_IsCulled (true), m_pConvertedFormat (NULL), m_PrevTransform (1), m_Transform (1), m_ListenerTransform (1), m_Definition (NULL), m_LogicalSound (NULL), m_StartOffset (0), m_PitchFactor (1.0F) { return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // AudibleSoundClass // //////////////////////////////////////////////////////////////////////////////////////////////// AudibleSoundClass::AudibleSoundClass (const AudibleSoundClass &src) : m_Priority (0.5F), m_RuntimePriority (0), m_SoundHandle (NULL), m_Length (0), m_CurrentPosition (0), m_Timestamp (0), m_State (STATE_STOPPED), m_Buffer (NULL), m_Volume (1.0F), m_RealVolume (1.0F), m_Pan (0.5F), m_LoopCount (1), m_LoopsLeft (0), m_Type (TYPE_SOUND_EFFECT), m_FadeType (FADE_NONE), m_FadeTimer (0), m_FadeTime (0), m_VirtualChannel (0), m_bDirty (true), m_DropOffRadius (1), m_IsCulled (true), m_pConvertedFormat (NULL), m_PrevTransform (1), m_Transform (1), m_Definition (NULL), m_LogicalSound (NULL), m_StartOffset (0), m_PitchFactor (1.0F) { (*this) = src; return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // ~AudibleSoundClass // //////////////////////////////////////////////////////////////////////////////////////////////// AudibleSoundClass::~AudibleSoundClass (void) { m_State = STATE_STOPPED; Free_Conversion (); REF_PTR_RELEASE (m_LogicalSound); // // Delay the release of the buffer (fixes a sync bug // with Miles internals). // if (m_Buffer != NULL) { WWAudioThreadsClass::Add_Delayed_Release_Object (m_Buffer); //REF_PTR_RELEASE (m_Buffer); m_Buffer = NULL; } Free_Miles_Handle (); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // operator= // //////////////////////////////////////////////////////////////////////////////////////////////// const AudibleSoundClass & AudibleSoundClass::operator= (const AudibleSoundClass &src) { m_Timestamp = src.m_Timestamp; m_Type = src.m_Type; m_FadeType = src.m_FadeType; m_FadeTimer = src.m_FadeTimer; m_FadeTime = src.m_FadeTime; m_VirtualChannel = src.m_VirtualChannel; m_LoopCount = src.m_LoopCount; m_LoopsLeft = src.m_LoopsLeft; m_Length = src.m_Length; m_CurrentPosition = src.m_CurrentPosition; m_bDirty = src.m_bDirty; m_DropOffRadius = src.m_DropOffRadius; m_PrevTransform = src.m_PrevTransform; m_RealVolume = src.m_RealVolume; m_State = STATE_STOPPED; Set_Buffer (src.m_Buffer); m_State = src.m_State; Cull_Sound (src.m_IsCulled); Set_Volume (src.m_RealVolume); Set_Pan (src.m_Pan); Set_Priority (src.m_Priority); Set_Transform (src.m_Transform); Set_Listener_Transform (src.m_ListenerTransform); return (*this); } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Buffer // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Buffer (SoundBufferClass *buffer) { // // Delay the release of the buffer (fixes a sync bug // with Miles internals). // if (m_Buffer != NULL) { WWAudioThreadsClass::Add_Delayed_Release_Object (m_Buffer); //REF_PTR_RELEASE (m_Buffer); m_Buffer = NULL; } REF_PTR_SET (m_Buffer, buffer); // Stop playing if necessary bool resume = false; if (m_State == STATE_PLAYING) { resume = Stop (false); } // Get the time (in ms) that this buffer will play for... if (m_Buffer != NULL) { m_Length = m_Buffer->Get_Duration (); } // Reinitialize the handle with this new data Initialize_Miles_Handle (); // Resume playing if necessary if (resume) { Play (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Buffer // //////////////////////////////////////////////////////////////////////////////////////////////// SoundBufferClass * AudibleSoundClass::Get_Buffer (void) const { if (m_Buffer) { m_Buffer->Add_Ref (); } return m_Buffer; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Peek_Buffer // //////////////////////////////////////////////////////////////////////////////////////////////// SoundBufferClass * AudibleSoundClass::Peek_Buffer (void) const { return m_Buffer; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Update_Fade // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Update_Fade (void) { m_FadeTimer -= WW3D::Get_Frame_Time (); m_FadeTimer = max (m_FadeTimer, 0); // // Determine what percent we should ramp up or down to... // float percent = ((float)m_FadeTimer / (float)m_FadeTime); percent = WWMath::Clamp (percent, 0.0F, 1.0F); // // Invert the percent if we're fading in // if (m_FadeType == FADE_IN) { percent = 1.0F - percent; } // // Re-adjust the music and sound effect volumes // Internal_Set_Volume (m_RealVolume * percent); // // Reset the state as necessary // if (m_FadeTimer == 0) { // // Stop the sound when its done fading out // if (m_FadeType == FADE_OUT) { Stop (); } m_FadeType = FADE_NONE; } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Fade_Out // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Fade_Out (int time_in_ms) { m_FadeTime = time_in_ms; m_FadeTimer = time_in_ms; m_FadeType = FADE_OUT; return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Fade_In // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Fade_In (int time_in_ms) { m_FadeTime = time_in_ms; m_FadeTimer = time_in_ms; m_FadeType = FADE_IN; // // Turn off the volume // Internal_Set_Volume (0.0F); // // Start the sample playing // Play (); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Verify_Playability // //////////////////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Verify_Playability (void) { bool retval = true; if (m_VirtualChannel != 0) { retval = WWAudioClass::Get_Instance ()->Acquire_Virtual_Channel (this, m_VirtualChannel); } return retval; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Play // //////////////////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Play (bool alloc_handle) { MMSLockClass lock; // // Check to ensure this sound should really be playing... // if (Verify_Playability () == false) { return false; } // // If we don't have a valid handle already, try to get one from miles // if (alloc_handle && (m_pConvertedFormat == NULL)) { Allocate_Miles_Handle (); } // // Is the sound already playing? // if (m_State != STATE_PLAYING) { // // Let the audio system know this sound is playing // WWAudioClass::Get_Instance ()->Add_To_Playlist (this); m_State = STATE_PLAYING; m_Timestamp = TIMEGETTIME (); m_LoopsLeft = m_LoopCount; // If we have a valid handle, then start playing the sample if (m_SoundHandle != NULL) { m_SoundHandle->Start_Sample (); } m_CurrentPosition = m_StartOffset * m_Length; if (m_CurrentPosition > 0) { Seek (m_CurrentPosition); } // Fire an event On_Event (AudioCallbackClass::EVENT_SOUND_STARTED); // // Create the associate logical sound (if necessary) // if (m_LogicalSound == NULL && m_Definition != NULL) { m_LogicalSound = m_Definition->Create_Logical (); } // // Add this logical sound to the scene // if (m_LogicalSound != NULL) { m_LogicalSound->Set_User_Data (m_UserObj, m_UserData); m_LogicalSound->Set_Transform (m_Transform); m_LogicalSound->Add_To_Scene (); } // // Should we send off the text notification? // if (m_IsCulled == false && m_Definition != NULL) { const StringClass &text = m_Definition->Get_Display_Text (); WWAudioClass::Get_Instance ()->Fire_Text_Callback (this, text); } } return true; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Pause // //////////////////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Pause (void) { MMSLockClass lock; bool retval = false; if (m_State == STATE_PLAYING) { // // Update our current position so we can resume at the correct // location // m_CurrentPosition = TIMEGETTIME () - m_Timestamp; // // Get rid of our play-handle (this will stop the sound) // Free_Miles_Handle (); // // Remember our new state // m_State = STATE_PAUSED; retval = true; } // Return the true/false result code return retval; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Resume // //////////////////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Resume (void) { MMSLockClass lock; bool retval = false; if (m_State == STATE_PAUSED) { // // Re-sync our timestamp // m_Timestamp = TIMEGETTIME () - m_CurrentPosition; // // Ensure we have a play handle... // Allocate_Miles_Handle (); // // If we have a valid handle, then start playing the sample // if (m_SoundHandle != NULL) { m_SoundHandle->Start_Sample (); } // // Re-seek to the correct position in the sound // if (m_CurrentPosition > 0) { Seek (m_CurrentPosition); } // // Remember our new state // m_State = STATE_PLAYING; retval = true; } // Return the true/false result code return retval; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Stop // //////////////////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Stop (bool remove_from_playlist) { MMSLockClass lock; // Assume failure bool retval = false; if ((m_State == STATE_PAUSED) || (m_State == STATE_PLAYING)) { // // Actually stop the sample from playing // if (m_SoundHandle != NULL) { m_SoundHandle->Stop_Sample (); } // // Free up the handle we have been using // Free_Miles_Handle (); m_State = STATE_STOPPED; retval = true; // // Reset some of the playing attributes // m_Timestamp = 0; m_CurrentPosition = 0; // // Remove the sound from the current playlist // if (remove_from_playlist) { WWAudioClass::Get_Instance ()->Remove_From_Playlist (this); } // // Release the virtual channel as necessary // if (m_VirtualChannel > 0) { WWAudioClass::Get_Instance ()->Release_Virtual_Channel (this, m_VirtualChannel); } // // Stop the logical portion of the sound // if (m_LogicalSound != NULL && m_LogicalSound->Is_Single_Shot () == false) { m_LogicalSound->Remove_From_Scene (); } } // Return the true/false result code return retval; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Seek // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Seek (unsigned long milliseconds) { MMSLockClass lock; if ((milliseconds >= 0) && (milliseconds < m_Length)) { // Record our new position and recalculate the 'starting' timestamp // from this information m_CurrentPosition = milliseconds; if (m_State == STATE_PLAYING) { m_Timestamp = TIMEGETTIME () - m_CurrentPosition; } // Update the actual sound data if we are playing the sound if (m_SoundHandle != NULL) { m_SoundHandle->Set_Sample_MS_Position (m_CurrentPosition); } } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Miles_Handle // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Miles_Handle (MILES_HANDLE handle) { // // Start fresh // Free_Miles_Handle (); // // Is our data valid? // if (handle != INVALID_MILES_HANDLE && m_Buffer != NULL) { // // Determine which type of sound handle to create, streaming or standard 2D // if (m_Buffer->Is_Streaming ()) { m_SoundHandle = new SoundStreamHandleClass; } else { m_SoundHandle = new Sound2DHandleClass; } // // Configure the sound handle // m_SoundHandle->Set_Miles_Handle (handle); // // Use this new handle // Initialize_Miles_Handle (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Initialize_Miles_Handle // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Initialize_Miles_Handle (void) { MMSLockClass lock; // If this sound is already playing, then update its // playing position to make sure we really should // be playing it... (it will free the miles handle if not) if (m_State == STATE_PLAYING) { Update_Play_Position (); } // Do we have a valid sample handle from miles? if (m_SoundHandle != NULL) { // // Initialize the handle // m_SoundHandle->Initialize (m_Buffer); // // Record the total length of the sample in milliseconds... // m_SoundHandle->Get_Sample_MS_Position ((S32 *)&m_Length, NULL); // // Pass our cached settings onto miles // m_SoundHandle->Set_Sample_Volume (0); m_SoundHandle->Set_Sample_Pan (int(m_Pan * 127.0F)); m_SoundHandle->Set_Sample_Loop_Count (m_LoopCount); // // Apply the pitch factor (if necessary) // if (m_PitchFactor != 1.0F) { Set_Pitch_Factor (m_PitchFactor); } // If this sound is already playing (and just now got a handle) // then make sure we start it. if (m_State == STATE_PLAYING) { m_SoundHandle->Start_Sample (); // Update the loop count based on the number of loops left m_SoundHandle->Set_Sample_Loop_Count (m_LoopsLeft); } // Seek to the position of the sound where we last left off. // For example, this sound could have gotten bumped due to a low priority, // but is now back and ready to resume at the position it would have been // at if it was never bumped. Seek (m_CurrentPosition); // // Pass the 'real' volume onto miles // float real_volume = Determine_Real_Volume (); m_SoundHandle->Set_Sample_Volume (int(real_volume * 127.0F)); // // Associate this object instance with the handle // m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, (S32)this); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Free_Miles_Handle // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Free_Miles_Handle (void) { MMSLockClass lock; // Do we have a valid sample handle from miles? if (m_SoundHandle != NULL) { // // Release our hold on this handle // m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, NULL); m_SoundHandle->End_Sample (); // // Remove the association between file handle and AudibleSoundClass object // //m_SoundHandle->Set_Sample_User_Data (INFO_OBJECT_PTR, NULL); // // Free the sound handle object // delete m_SoundHandle; m_SoundHandle = NULL; } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Pan // //////////////////////////////////////////////////////////////////////////////////////////////// float AudibleSoundClass::Get_Pan (void) { MMSLockClass lock; // // Do we have a valid sample handle from miles? // if (m_SoundHandle != NULL) { m_Pan = ((float)m_SoundHandle->Get_Sample_Pan ()) / 127.0F; } return m_Pan; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Pan // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Pan (float pan) { MMSLockClass lock; // // Cache the normalized pan value // m_Pan = min (pan, 1.0F); m_Pan = max (m_Pan, 0.0F); // // Do we have a valid sample handle from miles? // if (m_SoundHandle != NULL) { m_SoundHandle->Set_Sample_Pan (int(m_Pan * 127.0F)); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Pitch_Factor // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Pitch_Factor (float factor) { MMSLockClass lock; m_PitchFactor = factor; // // Do we have a valid sample handle from miles? // if (m_SoundHandle != NULL) { if (m_Buffer != NULL) { // // Get the base rate of the sound and scale our playback rate // based on the factor // int base_rate = m_Buffer->Get_Rate (); int new_rate = base_rate * m_PitchFactor; m_SoundHandle->Set_Sample_Playback_Rate (new_rate); } } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Playback_Rate // //////////////////////////////////////////////////////////////////////////////////////////////// int AudibleSoundClass::Get_Playback_Rate (void) { MMSLockClass lock; int retval = 0; // Do we have a valid sample handle from miles? if (m_SoundHandle != NULL) { retval = m_SoundHandle->Get_Sample_Playback_Rate (); } return retval; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Playback_Rate // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Playback_Rate (int rate_in_hz) { MMSLockClass lock; // Do we have a valid sample handle from miles? if (m_SoundHandle != NULL) { m_SoundHandle->Set_Sample_Playback_Rate (rate_in_hz); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Volume // //////////////////////////////////////////////////////////////////////////////////////////////// float AudibleSoundClass::Get_Volume (void) { MMSLockClass lock; // Do we have a valid sample handle from miles? if (m_SoundHandle != NULL) { m_Volume = ((float)m_SoundHandle->Get_Sample_Volume ()) / 127.0F; } // Return the current pan value return m_Volume; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Internal_Set_Volume // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Internal_Set_Volume (float volume) { MMSLockClass lock; // // Cache the normalized volume value // m_Volume = min (volume, 1.0F); m_Volume = max (m_Volume, 0.0F); // // Do we have a valid sample handle from miles? // if (m_SoundHandle != NULL) { // // Calculate the 'real' volume to set based on the global volume and the sound // effect volume. // float real_volume = Determine_Real_Volume (); m_SoundHandle->Set_Sample_Volume (int(real_volume * 127.0F)); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Volume // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Volume (float volume) { MMSLockClass lock; // // Cache the normalized volume value // m_RealVolume = min (volume, 1.0F); m_RealVolume = max (m_RealVolume, 0.0F); // // Update the volume // Internal_Set_Volume (m_RealVolume); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Loops_Left // //////////////////////////////////////////////////////////////////////////////////////////////// int AudibleSoundClass::Get_Loops_Left (void) const { return m_LoopsLeft; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Loop_Count // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Loop_Count (int count) { MMSLockClass lock; // Cache the loop count m_LoopCount = count; // Do we have a valid sample handle from miles? if (m_SoundHandle != NULL) { m_SoundHandle->Set_Sample_Loop_Count (m_LoopCount); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Priority // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Priority (float priority) { MMSLockClass lock; // Cache the normalized priority m_Priority = min (priority, 1.0F); m_Priority = max (m_Priority, 0.0F); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // On_Frame_Update // //////////////////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::On_Frame_Update (unsigned int milliseconds) { // // Do we need to track this sound's play-progress? // if ((m_LoopCount != INFINITE_LOOPS) && (m_State == STATE_PLAYING) && (m_Length > 0)) { Update_Play_Position (); } // // Update the fade as necessary // if (m_FadeType != FADE_NONE) { Update_Fade (); } if (m_pConvertedFormat != NULL) { m_pConvertedFormat->Re_Sync (*this); } // // Move the logical sound with the audible one... // if (m_LogicalSound != NULL) { m_LogicalSound->Set_Transform (m_Transform); } return true; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Update_Play_Position // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Update_Play_Position (void) { // Determine the current offset from the beginning of the sound buffer. unsigned long play_time = TIMEGETTIME () - m_Timestamp; m_CurrentPosition = play_time; // Have we gone past the end of a sounds play-time? if ((m_CurrentPosition > m_Length) && (m_Length > 0)) { // Normalize our position and timestamp information m_CurrentPosition = m_CurrentPosition % m_Length; m_Timestamp = TIMEGETTIME () - m_CurrentPosition; // Decrement our count of remaining loops (if necessary) if (m_LoopCount != INFINITE_LOOPS) { m_LoopsLeft -= (play_time / m_Length); } // Trigger the 'end loop' event On_Loop_End (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Allocate_Miles_Handle // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Allocate_Miles_Handle (void) { // // If we need to, get a play-handle from the audio system // if (m_SoundHandle == NULL) { Set_Miles_Handle ((MILES_HANDLE)WWAudioClass::Get_Instance ()->Get_2D_Sample (*this)); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // On_Loop_End // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::On_Loop_End (void) { // Determine if the sound is actually finished or still looping if ((m_LoopCount != INFINITE_LOOPS) && (m_LoopsLeft < 1)) { // Let the audio system know that we are done with this sound Stop (); if (m_Scene != NULL) { Remove_From_Scene (); } // Fire an event On_Event (AudioCallbackClass::EVENT_SOUND_ENDED); } else { Restart_Loop (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Determine_Real_Volume // //////////////////////////////////////////////////////////////////////////////////////////////// float AudibleSoundClass::Determine_Real_Volume (void) const { float volume = m_Volume; // Is this a piece of music or is it a sound effect? if (m_Type == TYPE_MUSIC) { volume = volume * WWAudioClass::Get_Instance ()->Get_Music_Volume (); } else if (m_Type == TYPE_SOUND_EFFECT) { volume = volume * WWAudioClass::Get_Instance ()->Get_Sound_Effects_Volume (); } else if (m_Type == TYPE_DIALOG) { volume = volume * WWAudioClass::Get_Instance ()->Get_Dialog_Volume (); } else if (m_Type == TYPE_CINEMATIC) { volume = volume * WWAudioClass::Get_Instance ()->Get_Cinematic_Volume (); } // Return the 'real' volume return volume; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Filename // //////////////////////////////////////////////////////////////////////////////////////////////// LPCTSTR AudibleSoundClass::Get_Filename (void) const { LPCTSTR filename = NULL; if (m_Buffer != NULL) { filename = m_Buffer->Get_Filename (); } return filename; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Cull_Sound // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Cull_Sound (bool culled) { // Is our state changing? if (m_IsCulled != culled) { m_IsCulled = culled; // // If this sound is culled, then throw away its play-handle. // Otherwise, make sure we have a valid handle. // // Note: We also free the handle if a converted form // of the sound is currently playing. // if (m_IsCulled || (m_pConvertedFormat != NULL)) { Free_Miles_Handle (); } else { Allocate_Miles_Handle (); } } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Transform // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Transform (const Matrix3D &transform) { // Update our internal transform m_PrevTransform = m_Transform; m_Transform = transform; Set_Dirty (); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_Position // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_Position (const Vector3 &position) { // Update our internal transform m_Transform.Set_Translation (position); Set_Dirty (); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Add_To_Scene // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Add_To_Scene (bool start_playing) { SoundSceneClass *scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene (); if ((scene != NULL) && (m_Scene == NULL)) { // // Add this sound to the static culling system // m_Scene = scene; scene->Add_Static_Sound (this, start_playing); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Remove_From_Scene // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Remove_From_Scene (void) { if (m_Scene != NULL) { // // Remove this sound from the static culling system // m_Scene->Remove_Static_Sound (this); m_Scene = NULL; m_PhysWrapper = NULL; } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Set_DropOff_Radius // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Set_DropOff_Radius (float radius) { m_DropOffRadius = radius; Set_Dirty (); return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Re_Sync // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Re_Sync (AudibleSoundClass &src) { m_Timestamp = src.m_Timestamp; m_State = src.m_State; m_Type = src.m_Type; m_FadeType = src.m_FadeType; m_FadeTimer = src.m_FadeTimer; m_FadeTime = src.m_FadeTime; m_VirtualChannel = src.m_VirtualChannel; m_LoopCount = src.m_LoopCount; m_LoopsLeft = src.m_LoopsLeft; m_Length = src.m_Length; m_CurrentPosition = src.m_CurrentPosition; m_bDirty = src.m_bDirty; m_DropOffRadius = src.m_DropOffRadius; m_PrevTransform = src.m_PrevTransform; Cull_Sound (src.m_IsCulled); Set_Volume (src.m_RealVolume); Set_Pan (src.m_Pan); Set_Priority (src.m_Priority); Set_Transform (src.m_Transform); Set_Listener_Transform (src.m_ListenerTransform); if (m_State != STATE_PLAYING) { Free_Miles_Handle (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Free_Conversion // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Free_Conversion (void) { if (m_pConvertedFormat != NULL) { m_pConvertedFormat->Stop (); REF_PTR_RELEASE (m_pConvertedFormat); } // // Reacquire a play-handle if necessary // if ((m_IsCulled == false) && (m_State == STATE_PLAYING)) { Allocate_Miles_Handle (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Convert_To_Filtered // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundClass::Convert_To_Filtered (void) { if (m_pConvertedFormat == NULL) { // // Make a copy of the sound in its new format // m_pConvertedFormat = new FilteredSoundClass; switch (Get_Class_ID ()) { case CLASSID_3D: (*m_pConvertedFormat) = (const Sound3DClass &)(*this); break; case CLASSID_PSEUDO3D: (*m_pConvertedFormat) = (const SoundPseudo3DClass &)(*this); break; case CLASSID_FILTERED: (*m_pConvertedFormat) = (const FilteredSoundClass &)(*this); break; default: (*m_pConvertedFormat) = (*this); break; } Free_Miles_Handle (); } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // As_Converted_Format // //////////////////////////////////////////////////////////////////////////////////////////////// AudibleSoundClass * AudibleSoundClass::As_Converted_Format (void) { if (m_pConvertedFormat == NULL) { Convert_To_Filtered (); } return m_pConvertedFormat; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Factory // //////////////////////////////////////////////////////////////////////////////////////////////// const PersistFactoryClass & AudibleSoundClass::Get_Factory (void) const { return _AudibleSoundPersistFactory; } //************************************************************************************************ //* //* Start of AudibleSoundDefinitionClass //* //************************************************************************************************ //////////////////////////////////////////////////////////////////////////////////////////////// // // AudibleSoundDefinitionClass // //////////////////////////////////////////////////////////////////////////////////////////////// AudibleSoundDefinitionClass::AudibleSoundDefinitionClass (void) : m_Priority (0.5F), m_Volume (1.0F), m_Pan (0.5F), m_LoopCount (1), m_DropOffRadius (40.0F), m_LogicalDropOffRadius (-1.0F), m_MaxVolRadius (20.0F), m_Is3D (true), m_Type (AudibleSoundClass::TYPE_SOUND_EFFECT), m_LogicalTypeMask (0), m_LogicalNotifyDelay (2), m_CreateLogical (false), m_AttenuationSphereColor (0, 0.75F, 0.75F), m_StartOffset (0), m_PitchFactor (1.0F), m_PitchFactorRandomizer (0.0F), m_VolumeRandomizer (0.0F), m_VirtualChannel (0) { // // Audible sound params // NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_SOUND_FILENAME, m_Filename, "Filename"); INT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_VirtualChannel, 0, 100); NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_DropOffRadius, "Drop-off Radius"); NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_MaxVolRadius, "Max-Vol Radius"); NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_BOOL, m_Is3D, "Is 3D Sound"); INT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_LoopCount, 0, 1000000); FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_Volume, 0, 1.0F); NAMED_FLOAT_UNITS_PARAM (AudibleSoundDefinitionClass, m_VolumeRandomizer, 0, 1.0F, "", "Volume Random (+/-)"); FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_Pan, 0, 1.0F); FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_Priority, 0, 1.0F); ENUM_PARAM (AudibleSoundDefinitionClass, m_Type, ( "Sound Effect", AudibleSoundClass::TYPE_SOUND_EFFECT, "Music", AudibleSoundClass::TYPE_MUSIC, "Dialog", AudibleSoundClass::TYPE_DIALOG, "Cinematic", AudibleSoundClass::TYPE_CINEMATIC, 0)); FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_StartOffset, 0, 1.0F); FLOAT_EDITABLE_PARAM (AudibleSoundDefinitionClass, m_PitchFactor, 0, 1.0F); NAMED_FLOAT_UNITS_PARAM (AudibleSoundDefinitionClass, m_PitchFactorRandomizer, 0, 1.0F, "", "Pitch Factor Random (+/-)"); NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_STRING, m_DisplayText, "Display Text"); // // Logical sound params // NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_BOOL, m_CreateLogical, "Create Logical Sound"); NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_LogicalDropOffRadius, "Logical Drop-off Radius"); NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_FLOAT, m_LogicalNotifyDelay, "Logical Notif Delay"); #ifdef PARAM_EDITING_ON // // Configure the logical type mask enumeration // EnumParameterClass *param = new EnumParameterClass (&m_LogicalTypeMask); param->Set_Name ("Logical Type"); int count = WWAudioClass::Get_Instance ()->Get_Logical_Type_Count (); for (int index = 0; index < count; index ++) { StringClass display_name(0,true); int id = WWAudioClass::Get_Instance ()->Get_Logical_Type (index, display_name); param->Add_Value (display_name, id); } GENERIC_EDITABLE_PARAM(AudibleSoundDefinitionClass, param); #endif NAMED_EDITABLE_PARAM (AudibleSoundDefinitionClass, ParameterClass::TYPE_COLOR, m_AttenuationSphereColor, "Sphere Color"); return ; } // SKB: Put here because of conficts with CLASSID_???? with other projects. uint32 AudibleSoundDefinitionClass::Get_Class_ID (void) const { return CLASSID_SOUND; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Initialize_From_Sound // //////////////////////////////////////////////////////////////////////////////////////////////// void AudibleSoundDefinitionClass::Initialize_From_Sound (AudibleSoundClass *sound) { // // Read the settings from the sound object // if (sound != NULL) { Sound3DClass *sound_3d = sound->As_Sound3DClass (); // // Choose defaults for the values that we can't get from // the sound. // m_LogicalDropOffRadius = -1.0F; m_LogicalNotifyDelay = 2; m_LogicalTypeMask = 0; m_CreateLogical = false; m_Pan = 0.5F; m_DisplayText = ""; // // Copy the values that we can from the sound object // m_Filename = sound->Get_Filename (); m_DropOffRadius = sound->Get_DropOff_Radius (); m_Priority = sound->Peek_Priority (); m_Is3D = (sound_3d != NULL); m_Type = sound->Get_Type (); m_LoopCount = sound->Get_Loop_Count (); m_Volume = sound->Get_Volume (); m_StartOffset = sound->Get_Start_Offset (); m_PitchFactor = sound->Get_Pitch_Factor (); m_VirtualChannel = sound->Get_Virtual_Channel (); if (sound_3d != NULL) { m_MaxVolRadius = sound_3d->Get_Max_Vol_Radius (); } } return ; } //////////////////////////////////////////////////////////////////////////////////////////////// // // Get_Factory // //////////////////////////////////////////////////////////////////////////////////////////////// const PersistFactoryClass & AudibleSoundDefinitionClass::Get_Factory (void) const { return _AudibleSoundDefPersistFactory; } ////////////////////////////////////////////////////////////////////////////////// // // Save // ////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundDefinitionClass::Save (ChunkSaveClass &csave) { using namespace AUDIBLE_SOUND_DEF_SAVELOAD; bool retval = true; csave.Begin_Chunk (CHUNKID_VARIABLES); retval &= Save_Variables (csave); csave.End_Chunk (); csave.Begin_Chunk (CHUNKID_BASE_CLASS); retval &= DefinitionClass::Save (csave); csave.End_Chunk (); return retval; } ////////////////////////////////////////////////////////////////////////////////// // // Load // ////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundDefinitionClass::Load (ChunkLoadClass &cload) { using namespace AUDIBLE_SOUND_DEF_SAVELOAD; bool retval = true; while (cload.Open_Chunk ()) { switch (cload.Cur_Chunk_ID ()) { case CHUNKID_VARIABLES: retval &= Load_Variables (cload); break; case CHUNKID_BASE_CLASS: retval &= DefinitionClass::Load (cload); break; } cload.Close_Chunk (); } return retval; } ////////////////////////////////////////////////////////////////////////////////// // // Save_Variables // ////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundDefinitionClass::Save_Variables (ChunkSaveClass &csave) { using namespace AUDIBLE_SOUND_DEF_SAVELOAD; // // Save the audible variables // WRITE_MICRO_CHUNK (csave, VARID_PRIORITY, m_Priority) WRITE_MICRO_CHUNK (csave, VARID_VOLUME, m_Volume) WRITE_MICRO_CHUNK (csave, VARID_PAN, m_Pan) WRITE_MICRO_CHUNK (csave, VARID_LOOP_COUNT, m_LoopCount) WRITE_MICRO_CHUNK (csave, VARID_DROP_OFF, m_DropOffRadius) WRITE_MICRO_CHUNK (csave, VARID_MAX_VOL, m_MaxVolRadius) WRITE_MICRO_CHUNK (csave, VARID_TYPE, m_Type) WRITE_MICRO_CHUNK (csave, VARID_IS3D, m_Is3D) WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_FILENAME, m_Filename) WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_DISPLAY_TEXT, m_DisplayText) WRITE_MICRO_CHUNK (csave, VARID_START_OFFSET, m_StartOffset); WRITE_MICRO_CHUNK (csave, VARID_PITCH_FACTOR, m_PitchFactor); WRITE_MICRO_CHUNK (csave, VARID_PITCH_FACTOR_RND, m_PitchFactorRandomizer); WRITE_MICRO_CHUNK (csave, VARID_VOLUME_RND, m_VolumeRandomizer); WRITE_MICRO_CHUNK (csave, VARID_VIRTUAL_CHANNEL, m_VirtualChannel); // // Save the logical variables // WRITE_MICRO_CHUNK (csave, VARID_LOGICAL_MASK, m_LogicalTypeMask) WRITE_MICRO_CHUNK (csave, VARID_LOGICAL_DELAY, m_LogicalNotifyDelay) WRITE_MICRO_CHUNK (csave, VARID_CREATE_LOGICAL, m_CreateLogical) WRITE_MICRO_CHUNK (csave, VARID_LOGICAL_DROP_OFF, m_LogicalDropOffRadius) WRITE_MICRO_CHUNK (csave, VARID_SPHERE_COLOR, m_AttenuationSphereColor) return true; } ////////////////////////////////////////////////////////////////////////////////// // // Load_Variables // ////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundDefinitionClass::Load_Variables (ChunkLoadClass &cload) { using namespace AUDIBLE_SOUND_DEF_SAVELOAD; // // Loop through all the microchunks that define the variables // while (cload.Open_Micro_Chunk ()) { switch (cload.Cur_Micro_Chunk_ID ()) { READ_MICRO_CHUNK (cload, VARID_PRIORITY, m_Priority) READ_MICRO_CHUNK (cload, VARID_VOLUME, m_Volume) READ_MICRO_CHUNK (cload, VARID_PAN, m_Pan) READ_MICRO_CHUNK (cload, VARID_LOOP_COUNT, m_LoopCount) READ_MICRO_CHUNK (cload, VARID_DROP_OFF, m_DropOffRadius) READ_MICRO_CHUNK (cload, VARID_MAX_VOL, m_MaxVolRadius) READ_MICRO_CHUNK (cload, VARID_TYPE, m_Type) READ_MICRO_CHUNK (cload, VARID_IS3D, m_Is3D) READ_MICRO_CHUNK_WWSTRING (cload, VARID_FILENAME, m_Filename) READ_MICRO_CHUNK_WWSTRING (cload, VARID_DISPLAY_TEXT, m_DisplayText) READ_MICRO_CHUNK (cload, VARID_LOGICAL_MASK, m_LogicalTypeMask) READ_MICRO_CHUNK (cload, VARID_LOGICAL_DELAY, m_LogicalNotifyDelay) READ_MICRO_CHUNK (cload, VARID_CREATE_LOGICAL, m_CreateLogical) READ_MICRO_CHUNK (cload, VARID_LOGICAL_DROP_OFF, m_LogicalDropOffRadius) READ_MICRO_CHUNK (cload, VARID_SPHERE_COLOR, m_AttenuationSphereColor) READ_MICRO_CHUNK (cload, VARID_START_OFFSET, m_StartOffset); READ_MICRO_CHUNK (cload, VARID_PITCH_FACTOR, m_PitchFactor); READ_MICRO_CHUNK (cload, VARID_PITCH_FACTOR_RND, m_PitchFactorRandomizer); READ_MICRO_CHUNK (cload, VARID_VOLUME_RND, m_VolumeRandomizer); READ_MICRO_CHUNK (cload, VARID_VIRTUAL_CHANNEL, m_VirtualChannel); } cload.Close_Micro_Chunk (); } return true; } ////////////////////////////////////////////////////////////////////////////////// // // Create // ////////////////////////////////////////////////////////////////////////////////// PersistClass * AudibleSoundDefinitionClass::Create (void) const { return Create_Sound (CLASSID_3D); } ////////////////////////////////////////////////////////////////////////////////// // // Create_Sound // ////////////////////////////////////////////////////////////////////////////////// AudibleSoundClass * AudibleSoundDefinitionClass::Create_Sound (int classid_hint) const { AudibleSoundClass *new_sound = NULL; // // If this is a relative path, strip it off and assume // the current directory is set correctly. // StringClass real_filename(m_Filename,true); const char *dir_delimiter = ::strrchr (m_Filename, '\\'); if (dir_delimiter != NULL && m_Filename.Get_Length () > 2 && m_Filename[1] != ':') { real_filename = (dir_delimiter + 1); } // // Should we create a 2D or 3D sound? // if (m_Is3D && classid_hint != CLASSID_2D) { new_sound = WWAudioClass::Get_Instance ()->Create_3D_Sound (real_filename, classid_hint); } else { new_sound = WWAudioClass::Get_Instance ()->Create_Sound_Effect (real_filename); } // // Did we successfully create the sound? // if (new_sound != NULL) { // // Configure the sound // new_sound->Set_Type ((AudibleSoundClass::SOUND_TYPE)m_Type); new_sound->Set_Priority (m_Priority); new_sound->Set_Loop_Count (m_LoopCount); new_sound->Set_DropOff_Radius (m_DropOffRadius); new_sound->Set_Definition ((AudibleSoundDefinitionClass *)this); new_sound->Set_Start_Offset (m_StartOffset); new_sound->Set_Virtual_Channel (m_VirtualChannel); // // Randomize the volume and pitch as necessary // float volume = m_Volume; if (m_VolumeRandomizer != 0) { volume += WWMath::Random_Float (-m_VolumeRandomizer, m_VolumeRandomizer); } float pitch_factor = m_PitchFactor; if (m_PitchFactor != 0) { pitch_factor += WWMath::Random_Float (-m_PitchFactorRandomizer, m_PitchFactorRandomizer); } // // Set the volume and pitch // new_sound->Set_Volume (volume); new_sound->Set_Pitch_Factor (pitch_factor); if (new_sound->As_Sound3DClass () != NULL) { ((Sound3DClass *)new_sound)->Set_Max_Vol_Radius (m_MaxVolRadius); } } return new_sound; } ////////////////////////////////////////////////////////////////////////////////// // // Create_Logical // ////////////////////////////////////////////////////////////////////////////////// LogicalSoundClass * AudibleSoundDefinitionClass::Create_Logical (void) { LogicalSoundClass *logical_sound = NULL; if (m_CreateLogical) { // // Create and configure the logical sound // logical_sound = new LogicalSoundClass; logical_sound->Set_Type_Mask (m_LogicalTypeMask); logical_sound->Set_Notify_Delay (m_LogicalNotifyDelay); logical_sound->Set_Single_Shot (m_LoopCount != 0); // // Use the audible sound's drop-off radius if the logical // isn't set... // if (m_LogicalDropOffRadius < 0) { logical_sound->Set_DropOff_Radius (m_DropOffRadius); } else { logical_sound->Set_DropOff_Radius (m_LogicalDropOffRadius); } } return logical_sound; } ////////////////////////////////////////////////////////////////////////////////// // // Save // ////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Save (ChunkSaveClass &csave) { using namespace AUDIBLE_SOUND_SAVELOAD; csave.Begin_Chunk (CHUNKID_BASE_CLASS); SoundSceneObjClass::Save (csave); csave.End_Chunk (); uint32 temp_position = 0; csave.Begin_Chunk (CHUNKID_VARIABLES); WRITE_MICRO_CHUNK (csave, VARID_STATE, m_State); WRITE_MICRO_CHUNK (csave, VARID_TYPE, m_Type); WRITE_MICRO_CHUNK (csave, VARID_PRIORITY, m_Priority); WRITE_MICRO_CHUNK (csave, VARID_VOLUME, m_Volume); WRITE_MICRO_CHUNK (csave, VARID_PAN, m_Pan); WRITE_MICRO_CHUNK (csave, VARID_LOOP_COUNT, m_LoopCount); WRITE_MICRO_CHUNK (csave, VARID_LOOPS_LEFT, m_LoopsLeft); WRITE_MICRO_CHUNK (csave, VARID_SOUND_LENGTH, m_Length); WRITE_MICRO_CHUNK (csave, VARID_CURR_POS, temp_position); WRITE_MICRO_CHUNK (csave, VARID_TRANSFORM, m_Transform); WRITE_MICRO_CHUNK (csave, VARID_PREV_TRANSFORM, m_PrevTransform); WRITE_MICRO_CHUNK (csave, VARID_IS_CULLED, m_IsCulled); WRITE_MICRO_CHUNK (csave, VARID_IS_DIRTY, m_bDirty); WRITE_MICRO_CHUNK (csave, VARID_DROP_OFF, m_DropOffRadius); WRITE_MICRO_CHUNK (csave, VARID_START_OFFSET, m_StartOffset); WRITE_MICRO_CHUNK (csave, VARID_PITCH_FACTOR, m_PitchFactor); WRITE_MICRO_CHUNK (csave, VARID_LISTENER_TRANSFORM, m_ListenerTransform); WRITE_MICRO_CHUNK (csave, VARID_VIRTUAL_CHANNEL, m_VirtualChannel); if (m_Buffer != NULL) { WRITE_MICRO_CHUNK_STRING (csave, VARID_FILENAME, m_Buffer->Get_Filename ()); } AudibleSoundClass *this_ptr = this; WRITE_MICRO_CHUNK (csave, VARID_THIS_PTR, this_ptr); csave.End_Chunk (); return true; } ////////////////////////////////////////////////////////////////////////////////// // // Load // ////////////////////////////////////////////////////////////////////////////////// bool AudibleSoundClass::Load (ChunkLoadClass &cload) { using namespace AUDIBLE_SOUND_SAVELOAD; StringClass filename(0,true); while (cload.Open_Chunk ()) { switch (cload.Cur_Chunk_ID ()) { case CHUNKID_BASE_CLASS: SoundSceneObjClass::Load (cload); break; case CHUNKID_VARIABLES: { // // Read all the variables from their micro-chunks // while (cload.Open_Micro_Chunk ()) { switch (cload.Cur_Micro_Chunk_ID ()) { READ_MICRO_CHUNK (cload, VARID_STATE, m_State); READ_MICRO_CHUNK (cload, VARID_TYPE, m_Type); READ_MICRO_CHUNK (cload, VARID_PRIORITY, m_Priority); READ_MICRO_CHUNK (cload, VARID_VOLUME, m_Volume); READ_MICRO_CHUNK (cload, VARID_PAN, m_Pan); READ_MICRO_CHUNK (cload, VARID_LOOP_COUNT, m_LoopCount); READ_MICRO_CHUNK (cload, VARID_LOOPS_LEFT, m_LoopsLeft); READ_MICRO_CHUNK (cload, VARID_SOUND_LENGTH, m_Length); READ_MICRO_CHUNK (cload, VARID_CURR_POS, m_CurrentPosition); READ_MICRO_CHUNK (cload, VARID_TRANSFORM, m_Transform); READ_MICRO_CHUNK (cload, VARID_PREV_TRANSFORM, m_PrevTransform); READ_MICRO_CHUNK (cload, VARID_IS_CULLED, m_IsCulled); READ_MICRO_CHUNK (cload, VARID_IS_DIRTY, m_bDirty); READ_MICRO_CHUNK (cload, VARID_DROP_OFF, m_DropOffRadius); READ_MICRO_CHUNK (cload, VARID_START_OFFSET, m_StartOffset); READ_MICRO_CHUNK (cload, VARID_PITCH_FACTOR, m_PitchFactor); READ_MICRO_CHUNK (cload, VARID_LISTENER_TRANSFORM, m_ListenerTransform); READ_MICRO_CHUNK (cload, VARID_VIRTUAL_CHANNEL, m_VirtualChannel); READ_MICRO_CHUNK_WWSTRING (cload, VARID_FILENAME, filename); case VARID_THIS_PTR: { AudibleSoundClass *old_ptr = NULL; cload.Read(&old_ptr, sizeof (old_ptr)); SaveLoadSystemClass::Register_Pointer (old_ptr, this); } break; } cload.Close_Micro_Chunk (); } } break; } cload.Close_Chunk (); } // // Reconstruct the sound buffer we had before we saved // if (filename.Get_Length () > 0) { bool is_3d = (As_Sound3DClass () != NULL); SoundBufferClass *buffer = WWAudioClass::Get_Instance ()->Get_Sound_Buffer (filename, is_3d); Set_Buffer (buffer); REF_PTR_RELEASE (buffer); } return true; }