early-access version 2824

This commit is contained in:
pineappleEA
2022-07-10 14:59:48 +02:00
parent da2f33c5e0
commit 29fab4f91a
43 changed files with 543 additions and 403 deletions

View File

@@ -57,4 +57,12 @@ void AudioCore::PauseSinks(const bool pausing) const {
}
}
u32 AudioCore::GetStreamQueue() const {
return estimated_queue.load();
}
void AudioCore::SetStreamQueue(u32 size) {
estimated_queue.store(size);
}
} // namespace AudioCore

View File

@@ -65,6 +65,20 @@ public:
*/
void PauseSinks(bool pausing) const;
/**
* Get the size of the current stream queue.
*
* @return Current stream queue size.
*/
u32 GetStreamQueue() const;
/**
* Get the size of the current stream queue.
*
* @param size - New stream size.
*/
void SetStreamQueue(u32 size);
private:
/**
* Create the sinks on startup.
@@ -79,6 +93,8 @@ private:
std::unique_ptr<Sink::Sink> input_sink;
/// The ADSP in the sysmodule
std::unique_ptr<AudioRenderer::ADSP::ADSP> adsp;
/// Current size of the stream queue
std::atomic<u32> estimated_queue{0};
};
} // namespace AudioCore

View File

@@ -5,6 +5,8 @@
#include "audio_core/audio_in_manager.h"
#include "audio_core/audio_manager.h"
#include "audio_core/in/audio_in.h"
#include "audio_core/sink/sink_details.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/audio/errors.h"
@@ -78,9 +80,12 @@ u32 Manager::GetDeviceNames(std::vector<AudioRenderer::AudioDevice::AudioDeviceN
LinkToManager();
names.push_back(AudioRenderer::AudioDevice::AudioDeviceName("Uac"));
return 1;
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (input_devices.size() > 1) {
names.push_back(AudioRenderer::AudioDevice::AudioDeviceName("Uac"));
return 1;
}
return 0;
}
} // namespace AudioCore::AudioIn

View File

@@ -37,13 +37,16 @@ Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_for
sink = &system.AudioCore().GetOutputSink();
}
stream = sink->AcquireSinkStream(system, channel_count, name, type);
initialized = true;
return ResultSuccess;
}
void DeviceSession::Finalize() {
Stop();
sink->CloseStream(stream);
stream = nullptr;
if (initialized) {
Stop();
sink->CloseStream(stream);
stream = nullptr;
}
}
void DeviceSession::Start() {

View File

@@ -100,7 +100,7 @@ private:
/// System
Core::System& system;
/// Output sink this device will use
Sink::Sink* sink;
Sink::Sink* sink{};
/// The backend stream for this device session to send samples to
Sink::SinkStream* stream{};
/// Name of this device session
@@ -119,6 +119,8 @@ private:
u64 applet_resource_user_id{};
/// Total number of samples played by this device session
u64 played_sample_count{};
/// Is this session initialised?
bool initialized{};
};
} // namespace AudioCore

View File

@@ -128,8 +128,8 @@ void AudioRenderer::CreateSinkStreams() {
u32 channels{sink.GetDeviceChannels()};
for (u32 i = 0; i < MaxRendererSessions; i++) {
std::string name{fmt::format("ADSP_RenderStream-{}", i)};
streams[i] = sink.AcquireSinkStream(system, channels, name,
::AudioCore::Sink::StreamType::Render, &render_event);
streams[i] =
sink.AcquireSinkStream(system, channels, name, ::AudioCore::Sink::StreamType::Render);
streams[i]->SetSystemChannels(streams[i]->GetDeviceChannels());
}
}
@@ -199,12 +199,9 @@ void AudioRenderer::ThreadFunc() {
command_list_processor.Process(index) - start_time;
}
// If the stream queue is building up too much, wait for a signal
// from the backend that a buffer was consumed.
// In practice this will wait longer than 1 buffer due to timing.
auto stream{command_list_processor.GetOutputSinkStream()};
if (stream->GetQueueSize() >= 4) {
render_event.WaitFor(std::chrono::milliseconds(5));
if (index == 0) {
auto stream{command_list_processor.GetOutputSinkStream()};
system.AudioCore().SetStreamQueue(stream->GetQueueSize());
}
const auto end_time{system.CoreTiming().GetClockTicks()};

View File

@@ -14,8 +14,11 @@
#include "common/thread.h"
namespace Core {
class System;
namespace Timing {
struct EventType;
}
class System;
} // namespace Core
namespace AudioCore {
namespace Sink {
@@ -194,8 +197,6 @@ private:
Sink::Sink& sink;
/// The streams which will receive the processed samples
std::array<Sink::SinkStream*, MaxRendererSessions> streams;
/// An event signalled from the backend when a buffer is consumed, used for timing.
Common::Event render_event{};
};
} // namespace AudioRenderer::ADSP

View File

@@ -63,7 +63,8 @@ static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& p
for (u32 sample_index = 0; sample_index < sample_count; sample_index++) {
for (u32 channel = 0; channel < params.channel_count; channel++) {
auto sample{Common::FixedPoint<49, 15>(inputs[channel][sample_index]) *
auto sample{(Common::FixedPoint<49, 15>(inputs[channel][sample_index]) /
Common::FixedPoint<49, 15>::one) *
params.input_gain};
auto abs_sample{sample};
if (sample < 0.0f) {
@@ -85,15 +86,17 @@ static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& p
auto lookahead_sample{
state.look_ahead_sample_buffers[channel]
[state.look_ahead_sample_offsets[channel]]};
state.look_ahead_sample_buffers[channel][state.look_ahead_sample_offsets[channel]] =
sample;
state.look_ahead_sample_offsets[channel] =
(state.look_ahead_sample_offsets[channel] + 1) % params.look_ahead_samples_min;
outputs[channel][sample_index] = static_cast<s32>(std::clamp(
(lookahead_sample * state.compression_gain[channel] * params.output_gain)
.to_long(),
min, max));
outputs[channel][sample_index] = static_cast<s32>(
std::clamp((lookahead_sample * state.compression_gain[channel] *
params.output_gain * Common::FixedPoint<49, 15>::one)
.to_long(),
min, max));
if (statistics) {
statistics->channel_max_sample[channel] =

View File

@@ -15,12 +15,17 @@ MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager",
MP_RGB(60, 19, 97));
namespace AudioCore::AudioRenderer {
constexpr std::chrono::nanoseconds BaseRenderTime{5'000'000UL};
constexpr std::chrono::nanoseconds RenderTimeOffset{400'000UL};
SystemManager::SystemManager(Core::System& core_)
: core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()},
thread_event{Core::Timing::CreateEvent(
"AudioRendererSystemManager",
[this](std::uintptr_t userdata, std::chrono::nanoseconds ns_late) { ThreadFunc2(); })} {}
"AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
return ThreadFunc2(time);
})} {
core.CoreTiming().RegisterPauseCallback([this](bool paused) { PauseCallback(paused); });
}
SystemManager::~SystemManager() {
Stop();
@@ -30,9 +35,9 @@ bool SystemManager::InitializeUnsafe() {
if (!active) {
if (adsp.Start()) {
active = true;
core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(2'304'000ULL * 2),
thread_event);
thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); });
core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
BaseRenderTime - RenderTimeOffset, thread_event);
}
}
@@ -95,11 +100,13 @@ void SystemManager::ThreadFunc() {
constexpr char name[]{"yuzu:AudioRenderSystemManager"};
MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name);
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
while (active) {
{
std::scoped_lock l{mutex1};
MICROPROFILE_SCOPE(Audio_RenderSystemManager);
for (auto system : systems) {
system->SendCommandToDsp();
}
@@ -113,9 +120,43 @@ void SystemManager::ThreadFunc() {
}
}
void SystemManager::ThreadFunc2() {
std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) {
std::optional<std::chrono::nanoseconds> new_schedule_time{std::nullopt};
const auto queue_size{core.AudioCore().GetStreamQueue()};
switch (state) {
case StreamState::Filling:
if (queue_size >= 5) {
new_schedule_time = BaseRenderTime;
state = StreamState::Steady;
}
break;
case StreamState::Steady:
if (queue_size <= 2) {
new_schedule_time = BaseRenderTime - RenderTimeOffset;
state = StreamState::Filling;
} else if (queue_size > 5) {
new_schedule_time = BaseRenderTime + RenderTimeOffset;
state = StreamState::Draining;
}
break;
case StreamState::Draining:
if (queue_size <= 5) {
new_schedule_time = BaseRenderTime;
state = StreamState::Steady;
}
break;
}
update.store(true);
update.notify_all();
return new_schedule_time;
}
void SystemManager::PauseCallback(bool paused) {
if (paused && core.IsPoweredOn() && core.IsShuttingDown()) {
update.store(true);
update.notify_all();
}
}
} // namespace AudioCore::AudioRenderer

View File

@@ -6,6 +6,7 @@
#include <list>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include "audio_core/renderer/system.h"
@@ -70,7 +71,20 @@ private:
/**
* Signalling core timing thread to run ThreadFunc.
*/
void ThreadFunc2();
std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time);
/**
* Callback from core timing when pausing, used to detect shutdowns and stop ThreadFunc.
*
* @param paused - Are we pausing or resuming?
*/
void PauseCallback(bool paused);
enum class StreamState {
Filling,
Steady,
Draining,
};
/// Core system
Core::System& core;
@@ -92,6 +106,8 @@ private:
std::shared_ptr<Core::Timing::EventType> thread_event;
/// Atomic for main thread to wait on
std::atomic<bool> update{};
/// Current state of the streams
StreamState state{StreamState::Filling};
};
} // namespace AudioCore::AudioRenderer

View File

@@ -44,8 +44,8 @@ public:
*/
CubebSinkStream(cubeb* ctx_, const u32 device_channels_, const u32 system_channels_,
cubeb_devid output_device, cubeb_devid input_device, const std::string& name_,
const StreamType type_, Core::System& system_, Common::Event* event)
: ctx{ctx_}, type{type_}, system{system_}, render_event{event} {
const StreamType type_, Core::System& system_)
: ctx{ctx_}, type{type_}, system{system_} {
#ifdef _WIN32
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
@@ -306,7 +306,6 @@ private:
manager.SetEvent(Event::Type::AudioInManager, true);
break;
case StreamType::Render:
render_event->Set();
break;
}
}
@@ -469,8 +468,6 @@ private:
::AudioCore::Sink::SinkBuffer released_buffer{};
/// The last played (or received) frame of audio, used when the callback underruns
std::array<s16, MaxChannels> last_frame{};
/// Audio render-only event, signalled when a render buffer is consumed
Common::Event* render_event;
};
CubebSink::CubebSink(std::string_view target_device_name) {
@@ -525,11 +522,9 @@ CubebSink::~CubebSink() {
}
SinkStream* CubebSink::AcquireSinkStream(Core::System& system, const u32 system_channels,
const std::string& name, const StreamType type,
Common::Event* event) {
SinkStreamPtr& stream = sink_streams.emplace_back(
std::make_unique<CubebSinkStream>(ctx, device_channels, system_channels, output_device,
input_device, name, type, system, event));
const std::string& name, const StreamType type) {
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>(
ctx, device_channels, system_channels, output_device, input_device, name, type, system));
return stream.get();
}

View File

@@ -39,8 +39,7 @@ public:
* @return A pointer to the created SinkStream
*/
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type,
Common::Event* event = nullptr) override;
const std::string& name, StreamType type) override;
/**
* Close a given stream.

View File

@@ -18,8 +18,7 @@ public:
SinkStream* AcquireSinkStream([[maybe_unused]] Core::System& system,
[[maybe_unused]] u32 system_channels,
[[maybe_unused]] const std::string& name,
[[maybe_unused]] StreamType type,
[[maybe_unused]] Common::Event* event = nullptr) override {
[[maybe_unused]] StreamType type) override {
return &null_sink_stream;
}

View File

@@ -46,8 +46,8 @@ public:
*/
SDLSinkStream(u32 device_channels_, const u32 system_channels_,
const std::string& output_device, const std::string& input_device,
const StreamType type_, Core::System& system_, Common::Event* event)
: type{type_}, system{system_}, render_event{event} {
const StreamType type_, Core::System& system_)
: type{type_}, system{system_} {
system_channels = system_channels_;
device_channels = device_channels_;
@@ -279,7 +279,6 @@ private:
manager.SetEvent(Event::Type::AudioInManager, true);
break;
case StreamType::Render:
render_event->Set();
break;
}
}
@@ -417,8 +416,6 @@ private:
::AudioCore::Sink::SinkBuffer released_buffer{};
/// The last played (or received) frame of audio, used when the callback underruns
std::array<s16, MaxChannels> last_frame{};
/// Audio render-only event, signalled when a render buffer is consumed
Common::Event* render_event;
};
SDLSink::SDLSink(std::string_view target_device_name) {
@@ -441,10 +438,9 @@ SDLSink::SDLSink(std::string_view target_device_name) {
SDLSink::~SDLSink() = default;
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, const u32 system_channels,
const std::string&, const StreamType type,
Common::Event* event) {
const std::string&, const StreamType type) {
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(
device_channels, system_channels, output_device, input_device, type, system, event));
device_channels, system_channels, output_device, input_device, type, system));
return stream.get();
}

View File

@@ -37,8 +37,7 @@ public:
* @return A pointer to the created SinkStream
*/
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type,
Common::Event* event = nullptr) override;
const std::string& name, StreamType type) override;
/**
* Close a given stream.

View File

@@ -63,8 +63,7 @@ public:
* @return A pointer to the created SinkStream
*/
virtual SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type,
Common::Event* event = nullptr) = 0;
const std::string& name, StreamType type) = 0;
/**
* Get the number of channels the hardware device supports.