Stable, correct and uncut audio playback GET!
Originally committed to SVN as r1100.
This commit is contained in:
parent
4276b02f89
commit
c1cb6e4367
2 changed files with 34 additions and 27 deletions
|
@ -62,7 +62,6 @@ DirectSoundPlayer::DirectSoundPlayer() {
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
directSound = NULL;
|
directSound = NULL;
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
notificationEvent = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,7 +81,7 @@ void DirectSoundPlayer::OpenStream() {
|
||||||
// Initialize the DirectSound object
|
// Initialize the DirectSound object
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
||||||
if (res != DS_OK) throw _T("Failed initializing DirectSound");
|
if (FAILED(res)) throw _T("Failed initializing DirectSound");
|
||||||
|
|
||||||
// Set DirectSound parameters
|
// Set DirectSound parameters
|
||||||
AegisubApp *app = (AegisubApp*) wxTheApp;
|
AegisubApp *app = (AegisubApp*) wxTheApp;
|
||||||
|
@ -99,7 +98,7 @@ void DirectSoundPlayer::OpenStream() {
|
||||||
waveFormat.cbSize = 0;
|
waveFormat.cbSize = 0;
|
||||||
|
|
||||||
// Create the buffer initializer
|
// Create the buffer initializer
|
||||||
int aim = 0x20000;
|
int aim = waveFormat.nAvgBytesPerSec + waveFormat.nAvgBytesPerSec/2; // one and a half second of buffer
|
||||||
int min = DSBSIZE_MIN;
|
int min = DSBSIZE_MIN;
|
||||||
int max = DSBSIZE_MAX;
|
int max = DSBSIZE_MAX;
|
||||||
bufSize = MIN(MAX(min,aim),max);
|
bufSize = MIN(MAX(min,aim),max);
|
||||||
|
@ -168,7 +167,6 @@ bool DirectSoundPlayer::FillBuffer(bool fill) {
|
||||||
if (FAILED(res)) return false;
|
if (FAILED(res)) return false;
|
||||||
toWrite = (int)bufplay - (int)offset;
|
toWrite = (int)bufplay - (int)offset;
|
||||||
if (toWrite < 0) toWrite += bufSize;
|
if (toWrite < 0) toWrite += bufSize;
|
||||||
//wxLogDebug(_T("DSound Fill Buffer: bufplay=%u, offset=%d, toWrite=%d"), bufplay, offset, toWrite);
|
|
||||||
}
|
}
|
||||||
if (toWrite == 0) return true;
|
if (toWrite == 0) return true;
|
||||||
|
|
||||||
|
@ -194,8 +192,6 @@ RetryLock:
|
||||||
// Update offset
|
// Update offset
|
||||||
offset = (offset + toWrite) % bufSize;
|
offset = (offset + toWrite) % bufSize;
|
||||||
|
|
||||||
//wxLogDebug(_T("DSound Fill Buffer: offset=%d, toWrite=%d, size1=%u, size2=%u"), offset, toWrite, size1, size2);
|
|
||||||
|
|
||||||
// Convert size to number of samples
|
// Convert size to number of samples
|
||||||
unsigned long int count1 = size1 / bytesps;
|
unsigned long int count1 = size1 / bytesps;
|
||||||
unsigned long int count2 = size2 / bytesps;
|
unsigned long int count2 = size2 / bytesps;
|
||||||
|
@ -207,12 +203,8 @@ RetryLock:
|
||||||
unsigned long int delta = 0;
|
unsigned long int delta = 0;
|
||||||
if (totalCount > left) delta = totalCount - left;
|
if (totalCount > left) delta = totalCount - left;
|
||||||
|
|
||||||
// If so, zero-fill buffer first
|
// And only write the remaining samples
|
||||||
if (delta) {
|
if (delta) {
|
||||||
// Zero at start
|
|
||||||
memset(ptr1,0,size1);
|
|
||||||
memset(ptr2,0,size2);
|
|
||||||
|
|
||||||
// Lower counts
|
// Lower counts
|
||||||
int temp = MIN(delta,count2);
|
int temp = MIN(delta,count2);
|
||||||
count2 -= temp;
|
count2 -= temp;
|
||||||
|
@ -222,19 +214,15 @@ RetryLock:
|
||||||
delta -= temp;
|
delta -= temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
//wxLogDebug(_T("DSound Fill Buffer, playpos=%d, count1=%u, count2=%u"), (int)playPos, count1, count2);
|
|
||||||
|
|
||||||
// Get source wave
|
// Get source wave
|
||||||
if (count1) provider->GetAudioWithVolume(ptr1, playPos, count1, volume);
|
if (count1) provider->GetAudioWithVolume(ptr1, playPos, count1, volume);
|
||||||
if (count2) provider->GetAudioWithVolume(ptr2, playPos+count1, count2, volume);
|
if (count2) provider->GetAudioWithVolume(ptr2, playPos+count1, count2, volume);
|
||||||
playPos += count1+count2;
|
playPos += count1+count2;
|
||||||
|
|
||||||
//wxLogDebug(_T("DSound Fill Buffer post-fill, playpos=%d, count1=%u, count2=%u"), (int)playPos, count1, count2);
|
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
buffer->Unlock(ptr1,count1*bytesps,ptr2,count2*bytesps);
|
buffer->Unlock(ptr1,count1*bytesps,ptr2,count2*bytesps);
|
||||||
|
|
||||||
return true;
|
return delta==0; // If delta>0 we hit end of stream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -268,6 +256,7 @@ void DirectSoundPlayer::Play(__int64 start,__int64 count) {
|
||||||
buffer->SetCurrentPosition(0);
|
buffer->SetCurrentPosition(0);
|
||||||
res = buffer->Play(0,0,DSBPLAY_LOOPING);
|
res = buffer->Play(0,0,DSBPLAY_LOOPING);
|
||||||
if (SUCCEEDED(res)) playing = true;
|
if (SUCCEEDED(res)) playing = true;
|
||||||
|
startTime = GetTickCount();
|
||||||
|
|
||||||
// Update timer
|
// Update timer
|
||||||
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
||||||
|
@ -295,11 +284,6 @@ void DirectSoundPlayer::Stop(bool timerToo) {
|
||||||
endPos = 0;
|
endPos = 0;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
// Close event handle
|
|
||||||
if (notificationEvent)
|
|
||||||
CloseHandle(notificationEvent);
|
|
||||||
notificationEvent = 0;
|
|
||||||
|
|
||||||
// Stop timer
|
// Stop timer
|
||||||
if (timerToo && displayTimer) {
|
if (timerToo && displayTimer) {
|
||||||
displayTimer->Stop();
|
displayTimer->Stop();
|
||||||
|
@ -327,6 +311,10 @@ __int64 DirectSoundPlayer::GetCurrentPosition() {
|
||||||
// Check if buffer is loaded
|
// Check if buffer is loaded
|
||||||
if (!buffer || !playing) return 0;
|
if (!buffer || !playing) return 0;
|
||||||
|
|
||||||
|
DWORD curtime = GetTickCount();
|
||||||
|
__int64 tdiff = curtime - startTime;
|
||||||
|
return startPos + tdiff * provider->GetSampleRate() / 1000;
|
||||||
|
|
||||||
// Read position
|
// Read position
|
||||||
unsigned long int play,write;
|
unsigned long int play,write;
|
||||||
HRESULT res = buffer->GetCurrentPosition(&play,NULL);
|
HRESULT res = buffer->GetCurrentPosition(&play,NULL);
|
||||||
|
@ -346,7 +334,7 @@ __int64 DirectSoundPlayer::GetCurrentPosition() {
|
||||||
// Thread constructor
|
// Thread constructor
|
||||||
DirectSoundPlayerThread::DirectSoundPlayerThread(DirectSoundPlayer *par) : wxThread(wxTHREAD_JOINABLE) {
|
DirectSoundPlayerThread::DirectSoundPlayerThread(DirectSoundPlayer *par) : wxThread(wxTHREAD_JOINABLE) {
|
||||||
parent = par;
|
parent = par;
|
||||||
stopnotify = CreateEvent(NULL, false, false, NULL);
|
stopnotify = CreateEvent(NULL, true, false, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -363,11 +351,30 @@ wxThread::ExitCode DirectSoundPlayerThread::Entry() {
|
||||||
// Wake up thread every half second to fill buffer as needed
|
// Wake up thread every half second to fill buffer as needed
|
||||||
// This more or less assumes the buffer is at least one second long
|
// This more or less assumes the buffer is at least one second long
|
||||||
while (WaitForSingleObject(stopnotify, 500)) {
|
while (WaitForSingleObject(stopnotify, 500)) {
|
||||||
if (!parent->FillBuffer(false))
|
if (!parent->FillBuffer(false)) {
|
||||||
// FillBuffer returns true if there's more to play
|
// FillBuffer returns false when end of stream is reached
|
||||||
// So false means end-of-stream
|
wxLogDebug(_T("DS thread hit end of stream"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now fill buffer with silence
|
||||||
|
DWORD bytesFilled = 0;
|
||||||
|
while (WaitForSingleObject(stopnotify, 500)) {
|
||||||
|
void *buf1, *buf2;
|
||||||
|
DWORD size1, size2;
|
||||||
|
DWORD playpos;
|
||||||
|
HRESULT res;
|
||||||
|
res = parent->buffer->GetCurrentPosition(&playpos, NULL);
|
||||||
|
if (FAILED(res)) break;
|
||||||
|
res = parent->buffer->Lock(parent->offset, (playpos-parent->offset)%parent->bufSize, &buf1, &size1, &buf2, &size2, 0);
|
||||||
|
if (FAILED(res)) break;
|
||||||
|
if (size1) memset(buf1, 0, size1);
|
||||||
|
if (size2) memset(buf2, 0, size2);
|
||||||
|
bytesFilled += size1 + size2;
|
||||||
|
parent->buffer->Unlock(buf1, size1, buf2, size2);
|
||||||
|
if (bytesFilled >= parent->bufSize) break;
|
||||||
|
}
|
||||||
|
|
||||||
wxLogDebug(_T("DS thread dead"));
|
wxLogDebug(_T("DS thread dead"));
|
||||||
|
|
||||||
|
|
|
@ -79,12 +79,12 @@ private:
|
||||||
int bufSize;
|
int bufSize;
|
||||||
|
|
||||||
volatile __int64 playPos;
|
volatile __int64 playPos;
|
||||||
volatile __int64 startPos;
|
__int64 startPos;
|
||||||
volatile __int64 endPos;
|
volatile __int64 endPos;
|
||||||
|
DWORD startTime;
|
||||||
|
|
||||||
IDirectSound8 *directSound;
|
IDirectSound8 *directSound;
|
||||||
IDirectSoundBuffer8 *buffer;
|
IDirectSoundBuffer8 *buffer;
|
||||||
HANDLE notificationEvent;
|
|
||||||
|
|
||||||
bool FillBuffer(bool fill);
|
bool FillBuffer(bool fill);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue