Files
source/Standard Gaming Platform/soundman.cpp
T

3248 lines
96 KiB
C++

/*********************************************************************************
* SGP Digital Sound Module
*
* This module handles the playing of digital samples, preloaded or streamed.
*
* Derek Beland, May 28, 1997
*********************************************************************************/
#ifdef JA2_PRECOMPILED_HEADERS
#include "JA2 SGP ALL.H"
#include "Debug Control.h"
#elif defined( WIZ8_PRECOMPILED_HEADERS )
#include "WIZ8 SGP ALL.H"
#else
#include <stdio.h>
#include <string.h>
#include "soundman.h"
#include "FileMan.h"
#include "debug.h"
#include "MemMan.h"
#include "mss.h"
#include "random.h"
#include "Debug Control.h"
#endif
// Uncomment this to disable the startup of sound hardware
//#define SOUND_DISABLE
#pragma pack(push,1)
// WAV file chunk definitions
typedef struct {
// General chunk header
CHAR8 cTag[4];
UINT32 uiChunkSize;
} WAVCHUNK;
typedef struct {
// WAV header
CHAR8 cRiff[4]; // "RIFF"
UINT32 uiChunkSize; // Chunk length
CHAR8 cFileType[4]; // "WAVE"
} WAVRIFF;
typedef struct {
// FMT chunk
CHAR8 cFormat[4]; // "FMT "
UINT32 uiChunkSize; // Chunk length
UINT16 uiStereo; // 1 if stereo, 0 if mono (Not reliable, use channels instead)
UINT16 uiChannels; // number of channels used 1=mono, 2=stereo, etc.
UINT32 uiSpeed; // Sampling Rate (speed)
UINT32 uiBytesSec; // Number of bytes per sec
UINT16 uiBytesSample; // Number of bytes per sample (1 = 8 bit mono,
// 2 = 8 bit stereo or 16 bit mono, 4 = 16 bit stereo
UINT16 uiBitsSample; // bits per sample
} WAVFMT;
typedef struct {
// Data chunk
CHAR8 cName[4]; // "DATA"
UINT32 uiChunkSize; // Chunk length
} WAVDATA;
#pragma pack(pop)
#define WAV_CHUNK_RIFF 0
#define WAV_CHUNK_FMT 1
#define WAV_CHUNK_DATA 2
#define NUM_WAV_CHUNKS 3
CHAR8 *cWAVChunks[3]={"RIFF", "FMT ", "DATA"};
// global settings
#define SOUND_MAX_CACHED 128 // number of cache slots
#ifdef JA2
#define SOUND_MAX_CHANNELS 16 // number of mixer channels
#else
#define SOUND_MAX_CHANNELS 32 // number of mixer channels
#endif
#pragma message("TEMP!")
#define SOUND_DEFAULT_MEMORY (8048*1024) // default memory limit
#define SOUND_DEFAULT_THRESH (256*8024) // size for sample to be double-buffered
#define SOUND_DEFAULT_STREAM (64*1024) // double-buffered buffer size
/*#define SOUND_DEFAULT_MEMORY (2048*1024) // default memory limit
#define SOUND_DEFAULT_THRESH (256*1024) // size for sample to be double-buffered
#define SOUND_DEFAULT_STREAM (64*1024) // double-buffered buffer size
*/
// playing/random value to indicate default
#define SOUND_PARMS_DEFAULT 0xffffffff
// Sound status flags
#define SOUND_CALLBACK 0x00000008
// Local Function Prototypes
BOOLEAN SoundInitCache(void);
BOOLEAN SoundShutdownCache(void);
UINT32 SoundLoadSample(STR pFilename);
UINT32 SoundFreeSample(STR pFilename);
UINT32 SoundGetCached(STR pFilename);
UINT32 SoundLoadDisk(STR pFilename);
// Low level
UINT32 SoundGetEmptySample(void);
BOOLEAN SoundProcessWAVHeader(UINT32 uiSample);
UINT32 SoundFreeSampleIndex(UINT32 uiSample);
UINT32 SoundGetIndexByID(UINT32 uiSoundID);
static HDIGDRIVER SoundInitDriver(UINT32 uiRate, UINT16 uiBits, UINT16 uiChans);
BOOLEAN SoundInitHardware(void);
BOOLEAN SoundGetDriverName(HDIGDRIVER DIG, CHAR8 *cBuf);
BOOLEAN SoundShutdownHardware(void);
UINT32 SoundGetFreeChannel(void);
UINT32 SoundStartSample(UINT32 uiSample, UINT32 uiChannel, SOUNDPARMS *pParms);
UINT32 SoundStartStream(STR pFilename, UINT32 uiChannel, SOUNDPARMS *pParms);
UINT32 SoundGetUniqueID(void);
BOOLEAN SoundPlayStreamed(STR pFilename);
BOOLEAN SoundCleanCache(void);
BOOLEAN SoundSampleIsPlaying(UINT32 uiSample);
BOOLEAN SoundIndexIsPlaying(UINT32 uiSound);
BOOLEAN SoundStopIndex(UINT32 uiSound);
UINT32 SoundGetVolumeIndex(UINT32 uiChannel);
BOOLEAN SoundSetVolumeIndex(UINT32 uiChannel, UINT32 uiVolume);
// Global variables
UINT32 guiSoundDefaultVolume = 127;
UINT32 guiSoundMemoryLimit=SOUND_DEFAULT_MEMORY; // Maximum memory used for sounds
UINT32 guiSoundMemoryUsed=0; // Memory currently in use
UINT32 guiSoundCacheThreshold=SOUND_DEFAULT_THRESH; // Double-buffered threshold
HDIGDRIVER hSoundDriver; // Sound driver handle
BOOLEAN fDirectSound=TRUE; // Using Direct Sound
// Local module variables
BOOLEAN fSoundSystemInit=FALSE; // Startup called T/F
BOOLEAN gfEnableStartup=TRUE; // Allow hardware to starup
// Sample cache list for files loaded
SAMPLETAG pSampleList[SOUND_MAX_CACHED];
// Sound channel list for output channels
SOUNDTAG pSoundList[SOUND_MAX_CHANNELS];
// 3D sound globals
CHAR8 *gpProviderName=NULL;
HPROVIDER gh3DProvider=0;
H3DPOBJECT gh3DListener=0;
BOOLEAN gfUsingEAX=TRUE;
UINT32 guiRoomTypeIndex=0;
CHAR8* pEAXRoomTypes[EAXROOMTYPE_NUM_TYPES] =
{
// None
"PLAIN",
// S,M,L Cave
"STONECORRIDOR",
"CAVE",
"CONCERTHALL",
// S,M,L Room
"LIVINGROOM",
"ROOM",
"AUDITORIUM",
// Flat open, valley
"CITY",
"MOUNTAINS",
// Swimming
"UNDERWATER"
};
//*******************************************************************************
// High Level Interface
//*******************************************************************************
//*******************************************************************************
// SoundEnableSound
//
// Allows or disallows the startup of the sound hardware.
//
// Returns: Nothing.
//
//*******************************************************************************
void SoundEnableSound(BOOLEAN fEnable)
{
gfEnableStartup=fEnable;
}
//*******************************************************************************
// InitializeSoundManager
//
// Zeros out the structs for the system info, and initializes the cache.
//
// Returns: TRUE always
//
//*******************************************************************************
BOOLEAN InitializeSoundManager(void)
{
UINT32 uiCount;
if(fSoundSystemInit)
ShutdownSoundManager();
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
memset(&pSoundList[uiCount], 0, sizeof(SOUNDTAG));
#ifndef SOUND_DISABLE
if(gfEnableStartup && SoundInitHardware())
fSoundSystemInit=TRUE;
#endif
SoundInitCache();
guiSoundMemoryLimit=SOUND_DEFAULT_MEMORY;
guiSoundMemoryUsed=0;
guiSoundCacheThreshold=SOUND_DEFAULT_THRESH;
if(gpProviderName && !gh3DProvider)
Sound3DInitProvider(gpProviderName);
return(TRUE);
}
//*******************************************************************************
// ShutdownSoundManager
//
// Silences all currently playing sound, deallocates any memory allocated,
// and releases the sound hardware.
//
//*******************************************************************************
void ShutdownSoundManager(void)
{
if(gh3DProvider)
Sound3DShutdownProvider();
SoundStopAll();
SoundStopMusic();
SoundShutdownCache();
Sleep(1000);
SoundShutdownHardware();
//Sleep(1000);
fSoundSystemInit=FALSE;
}
//*******************************************************************************
// SoundPlay
//
// Starts a sample playing. If the sample is not loaded in the cache, it will
// be found and loaded. The pParms structure is used to
// override the attributes of the sample such as playback speed, and to specify
// a volume. Any entry containing SOUND_PARMS_DEFAULT will be set by the system.
//
// Returns: If the sound was started, it returns a sound ID unique to that
// instance of the sound
// If an error occured, SOUND_ERROR will be returned
//
//
// !!Note: Can no longer play streamed files
//
//*******************************************************************************
UINT32 SoundPlay(STR pFilename, SOUNDPARMS *pParms)
{
UINT32 uiSample, uiChannel;
if( fSoundSystemInit )
{
if( !SoundPlayStreamed(pFilename) )
{
if((uiSample=SoundLoadSample(pFilename))!=NO_SAMPLE)
{
if((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR)
{
return(SoundStartSample(uiSample, uiChannel, pParms));
}
}
}
else
{
//Trying to play a sound which is bigger then the 'guiSoundCacheThreshold'
// This line was causing a page fault in the Wiz 8 project, so
// I changed it to the second line, which works OK. -- DB
//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("\n*******\nSoundPlay(): ERROR: trying to play %s which is bigger then the 'guiSoundCacheThreshold', use SoundPlayStreamedFile() instead\n", pFilename ) );
FastDebugMsg(String("SoundPlay: ERROR: Trying to play %s sound is too lardge to load into cache, use SoundPlayStreamedFile() instead\n", pFilename ) );
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundPlayStreamedFile
//
// The sample will
// be played as a double-buffered sample. The pParms structure is used to
// override the attributes of the sample such as playback speed, and to specify
// a volume. Any entry containing SOUND_PARMS_DEFAULT will be set by the system.
//
// Returns: If the sound was started, it returns a sound ID unique to that
// instance of the sound
// If an error occured, SOUND_ERROR will be returned
//
//*******************************************************************************
UINT32 SoundPlayStreamedFile( STR pFilename, SOUNDPARMS *pParms )
{
UINT32 uiChannel;
HANDLE hRealFileHandle;
CHAR8 pFileHandlefileName[ 128 ];
HWFILE hFile;
UINT32 uiRetVal=FALSE;
if( fSoundSystemInit )
{
if((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR)
{
//Open the file
hFile = FileOpen( pFilename, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE );
if( !hFile )
{
FastDebugMsg(String("\n*******\nSoundPlayStreamedFile(): ERROR: Couldnt open '%s' in SoundPlayStreamedFile()\n", pFilename ) );
return( SOUND_ERROR );
}
// MSS cannot determine which provider to play if you don't give it a real filename
// so if the file isn't in a library, play it normally
if(DB_EXTRACT_LIBRARY(hFile) == REAL_FILE_LIBRARY_ID)
{
FileClose(hFile);
return(SoundStartStream( pFilename, uiChannel, pParms));
}
//Get the real file handle of the file
hRealFileHandle = GetRealFileHandleFromFileManFileHandle( hFile );
if( hRealFileHandle == 0 )
{
FastDebugMsg(String("\n*******\nSoundPlayStreamedFile(): ERROR: Couldnt get a real file handle for '%s' in SoundPlayStreamedFile()\n", pFilename ) );
return( SOUND_ERROR );
}
//Convert the file handle into a 'name'
sprintf( pFileHandlefileName, "\\\\\\\\%d", hRealFileHandle );
//Start the sound stream
uiRetVal = SoundStartStream( pFileHandlefileName, uiChannel, pParms);
//if it succeeded, record the file handle
if( uiRetVal != SOUND_ERROR )
pSoundList[uiChannel].hFile = hFile;
else
FileClose( hFile );
return( uiRetVal );
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundPlayRandom
//
// Registers a sample to be played randomly within the specified parameters.
// Parameters are passed in through pParms. Any parameter containing
// SOUND_PARMS_DEFAULT will be set by the system. Only the uiTimeMin entry may
// NOT be defaulted.
//
// * Samples designated "random" are ALWAYS loaded into the cache, and locked
// in place. They are never double-buffered, and this call will fail if they
// cannot be loaded. *
//
// Returns: If successful, it returns the sample index it is loaded to, else
// SOUND_ERROR is returned.
//
//*******************************************************************************
UINT32 SoundPlayRandom(STR pFilename, RANDOMPARMS *pParms)
{
UINT32 uiSample, uiTicks;
if(fSoundSystemInit)
{
if((uiSample=SoundLoadSample(pFilename))!=NO_SAMPLE)
{
pSampleList[uiSample].uiFlags|=(SAMPLE_RANDOM|SAMPLE_LOCKED);
if(pParms->uiTimeMin==SOUND_PARMS_DEFAULT)
return(SOUND_ERROR);
else
pSampleList[uiSample].uiTimeMin=pParms->uiTimeMin;
if(pParms->uiTimeMax==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiTimeMax=pParms->uiTimeMin;
else
pSampleList[uiSample].uiTimeMax=pParms->uiTimeMax;
pSampleList[uiSample].uiSpeedMin=pParms->uiSpeedMin;
pSampleList[uiSample].uiSpeedMax=pParms->uiSpeedMax;
if(pParms->uiVolMin==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiVolMin=guiSoundDefaultVolume;
else
pSampleList[uiSample].uiVolMin=pParms->uiVolMin;
if(pParms->uiVolMax==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiVolMax=guiSoundDefaultVolume;
else
pSampleList[uiSample].uiVolMax=pParms->uiVolMax;
if(pParms->uiPanMin==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiPanMin=64;
else
pSampleList[uiSample].uiPanMin=pParms->uiPanMin;
if(pParms->uiPanMax==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiPanMax=64;
else
pSampleList[uiSample].uiPanMax=pParms->uiPanMax;
if(pParms->uiMaxInstances==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiMaxInstances=1;
else
pSampleList[uiSample].uiMaxInstances=pParms->uiMaxInstances;
if(pParms->uiPriority==SOUND_PARMS_DEFAULT)
pSampleList[uiSample].uiPriority=PRIORITY_RANDOM;
else
pSampleList[uiSample].uiPriority=pParms->uiPriority;
pSampleList[uiSample].uiInstances=0;
uiTicks=GetTickCount();
pSampleList[uiSample].uiTimeNext=GetTickCount()+pSampleList[uiSample].uiTimeMin+Random(pSampleList[uiSample].uiTimeMax-pSampleList[uiSample].uiTimeMin);
return(uiSample);
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundStreamCallback
//
// Plays a sound through streaming, and executes a callback for each buffer
// loaded.
//
// Returns: If successful, it returns the sample index it is loaded to, else
// SOUND_ERROR is returned.
//
//*******************************************************************************
UINT32 SoundStreamCallback(STR pFilename, SOUNDPARMS *pParms, void (*pCallback)(UINT8 *, UINT32, UINT32, UINT32, void *), void *pData)
{
UINT32 uiChannel, uiSoundID;
if(fSoundSystemInit)
{
if((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR)
{
uiSoundID=SoundStartStream(pFilename, uiChannel, pParms);
if(uiSoundID!=SOUND_ERROR)
{
AIL_auto_service_stream(pSoundList[uiChannel].hMSSStream, FALSE);
pSoundList[uiChannel].pCallback=pCallback;
pSoundList[uiChannel].pData=pData;
pSoundList[uiChannel].uiFlags|=SOUND_CALLBACK;
return(uiSoundID);
}
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundIsPlaying
//
// Returns TRUE/FALSE that an instance of a sound is still playing.
//
//*******************************************************************************
BOOLEAN SoundIsPlaying(UINT32 uiSoundID)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
uiSound=SoundGetIndexByID(uiSoundID);
if(uiSound!=NO_SAMPLE)
return(SoundIndexIsPlaying(uiSound));
}
return(FALSE);
}
//*****************************************************************************************
// SoundIndexIsPlaying
//
// Returns TRUE/FALSE whether a sound channel's sample is currently playing.
//
// Returns BOOLEAN - TRUE = playing, FALSE = stopped or nothing allocated
//
// UINT32 uiSound - Channel number of sound
//
// Created: 2/24/00 Derek Beland
//*****************************************************************************************
BOOLEAN SoundIndexIsPlaying(UINT32 uiSound)
{
INT32 iStatus=SMP_DONE;
if(fSoundSystemInit)
{
if(pSoundList[uiSound].hMSS!=NULL)
iStatus = AIL_sample_status(pSoundList[uiSound].hMSS);
if(pSoundList[uiSound].hMSSStream!=NULL)
iStatus = AIL_stream_status(pSoundList[uiSound].hMSSStream);
if(pSoundList[uiSound].hM3D!=NULL)
iStatus = AIL_3D_sample_status(pSoundList[uiSound].hM3D);
return((iStatus!=SMP_DONE) && (iStatus!=SMP_STOPPED));
}
return(FALSE);
}
//*******************************************************************************
// SoundStop
//
// Stops the playing of a sound instance, if still playing.
//
// Returns: TRUE if the sample was actually stopped, FALSE if it could not be
// found, or was not playing.
//
//*******************************************************************************
BOOLEAN SoundStop(UINT32 uiSoundID)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
if(SoundIsPlaying(uiSoundID))
{
uiSound=SoundGetIndexByID(uiSoundID);
if(uiSound!=NO_SAMPLE)
{
SoundStopIndex(uiSound);
return(TRUE);
}
}
}
return(FALSE);
}
//*******************************************************************************
// SoundStopGroup
//
// Stops multiple instances of sounds that have the indicated priority. This
// is useful for silencing all ambient sounds when switching to menus, etc.
//
// Returns: TRUE if samples were actually stopped, FALSE if none were found
//
//*******************************************************************************
BOOLEAN SoundStopGroup(UINT32 uiPriority)
{
UINT32 uiCount;
BOOLEAN fStopped=FALSE;
if(fSoundSystemInit)
{
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if((pSoundList[uiCount].hMSS!=NULL) || (pSoundList[uiCount].hMSSStream!=NULL) || (pSoundList[uiCount].hM3D!=NULL))
{
if(pSoundList[uiCount].uiPriority==uiPriority)
{
SoundStop(pSoundList[uiCount].uiSoundID);
fStopped=TRUE;
}
}
}
}
return(fStopped);
}
//*******************************************************************************
// SoundSetMemoryLimit
//
// Specifies how much memory the sound system is allowed to dynamically
// allocate. Once this limit is reached, the cache code will start dropping the
// least-used samples. You should always set the limit higher by a good margin
// than your actual memory requirements, to give the cache some elbow room.
//
// Returns: TRUE if the limit was set, or FALSE if the memory already used is
// greater than the limit requested.
//
//*******************************************************************************
BOOLEAN SoundSetMemoryLimit(UINT32 uiLimit)
{
if(guiSoundMemoryLimit < guiSoundMemoryUsed)
return(FALSE);
guiSoundMemoryLimit=uiLimit;
return(TRUE);
}
//*******************************************************************************
// SoundGetSystemInfo
//
// Returns information about the capabilities of the hardware. Currently does
// nothing.
//
// Returns: FALSE, always
//
//*******************************************************************************
BOOLEAN SoundGetSystemInfo(void)
{
return(FALSE);
}
//*******************************************************************************
// SoundSetDigitalVolume
//
// Sets the master volume for the digital section. All sample volumes will be
// affected by this setting.
//
// Returns: TRUE, always
//
//*******************************************************************************
BOOLEAN SoundSetDigitalVolume(UINT32 uiVolume)
{
UINT32 uiVolClip;
if(fSoundSystemInit)
{
uiVolClip=__min(uiVolume, 127);
AIL_set_digital_master_volume(hSoundDriver, uiVolClip);
}
return(TRUE);
}
//*******************************************************************************
// SoundGetDigitalVolume
//
// Returns the current value of the digital master volume.
//
// Returns: 0-127
//
//*******************************************************************************
UINT32 SoundGetDigitalVolume(UINT32 uiVolume)
{
if(fSoundSystemInit)
return((UINT32)AIL_digital_master_volume(hSoundDriver));
else
return(0);
}
//*****************************************************************************************
// SoundSetDefaultVolume
//
// Sets the volume to use when a default is not chosen.
//
// Returns BOOLEAN -
//
// UINT32 uiVolume -
//
// Created: 3/28/00 Derek Beland
//*****************************************************************************************
void SoundSetDefaultVolume(UINT32 uiVolume)
{
guiSoundDefaultVolume=__min(uiVolume, 127);
}
//*****************************************************************************************
// SoundGetDefaultVolume
//
//
//
// Returns UINT32 -
//
// UINT32 uiVolume -
//
// Created: 3/28/00 Derek Beland
//*****************************************************************************************
UINT32 SoundGetDefaultVolume(void)
{
return(guiSoundDefaultVolume);
}
//*******************************************************************************
// SoundStopAll
//
// Stops all currently playing sounds.
//
// Returns: TRUE, always
//
//*******************************************************************************
BOOLEAN SoundStopAll(void)
{
UINT32 uiCount;
if(fSoundSystemInit)
{
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
if(!pSoundList[uiCount].fMusic)
SoundStopIndex(uiCount);
}
return(TRUE);
}
//*****************************************************************************************
// SoundSetFadeVolume
//
// Sets a target volume to fade towards. The fade volume is updated in SoundServiceStreams.
//
// Returns BOOLEAN - TRUE if the fading volume was set, FALSE otherwise
//
// UINT32 uiSoundID - ID of sound
// UINT32 uiVolume - Volume to fade towards (0-127)
// UINT32 uiRate - Total time taken to change volume
// BOOLEAN fStopAtZero - If TRUE, sample is stopped when volume reaches zero
//
// Created: 3/17/00 Derek Beland
//*****************************************************************************************
BOOLEAN SoundSetFadeVolume(UINT32 uiSoundID, UINT32 uiVolume, UINT32 uiRate, BOOLEAN fStopAtZero)
{
UINT32 uiSound, uiVolCap, uiVolumeDiff;
if(fSoundSystemInit)
{
uiVolCap=__min(uiVolume, 127);
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
uiVolumeDiff = abs((long)(uiVolCap - SoundGetVolumeIndex(uiSound)));
if(!uiVolumeDiff)
return(FALSE);
pSoundList[uiSound].uiFadeVolume = uiVolCap;
pSoundList[uiSound].fStopAtZero = fStopAtZero;
pSoundList[uiSound].uiFadeRate = uiRate / uiVolumeDiff;
pSoundList[uiSound].uiFadeTime = GetTickCount();
return(TRUE);
}
}
return(FALSE);
}
//*******************************************************************************
// SoundSetVolume
//
// Sets the volume on a currently playing sound.
//
// Returns: TRUE if the volume was actually set on the sample, FALSE if the
// sample had already expired or couldn't be found
//
//*******************************************************************************
BOOLEAN SoundSetVolume(UINT32 uiSoundID, UINT32 uiVolume)
{
UINT32 uiSound, uiVolCap;
if(fSoundSystemInit)
{
uiVolCap=__min(uiVolume, 127);
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
pSoundList[uiSound].uiFadeVolume = uiVolume;
return(SoundSetVolumeIndex(uiSound, uiVolume));
}
}
return(FALSE);
}
//*****************************************************************************************
// SoundSetVolumeIndex
//
// Sounds the volume on a sound channel.
//
// Returns BOOLEAN - TRUE if the volume was set
//
// UINT32 uiChannel - Sound channel
// UINT32 uiVolume - New volume 0-127
//
// Created: 3/17/00 Derek Beland
//*****************************************************************************************
BOOLEAN SoundSetVolumeIndex(UINT32 uiChannel, UINT32 uiVolume)
{
UINT32 uiVolCap;
if(fSoundSystemInit)
{
uiVolCap=__min(uiVolume, 127);
if(pSoundList[uiChannel].hMSS!=NULL)
AIL_set_sample_volume(pSoundList[uiChannel].hMSS, uiVolCap);
if(pSoundList[uiChannel].hMSSStream!=NULL)
AIL_set_stream_volume(pSoundList[uiChannel].hMSSStream, uiVolCap);
if(pSoundList[uiChannel].hM3D!=NULL)
AIL_set_3D_sample_volume(pSoundList[uiChannel].hM3D, uiVolCap);
return(TRUE);
}
return(FALSE);
}
//*******************************************************************************
// SoundSetPan
//
// Sets the pan on a currently playing sound.
//
// Returns: TRUE if the pan was actually set on the sample, FALSE if the
// sample had already expired or couldn't be found
//
//*******************************************************************************
BOOLEAN SoundSetPan(UINT32 uiSoundID, UINT32 uiPan)
{
UINT32 uiSound, uiPanCap;
if(fSoundSystemInit)
{
uiPanCap=__min(uiPan, 127);
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
AIL_set_sample_pan(pSoundList[uiSound].hMSS, uiPanCap);
if(pSoundList[uiSound].hMSSStream!=NULL)
AIL_set_stream_pan(pSoundList[uiSound].hMSSStream, uiPanCap);
return(TRUE);
}
}
return(FALSE);
}
//*******************************************************************************
// SoundSetFrequency
//
// Sets the frequency on a currently playing sound.
//
// Returns: TRUE if the frequency was actually set on the sample, FALSE if the
// sample had already expired or couldn't be found
//
//*******************************************************************************
BOOLEAN SoundSetFrequency(UINT32 uiSoundID, UINT32 uiFreq)
{
UINT32 uiSound, uiFreqCap;
if(fSoundSystemInit)
{
uiFreqCap=__min(uiFreq, 44100);
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
AIL_set_sample_playback_rate(pSoundList[uiSound].hMSS, uiFreqCap);
if(pSoundList[uiSound].hMSSStream!=NULL)
AIL_set_stream_playback_rate(pSoundList[uiSound].hMSSStream, uiFreqCap);
if(pSoundList[uiSound].hM3D!=NULL)
AIL_set_3D_sample_playback_rate(pSoundList[uiSound].hM3D, uiFreqCap);
return(TRUE);
}
}
return(FALSE);
}
//*******************************************************************************
// SoundSetLoop
//
// Sets the loop on a currently playing sound.
//
// Returns: TRUE if the loop was actually set on the sample, FALSE if the
// sample had already expired or couldn't be found
//
//*******************************************************************************
BOOLEAN SoundSetLoop(UINT32 uiSoundID, UINT32 uiLoop)
{
UINT32 uiSound, uiLoopCap;
if(fSoundSystemInit)
{
uiLoopCap=__min(uiLoop, 10000);
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
AIL_set_sample_loop_count(pSoundList[uiSound].hMSS, uiLoopCap);
if(pSoundList[uiSound].hMSSStream!=NULL)
AIL_set_stream_loop_count(pSoundList[uiSound].hMSSStream, uiLoopCap);
if(pSoundList[uiSound].hM3D!=NULL)
AIL_set_3D_sample_loop_count(pSoundList[uiSound].hM3D, uiLoopCap);
return(TRUE);
}
}
return(FALSE);
}
//*******************************************************************************
// SoundGetVolume
//
// Returns the current volume setting of a sound that is playing. If the sound
// has expired, or could not be found, SOUND_ERROR is returned.
//
//*******************************************************************************
UINT32 SoundGetVolume(UINT32 uiSoundID)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
return(SoundGetVolumeIndex(uiSound));
}
return(SOUND_ERROR);
}
//*****************************************************************************************
// SoundGetVolumeIndex
//
// Returns the current volume of a sound channel.
//
// Returns UINT32 - Volume 0-127
//
// UINT32 uiChannel - Channel
//
// Created: 3/17/00 Derek Beland
//*****************************************************************************************
UINT32 SoundGetVolumeIndex(UINT32 uiChannel)
{
if(fSoundSystemInit)
{
if(pSoundList[uiChannel].hMSS!=NULL)
return((UINT32)AIL_sample_volume(pSoundList[uiChannel].hMSS));
if(pSoundList[uiChannel].hMSSStream!=NULL)
return((UINT32)AIL_stream_volume(pSoundList[uiChannel].hMSSStream));
if(pSoundList[uiChannel].hM3D!=NULL)
return((UINT32)AIL_3D_sample_volume(pSoundList[uiChannel].hM3D));
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundGetPan
//
// Returns the current pan setting of a sound that is playing. If the sound
// has expired, or could not be found, SOUND_ERROR is returned.
//
//*******************************************************************************
UINT32 SoundGetPan(UINT32 uiSoundID)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
return((UINT32)AIL_sample_pan(pSoundList[uiSound].hMSS));
if(pSoundList[uiSound].hMSSStream!=NULL)
return((UINT32)AIL_stream_pan(pSoundList[uiSound].hMSSStream));
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundGetFrequency
//
// Returns the current frequency setting of a sound that is playing. If the sound
// has expired, or could not be found, SOUND_ERROR is returned.
//
//*******************************************************************************
UINT32 SoundGetFrequency(UINT32 uiSoundID)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
return((UINT32)AIL_sample_playback_rate(pSoundList[uiSound].hMSS));
if(pSoundList[uiSound].hMSSStream!=NULL)
return((UINT32)AIL_stream_playback_rate(pSoundList[uiSound].hMSSStream));
if(pSoundList[uiSound].hM3D!=NULL)
return((UINT32)AIL_3D_sample_playback_rate(pSoundList[uiSound].hM3D));
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundGetLoop
//
// Returns the current loop count of a sound that is playing. If the sound
// has expired, or could not be found, SOUND_ERROR is returned.
//
//*******************************************************************************
UINT32 SoundGetLoop(UINT32 uiSoundID)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
return((UINT32)AIL_sample_loop_count(pSoundList[uiSound].hMSS));
if(pSoundList[uiSound].hMSSStream!=NULL)
return((UINT32)AIL_stream_loop_count(pSoundList[uiSound].hMSSStream));
if(pSoundList[uiSound].hM3D!=NULL)
return((UINT32)AIL_3D_sample_loop_count(pSoundList[uiSound].hM3D));
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundServiceRandom
//
// This function should be polled by the application if random samples are
// used. The time marks on each are checked and if it is time to spawn a new
// instance of the sound, the number already in existance are checked, and if
// there is room, a new one is made and the count updated.
// If random samples are not being used, there is no purpose in polling this
// function.
//
// Returns: TRUE if a new random sound was created, FALSE if nothing was done.
//
//*******************************************************************************
BOOLEAN SoundServiceRandom(void)
{
UINT32 uiCount;
// DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundServiceRandom ");
for(uiCount=0; uiCount < SOUND_MAX_CACHED; uiCount++)
{
if(!(pSampleList[uiCount].uiFlags&SAMPLE_RANDOM_MANUAL) && SoundRandomShouldPlay(uiCount))
SoundStartRandom(uiCount);
// DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("SoundStartRandom uicount = %d",uiCount));
}
return(FALSE);
}
//*******************************************************************************
// SoundRandomShouldPlay
//
// Determines whether a random sound is ready for playing or not.
//
// Returns: TRUE if a the sample should be played.
//
//*******************************************************************************
BOOLEAN SoundRandomShouldPlay(UINT32 uiSample)
{
UINT32 uiTicks;
uiTicks=GetTickCount();
if(pSampleList[uiSample].uiFlags&SAMPLE_RANDOM)
if(pSampleList[uiSample].uiTimeNext <= GetTickCount())
if(pSampleList[uiSample].uiInstances < pSampleList[uiSample].uiMaxInstances)
return(TRUE);
return(FALSE);
}
//*******************************************************************************
// SoundStartRandom
//
// Starts an instance of a random sample.
//
// Returns: TRUE if a new random sound was created, FALSE if nothing was done.
//
//*******************************************************************************
UINT32 SoundStartRandom(UINT32 uiSample)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartRandom ");
UINT32 uiChannel, uiSoundID;
SOUNDPARMS spParms;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartRandom: SoundGetFreeChannel ");
if((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartRandom: memset ");
memset(&spParms, 0xff, sizeof(SOUNDPARMS));
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartRandom: set sample info");
// spParms.uiSpeed=pSampleList[uiSample].uiSpeedMin+Random(pSampleList[uiSample].uiSpeedMax-pSampleList[uiSample].uiSpeedMin);
spParms.uiVolume=pSampleList[uiSample].uiVolMin+Random(pSampleList[uiSample].uiVolMax-pSampleList[uiSample].uiVolMin);
spParms.uiPan=pSampleList[uiSample].uiPanMin+Random(pSampleList[uiSample].uiPanMax-pSampleList[uiSample].uiPanMin);
spParms.uiLoop=1;
spParms.uiPriority=pSampleList[uiSample].uiPriority;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartRandom: SoundStartSample");
if((uiSoundID=SoundStartSample(uiSample, uiChannel, &spParms))!=SOUND_ERROR)
{
pSampleList[uiSample].uiTimeNext=GetTickCount()+pSampleList[uiSample].uiTimeMin+Random(pSampleList[uiSample].uiTimeMax-pSampleList[uiSample].uiTimeMin);
pSampleList[uiSample].uiInstances++;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("SoundStartRandom: returing sound %d ", uiSoundID));
return(uiSoundID);
}
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartRandom: sound error ");
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundStopAllRandom
//
// This function should be polled by the application if random samples are
// used. The time marks on each are checked and if it is time to spawn a new
// instance of the sound, the number already in existance are checked, and if
// there is room, a new one is made and the count updated.
// If random samples are not being used, there is no purpose in polling this
// function.
//
// Returns: TRUE if a new random sound was created, FALSE if nothing was done.
//
//*******************************************************************************
BOOLEAN SoundStopAllRandom(void)
{
UINT32 uiChannel, uiSample;
// Stop all currently playing random sounds
for(uiChannel=0; uiChannel < SOUND_MAX_CHANNELS; uiChannel++)
{
if((pSoundList[uiChannel].hMSS!=NULL) || (pSoundList[uiChannel].hM3D!=NULL))
{
uiSample=pSoundList[uiChannel].uiSample;
// if this was a random sample, decrease the iteration count
if(pSampleList[uiSample].uiFlags&SAMPLE_RANDOM)
SoundStopIndex(uiChannel);
}
}
// Unlock all random sounds so they can be dumped from the cache, and
// take the random flag off so they won't be serviced/played
for(uiSample=0; uiSample < SOUND_MAX_CACHED; uiSample++)
{
if(pSampleList[uiSample].uiFlags & SAMPLE_RANDOM)
pSampleList[uiSample].uiFlags &= (~(SAMPLE_RANDOM | SAMPLE_LOCKED));
}
return(FALSE);
}
//*******************************************************************************
// SoundServiceStreams
//
// Can be polled in tight loops where sound buffers might starve due to heavy
// hardware use, etc. Streams DO NOT normally need to be serviced manually, but
// in some cases (heavy file loading) it might be desirable.
//
// If you are using the end of sample callbacks, you must call this function
// periodically to check the sample's status.
//
// Returns: TRUE always.
//
//*******************************************************************************
BOOLEAN SoundServiceStreams(void)
{
UINT32 uiCount, uiSpeed, uiBuffLen, uiBytesPerSample;
UINT8 *pBuffer;
void *pData;
if(fSoundSystemInit)
{
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if(pSoundList[uiCount].hMSSStream!=NULL)
{
if(AIL_service_stream(pSoundList[uiCount].hMSSStream, 0))
{
if(pSoundList[uiCount].uiFlags&SOUND_CALLBACK)
{
uiSpeed=pSoundList[uiCount].hMSSStream->datarate;
uiBuffLen=pSoundList[uiCount].hMSSStream->bufsize;
pBuffer=pSoundList[uiCount].hMSSStream->bufs[pSoundList[uiCount].hMSSStream->buf1];
uiBytesPerSample=pSoundList[uiCount].hMSSStream->samp->format;
pData=pSoundList[uiCount].pData;
pSoundList[uiCount].pCallback(pBuffer, uiBuffLen, uiSpeed, uiBytesPerSample, pData);
}
}
}
if(pSoundList[uiCount].hMSS || pSoundList[uiCount].hMSSStream || pSoundList[uiCount].hM3D)
{
// If a sound has a handle, but isn't playing, stop it and free up the handle
if(!SoundIsPlaying(pSoundList[uiCount].uiSoundID))
SoundStopIndex(uiCount);
else
{ // Check the volume fades on currently playing sounds
UINT32 uiVolume = SoundGetVolumeIndex(uiCount);
UINT32 uiTime = GetTickCount();
if((uiVolume != pSoundList[uiCount].uiFadeVolume) && (uiTime >= (pSoundList[uiCount].uiFadeTime + pSoundList[uiCount].uiFadeRate)) )
{
if(uiVolume < pSoundList[uiCount].uiFadeVolume)
SoundSetVolumeIndex(uiCount, ++uiVolume);
else if(uiVolume > pSoundList[uiCount].uiFadeVolume)
{
uiVolume--;
if(!uiVolume && pSoundList[uiCount].fStopAtZero)
SoundStopIndex(uiCount);
else
SoundSetVolumeIndex(uiCount, uiVolume);
}
pSoundList[uiCount].uiFadeTime = uiTime;
}
}
}
}
}
return(TRUE);
}
//*******************************************************************************
// SoundGetPosition
//
// Reports the current time position of the sample.
//
// Note: You should be checking SoundIsPlaying very carefully while
// calling this function.
//
// Returns: The current time of the sample in milliseconds.
//
//*******************************************************************************
UINT32 SoundGetPosition(UINT32 uiSoundID)
{
//UINT32 uiSound, uiFreq=0, uiPosition=0, uiBytesPerSample=0, uiFormat=0;
UINT32 uiSound, uiTime, uiPosition;
if(fSoundSystemInit)
{
if((uiSound=SoundGetIndexByID(uiSoundID))!=NO_SAMPLE)
{
/* if(pSoundList[uiSound].hMSSStream!=NULL)
{
uiPosition=(UINT32)AIL_stream_position(pSoundList[uiSound].hMSSStream);
uiFreq=(UINT32)pSoundList[uiSound].hMSSStream->samp->playback_rate;
uiFormat=(UINT32)pSoundList[uiSound].hMSSStream->samp->format;
}
else if(pSoundList[uiSound].hMSS!=NULL)
{
uiPosition=(UINT32)AIL_sample_position(pSoundList[uiSound].hMSS);
uiFreq=(UINT32)pSoundList[uiSound].hMSS->playback_rate;
uiFormat=(UINT32)pSoundList[uiSound].hMSS->format;
}
}
switch(uiFormat)
{
case DIG_F_MONO_8: uiBytesPerSample=1;
break;
case DIG_F_MONO_16: uiBytesPerSample=2;
break;
case DIG_F_STEREO_8: uiBytesPerSample=2;
break;
case DIG_F_STEREO_16: uiBytesPerSample=4;
break;
}
if(uiFreq)
{
return((uiPosition/uiBytesPerSample)/(uiFreq/1000));
}
}
*/
uiTime=GetTickCount();
// check for rollover
if(uiTime < pSoundList[uiSound].uiTimeStamp)
uiPosition=(0-pSoundList[uiSound].uiTimeStamp)+uiTime;
else
uiPosition=(uiTime-pSoundList[uiSound].uiTimeStamp);
return(uiPosition);
}
}
return(0);
}
//*****************************************************************************************
//
// SoundGetMilliSecondPosition
//
// Get the sounds total length and our current position within that
// sound in milliseconds
//
//
// Returns BOOLEAN: TRUE if the sound exists.
//
// Created by: Gilles Beauparlant
// Created on: 7/23/99
//
//*****************************************************************************************
BOOLEAN SoundGetMilliSecondPosition(UINT32 uiSoundID, UINT32 *puiTotalMilliseconds, UINT32 *puiCurrentMilliseconds)
{
UINT32 uiSound;
if(fSoundSystemInit)
{
uiSound=SoundGetIndexByID(uiSoundID);
if(uiSound!=NO_SAMPLE)
{
if(pSoundList[uiSound].hMSS!=NULL)
{
AIL_sample_ms_position(pSoundList[uiSound].hMSS, (long *)puiTotalMilliseconds, (long *)puiCurrentMilliseconds);
return TRUE;
}
if(pSoundList[uiSound].hMSSStream!=NULL)
{
AIL_stream_ms_position(pSoundList[uiSound].hMSSStream, (long *)puiTotalMilliseconds, (long *)puiCurrentMilliseconds);
return TRUE;
}
}
}
*puiTotalMilliseconds = 0;
*puiCurrentMilliseconds = 0;
return FALSE;
}
//*******************************************************************************
// Cacheing Subsystem
//*******************************************************************************
//*******************************************************************************
// SoundInitCache
//
// Zeros out the structures of the sample list.
//
//*******************************************************************************
BOOLEAN SoundInitCache(void)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CACHED; uiCount++)
memset(&pSampleList[uiCount], 0, sizeof(SAMPLETAG));
return(TRUE);
}
//*******************************************************************************
// SoundShutdownCache
//
// Empties out the cache.
//
// Returns: TRUE, always
//
//*******************************************************************************
BOOLEAN SoundShutdownCache(void)
{
SoundEmptyCache();
return(TRUE);
}
//*******************************************************************************
// SoundSetCacheThreshold
//
// Sets the sound size above which samples will be played double-buffered,
// below which they will be loaded into the cache.
//
// Returns: TRUE, always
//
//*******************************************************************************
BOOLEAN SoundSetCacheThreshhold(UINT32 uiThreshold)
{
if(uiThreshold==0)
guiSoundCacheThreshold=SOUND_DEFAULT_THRESH;
else
guiSoundCacheThreshold=uiThreshold;
return(TRUE);
}
//*******************************************************************************
// SoundEmptyCache
//
// Frees up all samples in the cache.
//
// Returns: TRUE, always
//
//*******************************************************************************
BOOLEAN SoundEmptyCache(void)
{
UINT32 uiCount;
SoundStopAll();
for(uiCount=0; uiCount < SOUND_MAX_CACHED; uiCount++)
SoundFreeSampleIndex(uiCount);
return(TRUE);
}
//*******************************************************************************
// SoundLoadSample
//
// Frees up all samples in the cache.
//
// Returns: TRUE, always
//
//*******************************************************************************
UINT32 SoundLoadSample(STR pFilename)
{
UINT32 uiSample=NO_SAMPLE;
if((uiSample=SoundGetCached(pFilename))!=NO_SAMPLE)
return(uiSample);
return(SoundLoadDisk(pFilename));
}
//*******************************************************************************
// SoundLockSample
//
// Locks a sample into cache memory, so the cacheing system won't release it
// when it needs room.
//
// Returns: The sample index if successful, NO_SAMPLE if the file wasn't found
// in the cache.
//
//*******************************************************************************
UINT32 SoundLockSample(STR pFilename)
{
UINT32 uiSample;
if((uiSample=SoundGetCached(pFilename))!=NO_SAMPLE)
{
pSampleList[uiSample].uiFlags|=SAMPLE_LOCKED;
return(uiSample);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundUnlockSample
//
// Removes the lock on a sample so the cache is free to dump it when necessary.
//
// Returns: The sample index if successful, NO_SAMPLE if the file wasn't found
// in the cache.
//
//*******************************************************************************
UINT32 SoundUnlockSample(STR pFilename)
{
UINT32 uiSample;
if((uiSample=SoundGetCached(pFilename))!=NO_SAMPLE)
{
pSampleList[uiSample].uiFlags&=(~SAMPLE_LOCKED);
return(uiSample);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundFreeSample
//
// Releases the resources associated with a sample from the cache.
//
// Returns: The sample index if successful, NO_SAMPLE if the file wasn't found
// in the cache.
//
//*******************************************************************************
UINT32 SoundFreeSample(STR pFilename)
{
UINT32 uiSample;
if((uiSample=SoundGetCached(pFilename))!=NO_SAMPLE)
{
if(!SoundSampleIsPlaying(uiSample))
{
SoundFreeSampleIndex(uiSample);
return(uiSample);
}
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundFreeGroup
//
// Releases a group of samples with a given priority. Does not take into
// account locked/unlocked status.
//
// Returns: TRUE if samples were freed, FALSE if none
//
// NOTE:
// This function is going to be removed! If you are attempting to stop all
// random sounds, call SoundStopAllRandom instead.
//
//*******************************************************************************
BOOLEAN SoundFreeGroup(UINT32 uiPriority)
{
BOOLEAN fFreed=FALSE;
SoundStopGroup(uiPriority);
return(fFreed);
}
//*******************************************************************************
// SoundGetCached
//
// Tries to locate a sound by looking at what is currently loaded in the
// cache.
//
// Returns: The sample index if successful, NO_SAMPLE if the file wasn't found
// in the cache.
//
//*******************************************************************************
UINT32 SoundGetCached(STR pFilename)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CACHED; uiCount++)
{
if(_stricmp(pSampleList[uiCount].pName, pFilename)==0)
return(uiCount);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundLoadDisk
//
// Loads a sound file from disk into the cache, allocating memory and a slot
// for storage.
//
//
// Returns: The sample index if successful, NO_SAMPLE if the file wasn't found
// in the cache.
//
//*******************************************************************************
UINT32 SoundLoadDisk(STR pFilename)
{
HWFILE hFile;
UINT32 uiSize, uiSample;
BOOLEAN fRemoved=TRUE;
Assert(pFilename!=NULL);
if((hFile=FileOpen(pFilename, FILE_ACCESS_READ, FALSE))!=0)
{
uiSize=FileGetSize(hFile);
// if insufficient memory, start unloading old samples until either
// there's nothing left to unload, or we fit
fRemoved=TRUE;
while(((uiSize + guiSoundMemoryUsed) > guiSoundMemoryLimit) && (fRemoved))
fRemoved=SoundCleanCache();
// if we still don't fit
if((uiSize + guiSoundMemoryUsed) > guiSoundMemoryLimit)
{
FastDebugMsg(String("SoundLoadDisk: ERROR: trying to play %s, not enough memory\n", pFilename ) );
FileClose(hFile);
return(NO_SAMPLE);
}
// if all the sample slots are full, unloading one
if((uiSample=SoundGetEmptySample())==NO_SAMPLE)
{
SoundCleanCache();
uiSample=SoundGetEmptySample();
}
// if we still don't have a sample slot
if(uiSample==NO_SAMPLE)
{
FastDebugMsg(String("SoundLoadDisk: ERROR: Trying to play %s, sound channels are full\n", pFilename ) );
FileClose(hFile);
return(NO_SAMPLE);
}
memset(&pSampleList[uiSample], 0, sizeof(SAMPLETAG));
if((pSampleList[uiSample].pData=AIL_mem_alloc_lock(uiSize))==NULL)
{
FastDebugMsg(String("SoundLoadDisk: ERROR: Trying to play %s, AIL channels are full\n", pFilename ) );
FileClose(hFile);
return(NO_SAMPLE);
}
guiSoundMemoryUsed+=uiSize;
FileRead(hFile, pSampleList[uiSample].pData, uiSize, NULL);
FileClose(hFile);
strcpy(pSampleList[uiSample].pName, pFilename);
strupr(pSampleList[uiSample].pName);
pSampleList[uiSample].uiSize=uiSize;
pSampleList[uiSample].uiFlags|=SAMPLE_ALLOCATED;
/* if(!strstr(pFilename, ".MP3"))
SoundProcessWAVHeader(uiSample);
*/ return(uiSample);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundCleanCache
//
// Removes the least-used sound from the cache to make room.
//
// Returns: TRUE if a sample was freed, FALSE if none
//
//*******************************************************************************
BOOLEAN SoundCleanCache(void)
{
UINT32 uiCount, uiLowestHits=NO_SAMPLE, uiLowestHitsCount=0;
for(uiCount=0; uiCount < SOUND_MAX_CACHED; uiCount++)
{
if((pSampleList[uiCount].uiFlags&SAMPLE_ALLOCATED) &&
!(pSampleList[uiCount].uiFlags&SAMPLE_LOCKED))
{
if((uiLowestHits==NO_SAMPLE) || (uiLowestHitsCount < pSampleList[uiCount].uiCacheHits))
{
if(!SoundSampleIsPlaying(uiCount))
{
uiLowestHits=uiCount;
uiLowestHitsCount=pSampleList[uiCount].uiCacheHits;
}
}
}
}
if(uiLowestHits!=NO_SAMPLE)
{
SoundFreeSampleIndex(uiLowestHits);
return(TRUE);
}
return(FALSE);
}
//*******************************************************************************
// Low Level Interface (Local use only)
//*******************************************************************************
//*******************************************************************************
// SoundSampleIsPlaying
//
// Returns TRUE/FALSE that a sample is currently in use for playing a sound.
//
//*******************************************************************************
BOOLEAN SoundSampleIsPlaying(UINT32 uiSample)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if(pSoundList[uiCount].uiSample==uiSample)
return(TRUE);
}
return(FALSE);
}
//*******************************************************************************
// SoundGetEmptySample
//
// Returns the slot number of an available sample index.
//
// Returns: A free sample index, or NO_SAMPLE if none are left.
//
//*******************************************************************************
UINT32 SoundGetEmptySample(void)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CACHED; uiCount++)
{
if(!(pSampleList[uiCount].uiFlags&SAMPLE_ALLOCATED))
return(uiCount);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundProcessWAVHeader
//
// Reads the information contained in the header of a loaded WAV file, and
// transfers it to the system structures for that slot.
//
// Returns: TRUE if a good header was processed, FALSE if an error occurred.
//
//*******************************************************************************
BOOLEAN SoundProcessWAVHeader(UINT32 uiSample)
{
CHAR8 *pChunk;
AILSOUNDINFO ailInfo;
pChunk=(CHAR8 *)pSampleList[uiSample].pData;
if(!AIL_WAV_info((void *)pChunk, &ailInfo))
return(FALSE);
pSampleList[uiSample].uiSpeed=ailInfo.rate;
pSampleList[uiSample].fStereo=(BOOLEAN)(ailInfo.channels==2);
pSampleList[uiSample].ubBits=(UINT8)ailInfo.bits;
pSampleList[uiSample].pSoundStart=(PTR)ailInfo.data_ptr;
pSampleList[uiSample].uiSoundSize=ailInfo.data_len;
pSampleList[uiSample].uiAilWaveFormat=ailInfo.format;
pSampleList[uiSample].uiADPCMBlockSize=ailInfo.block_size;
return(TRUE);
}
//*******************************************************************************
// SoundFreeSampleIndex
//
// Frees up a sample referred to by it's index slot number.
//
// Returns: Slot number if something was free, NO_SAMPLE otherwise.
//
//*******************************************************************************
UINT32 SoundFreeSampleIndex(UINT32 uiSample)
{
if(pSampleList[uiSample].uiFlags&SAMPLE_ALLOCATED)
{
if(pSampleList[uiSample].pData!=NULL)
{
guiSoundMemoryUsed-=pSampleList[uiSample].uiSize;
AIL_mem_free_lock(pSampleList[uiSample].pData);
}
memset(&pSampleList[uiSample], 0, sizeof(SAMPLETAG));
return(uiSample);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundGetIndexByID
//
// Searches out a sound instance referred to by it's ID number.
//
// Returns: If the instance was found, the slot number. NO_SAMPLE otherwise.
//
//*******************************************************************************
UINT32 SoundGetIndexByID(UINT32 uiSoundID)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if(pSoundList[uiCount].uiSoundID==uiSoundID)
return(uiCount);
}
return(NO_SAMPLE);
}
//*******************************************************************************
// SoundInitHardware
//
// Initializes the sound hardware through Windows/DirectX. THe highest possible
// mixing rate and capabilities set are searched out and used.
//
// Returns: TRUE if the hardware was initialized, FALSE otherwise.
//
//*******************************************************************************
BOOLEAN SoundInitHardware(void)
{
UINT32 uiCount;
CHAR8 cDriverName[128];
// Try to start up the Miles Sound System
if(!AIL_startup())
return(FALSE);
// Initialize the driver handle
hSoundDriver = NULL;
// Set up preferences, to try to use DirectSound and to set the
// maximum number of handles that we are allowed to allocate. Note
// that this is not the number we may have playing at one time--
// that number is set by SOUND_MAX_CHANNELS
AIL_set_preference(DIG_MIXER_CHANNELS, SOUND_MAX_CHANNELS);
fDirectSound=TRUE;
AIL_set_preference(DIG_USE_WAVEOUT,NO);
// startup with DirectSound
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(44100, 16, 2);
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(44100, 8, 2);
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(22050, 8, 2);
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(11025, 8, 1);
if(hSoundDriver)
{
// Detect if the driver is emulated or not
SoundGetDriverName(hSoundDriver, cDriverName);
_strlwr(cDriverName);
// If it is, we don't want to use it, since the extra
// code layer can slow us down by up to 40% under NT
if(strstr(cDriverName, "emulated"))
{
AIL_waveOutClose(hSoundDriver);
hSoundDriver=NULL;
}
}
// nothing in DirectSound worked, so try waveOut
if (hSoundDriver == NULL)
{
fDirectSound=FALSE;
AIL_set_preference(DIG_USE_WAVEOUT,YES);
}
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(44100, 16, 2);
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(44100, 8, 2);
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(22050, 8, 2);
if (hSoundDriver == NULL)
hSoundDriver = SoundInitDriver(11025, 8, 1);
if (hSoundDriver!=NULL)
{
for(uiCount = 0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
memset(&pSoundList[uiCount], 0, sizeof(SOUNDTAG));
return(TRUE);
}
return(FALSE);
/*
// midi startup
if (hSoundDriver!=NULL)
{
soundMDI = MIDI_init_driver();
if (soundMDI==NULL)
{
_RPT1(_CRT_WARN, "MIDI: %s", AIL_last_error());
}
else
{
soundSEQ = MIDI_load_sequence(soundMDI, "SOUNDS\\DEMO.XMI");
if (soundSEQ==NULL)
_RPT1(_CRT_WARN, "MIDI: %s", AIL_last_error());
}
}
*/
}
//*******************************************************************************
// SoundShutdownHardware
//
// Shuts down the system hardware.
//
// Returns: TRUE always.
//
//*******************************************************************************
BOOLEAN SoundShutdownHardware(void)
{
if(fSoundSystemInit)
AIL_shutdown();
return(TRUE);
}
//*******************************************************************************
// SoundInitDriver
//
// Tries to initialize the sound driver using the specified settings.
//
// Returns: Pointer to the driver if successful, NULL otherwise.
//
//*******************************************************************************
static HDIGDRIVER SoundInitDriver(UINT32 uiRate, UINT16 uiBits, UINT16 uiChans)
{
static PCMWAVEFORMAT sPCMWF;
HDIGDRIVER DIG;
CHAR8 cBuf[128];
memset(&sPCMWF, 0, sizeof(PCMWAVEFORMAT));
sPCMWF.wf.wFormatTag = WAVE_FORMAT_PCM;
sPCMWF.wf.nChannels = uiChans;
sPCMWF.wf.nSamplesPerSec = uiRate;
sPCMWF.wf.nAvgBytesPerSec = uiRate * (uiBits / 8) * uiChans;
sPCMWF.wf.nBlockAlign = (uiBits / 8) * uiChans;
sPCMWF.wBitsPerSample = uiBits;
if(AIL_waveOutOpen(&DIG, NULL, 0, (LPWAVEFORMAT) &sPCMWF))
return(NULL);
memset(cBuf, 0, 128);
AIL_digital_configuration(DIG,0,0,cBuf);
FastDebugMsg(String("Sound Init: %dKHz, %d uiBits, %s %s\n", uiRate, uiBits, (uiChans==1)? "Mono": "Stereo", cBuf));
return(DIG);
}
//*******************************************************************************
// SoundGetDriverName
//
// Returns the name of the AIL device.
//
// Returns: TRUE or FALSE if the string was filled.
//
//*******************************************************************************
BOOLEAN SoundGetDriverName(HDIGDRIVER DIG, CHAR8 *cBuf)
{
if(DIG)
{
cBuf[0]='\0';
AIL_digital_configuration(DIG, NULL, NULL, cBuf);
return(TRUE);
}
else
return(FALSE);
}
//*******************************************************************************
// SoundGetFreeChannel
//
// Finds an unused sound channel in the channel list.
//
// Returns: Index of a sound channel if one was found, SOUND_ERROR if not.
//
//*******************************************************************************
UINT32 SoundGetFreeChannel(void)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if(!SoundIsPlaying(pSoundList[uiCount].uiSoundID))
{
SoundStopIndex(uiCount);
}
if((pSoundList[uiCount].hMSS==NULL) && (pSoundList[uiCount].hMSSStream==NULL) && (pSoundList[uiCount].hM3D==NULL))
return(uiCount);
}
return(SOUND_ERROR);
}
//*******************************************************************************
// SoundStartSample
//
// Starts up a sample on the specified channel. Override parameters are passed
// in through the structure pointer pParms. Any entry with a value of 0xffffffff
// will be filled in by the system.
//
// Returns: Unique sound ID if successful, SOUND_ERROR if not.
//
//*******************************************************************************
UINT32 SoundStartSample(UINT32 uiSample, UINT32 uiChannel, SOUNDPARMS *pParms)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample");
UINT32 uiSoundID;
CHAR8 AILString[200];
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check sound init");
if(!fSoundSystemInit)
return(SOUND_ERROR);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check sound driver");
if((pSoundList[uiChannel].hMSS = AIL_allocate_sample_handle(hSoundDriver))==NULL)
{
sprintf(AILString, "Sample Error: %s", AIL_last_error());
FastDebugMsg(AILString);
return(SOUND_ERROR);
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: AL_init_sample ");
AIL_init_sample(pSoundList[uiChannel].hMSS);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check sample");
if(!AIL_set_named_sample_file(pSoundList[uiChannel].hMSS, pSampleList[uiSample].pName, pSampleList[uiSample].pData, pSampleList[uiSample].uiSize, 0))
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: sample sound error");
AIL_release_sample_handle(pSoundList[uiChannel].hMSS);
pSoundList[uiChannel].hMSS=NULL;
sprintf(AILString, "AIL Set Sample Error: %s", AIL_last_error());
DbgMessage(TOPIC_GAME, DBG_LEVEL_0, AILString);
return(SOUND_ERROR);
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: store playback rate");
// Store the natural playback rate before we modify it below
pSampleList[uiSample].uiSpeed=AIL_sample_playback_rate(pSoundList[uiChannel].hMSS);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check if random sample");
if(pSampleList[uiSample].uiFlags & SAMPLE_RANDOM)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: random sample");
if((pSampleList[uiSample].uiSpeedMin != SOUND_PARMS_DEFAULT) && (pSampleList[uiSample].uiSpeedMin != SOUND_PARMS_DEFAULT))
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: get random sample");
UINT32 uiSpeed = pSampleList[uiSample].uiSpeedMin+Random(pSampleList[uiSample].uiSpeedMax-pSampleList[uiSample].uiSpeedMin);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: set playback rate");
AIL_set_sample_playback_rate(pSoundList[uiChannel].hMSS, uiSpeed);
}
}
else
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: not random sample");
if((pParms!=NULL) && (pParms->uiSpeed!=SOUND_PARMS_DEFAULT))
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check speed ");
Assert((pParms->uiSpeed > 0) && (pParms->uiSpeed <= 60000));
AIL_set_sample_playback_rate(pSoundList[uiChannel].hMSS, pParms->uiSpeed);
}
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check pitch bend");
if((pParms!=NULL) && (pParms->uiPitchBend!=SOUND_PARMS_DEFAULT))
{
UINT32 uiRate = AIL_sample_playback_rate(pSoundList[uiChannel].hMSS);
UINT32 uiBend = uiRate * pParms->uiPitchBend/100;
AIL_set_sample_playback_rate(pSoundList[uiChannel].hMSS, uiRate + (Random(uiBend*2)-uiBend));
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check volume");
if((pParms!=NULL) && (pParms->uiVolume!=SOUND_PARMS_DEFAULT))
AIL_set_sample_volume(pSoundList[uiChannel].hMSS, pParms->uiVolume);
else
AIL_set_sample_volume(pSoundList[uiChannel].hMSS, guiSoundDefaultVolume);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check looping");
if((pParms!=NULL) && (pParms->uiLoop!=SOUND_PARMS_DEFAULT))
{
AIL_set_sample_loop_count(pSoundList[uiChannel].hMSS, pParms->uiLoop);
// If looping infinately, lock the sample so it can't be unloaded
// and mark it as a looping sound
if(pParms->uiLoop==0)
{
pSampleList[uiSample].uiFlags|=SAMPLE_LOCKED;
pSoundList[uiChannel].fLooping=TRUE;
}
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check pan");
if((pParms!=NULL) && (pParms->uiPan!=SOUND_PARMS_DEFAULT))
AIL_set_sample_pan(pSoundList[uiChannel].hMSS, pParms->uiPan);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check priority");
if((pParms!=NULL) && (pParms->uiPriority!=SOUND_PARMS_DEFAULT))
pSoundList[uiChannel].uiPriority=pParms->uiPriority;
else
pSoundList[uiChannel].uiPriority=PRIORITY_MAX;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: check EOS callback");
if((pParms!=NULL) && ((UINT32)pParms->EOSCallback!=SOUND_PARMS_DEFAULT))
{
pSoundList[uiChannel].EOSCallback=pParms->EOSCallback;
pSoundList[uiChannel].pCallbackData=pParms->pCallbackData;
}
else
{
pSoundList[uiChannel].EOSCallback=NULL;
pSoundList[uiChannel].pCallbackData=NULL;
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: set up channel in sound list");
uiSoundID=SoundGetUniqueID();
pSoundList[uiChannel].uiSoundID=uiSoundID;
pSoundList[uiChannel].uiSample=uiSample;
pSoundList[uiChannel].uiTimeStamp=GetTickCount();
pSoundList[uiChannel].uiFadeVolume = SoundGetVolumeIndex(uiChannel);
pSampleList[uiSample].uiCacheHits++;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: start sample");
AIL_start_sample(pSoundList[uiChannel].hMSS);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SoundStartSample: done");
return(uiSoundID);
}
//*******************************************************************************
// SoundStartStream
//
// Starts up a stream on the specified channel. Override parameters are passed
// in through the structure pointer pParms. Any entry with a value of 0xffffffff
// will be filled in by the system.
//
// Returns: Unique sound ID if successful, SOUND_ERROR if not.
//
//*******************************************************************************
UINT32 SoundStartStream(STR pFilename, UINT32 uiChannel, SOUNDPARMS *pParms)
{
UINT32 uiSoundID, uiSpeed;
CHAR8 AILString[200];
if(!fSoundSystemInit)
return(SOUND_ERROR);
// Snap: First see if the file is in the custom Data catalogue:
std::string filePath;
if ( gCustomDataCat.FindFile(pFilename) ) {
filePath = gCustomDataCat.GetRootDir() + '\\';
}
filePath += pFilename;
// Bad cast! pFilename should have been const. Oh well...
pFilename = const_cast<STR>( filePath.c_str() );
// Now pFilename points either to the original file name,
// or to the full file path in the custom Data directory.
// Except for this substitution, the rest of the function is unchanged.
if((pSoundList[uiChannel].hMSSStream=AIL_open_stream(hSoundDriver, pFilename, SOUND_DEFAULT_STREAM))==NULL)
{
SoundCleanCache();
pSoundList[uiChannel].hMSSStream=AIL_open_stream(hSoundDriver, pFilename, SOUND_DEFAULT_STREAM);
}
if(pSoundList[uiChannel].hMSSStream==NULL)
{
sprintf(AILString, "Stream Error: %s", AIL_last_error());
DbgMessage(TOPIC_GAME, DBG_LEVEL_0, AILString);
return(SOUND_ERROR);
}
if((pParms!=NULL) && (pParms->uiSpeed!=SOUND_PARMS_DEFAULT))
uiSpeed=pParms->uiSpeed;
else
uiSpeed=AIL_stream_playback_rate(pSoundList[uiChannel].hMSSStream);
if((pParms!=NULL) && (pParms->uiPitchBend!=SOUND_PARMS_DEFAULT))
{
UINT32 uiBend = uiSpeed * pParms->uiPitchBend/100;
uiSpeed+=(Random(uiBend*2)-uiBend);
}
AIL_set_stream_playback_rate(pSoundList[uiChannel].hMSSStream, uiSpeed);
if((pParms!=NULL) && (pParms->uiVolume!=SOUND_PARMS_DEFAULT))
AIL_set_stream_volume(pSoundList[uiChannel].hMSSStream, pParms->uiVolume);
else
AIL_set_stream_volume(pSoundList[uiChannel].hMSSStream, guiSoundDefaultVolume);
if( pParms!=NULL )
{
if (pParms->uiLoop!=SOUND_PARMS_DEFAULT )
AIL_set_stream_loop_count(pSoundList[uiChannel].hMSSStream, pParms->uiLoop);
}
if((pParms!=NULL) && (pParms->uiPan!=SOUND_PARMS_DEFAULT))
AIL_set_stream_pan(pSoundList[uiChannel].hMSSStream, pParms->uiPan);
AIL_start_stream(pSoundList[uiChannel].hMSSStream);
uiSoundID=SoundGetUniqueID();
pSoundList[uiChannel].uiSoundID=uiSoundID;
if(pParms)
pSoundList[uiChannel].uiPriority=pParms->uiPriority;
else
pSoundList[uiChannel].uiPriority=SOUND_PARMS_DEFAULT;
if((pParms!=NULL) && ((UINT32)pParms->EOSCallback!=SOUND_PARMS_DEFAULT))
{
pSoundList[uiChannel].EOSCallback=pParms->EOSCallback;
pSoundList[uiChannel].pCallbackData=pParms->pCallbackData;
}
else
{
pSoundList[uiChannel].EOSCallback=NULL;
pSoundList[uiChannel].pCallbackData=NULL;
}
pSoundList[uiChannel].uiTimeStamp=GetTickCount();
pSoundList[uiChannel].uiFadeVolume = SoundGetVolumeIndex(uiChannel);
return(uiSoundID);
}
//*******************************************************************************
// SoundGetUniqueID
//
// Returns a unique ID number with every call. Basically it's just a 32-bit
// static value that is incremented each time.
//
//*******************************************************************************
UINT32 SoundGetUniqueID(void)
{
static UINT32 uiNextID=0;
if(uiNextID==SOUND_ERROR)
uiNextID++;
return(uiNextID++);
}
//*******************************************************************************
// SoundPlayStreamed
//
// Returns TRUE/FALSE whether a sound file should be played as a streamed
// sample, or loaded into the cache. The decision is based on the size of the
// file compared to the guiSoundCacheThreshold.
//
// Returns: TRUE if it should be streamed, FALSE if loaded.
//
//*******************************************************************************
BOOLEAN SoundPlayStreamed(STR pFilename)
{
HWFILE hDisk;
UINT32 uiFilesize;
if((hDisk=FileOpen(pFilename, FILE_ACCESS_READ, FALSE))!=0)
{
uiFilesize=FileGetSize(hDisk);
FileClose(hDisk);
return(uiFilesize >= guiSoundCacheThreshold);
}
return(FALSE);
}
//*******************************************************************************
// SoundStopIndex
//
// Stops a sound referred to by it's slot number. This function is the only
// one that should be deallocating sample handles. The random sounds have to have
// their counters maintained, and using this as the central function ensures
// that they stay in sync.
//
// Returns: TRUE if the sample was stopped, FALSE if it could not be found.
//
//*******************************************************************************
BOOLEAN SoundStopIndex(UINT32 uiChannel)
{
UINT32 uiSample;
if(fSoundSystemInit)
{
if(uiChannel!=NO_SAMPLE)
{
if(pSoundList[uiChannel].hMSS!=NULL)
{
AIL_stop_sample(pSoundList[uiChannel].hMSS);
AIL_release_sample_handle(pSoundList[uiChannel].hMSS);
pSoundList[uiChannel].hMSS=NULL;
uiSample=pSoundList[uiChannel].uiSample;
// if this was a random sample, decrease the iteration count
if(pSampleList[uiSample].uiFlags&SAMPLE_RANDOM)
pSampleList[uiSample].uiInstances--;
if(pSoundList[uiChannel].EOSCallback!=NULL)
pSoundList[uiChannel].EOSCallback(pSoundList[uiChannel].pCallbackData);
if(pSoundList[uiChannel].fLooping && !SoundSampleIsInUse(uiChannel))
SoundRemoveSampleFlags(uiSample, SAMPLE_LOCKED);
pSoundList[uiChannel].uiSample=NO_SAMPLE;
}
if(pSoundList[uiChannel].hMSSStream!=NULL)
{
AIL_close_stream(pSoundList[uiChannel].hMSSStream);
pSoundList[uiChannel].hMSSStream=NULL;
if(pSoundList[uiChannel].EOSCallback!=NULL)
pSoundList[uiChannel].EOSCallback(pSoundList[uiChannel].pCallbackData);
pSoundList[uiChannel].uiSample=NO_SAMPLE;
}
if(pSoundList[uiChannel].hM3D!=NULL)
{
AIL_stop_3D_sample(pSoundList[uiChannel].hM3D);
AIL_release_3D_sample_handle(pSoundList[uiChannel].hM3D);
pSoundList[uiChannel].hM3D=NULL;
uiSample=pSoundList[uiChannel].uiSample;
// if this was a random sample, decrease the iteration count
if(pSampleList[uiSample].uiFlags&SAMPLE_RANDOM)
pSampleList[uiSample].uiInstances--;
if(pSoundList[uiChannel].EOSCallback!=NULL)
pSoundList[uiChannel].EOSCallback(pSoundList[uiChannel].pCallbackData);
if(pSoundList[uiChannel].fLooping && !SoundSampleIsInUse(uiChannel))
SoundRemoveSampleFlags(uiSample, SAMPLE_LOCKED);
pSoundList[uiChannel].uiSample=NO_SAMPLE;
}
if( pSoundList[uiChannel].hFile != 0 )
{
FileClose( pSoundList[uiChannel].hFile );
pSoundList[uiChannel].hFile = 0;
pSoundList[uiChannel].uiSample=NO_SAMPLE;
}
return(TRUE);
}
}
return(FALSE);
}
//*******************************************************************************
// SoundGetDriverHandle
//
// Returns: Pointer to the current sound driver
//
//*******************************************************************************
HDIGDRIVER SoundGetDriverHandle(void)
{
return(hSoundDriver);
}
// FUNCTIONS TO SET / RESET SAMPLE FLAGS
void SoundSetSampleFlags( UINT32 uiSample, UINT32 uiFlags )
{
// CHECK FOR VALUE SAMPLE
if((pSampleList[ uiSample ].uiFlags&SAMPLE_ALLOCATED) )
{
// SET
pSampleList[uiSample].uiFlags |= uiFlags;
}
}
void SoundRemoveSampleFlags( UINT32 uiSample, UINT32 uiFlags )
{
// CHECK FOR VALID SAMPLE
if((pSampleList[ uiSample ].uiFlags&SAMPLE_ALLOCATED) )
{
//REMOVE
pSampleList[uiSample].uiFlags &= (~uiFlags);
}
}
//*******************************************************************************
// SoundSampleIsInUse
//
// Returns: TRUE if the sample index is currently being played by the system.
//
//*******************************************************************************
BOOLEAN SoundSampleIsInUse(UINT32 uiSample)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if((pSoundList[uiCount].uiSample==uiSample) && SoundIsPlaying(uiCount))
return(TRUE);
}
return(FALSE);
}
//*****************************************************************************************
// SoundFileIsPlaying
//
// Returns true or false on whether a certain file is currently being played. This function
// will only work on sounds loaded into the cache, it will NOT work on streamed sounds.
//
// Returns BOOLEAN -
//
// CHAR8 *pFilename -
//
// Created: 2/24/00 Derek Beland
//*****************************************************************************************
BOOLEAN SoundFileIsPlaying(CHAR8 *pFilename)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if(SoundIndexIsPlaying(uiCount))
{
if(stricmp(pSampleList[pSoundList[uiCount].uiSample].pName, pFilename)==0)
return(TRUE);
}
}
return(FALSE);
}
//*****************************************************************************************
// SoundSampleSetVolumeRange
//
// Sets the minimum and maximum volume for a sample.
//
// Returns nothing.
//
// UINT32 uiSample - Sample handle
// UINT32 uiVolMin - Minimum volume
// UINT32 uiVolMax - Maximum volume
//
// Created: 10/29/97 Andrew Emmons
//*****************************************************************************************
void SoundSampleSetVolumeRange(UINT32 uiSample, UINT32 uiVolMin, UINT32 uiVolMax)
{
Assert((uiSample >= 0) && (uiSample < SOUND_MAX_CACHED));
pSampleList[uiSample].uiVolMin=uiVolMin;
pSampleList[uiSample].uiVolMax=uiVolMax;
}
//*****************************************************************************************
// SoundSampleSetPanRange
//
// Sets the left/right pan values for a sample.
//
// Returns nothing.
//
// UINT32 uiSample - Sample handle
// UINT32 uiPanMin - Left setting
// UINT32 uiPanMax - Right setting
//
// Created: 10/29/97 Andrew Emmons
//*****************************************************************************************
void SoundSampleSetPanRange(UINT32 uiSample, UINT32 uiPanMin, UINT32 uiPanMax)
{
Assert((uiSample >= 0) && (uiSample < SOUND_MAX_CACHED));
pSampleList[uiSample].uiPanMin=uiPanMin;
pSampleList[uiSample].uiPanMax=uiPanMax;
}
//*****************************************************************************************
// SoundSetMusic
//
// Marks a sample as being music. Cannot be stopped by anything other than SoundStopMusic.
//
// Returns nothing.
//
// UINT32 uiSound - Sound instance to stop
//
// Created: 3/16/00 Derek Beland
//*****************************************************************************************
void SoundSetMusic(UINT32 uiSoundID)
{
UINT32 uiSound=SoundGetIndexByID(uiSoundID);
if(uiSound!=NO_SAMPLE)
pSoundList[uiSound].fMusic=TRUE;
}
//*****************************************************************************************
// SoundStopMusic
//
// Stops any sound instance with the music flag.
//
// Returns nothing.
//
// Created: 3/16/00 Derek Beland
//*****************************************************************************************
BOOLEAN SoundStopMusic(void)
{
UINT32 uiCount;
BOOLEAN fStopped=FALSE;
if(fSoundSystemInit)
{
for(uiCount=0; uiCount < SOUND_MAX_CHANNELS; uiCount++)
{
if((pSoundList[uiCount].hMSS!=NULL) || (pSoundList[uiCount].hMSSStream!=NULL) || (pSoundList[uiCount].hM3D!=NULL))
{
if(pSoundList[uiCount].fMusic)
{
SoundStop(pSoundList[uiCount].uiSoundID);
fStopped=TRUE;
}
}
}
}
return(fStopped);
}
//*****************************************************************************************
//
//
//
//
// New 3D Sound Code
//
//
//
//
//*****************************************************************************************
//*****************************************************************************************
// Sound3DSetProvider
//
// Sets the name of the 3D provider to initialize with.
//
// Returns nothing.
//
// CHAR8 *pProviderName - Pointer to provider name
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetProvider(CHAR8 *pProviderName)
{
Assert(pProviderName);
if(pProviderName)
{
gpProviderName = (CHAR8 *)MemAlloc(strlen(pProviderName)+1);
strcpy(gpProviderName, pProviderName);
}
}
//*****************************************************************************************
// Sound3DInitProvider
//
// Attempt
//
// Returns BOOLEAN -
//
// CHAR8 *pProviderName -
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
BOOLEAN Sound3DInitProvider(CHAR8 *pProviderName)
{
HPROENUM hEnum=HPROENUM_FIRST;
HPROVIDER hProvider=0;
BOOLEAN fDone=FALSE;
CHAR8 *pName;
INT32 iResult;
// 3D sound providers depend on the 2D sound system being initialized first
if(!fSoundSystemInit || !pProviderName)
return(FALSE);
// We're already booted up
if(gh3DProvider)
return(TRUE);
while(!fDone)
{
if(!AIL_enumerate_3D_providers(&hEnum, &hProvider, &pName))
fDone=TRUE;
else if(hProvider)
{
if(strcmp(pProviderName, pName)==0)
{
fDone=TRUE;
if(AIL_open_3D_provider(hProvider)==M3D_NOERR)
{
gh3DProvider = hProvider;
// Create a "listener" which represents our position in space
gh3DListener = AIL_open_3D_listener(gh3DProvider);
if(!gh3DListener)
{
AIL_close_3D_provider(gh3DProvider);
return(FALSE);
}
Sound3DSetListener(0.0f, 0.0f, 0.0f);
AIL_3D_provider_attribute(gh3DProvider, "EAX environment selection", &iResult);
if(iResult!=(-1))
gfUsingEAX = TRUE;
return(TRUE);
}
}
}
}
// We didn't find a provider with a matching name that would boot up
return(FALSE);
}
//*****************************************************************************************
// Sound3DShutdownProvider
//
// Shuts down and deallocates the 3D sound system
//
// Returns nothing.
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DShutdownProvider(void)
{
Sound3DStopAll();
if(gh3DListener)
{
AIL_close_3D_listener(gh3DListener);
gh3DListener=0;
}
if(gh3DProvider)
{
AIL_close_3D_provider(gh3DProvider);
gh3DProvider=0;
}
}
//*****************************************************************************************
// Sound3DSetPosition
//
// Sets the 3-space position of a sound sample.
//
// Returns nothing.
//
// UINT32 uiSample - ID of sample
// FLOAT flX - X coordinate
// FLOAT flY - Y coordinate
// FLOAT flZ - Z coordinate
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetPosition(UINT32 uiSample, FLOAT flX, FLOAT flY, FLOAT flZ)
{
UINT32 uiChannel;
if(fSoundSystemInit && gh3DProvider)
{
if((uiChannel=SoundGetIndexByID(uiSample))!=NO_SAMPLE)
{
if(pSoundList[uiChannel].hM3D!=NULL)
{
AIL_set_3D_position(pSoundList[uiChannel].hM3D, flX, flY, flZ);
}
}
}
}
//*****************************************************************************************
// Sound3DSetVelocity
//
// Sets the velocity of a sample. This is important for calculation of doppler effect (pitch
// shifting, think of a train whistle as it passes by you).
//
// Returns nothing.
//
// UINT32 uiSample - ID of sample
// FLOAT flX - X coordinate
// FLOAT flY - Y coordinate
// FLOAT flZ - Z coordinate
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetVelocity(UINT32 uiSample, FLOAT flX, FLOAT flY, FLOAT flZ)
{
UINT32 uiChannel;
if(fSoundSystemInit && gh3DProvider)
{
if((uiChannel=SoundGetIndexByID(uiSample))!=NO_SAMPLE)
{
if(pSoundList[uiChannel].hM3D!=NULL)
{
}
}
}
}
//*****************************************************************************************
// Sound3DSetListener
//
// Sets the listener location. This should be set to the current camera location.
//
// Returns nothing.
//
// FLOAT flX - X coordinate
// FLOAT flY - Y coordinate
// FLOAT flZ - Z coordinate
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetListener(FLOAT flX, FLOAT flY, FLOAT flZ)
{
if(fSoundSystemInit && gh3DListener)
AIL_set_3D_position(gh3DListener, flX, flY, flZ);
}
//*****************************************************************************************
// Sound3DSetFacing
//
// Sets the orientation of the listener. The inputs are two vectors that are *always* at
// right angles to each other. The first is the facing vector, and the second is the up
// vector, which points out of the top of the listeners head.
//
// Returns nothing.
//
// FLOAT flXFace - X coordinate facing
// FLOAT flYFace - Y coordinate facing
// FLOAT flZFace - Z coordinate facing
// FLOAT flXUp - X coordinate up
// FLOAT flYUp - Y coordinate up
// FLOAT flZUp - Z coordinate up
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetFacing(FLOAT flXFace, FLOAT flYFace, FLOAT flZFace, FLOAT flXUp, FLOAT flYUp, FLOAT flZUp)
{
if(fSoundSystemInit && gh3DListener)
AIL_set_3D_orientation(gh3DListener, flXFace, flYFace, flZFace, flXUp, flYUp, flZUp);
}
//*****************************************************************************************
// Sound3DSetDirection
//
// Sets the orientation of the listener. The inputs are two vectors that are *always* at
// right angles to each other. The first is the facing vector, and the second is the up
// vector, which points out of the top of the listeners head.
//
// Returns nothing.
//
// FLOAT flXFace - X coordinate facing
// FLOAT flYFace - Y coordinate facing
// FLOAT flZFace - Z coordinate facing
// FLOAT flXUp - X coordinate up
// FLOAT flYUp - Y coordinate up
// FLOAT flZUp - Z coordinate up
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetDirection(UINT32 uiSample, FLOAT flXFace, FLOAT flYFace, FLOAT flZFace, FLOAT flXUp, FLOAT flYUp, FLOAT flZUp)
{
UINT32 uiChannel;
if(fSoundSystemInit && gh3DProvider)
{
if((uiChannel=SoundGetIndexByID(uiSample))!=NO_SAMPLE)
{
if(pSoundList[uiChannel].hM3D!=NULL)
{
AIL_set_3D_orientation(pSoundList[uiChannel].hM3D, flXFace, flYFace, flZFace, flXUp, flYUp, flZUp);
}
}
}
}
//*****************************************************************************************
// Sound3DSetFalloff
//
// Sets the falloff of the sound which determines the maximum radius at which the sample
// produces any sound, and the minimum distance before the sound volume begins to fall off
// towards zero.
//
// Returns nothing.
//
// UINT32 uiSample - Sample index
// FLOAT flMax - Point at which the sound volume is zero
// FLOAT flMin - Point at which the sound volume begins to fall off
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetFalloff(UINT32 uiSample, FLOAT flMax, FLOAT flMin)
{
UINT32 uiChannel;
// max = far
// min = near
if(fSoundSystemInit && gh3DProvider)
{
if((uiChannel=SoundGetIndexByID(uiSample))!=NO_SAMPLE)
{
if(pSoundList[uiChannel].hM3D!=NULL)
{
AIL_set_3D_sample_distances(pSoundList[uiChannel].hM3D, flMax, flMin);
}
}
}
}
//*****************************************************************************************
// Sound3DActiveSounds
//
// Returns the number of active sounds.
//
// Returns INT32 - Number of 3D sounds playing
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
INT32 Sound3DActiveSounds(void)
{
return((INT32)AIL_active_3D_sample_count(gh3DProvider));
}
//*****************************************************************************************
// Sound3DSetEnvironment
//
// Sets the current environment type for the listener. This determines which atmospheric
// effects are applied to the 3D sounds. Eg. Caves, underwater, etc.
//
// Returns nothing.
//
// INT32 iEnvironment - Index of environment type
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DSetEnvironment(INT32 iEnvironment)
{
if(fSoundSystemInit && gh3DProvider)
{
}
}
//*****************************************************************************************
// Sound3DPlay
//
// Starts a 3D sample playing.
//
// Returns UINT32 - Sound index
//
// STR pFilename - Pointer to filename of sound
// SOUNDPARMS *pParms - Parameter struct (or NULL for defaults)
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
UINT32 Sound3DPlay(STR pFilename, SOUND3DPARMS *pParms)
{
UINT32 uiSample, uiChannel;
if(fSoundSystemInit && gh3DProvider)
{
if((uiSample=SoundLoadSample(pFilename))!=NO_SAMPLE)
{
if((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR)
{
return(Sound3DStartSample(uiSample, uiChannel, pParms));
}
}
else
{
FastDebugMsg(String("Sound3DPlay: ERROR: Failed loading sample %s\n", pFilename ) );
}
}
return(SOUND_ERROR);
}
//*******************************************************************************
// Sound3DStartSample
//
// Starts up a sample on the specified channel. Override parameters are passed
// in through the structure pointer pParms. Any entry with a value of 0xffffffff
// will be filled in by the system.
//
// Returns: Unique sound ID if successful, SOUND_ERROR if not.
//
//*******************************************************************************
UINT32 Sound3DStartSample(UINT32 uiSample, UINT32 uiChannel, SOUND3DPARMS *pParms)
{
UINT32 uiSoundID;
CHAR8 AILString[200];
if(!fSoundSystemInit || !gh3DProvider)
return(SOUND_ERROR);
// Stereo samples have no purpose in 3D, nor MP3 files
if(pSampleList[uiSample].fStereo || strstr(pSampleList[uiSample].pName, ".MP3"))
return(SOUND_ERROR);
if((pSoundList[uiChannel].hM3D = AIL_allocate_3D_sample_handle(gh3DProvider))==NULL)
{
sprintf(AILString, "AIL3D Error: %s", AIL_last_error());
DbgMessage(TOPIC_GAME, DBG_LEVEL_0, AILString);
return(SOUND_ERROR);
}
if(!AIL_set_3D_sample_file(pSoundList[uiChannel].hM3D, pSampleList[uiSample].pData))
{
AIL_release_3D_sample_handle(pSoundList[uiChannel].hM3D);
pSoundList[uiChannel].hM3D=NULL;
sprintf(AILString, "AIL3D Set Sample Error: %s", AIL_last_error());
DbgMessage(TOPIC_GAME, DBG_LEVEL_0, AILString);
return(SOUND_ERROR);
}
// Store the natural playback rate before we modify it below
pSampleList[uiSample].uiSpeed=AIL_3D_sample_playback_rate(pSoundList[uiChannel].hM3D);
if(pSampleList[uiSample].uiFlags & SAMPLE_RANDOM)
{
if((pSampleList[uiSample].uiSpeedMin != SOUND_PARMS_DEFAULT) && (pSampleList[uiSample].uiSpeedMax != SOUND_PARMS_DEFAULT))
{
UINT32 uiSpeed = pSampleList[uiSample].uiSpeedMin+Random(pSampleList[uiSample].uiSpeedMax-pSampleList[uiSample].uiSpeedMin);
AIL_set_3D_sample_playback_rate(pSoundList[uiChannel].hM3D, uiSpeed);
}
}
else
{
if((pParms!=NULL) && (pParms->uiSpeed!=SOUND_PARMS_DEFAULT))
AIL_set_3D_sample_playback_rate(pSoundList[uiChannel].hM3D, pParms->uiSpeed);
}
if((pParms!=NULL) && (pParms->uiPitchBend!=SOUND_PARMS_DEFAULT))
{
UINT32 uiRate = AIL_3D_sample_playback_rate(pSoundList[uiChannel].hM3D);
UINT32 uiBend = uiRate * pParms->uiPitchBend/100;
AIL_set_3D_sample_playback_rate(pSoundList[uiChannel].hM3D, uiRate + (Random(uiBend*2)-uiBend));
}
if((pParms!=NULL) && (pParms->uiVolume!=SOUND_PARMS_DEFAULT))
AIL_set_3D_sample_volume(pSoundList[uiChannel].hM3D, pParms->uiVolume);
else
AIL_set_3D_sample_volume(pSoundList[uiChannel].hM3D, guiSoundDefaultVolume);
if((pParms!=NULL) && (pParms->uiLoop!=SOUND_PARMS_DEFAULT))
{
AIL_set_3D_sample_loop_count(pSoundList[uiChannel].hM3D, pParms->uiLoop);
// If looping infinately, lock the sample so it can't be unloaded
// and mark it as a looping sound
if(pParms->uiLoop==0)
{
pSampleList[uiSample].uiFlags|=SAMPLE_LOCKED;
pSoundList[uiChannel].fLooping=TRUE;
}
}
if((pParms!=NULL) && (pParms->uiPriority!=SOUND_PARMS_DEFAULT))
pSoundList[uiChannel].uiPriority=pParms->uiPriority;
else
pSoundList[uiChannel].uiPriority=PRIORITY_MAX;
if((pParms!=NULL) && ((UINT32)pParms->EOSCallback!=SOUND_PARMS_DEFAULT))
{
pSoundList[uiChannel].EOSCallback=pParms->EOSCallback;
pSoundList[uiChannel].pCallbackData=pParms->pCallbackData;
}
else
{
pSoundList[uiChannel].EOSCallback=NULL;
pSoundList[uiChannel].pCallbackData=NULL;
}
AIL_set_3D_position(pSoundList[uiChannel].hM3D, pParms->Pos.flX, pParms->Pos.flY, pParms->Pos.flZ);
AIL_set_3D_velocity_vector(pSoundList[uiChannel].hM3D, pParms->Pos.flVelX, pParms->Pos.flVelY, pParms->Pos.flVelZ);
AIL_set_3D_orientation(pSoundList[uiChannel].hM3D, pParms->Pos.flFaceX, pParms->Pos.flFaceY, pParms->Pos.flFaceZ, pParms->Pos.flUpX, pParms->Pos.flUpY, pParms->Pos.flUpZ);
// AIL_set_3D_sample_distances(pSoundList[uiChannel].hM3D, pParms->Pos.flFalloffMax, pParms->Pos.flFalloffMin);
AIL_set_3D_sample_distances(pSoundList[uiChannel].hM3D, 99999999.9f, 99999999.9f);
uiSoundID=SoundGetUniqueID();
pSoundList[uiChannel].uiSoundID=uiSoundID;
pSoundList[uiChannel].uiSample=uiSample;
pSoundList[uiChannel].uiTimeStamp=GetTickCount();
pSampleList[uiSample].uiCacheHits++;
AIL_start_3D_sample(pSoundList[uiChannel].hM3D);
return(uiSoundID);
}
//*****************************************************************************************
// Sound3DStopAll
//
// Stops all currently playing 3D samples.
//
// Returns nothing.
//
// Created: 8/17/99 Derek Beland
//*****************************************************************************************
void Sound3DStopAll(void)
{
UINT32 uiChannel;
// Stop all currently playing random sounds
for(uiChannel=0; uiChannel < SOUND_MAX_CHANNELS; uiChannel++)
{
if(pSoundList[uiChannel].hM3D!=NULL)
SoundStopIndex(uiChannel);
}
}
//*******************************************************************************
// Sound3DStartRandom
//
// Starts an instance of a random sample.
//
// Returns: TRUE if a new random sound was created, FALSE if nothing was done.
//
//*******************************************************************************
UINT32 Sound3DStartRandom(UINT32 uiSample, SOUND3DPOS *pPos)
{
UINT32 uiChannel, uiSoundID;
SOUND3DPARMS sp3DParms;
if(pPos && ((uiChannel=SoundGetFreeChannel())!=SOUND_ERROR))
{
memset(&sp3DParms, 0xff, sizeof(SOUND3DPARMS));
// sp3DParms.uiSpeed=pSampleList[uiSample].uiSpeedMin+Random(pSampleList[uiSample].uiSpeedMax-pSampleList[uiSample].uiSpeedMin);
sp3DParms.uiLoop=1;
sp3DParms.uiPriority=pSampleList[uiSample].uiPriority;
// memcpy(&sp3DParms.Pos, pPos, sizeof(SOUND3DPOS));
sp3DParms.Pos.flX=pPos->flX;
sp3DParms.Pos.flY=pPos->flY;
sp3DParms.Pos.flZ=pPos->flZ;
sp3DParms.Pos.flVelX=pPos->flVelX;
sp3DParms.Pos.flVelY=pPos->flVelY;
sp3DParms.Pos.flVelZ=pPos->flVelZ;
sp3DParms.Pos.flFaceX=pPos->flFaceX;
sp3DParms.Pos.flFaceY=pPos->flFaceY;
sp3DParms.Pos.flFaceZ=pPos->flFaceZ;
sp3DParms.Pos.flUpX=pPos->flUpX;
sp3DParms.Pos.flUpY=pPos->flUpY;
sp3DParms.Pos.flUpZ=pPos->flUpZ;
sp3DParms.Pos.flFalloffMax=pPos->flFalloffMax;
sp3DParms.Pos.flFalloffMin=pPos->flFalloffMin;
sp3DParms.Pos.uiVolume=pPos->uiVolume;
sp3DParms.uiVolume=pPos->uiVolume;
if((uiSoundID=Sound3DStartSample(uiSample, uiChannel, &sp3DParms))!=SOUND_ERROR)
{
pSampleList[uiSample].uiTimeNext=GetTickCount()+pSampleList[uiSample].uiTimeMin+Random(pSampleList[uiSample].uiTimeMax-pSampleList[uiSample].uiTimeMin);
pSampleList[uiSample].uiInstances++;
return(uiSoundID);
}
}
return(NO_SAMPLE);
}
//*****************************************************************************************
// Sound3DSetRoomType
//
// Sets the environment presets (reverb, chorus, etc) for 3D sounds. Currently only
// has effect for EAX cards.
//
// Returns nothing.
//
// UINT32 uiRoomType - Index of room type (see Soundman.h e_EAXRoomTypes)
//
// Created: 8/23/99 Derek Beland
//*****************************************************************************************
void Sound3DSetRoomType(UINT32 uiRoomType)
{
if(gh3DProvider && gfUsingEAX && (guiRoomTypeIndex!=uiRoomType))
{
CHAR8 cName[128];
sprintf(cName, "EAX_ENVIRONMENT_%s", pEAXRoomTypes[uiRoomType]);
AIL_set_3D_provider_preference(gh3DProvider, cName, (void *)(&uiRoomType));
guiRoomTypeIndex = uiRoomType;
}
}
//*****************************************************************************************
// Sound3DChannelsUsed
//
//
//
// Returns UINT32 -
//
// Created: 5/26/00 Derek Beland
//*****************************************************************************************
UINT32 Sound3DChannelsInUse(void)
{
UINT32 uiChannel, uiUsed=0;
// Stop all currently playing random sounds
for(uiChannel=0; uiChannel < SOUND_MAX_CHANNELS; uiChannel++)
{
if(pSoundList[uiChannel].hM3D!=NULL)
uiUsed++;
}
return(uiUsed);
}
//*****************************************************************************************
// SoundStreamsInUse
//
//
//
// Returns UINT32 -
//
// Created: 5/26/00 Derek Beland
//*****************************************************************************************
UINT32 SoundStreamsInUse(void)
{
UINT32 uiChannel, uiUsed=0;
// Stop all currently playing random sounds
for(uiChannel=0; uiChannel < SOUND_MAX_CHANNELS; uiChannel++)
{
if(pSoundList[uiChannel].hMSSStream!=NULL)
uiUsed++;
}
return(uiUsed);
}
//*****************************************************************************************
// Sound2DChannelsInUse
//
//
//
// Returns UINT32 -
//
// Created: 5/26/00 Derek Beland
//*****************************************************************************************
UINT32 Sound2DChannelsInUse(void)
{
UINT32 uiChannel, uiUsed=0;
// Stop all currently playing random sounds
for(uiChannel=0; uiChannel < SOUND_MAX_CHANNELS; uiChannel++)
{
if(pSoundList[uiChannel].hMSS!=NULL)
uiUsed++;
}
return(uiUsed);
}
//*****************************************************************************************
// SoundChannelsInUse
//
//
//
// Returns UINT32 -
//
// Created: 5/26/00 Derek Beland
//*****************************************************************************************
UINT32 SoundTotalChannelsInUse(void)
{
UINT32 uiChannel, uiUsed=0;
// Stop all currently playing random sounds
for(uiChannel=0; uiChannel < SOUND_MAX_CHANNELS; uiChannel++)
{
if(SoundIndexIsPlaying(uiChannel))
uiUsed++;
}
return(uiUsed);
}