/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see .
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __SOUND__
#define __SOUND__
/*
===============================================================================
SOUND SHADER DECL
===============================================================================
*/
// unfortunately, our minDistance / maxDistance is specified in meters, and
// we have far too many of them to change at this time.
const float DOOM_TO_METERS = 0.0254f; // doom to meters
const float METERS_TO_DOOM = ( 1.0f / DOOM_TO_METERS ); // meters to doom
const float DB_SILENCE = -60.0f;
class idSoundSample;
// sound shader flags
static const int SSF_PRIVATE_SOUND = BIT( 0 ); // only plays for the current listenerId
static const int SSF_ANTI_PRIVATE_SOUND = BIT( 1 ); // plays for everyone but the current listenerId
static const int SSF_NO_OCCLUSION = BIT( 2 ); // don't flow through portals, only use straight line
static const int SSF_GLOBAL = BIT( 3 ); // play full volume to all speakers and all listeners
static const int SSF_OMNIDIRECTIONAL = BIT( 4 ); // fall off with distance, but play same volume in all speakers
static const int SSF_LOOPING = BIT( 5 ); // repeat the sound continuously
static const int SSF_PLAY_ONCE = BIT( 6 ); // never restart if already playing on any channel of a given emitter
static const int SSF_UNCLAMPED = BIT( 7 ); // don't clamp calculated volumes at 1.0
static const int SSF_NO_FLICKER = BIT( 8 ); // always return 1.0 for volume queries
static const int SSF_NO_DUPS = BIT( 9 ); // try not to play the same sound twice in a row
static const int SSF_VO = BIT( 10 ); // VO - direct a portion of the sound through the center channel (set automatically on shaders that contain files that start with "sound/vo/")
static const int SSF_MUSIC = BIT( 11 ); // Music - Muted when the player is playing his own music
// these options can be overriden from sound shader defaults on a per-emitter and per-channel basis
typedef struct
{
float minDistance;
float maxDistance;
float volume; // in dB. Negative values get quieter
float shakes;
int soundShaderFlags; // SSF_* bit flags
int soundClass; // for global fading of sounds
} soundShaderParms_t;
// sound classes are used to fade most sounds down inside cinematics, leaving dialog
// flagged with a non-zero class full volume
const int SOUND_MAX_CLASSES = 4;
// it is somewhat tempting to make this a virtual class to hide the private
// details here, but that doesn't fit easily with the decl manager at the moment.
class idSoundShader : public idDecl
{
public:
idSoundShader();
virtual ~idSoundShader();
virtual size_t Size() const;
virtual bool SetDefaultText();
virtual const char* DefaultDefinition() const;
virtual bool Parse( const char* text, const int textLength, bool allowBinaryVersion );
virtual void FreeData();
virtual void List() const;
// so the editor can draw correct default sound spheres
// this is currently defined as meters, which sucks, IMHO.
virtual float GetMinDistance() const; // FIXME: replace this with a GetSoundShaderParms()
virtual float GetMaxDistance() const;
// returns NULL if an AltSound isn't defined in the shader.
// we use this for pairing a specific broken light sound with a normal light sound
virtual const idSoundShader* GetAltSound() const;
virtual bool HasDefaultSound() const;
virtual const soundShaderParms_t* GetParms() const;
virtual int GetNumSounds() const;
virtual const char* GetSound( int index ) const;
private:
friend class idSoundWorldLocal;
friend class idSoundEmitterLocal;
friend class idSoundChannel;
// options from sound shader text
soundShaderParms_t parms; // can be overriden on a per-channel basis
int speakerMask;
const idSoundShader* altSound;
bool leadin; // true if this sound has a leadin
float leadinVolume; // allows light breaking leadin sounds to be much louder than the broken loop
idList entries;
private:
void Init();
bool ParseShader( idLexer& src );
};
/*
===============================================================================
SOUND EMITTER
===============================================================================
*/
// sound channels
static const int SCHANNEL_ANY = 0; // used in queries and commands to effect every channel at once, in
// startSound to have it not override any other channel
static const int SCHANNEL_ONE = 1; // any following integer can be used as a channel number
typedef int s_channelType; // the game uses its own series of enums, and we don't want to require casts
class idSoundEmitter
{
public:
virtual ~idSoundEmitter() {}
// a non-immediate free will let all currently playing sounds complete
// soundEmitters are not actually deleted, they are just marked as
// reusable by the soundWorld
virtual void Free( bool immediate ) = 0;
// the parms specified will be the default overrides for all sounds started on this emitter.
// NULL is acceptable for parms
virtual void UpdateEmitter( const idVec3& origin, int listenerId, const soundShaderParms_t* parms ) = 0;
// returns the length of the started sound in msec
virtual int StartSound( const idSoundShader* shader, const s_channelType channel, float diversity = 0, int shaderFlags = 0, bool allowSlow = true ) = 0;
// pass SCHANNEL_ANY to effect all channels
virtual void ModifySound( const s_channelType channel, const soundShaderParms_t* parms ) = 0;
virtual void StopSound( const s_channelType channel ) = 0;
// to is in Db, over is in seconds
virtual void FadeSound( const s_channelType channel, float to, float over ) = 0;
// returns true if there are any sounds playing from this emitter. There is some conservative
// slop at the end to remove inconsistent race conditions with the sound thread updates.
// FIXME: network game: on a dedicated server, this will always be false
virtual bool CurrentlyPlaying( const s_channelType channel = SCHANNEL_ANY ) const = 0;
// returns a 0.0 to 1.0 value based on the current sound amplitude, allowing
// graphic effects to be modified in time with the audio.
// just samples the raw wav file, it doesn't account for volume overrides in the
virtual float CurrentAmplitude() = 0;
// for save games. Index will always be > 0
virtual int Index() const = 0;
};
/*
===============================================================================
SOUND WORLD
There can be multiple independent sound worlds, just as there can be multiple
independent render worlds. The prime example is the editor sound preview
option existing simultaniously with a live game.
===============================================================================
*/
class idSoundWorld
{
public:
virtual ~idSoundWorld() {}
// call at each map start
virtual void ClearAllSoundEmitters() = 0;
virtual void StopAllSounds() = 0;
// get a new emitter that can play sounds in this world
virtual idSoundEmitter* AllocSoundEmitter() = 0;
// for load games, index 0 will return NULL
virtual idSoundEmitter* EmitterForIndex( int index ) = 0;
// query sound samples from all emitters reaching a given listener
virtual float CurrentShakeAmplitude() = 0;
// where is the camera/microphone
// listenerId allows listener-private and antiPrivate sounds to be filtered
virtual void PlaceListener( const idVec3& origin, const idMat3& axis, const int listenerId ) = 0;
// fade all sounds in the world with a given shader soundClass
// to is in Db, over is in seconds
virtual void FadeSoundClasses( const int soundClass, const float to, const float over ) = 0;
// menu sounds
virtual int PlayShaderDirectly( const char* name, int channel = -1 ) = 0;
// dumps the current state and begins archiving commands
virtual void StartWritingDemo( idDemoFile* demo ) = 0;
virtual void StopWritingDemo() = 0;
// read a sound command from a demo file
virtual void ProcessDemoCommand( idDemoFile* demo ) = 0;
// when cinematics are skipped, we need to advance sound time this much
virtual void Skip( int time ) = 0;
// pause and unpause the sound world
virtual void Pause() = 0;
virtual void UnPause() = 0;
virtual bool IsPaused() = 0;
// Write the sound output to multiple wav files. Note that this does not use the
// work done by AsyncUpdate, it mixes explicitly in the foreground every PlaceOrigin(),
// under the assumption that we are rendering out screenshots and the gameTime is going
// much slower than real time.
// path should not include an extension, and the generated filenames will be:
// _left.raw, _right.raw, or _51left.raw, _51right.raw,
// _51center.raw, _51lfe.raw, _51backleft.raw, _51backright.raw,
// If only two channel mixing is enabled, the left and right .raw files will also be
// combined into a stereo .wav file.
virtual void AVIOpen( const char* path, const char* name ) = 0;
virtual void AVIClose() = 0;
// SaveGame / demo Support
virtual void WriteToSaveGame( idFile* savefile ) = 0;
virtual void ReadFromSaveGame( idFile* savefile ) = 0;
virtual void SetSlowmoSpeed( float speed ) = 0;
virtual void SetEnviroSuit( bool active ) = 0;
};
/*
===============================================================================
SOUND SYSTEM
===============================================================================
*/
typedef struct
{
idStr name;
idStr format;
int numChannels;
int numSamplesPerSecond;
int num44kHzSamples;
int numBytes;
bool looping;
float lastVolume;
int start44kHzTime;
int current44kHzTime;
} soundDecoderInfo_t;
class idSoundSystem
{
public:
virtual ~idSoundSystem() {}
// All non-hardware initialization.
virtual void Init() = 0;
// Shutdown routine.
virtual void Shutdown() = 0;
// The renderWorld is used for visualization and light amplitude sampling.
virtual idSoundWorld* AllocSoundWorld( idRenderWorld* rw ) = 0;
virtual void FreeSoundWorld( idSoundWorld* sw ) = 0;
// Specifying NULL will cause silence to be played.
virtual void SetPlayingSoundWorld( idSoundWorld* soundWorld ) = 0;
// Some tools, like the sound dialog, may be used in both the game and the editor
// This can return NULL, so check!
virtual idSoundWorld* GetPlayingSoundWorld() = 0;
// Sends the current playing sound world information to the sound hardware.
virtual void Render() = 0;
virtual void MuteBackgroundMusic( bool mute ) = 0;
// Sets the final output volume to 0.
virtual void SetMute( bool mute ) = 0;
virtual bool IsMuted() = 0;
// Called by the decl system when a sound decl is reloaded
virtual void OnReloadSound( const idDecl* sound ) = 0;
// Called before freeing any sound sample resources
virtual void StopAllSounds() = 0;
// May be called to free memory for level loads
virtual void InitStreamBuffers() = 0;
virtual void FreeStreamBuffers() = 0;
// video playback needs to get this
virtual void* GetIXAudio2() const = 0;
// for the sound level meter window
virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ) = 0;
// Free all sounds loaded during the last map load
virtual void BeginLevelLoad() = 0;
// Load all sounds marked as used this level
virtual void EndLevelLoad() = 0;
virtual void Preload( idPreloadManifest& preload ) = 0;
// prints memory info
virtual void PrintMemInfo( MemInfo_t* mi ) = 0;
};
extern idSoundSystem* soundSystem;
#endif /* !__SOUND__ */