From: <man...@us...> - 2013-11-17 16:02:17
|
Revision: 3250 http://sourceforge.net/p/modplug/code/3250 Author: manxorist Date: 2013-11-17 16:02:07 +0000 (Sun, 17 Nov 2013) Log Message: ----------- [Ref] sounddev: Cleanup naming of buffer attributes statistics. [Ref] sounddev: Clarify that GetCurrentLatency() is informational only and should not be used for timing. [Imp] sounddev: Add current buffer usage to sound card statistics. [Imp] sounddev: Improve accuracy of latency and update interval statistics for portaudio based devices. [Ref] sounddev: Explicitly pass around the wanted update interval for sound devices where we manage the rendering thread instead of relying on the value from the buffer attributes structure. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mpdlgs.cpp trunk/OpenMPT/sounddev/SoundDevice.cpp trunk/OpenMPT/sounddev/SoundDevice.h trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h trunk/OpenMPT/sounddev/SoundDevicePortAudio.cpp trunk/OpenMPT/sounddev/SoundDevicePortAudio.h trunk/OpenMPT/sounddev/SoundDeviceWaveout.cpp trunk/OpenMPT/sounddev/SoundDeviceWaveout.h trunk/OpenMPT/sounddev/SoundDevices.h Modified: trunk/OpenMPT/mptrack/Mpdlgs.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-11-17 16:02:07 UTC (rev 3250) @@ -544,11 +544,13 @@ if(pMainFrm->gpSoundDevice && pMainFrm->IsPlaying()) { CHAR s[256]; - _snprintf(s, 255, "Buffers: %d\r\nUpdate interval: %4.1f ms\r\nLatency: %4.1f ms\r\nCurrent Latency: %4.1f ms", - pMainFrm->gpSoundDevice->GetRealNumBuffers(), - (float)(pMainFrm->gpSoundDevice->GetRealUpdateInterval() * 1000.0f), - (float)(pMainFrm->gpSoundDevice->GetRealLatency() * 1000.0f), - (float)(pMainFrm->gpSoundDevice->GetCurrentRealLatency() * 1000.0f) + const SoundBufferAttributes bufferAttributes = pMainFrm->gpSoundDevice->GetBufferAttributes(); + const double currentLatency = pMainFrm->gpSoundDevice->GetCurrentLatency(); + _snprintf(s, 255, "Buffers: %d (%d%%)\r\nUpdate interval: %4.1f ms\r\nLatency: %4.1f ms\r\nCurrent Latency: %4.1f ms", + (int)bufferAttributes.NumBuffers, (bufferAttributes.Latency > 0.0) ? Util::Round<int>(currentLatency / bufferAttributes.Latency * 100.0) : 0, + (float)(bufferAttributes.UpdateInterval * 1000.0f), + (float)(bufferAttributes.Latency * 1000.0f), + (float)(currentLatency * 1000.0f) ); m_EditStatistics.SetWindowText(s); } else Modified: trunk/OpenMPT/sounddev/SoundDevice.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.cpp 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDevice.cpp 2013-11-17 16:02:07 UTC (rev 3250) @@ -39,9 +39,9 @@ , m_InternalID(internalID) { - m_RealLatency = m_Settings.LatencyMS / 1000.0; - m_RealUpdateInterval = m_Settings.UpdateIntervalMS / 1000.0; - m_RealNumBuffers = 0; + m_BufferAttributes.Latency = m_Settings.LatencyMS / 1000.0; + m_BufferAttributes.UpdateInterval = m_Settings.UpdateIntervalMS / 1000.0; + m_BufferAttributes.NumBuffers = 0; m_IsPlaying = false; m_StreamPositionRenderFrames = 0; @@ -98,6 +98,13 @@ } +void ISoundDevice::UpdateBufferAttributes(SoundBufferAttributes attributes) +//------------------------------------------------------------------------- +{ + m_BufferAttributes = attributes; +} + + bool ISoundDevice::Open(const SoundDeviceSettings &settings) //---------------------------------------------------------- { @@ -110,9 +117,9 @@ if(m_Settings.LatencyMS > SNDDEV_MAXLATENCY_MS) m_Settings.LatencyMS = SNDDEV_MAXLATENCY_MS; if(m_Settings.UpdateIntervalMS < SNDDEV_MINUPDATEINTERVAL_MS) m_Settings.UpdateIntervalMS = SNDDEV_MINUPDATEINTERVAL_MS; if(m_Settings.UpdateIntervalMS > SNDDEV_MAXUPDATEINTERVAL_MS) m_Settings.UpdateIntervalMS = SNDDEV_MAXUPDATEINTERVAL_MS; - m_RealLatency = m_Settings.LatencyMS / 1000.0; - m_RealUpdateInterval = m_Settings.UpdateIntervalMS / 1000.0; - m_RealNumBuffers = 0; + m_BufferAttributes.Latency = m_Settings.LatencyMS / 1000.0; + m_BufferAttributes.UpdateInterval = m_Settings.UpdateIntervalMS / 1000.0; + m_BufferAttributes.NumBuffers = 0; return InternalOpen(); } @@ -276,6 +283,7 @@ } } + m_WakeupInterval = 0.0; m_hPlayThread = NULL; m_dwPlayThreadId = 0; m_hAudioWakeUp = NULL; @@ -527,7 +535,7 @@ { CPriorityBooster priorityBooster(*this, m_SoundDevice.m_Settings.BoostThreadPriority); - CPeriodicWaker periodicWaker(*this, m_SoundDevice.GetRealUpdateInterval()); + CPeriodicWaker periodicWaker(*this, m_WakeupInterval); m_SoundDevice.StartFromSoundThread(); @@ -561,6 +569,13 @@ } +void CAudioThread::SetWakeupInterval(double seconds) +//-------------------------------------------------- +{ + m_WakeupInterval = seconds; +} + + void CAudioThread::Activate() //--------------------------- { @@ -595,6 +610,13 @@ } +void CSoundDeviceWithThread::SetWakeupInterval(double seconds) +//------------------------------------------------------------ +{ + m_AudioThread.SetWakeupInterval(seconds); +} + + void CSoundDeviceWithThread::InternalStart() //------------------------------------------ { Modified: trunk/OpenMPT/sounddev/SoundDevice.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.h 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDevice.h 2013-11-17 16:02:07 UTC (rev 3250) @@ -206,6 +206,21 @@ class SoundDevicesManager; +struct SoundBufferAttributes +{ + double Latency; // seconds + double UpdateInterval; // seconds + int NumBuffers; + SoundBufferAttributes() + : Latency(0.0) + , UpdateInterval(0.0) + , NumBuffers(0) + { + return; + } +}; + + //============================================= class ISoundDevice : protected IFillAudioBuffer //============================================= @@ -227,9 +242,7 @@ private: - double m_RealLatency; - double m_RealUpdateInterval; - int m_RealNumBuffers; + SoundBufferAttributes m_BufferAttributes; bool m_IsPlaying; @@ -251,12 +264,7 @@ bool FillWaveFormatExtensible(WAVEFORMATEXTENSIBLE &WaveFormat); - void UpdateLatencyInfo(double latency, double updateInterval, int numBuffers) - { - m_RealLatency = latency; - m_RealUpdateInterval = updateInterval; - m_RealNumBuffers = numBuffers; - } + void UpdateBufferAttributes(SoundBufferAttributes attributes); virtual bool InternalHasGetStreamPosition() const { return false; } virtual int64 InternalGetStreamPositionFrames() const { return 0; } @@ -295,11 +303,11 @@ SampleFormat GetActualSampleFormat() { return IsOpen() ? m_Settings.sampleFormat : SampleFormatInvalid; } - double GetRealLatency() const { return m_RealLatency; } // seconds - double GetRealUpdateInterval() const { return m_RealUpdateInterval; } // seconds - int GetRealNumBuffers() const { return m_RealNumBuffers; } + SoundBufferAttributes GetBufferAttributes() const { return m_BufferAttributes; } - virtual double GetCurrentRealLatency() const { return GetRealLatency(); } + // Informational only, do not use for timing. + // Use GetStreamPositionFrames() for timing + virtual double GetCurrentLatency() const { return m_BufferAttributes.Latency; } int64 GetStreamPositionFrames() const; Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-11-17 16:02:07 UTC (rev 3250) @@ -270,10 +270,11 @@ } m_nAsioBufferLen = n; } - UpdateLatencyInfo( - m_nAsioBufferLen * 2.0 / m_Settings.Samplerate, - m_nAsioBufferLen * 1.0 / m_Settings.Samplerate, - 2); + SoundBufferAttributes bufferAttributes; + bufferAttributes.Latency = m_nAsioBufferLen * 2.0 / m_Settings.Samplerate; + bufferAttributes.UpdateInterval = m_nAsioBufferLen * 1.0 / m_Settings.Samplerate; + bufferAttributes.NumBuffers = 2; + UpdateBufferAttributes(bufferAttributes); #ifdef ASIO_LOG Log(" Using buffersize=%d samples\n", m_nAsioBufferLen); #endif Modified: trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp 2013-11-17 16:02:07 UTC (rev 3250) @@ -251,11 +251,13 @@ m_pMixBuffer->GetStatus(&dwStat); if (dwStat & DSBSTATUS_BUFFERLOST) m_pMixBuffer->Restore(); } - UpdateLatencyInfo( - m_nDSoundBufferSize * 1.0 / m_Settings.GetBytesPerSecond(), - std::min(m_Settings.UpdateIntervalMS / 1000.0, m_nDSoundBufferSize / (2.0 * m_Settings.GetBytesPerSecond())), - 1); m_dwWritePos = 0xFFFFFFFF; + SetWakeupInterval(std::min(m_Settings.UpdateIntervalMS / 1000.0, m_nDSoundBufferSize / (2.0 * m_Settings.GetBytesPerSecond()))); + SoundBufferAttributes bufferAttributes; + bufferAttributes.Latency = m_nDSoundBufferSize * 1.0 / m_Settings.GetBytesPerSecond(); + bufferAttributes.UpdateInterval = std::min(m_Settings.UpdateIntervalMS / 1000.0, m_nDSoundBufferSize / (2.0 * m_Settings.GetBytesPerSecond())); + bufferAttributes.NumBuffers = 1; + UpdateBufferAttributes(bufferAttributes); return true; } Modified: trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h 2013-11-17 16:02:07 UTC (rev 3250) @@ -46,7 +46,7 @@ void StartFromSoundThread(); void StopFromSoundThread(); bool InternalIsOpen() const { return (m_pMixBuffer != NULL); } - double GetCurrentRealLatency() const { return 1.0 * m_dwLatency / m_Settings.GetBytesPerSecond(); } + double GetCurrentLatency() const { return 1.0 * m_dwLatency / m_Settings.GetBytesPerSecond(); } SoundDeviceCaps GetDeviceCaps(const std::vector<uint32> &baseSampleRates); protected: Modified: trunk/OpenMPT/sounddev/SoundDevicePortAudio.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDevicePortAudio.cpp 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDevicePortAudio.cpp 2013-11-17 16:02:07 UTC (rev 3250) @@ -33,6 +33,7 @@ m_HostApi = SndDevTypeToHostApi(id.GetType()); MemsetZero(m_StreamParameters); m_Stream = 0; + m_StreamInfo = 0; m_CurrentFrameCount = 0; m_CurrentRealLatency = 0.0; } @@ -50,6 +51,7 @@ { MemsetZero(m_StreamParameters); m_Stream = 0; + m_StreamInfo = 0; m_CurrentFrameBuffer = 0; m_CurrentFrameCount = 0; m_StreamParameters.device = HostApiOutputIndexToGlobalDeviceIndex(GetDeviceIndex(), m_HostApi); @@ -83,16 +85,18 @@ } if(Pa_IsFormatSupported(NULL, &m_StreamParameters, m_Settings.Samplerate) != paFormatIsSupported) return false; if(Pa_OpenStream(&m_Stream, NULL, &m_StreamParameters, m_Settings.Samplerate, /*static_cast<long>(m_UpdateIntervalMS * pwfx->nSamplesPerSec / 1000.0f)*/ paFramesPerBufferUnspecified, paNoFlag, StreamCallbackWrapper, (void*)this) != paNoError) return false; - if(!Pa_GetStreamInfo(m_Stream)) + m_StreamInfo = Pa_GetStreamInfo(m_Stream); + if(!m_StreamInfo) { Pa_CloseStream(m_Stream); m_Stream = 0; return false; } - UpdateLatencyInfo( - Pa_GetStreamInfo(m_Stream)->outputLatency, - m_Settings.UpdateIntervalMS / 1000.0, - 1); + SoundBufferAttributes bufferAttributes; + bufferAttributes.Latency = m_StreamInfo->outputLatency; + bufferAttributes.UpdateInterval = m_Settings.UpdateIntervalMS / 1000.0; + bufferAttributes.NumBuffers = 1; + UpdateBufferAttributes(bufferAttributes); return true; } @@ -106,9 +110,10 @@ Pa_CloseStream(m_Stream); if(Pa_GetDeviceInfo(m_StreamParameters.device)->hostApi == Pa_HostApiTypeIdToHostApiIndex(paWDMKS)) { - Pa_Sleep((long)(GetRealLatency() * 2.0 * 1000.0)); // wait for broken wdm drivers not closing the stream immediatly + Pa_Sleep(Util::Round<long>(GetBufferAttributes().Latency * 2.0 * 1000.0 + 0.5)); // wait for broken wdm drivers not closing the stream immediatly } MemsetZero(m_StreamParameters); + m_StreamInfo = 0; m_Stream = 0; m_CurrentFrameCount = 0; m_CurrentFrameBuffer = 0; @@ -136,7 +141,7 @@ { if(m_CurrentFrameCount == 0) return; SourceAudioRead(m_CurrentFrameBuffer, m_CurrentFrameCount); - SourceAudioDone(m_CurrentFrameCount, static_cast<ULONG>(m_CurrentRealLatency * Pa_GetStreamInfo(m_Stream)->sampleRate)); + SourceAudioDone(m_CurrentFrameCount, static_cast<ULONG>(m_CurrentRealLatency * m_StreamInfo->sampleRate)); } @@ -144,12 +149,12 @@ //-------------------------------------------------------------- { if(Pa_IsStreamActive(m_Stream) != 1) return 0; - return static_cast<int64>(Pa_GetStreamTime(m_Stream) * Pa_GetStreamInfo(m_Stream)->sampleRate); + return static_cast<int64>(Pa_GetStreamTime(m_Stream) * m_StreamInfo->sampleRate); } -double CPortaudioDevice::GetCurrentRealLatency() const -//---------------------------------------------------- +double CPortaudioDevice::GetCurrentLatency() const +//------------------------------------------------ { return m_CurrentRealLatency; } @@ -206,11 +211,16 @@ { // For WDM-KS, timeInfo->outputBufferDacTime seems to contain bogus values. // Work-around it by using the slightly less accurate per-stream latency estimation. - m_CurrentRealLatency = Pa_GetStreamInfo(m_Stream)->outputLatency; + m_CurrentRealLatency = m_StreamInfo->outputLatency; } else { m_CurrentRealLatency = timeInfo->outputBufferDacTime - timeInfo->currentTime; } + SoundBufferAttributes bufferAttributes; + bufferAttributes.Latency = m_StreamInfo->outputLatency; + bufferAttributes.UpdateInterval = (double)frameCount / (double)m_StreamInfo->sampleRate; + bufferAttributes.NumBuffers = 1; + UpdateBufferAttributes(bufferAttributes); m_CurrentFrameBuffer = output; m_CurrentFrameCount = frameCount; SourceFillAudioBufferLocked(); Modified: trunk/OpenMPT/sounddev/SoundDevicePortAudio.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDevicePortAudio.h 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDevicePortAudio.h 2013-11-17 16:02:07 UTC (rev 3250) @@ -33,6 +33,7 @@ PaStreamParameters m_StreamParameters; PaWasapiStreamInfo m_WasapiStreamInfo; PaStream * m_Stream; + const PaStreamInfo * m_StreamInfo; void * m_CurrentFrameBuffer; unsigned long m_CurrentFrameCount; @@ -49,7 +50,7 @@ void InternalStart(); void InternalStop(); bool InternalIsOpen() const { return m_Stream ? true : false; } - double GetCurrentRealLatency() const; + double GetCurrentLatency() const; bool InternalHasGetStreamPosition() const { return false; } int64 InternalGetStreamPositionFrames() const; SoundDeviceCaps GetDeviceCaps(const std::vector<uint32> &baseSampleRates); Modified: trunk/OpenMPT/sounddev/SoundDeviceWaveout.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceWaveout.cpp 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDeviceWaveout.cpp 2013-11-17 16:02:07 UTC (rev 3250) @@ -93,12 +93,14 @@ Close(); return false; } - UpdateLatencyInfo( - m_nWaveBufferSize * m_nPreparedHeaders * 1.0 / m_Settings.GetBytesPerSecond(), - m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond(), - m_nPreparedHeaders); m_nBuffersPending = 0; m_nWriteBuffer = 0; + SetWakeupInterval(m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond()); + SoundBufferAttributes bufferAttributes; + bufferAttributes.Latency = m_nWaveBufferSize * m_nPreparedHeaders * 1.0 / m_Settings.GetBytesPerSecond(); + bufferAttributes.UpdateInterval = m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond(); + bufferAttributes.NumBuffers = m_nPreparedHeaders; + UpdateBufferAttributes(bufferAttributes); return true; } Modified: trunk/OpenMPT/sounddev/SoundDeviceWaveout.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceWaveout.h 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDeviceWaveout.h 2013-11-17 16:02:07 UTC (rev 3250) @@ -45,7 +45,7 @@ void StartFromSoundThread(); void StopFromSoundThread(); bool InternalIsOpen() const { return (m_hWaveOut != NULL); } - double GetCurrentRealLatency() const { return InterlockedExchangeAdd(&m_nBuffersPending, 0) * m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond(); } + double GetCurrentLatency() const { return InterlockedExchangeAdd(&m_nBuffersPending, 0) * m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond(); } bool InternalHasGetStreamPosition() const { return true; } int64 InternalGetStreamPositionFrames() const; Modified: trunk/OpenMPT/sounddev/SoundDevices.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDevices.h 2013-11-17 00:40:57 UTC (rev 3249) +++ trunk/OpenMPT/sounddev/SoundDevices.h 2013-11-17 16:02:07 UTC (rev 3250) @@ -38,6 +38,7 @@ FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics; FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics; + double m_WakeupInterval; HANDLE m_hAudioWakeUp; HANDLE m_hPlayThread; HANDLE m_hAudioThreadTerminateRequest; @@ -52,6 +53,7 @@ ~CAudioThread(); void Activate(); void Deactivate(); + void SetWakeupInterval(double seconds); }; @@ -62,6 +64,8 @@ CAudioThread m_AudioThread; private: void FillAudioBufferLocked(); +protected: + void SetWakeupInterval(double seconds); public: CSoundDeviceWithThread(SoundDeviceID id, const std::wstring &internalID) : ISoundDevice(id, internalID), m_AudioThread(*this) {} virtual ~CSoundDeviceWithThread() {} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |