diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index 7a47ccf7d22f..99f622a9043b 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -391,8 +391,7 @@ void Wiimote::HandleSpeakerData(const WiimoteCommon::OutputReportSpeakerData& rp else { // Speaker Pan - // GUI clamps pan setting from -127 to 127. Why? - const auto pan = int(m_options->numeric_settings[0]->GetValue() * 100); + const auto pan = m_options->numeric_settings[0]->GetValue(); m_speaker_logic.SpeakerData(rpt.data, rpt.length, pan); } diff --git a/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp b/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp index eda359c9d4e2..6fcd8c10a9c2 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp @@ -71,7 +71,7 @@ void stopdamnwav() } #endif -void SpeakerLogic::SpeakerData(const u8* data, int length, int speaker_pan) +void SpeakerLogic::SpeakerData(const u8* data, int length, float speaker_pan) { // TODO: should we still process samples for the decoder state? if (!SConfig::GetInstance().m_WiimoteEnableSpeaker) @@ -127,19 +127,20 @@ void SpeakerLogic::SpeakerData(const u8* data, int length, int speaker_pan) volume_divisor = reg_data.volume; } - // TODO: use speaker pan law + // SetWiimoteSpeakerVolume expects values from 0 to 255. + // Multiply by 256, cast to int, and clamp to 255 for a uniform conversion. + const double volume = float(reg_data.volume) / volume_divisor * 256; - const unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate; - float speaker_volume_ratio = (float)reg_data.volume / volume_divisor; - // Sloppy math: - unsigned int left_volume = - MathUtil::Clamp((0xff + (2 * speaker_pan)) * speaker_volume_ratio, 0, 0xff); - unsigned int right_volume = - MathUtil::Clamp((0xff - (2 * speaker_pan)) * speaker_volume_ratio, 0, 0xff); + // Speaker pan using "Constant Power Pan Law" + const double pan_prime = MathUtil::PI * (speaker_pan + 1) / 4; + + const auto left_volume = std::min(int(std::cos(pan_prime) * volume), 255); + const auto right_volume = std::min(int(std::sin(pan_prime) * volume), 255); g_sound_stream->GetMixer()->SetWiimoteSpeakerVolume(left_volume, right_volume); // ADPCM sample rate is thought to be x2.(3000 x2 = 6000). + const unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate; g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(samples.get(), sample_length, sample_rate * 2); diff --git a/Source/Core/Core/HW/WiimoteEmu/Speaker.h b/Source/Core/Core/HW/WiimoteEmu/Speaker.h index 80b5e217d0f7..6f305668423c 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Speaker.h +++ b/Source/Core/Core/HW/WiimoteEmu/Speaker.h @@ -23,7 +23,8 @@ class SpeakerLogic : public I2CSlave void Reset(); void DoState(PointerWrap& p); - void SpeakerData(const u8* data, int length, int speaker_pan); + // Pan is -1.0 to +1.0 + void SpeakerData(const u8* data, int length, float speaker_pan); private: // TODO: enum class diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index b99b57726517..e050226d0943 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -233,7 +233,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index) false, ControllerEmu::SettingType::NORMAL, true)); m_options->numeric_settings.emplace_back( - std::make_unique(_trans("Speaker Pan"), 0, -127, 127)); + std::make_unique(_trans("Speaker Pan"), 0, -100, 100)); m_options->numeric_settings.emplace_back( m_battery_setting = new ControllerEmu::NumericSetting(_trans("Battery"), 95.0 / 100, 0, 100));