diff options
| author | Mary <me@thog.eu> | 2021-02-26 01:11:56 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-26 01:11:56 +0100 |
| commit | f556c80d0230056335632b60c71f1567e177239e (patch) | |
| tree | 748aa6be62b93a8e941e25dbd83f39e1dbb37035 /Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs | |
| parent | 1c49089ff00fc87dc4872f135dc6a0d36169a970 (diff) | |
Haydn: Part 1 (#2007)
* Haydn: Part 1
Based on my reverse of audio 11.0.0.
As always, core implementation under LGPLv3 for the same reasons as for Amadeus.
This place the bases of a more flexible audio system while making audout & audin accurate.
This have the following improvements:
- Complete reimplementation of audout and audin.
- Audin currently only have a dummy backend.
- Dramatically reduce CPU usage by up to 50% in common cases (SoundIO and OpenAL).
- Audio Renderer now can output to 5.1 devices when supported.
- Audio Renderer init its backend on demand instead of keeping two up all the time.
- All backends implementation are now in their own project.
- Ryujinx.Audio.Renderer was renamed Ryujinx.Audio and was refactored because of this.
As a note, games having issues with OpenAL haven't improved and will not
because of OpenAL design (stopping when buffers finish playing causing
possible audio "pops" when buffers are very small).
* Update for latest hexkyz's edits on Switchbrew
* audren: Rollback channel configuration changes
* Address gdkchan's comments
* Fix typo in OpenAL backend driver
* Address last comments
* Fix a nit
* Address gdkchan's comments
Diffstat (limited to 'Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs')
| -rw-r--r-- | Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs | 838 |
1 files changed, 0 insertions, 838 deletions
diff --git a/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs deleted file mode 100644 index 9b87957a..00000000 --- a/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs +++ /dev/null @@ -1,838 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Server.Mix; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Server.Types; -using Ryujinx.Audio.Renderer.Server.Upsampler; -using Ryujinx.Audio.Renderer.Server.Voice; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Buffers; -using System.Diagnostics; -using System.Threading; - -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class AudioRenderSystem : IDisposable - { - private object _lock = new object(); - - private AudioRendererExecutionMode _executionMode; - private IWritableEvent _systemEvent; - private ManualResetEvent _terminationEvent; - private MemoryPoolState _dspMemoryPoolState; - private VoiceContext _voiceContext; - private MixContext _mixContext; - private SinkContext _sinkContext; - private SplitterContext _splitterContext; - private EffectContext _effectContext; - private PerformanceManager _performanceManager; - private UpsamplerManager _upsamplerManager; - private bool _isActive; - private BehaviourContext _behaviourContext; - private ulong _totalElapsedTicksUpdating; - private ulong _totalElapsedTicks; - private int _sessionId; - private Memory<MemoryPoolState> _memoryPools; - - private uint _sampleRate; - private uint _sampleCount; - private uint _mixBufferCount; - private uint _voiceChannelCountMax; - private uint _upsamplerCount; - private uint _memoryPoolCount; - private uint _processHandle; - private ulong _appletResourceId; - - private WritableRegion _workBufferRegion; - private MemoryHandle _workBufferMemoryPin; - - private Memory<float> _mixBuffer; - private Memory<float> _depopBuffer; - - private uint _renderingTimeLimitPercent; - private bool _voiceDropEnabled; - private uint _voiceDropCount; - private bool _isDspRunningBehind; - - private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator; - - private Memory<byte> _performanceBuffer; - - public IVirtualMemoryManager MemoryManager { get; private set; } - - private ulong _elapsedFrameCount; - private ulong _renderingStartTick; - - private AudioRendererManager _manager; - - public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent) - { - _manager = manager; - _terminationEvent = new ManualResetEvent(false); - _dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); - _voiceContext = new VoiceContext(); - _mixContext = new MixContext(); - _sinkContext = new SinkContext(); - _splitterContext = new SplitterContext(); - _effectContext = new EffectContext(); - - _commandProcessingTimeEstimator = null; - _systemEvent = systemEvent; - _behaviourContext = new BehaviourContext(); - - _totalElapsedTicksUpdating = 0; - _sessionId = 0; - } - - public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager) - { - if (!BehaviourContext.CheckValidRevision(parameter.Revision)) - { - return ResultCode.OperationFailed; - } - - if (GetWorkBufferSize(ref parameter) > workBufferSize) - { - return ResultCode.WorkBufferTooSmall; - } - - Debug.Assert(parameter.RenderingDevice == AudioRendererRenderingDevice.Dsp && parameter.ExecutionMode == AudioRendererExecutionMode.Auto); - - Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourContext.GetRevisionNumber(parameter.Revision)}"); - - _behaviourContext.SetUserRevision(parameter.Revision); - - _sampleRate = parameter.SampleRate; - _sampleCount = parameter.SampleCount; - _mixBufferCount = parameter.MixBufferCount; - _voiceChannelCountMax = RendererConstants.VoiceChannelCountMax; - _upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount; - _appletResourceId = appletResourceId; - _memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * RendererConstants.VoiceWaveBufferCount; - _executionMode = parameter.ExecutionMode; - _sessionId = sessionId; - MemoryManager = memoryManager; - - WorkBufferAllocator workBufferAllocator; - - _workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize); - _workBufferRegion.Memory.Span.Fill(0); - _workBufferMemoryPin = _workBufferRegion.Memory.Pin(); - - workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory); - - PoolMapper poolMapper = new PoolMapper(processHandle, false); - poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize); - - _mixBuffer = workBufferAllocator.Allocate<float>(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10); - - if (_mixBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - Memory<float> upSamplerWorkBuffer = workBufferAllocator.Allocate<float>(RendererConstants.TargetSampleCount * (_voiceChannelCountMax + _mixBufferCount) * _upsamplerCount, 0x10); - - if (upSamplerWorkBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _depopBuffer = workBufferAllocator.Allocate<float>((ulong)BitUtils.AlignUp(parameter.MixBufferCount, RendererConstants.BufferAlignment), RendererConstants.BufferAlignment); - - if (_depopBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Invalidate DSP cache on what was currently allocated with workBuffer. - AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset); - - Debug.Assert((workBufferAllocator.Offset % RendererConstants.BufferAlignment) == 0); - - Memory<VoiceState> voices = workBufferAllocator.Allocate<VoiceState>(parameter.VoiceCount, VoiceState.Alignment); - - if (voices.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - foreach (ref VoiceState voice in voices.Span) - { - voice.Initialize(); - } - - // A pain to handle as we can't have VoiceState*, use indices to be a bit more safe - Memory<int> sortedVoices = workBufferAllocator.Allocate<int>(parameter.VoiceCount, 0x10); - - if (sortedVoices.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Clear memory (use -1 as it's an invalid index) - sortedVoices.Span.Fill(-1); - - Memory<VoiceChannelResource> voiceChannelResources = workBufferAllocator.Allocate<VoiceChannelResource>(parameter.VoiceCount, VoiceChannelResource.Alignment); - - if (voiceChannelResources.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - for (uint id = 0; id < voiceChannelResources.Length; id++) - { - ref VoiceChannelResource voiceChannelResource = ref voiceChannelResources.Span[(int)id]; - - voiceChannelResource.Id = id; - voiceChannelResource.IsUsed = false; - } - - Memory<VoiceUpdateState> voiceUpdateStates = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align); - - if (voiceUpdateStates.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - uint mixesCount = parameter.SubMixBufferCount + 1; - - Memory<MixState> mixes = workBufferAllocator.Allocate<MixState>(mixesCount, MixState.Alignment); - - if (mixes.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - if (parameter.EffectCount == 0) - { - foreach (ref MixState mix in mixes.Span) - { - mix = new MixState(Memory<int>.Empty, ref _behaviourContext); - } - } - else - { - Memory<int> effectProcessingOrderArray = workBufferAllocator.Allocate<int>(parameter.EffectCount * mixesCount, 0x10); - - foreach (ref MixState mix in mixes.Span) - { - mix = new MixState(effectProcessingOrderArray.Slice(0, (int)parameter.EffectCount), ref _behaviourContext); - - effectProcessingOrderArray = effectProcessingOrderArray.Slice((int)parameter.EffectCount); - } - } - - // Initialize the final mix id - mixes.Span[0].MixId = RendererConstants.FinalMixId; - - Memory<int> sortedMixesState = workBufferAllocator.Allocate<int>(mixesCount, 0x10); - - if (sortedMixesState.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Clear memory (use -1 as it's an invalid index) - sortedMixesState.Span.Fill(-1); - - Memory<byte> nodeStatesWorkBuffer = Memory<byte>.Empty; - Memory<byte> edgeMatrixWorkBuffer = Memory<byte>.Empty; - - if (_behaviourContext.IsSplitterSupported()) - { - nodeStatesWorkBuffer = workBufferAllocator.Allocate((uint)NodeStates.GetWorkBufferSize((int)mixesCount), 1); - edgeMatrixWorkBuffer = workBufferAllocator.Allocate((uint)EdgeMatrix.GetWorkBufferSize((int)mixesCount), 1); - - if (nodeStatesWorkBuffer.IsEmpty || edgeMatrixWorkBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - } - - _mixContext.Initialize(sortedMixesState, mixes, nodeStatesWorkBuffer, edgeMatrixWorkBuffer); - - _memoryPools = workBufferAllocator.Allocate<MemoryPoolState>(_memoryPoolCount, MemoryPoolState.Alignment); - - if (_memoryPools.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - foreach (ref MemoryPoolState state in _memoryPools.Span) - { - state = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); - } - - if (!_splitterContext.Initialize(ref _behaviourContext, ref parameter, workBufferAllocator)) - { - return ResultCode.WorkBufferTooSmall; - } - - _processHandle = processHandle; - - _upsamplerManager = new UpsamplerManager(upSamplerWorkBuffer, _upsamplerCount); - - _effectContext.Initialize(parameter.EffectCount); - _sinkContext.Initialize(parameter.SinkCount); - - Memory<VoiceUpdateState> voiceUpdateStatesDsp = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align); - - if (voiceUpdateStatesDsp.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _voiceContext.Initialize(sortedVoices, voices, voiceChannelResources, voiceUpdateStates, voiceUpdateStatesDsp, parameter.VoiceCount); - - if (parameter.PerformanceMetricFramesCount > 0) - { - ulong performanceBufferSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref _behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; - - _performanceBuffer = workBufferAllocator.Allocate(performanceBufferSize, RendererConstants.BufferAlignment); - - if (_performanceBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _performanceManager = PerformanceManager.Create(_performanceBuffer, ref parameter, _behaviourContext); - } - else - { - _performanceManager = null; - } - - _totalElapsedTicksUpdating = 0; - _totalElapsedTicks = 0; - _renderingTimeLimitPercent = 100; - _voiceDropEnabled = parameter.VoiceDropEnabled && _executionMode == AudioRendererExecutionMode.Auto; - - AudioProcessorMemoryManager.InvalidateDataCache(workBuffer, workBufferSize); - - _processHandle = processHandle; - _elapsedFrameCount = 0; - - switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion()) - { - case 1: - _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion1(_sampleCount, _mixBufferCount); - break; - case 2: - _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion2(_sampleCount, _mixBufferCount); - break; - case 3: - _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion3(_sampleCount, _mixBufferCount); - break; - default: - throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourContext.GetCommandProcessingTimeEstimatorVersion()}."); - } - - return ResultCode.Success; - } - - public void Start() - { - Logger.Info?.Print(LogClass.AudioRenderer, $"Starting renderer id {_sessionId}"); - - lock (_lock) - { - _elapsedFrameCount = 0; - _isActive = true; - } - } - - public void Stop() - { - Logger.Info?.Print(LogClass.AudioRenderer, $"Stopping renderer id {_sessionId}"); - - lock (_lock) - { - _isActive = false; - } - - if (_executionMode == AudioRendererExecutionMode.Auto) - { - _terminationEvent.WaitOne(); - } - - Logger.Info?.Print(LogClass.AudioRenderer, $"Stopped renderer id {_sessionId}"); - } - - public ResultCode Update(Memory<byte> output, Memory<byte> performanceOutput, ReadOnlyMemory<byte> input) - { - lock (_lock) - { - ulong updateStartTicks = GetSystemTicks(); - - output.Span.Fill(0); - - StateUpdater stateUpdater = new StateUpdater(input, output, _processHandle, _behaviourContext); - - ResultCode result; - - result = stateUpdater.UpdateBehaviourContext(); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateMemoryPools(_memoryPools.Span); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateVoiceChannelResources(_voiceContext); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateVoices(_voiceContext, _memoryPools); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateEffects(_effectContext, _isActive, _memoryPools); - - if (result != ResultCode.Success) - { - return result; - } - - if (_behaviourContext.IsSplitterSupported()) - { - result = stateUpdater.UpdateSplitter(_splitterContext); - - if (result != ResultCode.Success) - { - return result; - } - } - - result = stateUpdater.UpdateMixes(_mixContext, GetMixBufferCount(), _effectContext, _splitterContext); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateSinks(_sinkContext, _memoryPools); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdatePerformanceBuffer(_performanceManager, performanceOutput.Span); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateErrorInfo(); - - if (result != ResultCode.Success) - { - return result; - } - - if (_behaviourContext.IsElapsedFrameCountSupported()) - { - result = stateUpdater.UpdateRendererInfo(_elapsedFrameCount); - - if (result != ResultCode.Success) - { - return result; - } - } - - result = stateUpdater.CheckConsumedSize(); - - if (result != ResultCode.Success) - { - return result; - } - - _systemEvent.Clear(); - - ulong updateEndTicks = GetSystemTicks(); - - _totalElapsedTicksUpdating += (updateEndTicks - updateStartTicks); - - return result; - } - } - - private ulong GetSystemTicks() - { - double ticks = ARMeilleure.State.ExecutionContext.ElapsedTicks * ARMeilleure.State.ExecutionContext.TickFrequency; - - return (ulong)(ticks * RendererConstants.TargetTimerFrequency); - } - - private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp) - { - int i; - - for (i = 0; i < commandBuffer.CommandList.Commands.Count; i++) - { - ICommand command = commandBuffer.CommandList.Commands[i]; - - CommandType commandType = command.CommandType; - - if (commandType == CommandType.AdpcmDataSourceVersion1 || - commandType == CommandType.AdpcmDataSourceVersion2 || - commandType == CommandType.PcmInt16DataSourceVersion1 || - commandType == CommandType.PcmInt16DataSourceVersion2 || - commandType == CommandType.PcmFloatDataSourceVersion1 || - commandType == CommandType.PcmFloatDataSourceVersion2 || - commandType == CommandType.Performance) - { - break; - } - } - - uint voiceDropped = 0; - - for (; i < commandBuffer.CommandList.Commands.Count; i++) - { - ICommand targetCommand = commandBuffer.CommandList.Commands[i]; - - int targetNodeId = targetCommand.NodeId; - - if (voicesEstimatedTime <= deltaTimeDsp || NodeIdHelper.GetType(targetNodeId) != NodeIdType.Voice) - { - break; - } - - ref VoiceState voice = ref _voiceContext.GetState(NodeIdHelper.GetBase(targetNodeId)); - - if (voice.Priority == RendererConstants.VoiceHighestPriority) - { - break; - } - - // We can safely drop this voice, disable all associated commands while activating depop preparation commands. - voiceDropped++; - voice.VoiceDropFlag = true; - - Logger.Warning?.Print(LogClass.AudioRenderer, $"Dropping voice {voice.NodeId}"); - - for (; i < commandBuffer.CommandList.Commands.Count; i++) - { - ICommand command = commandBuffer.CommandList.Commands[i]; - - if (command.NodeId != targetNodeId) - { - break; - } - - if (command.CommandType == CommandType.DepopPrepare) - { - command.Enabled = true; - } - else if (command.CommandType == CommandType.Performance || !command.Enabled) - { - continue; - } - else - { - command.Enabled = false; - - voicesEstimatedTime -= (long)command.EstimatedProcessingTime; - } - } - } - - return voiceDropped; - } - - private void GenerateCommandList(out CommandList commandList) - { - Debug.Assert(_executionMode == AudioRendererExecutionMode.Auto); - - PoolMapper.ClearUsageState(_memoryPools); - - ulong startTicks = GetSystemTicks(); - - commandList = new CommandList(this); - - if (_performanceManager != null) - { - _performanceManager.TapFrame(_isDspRunningBehind, _voiceDropCount, _renderingStartTick); - - _isDspRunningBehind = false; - _voiceDropCount = 0; - _renderingStartTick = 0; - } - - CommandBuffer commandBuffer = new CommandBuffer(commandList, _commandProcessingTimeEstimator); - - CommandGenerator commandGenerator = new CommandGenerator(commandBuffer, GetContext(), _voiceContext, _mixContext, _effectContext, _sinkContext, _splitterContext, _performanceManager); - - _voiceContext.Sort(); - commandGenerator.GenerateVoices(); - - long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime; - - commandGenerator.GenerateSubMixes(); - commandGenerator.GenerateFinalMixes(); - commandGenerator.GenerateSinks(); - - long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime; - - if (_voiceDropEnabled) - { - long maxDspTime = GetMaxAllocatedTimeForDsp(); - - long restEstimateTime = totalEstimatedTime - voicesEstimatedTime; - - long deltaTimeDsp = Math.Max(maxDspTime - restEstimateTime, 0); - - _voiceDropCount = ComputeVoiceDrop(commandBuffer, voicesEstimatedTime, deltaTimeDsp); - } - - _voiceContext.UpdateForCommandGeneration(); - - ulong endTicks = GetSystemTicks(); - - _totalElapsedTicks = endTicks - startTicks; - - _renderingStartTick = GetSystemTicks(); - _elapsedFrameCount++; - } - - private int GetMaxAllocatedTimeForDsp() - { - return (int)(RendererConstants.AudioProcessorMaxUpdateTimePerSessions * _behaviourContext.GetAudioRendererProcessingTimeLimit() * (GetRenderingTimeLimit() / 100.0f)); - } - - public void SendCommands() - { - lock (_lock) - { - if (_isActive) - { - _terminationEvent.Reset(); - - GenerateCommandList(out CommandList commands); - - _manager.Processor.Send(_sessionId, - commands, - GetMaxAllocatedTimeForDsp(), - _appletResourceId); - - _systemEvent.Signal(); - } - else - { - _terminationEvent.Set(); - } - } - } - - public uint GetMixBufferCount() - { - return _mixBufferCount; - } - - public void SetRenderingTimeLimitPercent(uint percent) - { - Debug.Assert(percent <= 100); - - _renderingTimeLimitPercent = percent; - } - - public uint GetRenderingTimeLimit() - { - return _renderingTimeLimitPercent; - } - - public Memory<float> GetMixBuffer() - { - return _mixBuffer; - } - - public uint GetSampleCount() - { - return _sampleCount; - } - - public uint GetSampleRate() - { - return _sampleRate; - } - - public uint GetVoiceChannelCountMax() - { - return _voiceChannelCountMax; - } - - public bool IsActive() - { - return _isActive; - } - - private RendererSystemContext GetContext() - { - return new RendererSystemContext - { - ChannelCount = _manager.OutputDevices[_sessionId].GetChannelCount(), - BehaviourContext = _behaviourContext, - DepopBuffer = _depopBuffer, - MixBufferCount = GetMixBufferCount(), - SessionId = _sessionId, - UpsamplerManager = _upsamplerManager - }; - } - - public int GetSessionId() - { - return _sessionId; - } - - public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) - { - BehaviourContext behaviourContext = new BehaviourContext(); - - behaviourContext.SetUserRevision(parameter.Revision); - - uint mixesCount = parameter.SubMixBufferCount + 1; - - uint memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * RendererConstants.VoiceWaveBufferCount; - - ulong size = 0; - - // Mix Buffers - size = WorkBufferAllocator.GetTargetSize<float>(size, parameter.SampleCount * (RendererConstants.VoiceChannelCountMax + parameter.MixBufferCount), 0x10); - - // Upsampler workbuffer - size = WorkBufferAllocator.GetTargetSize<float>(size, RendererConstants.TargetSampleCount * (RendererConstants.VoiceChannelCountMax + parameter.MixBufferCount) * (parameter.SinkCount + parameter.SubMixBufferCount), 0x10); - - // Depop buffer - size = WorkBufferAllocator.GetTargetSize<float>(size, (ulong)BitUtils.AlignUp(parameter.MixBufferCount, RendererConstants.BufferAlignment), RendererConstants.BufferAlignment); - - // Voice - size = WorkBufferAllocator.GetTargetSize<VoiceState>(size, parameter.VoiceCount, VoiceState.Alignment); - size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.VoiceCount, 0x10); - size = WorkBufferAllocator.GetTargetSize<VoiceChannelResource>(size, parameter.VoiceCount, VoiceChannelResource.Alignment); - size = WorkBufferAllocator.GetTargetSize<VoiceUpdateState>(size, parameter.VoiceCount, VoiceUpdateState.Align); - - // Mix - size = WorkBufferAllocator.GetTargetSize<MixState>(size, mixesCount, MixState.Alignment); - size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.EffectCount * mixesCount, 0x10); - size = WorkBufferAllocator.GetTargetSize<int>(size, mixesCount, 0x10); - - if (behaviourContext.IsSplitterSupported()) - { - size += (ulong)BitUtils.AlignUp(NodeStates.GetWorkBufferSize((int)mixesCount) + EdgeMatrix.GetWorkBufferSize((int)mixesCount), 0x10); - } - - // Memory Pool - size = WorkBufferAllocator.GetTargetSize<MemoryPoolState>(size, memoryPoolCount, MemoryPoolState.Alignment); - - // Splitter - size = SplitterContext.GetWorkBufferSize(size, ref behaviourContext, ref parameter); - - // DSP Voice - size = WorkBufferAllocator.GetTargetSize<VoiceUpdateState>(size, parameter.VoiceCount, VoiceUpdateState.Align); - - // Performance - if (parameter.PerformanceMetricFramesCount > 0) - { - ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; - - size += BitUtils.AlignUp(performanceMetricsPerFramesSize, RendererConstants.PerformanceMetricsPerFramesSizeAlignment); - } - - return BitUtils.AlignUp(size, RendererConstants.WorkBufferAlignment); - } - - public ResultCode QuerySystemEvent(out IWritableEvent systemEvent) - { - systemEvent = default; - - if (_executionMode == AudioRendererExecutionMode.Manual) - { - return ResultCode.UnsupportedOperation; - } - - systemEvent = _systemEvent; - - return ResultCode.Success; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (_isActive) - { - Stop(); - } - - PoolMapper mapper = new PoolMapper(_processHandle, false); - mapper.Unmap(ref _dspMemoryPoolState); - - PoolMapper.ClearUsageState(_memoryPools); - - for (int i = 0; i < _memoryPoolCount; i++) - { - ref MemoryPoolState memoryPool = ref _memoryPools.Span[i]; - - if (memoryPool.IsMapped()) - { - mapper.Unmap(ref memoryPool); - } - } - - _manager.Unregister(this); - _terminationEvent.Dispose(); - _workBufferMemoryPin.Dispose(); - _workBufferRegion.Dispose(); - } - } - } -} |
