From 458da8a94877677f086f06cdeecf959ec4283a33 Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Sat, 16 Jul 2022 23:48:45 +0100 Subject: Project Andio --- .../renderer/sink/circular_buffer_sink_info.cpp | 76 +++++++++ .../renderer/sink/circular_buffer_sink_info.h | 41 +++++ src/audio_core/renderer/sink/device_sink_info.cpp | 57 +++++++ src/audio_core/renderer/sink/device_sink_info.h | 40 +++++ src/audio_core/renderer/sink/sink_context.cpp | 21 +++ src/audio_core/renderer/sink/sink_context.h | 47 ++++++ src/audio_core/renderer/sink/sink_info_base.cpp | 51 ++++++ src/audio_core/renderer/sink/sink_info_base.h | 177 +++++++++++++++++++++ 8 files changed, 510 insertions(+) create mode 100644 src/audio_core/renderer/sink/circular_buffer_sink_info.cpp create mode 100644 src/audio_core/renderer/sink/circular_buffer_sink_info.h create mode 100644 src/audio_core/renderer/sink/device_sink_info.cpp create mode 100644 src/audio_core/renderer/sink/device_sink_info.h create mode 100644 src/audio_core/renderer/sink/sink_context.cpp create mode 100644 src/audio_core/renderer/sink/sink_context.h create mode 100644 src/audio_core/renderer/sink/sink_info_base.cpp create mode 100644 src/audio_core/renderer/sink/sink_info_base.h (limited to 'src/audio_core/renderer/sink') diff --git a/src/audio_core/renderer/sink/circular_buffer_sink_info.cpp b/src/audio_core/renderer/sink/circular_buffer_sink_info.cpp new file mode 100644 index 000000000..d91f10402 --- /dev/null +++ b/src/audio_core/renderer/sink/circular_buffer_sink_info.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "audio_core/renderer/memory/pool_mapper.h" +#include "audio_core/renderer/sink/circular_buffer_sink_info.h" +#include "audio_core/renderer/upsampler/upsampler_manager.h" + +namespace AudioCore::AudioRenderer { + +CircularBufferSinkInfo::CircularBufferSinkInfo() { + state.fill(0); + parameter.fill(0); + type = Type::CircularBufferSink; + + auto state_{reinterpret_cast(state.data())}; + state_->address_info.Setup(0, 0); +} + +void CircularBufferSinkInfo::CleanUp() { + auto state_{reinterpret_cast(state.data())}; + + if (state_->upsampler_info) { + state_->upsampler_info->manager->Free(state_->upsampler_info); + state_->upsampler_info = nullptr; + } + + parameter.fill(0); + type = Type::Invalid; +} + +void CircularBufferSinkInfo::Update(BehaviorInfo::ErrorInfo& error_info, OutStatus& out_status, + const InParameter& in_params, const PoolMapper& pool_mapper) { + const auto buffer_params{ + reinterpret_cast(&in_params.circular_buffer)}; + auto current_params{reinterpret_cast(parameter.data())}; + auto current_state{reinterpret_cast(state.data())}; + + if (in_use == buffer_params->in_use && !buffer_unmapped) { + error_info.error_code = ResultSuccess; + error_info.address = CpuAddr(0); + out_status.writeOffset = current_state->last_pos2; + return; + } + + node_id = in_params.node_id; + in_use = in_params.in_use; + + if (in_use) { + buffer_unmapped = + !pool_mapper.TryAttachBuffer(error_info, current_state->address_info, + buffer_params->cpu_address, buffer_params->size); + *current_params = *buffer_params; + } else { + *current_params = *buffer_params; + } + out_status.writeOffset = current_state->last_pos2; +} + +void CircularBufferSinkInfo::UpdateForCommandGeneration() { + if (in_use) { + auto params{reinterpret_cast(parameter.data())}; + auto state_{reinterpret_cast(state.data())}; + + const auto pos{state_->current_pos}; + state_->last_pos2 = state_->last_pos; + state_->last_pos = pos; + + state_->current_pos += static_cast(params->input_count * params->sample_count * + GetSampleFormatByteSize(SampleFormat::PcmInt16)); + if (params->size > 0) { + state_->current_pos %= params->size; + } + } +} + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/circular_buffer_sink_info.h b/src/audio_core/renderer/sink/circular_buffer_sink_info.h new file mode 100644 index 000000000..3356213ea --- /dev/null +++ b/src/audio_core/renderer/sink/circular_buffer_sink_info.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "audio_core/renderer/sink/sink_info_base.h" +#include "common/common_types.h" + +namespace AudioCore::AudioRenderer { +/** + * Info for a circular buffer sink. + */ +class CircularBufferSinkInfo : public SinkInfoBase { +public: + CircularBufferSinkInfo(); + + /** + * Clean up for info, resetting it to a default state. + */ + void CleanUp() override; + + /** + * Update the info according to parameters, and write the current state to out_status. + * + * @param error_info - Output error code. + * @param out_status - Output status. + * @param in_params - Input parameters. + * @param pool_mapper - Used to map the circular buffer. + */ + void Update(BehaviorInfo::ErrorInfo& error_info, OutStatus& out_status, + const InParameter& in_params, const PoolMapper& pool_mapper) override; + + /** + * Update the circular buffer on command generation, incrementing its current offsets. + */ + void UpdateForCommandGeneration() override; +}; +static_assert(sizeof(CircularBufferSinkInfo) <= sizeof(SinkInfoBase), + "CircularBufferSinkInfo is too large!"); + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/device_sink_info.cpp b/src/audio_core/renderer/sink/device_sink_info.cpp new file mode 100644 index 000000000..b7b3d6f1d --- /dev/null +++ b/src/audio_core/renderer/sink/device_sink_info.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "audio_core/renderer/sink/device_sink_info.h" +#include "audio_core/renderer/upsampler/upsampler_manager.h" + +namespace AudioCore::AudioRenderer { + +DeviceSinkInfo::DeviceSinkInfo() { + state.fill(0); + parameter.fill(0); + type = Type::DeviceSink; +} + +void DeviceSinkInfo::CleanUp() { + auto state_{reinterpret_cast(state.data())}; + + if (state_->upsampler_info) { + state_->upsampler_info->manager->Free(state_->upsampler_info); + state_->upsampler_info = nullptr; + } + + parameter.fill(0); + type = Type::Invalid; +} + +void DeviceSinkInfo::Update(BehaviorInfo::ErrorInfo& error_info, OutStatus& out_status, + const InParameter& in_params, + [[maybe_unused]] const PoolMapper& pool_mapper) { + + const auto device_params{reinterpret_cast(&in_params.device)}; + auto current_params{reinterpret_cast(parameter.data())}; + + if (in_use == in_params.in_use) { + current_params->downmix_enabled = device_params->downmix_enabled; + current_params->downmix_coeff = device_params->downmix_coeff; + } else { + type = in_params.type; + in_use = in_params.in_use; + node_id = in_params.node_id; + *current_params = *device_params; + } + + auto current_state{reinterpret_cast(state.data())}; + + for (size_t i = 0; i < current_state->downmix_coeff.size(); i++) { + current_state->downmix_coeff[i] = current_params->downmix_coeff[i]; + } + + std::memset(&out_status, 0, sizeof(OutStatus)); + error_info.error_code = ResultSuccess; + error_info.address = CpuAddr(0); +} + +void DeviceSinkInfo::UpdateForCommandGeneration() {} + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/device_sink_info.h b/src/audio_core/renderer/sink/device_sink_info.h new file mode 100644 index 000000000..a1c441454 --- /dev/null +++ b/src/audio_core/renderer/sink/device_sink_info.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "audio_core/renderer/sink/sink_info_base.h" +#include "common/common_types.h" + +namespace AudioCore::AudioRenderer { +/** + * Info for a device sink. + */ +class DeviceSinkInfo : public SinkInfoBase { +public: + DeviceSinkInfo(); + + /** + * Clean up for info, resetting it to a default state. + */ + void CleanUp() override; + + /** + * Update the info according to parameters, and write the current state to out_status. + * + * @param error_info - Output error code. + * @param out_status - Output status. + * @param in_params - Input parameters. + * @param pool_mapper - Unused. + */ + void Update(BehaviorInfo::ErrorInfo& error_info, OutStatus& out_status, + const InParameter& in_params, const PoolMapper& pool_mapper) override; + + /** + * Update the device sink on command generation, unused. + */ + void UpdateForCommandGeneration() override; +}; +static_assert(sizeof(DeviceSinkInfo) <= sizeof(SinkInfoBase), "DeviceSinkInfo is too large!"); + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/sink_context.cpp b/src/audio_core/renderer/sink/sink_context.cpp new file mode 100644 index 000000000..634bc1cf9 --- /dev/null +++ b/src/audio_core/renderer/sink/sink_context.cpp @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "audio_core/renderer/sink/sink_context.h" + +namespace AudioCore::AudioRenderer { + +void SinkContext::Initialize(std::span sink_infos_, const u32 sink_count_) { + sink_infos = sink_infos_; + sink_count = sink_count_; +} + +SinkInfoBase* SinkContext::GetInfo(const u32 index) { + return &sink_infos[index]; +} + +u32 SinkContext::GetCount() const { + return sink_count; +} + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/sink_context.h b/src/audio_core/renderer/sink/sink_context.h new file mode 100644 index 000000000..185572e29 --- /dev/null +++ b/src/audio_core/renderer/sink/sink_context.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "audio_core/renderer/sink/sink_info_base.h" +#include "common/common_types.h" + +namespace AudioCore::AudioRenderer { +/** + * Manages output sinks. + */ +class SinkContext { +public: + /** + * Initialize the sink context. + * + * @param sink_infos - Workbuffer for the sinks. + * @param sink_count - Number of sinks in the buffer. + */ + void Initialize(std::span sink_infos, u32 sink_count); + + /** + * Get a given index's info. + * + * @param index - Sink index to get. + * @return The sink info base for the given index. + */ + SinkInfoBase* GetInfo(u32 index); + + /** + * Get the current number of sinks. + * + * @return The number of sinks. + */ + u32 GetCount() const; + +private: + /// Buffer of sink infos + std::span sink_infos{}; + /// Number of sinks in the buffer + u32 sink_count{}; +}; + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/sink_info_base.cpp b/src/audio_core/renderer/sink/sink_info_base.cpp new file mode 100644 index 000000000..4279beaa0 --- /dev/null +++ b/src/audio_core/renderer/sink/sink_info_base.cpp @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "audio_core/renderer/memory/pool_mapper.h" +#include "audio_core/renderer/sink/sink_info_base.h" + +namespace AudioCore::AudioRenderer { + +void SinkInfoBase::CleanUp() { + type = Type::Invalid; +} + +void SinkInfoBase::Update(BehaviorInfo::ErrorInfo& error_info, OutStatus& out_status, + [[maybe_unused]] const InParameter& in_params, + [[maybe_unused]] const PoolMapper& pool_mapper) { + std::memset(&out_status, 0, sizeof(OutStatus)); + error_info.error_code = ResultSuccess; + error_info.address = CpuAddr(0); +} + +void SinkInfoBase::UpdateForCommandGeneration() {} + +SinkInfoBase::DeviceState* SinkInfoBase::GetDeviceState() { + return reinterpret_cast(state.data()); +} + +SinkInfoBase::Type SinkInfoBase::GetType() const { + return type; +} + +bool SinkInfoBase::IsUsed() const { + return in_use; +} + +bool SinkInfoBase::ShouldSkip() const { + return buffer_unmapped; +} + +u32 SinkInfoBase::GetNodeId() const { + return node_id; +} + +u8* SinkInfoBase::GetState() { + return state.data(); +} + +u8* SinkInfoBase::GetParameter() { + return parameter.data(); +} + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/sink/sink_info_base.h b/src/audio_core/renderer/sink/sink_info_base.h new file mode 100644 index 000000000..a1b855f20 --- /dev/null +++ b/src/audio_core/renderer/sink/sink_info_base.h @@ -0,0 +1,177 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "audio_core/common/common.h" +#include "audio_core/renderer/behavior/behavior_info.h" +#include "audio_core/renderer/memory/address_info.h" +#include "common/common_types.h" +#include "common/fixed_point.h" + +namespace AudioCore::AudioRenderer { +struct UpsamplerInfo; +class PoolMapper; + +/** + * Base for the circular buffer and device sinks, holding their states for the AudioRenderer and + * their parametetrs for generating sink commands. + */ +class SinkInfoBase { +public: + enum class Type : u8 { + Invalid, + DeviceSink, + CircularBufferSink, + }; + + struct DeviceInParameter { + /* 0x000 */ char name[0x100]; + /* 0x100 */ u32 input_count; + /* 0x104 */ std::array inputs; + /* 0x10A */ char unk10A[0x1]; + /* 0x10B */ bool downmix_enabled; + /* 0x10C */ std::array downmix_coeff; + }; + static_assert(sizeof(DeviceInParameter) == 0x11C, "DeviceInParameter has the wrong size!"); + + struct DeviceState { + /* 0x00 */ UpsamplerInfo* upsampler_info; + /* 0x08 */ std::array, 4> downmix_coeff; + /* 0x18 */ char unk18[0x18]; + }; + static_assert(sizeof(DeviceState) == 0x30, "DeviceState has the wrong size!"); + + struct CircularBufferInParameter { + /* 0x00 */ u64 cpu_address; + /* 0x08 */ u32 size; + /* 0x0C */ u32 input_count; + /* 0x10 */ u32 sample_count; + /* 0x14 */ u32 previous_pos; + /* 0x18 */ SampleFormat format; + /* 0x1C */ std::array inputs; + /* 0x22 */ bool in_use; + /* 0x23 */ char unk23[0x5]; + }; + static_assert(sizeof(CircularBufferInParameter) == 0x28, + "CircularBufferInParameter has the wrong size!"); + + struct CircularBufferState { + /* 0x00 */ u32 last_pos2; + /* 0x04 */ s32 current_pos; + /* 0x08 */ u32 last_pos; + /* 0x0C */ char unk0C[0x4]; + /* 0x10 */ AddressInfo address_info; + }; + static_assert(sizeof(CircularBufferState) == 0x30, "CircularBufferState has the wrong size!"); + + struct InParameter { + /* 0x000 */ Type type; + /* 0x001 */ bool in_use; + /* 0x004 */ u32 node_id; + /* 0x008 */ char unk08[0x18]; + union { + /* 0x020 */ DeviceInParameter device; + /* 0x020 */ CircularBufferInParameter circular_buffer; + }; + }; + static_assert(sizeof(InParameter) == 0x140, "SinkInfoBase::InParameter has the wrong size!"); + + struct OutStatus { + /* 0x00 */ u32 writeOffset; + /* 0x04 */ char unk04[0x1C]; + }; // size == 0x20 + static_assert(sizeof(OutStatus) == 0x20, "SinkInfoBase::OutStatus has the wrong size!"); + + virtual ~SinkInfoBase() = default; + + /** + * Clean up for info, resetting it to a default state. + */ + virtual void CleanUp(); + + /** + * Update the info according to parameters, and write the current state to out_status. + * + * @param error_info - Output error code. + * @param out_status - Output status. + * @param in_params - Input parameters. + * @param pool_mapper - Used to map the circular buffer. + */ + virtual void Update(BehaviorInfo::ErrorInfo& error_info, OutStatus& out_status, + [[maybe_unused]] const InParameter& in_params, + [[maybe_unused]] const PoolMapper& pool_mapper); + + /** + * Update the circular buffer on command generation, incrementing its current offsets. + */ + virtual void UpdateForCommandGeneration(); + + /** + * Get the state as a device sink. + * + * @return Device state. + */ + DeviceState* GetDeviceState(); + + /** + * Get the type of this sink. + * + * @return Either Device, Circular, or Invalid. + */ + Type GetType() const; + + /** + * Check if this sink is in use. + * + * @return True if used, otherwise false. + */ + bool IsUsed() const; + + /** + * Check if this sink should be skipped for updates. + * + * @return True if it should be skipped, otherwise false. + */ + bool ShouldSkip() const; + + /** + * Get the node if of this sink. + * + * @return Node id for this sink. + */ + u32 GetNodeId() const; + + /** + * Get the state of this sink. + * + * @return Pointer to the state, must be cast to the correct type. + */ + u8* GetState(); + + /** + * Get the parameters of this sink. + * + * @return Pointer to the parameters, must be cast to the correct type. + */ + u8* GetParameter(); + +protected: + /// Type of this sink + Type type{Type::Invalid}; + /// Is this sink in use? + bool in_use{}; + /// Is this sink's buffer unmapped? Circular only + bool buffer_unmapped{}; + /// Node id for this sink + u32 node_id{}; + /// State buffer for this sink + std::array state{}; + /// Parameter buffer for this sink + std::array + parameter{}; +}; + +} // namespace AudioCore::AudioRenderer -- cgit v1.2.3