early-access version 3381
This commit is contained in:
parent
248dd3823b
commit
0f06016cc7
22 changed files with 155 additions and 94 deletions
|
@ -1,7 +1,7 @@
|
|||
yuzu emulator early access
|
||||
=============
|
||||
|
||||
This is the source code for early-access 3380.
|
||||
This is the source code for early-access 3381.
|
||||
|
||||
## Legal Notice
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
*
|
||||
* @param out_buffers - The buffers which were registered.
|
||||
*/
|
||||
void RegisterBuffers(std::vector<AudioBuffer>& out_buffers) {
|
||||
void RegisterBuffers(std::span<AudioBuffer> out_buffers, u32& out_size) {
|
||||
std::scoped_lock l{lock};
|
||||
const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit),
|
||||
BufferAppendLimit - registered_count)};
|
||||
|
@ -59,7 +59,7 @@ public:
|
|||
index += N;
|
||||
}
|
||||
|
||||
out_buffers.push_back(buffers[index]);
|
||||
out_buffers[out_size++] = buffers[index];
|
||||
registered_count++;
|
||||
registered_index = (registered_index + 1) % append_limit;
|
||||
|
||||
|
@ -162,7 +162,7 @@ public:
|
|||
* @param max_buffers - Maximum number of buffers to released.
|
||||
* @return The number of buffers released.
|
||||
*/
|
||||
u32 GetRegisteredAppendedBuffers(std::vector<AudioBuffer>& buffers_flushed, u32 max_buffers) {
|
||||
u32 GetRegisteredAppendedBuffers(std::span<AudioBuffer> out_buffers, u32 max_buffers) {
|
||||
std::scoped_lock l{lock};
|
||||
if (registered_count + appended_count == 0) {
|
||||
return 0;
|
||||
|
@ -174,19 +174,20 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32 buffers_flushed{0};
|
||||
while (registered_count > 0) {
|
||||
auto index{registered_index - registered_count};
|
||||
if (index < 0) {
|
||||
index += N;
|
||||
}
|
||||
|
||||
buffers_flushed.push_back(buffers[index]);
|
||||
out_buffers[buffers_flushed++] = buffers[index];
|
||||
|
||||
registered_count--;
|
||||
released_count++;
|
||||
released_index = (released_index + 1) % append_limit;
|
||||
|
||||
if (buffers_flushed.size() >= buffers_to_flush) {
|
||||
if (buffers_flushed >= buffers_to_flush) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -197,18 +198,18 @@ public:
|
|||
index += N;
|
||||
}
|
||||
|
||||
buffers_flushed.push_back(buffers[index]);
|
||||
out_buffers[buffers_flushed++] = buffers[index];
|
||||
|
||||
appended_count--;
|
||||
released_count++;
|
||||
released_index = (released_index + 1) % append_limit;
|
||||
|
||||
if (buffers_flushed.size() >= buffers_to_flush) {
|
||||
if (buffers_flushed >= buffers_to_flush) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<u32>(buffers_flushed.size());
|
||||
return buffers_flushed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,8 +271,9 @@ public:
|
|||
*/
|
||||
bool FlushBuffers(u32& buffers_released) {
|
||||
std::scoped_lock l{lock};
|
||||
std::vector<AudioBuffer> buffers_flushed{};
|
||||
|
||||
static Common::ScratchBuffer<AudioBuffer> buffers_flushed{};
|
||||
buffers_flushed.resize_destructive(append_limit);
|
||||
buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit);
|
||||
|
||||
if (registered_count > 0) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "audio_core/device/audio_buffer.h"
|
||||
#include "audio_core/device/device_session.h"
|
||||
#include "audio_core/sink/sink_stream.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/memory.h"
|
||||
|
@ -79,21 +80,22 @@ void DeviceSession::ClearBuffers() {
|
|||
}
|
||||
}
|
||||
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
||||
for (const auto& buffer : buffers) {
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers, u32 out_size) const {
|
||||
static Common::ScratchBuffer<s16> samples{};
|
||||
|
||||
for (u32 i = 0; i < out_size; i++) {
|
||||
Sink::SinkBuffer new_buffer{
|
||||
.frames = buffer.size / (channel_count * sizeof(s16)),
|
||||
.frames = buffers[i].size / (channel_count * sizeof(s16)),
|
||||
.frames_played = 0,
|
||||
.tag = buffer.tag,
|
||||
.tag = buffers[i].tag,
|
||||
.consumed = false,
|
||||
};
|
||||
|
||||
if (type == Sink::StreamType::In) {
|
||||
std::vector<s16> samples{};
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
} else {
|
||||
std::vector<s16> samples(buffer.size / sizeof(s16));
|
||||
system.Memory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size);
|
||||
samples.resize_destructive(buffers[i].size / sizeof(s16));
|
||||
system.Memory().ReadBlockUnsafe(buffers[i].samples, samples.data(), buffers[i].size);
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
*
|
||||
* @param buffers - The buffers to play.
|
||||
*/
|
||||
void AppendBuffers(std::span<const AudioBuffer> buffers) const;
|
||||
void AppendBuffers(std::span<const AudioBuffer> buffers, u32 out_size) const;
|
||||
|
||||
/**
|
||||
* (Audio In only) Pop samples from the backend, and write them back to this buffer's address.
|
||||
|
|
|
@ -89,9 +89,10 @@ Result System::Start() {
|
|||
session->Start();
|
||||
state = State::Started;
|
||||
|
||||
std::vector<AudioBuffer> buffers_to_flush{};
|
||||
buffers.RegisterBuffers(buffers_to_flush);
|
||||
session->AppendBuffers(buffers_to_flush);
|
||||
std::array<AudioBuffer, BufferAppendLimit> buffers_to_flush{};
|
||||
u32 out_size{0};
|
||||
buffers.RegisterBuffers(buffers_to_flush, out_size);
|
||||
session->AppendBuffers(buffers_to_flush, out_size);
|
||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||
|
||||
return ResultSuccess;
|
||||
|
@ -134,9 +135,10 @@ bool System::AppendBuffer(const AudioInBuffer& buffer, const u64 tag) {
|
|||
|
||||
void System::RegisterBuffers() {
|
||||
if (state == State::Started) {
|
||||
std::vector<AudioBuffer> registered_buffers{};
|
||||
buffers.RegisterBuffers(registered_buffers);
|
||||
session->AppendBuffers(registered_buffers);
|
||||
std::array<AudioBuffer, BufferAppendLimit> registered_buffers{};
|
||||
u32 out_size{0};
|
||||
buffers.RegisterBuffers(registered_buffers, out_size);
|
||||
session->AppendBuffers(registered_buffers, out_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,9 +89,10 @@ Result System::Start() {
|
|||
session->Start();
|
||||
state = State::Started;
|
||||
|
||||
std::vector<AudioBuffer> buffers_to_flush{};
|
||||
buffers.RegisterBuffers(buffers_to_flush);
|
||||
session->AppendBuffers(buffers_to_flush);
|
||||
std::array<AudioBuffer, BufferAppendLimit> buffers_to_flush{};
|
||||
u32 out_size{0};
|
||||
buffers.RegisterBuffers(buffers_to_flush, out_size);
|
||||
session->AppendBuffers(buffers_to_flush, out_size);
|
||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||
|
||||
return ResultSuccess;
|
||||
|
@ -134,9 +135,10 @@ bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) {
|
|||
|
||||
void System::RegisterBuffers() {
|
||||
if (state == State::Started) {
|
||||
std::vector<AudioBuffer> registered_buffers{};
|
||||
buffers.RegisterBuffers(registered_buffers);
|
||||
session->AppendBuffers(registered_buffers);
|
||||
std::array<AudioBuffer, BufferAppendLimit> registered_buffers{};
|
||||
u32 out_size{0};
|
||||
buffers.RegisterBuffers(registered_buffers, out_size);
|
||||
session->AppendBuffers(registered_buffers, out_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info,
|
|||
while (destination != nullptr) {
|
||||
if (destination->IsConfigured()) {
|
||||
auto mix_id{destination->GetMixId()};
|
||||
if (mix_id < mix_context.GetCount()) {
|
||||
if (mix_id < mix_context.GetCount() && mix_id != -1) {
|
||||
auto mix_info{mix_context.GetInfo(mix_id)};
|
||||
command_buffer.GenerateDepopPrepareCommand(
|
||||
voice_info.node_id, voice_state, render_context.depop_buffer,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "audio_core/renderer/command/resample/resample.h"
|
||||
#include "common/fixed_point.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
@ -29,6 +30,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
const DecodeArg& req) {
|
||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||
static Common::ScratchBuffer<T> samples;
|
||||
|
||||
if (req.buffer == 0 || req.buffer_size == 0) {
|
||||
return 0;
|
||||
|
@ -49,7 +51,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
const u64 size{channel_count * samples_to_decode};
|
||||
const u64 size_bytes{size * sizeof(T)};
|
||||
|
||||
std::vector<T> samples(size);
|
||||
samples.resize_destructive(size);
|
||||
memory.ReadBlockUnsafe(source, samples.data(), size_bytes);
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
|
@ -73,7 +75,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
}
|
||||
|
||||
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
|
||||
std::vector<T> samples(samples_to_decode);
|
||||
samples.resize_destructive(samples_to_decode);
|
||||
memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T));
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
|
@ -103,6 +105,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
const DecodeArg& req) {
|
||||
constexpr u32 SamplesPerFrame{14};
|
||||
constexpr u32 NibblesPerFrame{16};
|
||||
static Common::ScratchBuffer<u8> wavebuffer;
|
||||
|
||||
if (req.buffer == 0 || req.buffer_size == 0) {
|
||||
return 0;
|
||||
|
@ -138,7 +141,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
}
|
||||
|
||||
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
|
||||
std::vector<u8> wavebuffer(size);
|
||||
wavebuffer.resize_destructive(size);
|
||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(),
|
||||
wavebuffer.size());
|
||||
|
||||
|
@ -227,6 +230,8 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
* @param args - The wavebuffer data, and information for how to decode it.
|
||||
*/
|
||||
void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuffersArgs& args) {
|
||||
Common::ScratchBuffer<s16> temp_buffer(TempBufferSize);
|
||||
|
||||
auto& voice_state{*args.voice_state};
|
||||
auto remaining_sample_count{args.sample_count};
|
||||
auto fraction{voice_state.fraction};
|
||||
|
@ -256,9 +261,8 @@ void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuf
|
|||
|
||||
bool is_buffer_starved{false};
|
||||
u32 offset{voice_state.offset};
|
||||
|
||||
std::memset(temp_buffer.data(), 0, temp_buffer.size() * sizeof(s16));
|
||||
auto output_buffer{args.output};
|
||||
std::vector<s16> temp_buffer(TempBufferSize, 0);
|
||||
|
||||
while (remaining_sample_count > 0) {
|
||||
const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/aux_.h"
|
||||
#include "audio_core/renderer/effect/aux_.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
@ -174,6 +175,19 @@ void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& process
|
|||
}
|
||||
|
||||
void AuxCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
// HACK!
|
||||
// Ignore aux for Super Mario Odyssey and Metroid Prime Remastered.
|
||||
// For some reason these games receive output samples, and then send them back in as input
|
||||
// again. Problem is the data being sent back in is slightly offset from the current output by
|
||||
// 240 or 480 samples, leading to a very fast echoing effect, which should not be there.
|
||||
// Timing issue or some bug in the code?
|
||||
// We can't disable this unconditionally as some games rely on it for synchronisation and will
|
||||
// softlock without it (Age of Calamity).
|
||||
const auto program_id = processor.system->GetCurrentProcessProgramID();
|
||||
if (program_id == 0x0100000000010000ull || program_id == 0x010012101468C000ull) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto input_buffer{
|
||||
processor.mix_buffers.subspan(input * processor.sample_count, processor.sample_count)};
|
||||
auto output_buffer{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/biquad_filter.h"
|
||||
#include "audio_core/renderer/voice/voice_state.h"
|
||||
#include "common/bit_cast.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
/**
|
||||
|
@ -19,21 +20,21 @@ namespace AudioCore::AudioRenderer {
|
|||
void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
|
||||
std::array<s16, 3>& b_, std::array<s16, 2>& a_,
|
||||
VoiceState::BiquadFilterState& state, const u32 sample_count) {
|
||||
constexpr s64 min{std::numeric_limits<s32>::min()};
|
||||
constexpr s64 max{std::numeric_limits<s32>::max()};
|
||||
constexpr f64 min{std::numeric_limits<s32>::min()};
|
||||
constexpr f64 max{std::numeric_limits<s32>::max()};
|
||||
std::array<f64, 3> b{Common::FixedPoint<50, 14>::from_base(b_[0]).to_double(),
|
||||
Common::FixedPoint<50, 14>::from_base(b_[1]).to_double(),
|
||||
Common::FixedPoint<50, 14>::from_base(b_[2]).to_double()};
|
||||
std::array<f64, 2> a{Common::FixedPoint<50, 14>::from_base(a_[0]).to_double(),
|
||||
Common::FixedPoint<50, 14>::from_base(a_[1]).to_double()};
|
||||
std::array<f64, 4> s{state.s0.to_double(), state.s1.to_double(), state.s2.to_double(),
|
||||
state.s3.to_double()};
|
||||
std::array<f64, 4> s{Common::BitCast<f64>(state.s0), Common::BitCast<f64>(state.s1),
|
||||
Common::BitCast<f64>(state.s2), Common::BitCast<f64>(state.s3)};
|
||||
|
||||
for (u32 i = 0; i < sample_count; i++) {
|
||||
f64 in_sample{static_cast<f64>(input[i])};
|
||||
auto sample{in_sample * b[0] + s[0] * b[1] + s[1] * b[2] + s[2] * a[0] + s[3] * a[1]};
|
||||
|
||||
output[i] = static_cast<s32>(std::clamp(static_cast<s64>(sample), min, max));
|
||||
output[i] = static_cast<s32>(std::clamp(sample, min, max));
|
||||
|
||||
s[1] = s[0];
|
||||
s[0] = in_sample;
|
||||
|
@ -41,10 +42,10 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
|
|||
s[2] = sample;
|
||||
}
|
||||
|
||||
state.s0 = s[0];
|
||||
state.s1 = s[1];
|
||||
state.s2 = s[2];
|
||||
state.s3 = s[3];
|
||||
state.s0 = Common::BitCast<s64>(s[0]);
|
||||
state.s1 = Common::BitCast<s64>(s[1]);
|
||||
state.s2 = Common::BitCast<s64>(s[2]);
|
||||
state.s3 = Common::BitCast<s64>(s[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,29 +59,20 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
|
|||
* @param sample_count - Number of samples to process.
|
||||
*/
|
||||
static void ApplyBiquadFilterInt(std::span<s32> output, std::span<const s32> input,
|
||||
std::array<s16, 3>& b_, std::array<s16, 2>& a_,
|
||||
std::array<s16, 3>& b, std::array<s16, 2>& a,
|
||||
VoiceState::BiquadFilterState& state, const u32 sample_count) {
|
||||
constexpr s64 min{std::numeric_limits<s32>::min()};
|
||||
constexpr s64 max{std::numeric_limits<s32>::max()};
|
||||
std::array<Common::FixedPoint<50, 14>, 3> b{
|
||||
Common::FixedPoint<50, 14>::from_base(b_[0]),
|
||||
Common::FixedPoint<50, 14>::from_base(b_[1]),
|
||||
Common::FixedPoint<50, 14>::from_base(b_[2]),
|
||||
};
|
||||
std::array<Common::FixedPoint<50, 14>, 3> a{
|
||||
Common::FixedPoint<50, 14>::from_base(a_[0]),
|
||||
Common::FixedPoint<50, 14>::from_base(a_[1]),
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < sample_count; i++) {
|
||||
s64 in_sample{input[i]};
|
||||
auto sample{in_sample * b[0] + state.s0};
|
||||
const auto out_sample{std::clamp(sample.to_long(), min, max)};
|
||||
const s64 in_sample{input[i]};
|
||||
const s64 sample{in_sample * b[0] + state.s0};
|
||||
const s64 out_sample{std::clamp<s64>((sample + (1 << 13)) >> 14, min, max)};
|
||||
|
||||
output[i] = static_cast<s32>(out_sample);
|
||||
|
||||
state.s0 = state.s1 + b[1] * in_sample + a[0] * out_sample;
|
||||
state.s1 = 0 + b[2] * in_sample + a[1] * out_sample;
|
||||
state.s1 = b[2] * in_sample + a[1] * out_sample;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/compressor.h"
|
||||
#include "audio_core/renderer/effect/compressor.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
|
@ -44,8 +45,8 @@ static void InitializeCompressorEffect(const CompressorInfo::ParameterVersion2&
|
|||
|
||||
static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
|
||||
CompressorInfo::State& state, bool enabled,
|
||||
std::vector<std::span<const s32>> input_buffers,
|
||||
std::vector<std::span<s32>> output_buffers, u32 sample_count) {
|
||||
std::span<std::span<const s32>> input_buffers,
|
||||
std::span<std::span<s32>> output_buffers, u32 sample_count) {
|
||||
if (enabled) {
|
||||
auto state_00{state.unk_00};
|
||||
auto state_04{state.unk_04};
|
||||
|
@ -124,8 +125,10 @@ void CompressorCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor&
|
|||
}
|
||||
|
||||
void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
||||
input_buffers.resize_destructive(parameter.channel_count);
|
||||
output_buffers.resize_destructive(parameter.channel_count);
|
||||
|
||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/delay.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
/**
|
||||
|
@ -74,8 +75,8 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params,
|
|||
*/
|
||||
template <size_t NumChannels>
|
||||
static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
||||
std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
std::span<std::span<const s32>> inputs, std::span<std::span<s32>> outputs,
|
||||
const u32 sample_count) {
|
||||
for (u32 sample_index = 0; sample_index < sample_count; sample_index++) {
|
||||
std::array<Common::FixedPoint<50, 14>, NumChannels> input_samples{};
|
||||
for (u32 channel = 0; channel < NumChannels; channel++) {
|
||||
|
@ -153,8 +154,8 @@ static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::St
|
|||
* @param sample_count - Number of samples to process.
|
||||
*/
|
||||
static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
||||
const bool enabled, std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
const bool enabled, std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
||||
|
||||
if (!IsChannelCountValid(params.channel_count)) {
|
||||
LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count);
|
||||
|
@ -208,8 +209,10 @@ void DelayCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proce
|
|||
}
|
||||
|
||||
void DelayCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
||||
input_buffers.resize_destructive(parameter.channel_count);
|
||||
output_buffers.resize_destructive(parameter.channel_count);
|
||||
|
||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/i3dl2_reverb.h"
|
||||
#include "common/polyfill_ranges.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
|
@ -408,8 +409,10 @@ void I3dl2ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor&
|
|||
}
|
||||
|
||||
void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
||||
input_buffers.resize_destructive(parameter.channel_count);
|
||||
output_buffers.resize_destructive(parameter.channel_count);
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/light_limiter.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
/**
|
||||
|
@ -47,8 +48,8 @@ static void InitializeLightLimiterEffect(const LightLimiterInfo::ParameterVersio
|
|||
*/
|
||||
static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params,
|
||||
LightLimiterInfo::State& state, const bool enabled,
|
||||
std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count,
|
||||
std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count,
|
||||
LightLimiterInfo::StatisticsInternal* statistics) {
|
||||
constexpr s64 min{std::numeric_limits<s32>::min()};
|
||||
constexpr s64 max{std::numeric_limits<s32>::max()};
|
||||
|
@ -147,8 +148,10 @@ void LightLimiterVersion1Command::Dump([[maybe_unused]] const ADSP::CommandListP
|
|||
}
|
||||
|
||||
void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
||||
input_buffers.resize_destructive(parameter.channel_count);
|
||||
output_buffers.resize_destructive(parameter.channel_count);
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
@ -190,8 +193,10 @@ void LightLimiterVersion2Command::Dump([[maybe_unused]] const ADSP::CommandListP
|
|||
}
|
||||
|
||||
void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
||||
input_buffers.resize_destructive(parameter.channel_count);
|
||||
output_buffers.resize_destructive(parameter.channel_count);
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/effect/reverb.h"
|
||||
#include "common/polyfill_ranges.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
|
@ -250,8 +251,8 @@ static Common::FixedPoint<50, 14> Axfx2AllPassTick(ReverbInfo::ReverbDelayLine&
|
|||
*/
|
||||
template <size_t NumChannels>
|
||||
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
||||
std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
||||
constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
@ -368,8 +369,8 @@ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, Rever
|
|||
* @param sample_count - Number of samples to process.
|
||||
*/
|
||||
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
||||
const bool enabled, std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
const bool enabled, std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
||||
if (enabled) {
|
||||
switch (params.channel_count) {
|
||||
case 0:
|
||||
|
@ -411,8 +412,10 @@ void ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proc
|
|||
}
|
||||
|
||||
void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
||||
input_buffers.resize_destructive(parameter.channel_count);
|
||||
output_buffers.resize_destructive(parameter.channel_count);
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||
#include "audio_core/renderer/command/sink/circular_buffer.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
@ -24,7 +25,9 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces
|
|||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||
|
||||
std::vector<s16> output(processor.sample_count);
|
||||
static Common::ScratchBuffer<s16> output{};
|
||||
output.resize_destructive(processor.sample_count);
|
||||
|
||||
for (u32 channel = 0; channel < input_count; channel++) {
|
||||
auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count,
|
||||
processor.sample_count)};
|
||||
|
|
|
@ -33,7 +33,8 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
|||
.consumed{false},
|
||||
};
|
||||
|
||||
std::vector<s16> samples(out_buffer.frames * input_count);
|
||||
static Common::ScratchBuffer<s16> samples{};
|
||||
samples.resize_destructive(out_buffer.frames * input_count);
|
||||
|
||||
for (u32 channel = 0; channel < input_count; channel++) {
|
||||
const auto offset{inputs[channel] * out_buffer.frames};
|
||||
|
|
|
@ -19,10 +19,10 @@ struct VoiceState {
|
|||
* State of the voice's biquad filter.
|
||||
*/
|
||||
struct BiquadFilterState {
|
||||
Common::FixedPoint<50, 14> s0;
|
||||
Common::FixedPoint<50, 14> s1;
|
||||
Common::FixedPoint<50, 14> s2;
|
||||
Common::FixedPoint<50, 14> s3;
|
||||
s64 s0;
|
||||
s64 s1;
|
||||
s64 s2;
|
||||
s64 s3;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "audio_core/sink/sink.h"
|
||||
#include "audio_core/sink/sink_stream.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
@ -20,7 +21,7 @@ public:
|
|||
explicit NullSinkStreamImpl(Core::System& system_, StreamType type_)
|
||||
: SinkStream{system_, type_} {}
|
||||
~NullSinkStreamImpl() override {}
|
||||
void AppendBuffer(SinkBuffer&, std::vector<s16>&) override {}
|
||||
void AppendBuffer(SinkBuffer&, Common::ScratchBuffer<s16>&) override {}
|
||||
std::vector<s16> ReleaseBuffer(u64) override {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
namespace AudioCore::Sink {
|
||||
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, Common::ScratchBuffer<s16>& samples) {
|
||||
if (type == StreamType::In) {
|
||||
queue.enqueue(buffer);
|
||||
queued_buffers++;
|
||||
|
@ -71,7 +71,9 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
|||
// We need moar samples! Not all games will provide 6 channel audio.
|
||||
// TODO: Implement some upmixing here. Currently just passthrough, with other
|
||||
// channels left as silence.
|
||||
std::vector<s16> new_samples(samples.size() / system_channels * device_channels, 0);
|
||||
static Common::ScratchBuffer<s16> new_samples{};
|
||||
new_samples.resize_destructive(samples.size() / system_channels * device_channels);
|
||||
std::memset(new_samples.data(), 0, new_samples.size() * sizeof(s16));
|
||||
|
||||
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||
read_index += system_channels, write_index += device_channels) {
|
||||
|
@ -100,7 +102,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
|||
}
|
||||
}
|
||||
|
||||
samples_buffer.Push(samples);
|
||||
samples_buffer.Push(samples.data(), samples.size());
|
||||
queue.enqueue(buffer);
|
||||
queued_buffers++;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "common/common_types.h"
|
||||
#include "common/reader_writer_queue.h"
|
||||
#include "common/ring_buffer.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
@ -169,7 +170,7 @@ public:
|
|||
* @param buffer - Audio buffer information to be queued.
|
||||
* @param samples - The s16 samples to be queue for playback.
|
||||
*/
|
||||
virtual void AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples);
|
||||
virtual void AppendBuffer(SinkBuffer& buffer, Common::ScratchBuffer<s16>& samples);
|
||||
|
||||
/**
|
||||
* Release a buffer. Audio In only, will fill a buffer with recorded samples.
|
||||
|
|
|
@ -24,6 +24,24 @@ public:
|
|||
|
||||
~ScratchBuffer() = default;
|
||||
|
||||
ScratchBuffer(ScratchBuffer&& rhs) {
|
||||
last_requested_size = rhs.last_requested_size;
|
||||
buffer_capacity = rhs.buffer_capacity;
|
||||
buffer = std::move(rhs.buffer);
|
||||
|
||||
rhs.last_requested_size = 0;
|
||||
rhs.buffer_capacity = 0;
|
||||
}
|
||||
|
||||
void operator=(ScratchBuffer&& rhs) {
|
||||
last_requested_size = rhs.last_requested_size;
|
||||
buffer_capacity = rhs.buffer_capacity;
|
||||
buffer = std::move(rhs.buffer);
|
||||
|
||||
rhs.last_requested_size = 0;
|
||||
rhs.buffer_capacity = 0;
|
||||
}
|
||||
|
||||
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
||||
/// The previously held data will remain intact.
|
||||
void resize(size_t size) {
|
||||
|
|
Loading…
Reference in a new issue