Remove memory allocations in some hot paths
This commit is contained in:
parent
e3122c5b46
commit
5da70f7197
84 changed files with 501 additions and 458 deletions
|
@ -7,6 +7,7 @@
|
|||
#include <mutex>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "audio_buffer.h"
|
||||
#include "audio_core/device/device_session.h"
|
||||
|
@ -48,7 +49,7 @@ public:
|
|||
*
|
||||
* @param out_buffers - The buffers which were registered.
|
||||
*/
|
||||
void RegisterBuffers(std::vector<AudioBuffer>& out_buffers) {
|
||||
void RegisterBuffers(boost::container::static_vector<AudioBuffer, N>& out_buffers) {
|
||||
std::scoped_lock l{lock};
|
||||
const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit),
|
||||
BufferAppendLimit - registered_count)};
|
||||
|
@ -162,7 +163,8 @@ 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(
|
||||
boost::container::static_vector<AudioBuffer, N>& buffers_flushed, u32 max_buffers) {
|
||||
std::scoped_lock l{lock};
|
||||
if (registered_count + appended_count == 0) {
|
||||
return 0;
|
||||
|
@ -270,7 +272,7 @@ public:
|
|||
*/
|
||||
bool FlushBuffers(u32& buffers_released) {
|
||||
std::scoped_lock l{lock};
|
||||
std::vector<AudioBuffer> buffers_flushed{};
|
||||
boost::container::static_vector<AudioBuffer, N> buffers_flushed{};
|
||||
|
||||
buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ void DeviceSession::ClearBuffers() {
|
|||
}
|
||||
}
|
||||
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
|
||||
for (const auto& buffer : buffers) {
|
||||
Sink::SinkBuffer new_buffer{
|
||||
.frames = buffer.size / (channel_count * sizeof(s16)),
|
||||
|
@ -88,13 +88,13 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
|||
.consumed = false,
|
||||
};
|
||||
|
||||
tmp_samples.resize_destructive(buffer.size / sizeof(s16));
|
||||
if (type == Sink::StreamType::In) {
|
||||
std::vector<s16> samples{};
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
stream->AppendBuffer(new_buffer, tmp_samples);
|
||||
} else {
|
||||
std::vector<s16> samples(buffer.size / sizeof(s16));
|
||||
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size);
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(),
|
||||
buffer.size);
|
||||
stream->AppendBuffer(new_buffer, tmp_samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/sink/sink.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace Core {
|
||||
|
@ -62,7 +63,7 @@ public:
|
|||
*
|
||||
* @param buffers - The buffers to play.
|
||||
*/
|
||||
void AppendBuffers(std::span<const AudioBuffer> buffers) const;
|
||||
void AppendBuffers(std::span<const AudioBuffer> buffers);
|
||||
|
||||
/**
|
||||
* (Audio In only) Pop samples from the backend, and write them back to this buffer's address.
|
||||
|
@ -146,8 +147,8 @@ private:
|
|||
std::shared_ptr<Core::Timing::EventType> thread_event;
|
||||
/// Is this session initialised?
|
||||
bool initialized{};
|
||||
/// Buffer queue
|
||||
std::vector<AudioBuffer> buffer_queue{};
|
||||
/// Temporary sample buffer
|
||||
Common::ScratchBuffer<s16> tmp_samples{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "audio_core/audio_event.h"
|
||||
#include "audio_core/audio_manager.h"
|
||||
#include "audio_core/in/audio_in_system.h"
|
||||
|
@ -89,7 +90,7 @@ Result System::Start() {
|
|||
session->Start();
|
||||
state = State::Started;
|
||||
|
||||
std::vector<AudioBuffer> buffers_to_flush{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
|
||||
buffers.RegisterBuffers(buffers_to_flush);
|
||||
session->AppendBuffers(buffers_to_flush);
|
||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||
|
@ -134,7 +135,7 @@ bool System::AppendBuffer(const AudioInBuffer& buffer, const u64 tag) {
|
|||
|
||||
void System::RegisterBuffers() {
|
||||
if (state == State::Started) {
|
||||
std::vector<AudioBuffer> registered_buffers{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
|
||||
buffers.RegisterBuffers(registered_buffers);
|
||||
session->AppendBuffers(registered_buffers);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ Result System::Start() {
|
|||
session->Start();
|
||||
state = State::Started;
|
||||
|
||||
std::vector<AudioBuffer> buffers_to_flush{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
|
||||
buffers.RegisterBuffers(buffers_to_flush);
|
||||
session->AppendBuffers(buffers_to_flush);
|
||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||
|
@ -134,7 +134,7 @@ bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) {
|
|||
|
||||
void System::RegisterBuffers() {
|
||||
if (state == State::Started) {
|
||||
std::vector<AudioBuffer> registered_buffers{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
|
||||
buffers.RegisterBuffers(registered_buffers);
|
||||
session->AppendBuffers(registered_buffers);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -27,6 +28,7 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4};
|
|||
template <typename T>
|
||||
static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const DecodeArg& req) {
|
||||
std::array<T, TempBufferSize> tmp_samples{};
|
||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||
|
||||
|
@ -49,18 +51,17 @@ 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);
|
||||
memory.ReadBlockUnsafe(source, samples.data(), size_bytes);
|
||||
memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes);
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
|
||||
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
|
||||
std::numeric_limits<s16>::max())};
|
||||
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
|
||||
}
|
||||
} else {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
out_buffer[i] = samples[i * channel_count + req.target_channel];
|
||||
out_buffer[i] = tmp_samples[i * channel_count + req.target_channel];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -73,17 +74,16 @@ 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);
|
||||
memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T));
|
||||
memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T));
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
|
||||
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
|
||||
std::numeric_limits<s16>::max())};
|
||||
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
|
||||
}
|
||||
} else {
|
||||
std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16));
|
||||
std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||
*/
|
||||
static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const DecodeArg& req) {
|
||||
std::array<u8, TempBufferSize> wavebuffer{};
|
||||
constexpr u32 SamplesPerFrame{14};
|
||||
constexpr u32 NibblesPerFrame{16};
|
||||
|
||||
|
@ -138,9 +139,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);
|
||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(),
|
||||
wavebuffer.size());
|
||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size);
|
||||
|
||||
auto context{req.adpcm_context};
|
||||
auto header{context->header};
|
||||
|
@ -258,7 +257,7 @@ void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuf
|
|||
u32 offset{voice_state.offset};
|
||||
|
||||
auto output_buffer{args.output};
|
||||
std::vector<s16> temp_buffer(TempBufferSize, 0);
|
||||
std::array<s16, TempBufferSize> temp_buffer{};
|
||||
|
||||
while (remaining_sample_count > 0) {
|
||||
const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)};
|
||||
|
|
|
@ -44,8 +44,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 +124,8 @@ 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);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -51,7 +51,7 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params,
|
|||
state.delay_lines[channel].sample_count_max = sample_count_max.to_int_floor();
|
||||
state.delay_lines[channel].sample_count = sample_count.to_int_floor();
|
||||
state.delay_lines[channel].buffer.resize(state.delay_lines[channel].sample_count, 0);
|
||||
if (state.delay_lines[channel].buffer.size() == 0) {
|
||||
if (state.delay_lines[channel].sample_count == 0) {
|
||||
state.delay_lines[channel].buffer.push_back(0);
|
||||
}
|
||||
state.delay_lines[channel].buffer_pos = 0;
|
||||
|
@ -74,8 +74,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 +153,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 +208,8 @@ 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);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -408,8 +408,8 @@ 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);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -47,8 +47,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 +147,8 @@ 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);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
@ -190,8 +190,8 @@ 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);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -250,8 +250,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) {
|
||||
static constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
@ -369,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:
|
||||
|
@ -412,8 +412,8 @@ 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);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
|
|
@ -24,7 +24,7 @@ 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);
|
||||
std::array<s16, TargetSampleCount * MaxChannels> output{};
|
||||
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,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces
|
|||
}
|
||||
|
||||
processor.memory->WriteBlockUnsafe(address + pos, output.data(),
|
||||
output.size() * sizeof(s16));
|
||||
processor.sample_count * sizeof(s16));
|
||||
pos += static_cast<u32>(processor.sample_count * sizeof(s16));
|
||||
if (pos >= size) {
|
||||
pos = 0;
|
||||
|
|
|
@ -33,8 +33,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
|||
.consumed{false},
|
||||
};
|
||||
|
||||
std::vector<s16> samples(out_buffer.frames * input_count);
|
||||
|
||||
std::array<s16, TargetSampleCount * MaxChannels> samples{};
|
||||
for (u32 channel = 0; channel < input_count; channel++) {
|
||||
const auto offset{inputs[channel] * out_buffer.frames};
|
||||
|
||||
|
@ -45,7 +44,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
|||
}
|
||||
|
||||
out_buffer.tag = reinterpret_cast<u64>(samples.data());
|
||||
stream->AppendBuffer(out_buffer, samples);
|
||||
stream->AppendBuffer(out_buffer, {samples.data(), out_buffer.frames * input_count});
|
||||
|
||||
if (stream->IsPaused()) {
|
||||
stream->Start();
|
||||
|
|
|
@ -125,10 +125,10 @@ bool MixContext::TSortInfo(const SplitterContext& splitter_context) {
|
|||
return false;
|
||||
}
|
||||
|
||||
std::vector<s32> sorted_results{node_states.GetSortedResuls()};
|
||||
const auto result_size{std::min(count, static_cast<s32>(sorted_results.size()))};
|
||||
auto sorted_results{node_states.GetSortedResuls()};
|
||||
const auto result_size{std::min(count, static_cast<s32>(sorted_results.second))};
|
||||
for (s32 i = 0; i < result_size; i++) {
|
||||
sorted_mix_infos[i] = &mix_infos[sorted_results[i]];
|
||||
sorted_mix_infos[i] = &mix_infos[sorted_results.first[i]];
|
||||
}
|
||||
|
||||
CalcMixBufferOffset();
|
||||
|
|
|
@ -134,8 +134,8 @@ u32 NodeStates::GetNodeCount() const {
|
|||
return node_count;
|
||||
}
|
||||
|
||||
std::vector<s32> NodeStates::GetSortedResuls() const {
|
||||
return {results.rbegin(), results.rbegin() + result_pos};
|
||||
std::pair<std::span<u32>::reverse_iterator, size_t> NodeStates::GetSortedResuls() const {
|
||||
return {results.rbegin(), result_pos};
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
||||
|
|
|
@ -175,7 +175,7 @@ public:
|
|||
*
|
||||
* @return Vector of nodes in reverse order.
|
||||
*/
|
||||
std::vector<s32> GetSortedResuls() const;
|
||||
std::pair<std::span<u32>::reverse_iterator, size_t> GetSortedResuls() const;
|
||||
|
||||
private:
|
||||
/// Number of nodes in the graph
|
||||
|
|
|
@ -444,6 +444,7 @@ Result System::Update(std::span<const u8> input, std::span<u8> performance, std:
|
|||
std::scoped_lock l{lock};
|
||||
|
||||
const auto start_time{core.CoreTiming().GetClockTicks()};
|
||||
std::memset(output.data(), 0, output.size());
|
||||
|
||||
InfoUpdater info_updater(input, output, process_handle, behavior);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
explicit NullSinkStreamImpl(Core::System& system_, StreamType type_)
|
||||
: SinkStream{system_, type_} {}
|
||||
~NullSinkStreamImpl() override {}
|
||||
void AppendBuffer(SinkBuffer&, std::vector<s16>&) override {}
|
||||
void AppendBuffer(SinkBuffer&, std::span<s16>) override {}
|
||||
std::vector<s16> ReleaseBuffer(u64) override {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
namespace AudioCore::Sink {
|
||||
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
||||
if (type == StreamType::In) {
|
||||
queue.enqueue(buffer);
|
||||
queued_buffers++;
|
||||
|
@ -66,15 +66,16 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
|||
static_cast<s16>(std::clamp(right_sample, min, max));
|
||||
}
|
||||
|
||||
samples.resize(samples.size() / system_channels * device_channels);
|
||||
samples = samples.subspan(0, samples.size() / system_channels * device_channels);
|
||||
|
||||
} else if (system_channels == 2 && device_channels == 6) {
|
||||
// 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);
|
||||
auto new_size = samples.size() / system_channels * device_channels;
|
||||
tmp_samples.resize_destructive(new_size);
|
||||
|
||||
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||
for (u32 read_index = 0, write_index = 0; read_index < new_size;
|
||||
read_index += system_channels, write_index += device_channels) {
|
||||
const auto left_sample{static_cast<s16>(std::clamp(
|
||||
static_cast<s32>(
|
||||
|
@ -82,7 +83,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
|||
volume),
|
||||
min, max))};
|
||||
|
||||
new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample;
|
||||
tmp_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample;
|
||||
|
||||
const auto right_sample{static_cast<s16>(std::clamp(
|
||||
static_cast<s32>(
|
||||
|
@ -90,9 +91,9 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
|||
volume),
|
||||
min, max))};
|
||||
|
||||
new_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample;
|
||||
tmp_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample;
|
||||
}
|
||||
samples = std::move(new_samples);
|
||||
samples = std::span<s16>(tmp_samples);
|
||||
|
||||
} else if (volume != 1.0f) {
|
||||
for (u32 i = 0; i < samples.size(); i++) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "common/polyfill_thread.h"
|
||||
#include "common/reader_writer_queue.h"
|
||||
#include "common/ring_buffer.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/thread.h"
|
||||
|
||||
namespace Core {
|
||||
|
@ -170,7 +171,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, std::span<s16> samples);
|
||||
|
||||
/**
|
||||
* Release a buffer. Audio In only, will fill a buffer with recorded samples.
|
||||
|
@ -255,6 +256,8 @@ private:
|
|||
/// Signalled when ring buffer entries are consumed
|
||||
std::condition_variable_any release_cv;
|
||||
std::mutex release_mutex;
|
||||
/// Temporary buffer for appending samples when upmixing
|
||||
Common::ScratchBuffer<s16> tmp_samples{};
|
||||
};
|
||||
|
||||
using SinkStreamPtr = std::unique_ptr<SinkStream>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue