Fix "no remove aqua speed" bug when player leaves the water
[ryzomcore.git] / nel / src / sound / driver / xaudio2 / adpcm_xaudio2.cpp
blob6aed31713b006522641323ca7e904dd858d011ab
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2008 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
3 //
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.
8 //
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 #include "stdxaudio2.h"
19 // Project includes
20 #include "buffer_xaudio2.h"
21 #include "adpcm_xaudio2.h"
23 #ifdef DEBUG_NEW
24 #define new DEBUG_NEW
25 #endif
27 using namespace std;
28 // using namespace NLMISC;
30 namespace NLSOUND {
32 CAdpcmXAudio2::CAdpcmXAudio2(bool loop)
33 : _SourceVoice(NULL), _SourceData(NULL), _SourceSize(0), _SampleRate(0),
34 _Loop(loop), _BufferNext(0), _SampleNb(0), _AdpcmSize(0),
35 _AdpcmIndex(0), _LastBufferContext(0)
37 _State.PreviousSample = 0;
38 _State.StepIndex = 0;
39 for (uint i = 0; i < _BufferNb; ++i)
40 _ValidBufferContext[i] = 0;
43 CAdpcmXAudio2::~CAdpcmXAudio2()
48 /// Submit the next ADPCM buffer, only 1 buffer can be submitted at a time!
49 void CAdpcmXAudio2::submitSourceBuffer(CBufferXAudio2 *buffer)
51 _Mutex.enter();
52 if (_SourceData) nlerror(NLSOUND_XAUDIO2_PREFIX "Only 1 ADPCM buffer can be submitted at a time! Call flushSourceBuffers first in CSourceXAudio2 stop().");
53 _SourceSize = buffer->getSize();
54 if (_SourceSize == 0)
56 nlwarning(NLSOUND_XAUDIO2_PREFIX "Empty ADPCM buffer!");
58 else
60 _AdpcmSize = buffer->getFrequency() / 40;
61 _SampleNb = _AdpcmSize * 2;
62 nlassert(_SampleNb < _BufferMax);
63 _SourceData = buffer->getData();
64 // nldebug("submit called!!!");
65 processBuffers();
67 _Mutex.leave();
70 /// Reset the decoder, clear the queued buffer
71 void CAdpcmXAudio2::flushSourceBuffers()
73 _Mutex.enter();
74 _SourceData = NULL;
75 for (uint i = 0; i < _BufferNb; ++i)
76 _ValidBufferContext[i] = 0;
77 //_SourceSize = 0;
78 _State.PreviousSample = 0;
79 _State.StepIndex = 0;
80 _AdpcmIndex = 0;
81 //_PcmSize = 0;
82 //_AdpcmSize = 0;
83 _Mutex.leave();
86 void CAdpcmXAudio2::processBuffers()
88 if (_SourceData)
90 XAUDIO2_VOICE_STATE voice_state;
91 _SourceVoice->GetState(&voice_state);
92 while (voice_state.BuffersQueued < _BufferNb)
94 // ADPCM = 4bit, PCM = 16bit // 1 adpcm byte = 2 samples
96 uint maxinbytes = _SourceSize - _AdpcmIndex;
97 uint inbytes = min(maxinbytes, _AdpcmSize);
99 // nldebug("queue: %u", (uint32)voice_state.BuffersQueued);
100 // nldebug("yeah, i'm decoding adpcm! %s, the size is %u and I'm at index %u, run %u, do %u bytes, source data %s!!!", _Loop ? "it's LOOPING" : "it's NOT looping", (uint32)_SourceSize, (uint32)_AdpcmIndex, (uint32)0, (uint32)inbytes, _SourceData ? "EXISTS" : "does NOT exist");
102 if (inbytes > 0)
104 IBuffer::decodeADPCM(_SourceData + _AdpcmIndex, _Buffer[_BufferNext], inbytes * 2, _State);
106 XAUDIO2_BUFFER xbuffer;
107 xbuffer.AudioBytes = inbytes * 4;
108 xbuffer.Flags = 0;
109 xbuffer.LoopBegin = 0;
110 xbuffer.LoopCount = 0;
111 xbuffer.LoopLength = 0;
112 xbuffer.pAudioData = (BYTE *)_Buffer[_BufferNext];
113 xbuffer.pContext = (void *)(++_LastBufferContext);
114 xbuffer.PlayBegin = 0;
115 xbuffer.PlayLength = 0;
116 _SourceVoice->SubmitSourceBuffer(&xbuffer);
117 // nlwarning("submit %u", (uint32)xbuffer.pContext);
119 _AdpcmIndex += inbytes;
120 _BufferNext = (_BufferNext + 1) % _BufferNb;
121 ++voice_state.BuffersQueued;
124 if (inbytes != _AdpcmSize) // end of buffer
126 _State.PreviousSample = 0;
127 _State.StepIndex = 0;
128 _AdpcmIndex = 0;
129 if (!_Loop)
131 _SourceData = NULL;
132 return;
136 nlassert(_SourceData);
141 void CAdpcmXAudio2::OnVoiceProcessingPassStart(UINT32 /* BytesRequired */)
146 void CAdpcmXAudio2::OnVoiceProcessingPassEnd()
151 void CAdpcmXAudio2::OnStreamEnd()
156 void CAdpcmXAudio2::OnBufferStart(void *pBufferContext)
158 // set a flag that this buffer has started
159 // nlwarning("start %u", (uint32)pBufferContext);
160 for (uint i = 0; i < _BufferNb; ++i) if (!_ValidBufferContext[i])
162 _ValidBufferContext[i] = pBufferContext;
163 return;
165 // nlwarning("No valid buffer context available for: %u", (uint32)pBufferContext);
168 void CAdpcmXAudio2::OnBufferEnd(void *pBufferContext)
170 // verify if this buffer has started
171 // nlwarning("end %u", (uint32)pBufferContext);
172 for (uint i = 0; i < _BufferNb; ++i) if (_ValidBufferContext[i] == pBufferContext)
174 _ValidBufferContext[i] = 0;
175 goto ProcessBuffers;
177 // nlwarning("Not a valid buffer context: %u", (uint32)pBufferContext);
178 return;
179 ProcessBuffers:
180 // The "correct" way would be to decode the buffer on a seperate thread,
181 // but since ADPCM decoding should be really fast, there is no problem
182 // with doing it here directly.
183 _Mutex.enter();
184 processBuffers();
185 _Mutex.leave();
188 void CAdpcmXAudio2::OnLoopEnd(void * /* pBufferContext */)
193 void CAdpcmXAudio2::OnVoiceError(void * /* pBufferContext */, HRESULT /* Error */)
198 } /* namespace NLSOUND */
200 /* end of file */