summaryrefslogtreecommitdiff
path: root/src/audio_core/voice_context.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2020-09-11 10:57:27 -0400
committerGravatar GitHub2020-09-11 10:57:27 -0400
commit324029d4f9fd2381f474e608a2859360324161e5 (patch)
treed2dc348235f05f20686c526f7092590f596f65c2 /src/audio_core/voice_context.cpp
parentMerge pull request #4597 from Morph1984/mjolnir-p2 (diff)
parentPreliminary effects (diff)
downloadyuzu-324029d4f9fd2381f474e608a2859360324161e5.tar.gz
yuzu-324029d4f9fd2381f474e608a2859360324161e5.tar.xz
yuzu-324029d4f9fd2381f474e608a2859360324161e5.zip
Merge pull request #4310 from ogniK5377/apollo-1-prod
audio_core: Apollo Part 1, AudioRenderer refactor
Diffstat (limited to 'src/audio_core/voice_context.cpp')
-rw-r--r--src/audio_core/voice_context.cpp526
1 files changed, 526 insertions, 0 deletions
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp
new file mode 100644
index 000000000..1d8f69844
--- /dev/null
+++ b/src/audio_core/voice_context.cpp
@@ -0,0 +1,526 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "audio_core/behavior_info.h"
6#include "audio_core/voice_context.h"
7#include "core/memory.h"
8
9namespace AudioCore {
10
11ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id) : id(id) {}
12ServerVoiceChannelResource::~ServerVoiceChannelResource() = default;
13
14bool ServerVoiceChannelResource::InUse() const {
15 return in_use;
16}
17
18float ServerVoiceChannelResource::GetCurrentMixVolumeAt(std::size_t i) const {
19 ASSERT(i < AudioCommon::MAX_MIX_BUFFERS);
20 return mix_volume.at(i);
21}
22
23float ServerVoiceChannelResource::GetLastMixVolumeAt(std::size_t i) const {
24 ASSERT(i < AudioCommon::MAX_MIX_BUFFERS);
25 return last_mix_volume.at(i);
26}
27
28void ServerVoiceChannelResource::Update(VoiceChannelResource::InParams& in_params) {
29 in_use = in_params.in_use;
30 // Update our mix volumes only if it's in use
31 if (in_params.in_use) {
32 mix_volume = in_params.mix_volume;
33 }
34}
35
36void ServerVoiceChannelResource::UpdateLastMixVolumes() {
37 last_mix_volume = mix_volume;
38}
39
40const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
41ServerVoiceChannelResource::GetCurrentMixVolume() const {
42 return mix_volume;
43}
44
45const std::array<float, AudioCommon::MAX_MIX_BUFFERS>&
46ServerVoiceChannelResource::GetLastMixVolume() const {
47 return last_mix_volume;
48}
49
50ServerVoiceInfo::ServerVoiceInfo() {
51 Initialize();
52}
53ServerVoiceInfo::~ServerVoiceInfo() = default;
54
55void ServerVoiceInfo::Initialize() {
56 in_params.in_use = false;
57 in_params.node_id = 0;
58 in_params.id = 0;
59 in_params.current_playstate = ServerPlayState::Stop;
60 in_params.priority = 255;
61 in_params.sample_rate = 0;
62 in_params.sample_format = SampleFormat::Invalid;
63 in_params.channel_count = 0;
64 in_params.pitch = 0.0f;
65 in_params.volume = 0.0f;
66 in_params.last_volume = 0.0f;
67 in_params.biquad_filter.fill({});
68 in_params.wave_buffer_count = 0;
69 in_params.wave_bufffer_head = 0;
70 in_params.mix_id = AudioCommon::NO_MIX;
71 in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
72 in_params.additional_params_address = 0;
73 in_params.additional_params_size = 0;
74 in_params.is_new = false;
75 out_params.played_sample_count = 0;
76 out_params.wave_buffer_consumed = 0;
77 in_params.voice_drop_flag = false;
78 in_params.buffer_mapped = false;
79 in_params.wave_buffer_flush_request_count = 0;
80 in_params.was_biquad_filter_enabled.fill(false);
81
82 for (auto& wave_buffer : in_params.wave_buffer) {
83 wave_buffer.start_sample_offset = 0;
84 wave_buffer.end_sample_offset = 0;
85 wave_buffer.is_looping = false;
86 wave_buffer.end_of_stream = false;
87 wave_buffer.buffer_address = 0;
88 wave_buffer.buffer_size = 0;
89 wave_buffer.context_address = 0;
90 wave_buffer.context_size = 0;
91 wave_buffer.sent_to_dsp = true;
92 }
93
94 stored_samples.clear();
95}
96
97void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
98 BehaviorInfo& behavior_info) {
99 in_params.in_use = voice_in.is_in_use;
100 in_params.id = voice_in.id;
101 in_params.node_id = voice_in.node_id;
102 in_params.last_playstate = in_params.current_playstate;
103 switch (voice_in.play_state) {
104 case PlayState::Paused:
105 in_params.current_playstate = ServerPlayState::Paused;
106 break;
107 case PlayState::Stopped:
108 if (in_params.current_playstate != ServerPlayState::Stop) {
109 in_params.current_playstate = ServerPlayState::RequestStop;
110 }
111 break;
112 case PlayState::Started:
113 in_params.current_playstate = ServerPlayState::Play;
114 break;
115 default:
116 UNREACHABLE_MSG("Unknown playstate {}", voice_in.play_state);
117 break;
118 }
119
120 in_params.priority = voice_in.priority;
121 in_params.sorting_order = voice_in.sorting_order;
122 in_params.sample_rate = voice_in.sample_rate;
123 in_params.sample_format = voice_in.sample_format;
124 in_params.channel_count = voice_in.channel_count;
125 in_params.pitch = voice_in.pitch;
126 in_params.volume = voice_in.volume;
127 in_params.biquad_filter = voice_in.biquad_filter;
128 in_params.wave_buffer_count = voice_in.wave_buffer_count;
129 in_params.wave_bufffer_head = voice_in.wave_buffer_head;
130 if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
131 in_params.wave_buffer_flush_request_count += voice_in.wave_buffer_flush_request_count;
132 }
133 in_params.mix_id = voice_in.mix_id;
134 if (behavior_info.IsSplitterSupported()) {
135 in_params.splitter_info_id = voice_in.splitter_info_id;
136 } else {
137 in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
138 }
139
140 std::memcpy(in_params.voice_channel_resource_id.data(),
141 voice_in.voice_channel_resource_ids.data(),
142 sizeof(s32) * in_params.voice_channel_resource_id.size());
143
144 if (behavior_info.IsVoicePlayedSampleCountResetAtLoopPointSupported()) {
145 in_params.behavior_flags.is_played_samples_reset_at_loop_point =
146 voice_in.behavior_flags.is_played_samples_reset_at_loop_point;
147 } else {
148 in_params.behavior_flags.is_played_samples_reset_at_loop_point.Assign(0);
149 }
150 if (behavior_info.IsVoicePitchAndSrcSkippedSupported()) {
151 in_params.behavior_flags.is_pitch_and_src_skipped =
152 voice_in.behavior_flags.is_pitch_and_src_skipped;
153 } else {
154 in_params.behavior_flags.is_pitch_and_src_skipped.Assign(0);
155 }
156
157 if (voice_in.is_voice_drop_flag_clear_requested) {
158 in_params.voice_drop_flag = false;
159 }
160
161 if (in_params.additional_params_address != voice_in.additional_params_address ||
162 in_params.additional_params_size != voice_in.additional_params_size) {
163 in_params.additional_params_address = voice_in.additional_params_address;
164 in_params.additional_params_size = voice_in.additional_params_size;
165 // TODO(ogniK): Reattach buffer, do we actually need to? Maybe just signal to the DSP that
166 // our context is new
167 }
168}
169
170void ServerVoiceInfo::UpdateWaveBuffers(
171 const VoiceInfo::InParams& voice_in,
172 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states,
173 BehaviorInfo& behavior_info) {
174 if (voice_in.is_new) {
175 // Initialize our wave buffers
176 for (auto& wave_buffer : in_params.wave_buffer) {
177 wave_buffer.start_sample_offset = 0;
178 wave_buffer.end_sample_offset = 0;
179 wave_buffer.is_looping = false;
180 wave_buffer.end_of_stream = false;
181 wave_buffer.buffer_address = 0;
182 wave_buffer.buffer_size = 0;
183 wave_buffer.context_address = 0;
184 wave_buffer.context_size = 0;
185 wave_buffer.sent_to_dsp = true;
186 }
187
188 // Mark all our wave buffers as invalid
189 for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count);
190 channel++) {
191 for (auto& is_valid : voice_states[channel]->is_wave_buffer_valid) {
192 is_valid = false;
193 }
194 }
195 }
196
197 // Update our wave buffers
198 for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; i++) {
199 // Assume that we have at least 1 channel voice state
200 const auto have_valid_wave_buffer = voice_states[0]->is_wave_buffer_valid[i];
201
202 UpdateWaveBuffer(in_params.wave_buffer[i], voice_in.wave_buffer[i], in_params.sample_format,
203 have_valid_wave_buffer, behavior_info);
204 }
205}
206
207void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
208 const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
209 bool is_buffer_valid, BehaviorInfo& behavior_info) {
210 if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) {
211 out_wavebuffer.buffer_address = 0;
212 out_wavebuffer.buffer_size = 0;
213 }
214
215 if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) {
216 // Validate sample offset sizings
217 if (sample_format == SampleFormat::Pcm16) {
218 const auto buffer_size = in_wave_buffer.buffer_size;
219 if (in_wave_buffer.start_sample_offset < 0 || in_wave_buffer.end_sample_offset < 0 ||
220 (buffer_size < (sizeof(s16) * in_wave_buffer.start_sample_offset)) ||
221 (buffer_size < (sizeof(s16) * in_wave_buffer.end_sample_offset))) {
222 // TODO(ogniK): Write error info
223 return;
224 }
225 }
226 // TODO(ogniK): ADPCM Size error
227
228 out_wavebuffer.sent_to_dsp = false;
229 out_wavebuffer.start_sample_offset = in_wave_buffer.start_sample_offset;
230 out_wavebuffer.end_sample_offset = in_wave_buffer.end_sample_offset;
231 out_wavebuffer.is_looping = in_wave_buffer.is_looping;
232 out_wavebuffer.end_of_stream = in_wave_buffer.end_of_stream;
233
234 out_wavebuffer.buffer_address = in_wave_buffer.buffer_address;
235 out_wavebuffer.buffer_size = in_wave_buffer.buffer_size;
236 out_wavebuffer.context_address = in_wave_buffer.context_address;
237 out_wavebuffer.context_size = in_wave_buffer.context_size;
238 in_params.buffer_mapped =
239 in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0;
240 // TODO(ogniK): Pool mapper attachment
241 // TODO(ogniK): IsAdpcmLoopContextBugFixed
242 }
243}
244
245void ServerVoiceInfo::WriteOutStatus(
246 VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in,
247 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) {
248 if (voice_in.is_new) {
249 in_params.is_new = true;
250 voice_out.wave_buffer_consumed = 0;
251 voice_out.played_sample_count = 0;
252 voice_out.voice_dropped = false;
253 } else if (!in_params.is_new) {
254 voice_out.wave_buffer_consumed = voice_states[0]->wave_buffer_consumed;
255 voice_out.played_sample_count = voice_states[0]->played_sample_count;
256 voice_out.voice_dropped = in_params.voice_drop_flag;
257 } else {
258 voice_out.wave_buffer_consumed = 0;
259 voice_out.played_sample_count = 0;
260 voice_out.voice_dropped = false;
261 }
262}
263
264const ServerVoiceInfo::InParams& ServerVoiceInfo::GetInParams() const {
265 return in_params;
266}
267
268ServerVoiceInfo::InParams& ServerVoiceInfo::GetInParams() {
269 return in_params;
270}
271
272const ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() const {
273 return out_params;
274}
275
276ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() {
277 return out_params;
278}
279
280bool ServerVoiceInfo::ShouldSkip() const {
281 // TODO(ogniK): Handle unmapped wave buffers or parameters
282 return !in_params.in_use || (in_params.wave_buffer_count == 0) || in_params.voice_drop_flag;
283}
284
285bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) {
286 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> dsp_voice_states{};
287 if (in_params.is_new) {
288 ResetResources(voice_context);
289 in_params.last_volume = in_params.volume;
290 in_params.is_new = false;
291 }
292
293 const s32 channel_count = in_params.channel_count;
294 for (s32 i = 0; i < channel_count; i++) {
295 const auto channel_resource = in_params.voice_channel_resource_id[i];
296 dsp_voice_states[i] =
297 &voice_context.GetDspSharedState(static_cast<std::size_t>(channel_resource));
298 }
299 return UpdateParametersForCommandGeneration(dsp_voice_states);
300}
301
302void ServerVoiceInfo::ResetResources(VoiceContext& voice_context) {
303 const s32 channel_count = in_params.channel_count;
304 for (s32 i = 0; i < channel_count; i++) {
305 const auto channel_resource = in_params.voice_channel_resource_id[i];
306 auto& dsp_state =
307 voice_context.GetDspSharedState(static_cast<std::size_t>(channel_resource));
308 dsp_state = {};
309 voice_context.GetChannelResource(static_cast<std::size_t>(channel_resource))
310 .UpdateLastMixVolumes();
311 }
312}
313
314bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
315 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states) {
316 const s32 channel_count = in_params.channel_count;
317 if (in_params.wave_buffer_flush_request_count > 0) {
318 FlushWaveBuffers(in_params.wave_buffer_flush_request_count, dsp_voice_states,
319 channel_count);
320 in_params.wave_buffer_flush_request_count = 0;
321 }
322
323 switch (in_params.current_playstate) {
324 case ServerPlayState::Play: {
325 for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; i++) {
326 if (!in_params.wave_buffer[i].sent_to_dsp) {
327 for (s32 channel = 0; channel < channel_count; channel++) {
328 dsp_voice_states[channel]->is_wave_buffer_valid[i] = true;
329 }
330 in_params.wave_buffer[i].sent_to_dsp = true;
331 }
332 }
333 in_params.should_depop = false;
334 return HasValidWaveBuffer(dsp_voice_states[0]);
335 }
336 case ServerPlayState::Paused:
337 case ServerPlayState::Stop: {
338 in_params.should_depop = in_params.last_playstate == ServerPlayState::Play;
339 return in_params.should_depop;
340 }
341 case ServerPlayState::RequestStop: {
342 for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; i++) {
343 in_params.wave_buffer[i].sent_to_dsp = true;
344 for (s32 channel = 0; channel < channel_count; channel++) {
345 auto* dsp_state = dsp_voice_states[channel];
346
347 if (dsp_state->is_wave_buffer_valid[i]) {
348 dsp_state->wave_buffer_index =
349 (dsp_state->wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
350 dsp_state->wave_buffer_consumed++;
351 }
352
353 dsp_state->is_wave_buffer_valid[i] = false;
354 }
355 }
356
357 for (s32 channel = 0; channel < channel_count; channel++) {
358 auto* dsp_state = dsp_voice_states[channel];
359 dsp_state->offset = 0;
360 dsp_state->played_sample_count = 0;
361 dsp_state->fraction = 0;
362 dsp_state->sample_history.fill(0);
363 dsp_state->context = {};
364 }
365
366 in_params.current_playstate = ServerPlayState::Stop;
367 in_params.should_depop = in_params.last_playstate == ServerPlayState::Play;
368 return in_params.should_depop;
369 }
370 default:
371 UNREACHABLE_MSG("Invalid playstate {}", in_params.current_playstate);
372 }
373
374 return false;
375}
376
377void ServerVoiceInfo::FlushWaveBuffers(
378 u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
379 s32 channel_count) {
380 auto wave_head = in_params.wave_bufffer_head;
381
382 for (u8 i = 0; i < flush_count; i++) {
383 in_params.wave_buffer[wave_head].sent_to_dsp = true;
384 for (s32 channel = 0; channel < channel_count; channel++) {
385 auto* dsp_state = dsp_voice_states[channel];
386 dsp_state->wave_buffer_consumed++;
387 dsp_state->is_wave_buffer_valid[wave_head] = false;
388 dsp_state->wave_buffer_index =
389 (dsp_state->wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
390 }
391 wave_head = (wave_head + 1) % AudioCommon::MAX_WAVE_BUFFERS;
392 }
393}
394
395bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const {
396 const auto& valid_wb = state->is_wave_buffer_valid;
397 return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
398}
399
400VoiceContext::VoiceContext(std::size_t voice_count) : voice_count(voice_count) {
401 for (std::size_t i = 0; i < voice_count; i++) {
402 voice_channel_resources.emplace_back(static_cast<s32>(i));
403 sorted_voice_info.push_back(&voice_info.emplace_back());
404 voice_states.emplace_back();
405 dsp_voice_states.emplace_back();
406 }
407}
408
409VoiceContext::~VoiceContext() {
410 sorted_voice_info.clear();
411}
412
413std::size_t VoiceContext::GetVoiceCount() const {
414 return voice_count;
415}
416
417ServerVoiceChannelResource& VoiceContext::GetChannelResource(std::size_t i) {
418 ASSERT(i < voice_count);
419 return voice_channel_resources.at(i);
420}
421
422const ServerVoiceChannelResource& VoiceContext::GetChannelResource(std::size_t i) const {
423 ASSERT(i < voice_count);
424 return voice_channel_resources.at(i);
425}
426
427VoiceState& VoiceContext::GetState(std::size_t i) {
428 ASSERT(i < voice_count);
429 return voice_states.at(i);
430}
431
432const VoiceState& VoiceContext::GetState(std::size_t i) const {
433 ASSERT(i < voice_count);
434 return voice_states.at(i);
435}
436
437VoiceState& VoiceContext::GetDspSharedState(std::size_t i) {
438 ASSERT(i < voice_count);
439 return dsp_voice_states.at(i);
440}
441
442const VoiceState& VoiceContext::GetDspSharedState(std::size_t i) const {
443 ASSERT(i < voice_count);
444 return dsp_voice_states.at(i);
445}
446
447ServerVoiceInfo& VoiceContext::GetInfo(std::size_t i) {
448 ASSERT(i < voice_count);
449 return voice_info.at(i);
450}
451
452const ServerVoiceInfo& VoiceContext::GetInfo(std::size_t i) const {
453 ASSERT(i < voice_count);
454 return voice_info.at(i);
455}
456
457ServerVoiceInfo& VoiceContext::GetSortedInfo(std::size_t i) {
458 ASSERT(i < voice_count);
459 return *sorted_voice_info.at(i);
460}
461
462const ServerVoiceInfo& VoiceContext::GetSortedInfo(std::size_t i) const {
463 ASSERT(i < voice_count);
464 return *sorted_voice_info.at(i);
465}
466
467s32 VoiceContext::DecodePcm16(s32* output_buffer, ServerWaveBuffer* wave_buffer, s32 channel,
468 s32 channel_count, s32 buffer_offset, s32 sample_count,
469 Core::Memory::Memory& memory) {
470 if (wave_buffer->buffer_address == 0) {
471 return 0;
472 }
473 if (wave_buffer->buffer_size == 0) {
474 return 0;
475 }
476 if (wave_buffer->end_sample_offset < wave_buffer->start_sample_offset) {
477 return 0;
478 }
479
480 const auto samples_remaining =
481 (wave_buffer->end_sample_offset - wave_buffer->start_sample_offset) - buffer_offset;
482 const auto start_offset = (wave_buffer->start_sample_offset + buffer_offset) * channel_count;
483 const auto buffer_pos = wave_buffer->buffer_address + start_offset;
484
485 s16* buffer_data = reinterpret_cast<s16*>(memory.GetPointer(buffer_pos));
486
487 const auto samples_processed = std::min(sample_count, samples_remaining);
488
489 // Fast path
490 if (channel_count == 1) {
491 for (std::size_t i = 0; i < samples_processed; i++) {
492 output_buffer[i] = buffer_data[i];
493 }
494 } else {
495 for (std::size_t i = 0; i < samples_processed; i++) {
496 output_buffer[i] = buffer_data[i * channel_count + channel];
497 }
498 }
499
500 return samples_processed;
501}
502
503void VoiceContext::SortInfo() {
504 for (std::size_t i = 0; i < voice_count; i++) {
505 sorted_voice_info[i] = &voice_info[i];
506 }
507
508 std::sort(sorted_voice_info.begin(), sorted_voice_info.end(),
509 [](const ServerVoiceInfo* lhs, const ServerVoiceInfo* rhs) {
510 const auto& lhs_in = lhs->GetInParams();
511 const auto& rhs_in = rhs->GetInParams();
512 // Sort by priority
513 if (lhs_in.priority != rhs_in.priority) {
514 return lhs_in.priority > rhs_in.priority;
515 } else {
516 // If the priorities match, sort by sorting order
517 return lhs_in.sorting_order > rhs_in.sorting_order;
518 }
519 });
520}
521
522void VoiceContext::UpdateStateByDspShared() {
523 voice_states = dsp_voice_states;
524}
525
526} // namespace AudioCore