mirror of
https://github.com/yuzu-emu/yuzu-android
synced 2025-08-05 07:32:33 -07:00
Project Andio
This commit is contained in:
76
src/audio_core/renderer/sink/circular_buffer_sink_info.cpp
Normal file
76
src/audio_core/renderer/sink/circular_buffer_sink_info.cpp
Normal file
@@ -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<CircularBufferState*>(state.data())};
|
||||
state_->address_info.Setup(0, 0);
|
||||
}
|
||||
|
||||
void CircularBufferSinkInfo::CleanUp() {
|
||||
auto state_{reinterpret_cast<DeviceState*>(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<const CircularBufferInParameter*>(&in_params.circular_buffer)};
|
||||
auto current_params{reinterpret_cast<CircularBufferInParameter*>(parameter.data())};
|
||||
auto current_state{reinterpret_cast<CircularBufferState*>(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<CircularBufferInParameter*>(parameter.data())};
|
||||
auto state_{reinterpret_cast<CircularBufferState*>(state.data())};
|
||||
|
||||
const auto pos{state_->current_pos};
|
||||
state_->last_pos2 = state_->last_pos;
|
||||
state_->last_pos = pos;
|
||||
|
||||
state_->current_pos += static_cast<s32>(params->input_count * params->sample_count *
|
||||
GetSampleFormatByteSize(SampleFormat::PcmInt16));
|
||||
if (params->size > 0) {
|
||||
state_->current_pos %= params->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
41
src/audio_core/renderer/sink/circular_buffer_sink_info.h
Normal file
41
src/audio_core/renderer/sink/circular_buffer_sink_info.h
Normal file
@@ -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
|
57
src/audio_core/renderer/sink/device_sink_info.cpp
Normal file
57
src/audio_core/renderer/sink/device_sink_info.cpp
Normal file
@@ -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<DeviceState*>(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<const DeviceInParameter*>(&in_params.device)};
|
||||
auto current_params{reinterpret_cast<DeviceInParameter*>(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<DeviceState*>(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
|
40
src/audio_core/renderer/sink/device_sink_info.h
Normal file
40
src/audio_core/renderer/sink/device_sink_info.h
Normal file
@@ -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
|
21
src/audio_core/renderer/sink/sink_context.cpp
Normal file
21
src/audio_core/renderer/sink/sink_context.cpp
Normal file
@@ -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<SinkInfoBase> 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
|
47
src/audio_core/renderer/sink/sink_context.h
Normal file
47
src/audio_core/renderer/sink/sink_context.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#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<SinkInfoBase> 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<SinkInfoBase> sink_infos{};
|
||||
/// Number of sinks in the buffer
|
||||
u32 sink_count{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
51
src/audio_core/renderer/sink/sink_info_base.cpp
Normal file
51
src/audio_core/renderer/sink/sink_info_base.cpp
Normal file
@@ -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<DeviceState*>(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
|
177
src/audio_core/renderer/sink/sink_info_base.h
Normal file
177
src/audio_core/renderer/sink/sink_info_base.h
Normal file
@@ -0,0 +1,177 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#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<s8, MaxChannels> inputs;
|
||||
/* 0x10A */ char unk10A[0x1];
|
||||
/* 0x10B */ bool downmix_enabled;
|
||||
/* 0x10C */ std::array<f32, 4> downmix_coeff;
|
||||
};
|
||||
static_assert(sizeof(DeviceInParameter) == 0x11C, "DeviceInParameter has the wrong size!");
|
||||
|
||||
struct DeviceState {
|
||||
/* 0x00 */ UpsamplerInfo* upsampler_info;
|
||||
/* 0x08 */ std::array<Common::FixedPoint<16, 16>, 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<s8, MaxChannels> 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<u8, std::max(sizeof(DeviceState), sizeof(CircularBufferState))> state{};
|
||||
/// Parameter buffer for this sink
|
||||
std::array<u8, std::max(sizeof(DeviceInParameter), sizeof(CircularBufferInParameter))>
|
||||
parameter{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
Reference in New Issue
Block a user