summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Marcec <dmarcecguzman@gmail.com>2020-08-01 08:25:08 +0200
committerDavid Marcec <dmarcecguzman@gmail.com>2020-08-01 08:25:08 +0200
commit0947f613b1f5480258a1bf197ccc7a85a54ab7e1 (patch)
tree1f0e21cabdd8f4bd315f2d85887da4b67b974796 /src
parentadpcm streaming (diff)
downloadyuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.tar
yuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.tar.gz
yuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.tar.bz2
yuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.tar.lz
yuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.tar.xz
yuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.tar.zst
yuzu-0947f613b1f5480258a1bf197ccc7a85a54ab7e1.zip
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/command_generator.cpp123
-rw-r--r--src/audio_core/command_generator.h8
2 files changed, 101 insertions, 30 deletions
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index 0c3b278ea..8f89292be 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -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
CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
@@ -55,12 +73,15 @@ CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_p
splitter_context(splitter_context), memory(memory),
mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_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;
void CommandGenerator::ClearMixBuffers() {
std::fill(mix_buffer.begin(), mix_buffer.end(), 0);
std::fill(sample_buffer.begin(), sample_buffer.end(), 0);
+ // std::fill(depop_buffer.begin(), depop_buffer.end(), 0);
}
void CommandGenerator::GenerateVoiceCommands() {
@@ -195,32 +216,39 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
auto& in_params = voice_info.GetInParams();
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) {
- return;
- }
-
- 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);
+ 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();
+ GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset);
+ } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) {
+ s32 index{};
+ while (const auto* destination =
+ GetDestinationData(in_params.splitter_info_id, index++)) {
+ if (!destination->IsConfigured()) {
+ continue;
+ }
+ auto& mix_info = mix_context.GetInfo(destination->GetMixId());
+ const auto& mix_in = mix_info.GetInParams();
+ GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset);
+ }
+ }
+ } 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};
}
+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) {
if (splitter_id == AudioCommon::NO_SPLITTER) {
return nullptr;
@@ -338,7 +394,9 @@ void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) {
if (dumping_frame) {
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
GenerateMixCommands(mix_info);
}
@@ -412,10 +470,13 @@ void CommandGenerator::GenerateFinalMixCommand() {
if (dumping_frame) {
LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand");
}
- // TODO(ogniK): Depop
- // TODO(ogniK): Effects
auto& mix_info = mix_context.GetFinalMixInfo();
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++) {
const s32 gain = static_cast<s32>(in_params.volume * 32768.0f);
if (dumping_frame) {
@@ -541,6 +602,10 @@ std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const {
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) {
return GetMixBuffer(worker_params.mix_buffer_count + channel);
}
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index 3f49c1303..656ad8143 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -43,6 +43,8 @@ public:
const s32* GetMixBuffer(std::size_t index) const;
std::size_t GetMixChannelBufferOffset(s32 channel) const;
+ std::size_t GetTotalMixBufferCount() const;
+
private:
void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel);
void GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
@@ -61,7 +63,10 @@ private:
void GenerateBiquadFilterCommand(s32 mix_buffer, const BiquadFilterParameter& params,
std::array<s64, 2>& state, std::size_t input_offset,
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);
// DSP Code
@@ -79,6 +84,7 @@ private:
Core::Memory::Memory& memory;
std::vector<s32> mix_buffer{};
std::vector<s32> sample_buffer{};
+ std::vector<s32> depop_buffer{};
bool dumping_frame{false};
};
} // namespace AudioCore