Preliminary effects

This commit is contained in:
David Marcec 2020-08-17 01:23:55 +10:00
parent ac9d36c1dc
commit f17f347e03
10 changed files with 731 additions and 35 deletions

View file

@ -4,6 +4,7 @@
#include "audio_core/algorithm/interpolate.h"
#include "audio_core/command_generator.h"
#include "audio_core/effect_context.h"
#include "audio_core/mix_context.h"
#include "audio_core/voice_context.h"
#include "core/memory.h"
@ -68,9 +69,10 @@ s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
VoiceContext& voice_context, MixContext& mix_context,
SplitterContext& splitter_context, Core::Memory::Memory& memory)
SplitterContext& splitter_context, EffectContext& effect_context,
Core::Memory::Memory& memory)
: worker_params(worker_params), voice_context(voice_context), mix_context(mix_context),
splitter_context(splitter_context), memory(memory),
splitter_context(splitter_context), effect_context(effect_context), memory(memory),
mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
worker_params.sample_count),
sample_buffer(MIX_BUFFER_SIZE),
@ -338,6 +340,120 @@ void CommandGenerator::GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_
}
}
void CommandGenerator::GenerateEffectCommand(ServerMixInfo& mix_info) {
const std::size_t effect_count = effect_context.GetCount();
const auto buffer_offset = mix_info.GetInParams().buffer_offset;
for (std::size_t i = 0; i < effect_count; i++) {
const auto index = mix_info.GetEffectOrder(i);
if (index == AudioCommon::NO_EFFECT_ORDER) {
break;
}
auto* info = effect_context.GetInfo(index);
const auto type = info->GetType();
// TODO(ogniK): Finish remaining effects
switch (type) {
case EffectType::Aux:
GenerateAuxCommand(buffer_offset, info, info->IsEnabled());
break;
case EffectType::I3dl2Reverb:
GenerateI3dl2ReverbEffectCommand(buffer_offset, info, info->IsEnabled());
break;
case EffectType::BiquadFilter:
GenerateBiquadFilterEffectCommand(buffer_offset, info, info->IsEnabled());
break;
default:
break;
}
info->UpdateForCommandGeneration();
}
}
void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info,
bool enabled) {
if (!enabled) {
return;
}
const auto& params = dynamic_cast<EffectI3dl2Reverb*>(info)->GetParams();
const auto channel_count = params.channel_count;
for (s32 i = 0; i < channel_count; i++) {
// TODO(ogniK): Actually implement reverb
if (params.input[i] != params.output[i]) {
const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
ApplyMix<1>(output, input, 32768, worker_params.sample_count);
}
}
}
void CommandGenerator::GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info,
bool enabled) {
if (!enabled) {
return;
}
const auto& params = dynamic_cast<EffectBiquadFilter*>(info)->GetParams();
const auto channel_count = params.channel_count;
for (s32 i = 0; i < channel_count; i++) {
// TODO(ogniK): Actually implement biquad filter
if (params.input[i] != params.output[i]) {
const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
ApplyMix<1>(output, input, 32768, worker_params.sample_count);
}
}
}
void CommandGenerator::GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled) {
auto aux = dynamic_cast<EffectAuxInfo*>(info);
const auto& params = aux->GetParams();
if (aux->GetSendBuffer() != 0 && aux->GetRecvBuffer() != 0) {
const auto max_channels = params.count;
u32 offset{};
for (u32 channel = 0; channel < max_channels; channel++) {
u32 write_count = 0;
if (channel == (max_channels - 1)) {
write_count = offset + worker_params.sample_count;
}
const auto input_index = params.input_mix_buffers[channel] + mix_buffer_offset;
const auto output_index = params.output_mix_buffers[channel] + mix_buffer_offset;
if (enabled) {
AuxInfoDSP send_info{};
AuxInfoDSP recv_info{};
memory.ReadBlock(aux->GetSendInfo(), &send_info, sizeof(AuxInfoDSP));
memory.ReadBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
WriteAuxBuffer(send_info, aux->GetSendBuffer(), params.sample_count,
GetMixBuffer(input_index), worker_params.sample_count, offset,
write_count);
memory.WriteBlock(aux->GetSendInfo(), &send_info, sizeof(AuxInfoDSP));
const auto samples_read = ReadAuxBuffer(
recv_info, aux->GetRecvBuffer(), params.sample_count,
GetMixBuffer(output_index), worker_params.sample_count, offset, write_count);
memory.WriteBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
if (samples_read != worker_params.sample_count &&
samples_read <= params.sample_count) {
std::memset(GetMixBuffer(output_index), 0, params.sample_count - samples_read);
}
} else {
AuxInfoDSP empty{};
memory.WriteBlock(aux->GetSendInfo(), &empty, sizeof(AuxInfoDSP));
memory.WriteBlock(aux->GetRecvInfo(), &empty, sizeof(AuxInfoDSP));
if (output_index != input_index) {
std::memcpy(GetMixBuffer(output_index), GetMixBuffer(input_index),
worker_params.sample_count * sizeof(s32));
}
}
offset += worker_params.sample_count;
}
}
}
ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) {
if (splitter_id == AudioCommon::NO_SPLITTER) {
return nullptr;
@ -345,6 +461,66 @@ ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter
return splitter_context.GetDestinationData(splitter_id, index);
}
s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples,
const s32* data, u32 sample_count, u32 write_offset,
u32 write_count) {
if (max_samples == 0) {
return 0;
}
u32 offset = dsp_info.write_offset + write_offset;
if (send_buffer == 0 || offset > max_samples) {
return 0;
}
std::size_t data_offset{};
u32 remaining = sample_count;
while (remaining > 0) {
// Get position in buffer
const auto base = send_buffer + (offset * sizeof(u32));
const auto samples_to_grab = std::min(max_samples - offset, remaining);
// Write to output
memory.WriteBlock(base, (data + data_offset), samples_to_grab * sizeof(u32));
offset = (offset + samples_to_grab) % max_samples;
remaining -= samples_to_grab;
data_offset += samples_to_grab;
}
if (write_count != 0) {
dsp_info.write_offset = (dsp_info.write_offset + write_count) % max_samples;
}
return sample_count;
}
s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples,
s32* out_data, u32 sample_count, u32 read_offset,
u32 read_count) {
if (max_samples == 0) {
return 0;
}
u32 offset = recv_info.read_offset + read_offset;
if (recv_buffer == 0 || offset > max_samples) {
return 0;
}
u32 remaining = sample_count;
while (remaining > 0) {
const auto base = recv_buffer + (offset * sizeof(u32));
const auto samples_to_grab = std::min(max_samples - offset, remaining);
std::vector<s32> buffer(samples_to_grab);
memory.ReadBlock(base, buffer.data(), buffer.size() * sizeof(u32));
std::memcpy(out_data, buffer.data(), buffer.size() * sizeof(u32));
out_data += samples_to_grab;
offset = (offset + samples_to_grab) % max_samples;
remaining -= samples_to_grab;
}
if (read_count != 0) {
recv_info.read_offset = (recv_info.read_offset + read_count) % max_samples;
}
return sample_count;
}
void CommandGenerator::GenerateVolumeRampCommand(float last_volume, float current_volume,
s32 channel, s32 node_id) {
const auto last = static_cast<s32>(last_volume * 32768.0f);
@ -398,7 +574,9 @@ void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) {
auto& in_params = mix_info.GetInParams();
GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
in_params.sample_rate);
// TODO(ogniK): Effects
GenerateEffectCommand(mix_info);
GenerateMixCommands(mix_info);
}
@ -476,7 +654,8 @@ void CommandGenerator::GenerateFinalMixCommand() {
GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
in_params.sample_rate);
// TODO(ogniK): Effects
GenerateEffectCommand(mix_info);
for (s32 i = 0; i < in_params.buffer_count; i++) {
const s32 gain = static_cast<s32>(in_params.volume * 32768.0f);