// // 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 m_peventsourceFinished; // the current buffer position of the sound BufferPositionTracker m_bufferPositionTracker; // The data source used to create this sound TRef m_pdata; // The current sound buffer (possibly NULL) TRef 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. virtual HRESULT PrepareBuffer(IDirectSound* 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 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 GetISoundTweakable(); // Gets an interface for tweaking the sound, if supported, NULL otherwise. virtual TRef 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 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 psource); // constructs an ASR 3D capable sound DS3DVirtualSoundBuffer(ISoundPCMData* pdata, DWORD dwLoopOffset, DWORD dwLoopLength, TRef psource); // // DSVirtualSoundBuffer overides // protected: // prepare a sound buffer with the given quality and 3D support using the // direct sound object pointed to by pDirectSound. virtual HRESULT PrepareBuffer(IDirectSound* 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 GetISoundTweakable(); // Gets an interface for tweaking the sound, if supported, NULL otherwise. virtual TRef GetISoundTweakable3D(); }; };