/*********************************************************************************************** * * Copyright © DreamWorks Interactive. 1997 * * Contents: * Audio classes: * * Bugs: * * To do: * * NOTE: * THIS FILE SHOULD NOT BE INCLUDED FROM ANYWHERE WITHIN THE PROJECT EXCEPT * FROM WITHIN THE AUDIO SYSTEM OR GUIAPP.CPP.. IF IT IS INCLUDED IT WILL * CAUSE BUILD ERRORS DUE TO THE DIRECTSOUND FILES. *********************************************************************************************** * * $Log:: /JP2_PC/Source/Lib/Audio/Audio.hpp $ * * 78 10/02/98 3:53a Rwyatt * Changed an int 3 to an assert * * 77 9/30/98 2:10a Rwyatt * Added bool for thread locked * * 76 9/29/98 1:04a Rwyatt * Thread callback is now set to 80ms * * 75 9/28/98 4:59a Rwyatt * All Audio is now defer loaded * * 74 9/23/98 12:09p Rwyatt * Added support for NULL samples while audio is enabled * * 73 9/21/98 3:32a Rwyatt * Loader thread cano now be paused. All clenup code has been modifed to handle this. * * 72 98/09/17 17:47 Speter * Must include BuildVer for VER_TEST etc. * * 71 9/15/98 8:40p Shernd * audio volume changes * * 70 9/08/98 4:10a Rwyatt * New member for the dynamically loading of the sound DLL and a new interface pointer for the * A3D control interface. * * 69 9/04/98 2:56a Rwyatt * New constructor for CAudio, new thread members * * 68 9/01/98 3:05p Rwyatt * New data elements in CSample. * Assert in release mode if the pseudo 3D buffers overflow as this will corrupt the following * data. * * 67 8/25/98 11:27a Rvande * Extra access specifier removed * * 66 8/23/98 2:23a Rwyatt * Added support thread when audio is disabled. This thread allows sub titles to be created in * the background without blocking. Construction and destruction of samples has been changed to * give a data flow flow to that when audio is enabled. * * 65 8/21/98 2:25a Rwyatt * Fixed streaming cutoff * The cleanup code now checks that audio is present. * * 64 8/19/98 1:42p Rwyatt * Fixes to VC6.0 warnings * * 63 98.08.13 4:25p Mmouni * Changes for VC++ 5.0sp3 compatibility. * * 62 8/10/98 5:24p Rwyatt * Initial EAX settings now have no reverb * * 61 8/04/98 3:57p Rwyatt * Support to set all EAX environment properties * * 60 7/29/98 10:50a Rwyatt * Added initial EAX support * * 59 7/20/98 10:24p Pkeet * Added headers to allow the library to compile. * * 58 7/14/98 3:57p Rwyatt * Changed the number of fading samples * * 57 6/08/98 12:53p Rwyatt * Samples now have a master volume. * * 56 5/25/98 6:47p Pkeet * Added casts to allow the project to build. * * 55 5/24/98 10:01p Rwyatt * New functions to return the presence of 3D audio hardware and the use of hardware. * * 54 5/23/98 9:18p Rwyatt * Removed all traces of the load library code. * * 53 5/09/98 5:35p Bbell * Attenuate from MaxVolDistance to edge of trigger, rather than having a discontinuity at the * MaxVolDistance. * * 52 5/06/98 3:35p Rwyatt * New CAudio memebers to hold the DLL handle of wither DSound.dll or A3D.dll. New CSample * function to set the transfer. * * 51 4/29/98 7:00p Rwyatt * Changed the fade sample member function so that it takes a stop flag. The threaded fader now * sets a request stop flag instead of stopping the sample. * * 50 4/27/98 7:26p Rwyatt * New data member in CSample and the deferred ambient structure for max volume distance. * * 49 3/09/98 10:53p Rwyatt * New static function to create a sample through a sound handle and a database * * 48 3/09/98 10:51p Rwyatt * Corrected bSampleError macro to account for new error messages * * 47 2/21/98 5:54p Rwyatt * Added a new CSample value for a failed instance, psamINSTANCE_FAILED * * 46 2/06/98 8:20p Rwyatt * CAudio quality settings are static so they survive the world database being destroyed. * * 45 2/03/98 2:28p Rwyatt * Temp check in. * * 44 1/07/98 5:19p Shernd * Added SetVolume to Primary Sound Buffer * * 43 12/17/97 2:53p Rwyatt * CreateInstance can now instance samples from one spatial type to another, by default the * instance is the same. * * 42 11/22/97 10:43p Rwyatt * Uses new global audio pointer which is a static member of the CAudio class, therefore there * can be only one. * Deferred loading with maximum of 100K chunks is implemented * * 41 11/18/97 9:40p Rwyatt * temp check-in: * Added callback structure for deferred loading * * 40 11/16/97 4:58a Rwyatt * Changed the MAX_PSEUDO3D_SAMPLES from 8 to 48, this value must be larger than * MAX_AMBIENT_SAMPLES defined in AudioDaemon.cpp * * 39 11/14/97 7:20p Rwyatt * A new constructor used in sample instancing * * 38 11/13/97 11:52p Rwyatt * New audio and sample classes for the new system * Mnay modifications, many new access members and lots more functionality. * * 37 11/07/97 9:22a Shernd * Add member function to Expose the Direct Sound Interface for use with Smacker * * 36 10/23/97 6:52p Rwyatt * New functions to control speaker configuration * * 35 7/23/97 8:38p Rwyatt * New functions for finding a sample in the cache and for getting the last cache hash value * * 34 7/14/97 12:27p Rwyatt * New audio library with a generic set of flags for creating any sample type. * * 33 7/07/97 11:54p Rwyatt * Initial tidy up after E3 crunch, sample class still needs to be done * * 32 6/13/97 6:06p Rwyatt * Sample cahce is now 48 to account for the duplicate samples that could get loaded. * * 31 6/09/97 12:09p Rwyatt * CSample now has members to control Audio streaming, * * 30 6/06/97 12:13p Rwyatt * New members to CSample to stop and loop samples. New structures and defines so that CAudio * can handle ambient loops * * 29 6/04/97 7:02p Rwyatt * Added memeber for getting and setting the output format. * * 28 6/02/97 4:52p Rwyatt * Added support for a Listener and relative path names, * * 27 5/29/97 8:31p Rwyatt * Added DirectX path to DirectX includes * * 26 5/29/97 6:20p Rwyatt * * 25 5/29/97 4:17p Rwyatt * DirectSound audio support. * * 24 5/25/97 8:31p Rwyatt * Removed all of Brandon's RSX code and renamed AudioDeemone to AudioDaemon. * ***********************************************************************************************/ #ifndef HEADER_LIB_AUDIO_AUDIO_HPP #define HEADER_LIB_AUDIO_AUDIO_HPP // DO NOT INCLUDE COMMON.HPP IN AUDIO FILES, // ALL OTHER AUDIO FILES SHOULD INCLUDE AUDIO.HPP INSTEAD #pragma warning(disable:4237) #pragma warning(disable:4786) #include "BuildVer.hpp" #include "SoundTypes.hpp" #include "SoundDefs.hpp" #include "dsound.h" #include "Ia3d.h" #include "Lib/Sys/DebugConsole.hpp" #include "lib/sys/memorylog.hpp" #include #include "AudioLoader.hpp" #include "Subtitle.hpp" #include //********************************************************************************************** // // the number of seconds of in memory sound for a streamed sample #define iSTREAM_BUFFER_LENGTH 1 // the maximum audio streams #define MAX_CONCURRENT_STREAMS 4 // the maximum number of pseudo 3D sounds that can exist at once, not all of these can be played #define MAX_PSEUDO3D_SAMPLES 32 // the maximum number of samples that can be faded at a time #define MAX_FADING_SAMPLES 1 // Only music can fade at this time // the maximum number of deferred actions that can be present at any given time #define MAX_DEFERRED_OPS 16 // length in seconds of a streaming buffer #define fSTREAM_LENGTH (1.5f) // the period in ms of the callback thread, the value here should be carefully choosen based // on the following factors. The length of the streaming buffers (defined above), the number of // streams that are likely to be playing at once and complexity of the stream. If 1 call back is // done every second, 4 streams are playing and the streams are all compressed then at every // callback a total of 4 seconds needs to be loaded and decompressed which may have an effect // on the frame rate. #define iSTREAM_CALLBACK_PERIOD (80) // milliseconds // half of half power in dBs or 20*log10(2)/2 #define fTHREE_DBS (3.010299957f) //********************************************************************************************** // forward declarations // class CSample; //********************************************************************************************* // This is returned as the sample handle from the instance functions if the source of the // instance is still loading // #define psamINSTANCE_IGNORE (CSample*)0x00000001 //********************************************************************************************** // This is passed to the callback function if a deferred sample is deleted. The callback may or // may not care about this but it probably needs to free allocated memory. // #define psamDEFER_LOAD_DELETE (CSample*)0x00000002 //********************************************************************************************* // This is returned by the create instance function when we failed to create the instance. // #define psamINSTANCE_FAILED (CSample*)0x00000003 //********************************************************************************************* // This is returned by the create instance function when we failed to create the instance. // #define bSampleError(psam) ( (((uint32)(psam))<=(0x00000003)) && ((psam)!=0) ) //********************************************************************************************** // define the callback function for defered load operations // typedef void (*TDeferCallback)(CSample*, void*); // prefix: dlcbfn // //************************************** //********************************************************************************************** // structure that controls fading audio... // struct SAudioFade // prefix: af // //************************************** { CSample* psam; float fDeltaVol; bool bStopAtMinimum; }; //********************************************************************************************** // structure that controls the EAX enviroment. This is binary compatible with the // EAX_REVERBPROPERTIES defined in EAX.h // struct SAudioEnvironment // prefix: aenv // //************************************** { uint32 u4Environment; // 0 to EAX_ENVIRONMENT_COUNT-1 float fVolume; // 0 to 1 float fDecayTime; // seconds, 0.1 to 100 float fDamping; // 0 to 1 }; //********************************************************************************************** struct SStreamedSample // prefix: ssam { CSample* psam; uint32 u4StopTick; // only used when audio is disabled. }; //********************************************************************************************** // template class CDSSize: public T // // Handy template class for setting the size of structures // // Example: instead of saying: // // DSBUFFERDESC sd; // memset(&sd, 0, sizeof(sd)); // sd.dwSize = sizeof(sd); // // Say: // // CDSSize sd; // //************************************** { public: // Constructor just sets everything to 0, then sets the correct dwSize field. CDSSize() { memset(this, 0, sizeof(*this)); dwSize = sizeof(*this); } }; //********************************************************************************************** #define u4SEMAPHORE_COUNT 2 //********************************************************************************************** // // CAudio // class CAudio // prefix: au { public: //***************************************************************************************** // constructors and deconstrutors // //***************************************************************************************** // CAudio ( void* h_wnd, bool b_enable, // set to false and the game will run without audio bool b_hardware // should we use 3D audio hardware ); //***************************************************************************************** // ~CAudio(); //***************************************************************************************** // Create the required audio COM objects // void CreateAudio ( void* h_wnd, bool b_enable ); //***************************************************************************************** // void DestroyAudio(bool b_shutdown); //***************************************************************************************** // void SetBasePathName(const char* str_path); //***************************************************************************************** // void AudioEnable(bool b_enable); //***************************************************************************************** // void SetNoAudio(); //***************************************************************************************** // bool bAudioActive() { return bSoundEnabled; } //***************************************************************************************** // std::string& GetBasePathName() { return strBasePath; } //***************************************************************************************** // bool bCanChangeFormat() { return bChangeFormat; } //***************************************************************************************** // void SetOutputFormat ( uint32 u4_frequency, ESoundChannels esc, ESoundBits esb ); //***************************************************************************************** // ESpeakerConfig esconGetSpeakerConfig(); //***************************************************************************************** // void SetSpeakerConfig ( ESpeakerConfig escon_speakers ); //***************************************************************************************** // uint32 u4GetFormat() { return u4Format; } //***************************************************************************************** // bool bAddAmbient ( CSample* psam, // sample to use for ambient, must be looping float f_x, // x pos in world float f_y, // y pos in world (up) float f_z, // z pos in world (into screen) float f_atten // attenuation in 100ths of a dB per meter. ); //***************************************************************************************** // sample creation functions // CSample* CreateSample ( const char* str_fname, uint32 u4_flags ); //***************************************************************************************** // void PositionListener(float f_x,float f_y,float f_z, bool b_immediate = true); //***************************************************************************************** // void OrientListener(float in_x,float in_y,float in_z, float up_x,float up_y,float up_z, bool b_immediate = true); //***************************************************************************************** // void CommitSettings(); //***************************************************************************************** // Create a raw direct sound buffer // LPDIRECTSOUNDBUFFER CreateDSBuffer ( uint32 u4_bytes, uint32 u4_frequency, ESoundChannels esc_channels, ESoundBits esb_bits, uint32 u4_create_flags ); //****************************************************************************************** // static CSample* psamCreateSample ( const char* str_fname, uint32 u4_flags, TDeferCallback pdlcbfn = NULL, void* pv_user = NULL ); //****************************************************************************************** // Memory constructors do not have a callback parameter // static CSample* psamCreateSample ( TSoundHandle sndhnd_sample, CAudioDatabase* padat, uint32 u4_flags, TDeferCallback pdlcbfn = NULL, void* pv_user = NULL ); //****************************************************************************************** // Add the specifed sample as a stream to active stream list // bool bAddStreamedSample(CSample*); //****************************************************************************************** // Remove the specifed sample as a stream to active stream list // void RemoveStreamedSample(CSample*); //****************************************************************************************** void ThreadProcessNoAudioSample ( CSample* psam, // the sample int32 i4_count // the index of this sample in the stream array ); //****************************************************************************************** // functions to return the position in world space of the listener // float fGetListenerX() { return fListenerX; } float fGetListenerY() { return fListenerY; } float fGetListenerZ() { return fListenerZ; } //****************************************************************************************** // return the distance to the listener. // float fGetSquaredListenerDistance ( float f_x, float f_y, float f_z ) { return ((f_x - fListenerX)*(f_x - fListenerX)) + ((f_y - fListenerY)*(f_y - fListenerY)) + ((f_z - fListenerZ)*(f_z - fListenerZ)); } //****************************************************************************************** // void AddPseudoSample(CSample* psam) { for (uint32 u4=0 ; u4GetStatus((DWORD*)&u4Status); Assert(hr==DS_OK); // convert it to our format if ((u4Status == DSBSTATUS_LOOPING) || (u4Status == DSBSTATUS_PLAYING)) return AU_BUFFER_STATUS_PLAYING; if (u4Status == DSBSTATUS_BUFFERLOST) return AU_BUFFER_STATUS_LOST; return AU_BUFFER_STATUS_NOTPLAYING; } //********************************************************************************************** // The instance flags are the same as the AU_CREATE flags passed to the sample constructor. // This enables instances of a sample to be of a different spatial type to their siblings. If // instance flags are zero then an identical instance is created. // CSample* psamCreateInstance ( uint32 u4_instance_flags = 0 ); //********************************************************************************************** void SetPosition ( float f_x, float f_y, float f_z, bool b_immediate = true ); //********************************************************************************************** void SetOrientation ( float f_x, float f_y, float f_z, bool b_immediate = true ); //********************************************************************************************** void SetFrustum ( float f_angle = AU_SOUND_FUSTRUM_DEFAULT_ANGLE, // angular displacement of the cone float f_volume = AU_SOUND_FUSTRUM_DEFAULT_VOLUME, // volume in dBs (0 = full volume -100dB silent) outside the cone bool b_immediate = true ); //********************************************************************************************** // attenuation is in dB/m (1.0 = 1dB/m therefore half volume will be at 6 meters) void SetAttenuation ( float f_atten, float f_mindist = 0.0f, // distance at which the attenuation is applied bool b_immediate = true ); //********************************************************************************************** void SetFrequency ( float f_freq ); //********************************************************************************************** void SetVolume ( float f_vol ); //********************************************************************************************** float fGetVolume() { return fVolume; } //********************************************************************************************** float fGetMasterVolume() { return fMasterVolume; } //********************************************************************************************** //Change the master volume of a sample void SetMasterVolume(float f_vol) { fMasterVolume = f_vol; SetVolume(fVolume); } //********************************************************************************************** // Get the actual play volume of a sample once it has been adjusted by its master volume float fGetAdjustedVolume() { float f_vol = fVolume; f_vol += fMasterVolume; if (f_vol>0.0f) f_vol = 0.0f; if (f_vol<-100.0f) f_vol = -100.0f; return f_vol; } //********************************************************************************************** void Lock ( uint32 u4_offset, uint32 u4_length ) { HRESULT hr; Assert(pDSBuffer); hr = pDSBuffer->Lock(u4_offset, u4_length, (void**)&pu1Lock1, (DWORD*)&u4Lock1Length, (void**)&pu1Lock2, (DWORD*)&u4Lock2Length, 0); Assert(hr == DS_OK); } //********************************************************************************************** void Unlock() { HRESULT hr; Assert(pDSBuffer); hr = pDSBuffer->Unlock(pu1Lock1, u4Lock1Length, pu1Lock2, u4Lock2Length); Assert(hr == DS_OK); } //********************************************************************************************** uint8* pu1Lock1Buffer() { return pu1Lock1; } //********************************************************************************************** uint8* pu1Lock2Buffer() { return pu1Lock2; } //********************************************************************************************** uint32 u4Lock1BufferLength() { return u4Lock1Length; } //********************************************************************************************** uint32 u4Lock2BufferLength() { return u4Lock2Length; } //********************************************************************************************** bool bSampleStreamed() { return (u4CreateFlags & AU_CREATE_STREAM) != 0; } //********************************************************************************************** bool bSampleLooped() { return (u4CreateFlags & AU_PLAY_LOOPED) != 0; } //********************************************************************************************** bool bSampleLoading() { return (u4CreateFlags & AU_CREATE_DEFER_LOAD) != 0; } //********************************************************************************************** uint32 u4SoundBufferLength() { return u4Length; } //********************************************************************************************** float fSamplePlayTime() { return fPlayTime; } //********************************************************************************************** // This is called when the streamer wants to stop the sample. It cannot call stop because of // semaphore issues. Instead it sets this lfag an expects the foreground to take care of it // when it gets a chance. void FlagStop() { u4CreateFlags |= AU_FLAG_STOP; } //********************************************************************************************** // Return true or flase depending on the state of the stop flag. bool bStopFlagged() { return (u4CreateFlags & AU_FLAG_STOP) != 0; } //********************************************************************************************** float fCalculateVolumeAttenuation() { float f_vol; float f_dist; // linear attenuation, distance * roll off per meter in dBs f_dist = sqrt(CAudio::pcaAudio->fGetSquaredListenerDistance(fWorldX, fWorldY, fWorldZ));// * -fAtten; // if the distance is less than the max vol distance then return max volume if (f_dist<=fMaxVolDistance) return 0.0f; f_vol = (f_dist - fMaxVolDistance) * -fAtten; if (f_vol<-100.0f) f_vol = -100.0f; return f_vol; } //********************************************************************************************** // // uint32 u4CreateFlags; // flags that the buffer was created with; uint32 u4Length; // length of the sound buffer in bytes float fPlayTime; // length of the sample in seconds float fVolume; // current volume of the sample uint32 u4Format; // format dword of the sample.... CCAULoad* pcauSample; // the loader responsible for this sample or NULL LPDIRECTSOUNDBUFFER pDSBuffer; // directSound interface LPDIRECTSOUND3DBUFFER pDS3DBuffer; // 3d interface, NULL if not 3D CAudioSubtitle* pasubSubtitle; // pointer to the sub title or NULL uint8* pu1Lock1; // base address of first half of lock uint8* pu1Lock2; // base address of second half of lock uint32 u4Lock1Length; // length of lock1 block uint32 u4Lock2Length; // length of lock2 block uint32 u4StreamLoadPosition; uint32 u4LastPlayCsr; uint32 u4BytesPlayed; float fAtten; float fMaxVolDistance;// Within this distance there is no attenuation float fWorldX; float fWorldY; float fWorldZ; float fFustrumAngle; float fOutsideVolume; float fMasterVolume; // What we should adjust the final volume by (+100 to -100 db, 0 being no change) TDeferCallback pdlcbfnCallback; void* pvUser; }; #endif