mix buffer depopping

This commit is contained in:
David Marcec 2020-08-01 16:25:08 +10:00
parent 1b8fe7073b
commit 0947f613b1
2 changed files with 101 additions and 30 deletions

View file

@ -46,6 +46,24 @@ void ApplyGainWithoutDelta(s32* output, const s32* input, s32 gain, s32 sample_c
} }
} }
s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
const bool positive = first_sample > 0;
auto final_sample = std::abs(first_sample);
for (s32 i = 0; i < sample_count; i++) {
final_sample = static_cast<s32>((static_cast<s64>(final_sample) * delta) >> 15);
if (positive) {
output[i] += final_sample;
} else {
output[i] -= final_sample;
}
}
if (positive) {
return final_sample;
} else {
return -final_sample;
}
}
} // namespace } // namespace
CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
@ -55,12 +73,15 @@ CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_p
splitter_context(splitter_context), memory(memory), splitter_context(splitter_context), memory(memory),
mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
worker_params.sample_count), worker_params.sample_count),
sample_buffer(MIX_BUFFER_SIZE) {} sample_buffer(MIX_BUFFER_SIZE),
depop_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
worker_params.sample_count) {}
CommandGenerator::~CommandGenerator() = default; CommandGenerator::~CommandGenerator() = default;
void CommandGenerator::ClearMixBuffers() { void CommandGenerator::ClearMixBuffers() {
std::fill(mix_buffer.begin(), mix_buffer.end(), 0); std::fill(mix_buffer.begin(), mix_buffer.end(), 0);
std::fill(sample_buffer.begin(), sample_buffer.end(), 0); std::fill(sample_buffer.begin(), sample_buffer.end(), 0);
// std::fill(depop_buffer.begin(), depop_buffer.end(), 0);
} }
void CommandGenerator::GenerateVoiceCommands() { void CommandGenerator::GenerateVoiceCommands() {
@ -195,32 +216,39 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
auto& in_params = voice_info.GetInParams(); auto& in_params = voice_info.GetInParams();
const auto depop = in_params.should_depop; const auto depop = in_params.should_depop;
if (in_params.mix_id != AudioCommon::NO_MIX) {
[[maybe_unused]] auto& mix_info = mix_context.GetInfo(in_params.mix_id);
// mix_info.
// TODO(ogniK): Depop to destination mix
} else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) {
// TODO(ogniK): Depop to splitter
}
if (depop) { if (depop) {
return; if (in_params.mix_id != AudioCommon::NO_MIX) {
} auto& mix_info = mix_context.GetInfo(in_params.mix_id);
const auto& mix_in = mix_info.GetInParams();
switch (in_params.sample_format) { GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset);
case SampleFormat::Pcm16: } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) {
DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel, s32 index{};
worker_params.sample_rate, worker_params.sample_count, while (const auto* destination =
in_params.node_id); GetDestinationData(in_params.splitter_info_id, index++)) {
break; if (!destination->IsConfigured()) {
case SampleFormat::Adpcm: continue;
ASSERT(channel == 0 && in_params.channel_count == 1); }
DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(0), dsp_state, 0, auto& mix_info = mix_context.GetInfo(destination->GetMixId());
worker_params.sample_rate, worker_params.sample_count, const auto& mix_in = mix_info.GetInParams();
in_params.node_id); GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset);
break; }
default: }
UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); } else {
switch (in_params.sample_format) {
case SampleFormat::Pcm16:
DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel,
worker_params.sample_rate, worker_params.sample_count,
in_params.node_id);
break;
case SampleFormat::Adpcm:
ASSERT(channel == 0 && in_params.channel_count == 1);
DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(0), dsp_state, 0,
worker_params.sample_rate, worker_params.sample_count,
in_params.node_id);
break;
default:
UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
}
} }
} }
@ -281,6 +309,34 @@ void AudioCore::CommandGenerator::GenerateBiquadFilterCommand(
state = {s0, s1}; state = {s0, s1};
} }
void CommandGenerator::GenerateDepopPrepareCommand(VoiceState& dsp_state,
std::size_t mix_buffer_count,
std::size_t mix_buffer_offset) {
for (std::size_t i = 0; i < mix_buffer_count; i++) {
auto& sample = dsp_state.previous_samples[i];
if (sample != 0) {
depop_buffer[mix_buffer_offset + i] += sample;
sample = 0;
}
}
}
void CommandGenerator::GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count,
std::size_t mix_buffer_offset,
s32 sample_rate) {
const std::size_t end_offset =
std::min(mix_buffer_offset + mix_buffer_count, GetTotalMixBufferCount());
const s32 delta = sample_rate == 48000 ? 0x7B29 : 0x78CB;
for (std::size_t i = mix_buffer_offset; i < end_offset; i++) {
if (depop_buffer[i] == 0) {
continue;
}
depop_buffer[i] =
ApplyMixDepop(GetMixBuffer(i), depop_buffer[i], delta, worker_params.sample_count);
}
}
ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) { ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) {
if (splitter_id == AudioCommon::NO_SPLITTER) { if (splitter_id == AudioCommon::NO_SPLITTER) {
return nullptr; return nullptr;
@ -338,7 +394,9 @@ void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) {
if (dumping_frame) { if (dumping_frame) {
LOG_DEBUG(Audio, "(DSP_TRACE) GenerateSubMixCommand"); LOG_DEBUG(Audio, "(DSP_TRACE) GenerateSubMixCommand");
} }
// TODO(ogniK): Depop auto& in_params = mix_info.GetInParams();
GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
in_params.sample_rate);
// TODO(ogniK): Effects // TODO(ogniK): Effects
GenerateMixCommands(mix_info); GenerateMixCommands(mix_info);
} }
@ -412,10 +470,13 @@ void CommandGenerator::GenerateFinalMixCommand() {
if (dumping_frame) { if (dumping_frame) {
LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand"); LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand");
} }
// TODO(ogniK): Depop
// TODO(ogniK): Effects
auto& mix_info = mix_context.GetFinalMixInfo(); auto& mix_info = mix_context.GetFinalMixInfo();
const auto in_params = mix_info.GetInParams(); const auto in_params = mix_info.GetInParams();
GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
in_params.sample_rate);
// TODO(ogniK): Effects
for (s32 i = 0; i < in_params.buffer_count; i++) { for (s32 i = 0; i < in_params.buffer_count; i++) {
const s32 gain = static_cast<s32>(in_params.volume * 32768.0f); const s32 gain = static_cast<s32>(in_params.volume * 32768.0f);
if (dumping_frame) { if (dumping_frame) {
@ -541,6 +602,10 @@ std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const {
return worker_params.mix_buffer_count + channel; return worker_params.mix_buffer_count + channel;
} }
std::size_t CommandGenerator::GetTotalMixBufferCount() const {
return worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT;
}
s32* CommandGenerator::GetChannelMixBuffer(s32 channel) { s32* CommandGenerator::GetChannelMixBuffer(s32 channel) {
return GetMixBuffer(worker_params.mix_buffer_count + channel); return GetMixBuffer(worker_params.mix_buffer_count + channel);
} }

View file

@ -43,6 +43,8 @@ public:
const s32* GetMixBuffer(std::size_t index) const; const s32* GetMixBuffer(std::size_t index) const;
std::size_t GetMixChannelBufferOffset(s32 channel) const; std::size_t GetMixChannelBufferOffset(s32 channel) const;
std::size_t GetTotalMixBufferCount() const;
private: private:
void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel);
void GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state, void GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
@ -61,7 +63,10 @@ private:
void GenerateBiquadFilterCommand(s32 mix_buffer, const BiquadFilterParameter& params, void GenerateBiquadFilterCommand(s32 mix_buffer, const BiquadFilterParameter& params,
std::array<s64, 2>& state, std::size_t input_offset, std::array<s64, 2>& state, std::size_t input_offset,
std::size_t output_offset, s32 sample_count, s32 node_id); std::size_t output_offset, s32 sample_count, s32 node_id);
void GenerateDepopPrepareCommand(VoiceState& dsp_state); void GenerateDepopPrepareCommand(VoiceState& dsp_state, std::size_t mix_buffer_count,
std::size_t mix_buffer_offset);
void GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count,
std::size_t mix_buffer_offset, s32 sample_rate);
ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
// DSP Code // DSP Code
@ -79,6 +84,7 @@ private:
Core::Memory::Memory& memory; Core::Memory::Memory& memory;
std::vector<s32> mix_buffer{}; std::vector<s32> mix_buffer{};
std::vector<s32> sample_buffer{}; std::vector<s32> sample_buffer{};
std::vector<s32> depop_buffer{};
bool dumping_frame{false}; bool dumping_frame{false};
}; };
} // namespace AudioCore } // namespace AudioCore