xaudio2: Support looping buffers.
Also shorten up the test runtime.
This commit is contained in:
parent
031af2ca9a
commit
c28bfbc5b2
|
@ -209,9 +209,9 @@ static void test_simple_streaming(IXAudio2 *xa)
|
|||
ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.AudioBytes = 44100 * fmt.nBlockAlign;
|
||||
buf.AudioBytes = 22050 * fmt.nBlockAlign;
|
||||
buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
|
||||
fill_buf((float*)buf.pAudioData, &fmt, 440, 44100);
|
||||
fill_buf((float*)buf.pAudioData, &fmt, 440, 22050);
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
@ -224,9 +224,9 @@ static void test_simple_streaming(IXAudio2 *xa)
|
|||
ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
|
||||
|
||||
memset(&buf2, 0, sizeof(buf2));
|
||||
buf2.AudioBytes = 44100 * fmt.nBlockAlign;
|
||||
buf2.AudioBytes = 22050 * fmt.nBlockAlign;
|
||||
buf2.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf2.AudioBytes);
|
||||
fill_buf((float*)buf2.pAudioData, &fmt, 220, 44100);
|
||||
fill_buf((float*)buf2.pAudioData, &fmt, 220, 22050);
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src2, &buf2, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
@ -264,12 +264,12 @@ static void test_simple_streaming(IXAudio2 *xa)
|
|||
IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
|
||||
else
|
||||
IXAudio2SourceVoice_GetState(src, &state, 0);
|
||||
if(state.SamplesPlayed >= 44100)
|
||||
if(state.SamplesPlayed >= 22050)
|
||||
break;
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
ok(state.SamplesPlayed == 44100, "Got wrong samples played\n");
|
||||
ok(state.SamplesPlayed == 22050, "Got wrong samples played\n");
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, (void*)buf.pAudioData);
|
||||
HeapFree(GetProcessHeap(), 0, (void*)buf2.pAudioData);
|
||||
|
@ -373,6 +373,45 @@ static const IXAudio2VoiceCallbackVtbl vcb_buf_vtbl = {
|
|||
|
||||
static IXAudio2VoiceCallback vcb_buf = { &vcb_buf_vtbl };
|
||||
|
||||
static int nloopends = 0;
|
||||
|
||||
static void WINAPI loop_buf_OnStreamEnd(IXAudio2VoiceCallback *This)
|
||||
{
|
||||
}
|
||||
|
||||
static void WINAPI loop_buf_OnBufferStart(IXAudio2VoiceCallback *This,
|
||||
void *pBufferContext)
|
||||
{
|
||||
}
|
||||
|
||||
static void WINAPI loop_buf_OnBufferEnd(IXAudio2VoiceCallback *This,
|
||||
void *pBufferContext)
|
||||
{
|
||||
}
|
||||
|
||||
static void WINAPI loop_buf_OnLoopEnd(IXAudio2VoiceCallback *This,
|
||||
void *pBufferContext)
|
||||
{
|
||||
++nloopends;
|
||||
}
|
||||
|
||||
static void WINAPI loop_buf_OnVoiceError(IXAudio2VoiceCallback *This,
|
||||
void *pBuffercontext, HRESULT Error)
|
||||
{
|
||||
}
|
||||
|
||||
static const IXAudio2VoiceCallbackVtbl loop_buf_vtbl = {
|
||||
vcb_buf_OnVoiceProcessingPassStart,
|
||||
vcb_buf_OnVoiceProcessingPassEnd,
|
||||
loop_buf_OnStreamEnd,
|
||||
loop_buf_OnBufferStart,
|
||||
loop_buf_OnBufferEnd,
|
||||
loop_buf_OnLoopEnd,
|
||||
loop_buf_OnVoiceError
|
||||
};
|
||||
|
||||
static IXAudio2VoiceCallback loop_buf = { &loop_buf_vtbl };
|
||||
|
||||
static void test_buffer_callbacks(IXAudio2 *xa)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
@ -450,6 +489,218 @@ static void test_buffer_callbacks(IXAudio2 *xa)
|
|||
IXAudio2MasteringVoice_DestroyVoice(master);
|
||||
}
|
||||
|
||||
static UINT32 play_to_completion(IXAudio2SourceVoice *src, UINT32 max_samples)
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
HRESULT hr;
|
||||
|
||||
nloopends = 0;
|
||||
|
||||
hr = IXAudio2SourceVoice_Start(src, 0, XAUDIO2_COMMIT_NOW);
|
||||
ok(hr == S_OK, "Start failed: %08x\n", hr);
|
||||
|
||||
while(1){
|
||||
if(xaudio27)
|
||||
IXAudio27SourceVoice_GetState((IXAudio27SourceVoice*)src, &state);
|
||||
else
|
||||
IXAudio2SourceVoice_GetState(src, &state, 0);
|
||||
if(state.BuffersQueued == 0)
|
||||
break;
|
||||
if(state.SamplesPlayed >= max_samples){
|
||||
if(xaudio27)
|
||||
IXAudio27SourceVoice_ExitLoop((IXAudio27SourceVoice*)src, XAUDIO2_COMMIT_NOW);
|
||||
else
|
||||
IXAudio2SourceVoice_ExitLoop(src, XAUDIO2_COMMIT_NOW);
|
||||
}
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
hr = IXAudio2SourceVoice_Stop(src, 0, XAUDIO2_COMMIT_NOW);
|
||||
ok(hr == S_OK, "Start failed: %08x\n", hr);
|
||||
|
||||
return state.SamplesPlayed;
|
||||
}
|
||||
|
||||
static void test_looping(IXAudio2 *xa)
|
||||
{
|
||||
HRESULT hr;
|
||||
IXAudio2MasteringVoice *master;
|
||||
IXAudio2SourceVoice *src;
|
||||
WAVEFORMATEX fmt;
|
||||
XAUDIO2_BUFFER buf;
|
||||
UINT32 played, running_total = 0;
|
||||
|
||||
XA2CALL_0V(StopEngine);
|
||||
|
||||
if(xaudio27)
|
||||
hr = IXAudio27_CreateMasteringVoice((IXAudio27*)xa, &master, 2, 44100, 0, 0, NULL);
|
||||
else
|
||||
hr = IXAudio2_CreateMasteringVoice(xa, &master, 2, 44100, 0, NULL, NULL, AudioCategory_GameEffects);
|
||||
ok(hr == S_OK, "CreateMasteringVoice failed: %08x\n", hr);
|
||||
|
||||
|
||||
fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
fmt.nChannels = 2;
|
||||
fmt.nSamplesPerSec = 44100;
|
||||
fmt.wBitsPerSample = 32;
|
||||
fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
|
||||
fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
|
||||
fmt.cbSize = 0;
|
||||
|
||||
XA2CALL(CreateSourceVoice, &src, &fmt, 0, 1.f, &loop_buf, NULL, NULL);
|
||||
ok(hr == S_OK, "CreateSourceVoice failed: %08x\n", hr);
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
buf.AudioBytes = 44100 * fmt.nBlockAlign;
|
||||
buf.pAudioData = HeapAlloc(GetProcessHeap(), 0, buf.AudioBytes);
|
||||
fill_buf((float*)buf.pAudioData, &fmt, 440, 44100);
|
||||
|
||||
XA2CALL_0(StartEngine);
|
||||
ok(hr == S_OK, "StartEngine failed: %08x\n", hr);
|
||||
|
||||
/* play from middle to end */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 0;
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 0;
|
||||
buf.LoopCount = 0;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 22050, "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
|
||||
/* play 4410 samples from middle */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 4410;
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 0;
|
||||
buf.LoopCount = 0;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 4410, "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
|
||||
/* loop 4410 samples in middle */
|
||||
buf.PlayBegin = 0;
|
||||
buf.PlayLength = 0;
|
||||
buf.LoopBegin = 22050;
|
||||
buf.LoopLength = 4410;
|
||||
buf.LoopCount = 1;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 44100 + 4410, "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
|
||||
/* play last half, then loop the whole buffer */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 0;
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 0;
|
||||
buf.LoopCount = 1;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 22050 + 44100, "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
|
||||
/* play short segment from middle, loop to the beginning, and end at PlayEnd */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 4410;
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 0;
|
||||
buf.LoopCount = 1;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 4410 + (22050 + 4410), "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
|
||||
/* invalid: LoopEnd must be <= PlayEnd
|
||||
* xaudio27: play until LoopEnd, loop to beginning, play until PlayEnd */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 4410;
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 22050 + 4410 * 2;
|
||||
buf.LoopCount = 1;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
if(xaudio27){
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 4410 + (22050 + 4410 * 2), "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
}else
|
||||
ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr);
|
||||
|
||||
/* invalid: LoopEnd must be within play range
|
||||
* xaudio27: plays only play range */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 0; /* == until end of buffer */
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 22050;
|
||||
buf.LoopCount = 1;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
if(xaudio27){
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, -1);
|
||||
ok(played - running_total == 22050, "Got wrong samples played: %u\n", played - running_total);
|
||||
running_total = played;
|
||||
ok(nloopends == 0, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
}else
|
||||
ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr);
|
||||
|
||||
/* invalid: LoopBegin must be before PlayEnd
|
||||
* xaudio27: crashes */
|
||||
if(!xaudio27){
|
||||
buf.PlayBegin = 0;
|
||||
buf.PlayLength = 4410;
|
||||
buf.LoopBegin = 22050;
|
||||
buf.LoopLength = 4410;
|
||||
buf.LoopCount = 1;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == XAUDIO2_E_INVALID_CALL, "SubmitSourceBuffer should have failed: %08x\n", hr);
|
||||
}
|
||||
|
||||
/* infinite looping buffer */
|
||||
buf.PlayBegin = 22050;
|
||||
buf.PlayLength = 0;
|
||||
buf.LoopBegin = 0;
|
||||
buf.LoopLength = 0;
|
||||
buf.LoopCount = 255;
|
||||
|
||||
hr = IXAudio2SourceVoice_SubmitSourceBuffer(src, &buf, NULL);
|
||||
ok(hr == S_OK, "SubmitSourceBuffer failed: %08x\n", hr);
|
||||
|
||||
played = play_to_completion(src, running_total + 88200);
|
||||
ok(played - running_total == 22050 + 44100 * 2, "Got wrong samples played: %u\n", played - running_total);
|
||||
ok(nloopends == (played - running_total) / 88200 + 1, "Got wrong OnLoopEnd calls: %u\n", nloopends);
|
||||
running_total = played;
|
||||
}
|
||||
|
||||
static UINT32 test_DeviceDetails(IXAudio27 *xa)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
@ -519,6 +770,7 @@ START_TEST(xaudio2)
|
|||
test_DeviceDetails(xa27);
|
||||
test_simple_streaming((IXAudio2*)xa27);
|
||||
test_buffer_callbacks((IXAudio2*)xa27);
|
||||
test_looping((IXAudio2*)xa27);
|
||||
}else
|
||||
skip("No audio devices available\n");
|
||||
|
||||
|
@ -537,6 +789,7 @@ START_TEST(xaudio2)
|
|||
if(has_devices){
|
||||
test_simple_streaming(xa);
|
||||
test_buffer_callbacks(xa);
|
||||
test_looping(xa);
|
||||
}else
|
||||
skip("No audio devices available\n");
|
||||
|
||||
|
|
|
@ -80,6 +80,9 @@ static void dump_fmt(const WAVEFORMATEX *fmt)
|
|||
TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
|
||||
TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
|
||||
TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
|
||||
}else if(fmt->wFormatTag == WAVE_FORMAT_ADPCM){
|
||||
ADPCMWAVEFORMAT *fmtadpcm = (void*)fmt;
|
||||
TRACE("wSamplesPerBlock: %u\n", fmtadpcm->wSamplesPerBlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +130,7 @@ HRESULT WINAPI DllUnregisterServer(void)
|
|||
typedef struct _XA2Buffer {
|
||||
XAUDIO2_BUFFER xa2buffer;
|
||||
DWORD offs_bytes;
|
||||
UINT32 latest_al_buf;
|
||||
UINT32 latest_al_buf, looped, loop_end_bytes, play_end_bytes, cur_end_bytes;
|
||||
} XA2Buffer;
|
||||
|
||||
typedef struct _IXAudio2Impl IXAudio2Impl;
|
||||
|
@ -625,7 +628,67 @@ static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
|
|||
* but pBuffer itself may be reused immediately */
|
||||
memcpy(&buf->xa2buffer, pBuffer, sizeof(*pBuffer));
|
||||
|
||||
buf->offs_bytes = 0;
|
||||
/* convert samples offsets to bytes */
|
||||
if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){
|
||||
/* ADPCM gives us a number of samples per block, so round down to
|
||||
* nearest block and convert to bytes */
|
||||
buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
|
||||
buf->xa2buffer.PlayLength = buf->xa2buffer.PlayLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
|
||||
buf->xa2buffer.LoopBegin = buf->xa2buffer.LoopBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
|
||||
buf->xa2buffer.LoopLength = buf->xa2buffer.LoopLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
|
||||
}else{
|
||||
buf->xa2buffer.PlayBegin *= This->fmt->nBlockAlign;
|
||||
buf->xa2buffer.PlayLength *= This->fmt->nBlockAlign;
|
||||
buf->xa2buffer.LoopBegin *= This->fmt->nBlockAlign;
|
||||
buf->xa2buffer.LoopLength *= This->fmt->nBlockAlign;
|
||||
}
|
||||
|
||||
if(buf->xa2buffer.PlayLength == 0)
|
||||
/* set to end of buffer */
|
||||
buf->xa2buffer.PlayLength = buf->xa2buffer.AudioBytes - buf->xa2buffer.PlayBegin;
|
||||
|
||||
buf->play_end_bytes = buf->xa2buffer.PlayBegin + buf->xa2buffer.PlayLength;
|
||||
|
||||
if(buf->xa2buffer.LoopCount){
|
||||
if(buf->xa2buffer.LoopLength == 0)
|
||||
/* set to end of play range */
|
||||
buf->xa2buffer.LoopLength = buf->play_end_bytes - buf->xa2buffer.LoopBegin;
|
||||
|
||||
if(buf->xa2buffer.LoopBegin >= buf->play_end_bytes){
|
||||
/* this actually crashes on native xaudio 2.7 */
|
||||
LeaveCriticalSection(&This->lock);
|
||||
return XAUDIO2_E_INVALID_CALL;
|
||||
}
|
||||
|
||||
buf->loop_end_bytes = buf->xa2buffer.LoopBegin + buf->xa2buffer.LoopLength;
|
||||
|
||||
/* xaudio 2.7 allows some invalid looping setups, but later versions
|
||||
* return an error */
|
||||
if(This->xa2->version > 27){
|
||||
if(buf->loop_end_bytes > buf->play_end_bytes){
|
||||
LeaveCriticalSection(&This->lock);
|
||||
return XAUDIO2_E_INVALID_CALL;
|
||||
}
|
||||
|
||||
if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
|
||||
LeaveCriticalSection(&This->lock);
|
||||
return XAUDIO2_E_INVALID_CALL;
|
||||
}
|
||||
}else{
|
||||
if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
|
||||
buf->xa2buffer.LoopCount = 0;
|
||||
buf->loop_end_bytes = buf->play_end_bytes;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
buf->xa2buffer.LoopLength = buf->xa2buffer.PlayLength;
|
||||
buf->xa2buffer.LoopBegin = buf->xa2buffer.PlayBegin;
|
||||
buf->loop_end_bytes = buf->play_end_bytes;
|
||||
}
|
||||
|
||||
buf->offs_bytes = buf->xa2buffer.PlayBegin;
|
||||
buf->cur_end_bytes = buf->loop_end_bytes;
|
||||
|
||||
buf->latest_al_buf = -1;
|
||||
|
||||
++This->nbufs;
|
||||
|
@ -692,7 +755,15 @@ static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
|
|||
static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
|
||||
{
|
||||
XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
|
||||
|
||||
TRACE("%p, 0x%x\n", This, OperationSet);
|
||||
|
||||
EnterCriticalSection(&This->lock);
|
||||
|
||||
This->buffers[This->cur_buf].looped = XAUDIO2_LOOP_INFINITE;
|
||||
|
||||
LeaveCriticalSection(&This->lock);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2908,12 +2979,12 @@ static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al
|
|||
UINT32 submit_bytes;
|
||||
const BYTE *submit_buf = NULL;
|
||||
|
||||
if(buf->offs_bytes >= buf->xa2buffer.AudioBytes){
|
||||
if(buf->offs_bytes >= buf->cur_end_bytes){
|
||||
WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->xa2buffer.AudioBytes - buf->offs_bytes);
|
||||
submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes);
|
||||
submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes;
|
||||
buf->offs_bytes += submit_bytes;
|
||||
|
||||
|
@ -2929,9 +3000,32 @@ static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al
|
|||
|
||||
TRACE("queueing %u bytes, now %u in AL\n", submit_bytes, src->in_al_bytes);
|
||||
|
||||
return buf->offs_bytes < buf->xa2buffer.AudioBytes;
|
||||
return buf->offs_bytes < buf->cur_end_bytes;
|
||||
}
|
||||
|
||||
/* Looping:
|
||||
*
|
||||
* The looped section of a buffer is a subset of the play area which is looped
|
||||
* LoopCount times.
|
||||
*
|
||||
* v PlayBegin
|
||||
* vvvvvvvvvvvvvvvvvv PlayLength
|
||||
* v (PlayEnd)
|
||||
* [-----PPPLLLLLLLLPPPPPPP------]
|
||||
* ^ LoopBegin
|
||||
* ^^^^^^^^ LoopLength
|
||||
* ^ (LoopEnd)
|
||||
*
|
||||
* In the simple case, playback will start at PlayBegin. At LoopEnd, playback
|
||||
* will move to LoopBegin and repeat that loop LoopCount times. Then, playback
|
||||
* will cease at LoopEnd.
|
||||
*
|
||||
* If PlayLength is zero, then PlayEnd is the end of the buffer.
|
||||
*
|
||||
* If LoopLength is zero, then LoopEnd is PlayEnd.
|
||||
*
|
||||
* For corner cases and version differences, see tests.
|
||||
*/
|
||||
static void update_source_state(XA2SourceImpl *src)
|
||||
{
|
||||
int i;
|
||||
|
@ -2985,18 +3079,38 @@ static void update_source_state(XA2SourceImpl *src)
|
|||
TRACE("%p: going to queue a period from buffer %u\n", src, src->cur_buf);
|
||||
|
||||
/* starting from an empty buffer */
|
||||
if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0)
|
||||
if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0 && !src->buffers[src->cur_buf].looped)
|
||||
IXAudio2VoiceCallback_OnBufferStart(src->cb,
|
||||
src->buffers[src->first_buf].xa2buffer.pContext);
|
||||
|
||||
if(!xa2buffer_queue_period(src, &src->buffers[src->cur_buf],
|
||||
src->al_bufs[(src->first_al_buf + src->al_bufs_used) % XAUDIO2_MAX_QUEUED_BUFFERS])){
|
||||
XA2Buffer *cur = &src->buffers[src->cur_buf];
|
||||
|
||||
if(cur->looped < cur->xa2buffer.LoopCount){
|
||||
if(cur->xa2buffer.LoopCount != XAUDIO2_LOOP_INFINITE)
|
||||
++cur->looped;
|
||||
else
|
||||
cur->looped = 1; /* indicate that we are executing a loop */
|
||||
|
||||
cur->offs_bytes = cur->xa2buffer.LoopBegin;
|
||||
if(cur->looped == cur->xa2buffer.LoopCount)
|
||||
cur->cur_end_bytes = cur->play_end_bytes;
|
||||
else
|
||||
cur->cur_end_bytes = cur->loop_end_bytes;
|
||||
|
||||
if(src->cb)
|
||||
IXAudio2VoiceCallback_OnLoopEnd(src->cb,
|
||||
src->buffers[src->cur_buf].xa2buffer.pContext);
|
||||
|
||||
}else{
|
||||
/* buffer is spent, move on */
|
||||
src->cur_buf++;
|
||||
src->cur_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_engine_tick(IXAudio2Impl *This)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue