From 9e3b1eea809ec99c4ee04a7cae96c3063eaa3673 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Sun, 27 Jun 2021 07:28:57 +0200 Subject: [PATCH] early-access version 1831 --- README.md | 2 +- externals/libusb/CMakeLists.txt | 2 +- src/audio_core/audio_renderer.cpp | 150 +++++++++++----------- src/audio_core/command_generator.cpp | 73 ++++++----- src/audio_core/command_generator.h | 8 +- src/audio_core/info_updater.cpp | 3 - src/audio_core/voice_context.cpp | 45 ++++--- src/audio_core/voice_context.h | 13 +- src/input_common/gcadapter/gc_adapter.cpp | 14 +- src/input_common/gcadapter/gc_adapter.h | 1 - 10 files changed, 165 insertions(+), 146 deletions(-) diff --git a/README.md b/README.md index 9466e90fe..d1b391339 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 1830. +This is the source code for early-access 1831. ## Legal Notice diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 7180fd42a..8b9e6433c 100755 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt @@ -1,4 +1,4 @@ -if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")) +if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR APPLE) set(LIBUSB_FOUND ON CACHE BOOL "libusb is present" FORCE) set(LIBUSB_VERSION "1.0.24" CACHE STRING "libusb version string" FORCE) diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 0757cd804..1952c88ef 100755 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -69,7 +69,7 @@ namespace { } // namespace namespace AudioCore { -constexpr s32 NUM_BUFFERS = 2; +constexpr s32 NUM_BUFFERS = 4; AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_, AudioCommon::AudioRendererParameter params, @@ -129,87 +129,85 @@ Stream::State AudioRenderer::GetStreamState() const { ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector& input_params, std::vector& output_params) { - { - std::scoped_lock lock{mutex}; - InfoUpdater info_updater{input_params, output_params, behavior_info}; + std::scoped_lock lock{mutex}; + InfoUpdater info_updater{input_params, output_params, behavior_info}; - if (!info_updater.UpdateBehaviorInfo(behavior_info)) { - LOG_ERROR(Audio, "Failed to update behavior info input parameters"); + if (!info_updater.UpdateBehaviorInfo(behavior_info)) { + LOG_ERROR(Audio, "Failed to update behavior info input parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + if (!info_updater.UpdateMemoryPools(memory_pool_info)) { + LOG_ERROR(Audio, "Failed to update memory pool parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + if (!info_updater.UpdateVoiceChannelResources(voice_context)) { + LOG_ERROR(Audio, "Failed to update voice channel resource parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + if (!info_updater.UpdateVoices(voice_context, memory_pool_info, 0)) { + LOG_ERROR(Audio, "Failed to update voice parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + // TODO(ogniK): Deal with stopped audio renderer but updates still taking place + if (!info_updater.UpdateEffects(effect_context, true)) { + LOG_ERROR(Audio, "Failed to update effect parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + if (behavior_info.IsSplitterSupported()) { + if (!info_updater.UpdateSplitterInfo(splitter_context)) { + LOG_ERROR(Audio, "Failed to update splitter parameters"); return AudioCommon::Audren::ERR_INVALID_PARAMETERS; } + } - if (!info_updater.UpdateMemoryPools(memory_pool_info)) { - LOG_ERROR(Audio, "Failed to update memory pool parameters"); + const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, + splitter_context, effect_context); + + if (mix_result.IsError()) { + LOG_ERROR(Audio, "Failed to update mix parameters"); + return mix_result; + } + + // TODO(ogniK): Sinks + if (!info_updater.UpdateSinks(sink_context)) { + LOG_ERROR(Audio, "Failed to update sink parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + // TODO(ogniK): Performance buffer + if (!info_updater.UpdatePerformanceBuffer()) { + LOG_ERROR(Audio, "Failed to update performance buffer parameters"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + if (!info_updater.UpdateErrorInfo(behavior_info)) { + LOG_ERROR(Audio, "Failed to update error info"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } + + if (behavior_info.IsElapsedFrameCountSupported()) { + if (!info_updater.UpdateRendererInfo(elapsed_frame_count)) { + LOG_ERROR(Audio, "Failed to update renderer info"); return AudioCommon::Audren::ERR_INVALID_PARAMETERS; } + } + // TODO(ogniK): Statistics - if (!info_updater.UpdateVoiceChannelResources(voice_context)) { - LOG_ERROR(Audio, "Failed to update voice channel resource parameters"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } + if (!info_updater.WriteOutputHeader()) { + LOG_ERROR(Audio, "Failed to write output header"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; + } - if (!info_updater.UpdateVoices(voice_context, memory_pool_info, 0)) { - LOG_ERROR(Audio, "Failed to update voice parameters"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } + // TODO(ogniK): Check when all sections are implemented - // TODO(ogniK): Deal with stopped audio renderer but updates still taking place - if (!info_updater.UpdateEffects(effect_context, true)) { - LOG_ERROR(Audio, "Failed to update effect parameters"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - - if (behavior_info.IsSplitterSupported()) { - if (!info_updater.UpdateSplitterInfo(splitter_context)) { - LOG_ERROR(Audio, "Failed to update splitter parameters"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - } - - const auto mix_result = info_updater.UpdateMixes( - mix_context, worker_params.mix_buffer_count, splitter_context, effect_context); - - if (mix_result.IsError()) { - LOG_ERROR(Audio, "Failed to update mix parameters"); - return mix_result; - } - - // TODO(ogniK): Sinks - if (!info_updater.UpdateSinks(sink_context)) { - LOG_ERROR(Audio, "Failed to update sink parameters"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - - // TODO(ogniK): Performance buffer - if (!info_updater.UpdatePerformanceBuffer()) { - LOG_ERROR(Audio, "Failed to update performance buffer parameters"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - - if (!info_updater.UpdateErrorInfo(behavior_info)) { - LOG_ERROR(Audio, "Failed to update error info"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - - if (behavior_info.IsElapsedFrameCountSupported()) { - if (!info_updater.UpdateRendererInfo(elapsed_frame_count)) { - LOG_ERROR(Audio, "Failed to update renderer info"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - } - // TODO(ogniK): Statistics - - if (!info_updater.WriteOutputHeader()) { - LOG_ERROR(Audio, "Failed to write output header"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } - - // TODO(ogniK): Check when all sections are implemented - - if (!info_updater.CheckConsumedSize()) { - LOG_ERROR(Audio, "Audio buffers were not consumed!"); - return AudioCommon::Audren::ERR_INVALID_PARAMETERS; - } + if (!info_updater.CheckConsumedSize()) { + LOG_ERROR(Audio, "Audio buffers were not consumed!"); + return AudioCommon::Audren::ERR_INVALID_PARAMETERS; } return ResultSuccess; } @@ -234,10 +232,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { command_generator.PostCommand(); // Base sample size std::size_t BUFFER_SIZE{worker_params.sample_count}; - // Samples - std::vector buffer(BUFFER_SIZE * stream->GetNumChannels()); - // Make sure to clear our samples - std::memset(buffer.data(), 0, buffer.size() * sizeof(s16)); + // Samples, making sure to clear + std::vector buffer(BUFFER_SIZE * stream->GetNumChannels(), 0); if (sink_context.InUse()) { const auto stream_channel_count = stream->GetNumChannels(); diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp index 437cc5ccd..0a26f587a 100755 --- a/src/audio_core/command_generator.cpp +++ b/src/audio_core/command_generator.cpp @@ -795,7 +795,7 @@ void CommandGenerator::UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbSta state.lowpass_1 = 0.0f; } else { const auto a = 1.0f - hf_gain; - const auto b = 2.0f * (1.0f - hf_gain * CosD(256.0f * info.hf_reference / + const auto b = 2.0f * (2.0f - hf_gain * CosD(256.0f * info.hf_reference / static_cast(info.sample_rate))); const auto c = std::sqrt(b * b - 4.0f * a * a); @@ -843,7 +843,7 @@ void CommandGenerator::UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbSta } const auto max_early_delay = state.early_delay_line.GetMaxDelay(); - const auto reflection_time = 1000.0f * (0.0098f * info.reverb_delay + 0.02f); + const auto reflection_time = 1000.0f * (0.9998f * info.reverb_delay + 0.02f); for (std::size_t tap = 0; tap < AudioCommon::I3DL2REVERB_TAPS; tap++) { const auto length = AudioCommon::CalculateDelaySamples( sample_rate, 1000.0f * info.reflection_delay + reflection_time * EARLY_TAP_TIMES[tap]); @@ -1004,7 +1004,8 @@ void CommandGenerator::GenerateFinalMixCommand() { } s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, - s32 sample_count, s32 channel, std::size_t mix_offset) { + s32 sample_start_offset, s32 sample_end_offset, s32 sample_count, + s32 channel, std::size_t mix_offset) { const auto& in_params = voice_info.GetInParams(); const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; if (wave_buffer.buffer_address == 0) { @@ -1013,14 +1014,12 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s if (wave_buffer.buffer_size == 0) { return 0; } - if (wave_buffer.end_sample_offset < wave_buffer.start_sample_offset) { + if (sample_end_offset < sample_start_offset) { return 0; } - const auto samples_remaining = - (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) - dsp_state.offset; + const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset; const auto start_offset = - ((wave_buffer.start_sample_offset + dsp_state.offset) * in_params.channel_count) * - sizeof(s16); + ((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(s16); const auto buffer_pos = wave_buffer.buffer_address + start_offset; const auto samples_processed = std::min(sample_count, samples_remaining); @@ -1044,8 +1043,8 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s } s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, - s32 sample_count, [[maybe_unused]] s32 channel, - std::size_t mix_offset) { + s32 sample_start_offset, s32 sample_end_offset, s32 sample_count, + [[maybe_unused]] s32 channel, std::size_t mix_offset) { const auto& in_params = voice_info.GetInParams(); const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; if (wave_buffer.buffer_address == 0) { @@ -1054,7 +1053,7 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s if (wave_buffer.buffer_size == 0) { return 0; } - if (wave_buffer.end_sample_offset < wave_buffer.start_sample_offset) { + if (sample_end_offset < sample_start_offset) { return 0; } @@ -1079,10 +1078,9 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s s32 coef1 = coeffs[idx * 2]; s32 coef2 = coeffs[idx * 2 + 1]; - const auto samples_remaining = - (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) - dsp_state.offset; + const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset; const auto samples_processed = std::min(sample_count, samples_remaining); - const auto sample_pos = wave_buffer.start_sample_offset + dsp_state.offset; + const auto sample_pos = dsp_state.offset + sample_start_offset; const auto samples_remaining_in_frame = sample_pos % SAMPLES_PER_FRAME; auto position_in_frame = ((sample_pos / SAMPLES_PER_FRAME) * NIBBLES_PER_SAMPLE) + @@ -1210,9 +1208,8 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o } std::size_t temp_mix_offset{}; - bool is_buffer_completed{false}; auto samples_remaining = sample_count; - while (samples_remaining > 0 && !is_buffer_completed) { + while (samples_remaining > 0) { const auto samples_to_output = std::min(samples_remaining, min_required_samples); const auto samples_to_read = (samples_to_output * resample_rate + dsp_state.fraction) >> 15; @@ -1229,7 +1226,6 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; // No more data can be read if (!dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index]) { - is_buffer_completed = true; break; } @@ -1238,15 +1234,29 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o // TODO(ogniK): ADPCM loop context } + s32 samples_offset_start; + s32 samples_offset_end; + if (dsp_state.loop_count > 0 || + (wave_buffer.loop_start_sample != 0 && wave_buffer.loop_end_sample != 0 && + wave_buffer.loop_start_sample <= wave_buffer.loop_end_sample)) { + samples_offset_start = wave_buffer.loop_start_sample; + samples_offset_end = wave_buffer.loop_end_sample; + } else { + samples_offset_start = wave_buffer.start_sample_offset; + samples_offset_end = wave_buffer.end_sample_offset; + } + s32 samples_decoded{0}; switch (in_params.sample_format) { case SampleFormat::Pcm16: - samples_decoded = DecodePcm16(voice_info, dsp_state, samples_to_read - samples_read, - channel, temp_mix_offset); + samples_decoded = + DecodePcm16(voice_info, dsp_state, samples_offset_start, samples_offset_end, + samples_to_read - samples_read, channel, temp_mix_offset); break; case SampleFormat::Adpcm: - samples_decoded = DecodeAdpcm(voice_info, dsp_state, samples_to_read - samples_read, - channel, temp_mix_offset); + samples_decoded = + DecodeAdpcm(voice_info, dsp_state, samples_offset_start, samples_offset_end, + samples_to_read - samples_read, channel, temp_mix_offset); break; default: UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); @@ -1257,15 +1267,19 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o dsp_state.offset += samples_decoded; dsp_state.played_sample_count += samples_decoded; - if (dsp_state.offset >= - (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) || + if (dsp_state.offset >= (samples_offset_end - samples_offset_start) || samples_decoded == 0) { // Reset our sample offset dsp_state.offset = 0; if (wave_buffer.is_looping) { - if (samples_decoded == 0) { + dsp_state.loop_count++; + if (wave_buffer.loop_count > 0 && + (dsp_state.loop_count > wave_buffer.loop_count || samples_decoded == 0)) { // End of our buffer - is_buffer_completed = true; + voice_info.SetWaveBufferCompleted(dsp_state, wave_buffer); + } + + if (samples_decoded == 0) { break; } @@ -1273,15 +1287,8 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o dsp_state.played_sample_count = 0; } } else { - // Update our wave buffer states - dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false; - dsp_state.wave_buffer_consumed++; - dsp_state.wave_buffer_index = - (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS; - if (wave_buffer.end_of_stream) { - dsp_state.played_sample_count = 0; - } + voice_info.SetWaveBufferCompleted(dsp_state, wave_buffer); } } } diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h index 2ebb755b0..673e4fbef 100755 --- a/src/audio_core/command_generator.h +++ b/src/audio_core/command_generator.h @@ -86,10 +86,10 @@ private: std::vector& work_buffer); void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear); // DSP Code - s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count, - s32 channel, std::size_t mix_offset); - s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count, - s32 channel, std::size_t mix_offset); + s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset, + s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset); + s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset, + s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset); void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, VoiceState& dsp_state, s32 channel, s32 target_sample_rate, s32 sample_count, s32 node_id); diff --git a/src/audio_core/info_updater.cpp b/src/audio_core/info_updater.cpp index 4a5b1b4ab..9b4ca1851 100755 --- a/src/audio_core/info_updater.cpp +++ b/src/audio_core/info_updater.cpp @@ -189,9 +189,6 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context, if (voice_in_params.is_new) { // Default our values for our voice voice_info.Initialize(); - if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) { - continue; - } // Zero out our voice states for (std::size_t channel = 0; channel < channel_count; channel++) { diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp index 867b8fc6b..f04ead485 100755 --- a/src/audio_core/voice_context.cpp +++ b/src/audio_core/voice_context.cpp @@ -66,7 +66,7 @@ void ServerVoiceInfo::Initialize() { in_params.last_volume = 0.0f; in_params.biquad_filter.fill({}); in_params.wave_buffer_count = 0; - in_params.wave_bufffer_head = 0; + in_params.wave_buffer_head = 0; in_params.mix_id = AudioCommon::NO_MIX; in_params.splitter_info_id = AudioCommon::NO_SPLITTER; in_params.additional_params_address = 0; @@ -75,7 +75,7 @@ void ServerVoiceInfo::Initialize() { out_params.played_sample_count = 0; out_params.wave_buffer_consumed = 0; in_params.voice_drop_flag = false; - in_params.buffer_mapped = false; + in_params.buffer_mapped = true; in_params.wave_buffer_flush_request_count = 0; in_params.was_biquad_filter_enabled.fill(false); @@ -126,7 +126,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in, in_params.volume = voice_in.volume; in_params.biquad_filter = voice_in.biquad_filter; in_params.wave_buffer_count = voice_in.wave_buffer_count; - in_params.wave_bufffer_head = voice_in.wave_buffer_head; + in_params.wave_buffer_head = voice_in.wave_buffer_head; if (behavior_info.IsFlushVoiceWaveBuffersSupported()) { const auto in_request_count = in_params.wave_buffer_flush_request_count; const auto voice_request_count = voice_in.wave_buffer_flush_request_count; @@ -185,14 +185,16 @@ void ServerVoiceInfo::UpdateWaveBuffers( wave_buffer.buffer_size = 0; wave_buffer.context_address = 0; wave_buffer.context_size = 0; + wave_buffer.loop_start_sample = 0; + wave_buffer.loop_end_sample = 0; wave_buffer.sent_to_dsp = true; } // Mark all our wave buffers as invalid for (std::size_t channel = 0; channel < static_cast(in_params.channel_count); channel++) { - for (auto& is_valid : voice_states[channel]->is_wave_buffer_valid) { - is_valid = false; + for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; ++i) { + voice_states[channel]->is_wave_buffer_valid[i] = false; } } } @@ -211,7 +213,7 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, const WaveBuffer& in_wave_buffer, SampleFormat sample_format, bool is_buffer_valid, [[maybe_unused]] BehaviorInfo& behavior_info) { - if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) { + if (!is_buffer_valid && out_wavebuffer.sent_to_dsp && out_wavebuffer.buffer_address != 0) { out_wavebuffer.buffer_address = 0; out_wavebuffer.buffer_size = 0; } @@ -239,6 +241,8 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, out_wavebuffer.buffer_size = in_wave_buffer.buffer_size; out_wavebuffer.context_address = in_wave_buffer.context_address; out_wavebuffer.context_size = in_wave_buffer.context_size; + out_wavebuffer.loop_start_sample = in_wave_buffer.loop_start_sample; + out_wavebuffer.loop_end_sample = in_wave_buffer.loop_end_sample; in_params.buffer_mapped = in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0; // TODO(ogniK): Pool mapper attachment @@ -249,19 +253,16 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, void ServerVoiceInfo::WriteOutStatus( VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in, std::array& voice_states) { - if (voice_in.is_new) { + if (voice_in.is_new || in_params.is_new) { in_params.is_new = true; voice_out.wave_buffer_consumed = 0; voice_out.played_sample_count = 0; voice_out.voice_dropped = false; - } else if (!in_params.is_new) { - voice_out.wave_buffer_consumed = voice_states[0]->wave_buffer_consumed; - voice_out.played_sample_count = voice_states[0]->played_sample_count; - voice_out.voice_dropped = in_params.voice_drop_flag; } else { - voice_out.wave_buffer_consumed = 0; - voice_out.played_sample_count = 0; - voice_out.voice_dropped = false; + const auto& state = voice_states[0]; + voice_out.wave_buffer_consumed = state->wave_buffer_consumed; + voice_out.played_sample_count = state->played_sample_count; + voice_out.voice_dropped = state->voice_dropped; } } @@ -283,7 +284,8 @@ ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() { bool ServerVoiceInfo::ShouldSkip() const { // TODO(ogniK): Handle unmapped wave buffers or parameters - return !in_params.in_use || (in_params.wave_buffer_count == 0) || in_params.voice_drop_flag; + return !in_params.in_use || in_params.wave_buffer_count == 0 || !in_params.buffer_mapped || + in_params.voice_drop_flag; } bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) { @@ -381,7 +383,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration( void ServerVoiceInfo::FlushWaveBuffers( u8 flush_count, std::array& dsp_voice_states, s32 channel_count) { - auto wave_head = in_params.wave_bufffer_head; + auto wave_head = in_params.wave_buffer_head; for (u8 i = 0; i < flush_count; i++) { in_params.wave_buffer[wave_head].sent_to_dsp = true; @@ -401,6 +403,17 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const { return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end(); } +void ServerVoiceInfo::SetWaveBufferCompleted(VoiceState& dsp_state, + const ServerWaveBuffer& wave_buffer) { + dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false; + dsp_state.wave_buffer_consumed++; + dsp_state.wave_buffer_index = (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS; + dsp_state.loop_count = 0; + if (wave_buffer.end_of_stream) { + dsp_state.played_sample_count = 0; + } +} + VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} { for (std::size_t i = 0; i < voice_count; i++) { voice_channel_resources.emplace_back(static_cast(i)); diff --git a/src/audio_core/voice_context.h b/src/audio_core/voice_context.h index 70359cadb..e1050897b 100755 --- a/src/audio_core/voice_context.h +++ b/src/audio_core/voice_context.h @@ -60,10 +60,12 @@ struct WaveBuffer { u8 is_looping{}; u8 end_of_stream{}; u8 sent_to_server{}; - INSERT_PADDING_BYTES(5); + INSERT_PADDING_BYTES(1); + s32 loop_count{}; u64 context_address{}; u64 context_size{}; - INSERT_PADDING_BYTES(8); + u32 loop_start_sample{}; + u32 loop_end_sample{}; }; static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer is an invalid size"); @@ -76,6 +78,9 @@ struct ServerWaveBuffer { bool end_of_stream{}; VAddr context_address{}; std::size_t context_size{}; + s32 loop_count{}; + u32 loop_start_sample{}; + u32 loop_end_sample{}; bool sent_to_dsp{true}; }; @@ -108,6 +113,7 @@ struct VoiceState { u32 external_context_size; bool is_external_context_used; bool voice_dropped; + s32 loop_count; }; class VoiceChannelResource { @@ -206,7 +212,7 @@ public: float last_volume{}; std::array biquad_filter{}; s32 wave_buffer_count{}; - s16 wave_bufffer_head{}; + s16 wave_buffer_head{}; INSERT_PADDING_BYTES(2); BehaviorFlags behavior_flags{}; VAddr additional_params_address{}; @@ -252,6 +258,7 @@ public: void FlushWaveBuffers(u8 flush_count, std::array& dsp_voice_states, s32 channel_count); + void SetWaveBufferCompleted(VoiceState& dsp_state, const ServerWaveBuffer& wave_buffer); private: std::vector stored_samples; diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 672ea9d74..4b8de2bfe 100755 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -103,9 +103,8 @@ void Adapter::AdapterInputThread(std::stop_token stop_token) { AdapterPayload adapter_payload{}; adapter_scan_thread = {}; - adapter_input_thread_running = true; - while (adapter_input_thread_running && !stop_token.stop_requested()) { + while (!stop_token.stop_requested()) { libusb_interrupt_transfer(usb_adapter_handle->get(), input_endpoint, adapter_payload.data(), static_cast(adapter_payload.size()), &payload_size, 16); if (IsPayloadCorrect(adapter_payload, payload_size)) { @@ -129,7 +128,7 @@ bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payloa adapter_payload[0]); if (input_error_counter++ > 20) { LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); - adapter_input_thread_running = false; + adapter_input_thread.request_stop(); restart_scan_thread = true; } return false; @@ -303,14 +302,15 @@ void Adapter::AdapterScanThread(std::stop_token stop_token) { usb_adapter_handle = nullptr; pads = {}; while (!stop_token.stop_requested() && !Setup()) { - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::seconds(2)); } } bool Adapter::Setup() { - constexpr u16 vid = 0x057e; // Nintendo - constexpr u16 pid = 0x0337; // GC Adapter - usb_adapter_handle = std::make_unique(libusb_ctx->get(), vid, pid); + constexpr u16 nintendo_vid = 0x057e; + constexpr u16 gc_adapter_pid = 0x0337; + usb_adapter_handle = + std::make_unique(libusb_ctx->get(), nintendo_vid, gc_adapter_pid); if (!usb_adapter_handle->get()) { return false; } diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index 4a1c87490..28dbcbe05 100755 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -156,6 +156,5 @@ private: bool configuring{false}; bool rumble_enabled{true}; bool vibration_changed{true}; - bool adapter_input_thread_running{false}; }; } // namespace GCAdapter