/// <summary>
        /// Open a new <see cref="AudioRenderSystem"/>
        /// </summary>
        /// <param name="renderer">The new <see cref="AudioRenderSystem"/></param>
        /// <param name="memoryManager">The memory manager that will be used for all guest memory operations.</param>
        /// <param name="parameter">The user configuration</param>
        /// <param name="appletResourceUserId">The applet resource user id of the application.</param>
        /// <param name="workBufferAddress">The guest work buffer address.</param>
        /// <param name="workBufferSize">The guest work buffer size.</param>
        /// <param name="processHandle">The process handle of the application.</param>
        /// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
        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);
        }
 /// <summary>
 /// Get the work buffer size required by a session.
 /// </summary>
 /// <param name="parameter">The user configuration</param>
 /// <returns>The work buffer size required by a session.</returns>
 public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter)
 {
     return(AudioRenderSystem.GetWorkBufferSize(ref parameter));
 }
Beispiel #3
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 = Constants.VoiceChannelCountMax;
            _upsamplerCount       = parameter.SinkCount + parameter.SubMixBufferCount;
            _appletResourceId     = appletResourceId;
            _memoryPoolCount      = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
            _executionMode        = parameter.ExecutionMode;
            _sessionId            = sessionId;
            MemoryManager         = memoryManager;

            if (memoryManager is IRefCounted rc)
            {
                rc.IncrementReferenceCount();
            }

            WorkBufferAllocator workBufferAllocator;

            _workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize);
            _workBufferRegion.Memory.Span.Fill(0);
            _workBufferMemoryPin = _workBufferRegion.Memory.Pin();

            workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory);

            PoolMapper poolMapper = new PoolMapper(processHandle, false);

            poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);

            _mixBuffer = workBufferAllocator.Allocate <float>(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10);

            if (_mixBuffer.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            Memory <float> upSamplerWorkBuffer = workBufferAllocator.Allocate <float>(Constants.TargetSampleCount * (_voiceChannelCountMax + _mixBufferCount) * _upsamplerCount, 0x10);

            if (upSamplerWorkBuffer.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            _depopBuffer = workBufferAllocator.Allocate <float>((ulong)BitUtils.AlignUp(parameter.MixBufferCount, Constants.BufferAlignment), Constants.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 % Constants.BufferAlignment) == 0);

            Memory <VoiceState> voices = workBufferAllocator.Allocate <VoiceState>(parameter.VoiceCount, VoiceState.Alignment);

            if (voices.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            foreach (ref VoiceState voice in voices.Span)
            {
                voice.Initialize();
            }

            // A pain to handle as we can't have VoiceState*, use indices to be a bit more safe
            Memory <int> sortedVoices = workBufferAllocator.Allocate <int>(parameter.VoiceCount, 0x10);

            if (sortedVoices.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            // Clear memory (use -1 as it's an invalid index)
            sortedVoices.Span.Fill(-1);

            Memory <VoiceChannelResource> voiceChannelResources = workBufferAllocator.Allocate <VoiceChannelResource>(parameter.VoiceCount, VoiceChannelResource.Alignment);

            if (voiceChannelResources.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            for (uint id = 0; id < voiceChannelResources.Length; id++)
            {
                ref VoiceChannelResource voiceChannelResource = ref voiceChannelResources.Span[(int)id];

                voiceChannelResource.Id     = id;
                voiceChannelResource.IsUsed = false;
            }
        /// <summary>
        /// Get the work buffer size while adding the size needed for splitter to operate.
        /// </summary>
        /// <param name="size">The current size.</param>
        /// <param name="behaviourContext">The behaviour context.</param>
        /// <param name="parameter">The renderer configuration.</param>
        /// <returns>Return the new size taking splitter into account.</returns>
        public static ulong GetWorkBufferSize(ulong size, ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter)
        {
            if (behaviourContext.IsSplitterSupported())
            {
                size = WorkBufferAllocator.GetTargetSize <SplitterState>(size, parameter.SplitterCount, SplitterState.Alignment);
                size = WorkBufferAllocator.GetTargetSize <SplitterDestination>(size, parameter.SplitterDestinationCount, SplitterDestination.Alignment);

                if (behaviourContext.IsSplitterBugFixed())
                {
                    size = WorkBufferAllocator.GetTargetSize <int>(size, parameter.SplitterDestinationCount, 0x10);
                }

                return(size);
            }
            else
            {
                return(size);
            }
        }
Beispiel #5
0
        public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
        {
            ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, context.Memory, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);

            if (result == ResultCode.Success)
            {
                obj = new AudioRenderer.AudioRenderer(renderer);
            }
            else
            {
                obj = null;
            }

            return(result);
        }
Beispiel #6
0
 public ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter)
 {
     return(AudioRendererManagerImpl.GetWorkBufferSize(ref parameter));
 }