1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2008 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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 #include "stdxaudio2.h"
20 #include "buffer_xaudio2.h"
21 #include "adpcm_xaudio2.h"
28 // using namespace NLMISC;
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;
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
)
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();
56 nlwarning(NLSOUND_XAUDIO2_PREFIX
"Empty ADPCM buffer!");
60 _AdpcmSize
= buffer
->getFrequency() / 40;
61 _SampleNb
= _AdpcmSize
* 2;
62 nlassert(_SampleNb
< _BufferMax
);
63 _SourceData
= buffer
->getData();
64 // nldebug("submit called!!!");
70 /// Reset the decoder, clear the queued buffer
71 void CAdpcmXAudio2::flushSourceBuffers()
75 for (uint i
= 0; i
< _BufferNb
; ++i
)
76 _ValidBufferContext
[i
] = 0;
78 _State
.PreviousSample
= 0;
86 void CAdpcmXAudio2::processBuffers()
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");
104 IBuffer::decodeADPCM(_SourceData
+ _AdpcmIndex
, _Buffer
[_BufferNext
], inbytes
* 2, _State
);
106 XAUDIO2_BUFFER xbuffer
;
107 xbuffer
.AudioBytes
= inbytes
* 4;
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;
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
;
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;
177 // nlwarning("Not a valid buffer context: %u", (uint32)pBufferContext);
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.
188 void CAdpcmXAudio2::OnLoopEnd(void * /* pBufferContext */)
193 void CAdpcmXAudio2::OnVoiceError(void * /* pBufferContext */, HRESULT
/* Error */)
198 } /* namespace NLSOUND */