diff --git a/rpcs3/Emu/Cell/Modules/cellMic.cpp b/rpcs3/Emu/Cell/Modules/cellMic.cpp index 86e4b8bafa..98e4692927 100644 --- a/rpcs3/Emu/Cell/Modules/cellMic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMic.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "3rdparty/OpenAL/openal-soft/include/AL/alext.h" @@ -575,6 +576,28 @@ bool microphone_device::has_data() const return mic_registered && mic_opened && mic_started && (rbuf_raw.has_data() || rbuf_dsp.has_data()); } +f32 microphone_device::calculate_energy_level() +{ + const auto& buffer = device_type == microphone_handler::real_singstar ? ::at32(devices, 0).buf : temp_buf; + const size_t num_samples = buffer.size() / sizeof(s16); + + f64 sum_squares = 0.0; + + for (usz i = 0; i < num_samples; i++) + { + const be_t sample = read_from_ptr>(buffer, i * sizeof(s16)); + const f64 normalized_sample = static_cast(sample) / -std::numeric_limits::min(); + sum_squares += normalized_sample * normalized_sample; + } + + const f32 rms = std::sqrt(sum_squares / num_samples); + const f32 decibels_max = 90.0f; + const f32 decibels_relative = 20.0f * std::log10(std::max(rms, 0.00001f)); + const f32 decibels = decibels_max + (decibels_relative * 0.5f); + + return std::clamp(decibels, 40.0f, decibels_max); +} + u32 microphone_device::capture_audio() { ensure(sample_size > 0); @@ -1089,7 +1112,7 @@ error_code cellMicGetSignalState(s32 dev_num, CellMicSignalState sig_state, vm:: *fval = 1.0f; // No gain applied break; case CELLMIC_SIGSTATE_MICENG: - *fval = 40.0f; // 40 decibels + *fval = device.calculate_energy_level(); break; case CELLMIC_SIGSTATE_SPKENG: *fval = 10.0f; // 10 decibels diff --git a/rpcs3/Emu/Cell/Modules/cellMic.h b/rpcs3/Emu/Cell/Modules/cellMic.h index b00848218c..f17b954278 100644 --- a/rpcs3/Emu/Cell/Modules/cellMic.h +++ b/rpcs3/Emu/Cell/Modules/cellMic.h @@ -289,6 +289,8 @@ public: void update_audio(); bool has_data() const; + f32 calculate_energy_level(); + bool is_registered() const { return mic_registered; } bool is_opened() const { return mic_opened; } bool is_started() const { return mic_started; }