1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #ifndef NL_SOURCE_DSOUND_H
18 #define NL_SOURCE_DSOUND_H
20 #include "nel/sound/driver/source.h"
21 #include "nel/sound/driver/sound_driver.h"
22 #include "nel/sound/driver/buffer.h"
28 /** Keep trace of following states of the DirectSound buffer:
29 * - the buffer is being filled with samples (filling),
30 * - the buffer still contains samples but silence is being written (silencing),
31 * - the buffer contains no samples but only silence (silenced)
33 /*enum TSourceDSoundBufferState
35 /// The buffer is being filled with samples (filling),
37 /// The buffer still contains samples but silence is being written (silencing),
39 /// The buffer contains no samples but only silence (silenced)
44 /** The state of the source as experienced by the user: playing, paused, and stopped. */
46 enum TSourceDSoundUserState
48 /// The buffer is playing.
50 /// The buffer is paused.
52 /// The buffer is stopped.
57 /** To figger out whether the sound device has played all the samples in the buffer,
58 * the position of the play cursor is traced relatively to the position of the last
59 * sample in the buffer.
62 enum TSourceDSoundEndState
71 * DirectSound sound source
74 * For arguments as 3D vectors, use the NeL vector coordinate system
76 * \author Peter Hanappe
77 * \author Nevrax France
80 class CSourceDSound
: public ISource
82 friend class CSoundDriverDSound
;
86 CSourceDSound(uint sourcename
= 0);
88 virtual ~CSourceDSound();
90 /// Initialize the DirectSound buffers. Called by the sound driver only.
91 void init(LPDIRECTSOUND directSound
, bool useEax
);
93 /// \name Initialization
95 /// Enable or disable streaming mode. Source must be stopped to call this.
96 virtual void setStreaming(bool streaming
);
97 /** Set the buffer that will be played (no streaming)
98 * If the buffer is stereo, the source mode becomes stereo and the source relative mode is on,
99 * otherwise the source is considered as a 3D source. Use submitStreamingBuffer for streaming.
101 virtual void setStaticBuffer(IBuffer
*buffer
);
102 /// Return the buffer, or NULL if streaming is used. Not available for streaming.
103 virtual IBuffer
*getStaticBuffer();
104 /// Add a buffer to the streaming queue. A buffer of 100ms length is optimal for streaming.
105 /// Should be called by a thread which checks countStreamingBuffers every 100ms.
106 virtual void submitStreamingBuffer(IBuffer
*buffer
);
107 /// Return the amount of buffers in the queue (playing and waiting). 3 buffers is optimal.
108 virtual uint
countStreamingBuffers() const;
111 /// \name Playback control
113 /// Set looping on/off for future playbacks (default: off), not available for streaming
114 virtual void setLooping(bool l
);
115 /// Return the looping state
116 virtual bool getLooping() const;
118 /** Play the static buffer (or stream in and play).
119 * This method can return false if the sample for this sound is unloaded.
124 /// Pause. Call play() to resume.
125 virtual void pause();
126 /// Return true if play() or pause(), false if stop().
127 virtual bool isPlaying() const;
128 /// Return true if playing is finished or stop() has been called.
129 virtual bool isStopped() const;
130 /// Return true if the playing source is paused
131 virtual bool isPaused() const;
132 /// Returns the number of milliseconds the source has been playing
133 virtual uint32
getTime();
136 /// \name Source properties
138 /** Set the position vector (default: (0,0,0)).
139 * 3D mode -> 3D position
140 * st mode -> x is the pan value (from left (-1) to right (1)), set y and z to 0
142 virtual void setPos(const NLMISC::CVector
& pos
, bool deffered
= true);
143 /** Get the position vector.
144 * See setPos() for details.
146 virtual const NLMISC::CVector
&getPos() const;
147 /// Set the velocity vector (3D mode only, ignored in stereo mode) (default: (0,0,0))
148 virtual void setVelocity(const NLMISC::CVector
& vel
, bool deferred
= true);
149 /// Get the velocity vector
150 virtual void getVelocity(NLMISC::CVector
& vel
) const;
151 /// Set the direction vector (3D mode only, ignored in stereo mode) (default: (0,0,0) as non-directional)
152 virtual void setDirection(const NLMISC::CVector
& dir
);
153 /// Get the direction vector
154 virtual void getDirection(NLMISC::CVector
& dir
) const;
155 /** Set the gain (volume value inside [0 , 1]). (default: 1)
158 * 1.0 -> no attenuation
159 * values > 1 (amplification) not supported by most drivers
161 virtual void setGain(float gain
);
163 virtual float getGain() const;
164 /** Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
165 * of one octave. 0 is not a legal value.
167 virtual void setPitch(float pitch
);
169 virtual float getPitch() const;
170 /// Set the source relative mode. If true, positions are interpreted relative to the listener position
171 virtual void setSourceRelativeMode(bool mode
);
172 /// Get the source relative mode
173 virtual bool getSourceRelativeMode() const;
174 /// Set the min and max distances (default: 1, MAX_FLOAT) (3D mode only)
175 virtual void setMinMaxDistances(float mindist
, float maxdist
, bool deferred
= true);
176 /// Get the min and max distances
177 virtual void getMinMaxDistances(float& mindist
, float& maxdist
) const;
178 /// Set the cone angles (in radian) and gain (in [0 , 1]) (default: 2PI, 2PI, 0)
179 virtual void setCone(float innerAngle
, float outerAngle
, float outerGain
);
180 /// Get the cone angles (in radian)
181 virtual void getCone(float& innerAngle
, float& outerAngle
, float& outerGain
) const;
182 /** Set the alpha value for the volume-distance curve
184 * Useful only with OptionManualRolloff. value from -1 to 1 (default 0)
186 * alpha.0: the volume will decrease linearly between 0dB and -100 dB
187 * alpha = 1.0: the volume will decrease linearly between 1.0 and 0.0 (linear scale)
188 * alpha = -1.0: the volume will decrease inversely with the distance (1/dist). This
189 * is the default used by DirectSound/OpenAL
191 * For any other value of alpha, an interpolation is be done between the two
192 * adjacent curves. For example, if alpha equals 0.5, the volume will be halfway between
193 * the linear dB curve and the linear amplitude curve.
195 virtual void setAlpha(double a
);
198 /// \name Direct output
200 /// Enable or disable direct output [true/false], default: true
201 virtual void setDirect(bool enable
= true);
202 /// Return if the direct output is enabled
203 virtual bool getDirect() const;
204 /// Set the gain for the direct path
205 virtual void setDirectGain(float gain
);
206 /// Get the gain for the direct path
207 virtual float getDirectGain() const;
209 /// Enable or disable the filter for the direct channel
210 virtual void enableDirectFilter(bool enable
= true);
211 /// Check if the filter on the direct channel is enabled
212 virtual bool isDirectFilterEnabled() const;
213 /// Set the filter parameters for the direct channel
214 virtual void setDirectFilter(TFilter filter
, float lowFrequency
, float highFrequency
, float passGain
);
215 /// Get the filter parameters for the direct channel
216 virtual void getDirectFilter(TFilter
&filterType
, float &lowFrequency
, float &highFrequency
, float &passGain
) const;
217 /// Set the direct filter gain
218 virtual void setDirectFilterPassGain(float passGain
);
219 /// Get the direct filter gain
220 virtual float getDirectFilterPassGain() const;
223 /// \name Effect output
225 /// Set the effect send for this source, NULL to disable. [IEffect], default: NULL
226 virtual void setEffect(IReverbEffect
*reverbEffect
);
227 /// Get the effect send for this source
228 virtual IEffect
*getEffect() const;
229 /// Set the gain for the effect path
230 virtual void setEffectGain(float gain
);
231 /// Get the gain for the effect path
232 virtual float getEffectGain() const;
234 /// Enable or disable the filter for the effect channel
235 virtual void enableEffectFilter(bool enable
= true);
236 /// Check if the filter on the effect channel is enabled
237 virtual bool isEffectFilterEnabled() const;
238 /// Set the filter parameters for the effect channel
239 virtual void setEffectFilter(TFilter filter
, float lowFrequency
, float highFrequency
, float passGain
);
240 /// Get the filter parameters for the effect channel
241 virtual void getEffectFilter(TFilter
&filterType
, float &lowFrequency
, float &highFrequency
, float &passGain
) const;
242 /// Set the effect filter gain
243 virtual void setEffectFilterPassGain(float passGain
);
244 /// Get the effect filter gain
245 virtual float getEffectFilterPassGain() const;
248 /// Return the OpenAL source name
249 uint
sourceName() { return _SourceName
; }
251 /// Returns the buffer associated with this source.
252 IBuffer
*getBuffer();
254 /// Reset the source before reuse
257 /// Update the source (e.g. continue to stream the data in)
260 /// Update the source's volume according to its distance and fade out curve.
261 /// It takes the current position of the listener as argument.
262 void updateVolume(const NLMISC::CVector
& listener
);
266 void copySampleTo16BitsTrack(void *dst
, void *src
, uint nbSample
, TSampleFormat sourceFormat
);
277 /// Release all DirectSound resources
280 // The minimum size of available space in the DS buffer for update
281 static const uint32 _UpdateCopySize
;
282 // The size of the samples that are copied when buffers are swapped
283 static const uint32 _SwapCopySize
;
284 // The number of channels
285 static const uint _DefaultChannels
;
286 // The default sample rate
287 static const uint _DefaultSampleRate
;
288 // The default sample size
289 static const uint _DefaultSampleSize
;
290 // The length of the crossfade, in samples
291 static const uint32 _XFadeSize
;
293 /// The play and write cursors
301 /// A locked buffer info.
302 struct TLockedBufferInfo
304 // First locked part.
308 // second locked part (or 0 if none)
313 // Utility function that locks the DirectSound buffer and restores it if it was lost.
314 // bool lock(uint32 writePos, uint32 size, uint8* &ptr1, DWORD &bytes1, uint8* &ptr2, DWORD &bytes2);
315 bool lock(uint32 writePos
, uint32 size
, TLockedBufferInfo
&lockedInfo
);
317 // Utility function that unlocks the DirectSound buffer
318 // bool unlock(uint8* ptr1, DWORD bytes1, uint8* ptr2, DWORD bytes2);
319 bool unlock(const TLockedBufferInfo
&lockedInfo
);
321 void getCursors(TCursors
&cursors
);
322 uint32
checkFillCursor();
325 void fillData(const TLockedBufferInfo
&lbi
, int nbSample
);
326 void fillData(sint16
*dst
, uint nbSample
);
327 void fillSilence(const TLockedBufferInfo
&lbi
, int nbSample
);
329 void xfade(const TLockedBufferInfo
&lbi
, sint16
*src
);
330 void fadeOut(const TLockedBufferInfo
&lbi
);
331 void fadeIn(const TLockedBufferInfo
&lbi
);
333 void advanceFill(TLockedBufferInfo
&lbi
, uint nbSample
);
337 // Replace the current buffer with the swap buffer
339 // getFadeOutSize() calculates how many samples have been written after the
340 // write cursor in the DirectSound buffer. This value is returned in the
341 // writtenTooMuch variable. The xfadeSize contains the number of samples over
342 // which to do a xfade or fade out, and in1 points to the sample in the sample
343 // buffer where to start the fade.
344 // void getFadeOutSize(uint32 writePos, uint32& xfadeSize, sint16* &in1, uint32 &writtenTooMuch);
346 // Fill the buffer with fresh samples. Should be called inside the critical zone.
348 // Fill the buffer with sparkling silence. Should be called inside the critical zone.
350 // Do a cross fade between the current buffer and the buffer stored in the _SwapBuffer
351 // variable. Call inside the critical zone.
353 // Fade out the current buffer. Call inside the critical zone.
355 // Fade in the current buffer. Call inside the critical zone.
357 /// Check whether the play position has advanced enough to require an update
366 // uint32 _FillCursor;
368 // The size of the sound buffer, in bytes
369 // uint32 _BufferSize;
372 // Size of the buffer in sample
374 // Position in the buffer in sample.
376 // The number of sample realy played (depend on play cursor).
378 TSampleFormat _Format
;
382 // The frequency of the source [0,10], i.e. slowed down or accelerated
384 // The sample rate of the source (= _Freq * _Buffer sample rate)
388 IBuffer
*_NextSample
;
392 uint32 _SilenceWriten
;
394 // The next sound buffer
395 // IBuffer *_SwapBuffer;
397 // To loop or not to loop
400 // The state of the source (playing, paused, stopped)
401 // TSourceDSoundUserState _UserState;
403 // DirectSound secondary buffer
404 LPDIRECTSOUNDBUFFER _SecondaryBuffer
;
405 // The byte size of the DirectSound secondary buffers
406 static const uint32 _SecondaryBufferSize
;
407 // The mask for the buffer size
408 static const uint32 _SizeMask
;
409 // 3D interface of the secondary buffer.
410 LPDIRECTSOUND3DBUFFER _3DBuffer
;
411 // The critial section object to protect the swap and update functions
412 CRITICAL_SECTION _CriticalSection
;
414 // The state for ADPCM decompression.
415 IBuffer::TADPCMState _ADPCMState
;
418 // The state of the DirectSound buffer (filling, silencing, silenced)
419 // TSourceDSoundBufferState _SecondaryBufferState;
423 // The next position in the DirectSound buffer where we should write next
424 // uint32 _NextWritePos;
426 // The total number of bytes written from the current sound buffer
427 // uint32 _BytesWritten;
429 // The amount of silence written (in bytes) after the end of the current sound buffer
430 // uint32 _SilenceWritten;
432 // The position of the last audio sample written.
433 // uint32 _EndPosition;
436 // The state of the buffer to reach the end of the audio samples. To flag the buffer as
437 // STOPPED, we have to make sure all the samples in the buffer are played. The play
438 // cursor in the DirectSound buffer is inspected and when it crosses the position of
439 // the last sample written (_EndPosition) the buffer is flagged as stopped. The _EndState
440 // field is used to keep a trace of the whereabouts of the play cursor.
441 // TSourceDSoundEndState _EndState;
444 // Has this source been handed out.
447 // Set the 'used' state of the source. Managed by the driver.
448 void setUsed(bool v) { _IsUsed = v; }
450 // Return the 'used' state of the source
451 bool isUsed() { return _IsUsed; }
456 NLMISC::CVector _Pos
;
459 #if EAX_AVAILABLE == 1
460 LPKSPROPERTYSET _EAXSource
;
468 static double _LastSwapTime
;
469 static double _TotalSwapTime
;
470 static double _MaxSwapTime
;
471 static double _MinSwapTime
;
472 static uint32 _SwapCount
;
474 static double _TotalUpdateTime
;
475 static double _MaxUpdateTime
;
476 static double _MinUpdateTime
;
477 static uint32 _UpdateCount
;
478 static uint32 _TotalUpdateSize
;
480 static double _PosTime
;
481 static double _LockTime
;
482 static double _CopyTime
;
483 static double _UnlockTime
;
484 static uint32 _CopyCount
;
488 static double getTestLast() { return 1000.0f
* _LastSwapTime
; };
489 static double getTestMax() { return 1000.0f
* _MaxSwapTime
; };
490 static double getTestMin() { return 1000.0f
* _MinSwapTime
; };
491 static double getTestAverage() { return (_SwapCount
> 0) ? 1000.0f
* _TotalSwapTime
/ _SwapCount
: 0.0; };
493 static double getAveragePosTime() { return (_CopyCount
> 0) ? 1000.0f
* _PosTime
/ _CopyCount
: 0.0; };
494 static double getAverageLockTime() { return (_CopyCount
> 0) ? 1000.0f
* _LockTime
/ _CopyCount
: 0.0; };
495 static double getAverageCopyTime() { return (_CopyCount
> 0) ? 1000.0f
* _CopyTime
/ _CopyCount
: 0.0; };
496 static double getAverageUnlockTime() { return (_CopyCount
> 0) ? 1000.0f
* _UnlockTime
/ _CopyCount
: 0.0; };
497 static double getAverageCumulTime() { return (_CopyCount
> 0) ? 1000.0f
* (_PosTime
+ _LockTime
+ _CopyTime
+ _UnlockTime
) / _CopyCount
: 0.0; };
498 static uint
getAverageUpdateSize() { return (_CopyCount
> 0) ? (uint
) (_TotalUpdateSize
/ _CopyCount
) : 0; };
500 static double getMaxUpdateTime() { return 1000.0f
* _MaxUpdateTime
; };
501 static double getMinUpdateTime() { return 1000.0f
* _MinUpdateTime
; };
502 static double getAverageUpdateTime() { return (_UpdateCount
> 0) ? 1000.0f
* _TotalUpdateTime
/ _UpdateCount
: 0.0; };
504 static double getTotalUpdateTime() { return 1000.0f
* _TotalUpdateTime
; };
505 static double getUpdateBytesPerMsec() { return (_UpdateCount
> 0) ? _TotalUpdateSize
/ _TotalUpdateTime
/ 1000.0 : 0.0; }
515 #endif // NL_SOURCE_DSOUND_H
517 /* End of source_al.h */