mirror of
https://github.com/yuzu-mirror/yuzu.git
synced 2024-11-09 16:00:01 +00:00
mix buffer depopping
This commit is contained in:
parent
1b8fe7073b
commit
0947f613b1
2 changed files with 101 additions and 30 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue