SPU2: Fix interface for output muting

This commit is contained in:
TheTechnician27 2025-10-12 03:28:42 -05:00 committed by TellowKrinkle
parent b02318e2b6
commit 38cfa9912d
5 changed files with 138 additions and 66 deletions

View File

@ -879,38 +879,6 @@ void EmuThread::endCapture()
MTGS::RunOnGSThread(&GSEndCapture);
}
void EmuThread::setAudioOutputVolume(int volume, int fast_forward_volume)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "setAudioOutputVolume", Qt::QueuedConnection, Q_ARG(int, volume),
Q_ARG(int, fast_forward_volume));
return;
}
if (!VMManager::HasValidVM())
return;
EmuConfig.SPU2.OutputVolume = static_cast<u32>(volume);
EmuConfig.SPU2.FastForwardVolume = static_cast<u32>(fast_forward_volume);
SPU2::SetOutputVolume(SPU2::GetResetVolume());
}
void EmuThread::setAudioOutputMuted(bool muted)
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, "setAudioOutputMuted", Qt::QueuedConnection, Q_ARG(bool, muted));
return;
}
if (!VMManager::HasValidVM())
return;
EmuConfig.SPU2.OutputMuted = muted;
SPU2::SetOutputVolume(SPU2::GetResetVolume());
}
std::optional<WindowInfo> EmuThread::acquireRenderWindow(bool recreate_window)
{
// Check if we're wanting to get exclusive fullscreen. This should be safe to read, since we're going to be calling from the GS thread.

View File

@ -112,8 +112,6 @@ public Q_SLOTS:
void queueSnapshot(quint32 gsdump_frames);
void beginCapture(const QString& path);
void endCapture();
void setAudioOutputVolume(int volume, int fast_forward_volume);
void setAudioOutputMuted(bool muted);
Q_SIGNALS:
bool messageConfirmed(const QString& title, const QString& message);

View File

@ -40,28 +40,58 @@ static void HotkeyAdjustTargetSpeed(double delta)
Host::OSD_QUICK_DURATION);
}
static void HotkeyAdjustVolume(s32 fixed, s32 delta)
static void HotkeyAdjustVolume(const s32 delta)
{
if (!VMManager::HasValidVM())
return;
const s32 current_vol = static_cast<s32>(SPU2::GetOutputVolume());
const s32 new_volume =
std::clamp((fixed >= 0) ? fixed : (current_vol + delta), 0, static_cast<s32>(Pcsx2Config::SPU2Options::MAX_VOLUME));
if (current_vol != new_volume)
// Volume-adjusting hotkeys override mute toggle hotkey. EmuConfig.SPU2.OutputMuted overrides hotkeys.
if (!SPU2::SetOutputMuted(false))
{
Host::AddIconOSDMessage("VolumeChanged", ICON_FA_VOLUME_XMARK, TRANSLATE_STR("Hotkeys", "Volume: Muted in Settings"));
return;
}
const s32 current_volume = static_cast<s32>(SPU2::GetOutputVolume());
const s32 maximum_volume = static_cast<s32>(Pcsx2Config::SPU2Options::MAX_VOLUME);
const s32 new_volume = std::clamp(current_volume + delta, 0, maximum_volume);
if (current_volume != new_volume)
SPU2::SetOutputVolume(static_cast<u32>(new_volume));
if (new_volume == 0)
if (new_volume > 0 && new_volume < maximum_volume)
{
Host::AddIconOSDMessage("VolumeChanged", ICON_FA_VOLUME_XMARK, TRANSLATE_STR("Hotkeys", "Volume: Muted"));
Host::AddIconOSDMessage("VolumeChanged", new_volume < 100 ? ICON_FA_VOLUME_LOW : ICON_FA_VOLUME_HIGH,
fmt::format(TRANSLATE_FS("Hotkeys", "Volume: {} to {}%"), delta < 0 ? TRANSLATE_STR("Hotkeys", "Decreased") : TRANSLATE_STR("Hotkeys", "Increased"), new_volume));
}
else
{
Host::AddIconOSDMessage("VolumeChanged", (current_vol < new_volume) ? ICON_FA_VOLUME_HIGH : ICON_FA_VOLUME_LOW,
fmt::format(TRANSLATE_FS("Hotkeys", "Volume: {}%"), new_volume));
Host::AddIconOSDMessage("VolumeChanged", delta < 0 ? ICON_FA_VOLUME_OFF : ICON_FA_VOLUME_HIGH,
fmt::format(TRANSLATE_FS("Hotkeys", "Volume: {} {}% Reached"), delta < 0 ? TRANSLATE_STR("Hotkeys", "Minimum") : TRANSLATE_STR("Hotkeys", "Maximum"), new_volume));
}
}
static void HotkeyToggleMute()
{
if (!VMManager::HasValidVM())
return;
// Attempt to toggle output muting. EmuConfig.SPU2.OutputMuted overrides hotkeys.
if (SPU2::SetOutputMuted(!SPU2::IsOutputMuted()))
{
if (SPU2::IsOutputMuted())
Host::AddIconOSDMessage("VolumeChanged", ICON_FA_VOLUME_XMARK, TRANSLATE_STR("Hotkeys", "Volume: Muted"));
else
{
const u32 current_volume = SPU2::GetOutputVolume();
Host::AddIconOSDMessage("VolumeChanged", current_volume < 100 ? (current_volume == 0 ? ICON_FA_VOLUME_OFF : ICON_FA_VOLUME_LOW) : ICON_FA_VOLUME_HIGH,
fmt::format(TRANSLATE_FS("Hotkeys", "Volume: Unmuted to {}%"), current_volume));
}
}
else
Host::AddIconOSDMessage("VolumeChanged", ICON_FA_VOLUME_XMARK, TRANSLATE_STR("Hotkeys", "Volume: Muted in Settings"));
}
static void HotkeyLoadStateSlot(s32 slot)
{
// Can reapply settings and thus binds, therefore must be deferred.
@ -293,16 +323,16 @@ DEFINE_HOTKEY_LOADSTATE_X(10, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 10
#undef DEFINE_HOTKEY_LOADSTATE_X
DEFINE_HOTKEY("Mute", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Toggle Mute"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume((SPU2::GetOutputVolume() == 0) ? SPU2::GetResetVolume() : 0, 0);
HotkeyToggleMute();
})
DEFINE_HOTKEY("IncreaseVolume", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Increase Volume"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume(-1, 5);
HotkeyAdjustVolume(5);
})
DEFINE_HOTKEY("DecreaseVolume", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Decrease Volume"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume(-1, -5);
HotkeyAdjustVolume(-5);
})
END_HOTKEY_LIST()

View File

@ -28,10 +28,13 @@ u32 lClocks = 0;
static bool s_audio_capture_active = false;
static bool s_psxmode = false;
static bool s_output_muted = false;
static std::unique_ptr<AudioStream> s_output_stream;
static std::array<s16, AudioStream::CHUNK_SIZE * 2> s_current_chunk;
static u32 s_current_chunk_pos;
static u32 s_standard_volume = 0;
static u32 s_fast_forward_volume = 0;
u32 SPU2::GetConsoleSampleRate()
{
@ -97,8 +100,17 @@ void SPU2writeDMA7Mem(u16* pMem, u32 size)
void SPU2::CreateOutputStream()
{
// Persist volume through stream recreates.
const u32 volume = s_output_stream ? s_output_stream->GetOutputVolume() : GetResetVolume();
// Initialize volume and mute settings on new session.
if (!s_output_stream)
{
s_standard_volume = EmuConfig.SPU2.OutputVolume;
s_fast_forward_volume = EmuConfig.SPU2.FastForwardVolume;
s_output_muted = EmuConfig.SPU2.OutputMuted;
}
// Else persist volume through stream recreates.
else if (!s_output_muted)
SPU2::SaveOutputVolume();
const u32 sample_rate = GetConsoleSampleRate();
s_output_stream.reset();
@ -114,7 +126,7 @@ void SPU2::CreateOutputStream()
s_output_stream = AudioStream::CreateNullStream(sample_rate, EmuConfig.SPU2.StreamParameters.buffer_ms);
}
s_output_stream->SetOutputVolume(volume);
SPU2::UpdateOutputVolume();
s_output_stream->SetNominalRate(GetNominalRate());
s_output_stream->SetPaused(VMManager::GetState() == VMState::Paused);
}
@ -144,20 +156,52 @@ void SPU2::SetOutputVolume(u32 volume)
s_output_stream->SetOutputVolume(volume);
}
u32 SPU2::GetResetVolume()
{
return EmuConfig.SPU2.OutputMuted ? 0 :
((VMManager::GetTargetSpeed() != 1.0f) ?
EmuConfig.SPU2.FastForwardVolume :
EmuConfig.SPU2.OutputVolume);
}
float SPU2::GetNominalRate()
{
// Adjust nominal rate when syncing to host.
return VMManager::IsTargetSpeedAdjustedToHost() ? VMManager::GetTargetSpeed() : 1.0f;
}
bool SPU2::SetOutputMuted(const bool muted)
{
// User setting takes precedence. Unmute not guaranteed by design.
if (!s_output_stream || (!muted && EmuConfig.SPU2.OutputMuted))
return false;
if (muted == s_output_muted)
return true;
if (muted)
SPU2::SaveOutputVolume();
s_output_muted = muted;
SPU2::UpdateOutputVolume();
return true;
}
bool SPU2::IsOutputMuted()
{
return s_output_muted;
}
void SPU2::UpdateOutputVolume()
{
s_output_stream->SetOutputVolume(s_output_muted ?
0 : (VMManager::GetTargetSpeed() == 1.0f ?
s_standard_volume : s_fast_forward_volume));
}
void SPU2::SaveOutputVolume()
{
if (!s_output_muted)
{
if (VMManager::GetTargetSpeed() == 1.0f)
s_standard_volume = s_output_stream->GetOutputVolume();
else
s_fast_forward_volume = s_output_stream->GetOutputVolume();
}
}
void SPU2::SetOutputPaused(bool paused)
{
s_output_stream->SetPaused(paused);
@ -210,8 +254,20 @@ void SPU2::OnTargetSpeedChanged()
s_output_stream->SetNominalRate(GetNominalRate());
if (EmuConfig.SPU2.OutputVolume != EmuConfig.SPU2.FastForwardVolume && !EmuConfig.SPU2.OutputMuted)
s_output_stream->SetOutputVolume(GetResetVolume());
// Flipped save as speed has already changed.
if (!s_output_muted)
{
if (VMManager::GetTargetSpeed() == 1.0f)
{
s_fast_forward_volume = s_output_stream->GetOutputVolume();
s_output_stream->SetOutputVolume(s_standard_volume);
}
else
{
s_standard_volume = s_output_stream->GetOutputVolume();
s_output_stream->SetOutputVolume(s_fast_forward_volume);
}
}
}
bool SPU2::Open()
@ -265,13 +321,25 @@ void SPU2::CheckForConfigChanges(const Pcsx2Config& old_config)
const Pcsx2Config::SPU2Options& oldopts = old_config.SPU2;
// No need to reinit for volume change.
if ((opts.OutputVolume != oldopts.OutputVolume && VMManager::GetTargetSpeed() == 1.0f) ||
(opts.FastForwardVolume != oldopts.FastForwardVolume && VMManager::GetTargetSpeed() != 1.0f) ||
opts.OutputMuted != oldopts.OutputMuted)
if (opts.OutputMuted != oldopts.OutputMuted)
SPU2::SetOutputMuted(opts.OutputMuted);
bool volume_settings_changed = false;
if (opts.OutputVolume != oldopts.OutputVolume)
{
SetOutputVolume(GetResetVolume());
s_standard_volume = opts.OutputVolume;
volume_settings_changed = true;
}
if (opts.FastForwardVolume != oldopts.FastForwardVolume)
{
s_fast_forward_volume = opts.FastForwardVolume;
volume_settings_changed = true;
}
if (volume_settings_changed)
SPU2::UpdateOutputVolume();
// Things which require re-initialzing the output.
if (opts.Backend != oldopts.Backend ||
opts.StreamParameters != oldopts.StreamParameters ||

View File

@ -36,8 +36,17 @@ u32 GetOutputVolume();
/// Directly updates the output volume without going through the configuration.
void SetOutputVolume(u32 volume);
/// Returns the volume that we would reset the output to on startup.
u32 GetResetVolume();
/// Sets up muting and unmuting and reports success or failure.
bool SetOutputMuted(const bool muted);
/// Returns true if the output is muted (distinct from 0%).
bool IsOutputMuted();
/// Updates the current volume based on running state.
void UpdateOutputVolume();
/// Saves the current volume based on running state.
void SaveOutputVolume();
/// Pauses/resumes the output stream.
void SetOutputPaused(bool paused);
@ -74,4 +83,3 @@ extern u32 lClocks;
extern void TimeUpdate(u32 cClocks);
extern void SPU2_FastWrite(u32 rmem, u16 value);
//#define PCM24_S1_INTERLEAVE