2061 lines
No EOL
53 KiB
C++
2061 lines
No EOL
53 KiB
C++
/*
|
|
** 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** 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<AudibleSoundDefinitionClass, CHUNKID_SOUND_DEF> _AudibleSoundDefPersistFactory;
|
|
SimplePersistFactoryClass<AudibleSoundClass, CHUNKID_AUDIBLE_SOUND> _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;
|
|
} |