diff options
Diffstat (limited to 'src/audio_core/voice_context.cpp')
| -rw-r--r-- | src/audio_core/voice_context.cpp | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp index 867b8fc6b..d8c954b60 100644 --- a/src/audio_core/voice_context.cpp +++ b/src/audio_core/voice_context.cpp | |||
| @@ -66,7 +66,7 @@ void ServerVoiceInfo::Initialize() { | |||
| 66 | in_params.last_volume = 0.0f; | 66 | in_params.last_volume = 0.0f; |
| 67 | in_params.biquad_filter.fill({}); | 67 | in_params.biquad_filter.fill({}); |
| 68 | in_params.wave_buffer_count = 0; | 68 | in_params.wave_buffer_count = 0; |
| 69 | in_params.wave_bufffer_head = 0; | 69 | in_params.wave_buffer_head = 0; |
| 70 | in_params.mix_id = AudioCommon::NO_MIX; | 70 | in_params.mix_id = AudioCommon::NO_MIX; |
| 71 | in_params.splitter_info_id = AudioCommon::NO_SPLITTER; | 71 | in_params.splitter_info_id = AudioCommon::NO_SPLITTER; |
| 72 | in_params.additional_params_address = 0; | 72 | in_params.additional_params_address = 0; |
| @@ -75,7 +75,7 @@ void ServerVoiceInfo::Initialize() { | |||
| 75 | out_params.played_sample_count = 0; | 75 | out_params.played_sample_count = 0; |
| 76 | out_params.wave_buffer_consumed = 0; | 76 | out_params.wave_buffer_consumed = 0; |
| 77 | in_params.voice_drop_flag = false; | 77 | in_params.voice_drop_flag = false; |
| 78 | in_params.buffer_mapped = false; | 78 | in_params.buffer_mapped = true; |
| 79 | in_params.wave_buffer_flush_request_count = 0; | 79 | in_params.wave_buffer_flush_request_count = 0; |
| 80 | in_params.was_biquad_filter_enabled.fill(false); | 80 | in_params.was_biquad_filter_enabled.fill(false); |
| 81 | 81 | ||
| @@ -126,7 +126,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in, | |||
| 126 | in_params.volume = voice_in.volume; | 126 | in_params.volume = voice_in.volume; |
| 127 | in_params.biquad_filter = voice_in.biquad_filter; | 127 | in_params.biquad_filter = voice_in.biquad_filter; |
| 128 | in_params.wave_buffer_count = voice_in.wave_buffer_count; | 128 | in_params.wave_buffer_count = voice_in.wave_buffer_count; |
| 129 | in_params.wave_bufffer_head = voice_in.wave_buffer_head; | 129 | in_params.wave_buffer_head = voice_in.wave_buffer_head; |
| 130 | if (behavior_info.IsFlushVoiceWaveBuffersSupported()) { | 130 | if (behavior_info.IsFlushVoiceWaveBuffersSupported()) { |
| 131 | const auto in_request_count = in_params.wave_buffer_flush_request_count; | 131 | const auto in_request_count = in_params.wave_buffer_flush_request_count; |
| 132 | const auto voice_request_count = voice_in.wave_buffer_flush_request_count; | 132 | const auto voice_request_count = voice_in.wave_buffer_flush_request_count; |
| @@ -185,14 +185,16 @@ void ServerVoiceInfo::UpdateWaveBuffers( | |||
| 185 | wave_buffer.buffer_size = 0; | 185 | wave_buffer.buffer_size = 0; |
| 186 | wave_buffer.context_address = 0; | 186 | wave_buffer.context_address = 0; |
| 187 | wave_buffer.context_size = 0; | 187 | wave_buffer.context_size = 0; |
| 188 | wave_buffer.loop_start_sample = 0; | ||
| 189 | wave_buffer.loop_end_sample = 0; | ||
| 188 | wave_buffer.sent_to_dsp = true; | 190 | wave_buffer.sent_to_dsp = true; |
| 189 | } | 191 | } |
| 190 | 192 | ||
| 191 | // Mark all our wave buffers as invalid | 193 | // Mark all our wave buffers as invalid |
| 192 | for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count); | 194 | for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count); |
| 193 | channel++) { | 195 | channel++) { |
| 194 | for (auto& is_valid : voice_states[channel]->is_wave_buffer_valid) { | 196 | for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; ++i) { |
| 195 | is_valid = false; | 197 | voice_states[channel]->is_wave_buffer_valid[i] = false; |
| 196 | } | 198 | } |
| 197 | } | 199 | } |
| 198 | } | 200 | } |
| @@ -211,7 +213,7 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, | |||
| 211 | const WaveBuffer& in_wave_buffer, SampleFormat sample_format, | 213 | const WaveBuffer& in_wave_buffer, SampleFormat sample_format, |
| 212 | bool is_buffer_valid, | 214 | bool is_buffer_valid, |
| 213 | [[maybe_unused]] BehaviorInfo& behavior_info) { | 215 | [[maybe_unused]] BehaviorInfo& behavior_info) { |
| 214 | if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) { | 216 | if (!is_buffer_valid && out_wavebuffer.sent_to_dsp && out_wavebuffer.buffer_address != 0) { |
| 215 | out_wavebuffer.buffer_address = 0; | 217 | out_wavebuffer.buffer_address = 0; |
| 216 | out_wavebuffer.buffer_size = 0; | 218 | out_wavebuffer.buffer_size = 0; |
| 217 | } | 219 | } |
| @@ -219,11 +221,40 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, | |||
| 219 | if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) { | 221 | if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) { |
| 220 | // Validate sample offset sizings | 222 | // Validate sample offset sizings |
| 221 | if (sample_format == SampleFormat::Pcm16) { | 223 | if (sample_format == SampleFormat::Pcm16) { |
| 222 | const auto buffer_size = in_wave_buffer.buffer_size; | 224 | const s64 buffer_size = static_cast<s64>(in_wave_buffer.buffer_size); |
| 223 | if (in_wave_buffer.start_sample_offset < 0 || in_wave_buffer.end_sample_offset < 0 || | 225 | const s64 start = sizeof(s16) * in_wave_buffer.start_sample_offset; |
| 224 | (buffer_size < (sizeof(s16) * in_wave_buffer.start_sample_offset)) || | 226 | const s64 end = sizeof(s16) * in_wave_buffer.end_sample_offset; |
| 225 | (buffer_size < (sizeof(s16) * in_wave_buffer.end_sample_offset))) { | 227 | if (0 > start || start > buffer_size || 0 > end || end > buffer_size) { |
| 226 | // TODO(ogniK): Write error info | 228 | // TODO(ogniK): Write error info |
| 229 | LOG_ERROR(Audio, | ||
| 230 | "PCM16 wavebuffer has an invalid size. Buffer has size 0x{:08X}, but " | ||
| 231 | "offsets were " | ||
| 232 | "{:08X} - 0x{:08X}", | ||
| 233 | buffer_size, sizeof(s16) * in_wave_buffer.start_sample_offset, | ||
| 234 | sizeof(s16) * in_wave_buffer.end_sample_offset); | ||
| 235 | return; | ||
| 236 | } | ||
| 237 | } else if (sample_format == SampleFormat::Adpcm) { | ||
| 238 | const s64 buffer_size = static_cast<s64>(in_wave_buffer.buffer_size); | ||
| 239 | const s64 start_frames = in_wave_buffer.start_sample_offset / 14; | ||
| 240 | const s64 start_extra = in_wave_buffer.start_sample_offset % 14 == 0 | ||
| 241 | ? 0 | ||
| 242 | : (in_wave_buffer.start_sample_offset % 14) / 2 + 1 + | ||
| 243 | (in_wave_buffer.start_sample_offset % 2); | ||
| 244 | const s64 start = start_frames * 8 + start_extra; | ||
| 245 | const s64 end_frames = in_wave_buffer.end_sample_offset / 14; | ||
| 246 | const s64 end_extra = in_wave_buffer.end_sample_offset % 14 == 0 | ||
| 247 | ? 0 | ||
| 248 | : (in_wave_buffer.end_sample_offset % 14) / 2 + 1 + | ||
| 249 | (in_wave_buffer.end_sample_offset % 2); | ||
| 250 | const s64 end = end_frames * 8 + end_extra; | ||
| 251 | if (in_wave_buffer.start_sample_offset < 0 || start > buffer_size || | ||
| 252 | in_wave_buffer.end_sample_offset < 0 || end > buffer_size) { | ||
| 253 | LOG_ERROR(Audio, | ||
| 254 | "ADPMC wavebuffer has an invalid size. Buffer has size 0x{:08X}, but " | ||
| 255 | "offsets were " | ||
| 256 | "{:08X} - 0x{:08X}", | ||
| 257 | in_wave_buffer.buffer_size, start, end); | ||
| 227 | return; | 258 | return; |
| 228 | } | 259 | } |
| 229 | } | 260 | } |
| @@ -239,29 +270,34 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, | |||
| 239 | out_wavebuffer.buffer_size = in_wave_buffer.buffer_size; | 270 | out_wavebuffer.buffer_size = in_wave_buffer.buffer_size; |
| 240 | out_wavebuffer.context_address = in_wave_buffer.context_address; | 271 | out_wavebuffer.context_address = in_wave_buffer.context_address; |
| 241 | out_wavebuffer.context_size = in_wave_buffer.context_size; | 272 | out_wavebuffer.context_size = in_wave_buffer.context_size; |
| 273 | out_wavebuffer.loop_start_sample = in_wave_buffer.loop_start_sample; | ||
| 274 | out_wavebuffer.loop_end_sample = in_wave_buffer.loop_end_sample; | ||
| 242 | in_params.buffer_mapped = | 275 | in_params.buffer_mapped = |
| 243 | in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0; | 276 | in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0; |
| 244 | // TODO(ogniK): Pool mapper attachment | 277 | // TODO(ogniK): Pool mapper attachment |
| 245 | // TODO(ogniK): IsAdpcmLoopContextBugFixed | 278 | // TODO(ogniK): IsAdpcmLoopContextBugFixed |
| 279 | if (sample_format == SampleFormat::Adpcm && in_wave_buffer.context_address != 0 && | ||
| 280 | in_wave_buffer.context_size != 0 && behavior_info.IsAdpcmLoopContextBugFixed()) { | ||
| 281 | } else { | ||
| 282 | out_wavebuffer.context_address = 0; | ||
| 283 | out_wavebuffer.context_size = 0; | ||
| 284 | } | ||
| 246 | } | 285 | } |
| 247 | } | 286 | } |
| 248 | 287 | ||
| 249 | void ServerVoiceInfo::WriteOutStatus( | 288 | void ServerVoiceInfo::WriteOutStatus( |
| 250 | VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in, | 289 | VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in, |
| 251 | std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) { | 290 | std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) { |
| 252 | if (voice_in.is_new) { | 291 | if (voice_in.is_new || in_params.is_new) { |
| 253 | in_params.is_new = true; | 292 | in_params.is_new = true; |
| 254 | voice_out.wave_buffer_consumed = 0; | 293 | voice_out.wave_buffer_consumed = 0; |
| 255 | voice_out.played_sample_count = 0; | 294 | voice_out.played_sample_count = 0; |
| 256 | voice_out.voice_dropped = false; | 295 | voice_out.voice_dropped = false; |
| 257 | } else if (!in_params.is_new) { | ||
| 258 | voice_out.wave_buffer_consumed = voice_states[0]->wave_buffer_consumed; | ||
| 259 | voice_out.played_sample_count = voice_states[0]->played_sample_count; | ||
| 260 | voice_out.voice_dropped = in_params.voice_drop_flag; | ||
| 261 | } else { | 296 | } else { |
| 262 | voice_out.wave_buffer_consumed = 0; | 297 | const auto& state = voice_states[0]; |
| 263 | voice_out.played_sample_count = 0; | 298 | voice_out.wave_buffer_consumed = state->wave_buffer_consumed; |
| 264 | voice_out.voice_dropped = false; | 299 | voice_out.played_sample_count = state->played_sample_count; |
| 300 | voice_out.voice_dropped = state->voice_dropped; | ||
| 265 | } | 301 | } |
| 266 | } | 302 | } |
| 267 | 303 | ||
| @@ -283,7 +319,8 @@ ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() { | |||
| 283 | 319 | ||
| 284 | bool ServerVoiceInfo::ShouldSkip() const { | 320 | bool ServerVoiceInfo::ShouldSkip() const { |
| 285 | // TODO(ogniK): Handle unmapped wave buffers or parameters | 321 | // TODO(ogniK): Handle unmapped wave buffers or parameters |
| 286 | return !in_params.in_use || (in_params.wave_buffer_count == 0) || in_params.voice_drop_flag; | 322 | return !in_params.in_use || in_params.wave_buffer_count == 0 || !in_params.buffer_mapped || |
| 323 | in_params.voice_drop_flag; | ||
| 287 | } | 324 | } |
| 288 | 325 | ||
| 289 | bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) { | 326 | bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) { |
| @@ -381,7 +418,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration( | |||
| 381 | void ServerVoiceInfo::FlushWaveBuffers( | 418 | void ServerVoiceInfo::FlushWaveBuffers( |
| 382 | u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states, | 419 | u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states, |
| 383 | s32 channel_count) { | 420 | s32 channel_count) { |
| 384 | auto wave_head = in_params.wave_bufffer_head; | 421 | auto wave_head = in_params.wave_buffer_head; |
| 385 | 422 | ||
| 386 | for (u8 i = 0; i < flush_count; i++) { | 423 | for (u8 i = 0; i < flush_count; i++) { |
| 387 | in_params.wave_buffer[wave_head].sent_to_dsp = true; | 424 | in_params.wave_buffer[wave_head].sent_to_dsp = true; |
| @@ -401,6 +438,17 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const { | |||
| 401 | return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end(); | 438 | return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end(); |
| 402 | } | 439 | } |
| 403 | 440 | ||
| 441 | void ServerVoiceInfo::SetWaveBufferCompleted(VoiceState& dsp_state, | ||
| 442 | const ServerWaveBuffer& wave_buffer) { | ||
| 443 | dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false; | ||
| 444 | dsp_state.wave_buffer_consumed++; | ||
| 445 | dsp_state.wave_buffer_index = (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS; | ||
| 446 | dsp_state.loop_count = 0; | ||
| 447 | if (wave_buffer.end_of_stream) { | ||
| 448 | dsp_state.played_sample_count = 0; | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 404 | VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} { | 452 | VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} { |
| 405 | for (std::size_t i = 0; i < voice_count; i++) { | 453 | for (std::size_t i = 0; i < voice_count; i++) { |
| 406 | voice_channel_resources.emplace_back(static_cast<s32>(i)); | 454 | voice_channel_resources.emplace_back(static_cast<s32>(i)); |