/*
** Command & Conquer Generals(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/WWAudio.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 8/14/01 2:27p $*
* *
* $Revision:: 52 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "always.h"
#include
#include "WWAudio.H"
#include "WWDebug.H"
#include "Utils.H"
#include "RealCRC.H"
#include "SoundBuffer.H"
#include "AudibleSound.H"
#include "Sound3D.H"
#include "RawFile.H"
#include "WW3D.H"
#include "SoundScene.H"
#include "SoundPseudo3D.H"
#include "FFactory.H"
#include "Registry.H"
#include "Threads.H"
#include "LogicalSound.h"
#include "LogicalListener.h"
#include "definitionclassids.h"
#include "wwmemlog.h"
#include "wwprofile.h"
#ifdef G_CODE_BASE
#include "..\wwlib\argv.h"
#endif
////////////////////////////////////////////////////////////////////////////////////////////////
// Static member initialization
////////////////////////////////////////////////////////////////////////////////////////////////
WWAudioClass *WWAudioClass::_theInstance = NULL;
HANDLE WWAudioClass::_TimerSyncEvent = NULL;
////////////////////////////////////////////////////////////////////////////////////////////////
// Registry value names
////////////////////////////////////////////////////////////////////////////////////////////////
const char *VALUE_NAME_IS_STEREO = "stereo";
const char *VALUE_NAME_BITS = "bits";
const char *VALUE_NAME_HERTZ = "hertz";
const char *VALUE_NAME_DEVICE_NAME = "device name";
const char *VALUE_NAME_MUSIC_ENABLED = "music enabled";
const char *VALUE_NAME_SOUND_ENABLED = "sound enabled";
const char *VALUE_NAME_MUSIC_VOL = "music volume";
const char *VALUE_NAME_SOUND_VOL = "sound volume";
////////////////////////////////////////////////////////////////////////////////////////////////
// Local inlines
////////////////////////////////////////////////////////////////////////////////////////////////
__inline bool
WWAudioClass::Is_OK_To_Give_Handle (const AudibleSoundClass &sound_obj)
{
bool is_ok = false;
AudibleSoundClass::SOUND_TYPE type = sound_obj.Get_Type ();
if (((type == AudibleSoundClass::TYPE_SOUND_EFFECT) && m_AreSoundEffectsEnabled) ||
((type == AudibleSoundClass::TYPE_MUSIC) && m_IsMusicEnabled)) {
is_ok = true;
}
return is_ok;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// WWAudioClass
//
////////////////////////////////////////////////////////////////////////////////////////////////
WWAudioClass::WWAudioClass (void)
: m_Driver2D (NULL),
m_Driver3D (NULL),
m_PlaybackRate (44100),
m_PlaybackBits (16),
m_PlaybackStereo (true),
m_ReverbFilter (INVALID_MILES_HANDLE),
m_UpdateTimer (-1),
m_Driver3DPseudo (NULL),
m_MusicVolume (DEF_MUSIC_VOL),
m_SoundVolume (DEF_SFX_VOL),
m_MaxCacheSize (DEF_CACHE_SIZE * 1024),
m_CurrentCacheSize (0),
m_Max2DSamples (DEF_2D_SAMPLE_COUNT),
m_Max3DSamples (DEF_3D_SAMPLE_COUNT),
m_Max2DBufferSize (DEF_MAX_2D_BUFFER_SIZE),
m_Max3DBufferSize (DEF_MAX_3D_BUFFER_SIZE),
m_SoundScene (NULL),
m_IsMusicEnabled (true),
m_AreSoundEffectsEnabled (true),
m_FileFactory (NULL),
m_EffectsLevel (0),
m_ReverbRoomType (ENVIRONMENT_GENERIC)
{
::InitializeCriticalSection (&MMSLockClass::_MSSLockCriticalSection);
//
// Start Miles Sound System
//
AIL_startup ();
_theInstance = this;
_TimerSyncEvent = ::CreateEvent (NULL, TRUE, FALSE, "WWAUDIO_TIMER_SYNC");
//
// Set some default values
//
Set_Sound_Effects_Volume ();
Set_Music_Volume ();
// Create a new sound scene to manage our 3D sounds...
m_SoundScene = W3DNEW SoundSceneClass;
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// ~WWAudioClass
//
////////////////////////////////////////////////////////////////////////////////////////////////
WWAudioClass::~WWAudioClass (void)
{
//
// Make sure the delayed-release thread is terminated
// before we exit (otherwise the process will crash).
//
WWAudioThreadsClass::End_Delayed_Release_Thread ();
Shutdown ();
_theInstance = NULL;
::CloseHandle(_TimerSyncEvent);
_TimerSyncEvent = NULL;
::DeleteCriticalSection (&MMSLockClass::_MSSLockCriticalSection);
//
// Free the list of logical "types".
//
Reset_Logical_Types ();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Flush_Cache
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Flush_Cache (void)
{
// Loop through all the hash indicies
for (int hash_index = 0; hash_index < MAX_CACHE_HASH; hash_index ++) {
// Loop through all the buffers at this hash index and free them all
for (int index = 0; index < m_CachedBuffers[hash_index].Count (); index ++) {
CACHE_ENTRY_STRUCT &info = m_CachedBuffers[hash_index][index];
// Free the buffer data
SAFE_FREE (info.string_id);
REF_PTR_RELEASE (info.buffer);
}
// Remove all the entries for this hash index
m_CachedBuffers[hash_index].Delete_All ();
}
m_CurrentCacheSize = 0;
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Open_2D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
WWAudioClass::DRIVER_TYPE_2D
WWAudioClass::Open_2D_Device (LPWAVEFORMAT format)
{
MMSLockClass lock;
//
// Store the playback settings for future reference
//
m_PlaybackRate = format->nSamplesPerSec;
m_PlaybackBits = (format->nAvgBytesPerSec << 3) / (format->nChannels * format->nSamplesPerSec);
m_PlaybackStereo = bool(format->nChannels > 1);
//
// Assume we will open the DirectSound driver
//
DRIVER_TYPE_2D type = DRIVER2D_DSOUND;
// First close the current 2D device and take
// all the sound handles away from the sound objects.
Close_2D_Device ();
AIL_set_preference (AIL_LOCK_PROTECTION, NO);
// Try to use DirectSound if possible
S32 success = ::AIL_set_preference (DIG_USE_WAVEOUT, FALSE);
WWASSERT (success == AIL_NO_ERROR);
// Open the driver
success = ::AIL_waveOutOpen (&m_Driver2D, NULL, 0, format);
// Do we need to switch from direct sound to waveout?
if ((success == AIL_NO_ERROR) &&
(m_Driver2D != NULL) &&
(m_Driver2D->emulated_ds == TRUE)) {
::AIL_waveOutClose (m_Driver2D);
success = 2;
WWDEBUG_SAY (("WWAudio: Detected 2D DirectSound emulation, switching to WaveOut.\r\n"));
}
// If we couldn't open the direct sound device, then use the
// default wave out device
if (success != AIL_NO_ERROR) {
// Try to use the default wave out driver
success = ::AIL_set_preference (DIG_USE_WAVEOUT, TRUE);
WWASSERT (success == AIL_NO_ERROR);
// Open the driver
success = ::AIL_waveOutOpen (&m_Driver2D, NULL, 0, format);
WWASSERT (success == AIL_NO_ERROR);
type = (success == AIL_NO_ERROR) ? DRIVER2D_WAVEOUT : DRIVER2D_ERROR;
}
// Allocate all the available handles if we were successful
if (success == AIL_NO_ERROR) {
Allocate_2D_Handles ();
ReAssign_2D_Handles ();
} else {
Close_2D_Device ();
WWDEBUG_SAY (("WWAudio: Error initializing 2D device.\r\n"));
}
// Return the opened device type
return type;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Open_2D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
WWAudioClass::DRIVER_TYPE_2D
WWAudioClass::Open_2D_Device
(
bool stereo,
int bits,
int hertz
)
{
// Build a wave format structure from the params
PCMWAVEFORMAT wave_format = { 0 };
wave_format.wf.wFormatTag = WAVE_FORMAT_PCM;
wave_format.wf.nChannels = stereo ? 2 : 1;
wave_format.wf.nSamplesPerSec = hertz;
wave_format.wf.nAvgBytesPerSec = (wave_format.wf.nChannels * wave_format.wf.nSamplesPerSec * bits) >> 3;
wave_format.wf.nBlockAlign = (wave_format.wf.nChannels * bits) >> 3;
wave_format.wBitsPerSample = bits;
DRIVER_TYPE_2D type = DRIVER2D_ERROR;
while (((type = Open_2D_Device ((LPWAVEFORMAT)&wave_format)) == DRIVER2D_ERROR) &&
(wave_format.wf.nSamplesPerSec >= 11025)) {
//
// Cut the playback rate in half and try again
//
wave_format.wf.nSamplesPerSec = wave_format.wf.nSamplesPerSec >> 1;
wave_format.wf.nAvgBytesPerSec = (wave_format.wf.nChannels * wave_format.wf.nSamplesPerSec * bits) >> 3;
wave_format.wf.nBlockAlign = (wave_format.wf.nChannels * bits) >> 3;
}
// Pass this structure onto the function that actually opens the device
return type;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Close_2D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Close_2D_Device (void)
{
MMSLockClass lock;
bool retval = false;
//
// Free any 2D sound handles
//
Remove_2D_Sound_Handles ();
Release_2D_Handles ();
//
// Do we have an open driver handle to close?
//
if (m_Driver2D != NULL) {
//
// Close the driver
//
::AIL_waveOutClose (m_Driver2D);
m_Driver2D = NULL;
retval = true;
}
//
// Return the true/false result code
//
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_Sound_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
SoundBufferClass *
WWAudioClass::Get_Sound_Buffer (const char *filename, bool is_3d)
{
//
// Try to find the buffer in our cache, otherwise create a new buffer.
//
SoundBufferClass *buffer = Find_Cached_Buffer (filename);
if (buffer == NULL) {
FileClass *file = Get_File (filename);
if (file != NULL && file->Is_Available ()) {
buffer = Create_Sound_Buffer (*file, filename, is_3d);
} else {
static int count = 0;
if ( ++count < 10 ) {
WWDEBUG_SAY(( "Sound \"%s\" not found\r\n", filename ));
}
}
Return_File (file);
}
return buffer;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_Sound_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
SoundBufferClass *
WWAudioClass::Get_Sound_Buffer (FileClass &file, const char *string_id, bool is_3d)
{
WWMEMLOG(MEM_SOUND);
//
// Try to find the buffer in our cache, otherwise create a new buffer.
//
SoundBufferClass *buffer = Find_Cached_Buffer (string_id);
if (buffer == NULL) {
buffer = Create_Sound_Buffer (file, string_id, is_3d);
}
return buffer;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Find_Cached_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
SoundBufferClass *
WWAudioClass::Find_Cached_Buffer (const char *string_id)
{
SoundBufferClass *sound_buffer = NULL;
// Param OK?
WWASSERT (string_id != NULL);
if (string_id != NULL) {
//
// Determine which index in our hash table to use
//
int hash_index = ::CRC_Stringi (string_id) & CACHE_HASH_MASK;
//
// Loop through all the buffers at this hash index and try to find
// one that matches the requested name
//
for (int index = 0; index < m_CachedBuffers[hash_index].Count (); index ++) {
//
// Is this the sound buffer we were looking for?
//
CACHE_ENTRY_STRUCT &info = m_CachedBuffers[hash_index][index];
if (::lstrcmpi (info.string_id, string_id) == 0) {
sound_buffer = info.buffer;
sound_buffer->Add_Ref ();
break;
}
}
}
//
// Return a pointer to the cached sound buffer
//
return sound_buffer;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Free_Cache_Space
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Free_Cache_Space (int bytes)
{
int bytes_freed = 0;
// Loop through all the hash indicies
for (int hash_index = 0;
(hash_index < MAX_CACHE_HASH) && (bytes_freed < bytes);
hash_index ++) {
// Loop through all the buffers at this hash index
for (int index = 0;
(index < m_CachedBuffers[hash_index].Count ()) && (bytes_freed < bytes);
index ++) {
// Can we free this cached buffer?
CACHE_ENTRY_STRUCT &info = m_CachedBuffers[hash_index][index];
if ((info.buffer != NULL) && (info.buffer->Num_Refs () == 1)) {
// Add the size of this buffer to our count of bytes freed
bytes_freed += info.buffer->Get_Raw_Length ();
// Free the buffer data
SAFE_FREE (info.string_id);
REF_PTR_RELEASE (info.buffer);
// Remove this entry from the hash table
m_CachedBuffers[hash_index].Delete (index);
index --;
}
}
}
// Make sure to recompute out current cache size
m_CurrentCacheSize -= bytes_freed;
WWASSERT (m_CurrentCacheSize >= 0);
// Return true if we freed enough bytes in the cache
return (bytes_freed >= bytes);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Cache_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Cache_Buffer
(
SoundBufferClass *buffer,
const char *string_id
)
{
// Assume failure
bool retval = false;
// Params OK?
WWASSERT (buffer != NULL);
WWASSERT (string_id != NULL);
if ((buffer != NULL) &&
(string_id != NULL) &&
(buffer->Get_Raw_Length () < (U32)(m_MaxCacheSize / 2))) {
// Attempt to free space in the cache (if needed)
int space_needed = (m_CurrentCacheSize + buffer->Get_Raw_Length ()) - (int)m_MaxCacheSize;
if (space_needed > 0) {
Free_Cache_Space (space_needed);
}
// Do we have enough space in the cache for this buffer?
space_needed = (m_CurrentCacheSize + buffer->Get_Raw_Length ()) - (int)m_MaxCacheSize;
if (space_needed <= 0) {
// Determine which index in our hash table to use
int hash_index = ::CRC_Stringi (string_id) & CACHE_HASH_MASK;
//
// Add this buffer to the hash table at the given index.
// Note: The assignment operator caused by the Add call
// will add a reference to the sound buffer.
//
CACHE_ENTRY_STRUCT info;
info.string_id = (char *)string_id;
info.buffer = buffer;
m_CachedBuffers[hash_index].Add (info);
// Update our current cache size
m_CurrentCacheSize += buffer->Get_Raw_Length ();
retval = true;
}
}
// Return the true/false result code
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
SoundBufferClass *
WWAudioClass::Create_Sound_Buffer
(
FileClass & file,
const char *string_id,
bool is_3d
)
{
SoundBufferClass *sound_buffer = NULL;
//
// Determine how large this buffer can be
//
int max_size = is_3d ? m_Max3DBufferSize : m_Max2DBufferSize;
//
// Create a streaming sound buffer object if the
// file is too large to preload.
//
if (file.Size () > max_size) {
sound_buffer = W3DNEW StreamSoundBufferClass;
} else {
sound_buffer = W3DNEW SoundBufferClass;
}
SET_REF_OWNER(sound_buffer);
//
// Create a new sound buffer from the provided file
//
bool success = sound_buffer->Load_From_File (file);
sound_buffer->Set_Filename (string_id);
WWASSERT (success);
// If we were successful in creating the sound buffer, then
// try to cache it as well, otherwise free the buffer and return NULL.
if (success && (string_id != NULL)) {
Cache_Buffer (sound_buffer, string_id);
} else if (success == false) {
REF_PTR_RELEASE (sound_buffer);
}
// Return a pointer to the new sound buffer
return sound_buffer;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
SoundBufferClass *
WWAudioClass::Create_Sound_Buffer
(
unsigned char * file_image,
unsigned long bytes,
const char * string_id,
bool is_3d
)
{
// Create a new sound buffer from the provided file
SoundBufferClass *sound_buffer = W3DNEW SoundBufferClass;
SET_REF_OWNER(sound_buffer);
//
// Initialize the sound from this piece of memory
//
bool success = sound_buffer->Load_From_Memory (file_image, bytes);
sound_buffer->Set_Filename (string_id);
WWASSERT (success);
// If we were successful in creating the sound buffer, then
// try to cache it as well, otherwise free the buffer and return NULL.
if (success && (string_id != NULL)) {
Cache_Buffer (sound_buffer, string_id);
} else if (success == false) {
REF_PTR_RELEASE (sound_buffer);
}
// Return a pointer to the new sound buffer
return sound_buffer;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound_Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Sound_Effect (FileClass &file, const char *string_id)
{
// Create a new sound object
AudibleSoundClass *sound_obj = W3DNEW AudibleSoundClass;
if (Is_Disabled () == false) {
// Try to find the buffer in our cache, otherwise create a new buffer.
SoundBufferClass *buffer = Get_Sound_Buffer (file, string_id, false);
// Pass the actual sound data onto the sound object
sound_obj->Set_Buffer (buffer);
REF_PTR_RELEASE (buffer);
}
// Return a pointer to the sound effect
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound_Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Sound_Effect (const char *filename)
{
// Assume failure
AudibleSoundClass *sound_obj = NULL;
if (Is_Disabled () == false) {
// Param OK?
WWASSERT (filename != NULL);
if (filename != NULL) {
// Create a file object and pass it onto the appropriate function
FileClass *file = Get_File (filename);
if (file && file->Is_Available()) {
sound_obj = Create_Sound_Effect (*file, filename);
} else {
WWDEBUG_SAY(( "Sound %s not found\r\n", filename ));
}
Return_File (file);
}
}
// Return a pointer to the sound effect
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound_Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Sound_Effect
(
const char * string_id,
unsigned char *raw_wave_data,
unsigned long bytes
)
{
// Create a new sound object
AudibleSoundClass *sound_obj = W3DNEW AudibleSoundClass;
if (Is_Disabled () == false) {
// Try to find the buffer in our cache, otherwise create a new buffer.
SoundBufferClass *buffer = Find_Cached_Buffer (string_id);
if (buffer == NULL) {
buffer = Create_Sound_Buffer (raw_wave_data, bytes, string_id, false);
}
// Pass the actual sound data onto the sound object
sound_obj->Set_Buffer (buffer);
REF_PTR_RELEASE (buffer);
}
// Return a pointer to the sound effect
return sound_obj;
}
/////////////////////////////////////////////////////////////////////////////////
//
// Create_3D_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
Sound3DClass *
WWAudioClass::Create_3D_Sound (FileClass &file, const char *string_id, int classid_hint)
{
Sound3DClass *sound_obj = NULL;
if (Is_Disabled () == false) {
// Try to find the buffer in our cache, otherwise create a new buffer.
SoundBufferClass *buffer = Get_Sound_Buffer (file, string_id, true);
//
// What type of sound object should we create? A true 3D sound or one of
// our pseudo-3d sounds? (volume and panning only)
//
if ( classid_hint == CLASSID_PSEUDO3D ||
Validate_3D_Sound_Buffer (buffer) == false)
{
sound_obj = W3DNEW SoundPseudo3DClass;
sound_obj->Set_Buffer (buffer);
} else if (buffer != NULL) {
sound_obj = W3DNEW Sound3DClass;
sound_obj->Set_Buffer (buffer);
}
REF_PTR_RELEASE (buffer);
}
// Return a pointer to the sound effect
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_3D_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
Sound3DClass *
WWAudioClass::Create_3D_Sound
(
const char * filename,
int classid_hint
)
{
WWMEMLOG(MEM_SOUND);
// Assume failure
Sound3DClass *sound_obj = NULL;
if (Is_Disabled () == false) {
// Param OK?
WWASSERT (filename != NULL);
if (filename != NULL) {
// Try to find the buffer in our cache, otherwise create a new buffer.
SoundBufferClass *buffer = Get_Sound_Buffer (filename, true);
//
// What type of sound object should we create? A true 3D sound or one of
// our pseudo-3d sounds? (volume and panning only)
//
if ( classid_hint == CLASSID_PSEUDO3D ||
Validate_3D_Sound_Buffer (buffer) == false)
{
sound_obj = W3DNEW SoundPseudo3DClass;
sound_obj->Set_Buffer (buffer);
} else if (buffer != NULL) {
sound_obj = W3DNEW Sound3DClass;
sound_obj->Set_Buffer (buffer);
} else {
static int count = 0;
if ( ++count < 10 ) {
WWDEBUG_SAY(( "Sound File not Found \"%s\"\r\n", filename ));
}
}
REF_PTR_RELEASE (buffer);
}
}
// Return a pointer to the sound effect
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_3D_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
Sound3DClass *
WWAudioClass::Create_3D_Sound
(
const char * string_id,
unsigned char * raw_wave_data,
unsigned long bytes,
int classid_hint
)
{
Sound3DClass *sound_obj = NULL;
if (Is_Disabled () == false) {
//
// Try to find the buffer in our cache, otherwise create a new buffer.
//
SoundBufferClass *buffer = Find_Cached_Buffer (string_id);
if (buffer == NULL) {
buffer = Create_Sound_Buffer (raw_wave_data, bytes, string_id, true);
}
//
// What type of sound object should we create? A true 3D sound or one of
// our pseudo-3d sounds? (volume and panning only)
//
if ( classid_hint == CLASSID_PSEUDO3D ||
Validate_3D_Sound_Buffer (buffer) == false)
{
sound_obj = W3DNEW SoundPseudo3DClass;
sound_obj->Set_Buffer (buffer);
} else if (buffer != NULL) {
sound_obj = W3DNEW Sound3DClass;
sound_obj->Set_Buffer (buffer);
}
REF_PTR_RELEASE (buffer);
}
// Return a pointer to the sound effect
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Sound
(
int definition_id,
RefCountClass *user_obj,
uint32 user_data,
int classid_hint
)
{
AudibleSoundClass *sound = NULL;
//
// Find the definition
//
DefinitionClass *definition = DefinitionMgrClass::Find_Definition (definition_id);
if (definition != NULL ) {
//
// Make sure this is really a sound definition
//
WWASSERT (definition->Get_Class_ID () == CLASSID_SOUND);
if (definition->Get_Class_ID () == CLASSID_SOUND) {
AudibleSoundDefinitionClass *sound_def = reinterpret_cast (definition);
//
// Create an instance of the sound
//
sound = sound_def->Create_Sound (classid_hint);
if (sound != NULL) {
sound->Set_User_Data (user_obj, user_data);
}
}
}
return sound;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Sound
(
const char * def_name,
RefCountClass *user_obj,
uint32 user_data,
int classid_hint
)
{
AudibleSoundClass *sound = NULL;
//
// Find the definition
//
DefinitionClass *definition = DefinitionMgrClass::Find_Typed_Definition (def_name, CLASSID_SOUND, true);
if (definition != NULL ) {
//
// Make sure this is really a sound definition
//
WWASSERT (definition->Get_Class_ID () == CLASSID_SOUND);
if (definition->Get_Class_ID () == CLASSID_SOUND) {
AudibleSoundDefinitionClass *sound_def = reinterpret_cast (definition);
//
// Create an instance of the sound
//
sound = sound_def->Create_Sound (classid_hint);
if (sound != NULL) {
sound->Set_User_Data (user_obj, user_data);
}
}
}
return sound;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Continuous_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Continuous_Sound
(
int definition_id,
RefCountClass *user_obj,
uint32 user_data,
int classid_hint
)
{
//
// Create an instance of the sound and play it
//
AudibleSoundClass *sound = Create_Sound (definition_id, user_obj, user_data, classid_hint);
if (sound != NULL) {
if (sound->Get_Loop_Count () != INFINITE_LOOPS) {
WWDEBUG_SAY (("Audio Error: Creating a continuous sound with a finite loop count!\r\n"));
}
}
return sound;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Instant_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
int
WWAudioClass::Create_Instant_Sound
(
int definition_id,
const Matrix3D & tm,
RefCountClass * user_obj,
uint32 user_data,
int classid_hint
)
{
int sound_id = 0;
//
// Create an instance of the sound and play it
//
AudibleSoundClass *sound = Create_Sound (definition_id, user_obj, user_data, classid_hint);
if (sound != NULL) {
if (sound->Get_Loop_Count () == INFINITE_LOOPS) {
WWDEBUG_SAY (("Audio Error: Creating an instant sound %s with an infinite loop count!\r\n",sound->Get_Definition()->Get_Name()));
}
sound_id = sound->Get_ID ();
sound->Set_Transform (tm);
sound->Add_To_Scene ();
sound->Release_Ref ();
}
return sound_id;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Continuous_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Create_Continuous_Sound
(
const char * def_name,
RefCountClass *user_obj,
uint32 user_data,
int classid_hint
)
{
//
// Create an instance of the sound and play it
//
AudibleSoundClass *sound = Create_Sound (def_name, user_obj, user_data, classid_hint);
if (sound != NULL) {
if (sound->Get_Loop_Count () != INFINITE_LOOPS) {
WWDEBUG_SAY (("Audio Error: Creating a continuous sound with a finite loop count!\r\n"));
}
}
return sound;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Instant_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////////
int
WWAudioClass::Create_Instant_Sound
(
const char * def_name,
const Matrix3D & tm,
RefCountClass * user_obj,
uint32 user_data,
int classid_hint
)
{
int sound_id = 0;
//
// Create an instance of the sound and play it
//
AudibleSoundClass *sound = Create_Sound (def_name, user_obj, user_data, classid_hint);
if (sound != NULL) {
if (sound->Get_Loop_Count () == INFINITE_LOOPS) {
WWDEBUG_SAY (("Audio Error: Creating an instant sound %s with an infinite loop count!\r\n",sound->Get_Definition()->Get_Name()));
}
sound_id = sound->Get_ID ();
sound->Set_Transform (tm);
sound->Add_To_Scene ();
sound->Release_Ref ();
}
return sound_id;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Flush_Playlist
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Flush_Playlist (void)
{
// First make sure to free any completed sounds
Free_Completed_Sounds ();
// Loop through all the entries in the playlist
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
REF_PTR_RELEASE (sound_obj);
}
// Free the list structure
m_Playlist.Delete_All ();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Free_Completed_Sounds
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Free_Completed_Sounds (void)
{
if (m_CompletedSounds.Count () > 0) {
// Loop through all the entries in the completed sounds list
for (int index = 0; index < m_CompletedSounds.Count (); index ++) {
AudibleSoundClass *sound_obj = m_CompletedSounds[index];
WWASSERT(sound_obj != NULL); //TSS 05/24/99
// Remove this sound from the playlist
bool found = false;
for (int play_index = 0; (play_index < m_Playlist.Count ()) && !found; play_index ++) {
if (m_Playlist[play_index] == sound_obj) {
// Free our hold on this sound object
m_Playlist.Delete (play_index);
REF_PTR_RELEASE (sound_obj);
found = true;
}
}
}
// Free the list structure
m_CompletedSounds.Delete_All ();
// Try to give a play-handle back to a sound that was priority-bumped.
Reprioritize_Playlist ();
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_Playlist_Entry
//
////////////////////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
WWAudioClass::Get_Playlist_Entry (int index) const
{
AudibleSoundClass *sound_obj = NULL;
// Params OK?
WWASSERT (index >= 0 && index < m_Playlist.Count ());
if ((index >= 0) && (index < m_Playlist.Count ())) {
m_Playlist[index]->Add_Ref ();
m_Playlist[index];
}
// Return a pointer to the sound object
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Add_To_Playlist
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Add_To_Playlist (AudibleSoundClass *sound)
{
// Assume failure
bool retval = false;
WWASSERT (sound != NULL);
if (sound != NULL) {
// Loop through all the entries in the playlist
bool already_added = false;
for (int index = 0; (index < m_Playlist.Count ()) && (already_added == false); index ++) {
already_added = (sound == m_Playlist[index]);
}
// Add this sound to our playlist
if (already_added == false) {
sound->Add_Ref ();
m_Playlist.Add (sound);
}
}
// Return the true/false result code
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Remove_From_Playlist
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Remove_From_Playlist (AudibleSoundClass *sound_obj)
{
// Assume failure
bool retval = false;
WWASSERT (sound_obj != NULL);
if (sound_obj != NULL) {
// Loop through all the entries in the playlist
for (int index = 0; (index < m_Playlist.Count ()) && (retval == false); index ++) {
// Is this the entry we are looking for?
if (sound_obj == m_Playlist[index]) {
// Add this sound to the 'completed' list
m_CompletedSounds.Add (sound_obj);
retval = true;
}
}
//
// Notify any callbacks that this sound is ending...
//
if (sound_obj->Get_Loop_Count () != INFINITE_LOOPS) {
for (index = 0; index < m_EOSCallbackList.Count (); index ++) {
uint32 user_data = NULL;
LPFNEOSCALLBACK callback = m_EOSCallbackList.Get_Callback (index, &user_data);
if (callback != NULL) {
(*callback) (sound_obj, user_data);
}
}
}
}
// Return the true/false result code
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Is_Sound_In_Playlist
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Is_Sound_In_Playlist (AudibleSoundClass *sound_obj)
{
// Assume failure
bool retval = false;
// Loop through all the entries in the playlist
for (int index = 0; (index < m_Playlist.Count ()) && (retval == false); index ++) {
if (sound_obj == m_Playlist[index]) {
retval = true;
}
}
// Return the true/false result code
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Reprioritize_Playlist
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Reprioritize_Playlist (void)
{
AudibleSoundClass *sound_to_get_handle = NULL;
float hightest_priority = 0;
// Loop through all the entries in the playlist
for (int index = 0; index < m_Playlist.Count (); index ++) {
// Is this the highest priority without a miles handle?
AudibleSoundClass *sound_obj = m_Playlist[index];
if ((sound_obj->Get_Miles_Handle () == NULL) &&
(sound_obj->Is_Sound_Culled () == false) &&
(sound_obj->Get_Priority () > hightest_priority))
{
// This is now the highest priority sound effect without
// a play-handle.
sound_to_get_handle = sound_obj;
hightest_priority = sound_obj->Get_Priority ();
}
}
// Get a new handle for this sound if necessary
if (sound_to_get_handle != NULL) {
sound_to_get_handle->Allocate_Miles_Handle ();
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// On_Frame_Update
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::On_Frame_Update (unsigned int milliseconds)
{
//
// Free any sounds we completed last frame
//
Free_Completed_Sounds ();
//
// Calculate the time in ms since the last frame
//
unsigned int time_delta = milliseconds;
if (time_delta == 0) {
time_delta = WW3D::Get_Frame_Time ();
}
if (m_SoundScene != NULL) {
m_SoundScene->On_Frame_Update (milliseconds);
m_SoundScene->Collect_Logical_Sounds ();
}
//
// Loop through all the entries in the playlist
//
for (int index = 0; index < m_Playlist.Count (); index ++) {
//
// Update this sound object
//
AudibleSoundClass *sound_obj = m_Playlist[index];
sound_obj->On_Frame_Update (time_delta);
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Release_2D_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Release_2D_Handles (void)
{
MMSLockClass lock;
// Release our hold on all the samples we've allocated
for (int index = 0; index < m_2DSampleHandles.Count (); index ++) {
HSAMPLE sample = m_2DSampleHandles[index];
if (sample != NULL) {
::AIL_release_sample_handle (sample);
}
}
m_2DSampleHandles.Delete_All ();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Allocate_2D_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Allocate_2D_Handles (void)
{
MMSLockClass lock;
// Start fresh
Release_2D_Handles ();
if (m_Driver2D != NULL) {
// Attempt to allocate our share of 2D sample handles
for (int index = 0; index < m_Max2DSamples; index ++) {
HSAMPLE sample = ::AIL_allocate_sample_handle (m_Driver2D);
if (sample != NULL) {
::AIL_set_sample_user_data (sample, INFO_OBJECT_PTR, NULL);
m_2DSampleHandles.Add (sample);
}
}
// Record our actual number of available 2D sample handles
m_Max2DSamples = m_2DSampleHandles.Count ();
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_2D_Sample
//
////////////////////////////////////////////////////////////////////////////////////////////
HSAMPLE
WWAudioClass::Get_2D_Sample (const AudibleSoundClass &sound_obj)
{
if (Is_OK_To_Give_Handle (sound_obj) == false) {
return (HSAMPLE)INVALID_MILES_HANDLE;
}
MMSLockClass lock;
float lowest_priority = sound_obj.Get_Priority ();
float lowest_runtime_priority = sound_obj.Get_Runtime_Priority ();
AudibleSoundClass *lowest_pri_sound = NULL;
HSAMPLE lowest_pri_sample = NULL;
HSAMPLE free_sample = (HSAMPLE)INVALID_MILES_HANDLE;
// Loop through all the available sample handles and try to find
// one that isn't being used to play a sound.
bool found = false;
for (int index = 0; (index < m_2DSampleHandles.Count ()) && !found; index ++) {
HSAMPLE sample = m_2DSampleHandles[index];
if (sample != NULL) {
// Get a pointer to the object that is currently using this sample
AudibleSoundClass *sound_obj = (AudibleSoundClass *)::AIL_sample_user_data (sample, INFO_OBJECT_PTR);
if (sound_obj == NULL) {
// Return this sample handle to the caller
free_sample = sample;
found = true;
} else {
//
// Determine if this sound's priority is lesser then the sound we want to play.
// This is done by comparing both the designer-specified priority and the current
// runtime priority (which is calculated by distance to the listener).
//
float priority = sound_obj->Get_Priority ();
float runtime_priority = sound_obj->Get_Runtime_Priority ();
if ( (priority < lowest_priority) ||
(priority == lowest_priority && runtime_priority <= lowest_runtime_priority))
{
lowest_priority = priority;
lowest_pri_sound = sound_obj;
lowest_pri_sample = sample;
lowest_runtime_priority = runtime_priority;
}
}
}
}
// Steal the sample handle from the lower priority
// sound and return the handle to the caller.
if ((found == false) && (lowest_pri_sound != NULL)) {
lowest_pri_sound->Free_Miles_Handle ();
free_sample = lowest_pri_sample;
}
// Return the free sample handle if we found one
return free_sample;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_3D_Sample
//
////////////////////////////////////////////////////////////////////////////////////////////////
H3DSAMPLE
WWAudioClass::Get_3D_Sample (const Sound3DClass &sound_obj)
{
if (Is_OK_To_Give_Handle (sound_obj) == false) {
return (H3DSAMPLE)INVALID_MILES_HANDLE;
}
MMSLockClass lock;
float lowest_priority = sound_obj.Get_Priority ();
float lowest_runtime_priority = sound_obj.Get_Runtime_Priority ();
AudibleSoundClass *lowest_pri_sound = NULL;
H3DSAMPLE lowest_pri_sample = NULL;
H3DSAMPLE free_sample = (H3DSAMPLE)INVALID_MILES_HANDLE;
// Loop through all the available sample handles and try to find
// one that isn't being used to play a sound.
bool found = false;
for (int index = 0; (index < m_3DSampleHandles.Count ()) && !found; index ++) {
H3DSAMPLE sample = m_3DSampleHandles[index];
if (sample != NULL) {
// Get a pointer to the object that is currently using this sample
AudibleSoundClass *sound_obj = (AudibleSoundClass *)::AIL_3D_object_user_data (sample, INFO_OBJECT_PTR);
if (sound_obj == NULL) {
// Return this sample handle to the caller
free_sample = sample;
found = true;
} else {
//
// Determine if this sound's priority is lesser then the sound we want to play.
// This is done by comparing both the designer-specified priority and the current
// runtime priority (which is calculated by distance to the listener).
//
float priority = sound_obj->Get_Priority ();
float runtime_priority = sound_obj->Get_Runtime_Priority ();
if ( (priority < lowest_priority) ||
(priority == lowest_priority && runtime_priority <= lowest_runtime_priority))
{
lowest_priority = priority;
lowest_pri_sound = sound_obj;
lowest_pri_sample = sample;
lowest_runtime_priority = runtime_priority;
}
}
}
}
// Steal the sample handle from the lower priority
// sound and return the handle to the caller.
if ((found == false) && (lowest_pri_sound != NULL)) {
lowest_pri_sound->Free_Miles_Handle ();
free_sample = lowest_pri_sample;
}
// Return the free sample handle if we found one
return free_sample;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_Listener_Handle
//
////////////////////////////////////////////////////////////////////////////////////////////////
H3DPOBJECT
WWAudioClass::Get_Listener_Handle (void)
{
MMSLockClass lock;
return ::AIL_3D_open_listener (m_Driver3D);
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Build_3D_Driver_List
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Build_3D_Driver_List (void)
{
MMSLockClass lock;
HPROENUM next = HPROENUM_FIRST;
HPROVIDER provider = NULL;
char *name = NULL;
while (::AIL_enumerate_3D_providers (&next, &provider, &name) > 0) {
// Can we successfully open this provider?
if (::AIL_open_3D_provider (provider) == M3D_NOERR) {
DRIVER_INFO_STRUCT *info = W3DNEW DRIVER_INFO_STRUCT;
info->driver = provider;
info->name = ::strdup (name);
m_Driver3DList.Add (info);
::AIL_close_3D_provider (provider);
} else {
char *error_info = ::AIL_last_error ();
WWDEBUG_SAY (("WWAudio: Unable to open %s.\r\n", name));
WWDEBUG_SAY (("WWAudio: Reason %s.\r\n", error_info));
}
}
// Attempt to select one of the known drivers (in the following order).
if ((Select_3D_Device (DRIVER3D_A3D) == false) &&
(Select_3D_Device (DRIVER3D_EAX) == false) &&
(Select_3D_Device (DRIVER3D_D3DSOUND) == false) &&
(Select_3D_Device (DRIVER3D_DOLBY) == false)) {
// Couldn't select a known driver, so just use the first possible.
if (m_Driver3DList.Count () > 0) {
Select_3D_Device ((int)0);
//DRIVER_INFO_STRUCT *info = m_Driver3DList[0];
//m_Driver3D = info->driver;
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Free_3D_Driver_List
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Free_3D_Driver_List (void)
{
MMSLockClass lock;
//
// Remove all the handles
//
Remove_3D_Sound_Handles ();
Release_3D_Handles ();
//
// Loop through all the driver entries and free them all
//
for (int index = 0; index < m_Driver3DList.Count (); index ++) {
DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
if (info != NULL) {
//
// Free the information we have stored with this driver
//
if (info->name != NULL) {
::free (info->name);
}
delete info;
}
}
if (m_Driver3D != NULL) {
::AIL_close_3D_provider (m_Driver3D);
m_Driver3D = NULL;
}
//
// Clear the list
//
m_Driver3DList.Delete_All ();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Select_3D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Select_3D_Device (const char *device_name)
{
bool retval = false;
//
// Loop through all the drivers until we've found the one we want
//
for (int index = 0; index < m_Driver3DList.Count (); index ++) {
DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
if (info != NULL) {
//
// Is this the device we were looking for?
//
if (::lstrcmpi (info->name, device_name) == 0) {
retval = Select_3D_Device (device_name, info->driver);
break;
}
}
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Select_3D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Select_3D_Device (const char *device_name, HPROVIDER provider)
{
bool retval = false;
if ((provider != NULL) && (provider != m_Driver3D)) {
//
// Remove all the handles
//
Remove_3D_Sound_Handles ();
Release_3D_Handles ();
//
// Close the previous driver if needs be
//
if (m_Driver3D != NULL) {
::AIL_close_3D_provider (m_Driver3D);
m_Driver3D = NULL;
}
//
// Select this device and re-allocate all handles
//
if (::AIL_open_3D_provider (provider) == M3D_NOERR) {
m_Driver3D = provider;
m_SoundScene->Initialize ();
Allocate_3D_Handles ();
AIL_set_3D_speaker_type (provider, AIL_3D_2_SPEAKER);
//
// Adjust the effects level to 1.0 if this is an EAX based driver
//
StringClass lower_name = device_name;
::strlwr (lower_name.Peek_Buffer ());
if (::strstr (device_name, "eax") != 0) {
m_EffectsLevel = 1.0F;
} else {
m_EffectsLevel = 0.0F;
}
}
retval = true;
}
// Return true if we successfully selected the device
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Select_3D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Select_3D_Device (int index)
{
bool retval = false;
//
// Index valid?
//
if ((index >= 0) && (index < m_Driver3DList.Count ())) {
Select_3D_Device (m_Driver3DList[index]->name, m_Driver3DList[index]->driver);
WWDEBUG_SAY (("WWAudio: Selecting 3D sound device: %s.\r\n", m_Driver3DList[index]->name));
retval = true;
}
//
// Return true if we successfully selected the device
//
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Select_3D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Select_3D_Device (DRIVER_TYPE_3D type)
{
// Return true if we successfully selected the device
return Select_3D_Device (Find_3D_Device (type));
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Find_3D_Device
//
////////////////////////////////////////////////////////////////////////////////////////////////
int
WWAudioClass::Find_3D_Device (DRIVER_TYPE_3D type)
{
// Determine which substring to search for in the
// name of the driver.
const char *sub_string = "RSX";
switch (type) {
case DRIVER3D_D3DSOUND:
sub_string = "DirectSound";
break;
case DRIVER3D_EAX:
sub_string = "EAX";
break;
case DRIVER3D_A3D:
sub_string = "A3D";
break;
case DRIVER3D_PSEUDO:
sub_string = "Fast";
break;
case DRIVER3D_DOLBY:
sub_string = "Dolby";
break;
}
// Loop through all the driver entries and free them all
int driver_index = -1;
for (int index = 0; (index < m_Driver3DList.Count ()) && (driver_index == -1); index ++) {
DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
if ((info != NULL) && (info->name != NULL)) {
// Is this the driver we were looking for?
if (::strstr (info->name, sub_string) != NULL) {
driver_index = index;
}
}
}
// Return -1 if not found, otherwise the 0 based index
return driver_index;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Allocate_3D_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Allocate_3D_Handles (void)
{
MMSLockClass lock;
// Start fresh
Release_3D_Handles ();
if (m_Driver3D != NULL) {
// Attempt to allocate our share of 3D sample handles
for (int index = 0; index < m_Max3DSamples; index ++) {
H3DSAMPLE sample = ::AIL_allocate_3D_sample_handle (m_Driver3D);
if (sample != NULL) {
::AIL_set_3D_object_user_data (sample, INFO_OBJECT_PTR, NULL);
m_3DSampleHandles.Add (sample);
}
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Release_3D_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Release_3D_Handles (void)
{
MMSLockClass lock;
//
// Release our hold on all the samples we've allocated
//
for (int index = 0; index < m_3DSampleHandles.Count (); index ++) {
H3DSAMPLE sample = m_3DSampleHandles[index];
if (sample != NULL) {
::AIL_release_3D_sample_handle (sample);
}
}
m_3DSampleHandles.Delete_All ();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Validate_3D_Sound_Buffer
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Validate_3D_Sound_Buffer (SoundBufferClass *buffer)
{
bool retval = false;
//
// 3D sound buffer MUST be uncompressed mono WAV data
//
if ((buffer != NULL) &&
(buffer->Get_Channels () == 1) &&
(buffer->Get_Type () == WAVE_FORMAT_PCM) &&
(buffer->Is_Streaming () == false))
{
retval = true;
}
// Return a true/false result code
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// ReAssign_2D_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::ReAssign_2D_Handles (void)
{
// Loop through all the entries in the playlist
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
// If this is a 2D sound effect, then force it to 'get' a new
// sound handle.
if ((sound_obj->Get_Class_ID () == CLASSID_2D) ||
(sound_obj->Get_Class_ID () == CLASSID_PSEUDO3D) ||
(sound_obj->Get_Class_ID () == CLASSID_2DTRIGGER))
{
sound_obj->Free_Miles_Handle ();
sound_obj->Allocate_Miles_Handle ();
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// ReAssign_3D_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::ReAssign_3D_Handles (void)
{
// Loop through all the entries in the playlist
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
// If this is a 3D sound effect, then force it to 'get' a new
// sound handle.
if (sound_obj->Get_Class_ID () == CLASSID_3D) {
sound_obj->Free_Miles_Handle ();
sound_obj->Allocate_Miles_Handle ();
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Remove_2D_Sound_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Remove_2D_Sound_Handles (void)
{
// Loop through all the entries in the playlist
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
// If this is a 2D sound effect, then take its handle away
if (sound_obj->Get_Class_ID () == CLASSID_2D) {
sound_obj->Free_Miles_Handle ();
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Remove_3D_Sound_Handles
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Remove_3D_Sound_Handles (void)
{
// Loop through all the entries in the playlist
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
// If this is a 3D sound effect, then force take its handle away
if (sound_obj->Get_Class_ID () == CLASSID_3D) {
sound_obj->Free_Miles_Handle ();
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Set_Sound_Effects_Volume
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Set_Sound_Effects_Volume (float volume)
{
m_SoundVolume = volume;
m_SoundVolume = min (1.0F, m_SoundVolume);
m_SoundVolume = max (0.0F, m_SoundVolume);
// Update all the currently playing 'Sound Effects' to
// reflect this new volume
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_SOUND_EFFECT) {
sound_obj->Update_Volume ();
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Set_Music_Volume
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Set_Music_Volume (float volume)
{
m_MusicVolume = volume;
m_MusicVolume = min (1.0F, m_MusicVolume);
m_MusicVolume = max (0.0F, m_MusicVolume);
// Update all currently playing music to
// reflect this new volume
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_MUSIC) {
sound_obj->Update_Volume ();
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Is_Disabled
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Is_Disabled (void) const
{
static bool _firsttime = true;
static bool _disabled = false;
if (_firsttime) {
_firsttime = false;
#ifdef G_CODE_BASE
//
// Use command line arguement.
//
ArgvClass argv;
if (argv.Find("-NOAUDIO")) {
_disabled = true;
}
#endif
//
// Read the disabled key from the registry
//
RegistryClass registry ("SOFTWARE\\Westwood\\WWAudio");
if (registry.Is_Valid ()) {
if (registry.Get_Int ("Disabled", 0) == 1) {
_disabled = true;
WWDEBUG_SAY (("WWAudio: Audio system disabled in registry.\r\n"));
}
}
}
return _disabled;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Initialize (const char *registry_subkey_name)
{
WWMEMLOG(MEM_SOUND);
if (Is_Disabled () == false) {
//
// Initialize the audio system from the registry settings
//
Load_From_Registry (registry_subkey_name);
//
// Grab the first (and only) filter for use with our 'tinny' effect.
//
HPROENUM next = HPROENUM_FIRST;
char *name = NULL;
if (::AIL_enumerate_filters (&next, &m_ReverbFilter, &name) == 0) {
m_ReverbFilter = INVALID_MILES_HANDLE;
}
}
//
// Register the file callbacks so we can support streaming from MIX files...
//
::AIL_set_file_callbacks (File_Open_Callback, File_Close_Callback,
File_Seek_Callback, File_Read_Callback);
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Initialize
(
bool stereo,
int bits,
int hertz
)
{
// Open the default 2D device, then build a list of 3D
// devices and open the default.
if (Is_Disabled () == false) {
Open_2D_Device (stereo, bits, hertz);
Build_3D_Driver_List ();
//
// Grab the first (and only) filter for use with our 'tinny' effect.
//
HPROENUM next = HPROENUM_FIRST;
char *name = NULL;
if (::AIL_enumerate_filters (&next, &m_ReverbFilter, &name) == 0) {
m_ReverbFilter = INVALID_MILES_HANDLE;
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Shutdown (void)
{
//
// If there is a timer running, then stop the timer...
//
if (m_UpdateTimer != -1) {
// Kill the timer
::AIL_stop_timer (m_UpdateTimer);
::AIL_release_timer_handle (m_UpdateTimer);
m_UpdateTimer = -1;
// Wait for the timer callback function to end
::WaitForSingleObject (_TimerSyncEvent, 20000);
::CloseHandle (_TimerSyncEvent);
_TimerSyncEvent = NULL;
}
//
// Stop all sounds from playing
//
Flush_Playlist ();
if (m_SoundScene != NULL) {
m_SoundScene->Flush_Scene ();
}
//
// Free all our cached sound buffers
//
Flush_Cache ();
//
// Close-out our hold on any driver resources
//
Remove_2D_Sound_Handles ();
Remove_3D_Sound_Handles ();
Release_2D_Handles ();
Release_3D_Handles ();
Free_3D_Driver_List ();
SAFE_DELETE (m_SoundScene);
Close_2D_Device ();
//
// Shutdown Miles Sound System
//
::AIL_shutdown ();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Register_EOS_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Register_EOS_Callback (LPFNEOSCALLBACK callback, DWORD user_param)
{
m_EOSCallbackList.Add_Callback (callback, user_param);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// UnRegister_EOS_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::UnRegister_EOS_Callback (LPFNEOSCALLBACK callback)
{
m_EOSCallbackList.Remove_Callback (callback);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Register_Text_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Register_Text_Callback (LPFNTEXTCALLBACK callback, DWORD user_param)
{
m_TextCallbackList.Add_Callback (callback, user_param);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// UnRegister_Text_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::UnRegister_Text_Callback (LPFNTEXTCALLBACK callback)
{
m_TextCallbackList.Remove_Callback (callback);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Fire_Text_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Fire_Text_Callback (AudibleSoundClass *sound_obj, const StringClass &text)
{
if (text.Get_Length () > 0) {
//
// Loop over all the text-callbacks that have been registered
//
for (int index = 0; index < m_TextCallbackList.Count (); index ++) {
uint32 user_data = 0L;
LPFNTEXTCALLBACK callback = m_TextCallbackList.Get_Callback (index, &user_data);
if (callback != NULL) {
//
// Fire the notification
//
(*callback) (sound_obj, text, user_data);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Allow_Sound_Effects
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Allow_Sound_Effects (bool onoff)
{
// Is the state changing?
if (m_AreSoundEffectsEnabled != onoff) {
m_AreSoundEffectsEnabled = onoff;
// Update all the currently playing 'Sound Effects' to
// reflect this new state.
if (m_AreSoundEffectsEnabled) {
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_SOUND_EFFECT) {
sound_obj->Allocate_Miles_Handle ();
}
}
} else {
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_SOUND_EFFECT) {
sound_obj->Free_Miles_Handle ();
}
}
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Allow_Music
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Allow_Music (bool onoff)
{
// Is the state changing?
if (m_IsMusicEnabled != onoff) {
m_IsMusicEnabled = onoff;
// Update all the currently playing 'music tracks' to
// reflect this new state.
if (m_IsMusicEnabled) {
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_MUSIC) {
sound_obj->Stop (false);
sound_obj->Play ();
}
}
} else {
for (int index = 0; index < m_Playlist.Count (); index ++) {
AudibleSoundClass *sound_obj = m_Playlist[index];
if (sound_obj->Get_Type () == AudibleSoundClass::TYPE_MUSIC) {
sound_obj->Free_Miles_Handle ();
}
}
}
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Simple_Play_2D_Sound_Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Simple_Play_2D_Sound_Effect
(
const char *filename,
float priority,
float volume
)
{
bool retval = false;
AudibleSoundClass *sound = Create_Sound_Effect (filename);
if (sound != NULL) {
sound->Set_Priority (priority);
sound->Set_Loop_Count (1);
sound->Set_Volume(volume);
sound->Play ();
sound->Release_Ref ();
sound = NULL;
retval = true;
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Simple_Play_2D_Sound_Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Simple_Play_2D_Sound_Effect
(
FileClass &file,
float priority,
float volume
)
{
bool retval = false;
AudibleSoundClass *sound = Create_Sound_Effect (file);
if (sound != NULL) {
sound->Set_Priority (priority);
sound->Set_Loop_Count (1);
sound->Set_Volume(volume);
sound->Play ();
sound->Release_Ref ();
sound = NULL;
retval = true;
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_File
//
////////////////////////////////////////////////////////////////////////////////////////////////
FileClass *
WWAudioClass::Get_File (LPCTSTR filename)
{
FileClass *file = NULL;
if (m_FileFactory != NULL) {
file = m_FileFactory->Get_File (filename);
} else {
file = _TheFileFactory->Get_File(filename);
}
// Return a pointer to the file
return file;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Return_File
//
////////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Return_File (FileClass *file)
{
if (m_FileFactory != NULL) {
m_FileFactory->Return_File (file);
} else {
SAFE_DELETE (file);
}
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Logical_Sound
//
////////////////////////////////////////////////////////////////////////////////////////////
LogicalSoundClass *
WWAudioClass::Create_Logical_Sound (void)
{
return W3DNEW LogicalSoundClass;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Create_Logical_Listener
//
////////////////////////////////////////////////////////////////////////////////////////////
LogicalListenerClass *
WWAudioClass::Create_Logical_Listener (void)
{
return W3DNEW LogicalListenerClass;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Add_Logical_Type
//
////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Add_Logical_Type (int id, LPCTSTR display_name)
{
m_LogicalTypes.Add (LOGICAL_TYPE_STRUCT (id, display_name));
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Reset_Logical_Types
//
////////////////////////////////////////////////////////////////////////////////////////////
void
WWAudioClass::Reset_Logical_Types (void)
{
m_LogicalTypes.Delete_All ();
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Get_Logical_Type
//
////////////////////////////////////////////////////////////////////////////////////////////
int
WWAudioClass::Get_Logical_Type (int index, StringClass &name)
{
int type_id = 0;
WWASSERT (index >= 0 && index < m_LogicalTypes.Count ());
if (index >= 0 && index < m_LogicalTypes.Count ()) {
type_id = m_LogicalTypes[index].id;
name = m_LogicalTypes[index].display_name;
}
return type_id;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Find_Sound_Object
//
////////////////////////////////////////////////////////////////////////////////////////////
SoundSceneObjClass *
WWAudioClass::Find_Sound_Object (uint32 sound_obj_id)
{
SoundSceneObjClass *sound_obj = NULL;
//
// Lookup the sound object and return it to the caller
//
int index = 0;
if (SoundSceneObjClass::Find_Sound_Object (sound_obj_id, &index)) {
sound_obj = SoundSceneObjClass::m_GlobalSoundList[index];
}
return sound_obj;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Load_From_Registry
//
////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Load_From_Registry (const char *subkey_name)
{
bool retval = true;
StringClass device_name;
bool is_stereo = true;
int bits = 16;
int hertz = 44100;
//
// Load the settings from the registry
//
if (Load_From_Registry (subkey_name, device_name, is_stereo, bits, hertz,
m_AreSoundEffectsEnabled, m_IsMusicEnabled, m_SoundVolume, m_MusicVolume))
{
//
// Close any open devices
//
Free_3D_Driver_List ();
Close_2D_Device ();
//
// Open the 2D device as specified
//
Open_2D_Device (is_stereo, bits, hertz);
//
// Find and open the 3D device specified
//
Build_3D_Driver_List ();
Select_3D_Device (device_name);
retval = true;
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Load_From_Registry
//
////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Load_From_Registry
(
const char * subkey_name,
StringClass & device_name,
bool & is_stereo,
int & bits,
int & hertz,
bool & sound_enabled,
bool & music_enabled,
float & sound_volume,
float & music_volume
)
{
bool retval = false;
//
// Attempt to open the registry key
//
RegistryClass registry (subkey_name);
if (registry.Is_Valid ()) {
//
// Read the device name into a string object
//
char temp_buffer[256] = { 0 };
registry.Get_String (VALUE_NAME_DEVICE_NAME, temp_buffer, sizeof (temp_buffer));
device_name = temp_buffer;
//
// Read the 2D settings
//
is_stereo = (registry.Get_Int (VALUE_NAME_IS_STEREO, true) == 1);
bits = registry.Get_Int (VALUE_NAME_BITS, 16);
hertz = registry.Get_Int (VALUE_NAME_HERTZ, 44100);
//
// Read the sound/music enabled settings
//
music_enabled = (registry.Get_Int (VALUE_NAME_MUSIC_ENABLED, 1) == 1);
sound_enabled = (registry.Get_Int (VALUE_NAME_SOUND_ENABLED, 1) == 1);
//
// Read the volume information
//
music_volume = registry.Get_Int (VALUE_NAME_MUSIC_VOL, 100) / 100.0F;
sound_volume = registry.Get_Int (VALUE_NAME_SOUND_VOL, 100) / 100.0F;
music_volume = WWMath::Clamp (music_volume, 0, 1.0F);
sound_volume = WWMath::Clamp (sound_volume, 0, 1.0F);
retval = true;
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Save_To_Registry
//
////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Save_To_Registry (const char *subkey_name)
{
StringClass device_name;
//
// Get the name of the current 3D driver
//
for (int index = 0; index < m_Driver3DList.Count (); index ++) {
DRIVER_INFO_STRUCT *info = m_Driver3DList[index];
//
// Is this the device we were looking for?
//
if (info != NULL && info->driver == m_Driver3D) {
device_name = info->name;
break;
}
}
//
// Save these settings to the registry
//
return Save_To_Registry (subkey_name, device_name, m_PlaybackStereo, m_PlaybackBits, m_PlaybackRate,
m_AreSoundEffectsEnabled, m_IsMusicEnabled, m_SoundVolume, m_MusicVolume);
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Save_To_Registry
//
////////////////////////////////////////////////////////////////////////////////////////////
bool
WWAudioClass::Save_To_Registry
(
const char * subkey_name,
const StringClass & device_name,
bool is_stereo,
int bits,
int hertz,
bool sound_enabled,
bool music_enabled,
float sound_volume,
float music_volume
)
{
bool retval = false;
//
// Attempt to open the registry key
//
RegistryClass registry (subkey_name);
if (registry.Is_Valid ()) {
//
// Save the settings to the registry
//
registry.Set_String (VALUE_NAME_DEVICE_NAME, device_name);
registry.Set_Int (VALUE_NAME_IS_STEREO, is_stereo);
registry.Set_Int (VALUE_NAME_BITS, bits);
registry.Set_Int (VALUE_NAME_HERTZ, hertz);
registry.Set_Int (VALUE_NAME_MUSIC_ENABLED, music_enabled);
registry.Set_Int (VALUE_NAME_SOUND_ENABLED, sound_enabled);
registry.Set_Int (VALUE_NAME_MUSIC_VOL, music_volume * 100);
registry.Set_Int (VALUE_NAME_SOUND_VOL, sound_volume * 100);
retval = true;
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// File_Open_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////
U32 AILCALLBACK
WWAudioClass::File_Open_Callback (char const *filename, U32 *file_handle)
{
U32 retval = false;
if (Get_Instance () != NULL) {
//
// Open the file
//
FileClass *file = Get_Instance ()->Get_File (filename);
if (file != NULL && file->Open ()) {
(*file_handle) = (U32)file;
retval = true;
}
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// File_Close_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////
void AILCALLBACK
WWAudioClass::File_Close_Callback (U32 file_handle)
{
if (Get_Instance () != NULL) {
//
// Close the file (if necessary)
//
FileClass *file = reinterpret_cast (file_handle);
if (file != NULL) {
Get_Instance ()->Return_File (file);
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// File_Seek_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////
S32 AILCALLBACK
WWAudioClass::File_Seek_Callback (U32 file_handle, S32 offset, U32 type)
{
S32 retval = 0;
//
// Convert the handle to a file handle type
//
FileClass *file = reinterpret_cast (file_handle);
if (file != NULL) {
//
// Convert the Miles seek type to one of our own
//
int seek_type = SEEK_CUR;
switch (type)
{
case AIL_FILE_SEEK_BEGIN:
seek_type = SEEK_SET;
break;
case AIL_FILE_SEEK_CURRENT:
seek_type = SEEK_CUR;
break;
case AIL_FILE_SEEK_END:
seek_type = SEEK_END;
break;
}
//
// Perform the seek
//
retval = file->Seek (offset, seek_type);
}
return retval;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// File_Read_Callback
//
////////////////////////////////////////////////////////////////////////////////////////////
U32 AILCALLBACK
WWAudioClass::File_Read_Callback (U32 file_handle, void *buffer, U32 bytes)
{
U32 retval = 0;
//
// Convert the handle to a file handle type
//
FileClass *file = reinterpret_cast (file_handle);
if (file != NULL) {
//
// Read the bytes from the file
//
retval = file->Read (buffer, bytes);
}
return retval;
}