From f556c80d0230056335632b60c71f1567e177239e Mon Sep 17 00:00:00 2001 From: Mary Date: Fri, 26 Feb 2021 01:11:56 +0100 Subject: 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 --- Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs | 838 ------------------ .../Server/AudioRendererManager.cs | 341 -------- Ryujinx.Audio.Renderer/Server/BehaviourContext.cs | 405 --------- Ryujinx.Audio.Renderer/Server/CommandBuffer.cs | 484 ----------- Ryujinx.Audio.Renderer/Server/CommandGenerator.cs | 940 --------------------- .../CommandProcessingTimeEstimatorVersion1.cs | 180 ---- .../CommandProcessingTimeEstimatorVersion2.cs | 544 ------------ .../CommandProcessingTimeEstimatorVersion3.cs | 635 -------------- .../Server/Effect/AuxiliaryBufferEffect.cs | 92 -- Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs | 257 ------ .../Server/Effect/BiquadFilterEffect.cs | 74 -- .../Server/Effect/BufferMixEffect.cs | 56 -- .../Server/Effect/DelayEffect.cs | 100 --- .../Server/Effect/EffectContext.cs | 82 -- .../Server/Effect/Reverb3dEffect.cs | 99 --- .../Server/Effect/ReverbEffect.cs | 102 --- Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs | 45 - .../Server/ICommandProcessingTimeEstimator.cs | 52 -- .../Server/MemoryPool/AddressInfo.cs | 151 ---- .../Server/MemoryPool/MemoryPoolState.cs | 148 ---- .../Server/MemoryPool/PoolMapper.cs | 383 --------- Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs | 276 ------ Ryujinx.Audio.Renderer/Server/Mix/MixState.cs | 330 -------- .../Server/Performance/IPerformanceDetailEntry.cs | 69 -- .../Server/Performance/IPerformanceEntry.cs | 63 -- .../Server/Performance/IPerformanceHeader.cs | 97 --- .../Performance/PerformanceDetailVersion1.cs | 89 -- .../Performance/PerformanceDetailVersion2.cs | 89 -- .../Performance/PerformanceEntryAddresses.cs | 73 -- .../Server/Performance/PerformanceEntryVersion1.cs | 79 -- .../Server/Performance/PerformanceEntryVersion2.cs | 79 -- .../Performance/PerformanceFrameHeaderVersion1.cs | 118 --- .../Performance/PerformanceFrameHeaderVersion2.cs | 134 --- .../Server/Performance/PerformanceManager.cs | 124 --- .../Performance/PerformanceManagerGeneric.cs | 311 ------- .../Server/RendererSystemContext.cs | 65 -- Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs | 119 --- .../Server/Sink/CircularBufferSink.cs | 126 --- Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs | 92 -- Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs | 73 -- .../Server/Splitter/SplitterContext.cs | 320 ------- .../Server/Splitter/SplitterDestination.cs | 210 ----- .../Server/Splitter/SplitterState.cs | 237 ------ Ryujinx.Audio.Renderer/Server/StateUpdater.cs | 575 ------------- .../Server/Types/AudioRendererExecutionMode.cs | 36 - .../Server/Types/AudioRendererRenderingDevice.cs | 41 - Ryujinx.Audio.Renderer/Server/Types/PlayState.cs | 56 -- .../Server/Upsampler/UpsamplerManager.cs | 101 --- .../Server/Upsampler/UpsamplerState.cs | 80 -- .../Server/Voice/VoiceChannelResource.cs | 57 -- .../Server/Voice/VoiceContext.cs | 166 ---- Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs | 715 ---------------- Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs | 121 --- 53 files changed, 11129 deletions(-) delete mode 100644 Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/BehaviourContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/CommandBuffer.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/CommandGenerator.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Mix/MixState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/StateUpdater.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Types/PlayState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs delete mode 100644 Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs (limited to 'Ryujinx.Audio.Renderer/Server') 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 . -// - -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 _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 _mixBuffer; - private Memory _depopBuffer; - - private uint _renderingTimeLimitPercent; - private bool _voiceDropEnabled; - private uint _voiceDropCount; - private bool _isDspRunningBehind; - - private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator; - - private Memory _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(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10); - - if (_mixBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - Memory upSamplerWorkBuffer = workBufferAllocator.Allocate(RendererConstants.TargetSampleCount * (_voiceChannelCountMax + _mixBufferCount) * _upsamplerCount, 0x10); - - if (upSamplerWorkBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _depopBuffer = workBufferAllocator.Allocate((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 voices = workBufferAllocator.Allocate(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 sortedVoices = workBufferAllocator.Allocate(parameter.VoiceCount, 0x10); - - if (sortedVoices.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Clear memory (use -1 as it's an invalid index) - sortedVoices.Span.Fill(-1); - - Memory voiceChannelResources = workBufferAllocator.Allocate(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 voiceUpdateStates = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceUpdateState.Align); - - if (voiceUpdateStates.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - uint mixesCount = parameter.SubMixBufferCount + 1; - - Memory mixes = workBufferAllocator.Allocate(mixesCount, MixState.Alignment); - - if (mixes.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - if (parameter.EffectCount == 0) - { - foreach (ref MixState mix in mixes.Span) - { - mix = new MixState(Memory.Empty, ref _behaviourContext); - } - } - else - { - Memory effectProcessingOrderArray = workBufferAllocator.Allocate(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 sortedMixesState = workBufferAllocator.Allocate(mixesCount, 0x10); - - if (sortedMixesState.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Clear memory (use -1 as it's an invalid index) - sortedMixesState.Span.Fill(-1); - - Memory nodeStatesWorkBuffer = Memory.Empty; - Memory edgeMatrixWorkBuffer = Memory.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(_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 voiceUpdateStatesDsp = workBufferAllocator.Allocate(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 output, Memory performanceOutput, ReadOnlyMemory 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 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(size, parameter.SampleCount * (RendererConstants.VoiceChannelCountMax + parameter.MixBufferCount), 0x10); - - // Upsampler workbuffer - size = WorkBufferAllocator.GetTargetSize(size, RendererConstants.TargetSampleCount * (RendererConstants.VoiceChannelCountMax + parameter.MixBufferCount) * (parameter.SinkCount + parameter.SubMixBufferCount), 0x10); - - // Depop buffer - size = WorkBufferAllocator.GetTargetSize(size, (ulong)BitUtils.AlignUp(parameter.MixBufferCount, RendererConstants.BufferAlignment), RendererConstants.BufferAlignment); - - // Voice - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceState.Alignment); - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, 0x10); - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceChannelResource.Alignment); - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceUpdateState.Align); - - // Mix - size = WorkBufferAllocator.GetTargetSize(size, mixesCount, MixState.Alignment); - size = WorkBufferAllocator.GetTargetSize(size, parameter.EffectCount * mixesCount, 0x10); - size = WorkBufferAllocator.GetTargetSize(size, mixesCount, 0x10); - - if (behaviourContext.IsSplitterSupported()) - { - size += (ulong)BitUtils.AlignUp(NodeStates.GetWorkBufferSize((int)mixesCount) + EdgeMatrix.GetWorkBufferSize((int)mixesCount), 0x10); - } - - // Memory Pool - size = WorkBufferAllocator.GetTargetSize(size, memoryPoolCount, MemoryPoolState.Alignment); - - // Splitter - size = SplitterContext.GetWorkBufferSize(size, ref behaviourContext, ref parameter); - - // DSP Voice - size = WorkBufferAllocator.GetTargetSize(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(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs deleted file mode 100644 index f552935b..00000000 --- a/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs +++ /dev/null @@ -1,341 +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 . -// - -using Ryujinx.Audio.Renderer.Dsp; -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Diagnostics; -using System.Threading; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// The audio renderer manager. - /// - public class AudioRendererManager : IDisposable - { - /// - /// Lock used for session allocation. - /// - private object _sessionLock = new object(); - - /// - /// Lock used to control the running state. - /// - private object _audioProcessorLock = new object(); - - /// - /// The session ids allocation table. - /// - private int[] _sessionIds; - - /// - /// The events linked to each session. - /// - private IWritableEvent[] _sessionsSystemEvent; - - /// - /// The sessions instances. - /// - private AudioRenderSystem[] _sessions; - - /// - /// The count of active sessions. - /// - private int _activeSessionCount; - - /// - /// The worker thread used to run . - /// - private Thread _workerThread; - - /// - /// Indicate if the worker thread and are running. - /// - private bool _isRunning; - - /// - /// The output devices associated to each session. - /// - // TODO: get ride of this with the audout rewrite. - public HardwareDevice[] OutputDevices { get; private set; } - - /// - /// The instance associated to this manager. - /// - public AudioProcessor Processor { get; } - - /// - /// Create a new . - /// - public AudioRendererManager() - { - Processor = new AudioProcessor(); - _sessionIds = new int[RendererConstants.AudioRendererSessionCountMax]; - _sessions = new AudioRenderSystem[RendererConstants.AudioRendererSessionCountMax]; - _activeSessionCount = 0; - - for (int i = 0; i < _sessionIds.Length; i++) - { - _sessionIds[i] = i; - } - } - - /// - /// Initialize the . - /// - /// The events associated to each session. - /// The output devices associated to each session. - public void Initialize(IWritableEvent[] sessionSystemEvents, HardwareDevice[] devices) - { - _sessionsSystemEvent = sessionSystemEvents; - OutputDevices = devices; - } - - /// - /// Get the work buffer size required by a session. - /// - /// The user configuration - /// The work buffer size required by a session. - public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) - { - return AudioRenderSystem.GetWorkBufferSize(ref parameter); - } - - /// - /// Acquire a new session id. - /// - /// A new session id. - private int AcquireSessionId() - { - lock (_sessionLock) - { - int index = _activeSessionCount; - - Debug.Assert(index < _sessionIds.Length); - - int sessionId = _sessionIds[index]; - - _sessionIds[index] = -1; - - _activeSessionCount++; - - Logger.Info?.Print(LogClass.AudioRenderer, $"Registered new renderer ({sessionId})"); - - return sessionId; - } - } - - /// - /// Release a given . - /// - /// The session id to release. - private void ReleaseSessionId(int sessionId) - { - lock (_sessionLock) - { - Debug.Assert(_activeSessionCount > 0); - - int newIndex = --_activeSessionCount; - - _sessionIds[newIndex] = sessionId; - } - - Logger.Info?.Print(LogClass.AudioRenderer, $"Unregistered renderer ({sessionId})"); - } - - /// - /// Check if there is any audio renderer active. - /// - /// Returns true if there is any audio renderer active. - private bool HasAnyActiveRendererLocked() - { - foreach (AudioRenderSystem renderer in _sessions) - { - if (renderer != null) - { - return true; - } - } - - return false; - } - - /// - /// Start the and worker thread. - /// - private void StartLocked() - { - _isRunning = true; - - // TODO: virtual device mapping (IAudioDevice) - Processor.SetOutputDevices(OutputDevices); - Processor.Start(); - - _workerThread = new Thread(SendCommands) - { - Name = "AudioRendererManager.Worker" - }; - - _workerThread.Start(); - } - - /// - /// Stop the and worker thread. - /// - private void StopLocked() - { - _isRunning = false; - - _workerThread.Join(); - Processor.Stop(); - - Logger.Info?.Print(LogClass.AudioRenderer, "Stopped audio renderer"); - } - - /// - /// Worker main function. This is used to dispatch audio renderer commands to the . - /// - private void SendCommands() - { - Logger.Info?.Print(LogClass.AudioRenderer, "Starting audio renderer"); - Processor.Wait(); - - while (_isRunning) - { - lock (_sessionLock) - { - foreach(AudioRenderSystem renderer in _sessions) - { - renderer?.SendCommands(); - } - } - - Processor.Signal(); - Processor.Wait(); - } - } - - /// - /// Register a new . - /// - /// The to register. - private void Register(AudioRenderSystem renderer) - { - lock (_sessionLock) - { - _sessions[renderer.GetSessionId()] = renderer; - } - - lock (_audioProcessorLock) - { - if (!_isRunning) - { - StartLocked(); - } - } - } - - /// - /// Unregister a new . - /// - /// The to unregister. - internal void Unregister(AudioRenderSystem renderer) - { - lock (_sessionLock) - { - int sessionId = renderer.GetSessionId(); - - _sessions[renderer.GetSessionId()] = null; - - ReleaseSessionId(sessionId); - } - - lock (_audioProcessorLock) - { - if (_isRunning && !HasAnyActiveRendererLocked()) - { - StopLocked(); - } - } - } - - /// - /// Open a new - /// - /// The new - /// The memory manager that will be used for all guest memory operations. - /// The user configuration - /// The applet resource user id of the application. - /// The guest work buffer address. - /// The guest work buffer size. - /// The process handle of the application. - /// A reporting an error or a success. - public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle) - { - int sessionId = AcquireSessionId(); - - AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]); - - ResultCode result = audioRenderer.Initialize(ref parameter, processHandle, workBufferAddress, workBufferSize, sessionId, appletResourceUserId, memoryManager); - - if (result == ResultCode.Success) - { - renderer = audioRenderer; - - Register(renderer); - } - else - { - ReleaseSessionId(sessionId); - - renderer = null; - } - - return result; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - lock (_audioProcessorLock) - { - if (_isRunning) - { - StopLocked(); - } - } - - Processor.Dispose(); - - foreach (HardwareDevice device in OutputDevices) - { - device.Dispose(); - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/BehaviourContext.cs b/Ryujinx.Audio.Renderer/Server/BehaviourContext.cs deleted file mode 100644 index 28bcdac5..00000000 --- a/Ryujinx.Audio.Renderer/Server/BehaviourContext.cs +++ /dev/null @@ -1,405 +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 . -// - -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// Behaviour context. - /// - /// This handles features based on the audio renderer revision provided by the user. - public class BehaviourContext - { - /// - /// The base magic of the Audio Renderer revision. - /// - public const int BaseRevisionMagic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); - - /// - /// REV1: first revision. - /// - public const int Revision1 = 1 << 24; - - /// - /// REV2: Added support for splitter and fix GC-ADPCM context not being provided to the DSP. - /// - /// This was added in system update 2.0.0 - public const int Revision2 = 2 << 24; - - /// - /// REV3: Incremented the max pre-delay from 150 to 350 for the reverb command and removed the (unused) codec system. - /// - /// This was added in system update 3.0.0 - public const int Revision3 = 3 << 24; - - /// - /// REV4: Added USB audio device support and incremented the rendering limit percent to 75%. - /// - /// This was added in system update 4.0.0 - public const int Revision4 = 4 << 24; - - /// - /// REV5: , were added to voice. - /// A new performance frame format (version 2) was added with support for more information about DSP timing. - /// was added to supply the count of update done sent to the DSP. - /// A new version of the command estimator was added to address timing changes caused by the voice changes. - /// Additionally, the rendering limit percent was incremented to 80%. - /// - /// - /// This was added in system update 6.0.0 - public const int Revision5 = 5 << 24; - - /// - /// REV6: This fixed a bug in the biquad filter command not clearing up with usage state. - /// - /// This was added in system update 6.1.0 - public const int Revision6 = 6 << 24; - - /// - /// REV7: Client side (finally) doesn't send all the mix client state to the server and can do partial updates. - /// - /// This was added in system update 8.0.0 - public const int Revision7 = 7 << 24; - - /// - /// REV8: - /// Wavebuffer was changed to support more control over loop (you can now specify where to start and end a loop, and how many times to loop). - /// was added (see for more info). - /// Final leftovers of the codec system were removed. - /// support was added. - /// A new version of the command estimator was added to address timing changes caused by the voice and command changes. - /// - /// This was added in system update 9.0.0 - public const int Revision8 = 8 << 24; - - /// - /// Last revision supported by the implementation. - /// - public const int LastRevision = Revision8; - - /// - /// Target revision magic supported by the implementation. - /// - public const int ProcessRevision = BaseRevisionMagic + LastRevision; - - /// - /// Get the revision number from the revision magic. - /// - /// The revision magic. - /// The revision number. - public static int GetRevisionNumber(int revision) => (revision - BaseRevisionMagic) >> 24; - - /// - /// Current active revision. - /// - public int UserRevision { get; private set; } - - /// - /// Error storage. - /// - private ErrorInfo[] _errorInfos; - - /// - /// Current position in the array. - /// - private uint _errorIndex; - - /// - /// Current flags of the . - /// - private ulong _flags; - - /// - /// Create a new instance of . - /// - public BehaviourContext() - { - UserRevision = 0; - _errorInfos = new ErrorInfo[RendererConstants.MaxErrorInfos]; - _errorIndex = 0; - } - - /// - /// Set the active revision. - /// - /// The active revision. - public void SetUserRevision(int userRevision) - { - UserRevision = userRevision; - } - - /// - /// Update flags of the . - /// - /// The new flags. - public void UpdateFlags(ulong flags) - { - _flags = flags; - } - - /// - /// Check if a given revision is valid/supported. - /// - /// The revision magic to check. - /// Returns true if the given revision is valid/supported - public static bool CheckValidRevision(int revision) - { - return GetRevisionNumber(revision) <= GetRevisionNumber(ProcessRevision); - } - - /// - /// Check if the given revision is greater than or equal the supported revision. - /// - /// The revision magic to check. - /// The revision magic of the supported revision. - /// Returns true if the given revision is greater than or equal the supported revision. - public static bool CheckFeatureSupported(int revision, int supportedRevision) - { - int revA = GetRevisionNumber(revision); - int revB = GetRevisionNumber(supportedRevision); - - if (revA > LastRevision) - { - revA = 1; - } - - if (revB > LastRevision) - { - revB = 1; - } - - return revA >= revB; - } - - /// - /// Check if the memory pool mapping bypass flag is active. - /// - /// True if the memory pool mapping bypass flag is active. - public bool IsMemoryPoolForceMappingEnabled() - { - return (_flags & 1) != 0; - } - - /// - /// Check if the audio renderer should fix the GC-ADPCM context not being provided to the DSP. - /// - /// True if if the audio renderer should fix it. - public bool IsAdpcmLoopContextBugFixed() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision2); - } - - /// - /// Check if the audio renderer should accept splitters. - /// - /// True if the audio renderer should accept splitters. - public bool IsSplitterSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision2); - } - - /// - /// Check if the audio renderer should use a max pre-delay of 350 instead of 150. - /// - /// True if the max pre-delay must be 350. - public bool IsLongSizePreDelaySupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision3); - } - - /// - /// Check if the audio renderer should expose USB audio device. - /// - /// True if the audio renderer should expose USB audio device. - public bool IsAudioUsbDeviceOutputSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision4); - } - - /// - /// Get the percentage allocated to the audio renderer on the DSP for processing. - /// - /// The percentage allocated to the audio renderer on the DSP for processing. - public float GetAudioRendererProcessingTimeLimit() - { - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5)) - { - return 0.80f; - } - else if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision4)) - { - return 0.75f; - } - - return 0.70f; - } - - /// - /// Check if the audio render should support voice flushing. - /// - /// True if the audio render should support voice flushing. - public bool IsFlushVoiceWaveBuffersSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// - /// Check if the audio renderer should trust the user destination count in . - /// - /// True if the audio renderer should trust the user destination count. - public bool IsSplitterBugFixed() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// - /// Check if the audio renderer should supply the elapsed frame count to the user when updating. - /// - /// True if the audio renderer should supply the elapsed frame count to the user when updating. - public bool IsElapsedFrameCountSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// - /// Get the performance metric data format version. - /// - /// The performance metric data format version. - public uint GetPerformanceMetricsDataFormat() - { - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5)) - { - return 2; - } - else - { - return 1; - } - } - - /// - /// Check if the audio renderer should support . - /// - /// True if the audio renderer should support . - public bool IsDecodingBehaviourFlagSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// - /// Check if the audio renderer should fix the biquad filter command not clearing up with usage state. - /// - /// True if the biquad filter state should be cleared. - public bool IsBiquadFilterEffectStateClearBugFixed() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision6); - } - - /// - /// Check if the audio renderer should accept partial mix updates. - /// - /// True if the audio renderer should accept partial mix updates. - public bool IsMixInParameterDirtyOnlyUpdateSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision7); - } - - /// - /// Check if the audio renderer should use the new wavebuffer format. - /// - /// True if the audio renderer should use the new wavebuffer format. - public bool IsWaveBufferVersion2Supported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision8); - } - - /// - /// Get the version of the . - /// - /// The version of the . - public int GetCommandProcessingTimeEstimatorVersion() - { - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision8)) - { - return 3; - } - - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5)) - { - return 2; - } - - return 1; - } - - /// - /// Append a new to the error array. - /// - /// The new to add. - public void AppendError(ref ErrorInfo errorInfo) - { - Debug.Assert(errorInfo.ErrorCode == ResultCode.Success); - - if (_errorIndex <= RendererConstants.MaxErrorInfos - 1) - { - _errorInfos[_errorIndex++] = errorInfo; - } - } - - /// - /// Copy the internal array to the given and output the count copied. - /// - /// The output . - /// The output error count containing the count of copied. - public void CopyErrorInfo(Span errorInfos, out uint errorCount) - { - if (errorInfos.Length != RendererConstants.MaxErrorInfos) - { - throw new ArgumentException("Invalid size of errorInfos span!"); - } - - errorCount = Math.Min(_errorIndex, RendererConstants.MaxErrorInfos); - - for (int i = 0; i < RendererConstants.MaxErrorInfos; i++) - { - if (i < errorCount) - { - errorInfos[i] = _errorInfos[i]; - } - else - { - errorInfos[i] = new ErrorInfo - { - ErrorCode = 0, - ExtraErrorInfo = 0 - }; - } - } - } - - /// - /// Clear the array. - /// - public void ClearError() - { - _errorIndex = 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandBuffer.cs b/Ryujinx.Audio.Renderer/Server/CommandBuffer.cs deleted file mode 100644 index ca37e090..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandBuffer.cs +++ /dev/null @@ -1,484 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Upsampler; -using Ryujinx.Audio.Renderer.Server.Voice; -using System; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// An API to generate commands and aggregate them into a . - /// - public class CommandBuffer - { - /// - /// The command processing time estimator in use. - /// - private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator; - - /// - /// The estimated total processing time. - /// - public ulong EstimatedProcessingTime { get; set; } - - /// - /// The command list that is populated by the . - /// - public CommandList CommandList { get; } - - /// - /// Create a new . - /// - /// The command list that will store the generated commands. - /// The command processing time estimator to use. - public CommandBuffer(CommandList commandList, ICommandProcessingTimeEstimator commandProcessingTimeEstimator) - { - CommandList = commandList; - EstimatedProcessingTime = 0; - _commandProcessingTimeEstimator = commandProcessingTimeEstimator; - } - - /// - /// Add a new generated command to the . - /// - /// The command to add. - private void AddCommand(ICommand command) - { - EstimatedProcessingTime += command.EstimatedProcessingTime; - - CommandList.AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The node id associated to this command. - public void GenerateClearMixBuffer(int nodeId) - { - ClearMixBufferCommand command = new ClearMixBufferCommand(nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The voice state associated. - /// The depop buffer. - /// The buffer count. - /// The target buffer offset. - /// The node id associated to this command. - /// Set to true if the voice was playing previously. - public void GenerateDepopPrepare(Memory state, Memory depopBuffer, uint bufferCount, uint bufferOffset, int nodeId, bool wasPlaying) - { - DepopPrepareCommand command = new DepopPrepareCommand(state, depopBuffer, bufferCount, bufferOffset, nodeId, wasPlaying); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The . - /// The performance operation to perform. - /// The node id associated to this command. - public void GeneratePerformance(ref PerformanceEntryAddresses performanceEntryAddresses, PerformanceCommand.Type type, int nodeId) - { - PerformanceCommand command = new PerformanceCommand(ref performanceEntryAddresses, type, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The previous volume. - /// The new volume. - /// The index of the mix buffer to use. - /// The node id associated to this command. - public void GenerateVolumeRamp(float previousVolume, float volume, uint bufferIndex, int nodeId) - { - VolumeRampCommand command = new VolumeRampCommand(previousVolume, volume, bufferIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The to generate the command from. - /// The to generate the command from. - /// The output buffer index to use. - /// The target channel index. - /// The node id associated to this command. - public void GenerateDataSourceVersion2(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - DataSourceVersion2Command command = new DataSourceVersion2Command(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The to generate the command from. - /// The to generate the command from. - /// The output buffer index to use. - /// The target channel index. - /// The node id associated to this command. - public void GeneratePcmInt16DataSourceVersion1(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - PcmInt16DataSourceCommandVersion1 command = new PcmInt16DataSourceCommandVersion1(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The to generate the command from. - /// The to generate the command from. - /// The output buffer index to use. - /// The target channel index. - /// The node id associated to this command. - public void GeneratePcmFloatDataSourceVersion1(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - PcmFloatDataSourceCommandVersion1 command = new PcmFloatDataSourceCommandVersion1(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The to generate the command from. - /// The to generate the command from. - /// The output buffer index to use. - /// The node id associated to this command. - public void GenerateAdpcmDataSourceVersion1(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, int nodeId) - { - AdpcmDataSourceCommandVersion1 command = new AdpcmDataSourceCommandVersion1(ref voiceState, state, outputBufferIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The base index of the input and output buffer. - /// The biquad filter parameter. - /// The biquad state. - /// The input buffer offset. - /// The output buffer offset. - /// Set to true if the biquad filter state needs to be initialized. - /// The node id associated to this command. - public void GenerateBiquadFilter(int baseIndex, ref BiquadFilterParameter filter, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) - { - BiquadFilterCommand command = new BiquadFilterCommand(baseIndex, ref filter, biquadFilterStateMemory, inputBufferOffset, outputBufferOffset, needInitialization, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The mix buffer count. - /// The base input index. - /// The base output index. - /// The previous volume. - /// The new volume. - /// The to generate the command from. - /// The node id associated to this command. - public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, Span previousVolume, Span volume, Memory state, int nodeId) - { - MixRampGroupedCommand command = new MixRampGroupedCommand(mixBufferCount, inputBufferIndex, outputBufferIndex, previousVolume, volume, state, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The previous volume. - /// The new volume. - /// The input buffer index. - /// The output buffer index. - /// The index in the array to store the ramped sample. - /// The to generate the command from. - /// The node id associated to this command. - public void GenerateMixRamp(float previousVolume, float volume, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory state, int nodeId) - { - MixRampCommand command = new MixRampCommand(previousVolume, volume, inputBufferIndex, outputBufferIndex, lastSampleIndex, state, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The depop buffer. - /// The target buffer offset. - /// The buffer count. - /// The node id associated to this command. - /// The target sample rate in use. - public void GenerateDepopForMixBuffersCommand(Memory depopBuffer, uint bufferOffset, uint bufferCount, int nodeId, uint sampleRate) - { - DepopForMixBuffersCommand command = new DepopForMixBuffersCommand(depopBuffer, bufferOffset, bufferCount, nodeId, sampleRate); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The input buffer index. - /// The output buffer index. - /// The node id associated to this command. - public void GenerateCopyMixBuffer(uint inputBufferIndex, uint outputBufferIndex, int nodeId) - { - CopyMixBufferCommand command = new CopyMixBufferCommand(inputBufferIndex, outputBufferIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The input buffer index. - /// The output buffer index. - /// The node id associated to this command. - /// The mix volume. - public void GenerateMix(uint inputBufferIndex, uint outputBufferIndex, int nodeId, float volume) - { - MixCommand command = new MixCommand(inputBufferIndex, outputBufferIndex, nodeId, volume); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Generate a new . - /// - /// The target buffer offset. - /// The reverb parameter. - /// The reverb state. - /// Set to true if the effect should be active. - /// The work buffer to use for processing. - /// The node id associated to this command. - /// If set to true, the long size pre-delay is supported. - public void GenerateReverbEffect(uint bufferOffset, ReverbParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId, bool isLongSizePreDelaySupported) - { - if (parameter.IsChannelCountValid()) - { - ReverbCommand command = new ReverbCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, isLongSizePreDelaySupported); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - /// - /// Generate a new . - /// - /// The target buffer offset. - /// The reverb 3d parameter. - /// The reverb 3d state. - /// Set to true if the effect should be active. - /// The work buffer to use for processing. - /// The node id associated to this command. - public void GenerateReverb3dEffect(uint bufferOffset, Reverb3dParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId) - { - if (parameter.IsChannelCountValid()) - { - Reverb3dCommand command = new Reverb3dCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - - /// - /// Generate a new . - /// - /// The target buffer offset. - /// The delay parameter. - /// The delay state. - /// Set to true if the effect should be active. - /// The work buffer to use for processing. - /// The node id associated to this command. - public void GenerateDelayEffect(uint bufferOffset, DelayParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId) - { - if (parameter.IsChannelCountValid()) - { - DelayCommand command = new DelayCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - /// - /// Generate a new . - /// - /// The target buffer offset. - /// The input buffer offset. - /// The output buffer offset. - /// The aux state. - /// Set to true if the effect should be active. - /// The limit of the circular buffer. - /// The guest address of the output buffer. - /// The guest address of the input buffer. - /// The count to add on the offset after write/read operations. - /// The write offset. - /// The node id associated to this command. - public void GenerateAuxEffect(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset, ref AuxiliaryBufferAddresses state, bool isEnabled, uint countMax, CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId) - { - if (state.SendBufferInfoBase != 0 && state.ReturnBufferInfoBase != 0) - { - AuxiliaryBufferCommand command = new AuxiliaryBufferCommand(bufferOffset, inputBufferOffset, outputBufferOffset, ref state, isEnabled, countMax, outputBuffer, inputBuffer, updateCount, writeOffset, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - /// - /// Generate a new . - /// - /// The target volume to apply. - /// The offset of the mix buffer. - /// The node id associated to this command. - public void GenerateVolume(float volume, uint bufferOffset, int nodeId) - { - VolumeCommand command = new VolumeCommand(volume, bufferOffset, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The offset of the mix buffer. - /// The of the circular buffer. - /// The node id associated to this command. - public void GenerateCircularBuffer(uint bufferOffset, CircularBufferSink sink, int nodeId) - { - CircularBufferSinkCommand command = new CircularBufferSinkCommand(bufferOffset, ref sink.Parameter, ref sink.CircularBufferAddressInfo, sink.CurrentWriteOffset, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The offset of the mix buffer. - /// The input buffer offset. - /// The output buffer offset. - /// The downmixer parameters to use. - /// The node id associated to this command. - public void GenerateDownMixSurroundToStereo(uint bufferOffset, Span inputBufferOffset, Span outputBufferOffset, ReadOnlySpan downMixParameter, int nodeId) - { - DownMixSurroundToStereoCommand command = new DownMixSurroundToStereoCommand(bufferOffset, inputBufferOffset, outputBufferOffset, downMixParameter, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The offset of the mix buffer. - /// The associated. - /// The total input count. - /// The input buffer mix offset. - /// The buffer count per sample. - /// The source sample count. - /// The source sample rate. - /// The node id associated to this command. - public void GenerateUpsample(uint bufferOffset, UpsamplerState upsampler, uint inputCount, Span inputBufferOffset, uint bufferCountPerSample, uint sampleCount, uint sampleRate, int nodeId) - { - UpsampleCommand command = new UpsampleCommand(bufferOffset, upsampler, inputCount, inputBufferOffset, bufferCountPerSample, sampleCount, sampleRate, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// - /// Create a new . - /// - /// The offset of the mix buffer. - /// The of the device sink. - /// The current audio renderer session id. - /// The mix buffer in use. - /// The node id associated to this command. - public void GenerateDeviceSink(uint bufferOffset, DeviceSink sink, int sessionId, Memory buffer, int nodeId) - { - DeviceSinkCommand command = new DeviceSinkCommand(bufferOffset, sink, sessionId, buffer, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandGenerator.cs b/Ryujinx.Audio.Renderer/Server/CommandGenerator.cs deleted file mode 100644 index 36c438fe..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandGenerator.cs +++ /dev/null @@ -1,940 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.Effect; -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.Voice; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class CommandGenerator - { - private CommandBuffer _commandBuffer; - private RendererSystemContext _rendererContext; - private VoiceContext _voiceContext; - private MixContext _mixContext; - private EffectContext _effectContext; - private SinkContext _sinkContext; - private SplitterContext _splitterContext; - private PerformanceManager _performanceManager; - - public CommandGenerator(CommandBuffer commandBuffer, RendererSystemContext rendererContext, VoiceContext voiceContext, MixContext mixContext, EffectContext effectContext, SinkContext sinkContext, SplitterContext splitterContext, PerformanceManager performanceManager) - { - _commandBuffer = commandBuffer; - _rendererContext = rendererContext; - _voiceContext = voiceContext; - _mixContext = mixContext; - _effectContext = effectContext; - _sinkContext = sinkContext; - _splitterContext = splitterContext; - _performanceManager = performanceManager; - - _commandBuffer.GenerateClearMixBuffer(RendererConstants.InvalidNodeId); - } - - private void GenerateDataSource(ref VoiceState voiceState, Memory dspState, int channelIndex) - { - if (voiceState.MixId != RendererConstants.UnusedMixId) - { - ref MixState mix = ref _mixContext.GetState(voiceState.MixId); - - _commandBuffer.GenerateDepopPrepare(dspState, - _rendererContext.DepopBuffer, - mix.BufferCount, - mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); - } - else if (voiceState.SplitterId != RendererConstants.UnusedSplitterId) - { - int destinationId = 0; - - while (true) - { - Span destinationSpan = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId++); - - if (destinationSpan.IsEmpty) - { - break; - } - - ref SplitterDestination destination = ref destinationSpan[0]; - - if (destination.IsConfigured()) - { - int mixId = destination.DestinationId; - - if (mixId < _mixContext.GetCount() && mixId != RendererConstants.UnusedSplitterIdInt) - { - ref MixState mix = ref _mixContext.GetState(mixId); - - _commandBuffer.GenerateDepopPrepare(dspState, - _rendererContext.DepopBuffer, - mix.BufferCount, - mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); - - destination.MarkAsNeedToUpdateInternalState(); - } - } - } - } - - if (!voiceState.WasPlaying) - { - Debug.Assert(voiceState.SampleFormat != SampleFormat.Adpcm || channelIndex == 0); - - if (_rendererContext.BehaviourContext.IsWaveBufferVersion2Supported()) - { - _commandBuffer.GenerateDataSourceVersion2(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); - } - else - { - switch (voiceState.SampleFormat) - { - case SampleFormat.PcmInt16: - _commandBuffer.GeneratePcmInt16DataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); - break; - case SampleFormat.PcmFloat: - _commandBuffer.GeneratePcmFloatDataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); - break; - case SampleFormat.Adpcm: - _commandBuffer.GenerateAdpcmDataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - voiceState.NodeId); - break; - default: - throw new NotImplementedException($"Unsupported data source {voiceState.SampleFormat}"); - } - } - } - } - - private void GenerateBiquadFilterForVoice(ref VoiceState voiceState, Memory state, int baseIndex, int bufferOffset, int nodeId) - { - for (int i = 0; i < voiceState.BiquadFilters.Length; i++) - { - ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i]; - - if (filter.Enable) - { - Memory biquadStateRawMemory = SpanMemoryManager.Cast(state).Slice(VoiceUpdateState.BiquadStateOffset, VoiceUpdateState.BiquadStateSize * RendererConstants.VoiceBiquadFilterCount); - - Memory stateMemory = SpanMemoryManager.Cast(biquadStateRawMemory); - - _commandBuffer.GenerateBiquadFilter(baseIndex, - ref filter, - stateMemory.Slice(i, 1), - bufferOffset, - bufferOffset, - !voiceState.BiquadFilterNeedInitialization[i], - nodeId); - } - } - } - - private void GenerateVoiceMix(Span mixVolumes, Span previousMixVolumes, Memory state, uint bufferOffset, uint bufferCount, uint bufferIndex, int nodeId) - { - if (bufferCount > RendererConstants.VoiceChannelCountMax) - { - _commandBuffer.GenerateMixRampGrouped(bufferCount, - bufferIndex, - bufferOffset, - previousMixVolumes, - mixVolumes, - state, - nodeId); - } - else - { - for (int i = 0; i < bufferCount; i++) - { - float previousMixVolume = previousMixVolumes[i]; - float mixVolume = mixVolumes[i]; - - if (mixVolume != 0.0f || previousMixVolume != 0.0f) - { - _commandBuffer.GenerateMixRamp(previousMixVolume, - mixVolume, - bufferIndex, - bufferOffset + (uint)i, - i, - state, - nodeId); - } - } - } - } - - private void GenerateVoice(ref VoiceState voiceState) - { - int nodeId = voiceState.NodeId; - uint channelsCount = voiceState.ChannelsCount; - - for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++) - { - Memory dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]); - - ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]); - - PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm; - - if (voiceState.SampleFormat == SampleFormat.PcmInt16) - { - dataSourceDetailType = PerformanceDetailType.PcmInt16; - } - else if (voiceState.SampleFormat == SampleFormat.PcmFloat) - { - dataSourceDetailType = PerformanceDetailType.PcmFloat; - } - - bool performanceInitialized = false; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, dataSourceDetailType, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateDataSource(ref voiceState, dspStateMemory, channelIndex); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - if (voiceState.WasPlaying) - { - voiceState.PreviousVolume = 0.0f; - } - else if (voiceState.HasAnyDestination()) - { - performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.BiquadFilter, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateBiquadFilterForVoice(ref voiceState, dspStateMemory, (int)_rendererContext.MixBufferCount, channelIndex, nodeId); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.VolumeRamp, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - _commandBuffer.GenerateVolumeRamp(voiceState.PreviousVolume, - voiceState.Volume, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - voiceState.PreviousVolume = voiceState.Volume; - - if (voiceState.MixId == RendererConstants.UnusedMixId) - { - if (voiceState.SplitterId != RendererConstants.UnusedSplitterId) - { - int destinationId = channelIndex; - - while (true) - { - Span destinationSpan = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId); - - if (destinationSpan.IsEmpty) - { - break; - } - - ref SplitterDestination destination = ref destinationSpan[0]; - - destinationId += (int)channelsCount; - - if (destination.IsConfigured()) - { - int mixId = destination.DestinationId; - - if (mixId < _mixContext.GetCount() && mixId != RendererConstants.UnusedSplitterIdInt) - { - ref MixState mix = ref _mixContext.GetState(mixId); - - GenerateVoiceMix(destination.MixBufferVolume, - destination.PreviousMixBufferVolume, - dspStateMemory, - mix.BufferOffset, - mix.BufferCount, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); - - destination.MarkAsNeedToUpdateInternalState(); - } - } - } - } - } - else - { - ref MixState mix = ref _mixContext.GetState(voiceState.MixId); - - performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.Mix, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateVoiceMix(channelResource.Mix.ToSpan(), - channelResource.PreviousMix.ToSpan(), - dspStateMemory, - mix.BufferOffset, - mix.BufferCount, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - channelResource.UpdateState(); - } - - for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++) - { - voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable; - } - } - } - } - - public void GenerateVoices() - { - for (int i = 0; i < _voiceContext.GetCount(); i++) - { - ref VoiceState sortedState = ref _voiceContext.GetSortedState(i); - - if (!sortedState.ShouldSkip() && sortedState.UpdateForCommandGeneration(_voiceContext)) - { - int nodeId = sortedState.NodeId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateVoice(ref sortedState); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - } - - _splitterContext.UpdateInternalState(); - } - - public void GeneratePerformance(ref PerformanceEntryAddresses performanceEntryAddresses, PerformanceCommand.Type type, int nodeId) - { - _commandBuffer.GeneratePerformance(ref performanceEntryAddresses, type, nodeId); - } - - private void GenerateBufferMixerEffect(int bufferOffset, BufferMixEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.BufferMix); - - if (effect.IsEnabled) - { - for (int i = 0; i < effect.Parameter.MixesCount; i++) - { - if (effect.Parameter.Volumes[i] != 0.0f) - { - _commandBuffer.GenerateMix((uint)bufferOffset + effect.Parameter.Input[i], - (uint)bufferOffset + effect.Parameter.Output[i], - nodeId, - effect.Parameter.Volumes[i]); - } - } - } - } - - private void GenerateAuxEffect(uint bufferOffset, AuxiliaryBufferEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.AuxiliaryBuffer); - - if (effect.IsEnabled) - { - effect.GetWorkBuffer(0); - effect.GetWorkBuffer(1); - } - - if (effect.State.SendBufferInfoBase != 0 && effect.State.ReturnBufferInfoBase != 0) - { - int i = 0; - uint writeOffset = 0; - for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--) - { - uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount; - - uint updateCount; - - if ((channelIndex - 1) != 0) - { - updateCount = 0; - } - else - { - updateCount = newUpdateCount; - } - - _commandBuffer.GenerateAuxEffect(bufferOffset, - effect.Parameter.Input[i], - effect.Parameter.Output[i], - ref effect.State, - effect.IsEnabled, - effect.Parameter.BufferStorageSize, - effect.State.SendBufferInfoBase, - effect.State.ReturnBufferInfoBase, - updateCount, - writeOffset, - nodeId); - - writeOffset = newUpdateCount; - - i++; - } - } - } - - private void GenerateDelayEffect(uint bufferOffset, DelayEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.Delay); - - ulong workBuffer = effect.GetWorkBuffer(-1); - - _commandBuffer.GenerateDelayEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId); - } - - private void GenerateReverbEffect(uint bufferOffset, ReverbEffect effect, int nodeId, bool isLongSizePreDelaySupported) - { - Debug.Assert(effect.Type == EffectType.Reverb); - - ulong workBuffer = effect.GetWorkBuffer(-1); - - _commandBuffer.GenerateReverbEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId, isLongSizePreDelaySupported); - } - - private void GenerateReverb3dEffect(uint bufferOffset, Reverb3dEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.Reverb3d); - - ulong workBuffer = effect.GetWorkBuffer(-1); - - _commandBuffer.GenerateReverb3dEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId); - } - - private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.BiquadFilter); - - if (effect.IsEnabled) - { - bool needInitialization = effect.Parameter.Status == UsageState.Invalid || - (effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - - BiquadFilterParameter parameter = new BiquadFilterParameter(); - - parameter.Enable = true; - effect.Parameter.Denominator.ToSpan().CopyTo(parameter.Denominator.ToSpan()); - effect.Parameter.Numerator.ToSpan().CopyTo(parameter.Numerator.ToSpan()); - - for (int i = 0; i < effect.Parameter.ChannelCount; i++) - { - _commandBuffer.GenerateBiquadFilter((int)bufferOffset, ref parameter, effect.State.Slice(i, 1), - effect.Parameter.Input[i], - effect.Parameter.Output[i], - needInitialization, - nodeId); - } - } - else - { - for (int i = 0; i < effect.Parameter.ChannelCount; i++) - { - uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i]; - uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i]; - - // If the input and output isn't the same, generate a command. - if (inputBufferIndex != outputBufferIndex) - { - _commandBuffer.GenerateCopyMixBuffer(inputBufferIndex, outputBufferIndex, nodeId); - } - } - } - } - - private void GenerateEffect(ref MixState mix, BaseEffect effect) - { - int nodeId = mix.NodeId; - - bool isFinalMix = mix.MixId == RendererConstants.FinalMixId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, effect.GetPerformanceDetailType(), - isFinalMix ? PerformanceEntryType.FinalMix : PerformanceEntryType.SubMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - switch (effect.Type) - { - case EffectType.BufferMix: - GenerateBufferMixerEffect((int)mix.BufferOffset, (BufferMixEffect)effect, nodeId); - break; - case EffectType.AuxiliaryBuffer: - GenerateAuxEffect(mix.BufferOffset, (AuxiliaryBufferEffect)effect, nodeId); - break; - case EffectType.Delay: - GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId); - break; - case EffectType.Reverb: - GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported); - break; - case EffectType.Reverb3d: - GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId); - break; - case EffectType.BiquadFilter: - GenerateBiquadFilterEffect(mix.BufferOffset, (BiquadFilterEffect)effect, nodeId); - break; - default: - throw new NotImplementedException($"Unsupported effect type {effect.Type}"); - } - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - effect.UpdateForCommandGeneration(); - } - - private void GenerateEffects(ref MixState mix) - { - ReadOnlySpan effectProcessingOrderArray = mix.EffectProcessingOrderArray; - - Debug.Assert(_effectContext.GetCount() == 0 || !effectProcessingOrderArray.IsEmpty); - - for (int i = 0; i < _effectContext.GetCount(); i++) - { - int effectOrder = effectProcessingOrderArray[i]; - - if (effectOrder == RendererConstants.InvalidProcessingOrder) - { - break; - } - - // BaseEffect is a class, we don't need to pass it by ref - BaseEffect effect = _effectContext.GetEffect(effectOrder); - - Debug.Assert(effect.Type != EffectType.Invalid); - Debug.Assert(effect.MixId == mix.MixId); - - if (!effect.ShouldSkip()) - { - GenerateEffect(ref mix, effect); - } - } - } - - private void GenerateMix(ref MixState mix) - { - if (mix.HasAnyDestination()) - { - Debug.Assert(mix.DestinationMixId != RendererConstants.UnusedMixId || mix.DestinationSplitterId != RendererConstants.UnusedSplitterId); - - if (mix.DestinationMixId == RendererConstants.UnusedMixId) - { - if (mix.DestinationSplitterId != RendererConstants.UnusedSplitterId) - { - int destinationId = 0; - - while (true) - { - int destinationIndex = destinationId++; - - Span destinationSpan = _splitterContext.GetDestination((int)mix.DestinationSplitterId, destinationIndex); - - if (destinationSpan.IsEmpty) - { - break; - } - - ref SplitterDestination destination = ref destinationSpan[0]; - - if (destination.IsConfigured()) - { - int mixId = destination.DestinationId; - - if (mixId < _mixContext.GetCount() && mixId != RendererConstants.UnusedSplitterIdInt) - { - ref MixState destinationMix = ref _mixContext.GetState(mixId); - - uint inputBufferIndex = mix.BufferOffset + ((uint)destinationIndex % mix.BufferCount); - - for (uint bufferDestinationIndex = 0; bufferDestinationIndex < destinationMix.BufferCount; bufferDestinationIndex++) - { - float volume = mix.Volume * destination.GetMixVolume((int)bufferDestinationIndex); - - if (volume != 0.0f) - { - _commandBuffer.GenerateMix(inputBufferIndex, - destinationMix.BufferOffset + bufferDestinationIndex, - mix.NodeId, - volume); - } - } - } - } - } - } - } - else - { - ref MixState destinationMix = ref _mixContext.GetState(mix.DestinationMixId); - - for (uint bufferIndex = 0; bufferIndex < mix.BufferCount; bufferIndex++) - { - for (uint bufferDestinationIndex = 0; bufferDestinationIndex < destinationMix.BufferCount; bufferDestinationIndex++) - { - float volume = mix.Volume * mix.GetMixBufferVolume((int)bufferIndex, (int)bufferDestinationIndex); - - if (volume != 0.0f) - { - _commandBuffer.GenerateMix(mix.BufferOffset + bufferIndex, - destinationMix.BufferOffset + bufferDestinationIndex, - mix.NodeId, - volume); - } - } - } - } - } - } - - private void GenerateSubMix(ref MixState subMix) - { - _commandBuffer.GenerateDepopForMixBuffersCommand(_rendererContext.DepopBuffer, - subMix.BufferOffset, - subMix.BufferCount, - subMix.NodeId, - subMix.SampleRate); - - GenerateEffects(ref subMix); - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - int nodeId = subMix.NodeId; - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.Mix, PerformanceEntryType.SubMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateMix(ref subMix); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - - public void GenerateSubMixes() - { - for (int id = 0; id < _mixContext.GetCount(); id++) - { - ref MixState sortedState = ref _mixContext.GetSortedState(id); - - if (sortedState.IsUsed && sortedState.MixId != RendererConstants.FinalMixId) - { - int nodeId = sortedState.NodeId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.SubMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateSubMix(ref sortedState); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - } - } - - private void GenerateFinalMix() - { - ref MixState finalMix = ref _mixContext.GetFinalState(); - - _commandBuffer.GenerateDepopForMixBuffersCommand(_rendererContext.DepopBuffer, - finalMix.BufferOffset, - finalMix.BufferCount, - finalMix.NodeId, - finalMix.SampleRate); - - GenerateEffects(ref finalMix); - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - int nodeId = finalMix.NodeId; - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.Mix, PerformanceEntryType.FinalMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - // Only generate volume command if the volume isn't 100%. - if (finalMix.Volume != 1.0f) - { - for (uint bufferIndex = 0; bufferIndex < finalMix.BufferCount; bufferIndex++) - { - bool performanceSubInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.VolumeRamp, PerformanceEntryType.FinalMix, nodeId)) - { - performanceSubInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - _commandBuffer.GenerateVolume(finalMix.Volume, - finalMix.BufferOffset + bufferIndex, - nodeId); - - if (performanceSubInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - } - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - - public void GenerateFinalMixes() - { - int nodeId = _mixContext.GetFinalState().NodeId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.FinalMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateFinalMix(); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - - private void GenerateCircularBuffer(CircularBufferSink sink, ref MixState finalMix) - { - _commandBuffer.GenerateCircularBuffer(finalMix.BufferOffset, sink, RendererConstants.InvalidNodeId); - } - - private void GenerateDevice(DeviceSink sink, ref MixState finalMix) - { - if (_commandBuffer.CommandList.SampleRate != 48000 && sink.UpsamplerState == null) - { - sink.UpsamplerState = _rendererContext.UpsamplerManager.Allocate(); - } - - bool useCustomDownMixingCommand = _rendererContext.ChannelCount == 2 && sink.Parameter.DownMixParameterEnabled; - - if (useCustomDownMixingCommand) - { - _commandBuffer.GenerateDownMixSurroundToStereo(finalMix.BufferOffset, - sink.Parameter.Input.ToSpan(), - sink.Parameter.Input.ToSpan(), - sink.DownMixCoefficients, - RendererConstants.InvalidNodeId); - } - // NOTE: we do the downmixing at the DSP level as right now the renderer interface doesn't use audout. - // TODO: Remove this when audout is rewritten. - else if (_rendererContext.ChannelCount == 2 && sink.Parameter.InputCount == 6) - { - _commandBuffer.GenerateDownMixSurroundToStereo(finalMix.BufferOffset, - sink.Parameter.Input.ToSpan(), - sink.Parameter.Input.ToSpan(), - RendererConstants.DefaultSurroundToStereoCoefficients, - RendererConstants.InvalidNodeId); - } - - CommandList commandList = _commandBuffer.CommandList; - - if (sink.UpsamplerState != null) - { - _commandBuffer.GenerateUpsample(finalMix.BufferOffset, - sink.UpsamplerState, - sink.Parameter.InputCount, - sink.Parameter.Input.ToSpan(), - commandList.BufferCount, - commandList.SampleCount, - commandList.SampleRate, - RendererConstants.InvalidNodeId); - } - - _commandBuffer.GenerateDeviceSink(finalMix.BufferOffset, - sink, - _rendererContext.SessionId, - commandList.Buffers, - RendererConstants.InvalidNodeId); - } - - private void GenerateSink(BaseSink sink, ref MixState finalMix) - { - bool performanceInitialized = false; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.Sink, sink.NodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, sink.NodeId); - } - - if (!sink.ShouldSkip) - { - switch (sink.Type) - { - case SinkType.CircularBuffer: - GenerateCircularBuffer((CircularBufferSink)sink, ref finalMix); - break; - case SinkType.Device: - GenerateDevice((DeviceSink)sink, ref finalMix); - break; - default: - throw new NotImplementedException($"Unsupported sink type {sink.Type}"); - } - - sink.UpdateForCommandGeneration(); - } - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, sink.NodeId); - } - } - - public void GenerateSinks() - { - ref MixState finalMix = ref _mixContext.GetFinalState(); - - for (int i = 0; i < _sinkContext.GetCount(); i++) - { - // BaseSink is a class, we don't need to pass it by ref - BaseSink sink = _sinkContext.GetSink(i); - - if (sink.IsUsed) - { - GenerateSink(sink, ref finalMix); - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs b/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs deleted file mode 100644 index 81d3b57b..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs +++ /dev/null @@ -1,180 +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 . -// - -using Ryujinx.Audio.Renderer.Dsp.Command; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// version 1. - /// - public class CommandProcessingTimeEstimatorVersion1 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion1(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - return 1454; - } - - public uint Estimate(ClearMixBufferCommand command) - { - return (uint)(_sampleCount * 0.83f * _bufferCount * 1.2f); - } - - public uint Estimate(BiquadFilterCommand command) - { - return (uint)(_sampleCount * 58.0f * 1.2f); - } - - public uint Estimate(MixRampGroupedCommand command) - { - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * 14.4f * 1.2f * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - return (uint)(_sampleCount * 14.4f * 1.2f); - } - - public uint Estimate(DepopPrepareCommand command) - { - return 1080; - } - - public uint Estimate(VolumeRampCommand command) - { - return (uint)(_sampleCount * 9.8f * 1.2f); - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - return (uint)(command.Pitch * 0.25f * 1.2f); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - return (uint)(command.Pitch * 0.46f * 1.2f); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - return (uint)(_sampleCount * 8.9f * command.MixBufferCount); - } - - public uint Estimate(CopyMixBufferCommand command) - { - // NOTE: Nintendo returns 0 here for some reasons even if it will generate a command like that on version 1.. maybe a mistake? - return 0; - } - - public uint Estimate(MixCommand command) - { - return (uint)(_sampleCount * 10.0f * 1.2f); - } - - public uint Estimate(DelayCommand command) - { - return (uint)(_sampleCount * command.Parameter.ChannelCount * 202.5f); - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(command.Parameter.IsChannelCountValid()); - - if (command.Enabled) - { - return (uint)(750 * _sampleCount * command.Parameter.ChannelCount * 1.2f); - } - - return 0; - } - - public uint Estimate(Reverb3dCommand command) - { - if (command.Enabled) - { - return (uint)(530 * _sampleCount * command.Parameter.ChannelCount * 1.2f); - } - - return 0; - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - if (command.Enabled) - { - return 15956; - } - - return 3765; - } - - public uint Estimate(VolumeCommand command) - { - return (uint)(_sampleCount * 8.8f * 1.2f); - } - - public uint Estimate(CircularBufferSinkCommand command) - { - return 55; - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - return 16108; - } - - public uint Estimate(UpsampleCommand command) - { - return 357915; - } - - public uint Estimate(DeviceSinkCommand command) - { - return 10042; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - return 0; - } - - public uint Estimate(DataSourceVersion2Command command) - { - return 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs b/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs deleted file mode 100644 index 0f4fe3c2..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs +++ /dev/null @@ -1,544 +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 . -// - -using Ryujinx.Audio.Renderer.Dsp.Command; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// version 2. (added with REV5) - /// - public class CommandProcessingTimeEstimatorVersion2 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion2(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)489.35f; - } - - return (uint)491.18f; - } - - public uint Estimate(ClearMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 668.8f; - float baseCost = 193.2f; - - if (_sampleCount == 160) - { - costPerBuffer = 260.4f; - baseCost = 139.65f; - } - - return (uint)(baseCost + costPerBuffer * _bufferCount); - } - - public uint Estimate(BiquadFilterCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)4813.2f; - } - - return (uint)6915.4f; - } - - public uint Estimate(MixRampGroupedCommand command) - { - const float costPerSample = 7.245f; - - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * costPerSample * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1859.0f; - } - - return (uint)2286.1f; - } - - public uint Estimate(DepopPrepareCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)306.62f; - } - - return (uint)293.22f; - } - - public uint Estimate(VolumeRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1403.9f; - } - - return (uint)1884.3f; - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 1195.5f; - float baseCost = 7797.0f; - - if (_sampleCount == 160) - { - costPerSample = 749.27f; - baseCost = 6138.9f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3564.1f; - float baseCost = 6225.5f; - - if (_sampleCount == 160) - { - costPerSample = 2125.6f; - baseCost = 9039.5f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)762.96f; - } - - return (uint)726.96f; - } - - public uint Estimate(CopyMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)836.32f; - } - - return (uint)1000.9f; - } - - public uint Estimate(MixCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1342.2f; - } - - return (uint)1833.2f; - } - - public uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)41636.0f; - case 2: - return (uint)97861.0f; - case 4: - return (uint)192520.0f; - case 6: - return (uint)301760.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)578.53f; - case 2: - return (uint)663.06f; - case 4: - return (uint)703.98f; - case 6: - return (uint)760.03f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)8770.3f; - case 2: - return (uint)25741.0f; - case 4: - return (uint)47551.0f; - case 6: - return (uint)81629.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)521.28f; - case 2: - return (uint)585.4f; - case 4: - return (uint)629.88f; - case 6: - return (uint)713.57f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)97192.0f; - case 2: - return (uint)103280.0f; - case 4: - return (uint)109580.0f; - case 6: - return (uint)115070.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)492.01f; - case 2: - return (uint)554.46f; - case 4: - return (uint)595.86f; - case 6: - return (uint)656.62f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)136460.0f; - case 2: - return (uint)145750.0f; - case 4: - return (uint)154800.0f; - case 6: - return (uint)161970.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)495.79f; - case 2: - return (uint)527.16f; - case 4: - return (uint)598.75f; - case 6: - return (uint)666.03f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)138840.0f; - case 2: - return (uint)135430.0f; - case 4: - return (uint)199180.0f; - case 6: - return (uint)247350.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)718.7f; - case 2: - return (uint)751.3f; - case 4: - return (uint)797.46f; - case 6: - return (uint)867.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)199950.0f; - case 2: - return (uint)195200.0f; - case 4: - return (uint)290580.0f; - case 6: - return (uint)363490.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)534.24f; - case 2: - return (uint)570.87f; - case 4: - return (uint)660.93f; - case 6: - return (uint)694.6f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - return (uint)7177.9f; - } - - return (uint)489.16f; - } - - if (command.Enabled) - { - return (uint)9499.8f; - } - - return (uint)485.56f; - } - - public uint Estimate(VolumeCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1280.3f; - } - - return (uint)1737.8f; - } - - public uint Estimate(CircularBufferSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 1726.0f; - float baseCost = 1369.7f; - - if (_sampleCount == 160) - { - costPerBuffer = 853.63f; - baseCost = 1284.5f; - } - - return (uint)(baseCost + costPerBuffer * command.InputCount); - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)10009.0f; - } - - return (uint)14577.0f; - } - - public uint Estimate(UpsampleCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)292000.0f; - } - - return (uint)0.0f; - } - - public uint Estimate(DeviceSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - Debug.Assert(command.InputCount == 2 || command.InputCount == 6); - - if (command.InputCount == 2) - { - if (_sampleCount == 160) - { - return (uint)9261.5f; - } - - return (uint)9336.1f; - } - - if (_sampleCount == 160) - { - return (uint)9111.8f; - } - - return (uint)9566.7f; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - // NOTE: This was added between REV7 and REV8 and for some reasons the estimator v2 was changed... - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3490.9f; - float baseCost = 10091.0f; - - if (_sampleCount == 160) - { - costPerSample = 2310.4f; - baseCost = 7845.3f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DataSourceVersion2Command command) - { - return 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs deleted file mode 100644 index 8e15d642..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs +++ /dev/null @@ -1,635 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// version 3. (added with REV8) - /// - public class CommandProcessingTimeEstimatorVersion3 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion3(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)498.17f; - } - - return (uint)489.42f; - } - - public uint Estimate(ClearMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 440.68f; - float baseCost = 0; - - if (_sampleCount == 160) - { - costPerBuffer = 266.65f; - } - - return (uint)(baseCost + costPerBuffer * _bufferCount); - } - - public uint Estimate(BiquadFilterCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)4173.2f; - } - - return (uint)5585.1f; - } - - public uint Estimate(MixRampGroupedCommand command) - { - float costPerSample = 6.4434f; - - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - costPerSample = 6.708f; - } - - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * costPerSample * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1968.7f; - } - - return (uint)2459.4f; - } - - public uint Estimate(DepopPrepareCommand command) - { - return 0; - } - - public uint Estimate(VolumeRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1425.3f; - } - - return (uint)1700.0f; - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 710.143f; - float baseCost = 7853.286f; - - if (_sampleCount == 160) - { - costPerSample = 427.52f; - baseCost = 6329.442f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3564.1f; - float baseCost = 9736.702f; - - if (_sampleCount == 160) - { - costPerSample = 2125.6f; - baseCost = 7913.808f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)739.64f; - } - - return (uint)910.97f; - } - - public uint Estimate(CopyMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)842.59f; - } - - return (uint)986.72f; - } - - public uint Estimate(MixCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1402.8f; - } - - return (uint)1853.2f; - } - - public uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)8929.04f; - case 2: - return (uint)25500.75f; - case 4: - return (uint)47759.62f; - case 6: - return (uint)82203.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)1295.20f; - case 2: - return (uint)1213.60f; - case 4: - return (uint)942.03f; - case 6: - return (uint)1001.55f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)11941.05f; - case 2: - return (uint)37197.37f; - case 4: - return (uint)69749.84f; - case 6: - return (uint)120042.40f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)997.67f; - case 2: - return (uint)977.63f; - case 4: - return (uint)792.30f; - case 6: - return (uint)875.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)81475.05f; - case 2: - return (uint)84975.0f; - case 4: - return (uint)91625.15f; - case 6: - return (uint)95332.27f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)536.30f; - case 2: - return (uint)588.70f; - case 4: - return (uint)643.70f; - case 6: - return (uint)706.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)120174.47f; - case 2: - return (uint)25262.22f; - case 4: - return (uint)135751.23f; - case 6: - return (uint)141129.23f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)617.64f; - case 2: - return (uint)659.54f; - case 4: - return (uint)711.43f; - case 6: - return (uint)778.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)116754.0f; - case 2: - return (uint)125912.05f; - case 4: - return (uint)146336.03f; - case 6: - return (uint)165812.66f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)734.0f; - case 2: - return (uint)766.62f; - case 4: - return (uint)797.46f; - case 6: - return (uint)867.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)170292.34f; - case 2: - return (uint)183875.63f; - case 4: - return (uint)214696.19f; - case 6: - return (uint)243846.77f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)508.47f; - case 2: - return (uint)582.45f; - case 4: - return (uint)626.42f; - case 6: - return (uint)682.47f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - return (uint)7182.14f; - } - - return (uint)472.11f; - } - - if (command.Enabled) - { - return (uint)9435.96f; - } - - return (uint)462.62f; - } - - public uint Estimate(VolumeCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1311.1f; - } - - return (uint)1713.6f; - } - - public uint Estimate(CircularBufferSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 770.26f; - float baseCost = 0f; - - if (_sampleCount == 160) - { - costPerBuffer = 531.07f; - } - - return (uint)(baseCost + costPerBuffer * command.InputCount); - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)9949.7f; - } - - return (uint)14679.0f; - } - - public uint Estimate(UpsampleCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)312990.0f; - } - - return (uint)0.0f; - } - - public uint Estimate(DeviceSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - Debug.Assert(command.InputCount == 2 || command.InputCount == 6); - - if (command.InputCount == 2) - { - if (_sampleCount == 160) - { - return (uint)8980.0f; - } - - return (uint)9221.9f; - } - - if (_sampleCount == 160) - { - return (uint)9177.9f; - } - - return (uint)9725.9f; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3490.9f; - float baseCost = 10090.9f; - - if (_sampleCount == 160) - { - costPerSample = 2310.4f; - baseCost = 7845.25f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DataSourceVersion2Command command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - (float baseCost, float costPerSample) = GetCostByFormat(_sampleCount, command.SampleFormat, command.SrcQuality); - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f) - 1.0f))); - } - - private static (float, float) GetCostByFormat(uint sampleCount, SampleFormat format, SampleRateConversionQuality quality) - { - Debug.Assert(sampleCount == 160 || sampleCount == 240); - - switch (format) - { - case SampleFormat.PcmInt16: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (6329.44f, 427.52f); - } - - return (7853.28f, 710.14f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (8049.42f, 371.88f); - } - - return (10138.84f, 610.49f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (5062.66f, 423.43f); - } - - return (5810.96f, 676.72f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - case SampleFormat.PcmFloat: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (7845.25f, 2310.4f); - } - - return (10090.9f, 3490.9f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (9446.36f, 2308.91f); - } - - return (12520.85f, 3480.61f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (9446.36f, 2308.91f); - } - - return (12520.85f, 3480.61f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - case SampleFormat.Adpcm: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (7913.81f, 1827.66f); - } - - return (9736.70f, 2756.37f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (9607.81f, 1829.29f); - } - - return (12154.38f, 2731.31f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (6517.48f, 1824.61f); - } - - return (7929.44f, 2732.15f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - default: - throw new NotImplementedException($"{format}"); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs deleted file mode 100644 index df82945b..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs +++ /dev/null @@ -1,92 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Server state for an auxiliary buffer effect. - /// - public class AuxiliaryBufferEffect : BaseEffect - { - /// - /// The auxiliary buffer parameter. - /// - public AuxiliaryBufferParameter Parameter; - - /// - /// Auxiliary buffer state. - /// - public AuxiliaryBufferAddresses State; - - public override EffectType TargetEffectType => EffectType.AuxiliaryBuffer; - - public override DspAddress GetWorkBuffer(int index) - { - return WorkBuffers[index].GetReference(true); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - UpdateParameterBase(ref parameter); - - Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; - IsEnabled = parameter.IsEnabled; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (BufferUnmapped || parameter.IsNew) - { - ulong bufferSize = (ulong)Unsafe.SizeOf() * Parameter.BufferStorageSize + (ulong)Unsafe.SizeOf() * 2; - - bool sendBufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], Parameter.SendBufferInfoAddress, bufferSize); - bool returnBufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[1], Parameter.ReturnBufferInfoAddress, bufferSize); - - BufferUnmapped = sendBufferUnmapped && returnBufferUnmapped; - - if (!BufferUnmapped) - { - DspAddress sendDspAddress = WorkBuffers[0].GetReference(false); - DspAddress returnDspAddress = WorkBuffers[1].GetReference(false); - - State.SendBufferInfo = sendDspAddress + (uint)Unsafe.SizeOf(); - State.SendBufferInfoBase = sendDspAddress + (uint)Unsafe.SizeOf() * 2; - - State.ReturnBufferInfo = returnDspAddress + (uint)Unsafe.SizeOf(); - State.ReturnBufferInfoBase = returnDspAddress + (uint)Unsafe.SizeOf() * 2; - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs deleted file mode 100644 index 7c491fd1..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs +++ /dev/null @@ -1,257 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Base class used as a server state for an effect. - /// - public class BaseEffect - { - /// - /// The of the effect. - /// - public EffectType Type; - - /// - /// Set to true if the effect must be active. - /// - public bool IsEnabled; - - /// - /// Set to true if the internal effect work buffers used wasn't mapped. - /// - public bool BufferUnmapped; - - /// - /// The current state of the effect. - /// - public UsageState UsageState; - - /// - /// The target mix id of the effect. - /// - public int MixId; - - /// - /// Position of the effect while processing effects. - /// - public uint ProcessingOrder; - - /// - /// Array of all the work buffer used by the effect. - /// - protected AddressInfo[] WorkBuffers; - - /// - /// Create a new . - /// - public BaseEffect() - { - Type = TargetEffectType; - UsageState = UsageState.Invalid; - - IsEnabled = false; - BufferUnmapped = false; - MixId = RendererConstants.UnusedMixId; - ProcessingOrder = uint.MaxValue; - - WorkBuffers = new AddressInfo[2]; - - foreach (ref AddressInfo info in WorkBuffers.AsSpan()) - { - info = AddressInfo.Create(); - } - } - - /// - /// The target handled by this . - /// - public virtual EffectType TargetEffectType => EffectType.Invalid; - - /// - /// Check if the sent by the user match the internal . - /// - /// The user parameter. - /// Returns true if the sent by the user matches the internal . - public bool IsTypeValid(ref EffectInParameter parameter) - { - return parameter.Type == TargetEffectType; - } - - /// - /// Update the usage state during command generation. - /// - protected void UpdateUsageStateForCommandGeneration() - { - UsageState = IsEnabled ? UsageState.Enabled : UsageState.Disabled; - } - - /// - /// Update the internal common parameters from a user parameter. - /// - /// The user parameter. - protected void UpdateParameterBase(ref EffectInParameter parameter) - { - MixId = parameter.MixId; - ProcessingOrder = parameter.ProcessingOrder; - } - - /// - /// Force unmap all the work buffers. - /// - /// The mapper to use. - public void ForceUnmapBuffers(PoolMapper mapper) - { - foreach (ref AddressInfo info in WorkBuffers.AsSpan()) - { - if (info.GetReference(false) != 0) - { - mapper.ForceUnmap(ref info); - } - } - } - - /// - /// Check if the effect needs to be skipped. - /// - /// Returns true if the effect needs to be skipped. - public bool ShouldSkip() - { - return BufferUnmapped; - } - - /// - /// Update the state during command generation. - /// - public virtual void UpdateForCommandGeneration() - { - Debug.Assert(Type == TargetEffectType); - } - - /// - /// Update the internal state from a user parameter. - /// - /// The possible that was generated. - /// The user parameter. - /// The mapper to use. - public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - updateErrorInfo = new ErrorInfo(); - } - - /// - /// Get the work buffer DSP address at the given index. - /// - /// The index of the work buffer - /// The work buffer DSP address at the given index. - public virtual DspAddress GetWorkBuffer(int index) - { - throw new InvalidOperationException(); - } - - /// - /// Get the first work buffer DSP address. - /// - /// The first work buffer DSP address. - protected DspAddress GetSingleBuffer() - { - if (IsEnabled) - { - return WorkBuffers[0].GetReference(true); - } - - if (UsageState != UsageState.Disabled) - { - DspAddress address = WorkBuffers[0].GetReference(false); - ulong size = WorkBuffers[0].Size; - - if (address != 0 && size != 0) - { - AudioProcessorMemoryManager.InvalidateDataCache(address, size); - } - } - - return 0; - } - - /// - /// Store the output status to the given user output. - /// - /// The given user output. - /// If set to true, the is active. - public void StoreStatus(ref EffectOutStatus outStatus, bool isAudioRendererActive) - { - if (isAudioRendererActive) - { - if (UsageState == UsageState.Disabled) - { - outStatus.State = EffectOutStatus.EffectState.Disabled; - } - else - { - outStatus.State = EffectOutStatus.EffectState.Enabled; - } - } - else if (UsageState == UsageState.New) - { - outStatus.State = EffectOutStatus.EffectState.Enabled; - } - else - { - outStatus.State = EffectOutStatus.EffectState.Disabled; - } - } - - /// - /// Get the associated to the of this effect. - /// - /// The associated to the of this effect. - public PerformanceDetailType GetPerformanceDetailType() - { - switch (Type) - { - case EffectType.BiquadFilter: - return PerformanceDetailType.BiquadFilter; - case EffectType.AuxiliaryBuffer: - return PerformanceDetailType.Aux; - case EffectType.Delay: - return PerformanceDetailType.Delay; - case EffectType.Reverb: - return PerformanceDetailType.Reverb; - case EffectType.Reverb3d: - return PerformanceDetailType.Reverb3d; - case EffectType.BufferMix: - return PerformanceDetailType.Mix; - default: - throw new NotImplementedException($"{Type}"); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs deleted file mode 100644 index aadf2844..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs +++ /dev/null @@ -1,74 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Server state for a biquad filter effect. - /// - public class BiquadFilterEffect : BaseEffect - { - /// - /// The biquad filter parameter. - /// - public BiquadFilterEffectParameter Parameter; - - /// - /// The biquad filter state. - /// - public Memory State { get; } - - /// - /// Create a new . - /// - public BiquadFilterEffect() - { - Parameter = new BiquadFilterEffectParameter(); - State = new BiquadFilterState[RendererConstants.ChannelCountMax]; - } - - public override EffectType TargetEffectType => EffectType.BiquadFilter; - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - UpdateParameterBase(ref parameter); - - Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; - IsEnabled = parameter.IsEnabled; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.Status = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs deleted file mode 100644 index 14ed3950..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs +++ /dev/null @@ -1,56 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Server state for a buffer mix effect. - /// - public class BufferMixEffect : BaseEffect - { - /// - /// The buffer mix parameter. - /// - public BufferMixParameter Parameter; - - public override EffectType TargetEffectType => EffectType.BufferMix; - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - UpdateParameterBase(ref parameter); - - Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; - IsEnabled = parameter.IsEnabled; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs deleted file mode 100644 index df3e5ee7..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs +++ /dev/null @@ -1,100 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Server state for a delay effect. - /// - public class DelayEffect : BaseEffect - { - /// - /// The delay parameter. - /// - public DelayParameter Parameter; - - /// - /// The delay state. - /// - public Memory State { get; } - - public DelayEffect() - { - State = new DelayState[1]; - } - - public override EffectType TargetEffectType => EffectType.Delay; - - public override DspAddress GetWorkBuffer(int index) - { - return GetSingleBuffer(); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref DelayParameter delayParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (delayParameter.IsChannelCountMaxValid()) - { - UpdateParameterBase(ref parameter); - - UsageState oldParameterStatus = Parameter.Status; - - Parameter = delayParameter; - - if (delayParameter.IsChannelCountValid()) - { - IsEnabled = parameter.IsEnabled; - - if (oldParameterStatus != UsageState.Enabled) - { - Parameter.Status = oldParameterStatus; - } - - if (BufferUnmapped || parameter.IsNew) - { - UsageState = UsageState.New; - Parameter.Status = UsageState.Invalid; - - BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize); - } - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.Status = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs b/Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs deleted file mode 100644 index ff6051ae..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs +++ /dev/null @@ -1,82 +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 . -// - -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Effect context. - /// - public class EffectContext - { - /// - /// Storage for . - /// - private BaseEffect[] _effects; - - /// - /// The total effect count. - /// - private uint _effectCount; - - /// - /// Create a new . - /// - public EffectContext() - { - _effects = null; - _effectCount = 0; - } - - /// - /// Initialize the . - /// - /// The total effect count. - public void Initialize(uint effectCount) - { - _effectCount = effectCount; - _effects = new BaseEffect[effectCount]; - - for (int i = 0; i < _effectCount; i++) - { - _effects[i] = new BaseEffect(); - } - } - - /// - /// Get the total effect count. - /// - /// The total effect count. - public uint GetCount() - { - return _effectCount; - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref BaseEffect GetEffect(int index) - { - Debug.Assert(index >= 0 && index < _effectCount); - - return ref _effects[index]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs deleted file mode 100644 index d9f23799..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs +++ /dev/null @@ -1,99 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Server state for a 3D reverberation effect. - /// - public class Reverb3dEffect : BaseEffect - { - /// - /// The 3D reverberation parameter. - /// - public Reverb3dParameter Parameter; - - /// - /// The 3D reverberation state. - /// - public Memory State { get; } - - public Reverb3dEffect() - { - State = new Reverb3dState[1]; - } - - public override EffectType TargetEffectType => EffectType.Reverb3d; - - public override ulong GetWorkBuffer(int index) - { - return GetSingleBuffer(); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref Reverb3dParameter reverbParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (reverbParameter.IsChannelCountMaxValid()) - { - UpdateParameterBase(ref parameter); - - UsageState oldParameterStatus = Parameter.ParameterStatus; - - Parameter = reverbParameter; - - if (reverbParameter.IsChannelCountValid()) - { - IsEnabled = parameter.IsEnabled; - - if (oldParameterStatus != UsageState.Enabled) - { - Parameter.ParameterStatus = oldParameterStatus; - } - - if (BufferUnmapped || parameter.IsNew) - { - UsageState = UsageState.New; - Parameter.ParameterStatus = UsageState.Invalid; - - BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize); - } - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.ParameterStatus = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs deleted file mode 100644 index 4c81f729..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs +++ /dev/null @@ -1,102 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// Server state for a reverberation effect. - /// - public class ReverbEffect : BaseEffect - { - /// - /// The reverberation parameter. - /// - public ReverbParameter Parameter; - - /// - /// The reverberation state. - /// - public Memory State { get; } - - /// - /// Create a new . - /// - public ReverbEffect() - { - State = new ReverbState[1]; - } - - public override EffectType TargetEffectType => EffectType.Reverb; - - public override ulong GetWorkBuffer(int index) - { - return GetSingleBuffer(); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref ReverbParameter reverbParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (reverbParameter.IsChannelCountMaxValid()) - { - UpdateParameterBase(ref parameter); - - UsageState oldParameterStatus = Parameter.Status; - - Parameter = reverbParameter; - - if (reverbParameter.IsChannelCountValid()) - { - IsEnabled = parameter.IsEnabled; - - if (oldParameterStatus != UsageState.Enabled) - { - Parameter.Status = oldParameterStatus; - } - - if (BufferUnmapped || parameter.IsNew) - { - UsageState = UsageState.New; - Parameter.Status = UsageState.Invalid; - - BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize); - } - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.Status = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs b/Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs deleted file mode 100644 index a519acd4..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs +++ /dev/null @@ -1,45 +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 . -// - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// - /// The usage state of an effect. - /// - public enum UsageState : byte - { - /// - /// The effect is in an invalid state. - /// - Invalid, - - /// - /// The effect is new. - /// - New, - - /// - /// The effect is enabled. - /// - Enabled, - - /// - /// The effect is disabled. - /// - Disabled - } -} diff --git a/Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs b/Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs deleted file mode 100644 index 119ec907..00000000 --- a/Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs +++ /dev/null @@ -1,52 +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 . -// - -using Ryujinx.Audio.Renderer.Dsp.Command; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// Estimate the time that a should take. - /// - /// This is used for voice dropping. - public interface ICommandProcessingTimeEstimator - { - uint Estimate(AuxiliaryBufferCommand command); - uint Estimate(BiquadFilterCommand command); - uint Estimate(ClearMixBufferCommand command); - uint Estimate(DelayCommand command); - uint Estimate(Reverb3dCommand command); - uint Estimate(ReverbCommand command); - uint Estimate(DepopPrepareCommand command); - uint Estimate(DepopForMixBuffersCommand command); - uint Estimate(MixCommand command); - uint Estimate(MixRampCommand command); - uint Estimate(MixRampGroupedCommand command); - uint Estimate(CopyMixBufferCommand command); - uint Estimate(PerformanceCommand command); - uint Estimate(VolumeCommand command); - uint Estimate(VolumeRampCommand command); - uint Estimate(PcmInt16DataSourceCommandVersion1 command); - uint Estimate(PcmFloatDataSourceCommandVersion1 command); - uint Estimate(AdpcmDataSourceCommandVersion1 command); - uint Estimate(DataSourceVersion2Command command); - uint Estimate(CircularBufferSinkCommand command); - uint Estimate(DeviceSinkCommand command); - uint Estimate(DownMixSurroundToStereoCommand command); - uint Estimate(UpsampleCommand command); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs b/Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs deleted file mode 100644 index 2b625d06..00000000 --- a/Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs +++ /dev/null @@ -1,151 +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 . -// - -using System; -using System.Runtime.InteropServices; - -using DspAddress = System.UInt64; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.MemoryPool -{ - /// - /// Represents the information of a region shared between the CPU and DSP. - /// - public struct AddressInfo - { - /// - /// The target CPU address of the region. - /// - public CpuAddress CpuAddress; - - /// - /// The size of the region. - /// - public ulong Size; - - private unsafe MemoryPoolState* _memoryPools; - - /// - /// The forced DSP address of the region. - /// - public DspAddress ForceMappedDspAddress; - - private unsafe ref MemoryPoolState MemoryPoolState => ref *_memoryPools; - - public unsafe bool HasMemoryPoolState => (IntPtr)_memoryPools != IntPtr.Zero; - - /// - /// Create an new empty . - /// - /// A new empty . - public static AddressInfo Create() - { - return Create(0, 0); - } - - /// - /// Create a new . - /// - /// The target of the region. - /// The target size of the region. - /// A new . - public static AddressInfo Create(CpuAddress cpuAddress, ulong size) - { - unsafe - { - return new AddressInfo - { - CpuAddress = cpuAddress, - _memoryPools = MemoryPoolState.Null, - Size = size, - ForceMappedDspAddress = 0 - }; - } - } - - /// - /// Setup the CPU address and size of the . - /// - /// The target of the region. - /// The size of the region. - public void Setup(CpuAddress cpuAddress, ulong size) - { - CpuAddress = cpuAddress; - Size = size; - ForceMappedDspAddress = 0; - - unsafe - { - _memoryPools = MemoryPoolState.Null; - } - } - - /// - /// Set the associated. - /// - /// The associated. - public void SetupMemoryPool(Span memoryPoolState) - { - unsafe - { - fixed (MemoryPoolState* ptr = &MemoryMarshal.GetReference(memoryPoolState)) - { - SetupMemoryPool(ptr); - } - } - } - - /// - /// Set the associated. - /// - /// The associated. - public unsafe void SetupMemoryPool(MemoryPoolState* memoryPoolState) - { - _memoryPools = memoryPoolState; - } - - /// - /// Check if the is mapped. - /// - /// Returns true if the is mapped. - public bool HasMappedMemoryPool() - { - return HasMemoryPoolState && MemoryPoolState.IsMapped(); - } - - /// - /// Get the DSP address associated to the . - /// - /// If true, mark the as used. - /// Returns the DSP address associated to the . - public DspAddress GetReference(bool markUsed) - { - if (!HasMappedMemoryPool()) - { - return ForceMappedDspAddress; - } - - if (markUsed) - { - MemoryPoolState.IsUsed = true; - } - - return MemoryPoolState.Translate(CpuAddress, Size); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs b/Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs deleted file mode 100644 index ebde1403..00000000 --- a/Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs +++ /dev/null @@ -1,148 +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 . -// - -using System; -using System.Runtime.InteropServices; - -using DspAddress = System.UInt64; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.MemoryPool -{ - /// - /// Server state for a memory pool. - /// - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)] - public struct MemoryPoolState - { - public const int Alignment = 0x10; - - /// - /// The location of the . - /// - public enum LocationType : uint - { - /// - /// located on the CPU side for user use. - /// - Cpu, - - /// - /// located on the DSP side for system use. - /// - Dsp - } - - /// - /// The CPU address associated to the . - /// - public CpuAddress CpuAddress; - - /// - /// The DSP address associated to the . - /// - public DspAddress DspAddress; - - /// - /// The size associated to the . - /// - public ulong Size; - - /// - /// The associated to the . - /// - public LocationType Location; - - /// - /// Set to true if the is used. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - public static unsafe MemoryPoolState* Null => (MemoryPoolState*)IntPtr.Zero.ToPointer(); - - /// - /// Create a new with the given . - /// - /// The location type to use. - /// A new with the given . - public static MemoryPoolState Create(LocationType location) - { - return new MemoryPoolState - { - CpuAddress = 0, - DspAddress = 0, - Size = 0, - Location = location - }; - } - - /// - /// Set the and size of the . - /// - /// The . - /// The size. - public void SetCpuAddress(CpuAddress cpuAddress, ulong size) - { - CpuAddress = cpuAddress; - Size = size; - } - - /// - /// Check if the given and size is contains in the . - /// - /// The . - /// The size. - /// True if the is contained inside the . - public bool Contains(CpuAddress targetCpuAddress, ulong size) - { - if (CpuAddress <= targetCpuAddress && size + targetCpuAddress <= Size + CpuAddress) - { - return true; - } - - return false; - } - - /// - /// Translate the given CPU address to a DSP address. - /// - /// The . - /// The size. - /// the target DSP address. - public DspAddress Translate(CpuAddress targetCpuAddress, ulong size) - { - if (Contains(targetCpuAddress, size) && IsMapped()) - { - ulong offset = targetCpuAddress - CpuAddress; - - return DspAddress + offset; - } - - return 0; - } - - /// - /// Is the mapped on the DSP? - /// - /// Returns true if the is mapped on the DSP. - public bool IsMapped() - { - return DspAddress != 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs b/Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs deleted file mode 100644 index b255960c..00000000 --- a/Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs +++ /dev/null @@ -1,383 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common.Logging; -using System; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -using CpuAddress = System.UInt64; -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.MemoryPool -{ - /// - /// Memory pool mapping helper. - /// - public class PoolMapper - { - const uint CurrentProcessPseudoHandle = 0xFFFF8001; - - /// - /// The result of . - /// - public enum UpdateResult : uint - { - /// - /// No error reported. - /// - Success = 0, - - /// - /// The user parameters were invalid. - /// - InvalidParameter = 1, - - /// - /// mapping failed. - /// - MapError = 2, - - /// - /// unmapping failed. - /// - UnmapError = 3 - } - - /// - /// The handle of the process owning the CPU memory manipulated. - /// - private uint _processHandle; - - /// - /// The that will be manipulated. - /// - private Memory _memoryPools; - - /// - /// If set to true, this will try to force map memory pool even if their state are considered invalid. - /// - private bool _isForceMapEnabled; - - /// - /// Create a new used for system mapping. - /// - /// The handle of the process owning the CPU memory manipulated. - /// If set to true, this will try to force map memory pool even if their state are considered invalid. - public PoolMapper(uint processHandle, bool isForceMapEnabled) - { - _processHandle = processHandle; - _isForceMapEnabled = isForceMapEnabled; - _memoryPools = Memory.Empty; - } - - /// - /// Create a new used for user mapping. - /// - /// The handle of the process owning the CPU memory manipulated. - /// The user memory pools. - /// If set to true, this will try to force map memory pool even if their state are considered invalid. - public PoolMapper(uint processHandle, Memory memoryPool, bool isForceMapEnabled) - { - _processHandle = processHandle; - _memoryPools = memoryPool; - _isForceMapEnabled = isForceMapEnabled; - } - - /// - /// Initialize the for system use. - /// - /// The for system use. - /// The to assign. - /// The size to assign. - /// Returns true if mapping on the succeeded. - public bool InitializeSystemPool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) - { - if (memoryPool.Location != MemoryPoolState.LocationType.Dsp) - { - return false; - } - - return InitializePool(ref memoryPool, cpuAddress, size); - } - - /// - /// Initialize the . - /// - /// The . - /// The to assign. - /// The size to assign. - /// Returns true if mapping on the succeeded. - public bool InitializePool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) - { - memoryPool.SetCpuAddress(cpuAddress, size); - - return Map(ref memoryPool) != 0; - } - - /// - /// Get the process handle associated to the . - /// - /// The . - /// Returns the process handle associated to the . - public uint GetProcessHandle(ref MemoryPoolState memoryPool) - { - if (memoryPool.Location == MemoryPoolState.LocationType.Cpu) - { - return CurrentProcessPseudoHandle; - } - else if (memoryPool.Location == MemoryPoolState.LocationType.Dsp) - { - return _processHandle; - } - - return 0; - } - - /// - /// Map the on the . - /// - /// The to map. - /// Returns the DSP address mapped. - public DspAddress Map(ref MemoryPoolState memoryPool) - { - DspAddress result = AudioProcessorMemoryManager.Map(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); - - if (result != 0) - { - memoryPool.DspAddress = result; - } - - return result; - } - - /// - /// Unmap the from the . - /// - /// The to unmap. - /// Returns true if unmapped. - public bool Unmap(ref MemoryPoolState memoryPool) - { - if (memoryPool.IsUsed) - { - return false; - } - - AudioProcessorMemoryManager.Unmap(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); - - memoryPool.SetCpuAddress(0, 0); - memoryPool.DspAddress = 0; - - return true; - } - - /// - /// Find a associated to the region given. - /// - /// The region . - /// The region size. - /// Returns the found or if not found. - private Span FindMemoryPool(CpuAddress cpuAddress, ulong size) - { - if (!_memoryPools.IsEmpty && _memoryPools.Length > 0) - { - for (int i = 0; i < _memoryPools.Length; i++) - { - if (_memoryPools.Span[i].Contains(cpuAddress, size)) - { - return _memoryPools.Span.Slice(i, 1); - } - } - } - - return Span.Empty; - } - - /// - /// Force unmap the given . - /// - /// The to force unmap - public void ForceUnmap(ref AddressInfo addressInfo) - { - if (_isForceMapEnabled) - { - Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); - - if (!memoryPool.IsEmpty) - { - AudioProcessorMemoryManager.Unmap(_processHandle, memoryPool[0].CpuAddress, memoryPool[0].Size); - - return; - } - - AudioProcessorMemoryManager.Unmap(_processHandle, addressInfo.CpuAddress, 0); - } - } - - /// - /// Try to attach the given region to the . - /// - /// The error information if an error was generated. - /// The to attach the region to. - /// The region . - /// The region size. - /// Returns true if mapping was performed. - public bool TryAttachBuffer(out ErrorInfo errorInfo, ref AddressInfo addressInfo, CpuAddress cpuAddress, ulong size) - { - errorInfo = new ErrorInfo(); - - addressInfo.Setup(cpuAddress, size); - - if (AssignDspAddress(ref addressInfo)) - { - errorInfo.ErrorCode = 0x0; - errorInfo.ExtraErrorInfo = 0x0; - - return true; - } - else - { - errorInfo.ErrorCode = ResultCode.InvalidAddressInfo; - errorInfo.ExtraErrorInfo = addressInfo.CpuAddress; - - return _isForceMapEnabled; - } - } - - /// - /// Update a using user parameters. - /// - /// The to update. - /// Input user parameter. - /// Output user parameter. - /// Returns the of the operations performed. - public UpdateResult Update(ref MemoryPoolState memoryPool, ref MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) - { - MemoryPoolUserState inputState = inParameter.State; - - MemoryPoolUserState outputState; - - const uint pageSize = 0x1000; - - if (inputState != MemoryPoolUserState.RequestAttach && inputState != MemoryPoolUserState.RequestDetach) - { - return UpdateResult.Success; - } - - if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0) - { - return UpdateResult.InvalidParameter; - } - - if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0) - { - return UpdateResult.InvalidParameter; - } - - if (inputState == MemoryPoolUserState.RequestAttach) - { - bool initializeSuccess = InitializePool(ref memoryPool, inParameter.CpuAddress, inParameter.Size); - - if (!initializeSuccess) - { - memoryPool.SetCpuAddress(0, 0); - - Logger.Error?.Print(LogClass.AudioRenderer, $"Map of memory pool (address: 0x{inParameter.CpuAddress:x}, size 0x{inParameter.Size:x}) failed!"); - return UpdateResult.MapError; - } - - outputState = MemoryPoolUserState.Attached; - } - else - { - if (memoryPool.CpuAddress != inParameter.CpuAddress || memoryPool.Size != inParameter.Size) - { - return UpdateResult.InvalidParameter; - } - - if (!Unmap(ref memoryPool)) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Unmap of memory pool (address: 0x{memoryPool.CpuAddress:x}, size 0x{memoryPool.Size:x}) failed!"); - return UpdateResult.UnmapError; - } - - outputState = MemoryPoolUserState.Detached; - } - - outStatus.State = outputState; - - return UpdateResult.Success; - } - - /// - /// Map the to the . - /// - /// The to map. - /// Returns true if mapping was performed. - private bool AssignDspAddress(ref AddressInfo addressInfo) - { - if (addressInfo.CpuAddress == 0) - { - return false; - } - - if (_memoryPools.Length > 0) - { - Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); - - if (!memoryPool.IsEmpty) - { - addressInfo.SetupMemoryPool(memoryPool); - - return true; - } - } - - if (_isForceMapEnabled) - { - DspAddress dspAddress = AudioProcessorMemoryManager.Map(_processHandle, addressInfo.CpuAddress, addressInfo.Size); - - addressInfo.ForceMappedDspAddress = dspAddress; - - AudioProcessorMemoryManager.Map(_processHandle, addressInfo.CpuAddress, addressInfo.Size); - } - else - { - unsafe - { - addressInfo.SetupMemoryPool(MemoryPoolState.Null); - } - } - - return false; - } - - /// - /// Remove the usage flag from all the . - /// - /// The to reset. - public static void ClearUsageState(Memory memoryPool) - { - foreach (ref MemoryPoolState info in memoryPool.Span) - { - info.IsUsed = false; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs b/Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs deleted file mode 100644 index 5a3c3a63..00000000 --- a/Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs +++ /dev/null @@ -1,276 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Mix -{ - /// - /// Mix context. - /// - public class MixContext - { - /// - /// The total mix count. - /// - private uint _mixesCount; - - /// - /// Storage for . - /// - private Memory _mixes; - - /// - /// Storage of the sorted indices to . - /// - private Memory _sortedMixes; - - /// - /// Graph state. - /// - public NodeStates NodeStates { get; } - - /// - /// The instance of the adjacent matrix. - /// - public EdgeMatrix EdgeMatrix { get; } - - /// - /// Create a new instance of . - /// - public MixContext() - { - NodeStates = new NodeStates(); - EdgeMatrix = new EdgeMatrix(); - } - - /// - /// Initialize the . - /// - /// The storage for sorted indices. - /// The storage of . - /// The storage used for the . - /// The storage used for the . - public void Initialize(Memory sortedMixes, Memory mixes, Memory nodeStatesWorkBuffer, Memory edgeMatrixWorkBuffer) - { - _mixesCount = (uint)mixes.Length; - _mixes = mixes; - _sortedMixes = sortedMixes; - - if (!nodeStatesWorkBuffer.IsEmpty && !edgeMatrixWorkBuffer.IsEmpty) - { - NodeStates.Initialize(nodeStatesWorkBuffer, mixes.Length); - EdgeMatrix.Initialize(edgeMatrixWorkBuffer, mixes.Length); - } - - int sortedId = 0; - for (int i = 0; i < _mixes.Length; i++) - { - SetSortedState(sortedId++, i); - } - } - - /// - /// Associate the given to a given . - /// - /// The sorted id. - /// The index to associate. - private void SetSortedState(int id, int targetIndex) - { - _sortedMixes.Span[id] = targetIndex; - } - - /// - /// Get a reference to the final . - /// - /// A reference to the final . - public ref MixState GetFinalState() - { - return ref GetState(RendererConstants.FinalMixId); - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref MixState GetState(int id) - { - return ref SpanIOHelper.GetFromMemory(_mixes, id, _mixesCount); - } - - /// - /// Get a reference to a at the given of the sorted mix info. - /// - /// The index to use. - /// A reference to a at the given . - public ref MixState GetSortedState(int id) - { - Debug.Assert(id >= 0 && id < _mixesCount); - - return ref GetState(_sortedMixes.Span[id]); - } - - /// - /// Get the total mix count. - /// - /// The total mix count. - public uint GetCount() - { - return _mixesCount; - } - - /// - /// Update the internal distance from the final mix value of every . - /// - private void UpdateDistancesFromFinalMix() - { - foreach (ref MixState mix in _mixes.Span) - { - mix.ClearDistanceFromFinalMix(); - } - - for (int i = 0; i < GetCount(); i++) - { - ref MixState mix = ref GetState(i); - - SetSortedState(i, i); - - if (mix.IsUsed) - { - uint distance; - - if (mix.MixId != RendererConstants.FinalMixId) - { - int mixId = mix.MixId; - - for (distance = 0; distance < GetCount(); distance++) - { - if (mixId == RendererConstants.UnusedMixId) - { - distance = MixState.InvalidDistanceFromFinalMix; - break; - } - - ref MixState distanceMix = ref GetState(mixId); - - if (distanceMix.DistanceFromFinalMix != MixState.InvalidDistanceFromFinalMix) - { - distance = distanceMix.DistanceFromFinalMix + 1; - break; - } - - mixId = distanceMix.DestinationMixId; - - if (mixId == RendererConstants.FinalMixId) - { - break; - } - } - - if (distance > GetCount()) - { - distance = MixState.InvalidDistanceFromFinalMix; - } - } - else - { - distance = MixState.InvalidDistanceFromFinalMix; - } - - mix.DistanceFromFinalMix = distance; - } - } - } - - /// - /// Update the internal mix buffer offset of all . - /// - private void UpdateMixBufferOffset() - { - uint offset = 0; - - foreach (ref MixState mix in _mixes.Span) - { - mix.BufferOffset = offset; - - offset += mix.BufferCount; - } - } - - /// - /// Sort the mixes using distance from the final mix. - /// - public void Sort() - { - UpdateDistancesFromFinalMix(); - - int[] sortedMixesTemp = _sortedMixes.Slice(0, (int)GetCount()).ToArray(); - - Array.Sort(sortedMixesTemp, (a, b) => - { - ref MixState stateA = ref GetState(a); - ref MixState stateB = ref GetState(b); - - return stateB.DistanceFromFinalMix.CompareTo(stateA.DistanceFromFinalMix); - }); - - sortedMixesTemp.AsSpan().CopyTo(_sortedMixes.Span); - - UpdateMixBufferOffset(); - } - - /// - /// Sort the mixes and splitters using an adjacency matrix. - /// - /// The used. - /// Return true, if no errors in the graph were detected. - public bool Sort(SplitterContext splitterContext) - { - if (splitterContext.UsingSplitter()) - { - bool isValid = NodeStates.Sort(EdgeMatrix); - - if (isValid) - { - ReadOnlySpan sortedMixesIndex = NodeStates.GetTsortResult(); - - int id = 0; - - for (int i = sortedMixesIndex.Length - 1; i >= 0; i--) - { - SetSortedState(id++, sortedMixesIndex[i]); - } - - UpdateMixBufferOffset(); - } - - return isValid; - } - else - { - UpdateMixBufferOffset(); - - return true; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Mix/MixState.cs b/Ryujinx.Audio.Renderer/Server/Mix/MixState.cs deleted file mode 100644 index d697488a..00000000 --- a/Ryujinx.Audio.Renderer/Server/Mix/MixState.cs +++ /dev/null @@ -1,330 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Common.Utilities; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using static Ryujinx.Audio.Renderer.RendererConstants; - -namespace Ryujinx.Audio.Renderer.Server.Mix -{ - /// - /// Server state for a mix. - /// - [StructLayout(LayoutKind.Sequential, Size = 0x940, Pack = Alignment)] - public struct MixState - { - public const uint InvalidDistanceFromFinalMix = 0x80000000; - - public const int Alignment = 0x10; - - /// - /// Base volume of the mix. - /// - public float Volume; - - /// - /// Target sample rate of the mix. - /// - public uint SampleRate; - - /// - /// Target buffer count. - /// - public uint BufferCount; - - /// - /// Set to true if in use. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - /// - /// The id of the mix. - /// - public int MixId; - - /// - /// The mix node id. - /// - public int NodeId; - - /// - /// the buffer offset to use for command generation. - /// - public uint BufferOffset; - - /// - /// The distance of the mix from the final mix. - /// - public uint DistanceFromFinalMix; - - /// - /// The effect processing order storage. - /// - private IntPtr _effectProcessingOrderArrayPointer; - - /// - /// The max element count that can be found in the effect processing order storage. - /// - public uint EffectProcessingOrderArrayMaxCount; - - /// - /// The mix to output the result of this mix. - /// - public int DestinationMixId; - - /// - /// Mix buffer volumes storage. - /// - private MixVolumeArray _mixVolumeArray; - - /// - /// The splitter to output the result of this mix. - /// - public uint DestinationSplitterId; - - /// - /// If set to true, the long size pre-delay is supported on the reverb command. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsLongSizePreDelaySupported; - - [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)] - private struct MixVolumeArray - { - private const int Size = 4 * MixBufferCountMax * MixBufferCountMax; - } - - /// - /// Mix buffer volumes. - /// - /// Used when no splitter id is specified. - public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mixVolumeArray); - - /// - /// Get the volume for a given connection destination. - /// - /// The source node index. - /// The destination node index - /// The volume for the given connection destination. - public float GetMixBufferVolume(int sourceIndex, int destinationIndex) - { - return MixBufferVolume[sourceIndex * MixBufferCountMax + destinationIndex]; - } - - /// - /// The array used to order effects associated to this mix. - /// - public Span EffectProcessingOrderArray - { - get - { - if (_effectProcessingOrderArrayPointer == IntPtr.Zero) - { - return Span.Empty; - } - - unsafe - { - return new Span((void*)_effectProcessingOrderArrayPointer, (int)EffectProcessingOrderArrayMaxCount); - } - } - } - - /// - /// Create a new - /// - /// - /// - public MixState(Memory effectProcessingOrderArray, ref BehaviourContext behaviourContext) : this() - { - MixId = UnusedMixId; - - DistanceFromFinalMix = InvalidDistanceFromFinalMix; - - DestinationMixId = UnusedMixId; - - DestinationSplitterId = UnusedSplitterId; - - unsafe - { - // SAFETY: safe as effectProcessingOrderArray comes from the work buffer memory that is pinned. - _effectProcessingOrderArrayPointer = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetReference(effectProcessingOrderArray.Span)); - } - - EffectProcessingOrderArrayMaxCount = (uint)effectProcessingOrderArray.Length; - - IsLongSizePreDelaySupported = behaviourContext.IsLongSizePreDelaySupported(); - - ClearEffectProcessingOrder(); - } - - /// - /// Clear the value to its default state. - /// - public void ClearDistanceFromFinalMix() - { - DistanceFromFinalMix = InvalidDistanceFromFinalMix; - } - - /// - /// Clear the to its default state. - /// - public void ClearEffectProcessingOrder() - { - EffectProcessingOrderArray.Fill(-1); - } - - /// - /// Return true if the mix has any destinations. - /// - /// True if the mix has any destinations. - public bool HasAnyDestination() - { - return DestinationMixId != UnusedMixId || DestinationSplitterId != UnusedSplitterId; - } - - /// - /// Update the mix connection on the adjacency matrix. - /// - /// The adjacency matrix. - /// The input parameter of the mix. - /// The splitter context. - /// Return true, new connections were done on the adjacency matrix. - private bool UpdateConnection(EdgeMatrix edgeMatrix, ref MixParameter parameter, ref SplitterContext splitterContext) - { - bool hasNewConnections; - - if (DestinationSplitterId == UnusedSplitterId) - { - hasNewConnections = false; - } - else - { - ref SplitterState splitter = ref splitterContext.GetState((int)DestinationSplitterId); - - hasNewConnections = splitter.HasNewConnection; - } - - if (DestinationMixId == parameter.DestinationMixId && DestinationSplitterId == parameter.DestinationSplitterId && !hasNewConnections) - { - return false; - } - - edgeMatrix.RemoveEdges(MixId); - - if (parameter.DestinationMixId == UnusedMixId) - { - if (parameter.DestinationSplitterId != UnusedSplitterId) - { - ref SplitterState splitter = ref splitterContext.GetState((int)parameter.DestinationSplitterId); - - for (int i = 0; i < splitter.DestinationCount; i++) - { - Span destination = splitter.GetData(i); - - if (!destination.IsEmpty) - { - int destinationMixId = destination[0].DestinationId; - - if (destinationMixId != UnusedMixId) - { - edgeMatrix.Connect(MixId, destinationMixId); - } - } - } - } - } - else - { - edgeMatrix.Connect(MixId, parameter.DestinationMixId); - } - - DestinationMixId = parameter.DestinationMixId; - DestinationSplitterId = parameter.DestinationSplitterId; - - return true; - } - - /// - /// Update the mix from user information. - /// - /// The adjacency matrix. - /// The input parameter of the mix. - /// The effect context. - /// The splitter context. - /// The behaviour context. - /// Return true if the mix was changed. - public bool Update(EdgeMatrix edgeMatrix, ref MixParameter parameter, EffectContext effectContext, SplitterContext splitterContext, BehaviourContext behaviourContext) - { - bool isDirty; - - Volume = parameter.Volume; - SampleRate = parameter.SampleRate; - BufferCount = parameter.BufferCount; - IsUsed = parameter.IsUsed; - MixId = parameter.MixId; - NodeId = parameter.NodeId; - parameter.MixBufferVolume.CopyTo(MixBufferVolume); - - if (behaviourContext.IsSplitterSupported()) - { - isDirty = UpdateConnection(edgeMatrix, ref parameter, ref splitterContext); - } - else - { - isDirty = DestinationMixId != parameter.DestinationMixId; - - if (DestinationMixId != parameter.DestinationMixId) - { - DestinationMixId = parameter.DestinationMixId; - } - - DestinationSplitterId = UnusedSplitterId; - } - - ClearEffectProcessingOrder(); - - for (int i = 0; i < effectContext.GetCount(); i++) - { - ref BaseEffect effect = ref effectContext.GetEffect(i); - - if (effect.MixId == MixId) - { - Debug.Assert(effect.ProcessingOrder <= EffectProcessingOrderArrayMaxCount); - - if (effect.ProcessingOrder > EffectProcessingOrderArrayMaxCount) - { - return isDirty; - } - - EffectProcessingOrderArray[(int)effect.ProcessingOrder] = i; - } - } - - return isDirty; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs b/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs deleted file mode 100644 index 893cc008..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs +++ /dev/null @@ -1,69 +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 . -// - -using Ryujinx.Audio.Renderer.Common; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Represents a detailed entry in a performance frame. - /// - public interface IPerformanceDetailEntry - { - /// - /// Get the start time of this entry event (in microseconds). - /// - /// The start time of this entry event (in microseconds). - int GetStartTime(); - - /// - /// Get the start time offset in this structure. - /// - /// The start time offset in this structure. - int GetStartTimeOffset(); - - /// - /// Get the processing time of this entry event (in microseconds). - /// - /// The processing time of this entry event (in microseconds). - int GetProcessingTime(); - - /// - /// Get the processing time offset in this structure. - /// - /// The processing time offset in this structure. - int GetProcessingTimeOffset(); - - /// - /// Set the of this entry. - /// - /// The node id of this entry. - void SetNodeId(int nodeId); - - /// - /// Set the of this entry. - /// - /// The type to use. - void SetEntryType(PerformanceEntryType type); - - /// - /// Set the of this entry. - /// - /// The type to use. - void SetDetailType(PerformanceDetailType detailType); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs b/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs deleted file mode 100644 index 2a2fa9cc..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs +++ /dev/null @@ -1,63 +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 . -// - -using Ryujinx.Audio.Renderer.Common; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Represents an entry in a performance frame. - /// - public interface IPerformanceEntry - { - /// - /// Get the start time of this entry event (in microseconds). - /// - /// The start time of this entry event (in microseconds). - int GetStartTime(); - - /// - /// Get the start time offset in this structure. - /// - /// The start time offset in this structure. - int GetStartTimeOffset(); - - /// - /// Get the processing time of this entry event (in microseconds). - /// - /// The processing time of this entry event (in microseconds). - int GetProcessingTime(); - - /// - /// Get the processing time offset in this structure. - /// - /// The processing time offset in this structure. - int GetProcessingTimeOffset(); - - /// - /// Set the of this entry. - /// - /// The node id of this entry. - void SetNodeId(int nodeId); - - /// - /// Set the of this entry. - /// - /// The type to use. - void SetEntryType(PerformanceEntryType type); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs b/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs deleted file mode 100644 index 5a26754d..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs +++ /dev/null @@ -1,97 +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 . -// - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// The header of a performance frame. - /// - public interface IPerformanceHeader - { - /// - /// Get the entry count offset in this structure. - /// - /// The entry count offset in this structure. - int GetEntryCountOffset(); - - /// - /// Set the DSP running behind flag. - /// - /// The flag. - void SetDspRunningBehind(bool isRunningBehind); - - /// - /// Set the count of voices that were dropped. - /// - /// The count of voices that were dropped. - void SetVoiceDropCount(uint voiceCount); - - /// - /// Set the start ticks of the . (before sending commands) - /// - /// The start ticks of the . (before sending commands) - void SetStartRenderingTicks(ulong startTicks); - - /// - /// Set the header magic. - /// - /// The header magic. - void SetMagic(uint magic); - - /// - /// Set the offset of the next performance header. - /// - /// The offset of the next performance header. - void SetNextOffset(int nextOffset); - - /// - /// Set the total time taken by all the commands profiled. - /// - /// The total time taken by all the commands profiled. - void SetTotalProcessingTime(int totalProcessingTime); - - /// - /// Set the index of this performance frame. - /// - /// The index of this performance frame. - void SetIndex(uint index); - - /// - /// Get the total count of entries in this frame. - /// - /// The total count of entries in this frame. - int GetEntryCount(); - - /// - /// Get the total count of detailed entries in this frame. - /// - /// The total count of detailed entries in this frame. - int GetEntryDetailCount(); - - /// - /// Set the total count of entries in this frame. - /// - /// The total count of entries in this frame. - void SetEntryCount(int entryCount); - - /// - /// Set the total count of detailed entries in this frame. - /// - /// The total count of detailed entries in this frame. - void SetEntryDetailCount(int entryDetailCount); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs deleted file mode 100644 index b7df7f28..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs +++ /dev/null @@ -1,89 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Implementation of for performance metrics version 1. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] - public struct PerformanceDetailVersion1 : IPerformanceDetailEntry - { - /// - /// The node id associated to this detailed entry. - /// - public int NodeId; - - /// - /// The start time (in microseconds) associated to this detailed entry. - /// - public int StartTime; - - /// - /// The processing time (in microseconds) associated to this detailed entry. - /// - public int ProcessingTime; - - /// - /// The detailed entry type associated to this detailed entry. - /// - public PerformanceDetailType DetailType; - - /// - /// The entry type associated to this detailed entry. - /// - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetDetailType(PerformanceDetailType detailType) - { - DetailType = detailType; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs deleted file mode 100644 index da898b29..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs +++ /dev/null @@ -1,89 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Implementation of for performance metrics version 2. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)] - public struct PerformanceDetailVersion2 : IPerformanceDetailEntry - { - /// - /// The node id associated to this detailed entry. - /// - public int NodeId; - - /// - /// The start time (in microseconds) associated to this detailed entry. - /// - public int StartTime; - - /// - /// The processing time (in microseconds) associated to this detailed entry. - /// - public int ProcessingTime; - - /// - /// The detailed entry type associated to this detailed entry. - /// - public PerformanceDetailType DetailType; - - /// - /// The entry type associated to this detailed entry. - /// - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetDetailType(PerformanceDetailType detailType) - { - DetailType = detailType; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs deleted file mode 100644 index ad99867f..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs +++ /dev/null @@ -1,73 +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 . -// - -using System; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Information used by the performance command to store informations in the performance entry. - /// - public class PerformanceEntryAddresses - { - /// - /// The memory storing the performance entry. - /// - public Memory BaseMemory; - - /// - /// The offset to the start time field. - /// - public uint StartTimeOffset; - - /// - /// The offset to the entry count field. - /// - public uint EntryCountOffset; - - /// - /// The offset to the processing time field. - /// - public uint ProcessingTimeOffset; - - /// - /// Increment the entry count. - /// - public void IncrementEntryCount() - { - BaseMemory.Span[(int)EntryCountOffset / 4]++; - } - - /// - /// Set the start time in the entry. - /// - /// The start time in nanoseconds. - public void SetStartTime(ulong startTimeNano) - { - BaseMemory.Span[(int)StartTimeOffset / 4] = (int)(startTimeNano / 1000); - } - - /// - /// Set the processing time in the entry. - /// - /// The end time in nanoseconds. - public void SetProcessingTime(ulong endTimeNano) - { - BaseMemory.Span[(int)ProcessingTimeOffset / 4] = (int)(endTimeNano / 1000) - BaseMemory.Span[(int)StartTimeOffset / 4]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs deleted file mode 100644 index ac91ca19..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs +++ /dev/null @@ -1,79 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Implementation of for performance metrics version 1. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] - public struct PerformanceEntryVersion1 : IPerformanceEntry - { - /// - /// The node id associated to this entry. - /// - public int NodeId; - - /// - /// The start time (in microseconds) associated to this entry. - /// - public int StartTime; - - /// - /// The processing time (in microseconds) associated to this entry. - /// - public int ProcessingTime; - - /// - /// The entry type associated to this entry. - /// - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs deleted file mode 100644 index 84ee5bc9..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs +++ /dev/null @@ -1,79 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Implementation of for performance metrics version 2. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)] - public struct PerformanceEntryVersion2 : IPerformanceEntry - { - /// - /// The node id associated to this entry. - /// - public int NodeId; - - /// - /// The start time (in microseconds) associated to this entry. - /// - public int StartTime; - - /// - /// The processing time (in microseconds) associated to this entry. - /// - public int ProcessingTime; - - /// - /// The entry type associated to this entry. - /// - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs deleted file mode 100644 index b0757b37..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs +++ /dev/null @@ -1,118 +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 . -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Implementation of for performance metrics version 1. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)] - public struct PerformanceFrameHeaderVersion1 : IPerformanceHeader - { - /// - /// The magic of the performance header. - /// - public uint Magic; - - /// - /// The total count of entries in this frame. - /// - public int EntryCount; - - /// - /// The total count of detailed entries in this frame. - /// - public int EntryDetailCount; - - /// - /// The offset of the next performance header. - /// - public int NextOffset; - - /// - /// The total time taken by all the commands profiled. - /// - public int TotalProcessingTime; - - /// - /// The count of voices that were dropped. - /// - public uint VoiceDropCount; - - public int GetEntryCount() - { - return EntryCount; - } - - public int GetEntryCountOffset() - { - return 4; - } - - public int GetEntryDetailCount() - { - return EntryDetailCount; - } - - public void SetDspRunningBehind(bool isRunningBehind) - { - // NOTE: Not present in version 1 - } - - public void SetEntryCount(int entryCount) - { - EntryCount = entryCount; - } - - public void SetEntryDetailCount(int entryDetailCount) - { - EntryDetailCount = entryDetailCount; - } - - public void SetIndex(uint index) - { - // NOTE: Not present in version 1 - } - - public void SetMagic(uint magic) - { - Magic = magic; - } - - public void SetNextOffset(int nextOffset) - { - NextOffset = nextOffset; - } - - public void SetStartRenderingTicks(ulong startTicks) - { - // NOTE: not present in version 1 - } - - public void SetTotalProcessingTime(int totalProcessingTime) - { - TotalProcessingTime = totalProcessingTime; - } - - public void SetVoiceDropCount(uint voiceCount) - { - VoiceDropCount = voiceCount; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs deleted file mode 100644 index ba873239..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs +++ /dev/null @@ -1,134 +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 . -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// Implementation of for performance metrics version 2. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x30)] - public struct PerformanceFrameHeaderVersion2 : IPerformanceHeader - { - /// - /// The magic of the performance header. - /// - public uint Magic; - - /// - /// The total count of entries in this frame. - /// - public int EntryCount; - - /// - /// The total count of detailed entries in this frame. - /// - public int EntryDetailCount; - - /// - /// The offset of the next performance header. - /// - public int NextOffset; - - /// - /// The total time taken by all the commands profiled. - /// - public int TotalProcessingTime; - - /// - /// The count of voices that were dropped. - /// - public uint VoiceDropCount; - - /// - /// The start ticks of the . (before sending commands) - /// - public ulong StartRenderingTicks; - - /// - /// The index of this performance frame. - /// - public uint Index; - - /// - /// If set to true, the DSP is running behind. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsDspRunningBehind; - - public int GetEntryCount() - { - return EntryCount; - } - - public int GetEntryCountOffset() - { - return 4; - } - - public int GetEntryDetailCount() - { - return EntryDetailCount; - } - - public void SetDspRunningBehind(bool isRunningBehind) - { - IsDspRunningBehind = isRunningBehind; - } - - public void SetEntryCount(int entryCount) - { - EntryCount = entryCount; - } - - public void SetEntryDetailCount(int entryDetailCount) - { - EntryDetailCount = entryDetailCount; - } - - public void SetIndex(uint index) - { - Index = index; - } - - public void SetMagic(uint magic) - { - Magic = magic; - } - - public void SetNextOffset(int nextOffset) - { - NextOffset = nextOffset; - } - - public void SetStartRenderingTicks(ulong startTicks) - { - StartRenderingTicks = startTicks; - } - - public void SetTotalProcessingTime(int totalProcessingTime) - { - TotalProcessingTime = totalProcessingTime; - } - - public void SetVoiceDropCount(uint voiceCount) - { - VoiceDropCount = voiceCount; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs deleted file mode 100644 index 3a336af3..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs +++ /dev/null @@ -1,124 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - public abstract class PerformanceManager - { - /// - /// Get the required size for a single performance frame. - /// - /// The audio renderer configuration. - /// The behaviour context. - /// The required size for a single performance frame. - public static ulong GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref AudioRendererConfiguration parameter, ref BehaviourContext behaviourContext) - { - uint version = behaviourContext.GetPerformanceMetricsDataFormat(); - - if (version == 2) - { - return (ulong)PerformanceManagerGeneric.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); - } - else if (version == 1) - { - return (ulong)PerformanceManagerGeneric.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); - } - - throw new NotImplementedException($"Unknown Performance metrics data format version {version}"); - } - - /// - /// Copy the performance frame history to the supplied user buffer and returns the size copied. - /// - /// The supplied user buffer to store the performance frame into. - /// The size copied to the supplied buffer. - public abstract uint CopyHistories(Span performanceOutput); - - /// - /// Set the target node id to profile. - /// - /// The target node id to profile. - public abstract void SetTargetNodeId(int target); - - /// - /// Check if the given target node id is profiled. - /// - /// The target node id to check. - /// Return true, if the given target node id is profiled. - public abstract bool IsTargetNodeId(int target); - - /// - /// Get the next buffer to store a performance entry. - /// - /// The output . - /// The info. - /// The node id of the entry. - /// Return true, if a valid was returned. - public abstract bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceEntryType entryType, int nodeId); - - /// - /// Get the next buffer to store a performance detailed entry. - /// - /// The output . - /// The info. - /// The info. - /// The node id of the entry. - /// Return true, if a valid was returned. - public abstract bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceDetailType detailType, PerformanceEntryType entryType, int nodeId); - - /// - /// Finalize the current performance frame. - /// - /// Indicate if the DSP is running behind. - /// The count of voices that were dropped. - /// The start ticks of the audio rendering. - public abstract void TapFrame(bool dspRunningBehind, uint voiceDropCount, ulong startRenderingTicks); - - /// - /// Create a new . - /// - /// The backing memory available for use by the manager. - /// The audio renderer configuration. - /// The behaviour context; - /// A new . - public static PerformanceManager Create(Memory performanceBuffer, ref AudioRendererConfiguration parameter, BehaviourContext behaviourContext) - { - uint version = behaviourContext.GetPerformanceMetricsDataFormat(); - - switch (version) - { - case 1: - return new PerformanceManagerGeneric(performanceBuffer, - ref parameter); - case 2: - return new PerformanceManagerGeneric(performanceBuffer, - ref parameter); - default: - throw new NotImplementedException($"Unknown Performance metrics data format version {version}"); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs deleted file mode 100644 index b17e6f3f..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs +++ /dev/null @@ -1,311 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// - /// A Generic implementation of . - /// - /// The header implementation of the performance frame. - /// The entry implementation of the performance frame. - /// A detailed implementation of the performance frame. - public class PerformanceManagerGeneric : PerformanceManager where THeader: unmanaged, IPerformanceHeader where TEntry : unmanaged, IPerformanceEntry where TEntryDetail: unmanaged, IPerformanceDetailEntry - { - /// - /// The magic used for the . - /// - private const uint MagicPerformanceBuffer = 0x46524550; - - /// - /// The fixed amount of that can be stored in a frame. - /// - private const int MaxFrameDetailCount = 100; - - private Memory _buffer; - private Memory _historyBuffer; - - private Memory CurrentBuffer => _buffer.Slice(0, _frameSize); - private Memory CurrentBufferData => CurrentBuffer.Slice(Unsafe.SizeOf()); - - private ref THeader CurrentHeader => ref MemoryMarshal.Cast(CurrentBuffer.Span)[0]; - - private Span Entries => MemoryMarshal.Cast(CurrentBufferData.Span.Slice(0, GetEntriesSize())); - private Span EntriesDetail => MemoryMarshal.Cast(CurrentBufferData.Span.Slice(GetEntriesSize(), GetEntriesDetailSize())); - - private int _frameSize; - private int _availableFrameCount; - private int _entryCountPerFrame; - private int _detailTarget; - private int _entryIndex; - private int _entryDetailIndex; - private int _indexHistoryWrite; - private int _indexHistoryRead; - private uint _historyFrameIndex; - - public PerformanceManagerGeneric(Memory buffer, ref AudioRendererConfiguration parameter) - { - _buffer = buffer; - _frameSize = GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); - - _entryCountPerFrame = (int)GetEntryCount(ref parameter); - _availableFrameCount = buffer.Length / _frameSize - 1; - - _historyFrameIndex = 0; - - _historyBuffer = _buffer.Slice(_frameSize); - - SetupNewHeader(); - } - - private Span GetBufferFromIndex(Span data, int index) - { - return data.Slice(index * _frameSize, _frameSize); - } - - private ref THeader GetHeaderFromBuffer(Span data, int index) - { - return ref MemoryMarshal.Cast(GetBufferFromIndex(data, index))[0]; - } - - private Span GetEntriesFromBuffer(Span data, int index) - { - return MemoryMarshal.Cast(GetBufferFromIndex(data, index).Slice(Unsafe.SizeOf(), GetEntriesSize())); - } - - private Span GetEntriesDetailFromBuffer(Span data, int index) - { - return MemoryMarshal.Cast(GetBufferFromIndex(data, index).Slice(Unsafe.SizeOf() + GetEntriesSize(), GetEntriesDetailSize())); - } - - private void SetupNewHeader() - { - _entryIndex = 0; - _entryDetailIndex = 0; - - CurrentHeader.SetEntryCount(0); - CurrentHeader.SetEntryDetailCount(0); - } - - public static uint GetEntryCount(ref AudioRendererConfiguration parameter) - { - return parameter.VoiceCount + parameter.EffectCount + parameter.SubMixBufferCount + parameter.SinkCount + 1; - } - - public int GetEntriesSize() - { - return Unsafe.SizeOf() * _entryCountPerFrame; - } - - public static int GetEntriesDetailSize() - { - return Unsafe.SizeOf() * MaxFrameDetailCount; - } - - public static int GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref AudioRendererConfiguration parameter) - { - return Unsafe.SizeOf() * (int)GetEntryCount(ref parameter) + GetEntriesDetailSize() + Unsafe.SizeOf(); - } - - public override uint CopyHistories(Span performanceOutput) - { - if (performanceOutput.IsEmpty) - { - return 0; - } - - int nextOffset = 0; - - while (_indexHistoryRead != _indexHistoryWrite) - { - if (nextOffset >= performanceOutput.Length) - { - break; - } - - ref THeader inputHeader = ref GetHeaderFromBuffer(_historyBuffer.Span, _indexHistoryRead); - Span inputEntries = GetEntriesFromBuffer(_historyBuffer.Span, _indexHistoryRead); - Span inputEntriesDetail = GetEntriesDetailFromBuffer(_historyBuffer.Span, _indexHistoryRead); - - Span targetSpan = performanceOutput.Slice(nextOffset); - - ref THeader outputHeader = ref MemoryMarshal.Cast(targetSpan)[0]; - - nextOffset += Unsafe.SizeOf(); - - Span outputEntries = MemoryMarshal.Cast(targetSpan.Slice(nextOffset)); - - int totalProcessingTime = 0; - - int effectiveEntryCount = 0; - - for (int entryIndex = 0; entryIndex < inputHeader.GetEntryCount(); entryIndex++) - { - ref TEntry input = ref inputEntries[entryIndex]; - - if (input.GetProcessingTime() != 0 || input.GetStartTime() != 0) - { - ref TEntry output = ref outputEntries[effectiveEntryCount++]; - - output = input; - - nextOffset += Unsafe.SizeOf(); - - totalProcessingTime += input.GetProcessingTime(); - } - } - - Span outputEntriesDetail = MemoryMarshal.Cast(targetSpan.Slice(nextOffset)); - - int effectiveEntryDetailCount = 0; - - for (int entryDetailIndex = 0; entryDetailIndex < inputHeader.GetEntryDetailCount(); entryDetailIndex++) - { - ref TEntryDetail input = ref inputEntriesDetail[entryDetailIndex]; - - if (input.GetProcessingTime() != 0 || input.GetStartTime() != 0) - { - ref TEntryDetail output = ref outputEntriesDetail[effectiveEntryDetailCount++]; - - output = input; - - nextOffset += Unsafe.SizeOf(); - } - } - - outputHeader = inputHeader; - outputHeader.SetMagic(MagicPerformanceBuffer); - outputHeader.SetTotalProcessingTime(totalProcessingTime); - outputHeader.SetNextOffset(nextOffset); - outputHeader.SetEntryCount(effectiveEntryCount); - outputHeader.SetEntryDetailCount(effectiveEntryDetailCount); - - _indexHistoryRead = (_indexHistoryRead + 1) % _availableFrameCount; - } - - if (nextOffset < performanceOutput.Length && (performanceOutput.Length - nextOffset) >= Unsafe.SizeOf()) - { - ref THeader outputHeader = ref MemoryMarshal.Cast(performanceOutput.Slice(nextOffset))[0]; - - outputHeader = default; - } - - return (uint)nextOffset; - } - - public override bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceEntryType entryType, int nodeId) - { - performanceEntry = new PerformanceEntryAddresses(); - performanceEntry.BaseMemory = SpanMemoryManager.Cast(CurrentBuffer); - performanceEntry.EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(); - - uint baseEntryOffset = (uint)(Unsafe.SizeOf() + Unsafe.SizeOf() * _entryIndex); - - ref TEntry entry = ref Entries[_entryIndex]; - - performanceEntry.StartTimeOffset = baseEntryOffset + (uint)entry.GetStartTimeOffset(); - performanceEntry.ProcessingTimeOffset = baseEntryOffset + (uint)entry.GetProcessingTimeOffset(); - - entry = default; - entry.SetEntryType(entryType); - entry.SetNodeId(nodeId); - - _entryIndex++; - - return true; - } - - public override bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceDetailType detailType, PerformanceEntryType entryType, int nodeId) - { - performanceEntry = null; - - if (_entryDetailIndex > MaxFrameDetailCount) - { - return false; - } - - performanceEntry = new PerformanceEntryAddresses(); - performanceEntry.BaseMemory = SpanMemoryManager.Cast(CurrentBuffer); - performanceEntry.EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(); - - uint baseEntryOffset = (uint)(Unsafe.SizeOf() + GetEntriesSize() + Unsafe.SizeOf() * _entryDetailIndex); - - ref TEntryDetail entryDetail = ref EntriesDetail[_entryDetailIndex]; - - performanceEntry.StartTimeOffset = baseEntryOffset + (uint)entryDetail.GetStartTimeOffset(); - performanceEntry.ProcessingTimeOffset = baseEntryOffset + (uint)entryDetail.GetProcessingTimeOffset(); - - entryDetail = default; - entryDetail.SetDetailType(detailType); - entryDetail.SetEntryType(entryType); - entryDetail.SetNodeId(nodeId); - - _entryDetailIndex++; - - return true; - } - - public override bool IsTargetNodeId(int target) - { - return _detailTarget == target; - } - - public override void SetTargetNodeId(int target) - { - _detailTarget = target; - } - - public override void TapFrame(bool dspRunningBehind, uint voiceDropCount, ulong startRenderingTicks) - { - if (_availableFrameCount > 0) - { - int targetIndexForHistory = _indexHistoryWrite; - - _indexHistoryWrite = (_indexHistoryWrite + 1) % _availableFrameCount; - - ref THeader targetHeader = ref GetHeaderFromBuffer(_historyBuffer.Span, targetIndexForHistory); - - CurrentBuffer.Span.CopyTo(GetBufferFromIndex(_historyBuffer.Span, targetIndexForHistory)); - - uint targetHistoryFrameIndex = _historyFrameIndex; - - if (_historyFrameIndex == uint.MaxValue) - { - _historyFrameIndex = 0; - } - else - { - _historyFrameIndex++; - } - - targetHeader.SetDspRunningBehind(dspRunningBehind); - targetHeader.SetVoiceDropCount(voiceDropCount); - targetHeader.SetStartRenderingTicks(startRenderingTicks); - targetHeader.SetIndex(targetHistoryFrameIndex); - - // Finally setup the new header - SetupNewHeader(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs b/Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs deleted file mode 100644 index a89a8a60..00000000 --- a/Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs +++ /dev/null @@ -1,65 +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 . -// - -using Ryujinx.Audio.Renderer.Server.Upsampler; -using System; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// Represents a lite version of used by the - /// - /// - /// This also allows to reduce dependencies on the for unit testing. - /// - public sealed class RendererSystemContext - { - /// - /// The session id of the current renderer. - /// - public int SessionId; - - /// - /// The target channel count for sink. - /// - /// See for usage. - public uint ChannelCount; - - /// - /// The total count of mix buffer. - /// - public uint MixBufferCount; - - /// - /// Instance of the used to derive bug fixes and features of the current audio renderer revision. - /// - public BehaviourContext BehaviourContext; - - /// - /// Instance of the used for upsampling (see ) - /// - public UpsamplerManager UpsamplerManager; - - /// - /// The memory to use for depop processing. - /// - /// - /// See and - /// - public Memory DepopBuffer; - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs b/Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs deleted file mode 100644 index 949e3971..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs +++ /dev/null @@ -1,119 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// - /// Base class used for server information of a sink. - /// - public class BaseSink - { - /// - /// The type of this . - /// - public SinkType Type; - - /// - /// Set to true if the sink is used. - /// - public bool IsUsed; - - /// - /// Set to true if the sink need to be skipped because of invalid state. - /// - public bool ShouldSkip; - - /// - /// The node id of the sink. - /// - public int NodeId; - - /// - /// Create a new . - /// - public BaseSink() - { - CleanUp(); - } - - /// - /// Clean up the internal state of the . - /// - public virtual void CleanUp() - { - Type = TargetSinkType; - IsUsed = false; - ShouldSkip = false; - } - - /// - /// The target handled by this . - /// - public virtual SinkType TargetSinkType => SinkType.Invalid; - - /// - /// Check if the sent by the user match the internal . - /// - /// The user parameter. - /// Return true, if the sent by the user match the internal . - public bool IsTypeValid(ref SinkInParameter parameter) - { - return parameter.Type == TargetSinkType; - } - - /// - /// Update the state during command generation. - /// - public virtual void UpdateForCommandGeneration() - { - Debug.Assert(Type == TargetSinkType); - } - - /// - /// Update the internal common parameters from user parameter. - /// - /// The user parameter. - protected void UpdateStandardParameter(ref SinkInParameter parameter) - { - if (IsUsed != parameter.IsUsed) - { - IsUsed = parameter.IsUsed; - NodeId = parameter.NodeId; - } - } - - /// - /// Update the internal state from user parameter. - /// - /// The possible that was generated. - /// The user parameter. - /// The user output status. - /// The mapper to use. - public virtual void Update(out ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - errorInfo = new ErrorInfo(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs b/Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs deleted file mode 100644 index 16d25a65..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs +++ /dev/null @@ -1,126 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Sink; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// - /// Server information for a circular buffer sink. - /// - public class CircularBufferSink : BaseSink - { - /// - /// The circular buffer parameter. - /// - public CircularBufferParameter Parameter; - - /// - /// The last written data offset on the circular buffer. - /// - private uint _lastWrittenOffset; - - /// - /// THe previous written offset of the circular buffer. - /// - private uint _oldWrittenOffset; - - /// - /// The current offset to write data on the circular buffer. - /// - public uint CurrentWriteOffset { get; private set; } - - /// - /// The of the circular buffer. - /// - public AddressInfo CircularBufferAddressInfo; - - public CircularBufferSink() - { - CircularBufferAddressInfo = AddressInfo.Create(); - } - - public override SinkType TargetSinkType => SinkType.CircularBuffer; - - public override void Update(out BehaviourParameter.ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) - { - errorInfo = new BehaviourParameter.ErrorInfo(); - outStatus = new SinkOutStatus(); - - Debug.Assert(IsTypeValid(ref parameter)); - - ref CircularBufferParameter inputDeviceParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; - - if (parameter.IsUsed != IsUsed || ShouldSkip) - { - UpdateStandardParameter(ref parameter); - - if (parameter.IsUsed) - { - Debug.Assert(CircularBufferAddressInfo.CpuAddress == 0); - Debug.Assert(CircularBufferAddressInfo.GetReference(false) == 0); - - ShouldSkip = !mapper.TryAttachBuffer(out errorInfo, ref CircularBufferAddressInfo, inputDeviceParameter.BufferAddress, inputDeviceParameter.BufferSize); - } - else - { - Debug.Assert(CircularBufferAddressInfo.CpuAddress != 0); - Debug.Assert(CircularBufferAddressInfo.GetReference(false) != 0); - } - - Parameter = inputDeviceParameter; - } - - outStatus.LastWrittenOffset = _lastWrittenOffset; - } - - public override void UpdateForCommandGeneration() - { - Debug.Assert(Type == TargetSinkType); - - if (IsUsed) - { - uint frameSize = RendererConstants.TargetSampleSize * Parameter.SampleCount * Parameter.InputCount; - - _lastWrittenOffset = _oldWrittenOffset; - - _oldWrittenOffset = CurrentWriteOffset; - - CurrentWriteOffset += frameSize; - - if (Parameter.BufferSize > 0) - { - CurrentWriteOffset %= Parameter.BufferSize; - } - } - } - - public override void CleanUp() - { - CircularBufferAddressInfo = AddressInfo.Create(); - _lastWrittenOffset = 0; - _oldWrittenOffset = 0; - CurrentWriteOffset = 0; - base.CleanUp(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs b/Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs deleted file mode 100644 index 79af05f7..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs +++ /dev/null @@ -1,92 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Sink; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Server.Upsampler; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// - /// Server information for a device sink. - /// - public class DeviceSink : BaseSink - { - /// - /// The downmix coefficients. - /// - public float[] DownMixCoefficients; - - /// - /// The device parameters. - /// - public DeviceParameter Parameter; - - /// - /// The upsampler instance used by this sink. - /// - /// Null if no upsampling is needed. - public UpsamplerState UpsamplerState; - - /// - /// Create a new . - /// - public DeviceSink() - { - DownMixCoefficients = new float[4]; - } - - public override void CleanUp() - { - UpsamplerState?.Release(); - - UpsamplerState = null; - - base.CleanUp(); - } - - public override SinkType TargetSinkType => SinkType.Device; - - public override void Update(out BehaviourParameter.ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref DeviceParameter inputDeviceParameter = ref MemoryMarshal.Cast(parameter.SpecificData)[0]; - - if (parameter.IsUsed != IsUsed) - { - UpdateStandardParameter(ref parameter); - Parameter = inputDeviceParameter; - } - else - { - Parameter.DownMixParameterEnabled = inputDeviceParameter.DownMixParameterEnabled; - inputDeviceParameter.DownMixParameter.ToSpan().CopyTo(Parameter.DownMixParameter.ToSpan()); - } - - Parameter.DownMixParameter.ToSpan().CopyTo(DownMixCoefficients.AsSpan()); - - errorInfo = new BehaviourParameter.ErrorInfo(); - outStatus = new SinkOutStatus(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs b/Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs deleted file mode 100644 index b57dbde9..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs +++ /dev/null @@ -1,73 +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 . -// - -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// - /// Sink context. - /// - public class SinkContext - { - /// - /// Storage for . - /// - private BaseSink[] _sinks; - - /// - /// The total sink count. - /// - private uint _sinkCount; - - /// - /// Initialize the . - /// - /// The total sink count. - public void Initialize(uint sinksCount) - { - _sinkCount = sinksCount; - _sinks = new BaseSink[_sinkCount]; - - for (int i = 0; i < _sinkCount; i++) - { - _sinks[i] = new BaseSink(); - } - } - - /// - /// Get the total sink count. - /// - /// The total sink count. - public uint GetCount() - { - return _sinkCount; - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref BaseSink GetSink(int id) - { - Debug.Assert(id >= 0 && id < _sinkCount); - - return ref _sinks[id]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs b/Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs deleted file mode 100644 index 0e107a53..00000000 --- a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs +++ /dev/null @@ -1,320 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Splitter -{ - /// - /// Splitter context. - /// - public class SplitterContext - { - /// - /// Storage for . - /// - private Memory _splitters; - - /// - /// Storage for . - /// - private Memory _splitterDestinations; - - /// - /// If set to true, trust the user destination count in . - /// - public bool IsBugFixed { get; private set; } - - /// - /// Initialize . - /// - /// The behaviour context. - /// The audio renderer configuration. - /// The . - /// Return true if the initialization was successful. - public bool Initialize(ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter, WorkBufferAllocator workBufferAllocator) - { - if (!behaviourContext.IsSplitterSupported() || parameter.SplitterCount <= 0 || parameter.SplitterDestinationCount <= 0) - { - Setup(Memory.Empty, Memory.Empty, false); - - return true; - } - - Memory splitters = workBufferAllocator.Allocate(parameter.SplitterCount, SplitterState.Alignment); - - if (splitters.IsEmpty) - { - return false; - } - - int splitterId = 0; - - foreach (ref SplitterState splitter in splitters.Span) - { - splitter = new SplitterState(splitterId++); - } - - Memory splitterDestinations = workBufferAllocator.Allocate(parameter.SplitterDestinationCount, - SplitterDestination.Alignment); - - if (splitterDestinations.IsEmpty) - { - return false; - } - - int splitterDestinationId = 0; - foreach (ref SplitterDestination data in splitterDestinations.Span) - { - data = new SplitterDestination(splitterDestinationId++); - } - - SplitterState.InitializeSplitters(splitters.Span); - - Setup(splitters, splitterDestinations, behaviourContext.IsSplitterBugFixed()); - - return true; - } - - /// - /// Get the work buffer size while adding the size needed for splitter to operate. - /// - /// The current size. - /// The behaviour context. - /// The renderer configuration. - /// Return the new size taking splitter into account. - public static ulong GetWorkBufferSize(ulong size, ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter) - { - if (behaviourContext.IsSplitterSupported()) - { - size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterCount, SplitterState.Alignment); - size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, SplitterDestination.Alignment); - - if (behaviourContext.IsSplitterBugFixed()) - { - size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, 0x10); - } - - return size; - } - else - { - return size; - } - } - - /// - /// Setup the instance. - /// - /// The storage. - /// The storage. - /// If set to true, trust the user destination count in . - private void Setup(Memory splitters, Memory splitterDestinations, bool isBugFixed) - { - _splitters = splitters; - _splitterDestinations = splitterDestinations; - IsBugFixed = isBugFixed; - } - - /// - /// Clear the new connection flag. - /// - private void ClearAllNewConnectionFlag() - { - foreach (ref SplitterState splitter in _splitters.Span) - { - splitter.ClearNewConnectionFlag(); - } - } - - /// - /// Get the destination count using the count of splitter. - /// - /// The destination count using the count of splitter. - public int GetDestinationCountPerStateForCompatibility() - { - if (_splitters.IsEmpty) - { - return 0; - } - - return _splitterDestinations.Length / _splitters.Length; - } - - /// - /// Update one or multiple from user parameters. - /// - /// The splitter header. - /// The raw data after the splitter header. - private void UpdateState(ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan input) - { - for (int i = 0; i < inputHeader.SplitterCount; i++) - { - SplitterInParameter parameter = MemoryMarshal.Read(input); - - Debug.Assert(parameter.IsMagicValid()); - - if (parameter.IsMagicValid()) - { - if (parameter.Id >= 0 && parameter.Id < _splitters.Length) - { - ref SplitterState splitter = ref GetState(parameter.Id); - - splitter.Update(this, ref parameter, input.Slice(Unsafe.SizeOf())); - } - - input = input.Slice(0x1C + (int)parameter.DestinationCount * 4); - } - } - } - - /// - /// Update one or multiple from user parameters. - /// - /// The splitter header. - /// The raw data after the splitter header. - private void UpdateData(ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan input) - { - for (int i = 0; i < inputHeader.SplitterDestinationCount; i++) - { - SplitterDestinationInParameter parameter = MemoryMarshal.Read(input); - - Debug.Assert(parameter.IsMagicValid()); - - if (parameter.IsMagicValid()) - { - if (parameter.Id >= 0 && parameter.Id < _splitterDestinations.Length) - { - ref SplitterDestination destination = ref GetDestination(parameter.Id); - - destination.Update(parameter); - } - - input = input.Slice(Unsafe.SizeOf()); - } - } - } - - /// - /// Update splitter from user parameters. - /// - /// The input raw user data. - /// The total consumed size. - /// Return true if the update was successful. - public bool Update(ReadOnlySpan input, out int consumedSize) - { - if (_splitterDestinations.IsEmpty || _splitters.IsEmpty) - { - consumedSize = 0; - - return true; - } - - int originalSize = input.Length; - - SplitterInParameterHeader header = SpanIOHelper.Read(ref input); - - if (header.IsMagicValid()) - { - ClearAllNewConnectionFlag(); - - UpdateState(ref header, ref input); - UpdateData(ref header, ref input); - - consumedSize = BitUtils.AlignUp(originalSize - input.Length, 0x10); - - return true; - } - else - { - consumedSize = 0; - - return false; - } - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref SplitterState GetState(int id) - { - return ref SpanIOHelper.GetFromMemory(_splitters, id, (uint)_splitters.Length); - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref SplitterDestination GetDestination(int id) - { - return ref SpanIOHelper.GetFromMemory(_splitterDestinations, id, (uint)_splitterDestinations.Length); - } - - /// - /// Get a at the given . - /// - /// The index to use. - /// A at the given . - public Memory GetDestinationMemory(int id) - { - return SpanIOHelper.GetMemory(_splitterDestinations, id, (uint)_splitterDestinations.Length); - } - - /// - /// Get a in the at and pass to . - /// - /// The index to use to get the . - /// The index of the . - /// A . - public Span GetDestination(int id, int destinationId) - { - ref SplitterState splitter = ref GetState(id); - - return splitter.GetData(destinationId); - } - - /// - /// Return true if the audio renderer has any splitters. - /// - /// True if the audio renderer has any splitters. - public bool UsingSplitter() - { - return !_splitters.IsEmpty && !_splitterDestinations.IsEmpty; - } - - /// - /// Update the internal state of all splitters. - /// - public void UpdateInternalState() - { - foreach (ref SplitterState splitter in _splitters.Span) - { - splitter.UpdateInternalState(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs b/Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs deleted file mode 100644 index 6d273e45..00000000 --- a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs +++ /dev/null @@ -1,210 +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 . -// - -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Common.Utilities; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Splitter -{ - /// - /// Server state for a splitter destination. - /// - [StructLayout(LayoutKind.Sequential, Size = 0xE0, Pack = Alignment)] - public struct SplitterDestination - { - public const int Alignment = 0x10; - - /// - /// The unique id of this . - /// - public int Id; - - /// - /// The mix to output the result of the splitter. - /// - public int DestinationId; - - /// - /// Mix buffer volumes storage. - /// - private MixArray _mix; - private MixArray _previousMix; - - /// - /// Pointer to the next linked element. - /// - private unsafe SplitterDestination* _next; - - /// - /// Set to true if in use. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - /// - /// Set to true if the internal state need to be updated. - /// - [MarshalAs(UnmanagedType.I1)] - public bool NeedToUpdateInternalState; - - [StructLayout(LayoutKind.Sequential, Size = 4 * RendererConstants.MixBufferCountMax, Pack = 1)] - private struct MixArray { } - - /// - /// Mix buffer volumes. - /// - /// Used when a splitter id is specified in the mix. - public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mix); - - /// - /// Previous mix buffer volumes. - /// - /// Used when a splitter id is specified in the mix. - public Span PreviousMixBufferVolume => SpanHelpers.AsSpan(ref _previousMix); - - /// - /// Get the of the next element or if not present. - /// - public Span Next - { - get - { - unsafe - { - return _next != null ? new Span(_next, 1) : Span.Empty; - } - } - } - - /// - /// Create a new . - /// - /// The unique id of this . - public SplitterDestination(int id) : this() - { - Id = id; - DestinationId = RendererConstants.UnusedMixId; - - ClearVolumes(); - } - - /// - /// Update the from user parameter. - /// - /// The user parameter. - public void Update(SplitterDestinationInParameter parameter) - { - Debug.Assert(Id == parameter.Id); - - if (parameter.IsMagicValid() && Id == parameter.Id) - { - DestinationId = parameter.DestinationId; - - parameter.MixBufferVolume.CopyTo(MixBufferVolume); - - if (!IsUsed && parameter.IsUsed) - { - MixBufferVolume.CopyTo(PreviousMixBufferVolume); - - NeedToUpdateInternalState = false; - } - - IsUsed = parameter.IsUsed; - } - } - - /// - /// Update the internal state of the instance. - /// - public void UpdateInternalState() - { - if (IsUsed && NeedToUpdateInternalState) - { - MixBufferVolume.CopyTo(PreviousMixBufferVolume); - } - - NeedToUpdateInternalState = false; - } - - /// - /// Set the update internal state marker. - /// - public void MarkAsNeedToUpdateInternalState() - { - NeedToUpdateInternalState = true; - } - - /// - /// Return true if the is used and has a destination. - /// - /// True if the is used and has a destination. - public bool IsConfigured() - { - return IsUsed && DestinationId != RendererConstants.UnusedMixId; - } - - /// - /// Get the volume for a given destination. - /// - /// The destination index to use. - /// The volume for the given destination. - public float GetMixVolume(int destinationIndex) - { - Debug.Assert(destinationIndex >= 0 && destinationIndex < RendererConstants.MixBufferCountMax); - - return MixBufferVolume[destinationIndex]; - } - - /// - /// Clear the volumes. - /// - public void ClearVolumes() - { - MixBufferVolume.Fill(0); - PreviousMixBufferVolume.Fill(0); - } - - /// - /// Link the next element to the given . - /// - /// The given to link. - public void Link(ref SplitterDestination next) - { - unsafe - { - fixed (SplitterDestination *nextPtr = &next) - { - _next = nextPtr; - } - } - } - - /// - /// Remove the link to the next element. - /// - public void Unlink() - { - unsafe - { - _next = null; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs b/Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs deleted file mode 100644 index c928ec53..00000000 --- a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs +++ /dev/null @@ -1,237 +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 . -// -using Ryujinx.Audio.Renderer.Parameter; -using System; -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Splitter -{ - /// - /// Server state for a splitter. - /// - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)] - public struct SplitterState - { - public const int Alignment = 0x10; - - /// - /// The unique id of this . - /// - public int Id; - - /// - /// Target sample rate to use on the splitter. - /// - public uint SampleRate; - - /// - /// Count of splitter destinations (). - /// - public int DestinationCount; - - /// - /// Set to true if the splitter has a new connection. - /// - [MarshalAs(UnmanagedType.I1)] - public bool HasNewConnection; - - /// - /// Linked list of . - /// - private unsafe SplitterDestination* _destinationsData; - - /// - /// Span to the first element of the linked list of . - /// - public Span Destinations - { - get - { - unsafe - { - return (IntPtr)_destinationsData != IntPtr.Zero ? new Span(_destinationsData, 1) : Span.Empty; - } - } - } - - /// - /// Create a new . - /// - /// The unique id of this . - public SplitterState(int id) : this() - { - Id = id; - } - - public Span GetData(int index) - { - int i = 0; - - Span result = Destinations; - - while (i < index) - { - if (result.IsEmpty) - { - break; - } - - result = result[0].Next; - i++; - } - - return result; - } - - /// - /// Clear the new connection flag. - /// - public void ClearNewConnectionFlag() - { - HasNewConnection = false; - } - - /// - /// Utility function to apply a given to all . - /// - /// The action to execute on each elements. - private void ForEachDestination(SpanAction action) - { - Span temp = Destinations; - - int i = 0; - - while (true) - { - if (temp.IsEmpty) - { - break; - } - - Span next = temp[0].Next; - - action.Invoke(temp, i++); - - temp = next; - } - } - - /// - /// Update the from user parameter. - /// - /// The splitter context. - /// The user parameter. - /// The raw input data after the . - public void Update(SplitterContext context, ref SplitterInParameter parameter, ReadOnlySpan input) - { - ClearLinks(); - - int destinationCount; - - if (context.IsBugFixed) - { - destinationCount = parameter.DestinationCount; - } - else - { - destinationCount = Math.Min(context.GetDestinationCountPerStateForCompatibility(), parameter.DestinationCount); - } - - if (destinationCount > 0) - { - ReadOnlySpan destinationIds = MemoryMarshal.Cast(input); - - Memory destination = context.GetDestinationMemory(destinationIds[0]); - - SetDestination(ref destination.Span[0]); - - DestinationCount = destinationCount; - - for (int i = 1; i < destinationCount; i++) - { - Memory nextDestination = context.GetDestinationMemory(destinationIds[i]); - - destination.Span[0].Link(ref nextDestination.Span[0]); - destination = nextDestination; - } - } - - Debug.Assert(parameter.Id == Id); - - if (parameter.Id == Id) - { - SampleRate = parameter.SampleRate; - HasNewConnection = true; - } - } - - /// - /// Set the head of the linked list of . - /// - /// A reference to a . - public void SetDestination(ref SplitterDestination newValue) - { - unsafe - { - fixed (SplitterDestination* newValuePtr = &newValue) - { - _destinationsData = newValuePtr; - } - } - } - - /// - /// Update the internal state of this instance. - /// - public void UpdateInternalState() - { - ForEachDestination((destination, _) => destination[0].UpdateInternalState()); - } - - /// - /// Clear all links from the . - /// - public void ClearLinks() - { - ForEachDestination((destination, _) => destination[0].Unlink()); - - unsafe - { - _destinationsData = (SplitterDestination*)IntPtr.Zero; - } - } - - /// - /// Initialize a given . - /// - /// All the to initialize. - public static void InitializeSplitters(Span splitters) - { - foreach (ref SplitterState splitter in splitters) - { - unsafe - { - splitter._destinationsData = (SplitterDestination*)IntPtr.Zero; - } - - splitter.DestinationCount = 0; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/StateUpdater.cs b/Ryujinx.Audio.Renderer/Server/StateUpdater.cs deleted file mode 100644 index b26e2721..00000000 --- a/Ryujinx.Audio.Renderer/Server/StateUpdater.cs +++ /dev/null @@ -1,575 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Performance; -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.Voice; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common.Logging; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class StateUpdater - { - private readonly ReadOnlyMemory _inputOrigin; - private ReadOnlyMemory _outputOrigin; - private ReadOnlyMemory _input; - - private Memory _output; - private uint _processHandle; - private BehaviourContext _behaviourContext; - - private UpdateDataHeader _inputHeader; - private Memory _outputHeader; - - private ref UpdateDataHeader OutputHeader => ref _outputHeader.Span[0]; - - public StateUpdater(ReadOnlyMemory input, Memory output, uint processHandle, BehaviourContext behaviourContext) - { - _input = input; - _inputOrigin = _input; - _output = output; - _outputOrigin = _output; - _processHandle = processHandle; - _behaviourContext = behaviourContext; - - _inputHeader = SpanIOHelper.Read(ref _input); - - _outputHeader = SpanMemoryManager.Cast(_output.Slice(0, Unsafe.SizeOf())); - OutputHeader.Initialize(_behaviourContext.UserRevision); - _output = _output.Slice(Unsafe.SizeOf()); - } - - public ResultCode UpdateBehaviourContext() - { - BehaviourParameter parameter = SpanIOHelper.Read(ref _input); - - if (!BehaviourContext.CheckValidRevision(parameter.UserRevision) || parameter.UserRevision != _behaviourContext.UserRevision) - { - return ResultCode.InvalidUpdateInfo; - } - - _behaviourContext.ClearError(); - _behaviourContext.UpdateFlags(parameter.Flags); - - if (_inputHeader.BehaviourSize != Unsafe.SizeOf()) - { - return ResultCode.InvalidUpdateInfo; - } - - return ResultCode.Success; - } - - public ResultCode UpdateMemoryPools(Span memoryPools) - { - PoolMapper mapper = new PoolMapper(_processHandle, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - if (memoryPools.Length * Unsafe.SizeOf() != _inputHeader.MemoryPoolsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - foreach (ref MemoryPoolState memoryPool in memoryPools) - { - MemoryPoolInParameter parameter = SpanIOHelper.Read(ref _input); - - ref MemoryPoolOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - PoolMapper.UpdateResult updateResult = mapper.Update(ref memoryPool, ref parameter, ref outStatus); - - if (updateResult != PoolMapper.UpdateResult.Success && - updateResult != PoolMapper.UpdateResult.MapError && - updateResult != PoolMapper.UpdateResult.UnmapError) - { - if (updateResult != PoolMapper.UpdateResult.InvalidParameter) - { - throw new InvalidOperationException($"{updateResult}"); - } - - return ResultCode.InvalidUpdateInfo; - } - } - - OutputHeader.MemoryPoolsSize = (uint)(Unsafe.SizeOf() * memoryPools.Length); - OutputHeader.TotalSize += OutputHeader.MemoryPoolsSize; - - return ResultCode.Success; - } - - public ResultCode UpdateVoiceChannelResources(VoiceContext context) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoiceResourcesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - for (int i = 0; i < context.GetCount(); i++) - { - VoiceChannelResourceInParameter parameter = SpanIOHelper.Read(ref _input); - - ref VoiceChannelResource resource = ref context.GetChannelResource(i); - - resource.Id = parameter.Id; - parameter.Mix.ToSpan().CopyTo(resource.Mix.ToSpan()); - resource.IsUsed = parameter.IsUsed; - } - - return ResultCode.Success; - } - - public ResultCode UpdateVoices(VoiceContext context, Memory memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoicesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.VoicesSize).Span); - - _input = _input.Slice((int)_inputHeader.VoicesSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - // First make everything not in use. - for (int i = 0; i < context.GetCount(); i++) - { - ref VoiceState state = ref context.GetState(i); - - state.InUse = false; - } - - // Start processing - for (int i = 0; i < context.GetCount(); i++) - { - VoiceInParameter parameter = parameters[i]; - - Memory[] voiceUpdateStates = new Memory[RendererConstants.VoiceChannelCountMax]; - - ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - if (parameter.InUse) - { - ref VoiceState currentVoiceState = ref context.GetState(i); - - for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++) - { - int channelId = parameter.ChannelResourceIds[channelResourceIndex]; - - Debug.Assert(channelId >= 0 && channelId < context.GetCount()); - - voiceUpdateStates[channelResourceIndex] = context.GetUpdateStateForCpu(channelId); - } - - if (parameter.IsNew) - { - currentVoiceState.Initialize(); - } - - currentVoiceState.UpdateParameters(out ErrorInfo updateParameterError, ref parameter, ref mapper, ref _behaviourContext); - - if (updateParameterError.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateParameterError); - } - - currentVoiceState.UpdateWaveBuffers(out ErrorInfo[] waveBufferUpdateErrorInfos, ref parameter, voiceUpdateStates, ref mapper, ref _behaviourContext); - - foreach (ref ErrorInfo errorInfo in waveBufferUpdateErrorInfos.AsSpan()) - { - if (errorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref errorInfo); - } - } - - currentVoiceState.WriteOutStatus(ref outStatus, ref parameter, voiceUpdateStates); - } - } - - int currentOutputSize = _output.Length; - - OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.VoicesSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.VoicesSize); - - return ResultCode.Success; - } - - private static void ResetEffect(ref BaseEffect effect, ref EffectInParameter parameter, PoolMapper mapper) - { - effect.ForceUnmapBuffers(mapper); - - switch (parameter.Type) - { - case EffectType.Invalid: - effect = new BaseEffect(); - break; - case EffectType.BufferMix: - effect = new BufferMixEffect(); - break; - case EffectType.AuxiliaryBuffer: - effect = new AuxiliaryBufferEffect(); - break; - case EffectType.Delay: - effect = new DelayEffect(); - break; - case EffectType.Reverb: - effect = new ReverbEffect(); - break; - case EffectType.Reverb3d: - effect = new Reverb3dEffect(); - break; - case EffectType.BiquadFilter: - effect = new BiquadFilterEffect(); - break; - default: - throw new NotImplementedException($"EffectType {parameter.Type} not implemented!"); - } - } - - public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, Memory memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.EffectsSize).Span); - - _input = _input.Slice((int)_inputHeader.EffectsSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - for (int i = 0; i < context.GetCount(); i++) - { - EffectInParameter parameter = parameters[i]; - - ref EffectOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - ref BaseEffect effect = ref context.GetEffect(i); - - if (!effect.IsTypeValid(ref parameter)) - { - ResetEffect(ref effect, ref parameter, mapper); - } - - effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - - effect.StoreStatus(ref outStatus, isAudioRendererActive); - } - - int currentOutputSize = _output.Length; - - OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.EffectsSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); - - return ResultCode.Success; - } - - public ResultCode UpdateSplitter(SplitterContext context) - { - if (context.Update(_input.Span, out int consumedSize)) - { - _input = _input.Slice(consumedSize); - - return ResultCode.Success; - } - else - { - return ResultCode.InvalidUpdateInfo; - } - } - - private bool CheckMixParametersValidity(MixContext mixContext, uint mixBufferCount, uint inputMixCount, ReadOnlySpan parameters) - { - uint maxMixStateCount = mixContext.GetCount(); - uint totalRequiredMixBufferCount = 0; - - for (int i = 0; i < inputMixCount; i++) - { - if (parameters[i].IsUsed) - { - if (parameters[i].DestinationMixId != RendererConstants.UnusedMixId && - parameters[i].DestinationMixId > maxMixStateCount && - parameters[i].MixId != RendererConstants.FinalMixId) - { - return true; - } - - totalRequiredMixBufferCount += parameters[i].BufferCount; - } - } - - return totalRequiredMixBufferCount > mixBufferCount; - } - - public ResultCode UpdateMixes(MixContext mixContext, uint mixBufferCount, EffectContext effectContext, SplitterContext splitterContext) - { - uint mixCount; - uint inputMixSize; - uint inputSize = 0; - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - MixInParameterDirtyOnlyUpdate parameter = MemoryMarshal.Cast(_input.Span)[0]; - - mixCount = parameter.MixCount; - - inputSize += (uint)Unsafe.SizeOf(); - } - else - { - mixCount = mixContext.GetCount(); - } - - inputMixSize = mixCount * (uint)Unsafe.SizeOf(); - - inputSize += inputMixSize; - - if (inputSize != _inputHeader.MixesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - _input = _input.Slice(Unsafe.SizeOf()); - } - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Span.Slice(0, (int)inputMixSize)); - - _input = _input.Slice((int)inputMixSize); - - if (CheckMixParametersValidity(mixContext, mixBufferCount, mixCount, parameters)) - { - return ResultCode.InvalidUpdateInfo; - } - - bool isMixContextDirty = false; - - for (int i = 0; i < parameters.Length; i++) - { - MixParameter parameter = parameters[i]; - - int mixId = i; - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - mixId = parameter.MixId; - } - - ref MixState mix = ref mixContext.GetState(mixId); - - if (parameter.IsUsed != mix.IsUsed) - { - mix.IsUsed = parameter.IsUsed; - - if (parameter.IsUsed) - { - mix.ClearEffectProcessingOrder(); - } - - isMixContextDirty = true; - } - - if (mix.IsUsed) - { - isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, ref parameter, effectContext, splitterContext, _behaviourContext); - } - } - - if (isMixContextDirty) - { - if (_behaviourContext.IsSplitterSupported() && splitterContext.UsingSplitter()) - { - if (!mixContext.Sort(splitterContext)) - { - return ResultCode.InvalidMixSorting; - } - } - else - { - mixContext.Sort(); - } - } - - return ResultCode.Success; - } - - private static void ResetSink(ref BaseSink sink, ref SinkInParameter parameter) - { - sink.CleanUp(); - - switch (parameter.Type) - { - case SinkType.Invalid: - sink = new BaseSink(); - break; - case SinkType.CircularBuffer: - sink = new CircularBufferSink(); - break; - case SinkType.Device: - sink = new DeviceSink(); - break; - default: - throw new NotImplementedException($"SinkType {parameter.Type} not implemented!"); - } - } - - public ResultCode UpdateSinks(SinkContext context, Memory memoryPools) - { - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.SinksSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.SinksSize).Span); - - _input = _input.Slice((int)_inputHeader.SinksSize); - - for (int i = 0; i < context.GetCount(); i++) - { - SinkInParameter parameter = parameters[i]; - ref SinkOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - ref BaseSink sink = ref context.GetSink(i); - - if (!sink.IsTypeValid(ref parameter)) - { - ResetSink(ref sink, ref parameter); - } - - sink.Update(out ErrorInfo updateErrorInfo, ref parameter, ref outStatus, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - } - - int currentOutputSize = _output.Length; - - OutputHeader.SinksSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.SinksSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.SinksSize); - - return ResultCode.Success; - } - - public ResultCode UpdatePerformanceBuffer(PerformanceManager manager, Span performanceOutput) - { - if (Unsafe.SizeOf() != _inputHeader.PerformanceBufferSize) - { - return ResultCode.InvalidUpdateInfo; - } - - PerformanceInParameter parameter = SpanIOHelper.Read(ref _input); - - ref PerformanceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - if (manager != null) - { - outStatus.HistorySize = manager.CopyHistories(performanceOutput); - - manager.SetTargetNodeId(parameter.TargetNodeId); - } - else - { - outStatus.HistorySize = 0; - } - - OutputHeader.PerformanceBufferSize = (uint)Unsafe.SizeOf(); - OutputHeader.TotalSize += OutputHeader.PerformanceBufferSize; - - return ResultCode.Success; - } - - public ResultCode UpdateErrorInfo() - { - ref BehaviourErrorInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - _behaviourContext.CopyErrorInfo(outStatus.ErrorInfos.ToSpan(), out outStatus.ErrorInfosCount); - - OutputHeader.BehaviourSize = (uint)Unsafe.SizeOf(); - OutputHeader.TotalSize += OutputHeader.BehaviourSize; - - return ResultCode.Success; - } - - public ResultCode UpdateRendererInfo(ulong elapsedFrameCount) - { - ref RendererInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - outStatus.ElapsedFrameCount = elapsedFrameCount; - - OutputHeader.RenderInfoSize = (uint)Unsafe.SizeOf(); - OutputHeader.TotalSize += OutputHeader.RenderInfoSize; - - return ResultCode.Success; - } - - public ResultCode CheckConsumedSize() - { - int consumedInputSize = _inputOrigin.Length - _input.Length; - int consumedOutputSize = _outputOrigin.Length - _output.Length; - - if (consumedInputSize != _inputHeader.TotalSize) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Consumed input size mismatch (got {consumedInputSize} expected {_inputHeader.TotalSize})"); - - return ResultCode.InvalidUpdateInfo; - } - - if (consumedOutputSize != OutputHeader.TotalSize) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Consumed output size mismatch (got {consumedOutputSize} expected {OutputHeader.TotalSize})"); - - return ResultCode.InvalidUpdateInfo; - } - - return ResultCode.Success; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs b/Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs deleted file mode 100644 index 7bb0507c..00000000 --- a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs +++ /dev/null @@ -1,36 +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 . -// - -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// - /// The execution mode of an . - /// - public enum AudioRendererExecutionMode : byte - { - /// - /// Automatically send commands to the DSP at a fixed rate (see - /// - Auto, - - /// - /// Audio renderer operation needs to be done manually via ExecuteAudioRenderer. - /// - /// This is not supported on the DSP and is as such stubbed. - Manual - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs b/Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs deleted file mode 100644 index f89086f6..00000000 --- a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs +++ /dev/null @@ -1,41 +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 . -// - -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// - /// The rendering device of an . - /// - public enum AudioRendererRenderingDevice : byte - { - /// - /// Rendering is performed on the DSP. - /// - /// - /// Only supports . - /// - Dsp, - - /// - /// Rendering is performed on the CPU. - /// - /// - /// Only supports . - /// - Cpu - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Types/PlayState.cs b/Ryujinx.Audio.Renderer/Server/Types/PlayState.cs deleted file mode 100644 index 7f8895c9..00000000 --- a/Ryujinx.Audio.Renderer/Server/Types/PlayState.cs +++ /dev/null @@ -1,56 +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 . -// - -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// - /// The internal play state of a - /// - public enum PlayState - { - /// - /// The voice has been started and is playing. - /// - Started, - - /// - /// The voice has been stopped. - /// - /// - /// This cannot be directly set by user. - /// See for correct usage. - /// - Stopped, - - /// - /// The user asked the voice to be stopped. - /// - /// - /// This is changed to the state after command generation. - /// - /// - Stopping, - - /// - /// The voice has been paused by user request. - /// - /// - /// The user can resume to the state. - /// - Paused - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs b/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs deleted file mode 100644 index fd396d9f..00000000 --- a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs +++ /dev/null @@ -1,101 +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 . -// - -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Upsampler -{ - /// - /// Upsampler manager. - /// - public class UpsamplerManager - { - /// - /// Work buffer for upsampler. - /// - private Memory _upSamplerWorkBuffer; - - /// - /// Global lock of the object. - /// - private object Lock = new object(); - - /// - /// The upsamplers instances. - /// - private UpsamplerState[] _upsamplers; - - /// - /// The count of upsamplers. - /// - private uint _count; - - /// - /// Create a new . - /// - /// Work buffer for upsampler. - /// The count of upsamplers. - public UpsamplerManager(Memory upSamplerWorkBuffer, uint count) - { - _upSamplerWorkBuffer = upSamplerWorkBuffer; - _count = count; - - _upsamplers = new UpsamplerState[_count]; - } - - /// - /// Allocate a new . - /// - /// A new or null if out of memory. - public UpsamplerState Allocate() - { - int workBufferOffset = 0; - - lock (Lock) - { - for (int i = 0; i < _count; i++) - { - if (_upsamplers[i] == null) - { - _upsamplers[i] = new UpsamplerState(this, i, _upSamplerWorkBuffer.Slice(workBufferOffset, RendererConstants.UpSampleEntrySize), RendererConstants.TargetSampleCount); - - return _upsamplers[i]; - } - - workBufferOffset += RendererConstants.UpSampleEntrySize; - } - } - - return null; - } - - /// - /// Free a at the given index. - /// - /// The index of the to free. - public void Free(int index) - { - lock (Lock) - { - Debug.Assert(_upsamplers[index] != null); - - _upsamplers[index] = null; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs b/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs deleted file mode 100644 index 8ea55384..00000000 --- a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs +++ /dev/null @@ -1,80 +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 . -// - -using System; - -namespace Ryujinx.Audio.Renderer.Server.Upsampler -{ - /// - /// Server state for a upsampling. - /// - public class UpsamplerState - { - /// - /// The output buffer containing the target samples. - /// - public Memory OutputBuffer { get; } - - /// - /// The target sample count. - /// - public uint SampleCount { get; } - - /// - /// The index of the . (used to free it) - /// - private int _index; - - /// - /// The . - /// - private UpsamplerManager _manager; - - /// - /// The source sample count. - /// - public uint SourceSampleCount; - - /// - /// The input buffer indices of the buffers holding the samples that need upsampling. - /// - public ushort[] InputBufferIndices; - - /// - /// Create a new . - /// - /// The upsampler manager. - /// The index of the . (used to free it) - /// The output buffer used to contain the target samples. - /// The target sample count. - public UpsamplerState(UpsamplerManager manager, int index, Memory outputBuffer, uint sampleCount) - { - _manager = manager; - _index = index; - OutputBuffer = outputBuffer; - SampleCount = sampleCount; - } - - /// - /// Release the . - /// - public void Release() - { - _manager.Free(_index); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs b/Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs deleted file mode 100644 index 00520cfc..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs +++ /dev/null @@ -1,57 +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 . -// - -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// - /// Server state for a voice channel resource. - /// - [StructLayout(LayoutKind.Sequential, Size = 0xD0, Pack = Alignment)] - public struct VoiceChannelResource - { - public const int Alignment = 0x10; - - /// - /// Mix volumes for the resource. - /// - public Array24 Mix; - - /// - /// Previous mix volumes for resource. - /// - public Array24 PreviousMix; - - /// - /// The id of the resource. - /// - public uint Id; - - /// - /// Indicate if the resource is used. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - public void UpdateState() - { - Mix.ToSpan().CopyTo(PreviousMix.ToSpan()); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs b/Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs deleted file mode 100644 index 0dfaa4d5..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs +++ /dev/null @@ -1,166 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// - /// Voice context. - /// - public class VoiceContext - { - /// - /// Storage of the sorted indices to . - /// - private Memory _sortedVoices; - - /// - /// Storage for . - /// - private Memory _voices; - - /// - /// Storage for . - /// - private Memory _voiceChannelResources; - - /// - /// Storage for that are used during audio renderer server updates. - /// - private Memory _voiceUpdateStatesCpu; - - /// - /// Storage for for the . - /// - private Memory _voiceUpdateStatesDsp; - - /// - /// The total voice count. - /// - private uint _voiceCount; - - public void Initialize(Memory sortedVoices, Memory voices, Memory voiceChannelResources, Memory voiceUpdateStatesCpu, Memory voiceUpdateStatesDsp, uint voiceCount) - { - _sortedVoices = sortedVoices; - _voices = voices; - _voiceChannelResources = voiceChannelResources; - _voiceUpdateStatesCpu = voiceUpdateStatesCpu; - _voiceUpdateStatesDsp = voiceUpdateStatesDsp; - _voiceCount = voiceCount; - } - - /// - /// Get the total voice count. - /// - /// The total voice count. - public uint GetCount() - { - return _voiceCount; - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref VoiceChannelResource GetChannelResource(int id) - { - return ref SpanIOHelper.GetFromMemory(_voiceChannelResources, id, _voiceCount); - } - - /// - /// Get a at the given . - /// - /// The index to use. - /// A at the given . - /// The returned should only be used when updating the server state. - public Memory GetUpdateStateForCpu(int id) - { - return SpanIOHelper.GetMemory(_voiceUpdateStatesCpu, id, _voiceCount); - } - - /// - /// Get a at the given . - /// - /// The index to use. - /// A at the given . - /// The returned should only be used in the context of processing on the . - public Memory GetUpdateStateForDsp(int id) - { - return SpanIOHelper.GetMemory(_voiceUpdateStatesDsp, id, _voiceCount); - } - - /// - /// Get a reference to a at the given . - /// - /// The index to use. - /// A reference to a at the given . - public ref VoiceState GetState(int id) - { - return ref SpanIOHelper.GetFromMemory(_voices, id, _voiceCount); - } - - public ref VoiceState GetSortedState(int id) - { - Debug.Assert(id >= 0 && id < _voiceCount); - - return ref GetState(_sortedVoices.Span[id]); - } - - /// - /// Update internal state during command generation. - /// - public void UpdateForCommandGeneration() - { - _voiceUpdateStatesDsp.CopyTo(_voiceUpdateStatesCpu); - } - - /// - /// Sort the internal voices by priority and sorting order (if the priorities match). - /// - public void Sort() - { - for (int i = 0; i < _voiceCount; i++) - { - _sortedVoices.Span[i] = i; - } - - int[] sortedVoicesTemp = _sortedVoices.Slice(0, (int)GetCount()).ToArray(); - - Array.Sort(sortedVoicesTemp, (a, b) => - { - ref VoiceState aState = ref GetState(a); - ref VoiceState bState = ref GetState(b); - - int result = aState.Priority.CompareTo(bState.Priority); - - if (result == 0) - { - return aState.SortingOrder.CompareTo(bState.SortingOrder); - } - - return result; - }); - - sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs b/Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs deleted file mode 100644 index f30ee2f7..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs +++ /dev/null @@ -1,715 +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 . -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Common.Memory; -using Ryujinx.Common.Utilities; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - [StructLayout(LayoutKind.Sequential, Pack = Alignment)] - public struct VoiceState - { - public const int Alignment = 0x10; - - /// - /// Set to true if the voice is used. - /// - [MarshalAs(UnmanagedType.I1)] - public bool InUse; - - /// - /// Set to true if the voice is new. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsNew; - - [MarshalAs(UnmanagedType.I1)] - public bool WasPlaying; - - /// - /// The of the voice. - /// - public SampleFormat SampleFormat; - - /// - /// The sample rate of the voice. - /// - public uint SampleRate; - - /// - /// The total channel count used. - /// - public uint ChannelsCount; - - /// - /// Id of the voice. - /// - public int Id; - - /// - /// Node id of the voice. - /// - public int NodeId; - - /// - /// The target mix id of the voice. - /// - public int MixId; - - /// - /// The current voice . - /// - public Types.PlayState PlayState; - - /// - /// The previous voice . - /// - public Types.PlayState PreviousPlayState; - - /// - /// The priority of the voice. - /// - public uint Priority; - - /// - /// Target sorting position of the voice. (used to sort voice with the same ) - /// - public uint SortingOrder; - - /// - /// The pitch used on the voice. - /// - public float Pitch; - - /// - /// The output volume of the voice. - /// - public float Volume; - - /// - /// The previous output volume of the voice. - /// - public float PreviousVolume; - - /// - /// Biquad filters to apply to the output of the voice. - /// - public Array2 BiquadFilters; - - /// - /// Total count of of the voice. - /// - public uint WaveBuffersCount; - - /// - /// Current playing of the voice. - /// - public uint WaveBuffersIndex; - - /// - /// Change the behaviour of the voice. - /// - /// This was added on REV5. - public DecodingBehaviour DecodingBehaviour; - - /// - /// User state required by the data source. - /// - /// Only used for as the GC-ADPCM coefficients. - public AddressInfo DataSourceStateAddressInfo; - - /// - /// The wavebuffers of this voice. - /// - public Array4 WaveBuffers; - - /// - /// The channel resource ids associated to the voice. - /// - public Array6 ChannelResourceIds; - - /// - /// The target splitter id of the voice. - /// - public uint SplitterId; - - /// - /// Change the Sample Rate Conversion (SRC) quality of the voice. - /// - /// This was added on REV8. - public SampleRateConversionQuality SrcQuality; - - /// - /// If set to true, the voice was dropped. - /// - [MarshalAs(UnmanagedType.I1)] - public bool VoiceDropFlag; - - /// - /// Set to true if the data source state work buffer wasn't mapped. - /// - [MarshalAs(UnmanagedType.I1)] - public bool DataSourceStateUnmapped; - - /// - /// Set to true if any of the work buffer wasn't mapped. - /// - [MarshalAs(UnmanagedType.I1)] - public bool BufferInfoUnmapped; - - /// - /// The biquad filter initialization state storage. - /// - private BiquadFilterNeedInitializationArrayStruct _biquadFilterNeedInitialization; - - /// - /// Flush the amount of wavebuffer specified. This will result in the wavebuffer being skipped and marked played. - /// - /// This was added on REV5. - public byte FlushWaveBufferCount; - - [StructLayout(LayoutKind.Sequential, Size = RendererConstants.VoiceBiquadFilterCount)] - private struct BiquadFilterNeedInitializationArrayStruct { } - - /// - /// The biquad filter initialization state array. - /// - public Span BiquadFilterNeedInitialization => SpanHelpers.AsSpan(ref _biquadFilterNeedInitialization); - - /// - /// Initialize the . - /// - public void Initialize() - { - IsNew = false; - VoiceDropFlag = false; - DataSourceStateUnmapped = false; - BufferInfoUnmapped = false; - FlushWaveBufferCount = 0; - PlayState = Types.PlayState.Stopped; - Priority = RendererConstants.VoiceLowestPriority; - Id = 0; - NodeId = 0; - SampleRate = 0; - SampleFormat = SampleFormat.Invalid; - ChannelsCount = 0; - Pitch = 0.0f; - Volume= 0.0f; - PreviousVolume = 0.0f; - BiquadFilters.ToSpan().Fill(new BiquadFilterParameter()); - WaveBuffersCount = 0; - WaveBuffersIndex = 0; - MixId = RendererConstants.UnusedMixId; - SplitterId = RendererConstants.UnusedSplitterId; - DataSourceStateAddressInfo.Setup(0, 0); - - InitializeWaveBuffers(); - } - - /// - /// Initialize the in this . - /// - private void InitializeWaveBuffers() - { - for (int i = 0; i < WaveBuffers.Length; i++) - { - WaveBuffers[i].StartSampleOffset = 0; - WaveBuffers[i].EndSampleOffset = 0; - WaveBuffers[i].ShouldLoop = false; - WaveBuffers[i].IsEndOfStream = false; - WaveBuffers[i].BufferAddressInfo.Setup(0, 0); - WaveBuffers[i].ContextAddressInfo.Setup(0, 0); - WaveBuffers[i].IsSendToAudioProcessor = true; - } - } - - /// - /// Check if the voice needs to be skipped. - /// - /// Returns true if the voice needs to be skipped. - public bool ShouldSkip() - { - return !InUse || WaveBuffersCount == 0 || DataSourceStateUnmapped || BufferInfoUnmapped || VoiceDropFlag; - } - - /// - /// Return true if the mix has any destinations. - /// - /// True if the mix has any destinations. - public bool HasAnyDestination() - { - return MixId != RendererConstants.UnusedMixId || SplitterId != RendererConstants.UnusedSplitterId; - } - - /// - /// Indicate if the server voice information needs to be updated. - /// - /// The user parameter. - /// Return true, if the server voice information needs to be updated. - private bool ShouldUpdateParameters(ref VoiceInParameter parameter) - { - if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress) - { - return DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize; - } - - return DataSourceStateAddressInfo.CpuAddress != parameter.DataSourceStateAddress || - DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize || - DataSourceStateUnmapped; - } - - /// - /// Update the internal state from a user parameter. - /// - /// The possible that was generated. - /// The user parameter. - /// The mapper to use. - /// The behaviour context. - public void UpdateParameters(out ErrorInfo outErrorInfo, ref VoiceInParameter parameter, ref PoolMapper poolMapper, ref BehaviourContext behaviourContext) - { - InUse = parameter.InUse; - Id = parameter.Id; - NodeId = parameter.NodeId; - - UpdatePlayState(parameter.PlayState); - - SrcQuality = parameter.SrcQuality; - - Priority = parameter.Priority; - SortingOrder = parameter.SortingOrder; - SampleRate = parameter.SampleRate; - SampleFormat = parameter.SampleFormat; - ChannelsCount = parameter.ChannelCount; - Pitch = parameter.Pitch; - Volume = parameter.Volume; - parameter.BiquadFilters.ToSpan().CopyTo(BiquadFilters.ToSpan()); - WaveBuffersCount = parameter.WaveBuffersCount; - WaveBuffersIndex = parameter.WaveBuffersIndex; - - if (behaviourContext.IsFlushVoiceWaveBuffersSupported()) - { - FlushWaveBufferCount += parameter.FlushWaveBufferCount; - } - - MixId = parameter.MixId; - - if (behaviourContext.IsSplitterSupported()) - { - SplitterId = parameter.SplitterId; - } - else - { - SplitterId = RendererConstants.UnusedSplitterId; - } - - parameter.ChannelResourceIds.ToSpan().CopyTo(ChannelResourceIds.ToSpan()); - - DecodingBehaviour behaviour = DecodingBehaviour.Default; - - if (behaviourContext.IsDecodingBehaviourFlagSupported()) - { - behaviour = parameter.DecodingBehaviourFlags; - } - - DecodingBehaviour = behaviour; - - if (parameter.ResetVoiceDropFlag) - { - VoiceDropFlag = false; - } - - if (ShouldUpdateParameters(ref parameter)) - { - DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize); - } - else - { - outErrorInfo = new ErrorInfo(); - } - } - - /// - /// Update the internal play state from user play state. - /// - /// The target user play state. - public void UpdatePlayState(PlayState userPlayState) - { - Types.PlayState oldServerPlayState = PlayState; - - PreviousPlayState = oldServerPlayState; - - Types.PlayState newServerPlayState; - - switch (userPlayState) - { - case Common.PlayState.Start: - newServerPlayState = Types.PlayState.Started; - break; - - case Common.PlayState.Stop: - if (oldServerPlayState == Types.PlayState.Stopped) - { - return; - } - - newServerPlayState = Types.PlayState.Stopping; - break; - - case Common.PlayState.Pause: - newServerPlayState = Types.PlayState.Paused; - break; - - default: - throw new NotImplementedException($"Unhandled PlayState.{userPlayState}"); - } - - PlayState = newServerPlayState; - } - - /// - /// Write the status of the voice to the given user output. - /// - /// The given user output. - /// The user parameter. - /// The voice states associated to the . - public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, Memory[] voiceUpdateStates) - { -#if DEBUG - // Sanity check in debug mode of the internal state - if (!parameter.IsNew && !IsNew) - { - for (int i = 1; i < ChannelsCount; i++) - { - ref VoiceUpdateState stateA = ref voiceUpdateStates[i - 1].Span[0]; - ref VoiceUpdateState stateB = ref voiceUpdateStates[i].Span[0]; - - Debug.Assert(stateA.WaveBufferConsumed == stateB.WaveBufferConsumed); - Debug.Assert(stateA.PlayedSampleCount == stateB.PlayedSampleCount); - Debug.Assert(stateA.Offset == stateB.Offset); - Debug.Assert(stateA.WaveBufferIndex == stateB.WaveBufferIndex); - Debug.Assert(stateA.Fraction == stateB.Fraction); - Debug.Assert(stateA.IsWaveBufferValid.SequenceEqual(stateB.IsWaveBufferValid)); - } - } -#endif - if (parameter.IsNew || IsNew) - { - IsNew = true; - - outStatus.VoiceDropFlag = false; - outStatus.PlayedWaveBuffersCount = 0; - outStatus.PlayedSampleCount = 0; - } - else - { - ref VoiceUpdateState state = ref voiceUpdateStates[0].Span[0]; - - outStatus.VoiceDropFlag = VoiceDropFlag; - outStatus.PlayedWaveBuffersCount = state.WaveBufferConsumed; - outStatus.PlayedSampleCount = state.PlayedSampleCount; - } - } - - /// - /// Update the internal state of all the of the . - /// - /// An array of used to report errors when mapping any of the . - /// The user parameter. - /// The voice states associated to the . - /// The mapper to use. - /// The behaviour context. - public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, Memory[] voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext) - { - errorInfos = new ErrorInfo[RendererConstants.VoiceWaveBufferCount * 2]; - - if (parameter.IsNew) - { - InitializeWaveBuffers(); - - for (int i = 0; i < parameter.ChannelCount; i++) - { - voiceUpdateStates[i].Span[0].IsWaveBufferValid.Fill(false); - } - } - - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0]; - - for (int i = 0; i < RendererConstants.VoiceWaveBufferCount; i++) - { - UpdateWaveBuffer(errorInfos.AsSpan().Slice(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], ref mapper, ref behaviourContext); - } - } - - /// - /// Update the internal state of one of the of the . - /// - /// A used to report errors when mapping the . - /// The to update. - /// The from the user input. - /// The from the user input. - /// If set to true, the server side wavebuffer is considered valid. - /// The mapper to use. - /// The behaviour context. - private void UpdateWaveBuffer(Span errorInfos, ref WaveBuffer waveBuffer, ref WaveBufferInternal inputWaveBuffer, SampleFormat sampleFormat, bool isValid, ref PoolMapper mapper, ref BehaviourContext behaviourContext) - { - if (!isValid && waveBuffer.IsSendToAudioProcessor && waveBuffer.BufferAddressInfo.CpuAddress != 0) - { - mapper.ForceUnmap(ref waveBuffer.BufferAddressInfo); - waveBuffer.BufferAddressInfo.Setup(0, 0); - } - - if (!inputWaveBuffer.SentToServer || BufferInfoUnmapped) - { - if (inputWaveBuffer.IsSampleOffsetValid(sampleFormat)) - { - Debug.Assert(waveBuffer.IsSendToAudioProcessor); - - waveBuffer.IsSendToAudioProcessor = false; - waveBuffer.StartSampleOffset = inputWaveBuffer.StartSampleOffset; - waveBuffer.EndSampleOffset = inputWaveBuffer.EndSampleOffset; - waveBuffer.ShouldLoop = inputWaveBuffer.ShouldLoop; - waveBuffer.IsEndOfStream = inputWaveBuffer.IsEndOfStream; - waveBuffer.LoopStartSampleOffset = inputWaveBuffer.LoopFirstSampleOffset; - waveBuffer.LoopEndSampleOffset = inputWaveBuffer.LoopLastSampleOffset; - waveBuffer.LoopCount = inputWaveBuffer.LoopCount; - - BufferInfoUnmapped = !mapper.TryAttachBuffer(out ErrorInfo bufferInfoError, ref waveBuffer.BufferAddressInfo, inputWaveBuffer.Address, inputWaveBuffer.Size); - - errorInfos[0] = bufferInfoError; - - if (sampleFormat == SampleFormat.Adpcm && behaviourContext.IsAdpcmLoopContextBugFixed() && inputWaveBuffer.ContextAddress != 0) - { - bool adpcmLoopContextMapped = mapper.TryAttachBuffer(out ErrorInfo adpcmLoopContextInfoError, - ref waveBuffer.ContextAddressInfo, - inputWaveBuffer.ContextAddress, - inputWaveBuffer.ContextSize); - - errorInfos[1] = adpcmLoopContextInfoError; - - if (adpcmLoopContextMapped) - { - BufferInfoUnmapped = DataSourceStateUnmapped; - } - else - { - BufferInfoUnmapped = true; - } - } - else - { - waveBuffer.ContextAddressInfo.Setup(0, 0); - } - } - else - { - errorInfos[0].ErrorCode = ResultCode.InvalidAddressInfo; - errorInfos[0].ExtraErrorInfo = inputWaveBuffer.Address; - } - } - } - - /// - /// Reset the resources associated to this . - /// - /// The voice context. - private void ResetResources(VoiceContext context) - { - for (int i = 0; i < ChannelsCount; i++) - { - int channelResourceId = ChannelResourceIds[i]; - - ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId); - - Debug.Assert(voiceChannelResource.IsUsed); - - Memory dspSharedState = context.GetUpdateStateForDsp(channelResourceId); - - MemoryMarshal.Cast(dspSharedState.Span).Fill(0); - - voiceChannelResource.UpdateState(); - } - } - - /// - /// Flush a certain amount of . - /// - /// The amount of wavebuffer to flush. - /// The voice states associated to the . - /// The channel count from user input. - private void FlushWaveBuffers(uint waveBufferCount, Memory[] voiceUpdateStates, uint channelCount) - { - uint waveBufferIndex = WaveBuffersIndex; - - for (int i = 0; i < waveBufferCount; i++) - { - WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true; - - for (int j = 0; j < channelCount; j++) - { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0]; - - voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % RendererConstants.VoiceWaveBufferCount; - voiceUpdateState.WaveBufferConsumed++; - voiceUpdateState.IsWaveBufferValid[(int)waveBufferIndex] = false; - } - - waveBufferIndex = (waveBufferIndex + 1) % RendererConstants.VoiceWaveBufferCount; - } - } - - /// - /// Update the internal parameters for command generation. - /// - /// The voice states associated to the . - /// Return true if this voice should be played. - public bool UpdateParametersForCommandGeneration(Memory[] voiceUpdateStates) - { - if (FlushWaveBufferCount != 0) - { - FlushWaveBuffers(FlushWaveBufferCount, voiceUpdateStates, ChannelsCount); - - FlushWaveBufferCount = 0; - } - - switch (PlayState) - { - case Types.PlayState.Started: - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref WaveBuffer wavebuffer = ref WaveBuffers[i]; - - if (!wavebuffer.IsSendToAudioProcessor) - { - for (int y = 0; y < ChannelsCount; y++) - { - Debug.Assert(!voiceUpdateStates[y].Span[0].IsWaveBufferValid[i]); - - voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true; - } - - wavebuffer.IsSendToAudioProcessor = true; - } - } - - WasPlaying = false; - - ref VoiceUpdateState primaryVoiceUpdateState = ref voiceUpdateStates[0].Span[0]; - - for (int i = 0; i < primaryVoiceUpdateState.IsWaveBufferValid.Length; i++) - { - if (primaryVoiceUpdateState.IsWaveBufferValid[i]) - { - return true; - } - } - - return false; - - case Types.PlayState.Stopping: - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref WaveBuffer wavebuffer = ref WaveBuffers[i]; - - wavebuffer.IsSendToAudioProcessor = true; - - for (int j = 0; j < ChannelsCount; j++) - { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0]; - - if (voiceUpdateState.IsWaveBufferValid[i]) - { - voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % RendererConstants.VoiceWaveBufferCount; - voiceUpdateState.WaveBufferConsumed++; - } - - voiceUpdateState.IsWaveBufferValid[i] = false; - } - } - - for (int i = 0; i < ChannelsCount; i++) - { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[i].Span[0]; - - voiceUpdateState.Offset = 0; - voiceUpdateState.PlayedSampleCount = 0; - voiceUpdateState.Pitch.ToSpan().Fill(0); - voiceUpdateState.Fraction = 0; - voiceUpdateState.LoopContext = new Dsp.State.AdpcmLoopContext(); - } - - PlayState = Types.PlayState.Stopped; - WasPlaying = PreviousPlayState == Types.PlayState.Started; - - return WasPlaying; - - case Types.PlayState.Stopped: - case Types.PlayState.Paused: - foreach (ref WaveBuffer wavebuffer in WaveBuffers.ToSpan()) - { - wavebuffer.BufferAddressInfo.GetReference(true); - wavebuffer.ContextAddressInfo.GetReference(true); - } - - if (SampleFormat == SampleFormat.Adpcm) - { - if (DataSourceStateAddressInfo.CpuAddress != 0) - { - DataSourceStateAddressInfo.GetReference(true); - } - } - - WasPlaying = PreviousPlayState == Types.PlayState.Started; - - return WasPlaying; - default: - throw new NotImplementedException($"{PlayState}"); - } - } - - /// - /// Update the internal state for command generation. - /// - /// The voice context. - /// Return true if this voice should be played. - public bool UpdateForCommandGeneration(VoiceContext context) - { - if (IsNew) - { - ResetResources(context); - PreviousVolume = Volume; - IsNew = false; - } - - Memory[] voiceUpdateStates = new Memory[RendererConstants.VoiceChannelCountMax]; - - for (int i = 0; i < ChannelsCount; i++) - { - voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]); - } - - return UpdateParametersForCommandGeneration(voiceUpdateStates); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs b/Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs deleted file mode 100644 index a03aa757..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs +++ /dev/null @@ -1,121 +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 . -// - -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// - /// A wavebuffer used for server update. - /// - [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 1)] - public struct WaveBuffer - { - /// - /// The of the sample data of the wavebuffer. - /// - public AddressInfo BufferAddressInfo; - - /// - /// The of the context of the wavebuffer. - /// - /// Only used by . - public AddressInfo ContextAddressInfo; - - - /// - /// First sample to play of the wavebuffer. - /// - public uint StartSampleOffset; - - /// - /// Last sample to play of the wavebuffer. - /// - public uint EndSampleOffset; - - /// - /// Set to true if the wavebuffer is looping. - /// - [MarshalAs(UnmanagedType.I1)] - public bool ShouldLoop; - - /// - /// Set to true if the wavebuffer is the end of stream. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsEndOfStream; - - /// - /// Set to true if the wavebuffer wasn't sent to the . - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsSendToAudioProcessor; - - /// - /// First sample to play when looping the wavebuffer. - /// - public uint LoopStartSampleOffset; - - /// - /// Last sample to play when looping the wavebuffer. - /// - public uint LoopEndSampleOffset; - - /// - /// The max loop count. - /// - public int LoopCount; - - /// - /// Create a new for use by the . - /// - /// The target version of the wavebuffer. - /// A new for use by the . - public Common.WaveBuffer ToCommon(int version) - { - Common.WaveBuffer waveBuffer = new Common.WaveBuffer(); - - waveBuffer.Buffer = BufferAddressInfo.GetReference(true); - waveBuffer.BufferSize = (uint)BufferAddressInfo.Size; - - if (ContextAddressInfo.CpuAddress != 0) - { - waveBuffer.Context = ContextAddressInfo.GetReference(true); - waveBuffer.ContextSize = (uint)ContextAddressInfo.Size; - } - - waveBuffer.StartSampleOffset = StartSampleOffset; - waveBuffer.EndSampleOffset = EndSampleOffset; - waveBuffer.Looping = ShouldLoop; - waveBuffer.IsEndOfStream = IsEndOfStream; - - if (version == 2) - { - waveBuffer.LoopCount = LoopCount; - waveBuffer.LoopStartSampleOffset = LoopStartSampleOffset; - waveBuffer.LoopEndSampleOffset = LoopEndSampleOffset; - } - else - { - waveBuffer.LoopCount = -1; - } - - return waveBuffer; - } - } -} -- cgit v1.2.3