Merge pull request #1455 from ogniK5377/smo-softlockfix
Fixed smo softlock due to incorrect effect state updating
This commit is contained in:
		
						commit
						6aab309e41
					
				@ -30,7 +30,7 @@ public:
 | 
				
			|||||||
        return info;
 | 
					        return info;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VoiceInfo& Info() {
 | 
					    VoiceInfo& GetInfo() {
 | 
				
			||||||
        return info;
 | 
					        return info;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,9 +51,30 @@ private:
 | 
				
			|||||||
    VoiceInfo info{};
 | 
					    VoiceInfo info{};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AudioRenderer::EffectState {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    const EffectOutStatus& GetOutStatus() const {
 | 
				
			||||||
 | 
					        return out_status;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const EffectInStatus& GetInfo() const {
 | 
				
			||||||
 | 
					        return info;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EffectInStatus& GetInfo() {
 | 
				
			||||||
 | 
					        return info;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void UpdateState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    EffectOutStatus out_status{};
 | 
				
			||||||
 | 
					    EffectInStatus info{};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
AudioRenderer::AudioRenderer(AudioRendererParameter params,
 | 
					AudioRenderer::AudioRenderer(AudioRendererParameter params,
 | 
				
			||||||
                             Kernel::SharedPtr<Kernel::Event> buffer_event)
 | 
					                             Kernel::SharedPtr<Kernel::Event> buffer_event)
 | 
				
			||||||
    : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) {
 | 
					    : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
 | 
				
			||||||
 | 
					      effects(params.effect_count) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    audio_out = std::make_unique<AudioCore::AudioOut>();
 | 
					    audio_out = std::make_unique<AudioCore::AudioOut>();
 | 
				
			||||||
    stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
 | 
					    stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
 | 
				
			||||||
@ -96,11 +117,29 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
 | 
				
			|||||||
                memory_pool_count * sizeof(MemoryPoolInfo));
 | 
					                memory_pool_count * sizeof(MemoryPoolInfo));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Copy VoiceInfo structs
 | 
					    // Copy VoiceInfo structs
 | 
				
			||||||
    std::size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size +
 | 
					    std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
 | 
				
			||||||
                       config.voice_resource_size};
 | 
					                             config.memory_pools_size + config.voice_resource_size};
 | 
				
			||||||
    for (auto& voice : voices) {
 | 
					    for (auto& voice : voices) {
 | 
				
			||||||
        std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo));
 | 
					        std::memcpy(&voice.GetInfo(), input_params.data() + voice_offset, sizeof(VoiceInfo));
 | 
				
			||||||
        offset += sizeof(VoiceInfo);
 | 
					        voice_offset += sizeof(VoiceInfo);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t effect_offset{sizeof(UpdateDataHeader) + config.behavior_size +
 | 
				
			||||||
 | 
					                              config.memory_pools_size + config.voice_resource_size +
 | 
				
			||||||
 | 
					                              config.voices_size};
 | 
				
			||||||
 | 
					    for (auto& effect : effects) {
 | 
				
			||||||
 | 
					        std::memcpy(&effect.GetInfo(), input_params.data() + effect_offset, sizeof(EffectInStatus));
 | 
				
			||||||
 | 
					        effect_offset += sizeof(EffectInStatus);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Update memory pool state
 | 
				
			||||||
 | 
					    std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
 | 
				
			||||||
 | 
					    for (std::size_t index = 0; index < memory_pool.size(); ++index) {
 | 
				
			||||||
 | 
					        if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
 | 
				
			||||||
 | 
					            memory_pool[index].state = MemoryPoolStates::Attached;
 | 
				
			||||||
 | 
					        } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
 | 
				
			||||||
 | 
					            memory_pool[index].state = MemoryPoolStates::Detached;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Update voices
 | 
					    // Update voices
 | 
				
			||||||
@ -114,14 +153,8 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Update memory pool state
 | 
					    for (auto& effect : effects) {
 | 
				
			||||||
    std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
 | 
					        effect.UpdateState();
 | 
				
			||||||
    for (std::size_t index = 0; index < memory_pool.size(); ++index) {
 | 
					 | 
				
			||||||
        if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
 | 
					 | 
				
			||||||
            memory_pool[index].state = MemoryPoolStates::Attached;
 | 
					 | 
				
			||||||
        } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
 | 
					 | 
				
			||||||
            memory_pool[index].state = MemoryPoolStates::Detached;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Release previous buffers and queue next ones for playback
 | 
					    // Release previous buffers and queue next ones for playback
 | 
				
			||||||
@ -144,6 +177,14 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
 | 
				
			|||||||
        voice_out_status_offset += sizeof(VoiceOutStatus);
 | 
					        voice_out_status_offset += sizeof(VoiceOutStatus);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t effect_out_status_offset{
 | 
				
			||||||
 | 
					        sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
 | 
				
			||||||
 | 
					        response_data.voice_resource_size};
 | 
				
			||||||
 | 
					    for (const auto& effect : effects) {
 | 
				
			||||||
 | 
					        std::memcpy(output_params.data() + effect_out_status_offset, &effect.GetOutStatus(),
 | 
				
			||||||
 | 
					                    sizeof(EffectOutStatus));
 | 
				
			||||||
 | 
					        effect_out_status_offset += sizeof(EffectOutStatus);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return output_params;
 | 
					    return output_params;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -244,11 +285,29 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    samples = Interpolate(interp_state, std::move(samples), Info().sample_rate, STREAM_SAMPLE_RATE);
 | 
					    samples =
 | 
				
			||||||
 | 
					        Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    is_refresh_pending = false;
 | 
					    is_refresh_pending = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AudioRenderer::EffectState::UpdateState() {
 | 
				
			||||||
 | 
					    if (info.is_new) {
 | 
				
			||||||
 | 
					        out_status.state = EffectStatus::New;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (info.type == Effect::Aux) {
 | 
				
			||||||
 | 
					            ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0,
 | 
				
			||||||
 | 
					                       "Aux buffers tried to update");
 | 
				
			||||||
 | 
					            ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0,
 | 
				
			||||||
 | 
					                       "Aux buffers tried to update");
 | 
				
			||||||
 | 
					            ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0,
 | 
				
			||||||
 | 
					                       "Aux buffers tried to update");
 | 
				
			||||||
 | 
					            ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0,
 | 
				
			||||||
 | 
					                       "Aux buffers tried to update");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static constexpr s16 ClampToS16(s32 value) {
 | 
					static constexpr s16 ClampToS16(s32 value) {
 | 
				
			||||||
    return static_cast<s16>(std::clamp(value, -32768, 32767));
 | 
					    return static_cast<s16>(std::clamp(value, -32768, 32767));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -28,6 +28,16 @@ enum class PlayState : u8 {
 | 
				
			|||||||
    Paused = 2,
 | 
					    Paused = 2,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Effect : u8 {
 | 
				
			||||||
 | 
					    None = 0,
 | 
				
			||||||
 | 
					    Aux = 2,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class EffectStatus : u8 {
 | 
				
			||||||
 | 
					    None = 0,
 | 
				
			||||||
 | 
					    New = 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct AudioRendererParameter {
 | 
					struct AudioRendererParameter {
 | 
				
			||||||
    u32_le sample_rate;
 | 
					    u32_le sample_rate;
 | 
				
			||||||
    u32_le sample_count;
 | 
					    u32_le sample_count;
 | 
				
			||||||
@ -128,6 +138,43 @@ struct VoiceOutStatus {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
 | 
					static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AuxInfo {
 | 
				
			||||||
 | 
					    std::array<u8, 24> input_mix_buffers;
 | 
				
			||||||
 | 
					    std::array<u8, 24> output_mix_buffers;
 | 
				
			||||||
 | 
					    u32_le mix_buffer_count;
 | 
				
			||||||
 | 
					    u32_le sample_rate; // Stored in the aux buffer currently
 | 
				
			||||||
 | 
					    u32_le sampe_count;
 | 
				
			||||||
 | 
					    u64_le send_buffer_info;
 | 
				
			||||||
 | 
					    u64_le send_buffer_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u64_le return_buffer_info;
 | 
				
			||||||
 | 
					    u64_le return_buffer_base;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct EffectInStatus {
 | 
				
			||||||
 | 
					    Effect type;
 | 
				
			||||||
 | 
					    u8 is_new;
 | 
				
			||||||
 | 
					    u8 is_enabled;
 | 
				
			||||||
 | 
					    INSERT_PADDING_BYTES(1);
 | 
				
			||||||
 | 
					    u32_le mix_id;
 | 
				
			||||||
 | 
					    u64_le buffer_base;
 | 
				
			||||||
 | 
					    u64_le buffer_sz;
 | 
				
			||||||
 | 
					    s32_le priority;
 | 
				
			||||||
 | 
					    INSERT_PADDING_BYTES(4);
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        std::array<u8, 0xa0> raw;
 | 
				
			||||||
 | 
					        AuxInfo aux_info;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static_assert(sizeof(EffectInStatus) == 0xc0, "EffectInStatus is an invalid size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct EffectOutStatus {
 | 
				
			||||||
 | 
					    EffectStatus state;
 | 
				
			||||||
 | 
					    INSERT_PADDING_BYTES(0xf);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static_assert(sizeof(EffectOutStatus) == 0x10, "EffectOutStatus is an invalid size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct UpdateDataHeader {
 | 
					struct UpdateDataHeader {
 | 
				
			||||||
    UpdateDataHeader() {}
 | 
					    UpdateDataHeader() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -173,11 +220,13 @@ public:
 | 
				
			|||||||
    Stream::State GetStreamState() const;
 | 
					    Stream::State GetStreamState() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					    class EffectState;
 | 
				
			||||||
    class VoiceState;
 | 
					    class VoiceState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    AudioRendererParameter worker_params;
 | 
					    AudioRendererParameter worker_params;
 | 
				
			||||||
    Kernel::SharedPtr<Kernel::Event> buffer_event;
 | 
					    Kernel::SharedPtr<Kernel::Event> buffer_event;
 | 
				
			||||||
    std::vector<VoiceState> voices;
 | 
					    std::vector<VoiceState> voices;
 | 
				
			||||||
 | 
					    std::vector<EffectState> effects;
 | 
				
			||||||
    std::unique_ptr<AudioOut> audio_out;
 | 
					    std::unique_ptr<AudioOut> audio_out;
 | 
				
			||||||
    AudioCore::StreamPtr stream;
 | 
					    AudioCore::StreamPtr stream;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user