// // 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); } } }