summaryrefslogtreecommitdiff
path: root/src/audio_core/voice_context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_core/voice_context.cpp')
-rw-r--r--src/audio_core/voice_context.cpp88
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
249void ServerVoiceInfo::WriteOutStatus( 288void 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
284bool ServerVoiceInfo::ShouldSkip() const { 320bool 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
289bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) { 326bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) {
@@ -381,7 +418,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
381void ServerVoiceInfo::FlushWaveBuffers( 418void 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
441void 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
404VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} { 452VoiceContext::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));