From 08ad5aad5322c8ebd1d68330408a4f979b4df474 Mon Sep 17 00:00:00 2001
From: Connor McLaughlin <stenzek@gmail.com>
Date: Fri, 27 Mar 2020 01:42:43 +1000
Subject: [PATCH] SPU: Run muted voices when IRQ is enabled

Fixes SPU timeout in Casper. We can still optimize for most games where
interrupts are not used by completely ignoring muted voices in those.
---
 src/core/spu.cpp | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/src/core/spu.cpp b/src/core/spu.cpp
index d8ba9104e..7dfd67120 100644
--- a/src/core/spu.cpp
+++ b/src/core/spu.cpp
@@ -1225,7 +1225,7 @@ void SPU::ReadADPCMBlock(u16 address, ADPCMBlock* block)
 std::tuple<s32, s32> SPU::SampleVoice(u32 voice_index)
 {
   Voice& voice = m_voices[voice_index];
-  if (!voice.IsOn())
+  if (!voice.IsOn() && !m_SPUCNT.irq9_enable)
   {
     voice.last_volume = 0;
     return {};
@@ -1245,18 +1245,28 @@ std::tuple<s32, s32> SPU::SampleVoice(u32 voice_index)
     }
   }
 
-  // interpolate/sample and apply ADSR volume
-  s16 sample;
-  if (IsVoiceNoiseEnabled(voice_index))
-    sample = GetVoiceNoiseLevel();
-  else
-    sample = voice.Interpolate();
+  // skip interpolation when the volume is muted anyway
+  s32 volume;
+  if (voice.regs.adsr_volume != 0)
+  {
+    // interpolate/sample and apply ADSR volume
+    s16 sample;
+    if (IsVoiceNoiseEnabled(voice_index))
+      sample = GetVoiceNoiseLevel();
+    else
+      sample = voice.Interpolate();
+
+    volume = ApplyVolume(sample, voice.regs.adsr_volume);
+  }
+  else
+  {
+    volume = 0;
+  }
 
-  const s32 volume = ApplyVolume(sample, voice.regs.adsr_volume);
-  // if (voice_index == 3 || voice_index == 4)
-  // Log_WarningPrintf("voice %u %d", voice_index, volume);
   voice.last_volume = volume;
-  voice.TickADSR();
+
+  if (voice.adsr_phase != ADSRPhase::Off)
+    voice.TickADSR();
 
   // Pitch modulation
   u16 step = voice.regs.adpcm_sample_rate;