From: <man...@us...> - 2013-11-21 19:02:55
|
Revision: 3286 http://sourceforge.net/p/modplug/code/3286 Author: manxorist Date: 2013-11-21 19:02:46 +0000 (Thu, 21 Nov 2013) Log Message: ----------- [Imp] sounddev: Add a hidden setting to use hardware timing (defaults to off). [Imp] ASIO: Implement gathering timing information directly from the ASIO driver (this is still mostly not tested). Modified Paths: -------------- trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/mptrack/TrackerSettings.h trunk/OpenMPT/sounddev/SoundDevice.h trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp trunk/OpenMPT/sounddev/SoundDeviceASIO.h Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-11-21 18:46:06 UTC (rev 3285) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-11-21 19:02:46 UTC (rev 3286) @@ -159,6 +159,7 @@ , m_SampleFormat(conf, "Sound Settings", "BitsPerSample", SoundDeviceSettings().sampleFormat) , m_SoundDeviceExclusiveMode(conf, "Sound Settings", "ExclusiveMode", SoundDeviceSettings().ExclusiveMode) , m_SoundDeviceBoostThreadPriority(conf, "Sound Settings", "BoostThreadPriority", SoundDeviceSettings().BoostThreadPriority) + , m_SoundDeviceUseHardwareTiming(conf, "Sound Settings", "UseHardwareTiming", SoundDeviceSettings().UseHardwareTiming) , m_SoundDeviceBaseChannel(conf, "Sound Settings", "ASIOBaseChannel", SoundDeviceSettings().BaseChannel) , MixerMaxChannels(conf, "Sound Settings", "MixChannels", MixerSettings().m_nMaxMixChannels) , MixerDSPMask(conf, "Sound Settings", "Quality", MixerSettings().DSPMask) Modified: trunk/OpenMPT/mptrack/TrackerSettings.h =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.h 2013-11-21 18:46:06 UTC (rev 3285) +++ trunk/OpenMPT/mptrack/TrackerSettings.h 2013-11-21 19:02:46 UTC (rev 3286) @@ -276,6 +276,7 @@ Setting<SampleFormat> m_SampleFormat; Setting<bool> m_SoundDeviceExclusiveMode; Setting<bool> m_SoundDeviceBoostThreadPriority; + Setting<bool> m_SoundDeviceUseHardwareTiming; Setting<uint32> m_SoundDeviceBaseChannel; SoundDeviceSettings GetSoundDeviceSettings() const; void SetSoundDeviceSettings(const SoundDeviceSettings &settings); Modified: trunk/OpenMPT/sounddev/SoundDevice.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.h 2013-11-21 18:46:06 UTC (rev 3285) +++ trunk/OpenMPT/sounddev/SoundDevice.h 2013-11-21 19:02:46 UTC (rev 3286) @@ -167,6 +167,7 @@ SampleFormat sampleFormat; bool ExclusiveMode; // Use hardware buffers directly bool BoostThreadPriority; // Boost thread priority for glitch-free audio rendering + bool UseHardwareTiming; uint32 BaseChannel; SoundDeviceSettings() : hWnd(NULL) @@ -177,6 +178,7 @@ , sampleFormat(SampleFormatInt16) , ExclusiveMode(false) , BoostThreadPriority(true) + , UseHardwareTiming(false) , BaseChannel(0) { return; @@ -192,6 +194,7 @@ && sampleFormat == cmp.sampleFormat && ExclusiveMode == cmp.ExclusiveMode && BoostThreadPriority == cmp.BoostThreadPriority + && UseHardwareTiming == cmp.UseHardwareTiming && BaseChannel == cmp.BaseChannel ; } Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-11-21 18:46:06 UTC (rev 3285) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-11-21 19:02:46 UTC (rev 3286) @@ -194,6 +194,7 @@ m_CanOutputReady = false; m_DeviceRunning = false; + m_TotalFramesWritten = 0; m_BufferIndex = 0; InterlockedExchange(&m_RenderSilence, 0); InterlockedExchange(&m_RenderingSilence, 0); @@ -215,12 +216,13 @@ Init(); - Log(mpt::String::Print("ASIO: Open(%1:'%2'): %3-bit, %4 channels, %5Hz" + Log(mpt::String::Print("ASIO: Open(%1:'%2'): %3-bit, %4 channels, %5Hz, hw-timing=%6" , GetDeviceIndex() , mpt::ToLocale(GetDeviceInternalID()) , m_Settings.sampleFormat.GetBitsPerSample() , m_Settings.Channels , m_Settings.Samplerate + , m_Settings.UseHardwareTiming )); try @@ -369,6 +371,8 @@ m_CanOutputReady = false; } + m_StreamPositionOffset = m_nAsioBufferLen; + m_SampleBuffer.resize(m_nAsioBufferLen * m_Settings.Channels); SoundBufferAttributes bufferAttributes; @@ -464,6 +468,7 @@ { asioCall(start()); m_DeviceRunning = true; + m_TotalFramesWritten = 0; } catch(...) { return false; @@ -494,6 +499,7 @@ { // continue } + m_TotalFramesWritten = 0; m_DeviceRunning = false; } SetRenderSilence(false); @@ -780,6 +786,73 @@ } +bool CASIODevice::InternalHasTimeInfo() const +//------------------------------------------- +{ + return m_Settings.UseHardwareTiming; +} + + +bool CASIODevice::InternalHasGetStreamPosition() const +//---------------------------------------------------- +{ + return m_Settings.UseHardwareTiming; +} + + +int64 CASIODevice::InternalGetStreamPositionFrames() const +//-------------------------------------------------------- +{ + if(m_Settings.UseHardwareTiming) + { + const uint64 asioNow = Clock().NowNanoseconds(); + SoundTimeInfo timeInfo = GetTimeInfo(); + int64 currentStreamPositionFrames = + Util::Round<int64>( + timeInfo.StreamFrames + ((double)((int64)(asioNow - timeInfo.SystemTimestamp)) * timeInfo.Speed * m_Settings.Samplerate / (1000.0 * 1000.0)) + ) + ; + return currentStreamPositionFrames; + } else + { + return ISoundDevice::InternalGetStreamPositionFrames(); + } +} + + +void CASIODevice::UpdateTimeInfo(AsioTimeInfo asioTimeInfo) +//--------------------------------------------------------- +{ + if(m_Settings.UseHardwareTiming) + { + if((asioTimeInfo.flags & kSamplePositionValid) && (asioTimeInfo.flags & kSystemTimeValid)) + { + double speed = 1.0; + if((asioTimeInfo.flags & kSpeedValid) && (asioTimeInfo.speed > 0.0)) + { + speed = asioTimeInfo.speed; + } else if((asioTimeInfo.flags & kSampleRateValid) && (asioTimeInfo.sampleRate > 0.0)) + { + speed *= asioTimeInfo.sampleRate / m_Settings.Samplerate; + } + SoundTimeInfo timeInfo; + timeInfo.StreamFrames = ((((uint64)asioTimeInfo.samplePosition.hi) << 32) | asioTimeInfo.samplePosition.lo) - m_StreamPositionOffset; + timeInfo.SystemTimestamp = (((uint64)asioTimeInfo.systemTime.hi) << 32) | asioTimeInfo.systemTime.lo; + timeInfo.Speed = speed; + ISoundDevice::UpdateTimeInfo(timeInfo); + } else + { // spec violation or nothing provided at all, better to estimate this stuff ourselves + const uint64 asioNow = Clock().NowNanoseconds(); + SoundTimeInfo timeInfo; + timeInfo.StreamFrames = m_TotalFramesWritten + m_nAsioBufferLen - m_StreamPositionOffset; + timeInfo.SystemTimestamp = asioNow + Util::Round<int64>(GetBufferAttributes().Latency * 1000.0 * 1000.0 * 1000.0); + timeInfo.Speed = 1.0; + ISoundDevice::UpdateTimeInfo(timeInfo); + } + } +} + + void CASIODevice::BufferSwitch(long doubleBufferIndex, ASIOBool directProcess) //---------------------------------------------------------------------------- { @@ -792,16 +865,61 @@ { ASSERT(directProcess); // !directProcess is not handled correctly in OpenMPT, would require a separate thread and potentially additional buffering MPT_UNREFERENCED_PARAMETER(directProcess); + if(m_Settings.UseHardwareTiming) + { + if(params) + { + UpdateTimeInfo(params->timeInfo); + } else + { + AsioTimeInfo asioTimeInfo; + MemsetZero(asioTimeInfo); + UpdateTimeInfo(asioTimeInfo); + try + { + ASIOSamples samplePosition; + ASIOTimeStamp systemTime; + MemsetZero(samplePosition); + MemsetZero(systemTime); + if(asioCallUncatched(getSamplePosition(&samplePosition, &systemTime)) == ASE_OK) + { + AsioTimeInfo asioTimeInfoQueried; + MemsetZero(asioTimeInfoQueried); + asioTimeInfoQueried.flags = kSamplePositionValid | kSystemTimeValid; + asioTimeInfoQueried.samplePosition = samplePosition; + asioTimeInfoQueried.systemTime = systemTime; + asioTimeInfoQueried.speed = 1.0; + ASIOSampleRate sampleRate; + MemsetZero(sampleRate); + if(asioCallUncatched(getSampleRate(&sampleRate)) == ASE_OK) + { + if(sampleRate >= 0.0) + { + asioTimeInfoQueried.flags |= kSampleRateValid; + asioTimeInfoQueried.sampleRate = sampleRate; + } + } + asioTimeInfo = asioTimeInfoQueried; + } + } catch(...) + { + // continue + } + UpdateTimeInfo(asioTimeInfo); + } + } m_BufferIndex = doubleBufferIndex; bool rendersilence = (InterlockedExchangeAdd(&m_RenderSilence, 0) == 1); InterlockedExchange(&m_RenderingSilence, rendersilence ? 1 : 0 ); if(rendersilence) { + m_StreamPositionOffset += m_nAsioBufferLen; FillAudioBuffer(); } else { SourceFillAudioBufferLocked(); } + m_TotalFramesWritten += m_nAsioBufferLen; return params; } @@ -827,7 +945,7 @@ result = 1; break; case kAsioSupportsTimeInfo: - result = 0; + result = m_Settings.UseHardwareTiming ? 1 : 0; break; case kAsioResetRequest: case kAsioBufferSizeChange: @@ -844,7 +962,7 @@ result = 2; break; case kAsioSupportsTimeInfo: - result = 0; + result = m_Settings.UseHardwareTiming ? 1 : 0; break; case kAsioResetRequest: case kAsioBufferSizeChange: Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.h 2013-11-21 18:46:06 UTC (rev 3285) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.h 2013-11-21 19:02:46 UTC (rev 3286) @@ -44,11 +44,15 @@ bool m_CanOutputReady; bool m_DeviceRunning; + uint64 m_TotalFramesWritten; long m_BufferIndex; LONG m_RenderSilence; LONG m_RenderingSilence; + int64 m_StreamPositionOffset; + private: + void UpdateTimeInfo(AsioTimeInfo asioTimeInfo); static bool IsSampleTypeFloat(ASIOSampleType sampleType); static std::size_t GetSampleSize(ASIOSampleType sampleType); @@ -82,6 +86,10 @@ void CloseDriver(); bool IsDriverOpen() const { return (m_pAsioDrv != nullptr); } + bool InternalHasTimeInfo() const; + bool InternalHasGetStreamPosition() const; + int64 InternalGetStreamPositionFrames() const; + protected: long AsioMessage(long selector, long value, void* message, double* opt); void SampleRateDidChange(ASIOSampleRate sRate); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |