[svc, audio] Implement REV13 audio renderer support and stub IAudioDevice commands up to 18.0.0+ #92
10 changed files with 170 additions and 11 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -44,6 +47,8 @@ enum class SupportTags {
|
||||||
DelayChannelMappingChange,
|
DelayChannelMappingChange,
|
||||||
ReverbChannelMappingChange,
|
ReverbChannelMappingChange,
|
||||||
I3dl2ReverbChannelMappingChange,
|
I3dl2ReverbChannelMappingChange,
|
||||||
|
DecodingBehaviourFlag,
|
||||||
|
BiquadFilterParameterForSplitter,
|
||||||
|
|
||||||
// Not a real tag, just here to get the count.
|
// Not a real tag, just here to get the count.
|
||||||
Size
|
Size
|
||||||
|
@ -87,6 +92,8 @@ constexpr bool CheckFeatureSupported(SupportTags tag, u32 user_revision) {
|
||||||
{SupportTags::DelayChannelMappingChange, 11},
|
{SupportTags::DelayChannelMappingChange, 11},
|
||||||
{SupportTags::ReverbChannelMappingChange, 11},
|
{SupportTags::ReverbChannelMappingChange, 11},
|
||||||
{SupportTags::I3dl2ReverbChannelMappingChange, 11},
|
{SupportTags::I3dl2ReverbChannelMappingChange, 11},
|
||||||
|
{SupportTags::DecodingBehaviourFlag, 12},
|
||||||
|
{SupportTags::BiquadFilterParameterForSplitter, 13},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const auto& feature =
|
const auto& feature =
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -93,6 +96,7 @@ private:
|
||||||
bool system_registered{};
|
bool system_registered{};
|
||||||
/// Audio render system, main driver of audio rendering
|
/// Audio render system, main driver of audio rendering
|
||||||
System system;
|
System system;
|
||||||
|
bool m_volume_ramp_reset = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Renderer
|
} // namespace Renderer
|
||||||
|
|
22
src/audio_core/renderer/splitter/parameters.h
Normal file
22
src/audio_core/renderer/splitter/parameters.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input struct passed to a splitter destination in REV13.
|
||||||
|
*/
|
||||||
|
struct SplitterDestinationInParameter {
|
||||||
|
/* 0x00 */ s32 magic;
|
||||||
|
/* 0x04 */ s32 id;
|
||||||
|
/* 0x08 */ bool reset_prev_volume;
|
||||||
|
/* 0x09 */ u8 reserved[11]; // Padding to align to 0x14
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SplitterDestinationInParameter) == 0x14,
|
||||||
|
"SplitterDestinationInParameter must be 0x14 bytes.");
|
||||||
|
|
||||||
|
} // namespace AudioCore::Renderer
|
|
@ -1,9 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "audio_core/common/audio_renderer_parameter.h"
|
#include "audio_core/common/audio_renderer_parameter.h"
|
||||||
#include "audio_core/common/workbuffer_allocator.h"
|
#include "audio_core/common/workbuffer_allocator.h"
|
||||||
#include "audio_core/renderer/behavior/behavior_info.h"
|
#include "audio_core/renderer/behavior/behavior_info.h"
|
||||||
|
#include "audio_core/renderer/splitter/parameters.h"
|
||||||
#include "audio_core/renderer/splitter/splitter_context.h"
|
#include "audio_core/renderer/splitter/splitter_context.h"
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
|
|
||||||
|
@ -134,19 +138,30 @@ u32 SplitterContext::UpdateInfo(const u8* input, u32 offset, const u32 splitter_
|
||||||
|
|
||||||
u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) {
|
u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) {
|
||||||
for (u32 i = 0; i < count; i++) {
|
for (u32 i = 0; i < count; i++) {
|
||||||
auto data_header{
|
const auto* data_header =
|
||||||
reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset)};
|
reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset);
|
||||||
|
|
||||||
if (data_header->magic != GetSplitterSendDataMagic()) {
|
if (data_header->magic != GetSplitterSendDataMagic()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_header->id < 0 || data_header->id > destinations_count) {
|
if (data_header->id < 0 || data_header->id >= destinations_count) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
splitter_destinations[data_header->id].Update(*data_header);
|
auto& destination = splitter_destinations[data_header->id];
|
||||||
offset += sizeof(SplitterDestinationData::InParameter);
|
destination.Update(*data_header);
|
||||||
|
|
||||||
|
// REV13: Set reset flag if present in extended struct
|
||||||
|
const auto* reset_data =
|
||||||
|
reinterpret_cast<const SplitterDestinationInParameter*>(
|
||||||
|
input + offset + sizeof(SplitterDestinationData::InParameter));
|
||||||
|
if (reset_data->reset_prev_volume) {
|
||||||
|
destination.SetResetPrevVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += sizeof(SplitterDestinationData::InParameter) +
|
||||||
|
sizeof(SplitterDestinationInParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -214,4 +229,9 @@ u64 SplitterContext::CalcWorkBufferSize(const BehaviorInfo& behavior,
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<SplitterDestinationData> SplitterContext::GetDestinations() {
|
||||||
|
return std::span<SplitterDestinationData>{splitter_destinations,
|
||||||
|
static_cast<size_t>(destinations_count)};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -159,6 +162,13 @@ public:
|
||||||
static u64 CalcWorkBufferSize(const BehaviorInfo& behavior,
|
static u64 CalcWorkBufferSize(const BehaviorInfo& behavior,
|
||||||
const AudioRendererParameterInternal& params);
|
const AudioRendererParameterInternal& params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all active splitter destinations.
|
||||||
|
*
|
||||||
|
* @return Span of splitter destinations.
|
||||||
|
*/
|
||||||
|
std::span<SplitterDestinationData> GetDestinations();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Setup the context.
|
* Setup the context.
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -84,4 +87,16 @@ void SplitterDestinationData::SetNext(SplitterDestinationData* next_) {
|
||||||
next = next_;
|
next = next_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SplitterDestinationData::SetResetPrevVolume() {
|
||||||
|
m_reset_prev_volume = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SplitterDestinationData::ShouldResetPrevVolume() const {
|
||||||
|
return m_reset_prev_volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitterDestinationData::ClearResetPrevVolume() {
|
||||||
|
m_reset_prev_volume = false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -115,6 +118,21 @@ public:
|
||||||
*/
|
*/
|
||||||
void SetNext(SplitterDestinationData* next);
|
void SetNext(SplitterDestinationData* next);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REV13: Called during UpdateData() if the struct's flag is set
|
||||||
|
*/
|
||||||
|
void SetResetPrevVolume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REV13: Called during GenerateCommand() to check for a reset
|
||||||
|
*/
|
||||||
|
bool ShouldResetPrevVolume() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REV13: Called after reset is applied to clear the flag
|
||||||
|
*/
|
||||||
|
void ClearResetPrevVolume();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Id of this destination
|
/// Id of this destination
|
||||||
const s32 id;
|
const s32 id;
|
||||||
|
@ -130,6 +148,8 @@ private:
|
||||||
bool in_use{};
|
bool in_use{};
|
||||||
/// Does this destination need its volumes updated?
|
/// Does this destination need its volumes updated?
|
||||||
bool need_update{};
|
bool need_update{};
|
||||||
|
/// REV13: Flag to reset previous volume ramps
|
||||||
|
bool m_reset_prev_volume{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -688,6 +691,7 @@ u64 System::GenerateCommand(std::span<u8> in_command_buffer,
|
||||||
sink_context, splitter_context, perf_manager};
|
sink_context, splitter_context, perf_manager};
|
||||||
|
|
||||||
voice_context.SortInfo();
|
voice_context.SortInfo();
|
||||||
|
|
||||||
command_generator.GenerateVoiceCommands();
|
command_generator.GenerateVoiceCommands();
|
||||||
|
|
||||||
const auto start_estimated_time{drop_voice_param *
|
const auto start_estimated_time{drop_voice_param *
|
||||||
|
@ -697,6 +701,17 @@ u64 System::GenerateCommand(std::span<u8> in_command_buffer,
|
||||||
command_generator.GenerateFinalMixCommands();
|
command_generator.GenerateFinalMixCommands();
|
||||||
command_generator.GenerateSinkCommands();
|
command_generator.GenerateSinkCommands();
|
||||||
|
|
||||||
|
// REV13: Reset previous volumes for any splitter destinations requesting it
|
||||||
|
for (auto& destination : splitter_context.GetDestinations()) {
|
||||||
|
if (destination.ShouldResetPrevVolume()) {
|
||||||
|
for (auto& volume : destination.GetMixVolumePrev()) {
|
||||||
|
volume = 0.0f;
|
||||||
|
}
|
||||||
|
destination.ClearResetPrevVolume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (drop_voice) {
|
if (drop_voice) {
|
||||||
f32 time_limit_percent{70.0f};
|
f32 time_limit_percent{70.0f};
|
||||||
if (render_context.behavior->IsAudioRendererProcessingTimeLimit80PercentSupported()) {
|
if (render_context.behavior->IsAudioRendererProcessingTimeLimit80PercentSupported()) {
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -29,12 +32,12 @@ IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u
|
||||||
{12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
|
{12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
|
||||||
{13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
|
{13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
|
||||||
{14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
|
{14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
|
||||||
{15, nullptr, "AcquireAudioInputDeviceNotification"}, // 17.0.0+
|
{15, D<&IAudioDevice::AcquireAudioInputDeviceNotification>, "AcquireAudioInputDeviceNotification"}, // 17.0.0+
|
||||||
{16, nullptr, "ReleaseAudioInputDeviceNotification"}, // 17.0.0+
|
{16, D<&IAudioDevice::ReleaseAudioInputDeviceNotification>, "ReleaseAudioInputDeviceNotification"}, // 17.0.0+
|
||||||
{17, nullptr, "AcquireAudioOutputDeviceNotification"}, // 17.0.0+
|
{17, D<&IAudioDevice::AcquireAudioOutputDeviceNotification>, "AcquireAudioOutputDeviceNotification"}, // 17.0.0+
|
||||||
{18, nullptr, "ReleaseAudioOutputDeviceNotification"}, // 17.0.0+
|
{18, D<&IAudioDevice::ReleaseAudioOutputDeviceNotification>, "ReleaseAudioOutputDeviceNotification"}, // 17.0.0+
|
||||||
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
|
{19, D<&IAudioDevice::SetAudioDeviceOutputVolumeAutoTuneEnabled>, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
|
||||||
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"} // 18.0.0+
|
{20, D<&IAudioDevice::IsAudioDeviceOutputVolumeAutoTuneEnabled>, "IsAudioDeviceOutputVolumeAutoTuneEnabled"} // 18.0.0+
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
@ -166,4 +169,37 @@ Result IAudioDevice::ListAudioOutputDeviceName(
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IAudioDevice::AcquireAudioInputDeviceNotification(OutCopyHandle<Kernel::KEvent> out_event_handle, u64 device_id) {
|
||||||
|
LOG_DEBUG(Service_Audio, "(STUBBED) AcquireAudioInputDeviceNotification called. device_id={:016X}", device_id);
|
||||||
|
*out_event_handle = event; // Reuse existing stub logic as placeholder
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IAudioDevice::ReleaseAudioInputDeviceNotification(u64 device_id) {
|
||||||
|
LOG_DEBUG(Service_Audio, "(STUBBED) ReleaseAudioInputDeviceNotification called. device_id={:016X}", device_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IAudioDevice::AcquireAudioOutputDeviceNotification(OutCopyHandle<Kernel::KEvent> out_event_handle, u64 device_id) {
|
||||||
|
LOG_DEBUG(Service_Audio, "(STUBBED) AcquireAudioOutputDeviceNotification called. device_id={:016X}", device_id);
|
||||||
|
*out_event_handle = event; // Reuse existing stub logic as placeholder
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IAudioDevice::ReleaseAudioOutputDeviceNotification(u64 device_id) {
|
||||||
|
LOG_DEBUG(Service_Audio, "(STUBBED) ReleaseAudioOutputDeviceNotification called. device_id={:016X}", device_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IAudioDevice::SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled) {
|
||||||
|
LOG_DEBUG(Service_Audio, "(STUBBED) SetAudioDeviceOutputVolumeAutoTuneEnabled called. enabled={}", enabled);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IAudioDevice::IsAudioDeviceOutputVolumeAutoTuneEnabled(Out<bool> out_enabled) {
|
||||||
|
*out_enabled = false;
|
||||||
|
LOG_DEBUG(Service_Audio, "(STUBBED) IsAudioDeviceOutputVolumeAutoTuneEnabled called. returning false");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::Audio
|
} // namespace Service::Audio
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -49,6 +52,13 @@ private:
|
||||||
Result ListAudioOutputDeviceName(
|
Result ListAudioOutputDeviceName(
|
||||||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
|
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
|
||||||
Out<s32> out_count);
|
Out<s32> out_count);
|
||||||
|
Result AcquireAudioInputDeviceNotification(OutCopyHandle<Kernel::KEvent> out_event_handle, u64 device_id);
|
||||||
|
Result ReleaseAudioInputDeviceNotification(u64 device_id);
|
||||||
|
Result AcquireAudioOutputDeviceNotification(OutCopyHandle<Kernel::KEvent> out_event_handle, u64 device_id);
|
||||||
|
Result ReleaseAudioOutputDeviceNotification(u64 device_id);
|
||||||
|
Result SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled);
|
||||||
|
Result IsAudioDeviceOutputVolumeAutoTuneEnabled(Out<bool> out_enabled);
|
||||||
|
|
||||||
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
KernelHelpers::ServiceContext service_context;
|
||||||
std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
|
std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue