diff options
| author | Ac_K <Acoustik666@gmail.com> | 2019-09-20 01:49:05 +0200 |
|---|---|---|
| committer | Thomas Guillemard <me@thog.eu> | 2019-09-20 01:49:05 +0200 |
| commit | f17b772c56cf73ac539b4c8c47e0a7c8f29dae5a (patch) | |
| tree | dbc043dbea8502a2978f1ac7809f14884bd8d3ff /Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager | |
| parent | a0720b5681852f3d786d77bd3793b0359dea321c (diff) | |
audren: Fix AudioRenderer implementation (#773)
* Fix AudioRenderer implementation
According to RE:
- `GetAudioRendererWorkBufferSize` is updated and improved to support `REV7`
- `RequestUpdateAudioRenderer` is updated to `REV7` too
Should improve results on recent game and close #718 and #707
* Fix NodeStates.GetWorkBufferSize
* Use BitUtils instead of IntUtils
* Nits
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager')
14 files changed, 208 insertions, 29 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs new file mode 100644 index 00000000..c884b465 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class AudioRendererCommon + { + public static bool CheckValidRevision(AudioRendererParameter parameters) => GetRevisionVersion(parameters.Revision) <= AudioRendererConsts.Revision; + public static bool CheckFeatureSupported(int revision, int supportedRevision) => revision >= supportedRevision; + public static int GetRevisionVersion(int revision) => (revision - AudioRendererConsts.Rev0Magic) >> 24; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs new file mode 100644 index 00000000..461e4337 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs @@ -0,0 +1,30 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class BehaviorInfo + { + private const int _revision = AudioRendererConsts.Revision; + + private int _userRevision = 0; + + public BehaviorInfo() + { + /* TODO: this class got a size of 0xC0 + 0x00 - uint - Internal Revision + 0x04 - uint - User Revision + 0x08 - ... unknown ... + */ + } + + public bool IsSplitterSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.Splitter); + public bool IsSplitterBugFixed() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.SplitterBugFix); + public bool IsVariadicCommandBufferSizeSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.VariadicCommandBufferSize); + public bool IsElapsedFrameCountSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.ElapsedFrameCount); + + public int GetPerformanceMetricsDataFormat() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.PerformanceMetricsDataFormatVersion2) ? 2 : 1; + + public void SetUserLibRevision(int revision) + { + _userRevision = AudioRendererCommon.GetRevisionVersion(revision); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs new file mode 100644 index 00000000..b09b990b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class CommandGenerator + { + public static long CalculateCommandBufferSize(AudioRendererParameter parameters) + { + return parameters.EffectCount * 0x840 + + parameters.SubMixCount * 0x5A38 + + parameters.SinkCount * 0x148 + + parameters.SplitterDestinationDataCount * 0x540 + + (parameters.SplitterCount * 0x68 + 0x2E0) * parameters.VoiceCount + + ((parameters.VoiceCount + parameters.SubMixCount + parameters.EffectCount + parameters.SinkCount + 0x65) << 6) + + 0x3F8; + } + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs new file mode 100644 index 00000000..3f87ae04 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class EdgeMatrix + { + public static int GetWorkBufferSize(int totalMixCount) + { + int size = BitUtils.AlignUp(totalMixCount * totalMixCount, AudioRendererConsts.BufferAlignment); + + if (size < 0) + { + size |= 7; + } + + return size / 8; + } + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs index 975992aa..0075fd5f 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs @@ -51,8 +51,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager _params = Params; _track = audioOut.OpenTrack( - AudioConsts.HostSampleRate, - AudioConsts.HostChannelsCount, + AudioRendererConsts.HostSampleRate, + AudioRendererConsts.HostChannelsCount, AudioCallback); _memoryPools = CreateArray<MemoryPoolContext>(Params.EffectCount + Params.VoiceCount * 4); @@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager // GetMixBufferCount() -> u32 public ResultCode GetMixBufferCount(ServiceCtx context) { - context.ResponseData.Write(_params.MixCount); + context.ResponseData.Write(_params.SubMixCount); return ResultCode.Success; } @@ -145,6 +145,10 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager UpdateDataHeader inputHeader = reader.Read<UpdateDataHeader>(); + BehaviorInfo behaviorInfo = new BehaviorInfo(); + + behaviorInfo.SetUserLibRevision(inputHeader.Revision); + reader.Read<BehaviorIn>(inputHeader.BehaviorSize); MemoryPoolIn[] memoryPoolsIn = reader.Read<MemoryPoolIn>(inputHeader.MemoryPoolSize); @@ -207,20 +211,27 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager int updateHeaderSize = Marshal.SizeOf<UpdateDataHeader>(); - outputHeader.Revision = IAudioRendererManager.RevMagic; + outputHeader.Revision = AudioRendererConsts.RevMagic; outputHeader.BehaviorSize = 0xb0; outputHeader.MemoryPoolSize = (_params.EffectCount + _params.VoiceCount * 4) * 0x10; outputHeader.VoiceSize = _params.VoiceCount * 0x10; outputHeader.EffectSize = _params.EffectCount * 0x10; outputHeader.SinkSize = _params.SinkCount * 0x20; outputHeader.PerformanceManagerSize = 0x10; - outputHeader.TotalSize = updateHeaderSize + - outputHeader.BehaviorSize + - outputHeader.MemoryPoolSize + - outputHeader.VoiceSize + - outputHeader.EffectSize + - outputHeader.SinkSize + - outputHeader.PerformanceManagerSize; + + if (behaviorInfo.IsElapsedFrameCountSupported()) + { + outputHeader.ElapsedFrameCountInfoSize = 0x10; + } + + outputHeader.TotalSize = updateHeaderSize + + outputHeader.BehaviorSize + + outputHeader.MemoryPoolSize + + outputHeader.VoiceSize + + outputHeader.EffectSize + + outputHeader.SinkSize + + outputHeader.PerformanceManagerSize + + outputHeader.ElapsedFrameCountInfoSize; writer.Write(outputHeader); @@ -305,7 +316,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager private void AppendMixedBuffer(long tag) { - int[] mixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount]; + int[] mixBuffer = new int[MixBufferSamplesCount * AudioRendererConsts.HostChannelsCount]; foreach (VoiceContext voice in _voices) { diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs new file mode 100644 index 00000000..7ae9aeea --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class NodeStates + { + public static long GetWorkBufferSize(int totalMixCount) + { + int size = BitUtils.AlignUp(totalMixCount, AudioRendererConsts.BufferAlignment); + + if (size < 0) + { + size |= 7; + } + + return 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (size / 8); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs new file mode 100644 index 00000000..1b8c8a7c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs @@ -0,0 +1,30 @@ +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class PerformanceManager + { + public static long GetRequiredBufferSizeForPerformanceMetricsPerFrame(BehaviorInfo behaviorInfo, AudioRendererParameter parameters) + { + int performanceMetricsDataFormat = behaviorInfo.GetPerformanceMetricsDataFormat(); + + if (performanceMetricsDataFormat == 2) + { + return 24 * (parameters.VoiceCount + + parameters.EffectCount + + parameters.SubMixCount + + parameters.SinkCount + 1) + 0x990; + } + + if (performanceMetricsDataFormat != 1) + { + Logger.PrintWarning(LogClass.ServiceAudio, $"PerformanceMetricsDataFormat: {performanceMetricsDataFormat} is not supported!"); + } + + return (((parameters.VoiceCount + + parameters.EffectCount + + parameters.SubMixCount + + parameters.SinkCount + 1) << 32) >> 0x1C) + 0x658; + } + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs new file mode 100644 index 00000000..e46af443 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs @@ -0,0 +1,25 @@ +using Ryujinx.Common; + +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + class SplitterContext + { + public static long CalcWorkBufferSize(BehaviorInfo behaviorInfo, AudioRendererParameter parameters) + { + if (!behaviorInfo.IsSplitterSupported()) + { + return 0; + } + + long size = parameters.SplitterDestinationDataCount * 0xE0 + + parameters.SplitterCount * 0x20; + + if (!behaviorInfo.IsSplitterBugFixed()) + { + size += BitUtils.AlignUp(4 * parameters.SplitterDestinationDataCount, 16); + } + + return size; + } + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs deleted file mode 100644 index f3b6995c..00000000 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioConsts.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager -{ - static class AudioConsts - { - public const int HostSampleRate = 48000; - public const int HostChannelsCount = 2; - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs new file mode 100644 index 00000000..7e8b89bd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class AudioRendererConsts + { + // Revision Consts + public const int Revision = 7; + public const int Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); + public const int RevMagic = Rev0Magic + (Revision << 24); + + // Misc Consts + public const int BufferAlignment = 0x40; + + // Host Consts + public const int HostSampleRate = 48000; + public const int HostChannelsCount = 2; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs index 9772f786..2cfbc4b7 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs @@ -7,8 +7,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager { public int SampleRate; public int SampleCount; - public int Unknown8; - public int MixCount; + public int MixBufferCount; + public int SubMixCount; public int VoiceCount; public int SinkCount; public int EffectCount; diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs new file mode 100644 index 00000000..a418d89e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager +{ + static class SupportTags + { + public const int Splitter = 2; + public const int SplitterBugFix = 5; + public const int PerformanceMetricsDataFormatVersion2 = 5; + public const int VariadicCommandBufferSize = 5; + public const int ElapsedFrameCount = 5; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs index b1f14984..1c5b2903 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs @@ -12,7 +12,7 @@ public int SinkSize; public int PerformanceManagerSize; public int Unknown24; - public int Unknown28; + public int ElapsedFrameCountInfoSize; public int Unknown2C; public int Unknown30; public int Unknown34; diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs index c9fb8502..4bf15a59 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs @@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager int maxSize = _samples.Length - _offset; - int size = maxSamples * AudioConsts.HostChannelsCount; + int size = maxSamples * AudioRendererConsts.HostChannelsCount; if (size > maxSize) { @@ -96,7 +96,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager Array.Copy(_samples, _offset, output, 0, size); - samplesCount = size / AudioConsts.HostChannelsCount; + samplesCount = size / AudioRendererConsts.HostChannelsCount; _outStatus.PlayedSamplesCount += samplesCount; @@ -140,7 +140,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager { int samplesCount = (int)(wb.Size / (sizeof(short) * ChannelsCount)); - _samples = new int[samplesCount * AudioConsts.HostChannelsCount]; + _samples = new int[samplesCount * AudioRendererConsts.HostChannelsCount]; if (ChannelsCount == 1) { @@ -171,19 +171,19 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager throw new InvalidOperationException(); } - if (SampleRate != AudioConsts.HostSampleRate) + if (SampleRate != AudioRendererConsts.HostSampleRate) { // TODO: We should keep the frames being discarded (see the 4 below) // on a buffer and include it on the next samples buffer, to allow // the resampler to do seamless interpolation between wave buffers. - int samplesCount = _samples.Length / AudioConsts.HostChannelsCount; + int samplesCount = _samples.Length / AudioRendererConsts.HostChannelsCount; samplesCount = Math.Max(samplesCount - 4, 0); _samples = Resampler.Resample2Ch( _samples, SampleRate, - AudioConsts.HostSampleRate, + AudioRendererConsts.HostSampleRate, samplesCount, ref _resamplerFracPart); } |
