//
// ds3dvirtualbuffer.h
//
// Classes representing virtual DirectSound3D buffers that may or may not have
// a real DirectSoundBuffer associated with them at any given moment.
//
namespace SoundEngine {
//
// Tracks a buffer position over the lifetime of a virtual sound. This is
// designed to lighter-weight than an actual sound buffer, because the sound
// it represents may never be played. It's designed to be accurate, however,
// so that a buffer created using this information can start at the appropriate
// point.
//
class BufferPositionTracker
{
// the current position in the sound
DWORD m_dwPosition;
// the length of the buffer
DWORD m_dwLength;
// the sample rate of the sound, in bytes per second.
DWORD m_dwBytesPerSec;
// a mask of valid position bits (since a position must start on a sample
// boundary)
DWORD m_dwPositionMask;
// true iff end has been called on this
bool m_bEnding;
//
// Non-ASR data
//
// true if this is looping
bool m_bLooping;
//
// ASR data
//
// true iff this is an ASR sound.
bool m_bASR;
// the starting position of the sustain loop.
DWORD m_dwLoopStart;
// the length of the sustain loop
DWORD m_dwLoopLength;
public:
// Create a position tracker for a sound which plays until it reaches the
// end (for non-looping sounds) or has stop called upon it.
BufferPositionTracker(ISoundPCMData* pdata, bool bLooping = false);
// Creates a position tracker for an ASR buffer.
BufferPositionTracker(ISoundPCMData* pdata,
DWORD dwLoopStart, DWORD dwLoopLength);
//
// Events that the buffer tracker needs to know about
//
// the sound has been given a stop.
void Stop(bool bForceNow = false);
// the given number of miliseconds have elapsed
void AddTime(DWORD dwElapsedTime);
// Resets the position to the given one, presumably retrieved from a
// playing buffer.
void SetPosition(DWORD dwPosition);
//
// Info a SoundInstance may need.
//
// true iff this has stopped playing.
bool IsStopped()
{
return m_dwPosition >= m_dwLength;
};
// is the sound in the process of stopping?
bool IsStopping()
{
return m_bASR && m_bEnding;
}
// what is the current offset in the source buffer?
DWORD GetPosition()
{
return m_dwPosition & m_dwPositionMask;
}
//
// ASR info
//
// is this tracking an ASR sound?
bool IsASR()
{
return m_bASR;
}
// get the loop offset in the ASR sound
DWORD GetLoopOffset()
{
ZAssert(m_bASR);
return m_dwLoopStart;
}
// get the loop length in an ASR sound
DWORD GetLoopLength()
{
ZAssert(m_bASR);
return m_dwLoopLength;
}
//
// non-ASR info
//
// true if this is a looping sound
bool IsLooping()
{
ZAssert(!m_bASR);
return m_bLooping;
}
};
//
// A sound instance implementation representing a single virtual DirectSound3D
// sound buffer. This may or may not have an actual direct sound buffer
// associated with it at any time - the sound engine controls that aspect of
// things.
//
class DSVirtualSoundBuffer : public ISoundInstance, public ISoundTweakable SoundDebugImpl
{
protected:
// An event source which is triggered when a sound is finished (often NULL)
TRef<EventSourceImpl> m_peventsourceFinished;
// the current buffer position of the sound
BufferPositionTracker m_bufferPositionTracker;
// The data source used to create this sound
TRef<ISoundPCMData> m_pdata;
// The current sound buffer (possibly NULL)
TRef<DS3DSoundBuffer> m_pds3dbuffer;
// the aproximate age of this sound in seconds, used for priority purposes
float m_fAge;
// has this sound started?
bool m_bStarted;
// has this sound stopped?
bool m_bStopped;
// are we trying to stop this sound?
bool m_bRetryStop;
// is the buffer currently playing?
bool m_bBufferPlaying;
// is the buffer currently audible?
bool m_bAudible;
// what is the quality of the sound currently?
ISoundEngine::Quality m_quality;
// can the current buffer play in hardware, if available?
bool m_bAllowHardware;
// the dynamic priority of the sound. The only meaning this number has is
// in relation to other priorities, where the higher number is the higher
// priority.
float m_fDynamicPriority;
//
// cached settings
//
// The current priority of the sound
float m_fPriority;
// The current gain of the sound
float m_fGain;
// the current pitch of the sound
float m_fPitch;
// prepare a sound buffer with the given quality and 3D support using the
// direct sound object pointed to by pDirectSound.
// mdvalley: DirectSound8
virtual HRESULT PrepareBuffer(IDirectSound* pDirectSound,
ISoundEngine::Quality quality, bool bAllowHardware, bool bSupport3D);
virtual HRESULT PrepareBuffer8(IDirectSound8* pDirectSound,
ISoundEngine::Quality quality, bool bAllowHardware, bool bSupport3D);
public:
// Creates a virtual sound buffer for a normal sound, possibly looping
DSVirtualSoundBuffer(ISoundPCMData* pdata, bool bLooping);
// Creates a virtual sound buffer for an ASR sound
DSVirtualSoundBuffer(ISoundPCMData* pdata, DWORD dwLoopOffset, DWORD dwLoopLength);
//
// Accessors
//
// returns true iff the buffer is no longer playing (and can be discarded)
bool IsStopped()
{
return m_bStopped;
};
// Returns true if this has a playing physical buffer
bool HasPlayingBuffer()
{
return m_bBufferPlaying;
};
// Returns true if this is audible at the moment
bool IsAudible()
{
return m_bAudible;
};
// Gets the dynamic priority of the sound. The only meaning this number
// has is in relation to other priorities, where the higher number is the
// higher priority.
float GetDynamicPriority()
{
return m_fDynamicPriority;
};
// Recalculates the sounds position, loudness, whether it's playing, etc..
virtual HRESULT Update(DWORD dwTimeElapsed,
const Vector& vectListenerPosition, float fRolloffFactor);
// Creates and starts a real dsound buffer for this sound
// mdvalley: DirectSound8
virtual HRESULT StartBuffer8(IDirectSound8* pDirectSound,
ISoundEngine::Quality quality, bool bAllowHardware);
virtual HRESULT StartBuffer(IDirectSound* pDirectSound,
ISoundEngine::Quality quality, bool bAllowHardware);
// forcibly stops the given buffer.
HRESULT StopBuffer();
//
// ISoundTweakable interface
//
// Sets the gain, from 0 to -100 dB
virtual HRESULT SetGain(float fGain);
// Sets the pitch shift, where 1.0 is normal, 0.5 is half of normal speed,
// and 2.0 is twice normal speed.
virtual HRESULT SetPitch(float fPitch);
// sets the priority - used as a addition to volume when choosing which
// sounds are most important to play.
virtual HRESULT SetPriority(float fPriority);
//
// ISoundInstance interface
//
// Stops the sound. If bForceNow is true the sound will stop ASAP,
// possibly popping. If it is false some sounds may play a trail-off
// sound or fade away.
virtual HRESULT Stop(bool bForceNow = false);
// returns S_OK if the sound is currently playing, S_FALSE otherwise.
virtual HRESULT IsPlaying();
// Gets an event which fires when the sound finishes playing (for any
// reason)
virtual IEventSource* GetFinishEventSource();
// Gets an interface for tweaking the sound, if supported, NULL otherwise.
virtual TRef<ISoundTweakable> GetISoundTweakable();
// Gets an interface for tweaking the sound, if supported, NULL otherwise.
virtual TRef<ISoundTweakable3D> GetISoundTweakable3D();
//
// ISoundDebugDump
//
#ifdef _DEBUG
// return a human-readable description of the object, prepending
// strIndent to the beginning of each line.
ZString DebugDump(const ZString& strIndent = "");
#endif
};
class DS3DVirtualSoundBuffer : public DSVirtualSoundBuffer, public ISoundTweakable3D
{
private:
//
// cached settings
//
// The source of this sound, position-wise
TRef<ISoundPositionSource> m_pposSource;
// is 3D on at the moment?
bool m_b3D;
// have we decided to play in 3D at the moment?
bool m_bPlayingIn3D;
// the current maximum distance of the sound
float m_fMinimumDistance;
// the current sound cone
float m_fInnerAngle, m_fOuterAngle, m_fOutsideGain;
// the last known position of the sound
Vector m_vectPosition;
// the last known velocity of the sound
Vector m_vectVelocity;
// the last known orientation of the sound
Vector m_vectOrientation;
// whether or not the last known info is relative to the listener
bool m_bListenerRelative;
public:
// constructs a simple 3D capable sound
DS3DVirtualSoundBuffer(ISoundPCMData* pdata, bool bLooping,
TRef<ISoundPositionSource> psource);
// constructs an ASR 3D capable sound
DS3DVirtualSoundBuffer(ISoundPCMData* pdata, DWORD dwLoopOffset,
DWORD dwLoopLength, TRef<ISoundPositionSource> psource);
//
// DSVirtualSoundBuffer overides
//
protected:
// prepare a sound buffer with the given quality and 3D support using the
// direct sound object pointed to by pDirectSound.
// mdvalley: DirectSound8
virtual HRESULT PrepareBuffer(IDirectSound* pDirectSound,
ISoundEngine::Quality quality, bool bAllowHardware, bool bSupport3D);
virtual HRESULT PrepareBuffer8(IDirectSound8* pDirectSound,
ISoundEngine::Quality quality, bool bAllowHardware, bool bSupport3D);
public:
// Recalculates the sounds position, loudness, whether it's playing, etc..
virtual HRESULT Update(DWORD dwTimeElapsed,
const Vector& vectListenerPosition, float fRolloffFactor);
//
// ISoundTweakable3D interface
//
// toggles 3D Positioning on and off for the given sound.
virtual HRESULT Set3D(bool b3D);
// Sets the distance at which the sound will be at max volume. This
// effects how quickly the sound drops off with distance.
virtual HRESULT SetMinimumDistance(float fMinimumDistance);
// Sets a sound cone of size fInnerAngle (in degrees) where the volume is at
// normal levels, outside of which it fades down by fOutsideGain
// (range of 0 to -100 db) at fOuterAngle (degrees) and beyond.
virtual HRESULT SetCone(float fInnerAngle, float fOuterAngle, float fOutsideGain);
//
// ISoundTweakable interface
//
// Sets the gain, from 0 to -100 dB
virtual HRESULT SetGain(float fGain);
// Sets the pitch shift, where 1.0 is normal, 0.5 is half of normal speed,
// and 2.0 is twice normal speed.
virtual HRESULT SetPitch(float fPitch);
// sets the priority - used as a addition to volume when choosing which
// sounds are most important to play.
virtual HRESULT SetPriority(float fPriority);
// Gets an interface for tweaking the sound, if supported, NULL otherwise.
virtual TRef<ISoundTweakable> GetISoundTweakable();
// Gets an interface for tweaking the sound, if supported, NULL otherwise.
virtual TRef<ISoundTweakable3D> GetISoundTweakable3D();
};
};