mirror of https://github.com/PCSX2/pcsx2.git
SPU2: Rewrite ADSR [SAVEVERSION+]
This commit is contained in:
parent
43e700036d
commit
7bf8f6115f
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
static constexpr s32 ADSR_MAX_VOL = 0x7fffffff;
|
||||
static constexpr s32 ADSR_MAX_VOL = 0x7fff;
|
||||
|
||||
static const int InvExpOffsets[] = {0, 4, 6, 8, 9, 10, 11, 12};
|
||||
|
||||
|
@ -47,191 +47,120 @@ static constexpr PSXRateTable ComputePSXRates()
|
|||
|
||||
static constexpr const PSXRateTable PsxRates = ComputePSXRates();
|
||||
|
||||
bool V_ADSR::Calculate()
|
||||
void V_ADSR::UpdateCache()
|
||||
{
|
||||
pxAssume(Phase != 0);
|
||||
CachedPhases[PHASE_ATTACK].Decr = false;
|
||||
CachedPhases[PHASE_ATTACK].Exp = AttackMode;
|
||||
CachedPhases[PHASE_ATTACK].Shift = AttackShift;
|
||||
CachedPhases[PHASE_ATTACK].Step = 7 - AttackStep;
|
||||
CachedPhases[PHASE_ATTACK].Target = ADSR_MAX_VOL;
|
||||
|
||||
if (Releasing && (Phase < 5))
|
||||
Phase = 5;
|
||||
CachedPhases[PHASE_DECAY].Decr = true;
|
||||
CachedPhases[PHASE_DECAY].Exp = true;
|
||||
CachedPhases[PHASE_DECAY].Shift = DecayShift;
|
||||
CachedPhases[PHASE_DECAY].Step = -8;
|
||||
CachedPhases[PHASE_DECAY].Target = (SustainLevel + 1) << 11;
|
||||
|
||||
switch (Phase)
|
||||
{
|
||||
case 1: // attack
|
||||
if (Value == ADSR_MAX_VOL)
|
||||
{
|
||||
// Already maxed out. Progress phase and nothing more:
|
||||
Phase++;
|
||||
break;
|
||||
}
|
||||
CachedPhases[PHASE_SUSTAIN].Decr = SustainDir;
|
||||
CachedPhases[PHASE_SUSTAIN].Exp = SustainMode;
|
||||
CachedPhases[PHASE_SUSTAIN].Shift = SustainShift;
|
||||
CachedPhases[PHASE_SUSTAIN].Step = 7 - SustainStep;
|
||||
|
||||
// Case 1 below is for pseudo exponential below 75%.
|
||||
// Pseudo Exp > 75% and Linear are the same.
|
||||
if (CachedPhases[PHASE_SUSTAIN].Decr)
|
||||
CachedPhases[PHASE_SUSTAIN].Step = ~CachedPhases[PHASE_SUSTAIN].Step;
|
||||
|
||||
if (AttackMode && (Value >= 0x60000000))
|
||||
Value += PsxRates[(AttackRate ^ 0x7f) - 0x18 + 32];
|
||||
else
|
||||
Value += PsxRates[(AttackRate ^ 0x7f) - 0x10 + 32];
|
||||
CachedPhases[PHASE_SUSTAIN].Target = 0;
|
||||
|
||||
if (Value < 0)
|
||||
{
|
||||
// We hit the ceiling.
|
||||
Phase++;
|
||||
Value = ADSR_MAX_VOL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // decay
|
||||
{
|
||||
const u32 off = InvExpOffsets[(Value >> 28) & 7];
|
||||
Value -= PsxRates[((DecayRate ^ 0x1f) * 4) - 0x18 + off + 32];
|
||||
|
||||
// calculate sustain level as a factor of the ADSR maximum volume.
|
||||
|
||||
s32 suslev = ((0x80000000 / 0x10) * (SustainLevel + 1)) - 1;
|
||||
|
||||
if (Value <= suslev)
|
||||
{
|
||||
if (Value < 0)
|
||||
Value = 0;
|
||||
Phase++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // sustain
|
||||
{
|
||||
// 0x7f disables sustain (infinite sustain)
|
||||
if (SustainRate == 0x7f)
|
||||
return true;
|
||||
|
||||
if (SustainMode & 2) // decreasing
|
||||
{
|
||||
if (SustainMode & 4) // exponential
|
||||
{
|
||||
const u32 off = InvExpOffsets[(Value >> 28) & 7];
|
||||
Value -= PsxRates[(SustainRate ^ 0x7f) - 0x1b + off + 32];
|
||||
}
|
||||
else // linear
|
||||
Value -= PsxRates[(SustainRate ^ 0x7f) - 0xf + 32];
|
||||
|
||||
if (Value <= 0)
|
||||
{
|
||||
Value = 0;
|
||||
Phase++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // increasing
|
||||
if ((SustainMode & 4) && (Value >= 0x60000000))
|
||||
Value += PsxRates[(SustainRate ^ 0x7f) - 0x18 + 32];
|
||||
else
|
||||
// linear / Pseudo below 75% (they're the same)
|
||||
Value += PsxRates[(SustainRate ^ 0x7f) - 0x10 + 32];
|
||||
|
||||
if (Value < 0)
|
||||
{
|
||||
Value = ADSR_MAX_VOL;
|
||||
Phase++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // sustain end
|
||||
Value = (SustainMode & 2) ? 0 : ADSR_MAX_VOL;
|
||||
if (Value == 0)
|
||||
Phase = 6;
|
||||
break;
|
||||
|
||||
case 5: // release
|
||||
if (ReleaseMode) // exponential
|
||||
{
|
||||
const u32 off = InvExpOffsets[(Value >> 28) & 7];
|
||||
Value -= PsxRates[((ReleaseRate ^ 0x1f) * 4) - 0x18 + off + 32];
|
||||
}
|
||||
else
|
||||
{ // linear
|
||||
//Value-=PsxRates[((ReleaseRate^0x1f)*4)-0xc+32];
|
||||
if (ReleaseRate != 0x1f)
|
||||
Value -= (1 << (0x1f - ReleaseRate));
|
||||
}
|
||||
|
||||
if (Value <= 0)
|
||||
{
|
||||
Value = 0;
|
||||
Phase++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // release end
|
||||
Value = 0;
|
||||
break;
|
||||
|
||||
jNO_DEFAULT
|
||||
}
|
||||
|
||||
// returns true if the voice is active, or false if it's stopping.
|
||||
return Phase != 6;
|
||||
CachedPhases[PHASE_RELEASE].Decr = true;
|
||||
CachedPhases[PHASE_RELEASE].Exp = ReleaseMode;
|
||||
CachedPhases[PHASE_RELEASE].Shift = ReleaseShift;
|
||||
CachedPhases[PHASE_RELEASE].Step = -8;
|
||||
CachedPhases[PHASE_RELEASE].Target = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
bool V_ADSR::Calculate(int voiceidx)
|
||||
{
|
||||
pxAssume(Phase != PHASE_STOPPED);
|
||||
|
||||
#define VOLFLAG_REVERSE_PHASE (1ul << 0)
|
||||
#define VOLFLAG_DECREMENT (1ul << 1)
|
||||
#define VOLFLAG_EXPONENTIAL (1ul << 2)
|
||||
#define VOLFLAG_SLIDE_ENABLE (1ul << 3)
|
||||
auto& p = CachedPhases.at(Phase);
|
||||
|
||||
// maybe not correct for the "infinite" settings
|
||||
u32 counter_inc = 0x8000 >> std::max(0, p.Shift - 11);
|
||||
s16 level_inc = (s16)(p.Step << std::max(0, 11 - p.Shift));
|
||||
|
||||
if (p.Exp)
|
||||
{
|
||||
if (!p.Decr && Value > 0x6000)
|
||||
{
|
||||
counter_inc >>= 2;
|
||||
}
|
||||
|
||||
if (p.Decr)
|
||||
{
|
||||
level_inc = (s16)((level_inc * Value) >> 15);
|
||||
}
|
||||
}
|
||||
|
||||
counter_inc = std::max<u32>(1, counter_inc);
|
||||
Counter += counter_inc;
|
||||
|
||||
if (Counter >= 0x8000)
|
||||
{
|
||||
Counter = 0;
|
||||
Value = std::clamp<s32>(Value + level_inc, 0, INT16_MAX);
|
||||
}
|
||||
|
||||
// Stay in sustain until key off or silence
|
||||
if (Phase == PHASE_SUSTAIN)
|
||||
{
|
||||
return Value != 0;
|
||||
}
|
||||
|
||||
// Check if target is reached to advance phase
|
||||
if ((!p.Decr && Value >= p.Target) || (p.Decr && Value <= p.Target))
|
||||
{
|
||||
Phase++;
|
||||
}
|
||||
|
||||
// All phases done, stop the voice
|
||||
if (Phase > PHASE_RELEASE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void V_ADSR::Attack()
|
||||
{
|
||||
Phase = PHASE_ATTACK;
|
||||
Counter = 0;
|
||||
Value = 0;
|
||||
}
|
||||
|
||||
void V_ADSR::Release()
|
||||
{
|
||||
if (Phase != PHASE_STOPPED)
|
||||
{
|
||||
Phase = PHASE_RELEASE;
|
||||
Counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void V_VolumeSlide::RegSet(u16 src)
|
||||
{
|
||||
Reg_VOL = src;
|
||||
if (!Enable)
|
||||
{
|
||||
// Shift and sign extend;
|
||||
Value = (s16)(src << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void V_VolumeSlide::Update()
|
||||
{
|
||||
if (!(Mode & VOLFLAG_SLIDE_ENABLE))
|
||||
return;
|
||||
|
||||
// Volume slides use the same basic logic as ADSR, but simplified (single-stage
|
||||
// instead of multi-stage)
|
||||
|
||||
if (Increment == 0x7f)
|
||||
return;
|
||||
|
||||
s32 value = abs(Value);
|
||||
|
||||
if (Mode & VOLFLAG_DECREMENT)
|
||||
if (!Enable)
|
||||
{
|
||||
// Decrement
|
||||
|
||||
if (Mode & VOLFLAG_EXPONENTIAL)
|
||||
{
|
||||
const u32 off = InvExpOffsets[(value >> 28) & 7];
|
||||
value -= PsxRates[(Increment ^ 0x7f) - 0x1b + off + 32];
|
||||
}
|
||||
else
|
||||
value -= PsxRates[(Increment ^ 0x7f) - 0xf + 32];
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
value = 0;
|
||||
Mode = 0; // disable slide
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increment
|
||||
// Pseudo-exponential increments, as done by the SPU2 (really!)
|
||||
// Above 75% slides slow, below 75% slides fast. It's exponential, pseudo'ly speaking.
|
||||
|
||||
if ((Mode & VOLFLAG_EXPONENTIAL) && (value >= 0x60000000))
|
||||
value += PsxRates[(Increment ^ 0x7f) - 0x18 + 32];
|
||||
else
|
||||
// linear / Pseudo below 75% (they're the same)
|
||||
value += PsxRates[(Increment ^ 0x7f) - 0x10 + 32];
|
||||
|
||||
if (value < 0) // wrapped around the "top"?
|
||||
{
|
||||
value = 0x7fffffff;
|
||||
Mode = 0; // disable slide
|
||||
}
|
||||
}
|
||||
|
||||
Value = (Value < 0) ? -value : value;
|
||||
}
|
||||
|
|
|
@ -176,25 +176,29 @@ void SPU2::DoFullDump()
|
|||
Cores[c].Voices[v].Volume.DebugDump(dump, "");
|
||||
|
||||
fprintf(dump, " - ADSR Envelope: %x & %x\n"
|
||||
" - Ar: %x\n"
|
||||
" - Ash: %x\n"
|
||||
" - Ast: %x\n"
|
||||
" - Am: %x\n"
|
||||
" - Dr: %x\n"
|
||||
" - Dsh: %x\n"
|
||||
" - Sl: %x\n"
|
||||
" - Sr: %x\n"
|
||||
" - Ssh: %x\n"
|
||||
" - Sst: %x\n"
|
||||
" - Sm: %x\n"
|
||||
" - Rr: %x\n"
|
||||
" - Rsh: %x\n"
|
||||
" - Rm: %x\n"
|
||||
" - Phase: %x\n"
|
||||
" - Value: %x\n",
|
||||
Cores[c].Voices[v].ADSR.regADSR1,
|
||||
Cores[c].Voices[v].ADSR.regADSR2,
|
||||
Cores[c].Voices[v].ADSR.AttackRate,
|
||||
Cores[c].Voices[v].ADSR.AttackShift,
|
||||
Cores[c].Voices[v].ADSR.AttackStep,
|
||||
Cores[c].Voices[v].ADSR.AttackMode,
|
||||
Cores[c].Voices[v].ADSR.DecayRate,
|
||||
Cores[c].Voices[v].ADSR.DecayShift,
|
||||
Cores[c].Voices[v].ADSR.SustainLevel,
|
||||
Cores[c].Voices[v].ADSR.SustainRate,
|
||||
Cores[c].Voices[v].ADSR.SustainShift,
|
||||
Cores[c].Voices[v].ADSR.SustainStep,
|
||||
Cores[c].Voices[v].ADSR.SustainMode,
|
||||
Cores[c].Voices[v].ADSR.ReleaseRate,
|
||||
Cores[c].Voices[v].ADSR.ReleaseShift,
|
||||
Cores[c].Voices[v].ADSR.ReleaseMode,
|
||||
Cores[c].Voices[v].ADSR.Phase,
|
||||
Cores[c].Voices[v].ADSR.Value);
|
||||
|
|
|
@ -287,6 +287,11 @@ static __forceinline s32 ApplyVolume(s32 data, s32 volume)
|
|||
return MulShr32(data << 1, volume);
|
||||
}
|
||||
|
||||
static __forceinline s32 ApplyVolume16(s32 data, s32 volume)
|
||||
{
|
||||
return (volume * data) >> 15;
|
||||
}
|
||||
|
||||
static __forceinline StereoOut32 ApplyVolume(const StereoOut32& data, const V_VolumeLR& volume)
|
||||
{
|
||||
return StereoOut32(
|
||||
|
@ -323,13 +328,13 @@ static __forceinline void CalculateADSR(V_Core& thiscore, uint voiceidx)
|
|||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
|
||||
if (vc.ADSR.Phase == 0)
|
||||
if (vc.ADSR.Phase == V_ADSR::PHASE_STOPPED)
|
||||
{
|
||||
vc.ADSR.Value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vc.ADSR.Calculate())
|
||||
if (!vc.ADSR.Calculate(thiscore.Index | (voiceidx << 1)))
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
|
@ -465,7 +470,7 @@ static __forceinline StereoOut32 MixVoice(uint coreidx, uint voiceidx)
|
|||
StereoOut32 voiceOut(0, 0);
|
||||
s32 Value = 0;
|
||||
|
||||
if (vc.ADSR.Phase > 0)
|
||||
if (vc.ADSR.Phase > V_ADSR::PHASE_STOPPED)
|
||||
{
|
||||
if (vc.Noise)
|
||||
Value = GetNoiseValues(thiscore);
|
||||
|
@ -480,7 +485,7 @@ static __forceinline StereoOut32 MixVoice(uint coreidx, uint voiceidx)
|
|||
// use a full 64-bit multiply/result here.
|
||||
|
||||
CalculateADSR(thiscore, voiceidx);
|
||||
Value = ApplyVolume(Value, vc.ADSR.Value);
|
||||
Value = ApplyVolume16(Value, vc.ADSR.Value);
|
||||
vc.OutX = Value;
|
||||
|
||||
if (IsDevBuild)
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
PVCP(c, v, Pitch), \
|
||||
PVCP(c, v, ADSR.regADSR1), \
|
||||
PVCP(c, v, ADSR.regADSR2), \
|
||||
PVCP(c, v, ADSR.Value) + 1, \
|
||||
PVCP(c, v, ADSR.Value), \
|
||||
PVCP(c, v, Volume.Left.Value) + 1, \
|
||||
PVCP(c, v, Volume.Right.Value) + 1
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "SPU2/SndOut.h"
|
||||
#include "SPU2/Global.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SPU2 Register Table LUT
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -122,24 +124,49 @@ struct V_ADSR
|
|||
|
||||
struct
|
||||
{
|
||||
u32 SustainLevel : 4,
|
||||
DecayRate : 4,
|
||||
AttackRate : 7,
|
||||
AttackMode : 1, // 0 for linear (+lin), 1 for pseudo exponential (+exp)
|
||||
|
||||
ReleaseRate : 5,
|
||||
ReleaseMode : 1, // 0 for linear (-lin), 1 for exponential (-exp)
|
||||
SustainRate : 7,
|
||||
SustainMode : 3; // 0 = +lin, 1 = -lin, 2 = +exp, 3 = -exp
|
||||
u32 SustainLevel : 4;
|
||||
u32 DecayShift : 4;
|
||||
u32 AttackStep : 2;
|
||||
u32 AttackShift : 5;
|
||||
u32 AttackMode : 1;
|
||||
u32 ReleaseShift : 5;
|
||||
u32 ReleaseMode : 1;
|
||||
u32 SustainStep : 2;
|
||||
u32 SustainShift : 5;
|
||||
u32 : 1;
|
||||
u32 SustainDir : 1;
|
||||
u32 SustainMode : 1;
|
||||
};
|
||||
};
|
||||
|
||||
s32 Value; // Ranges from 0 to 0x7fffffff (signed values are clamped to 0) [Reg_ENVX]
|
||||
u8 Phase; // monitors current phase of ADSR envelope
|
||||
bool Releasing; // Ready To Release, triggered by Voice.Stop();
|
||||
static constexpr int ADSR_PHASES = 5;
|
||||
|
||||
static constexpr int PHASE_STOPPED = 0;
|
||||
static constexpr int PHASE_ATTACK = 1;
|
||||
static constexpr int PHASE_DECAY = 2;
|
||||
static constexpr int PHASE_SUSTAIN = 3;
|
||||
static constexpr int PHASE_RELEASE = 4;
|
||||
|
||||
struct CachedADSR
|
||||
{
|
||||
bool Decr;
|
||||
bool Exp;
|
||||
u8 Shift;
|
||||
s8 Step;
|
||||
s32 Target;
|
||||
};
|
||||
|
||||
std::array<CachedADSR, ADSR_PHASES> CachedPhases;
|
||||
|
||||
u32 Counter;
|
||||
s32 Value; // Ranges from 0 to 0x7fff (signed values are clamped to 0) [Reg_ENVX]
|
||||
u8 Phase; // monitors current phase of ADSR envelope
|
||||
|
||||
public:
|
||||
bool Calculate();
|
||||
void UpdateCache();
|
||||
bool Calculate(int voiceidx);
|
||||
void Attack();
|
||||
void Release();
|
||||
};
|
||||
|
||||
|
||||
|
@ -359,34 +386,34 @@ struct V_Core
|
|||
V_CoreGates WetGate;
|
||||
|
||||
V_VolumeSlideLR MasterVol; // Master Volume
|
||||
V_VolumeLR ExtVol; // Volume for External Data Input
|
||||
V_VolumeLR InpVol; // Volume for Sound Data Input
|
||||
V_VolumeLR FxVol; // Volume for Output from Effects
|
||||
V_VolumeLR ExtVol; // Volume for External Data Input
|
||||
V_VolumeLR InpVol; // Volume for Sound Data Input
|
||||
V_VolumeLR FxVol; // Volume for Output from Effects
|
||||
|
||||
V_Voice Voices[NumVoices];
|
||||
|
||||
u32 IRQA; // Interrupt Address
|
||||
u32 TSA; // DMA Transfer Start Address
|
||||
u32 TSA; // DMA Transfer Start Address
|
||||
u32 ActiveTSA; // Active DMA TSA - Required for NFL 2k5 which overwrites it mid transfer
|
||||
|
||||
bool IRQEnable; // Interrupt Enable
|
||||
bool FxEnable; // Effect Enable
|
||||
bool Mute; // Mute
|
||||
bool FxEnable; // Effect Enable
|
||||
bool Mute; // Mute
|
||||
bool AdmaInProgress;
|
||||
|
||||
s8 DMABits; // DMA related?
|
||||
u8 NoiseClk; // Noise Clock
|
||||
u32 NoiseCnt; // Noise Counter
|
||||
u32 NoiseOut; // Noise Output
|
||||
u16 AutoDMACtrl; // AutoDMA Status
|
||||
s32 DMAICounter; // DMA Interrupt Counter
|
||||
u32 LastClock; // DMA Interrupt Clock Cycle Counter
|
||||
s8 DMABits; // DMA related?
|
||||
u8 NoiseClk; // Noise Clock
|
||||
u32 NoiseCnt; // Noise Counter
|
||||
u32 NoiseOut; // Noise Output
|
||||
u16 AutoDMACtrl; // AutoDMA Status
|
||||
s32 DMAICounter; // DMA Interrupt Counter
|
||||
u32 LastClock; // DMA Interrupt Clock Cycle Counter
|
||||
u32 InputDataLeft; // Input Buffer
|
||||
u32 InputDataTransferred; // Used for simulating MADR increase (GTA VC)
|
||||
u32 InputPosWrite;
|
||||
u32 InputDataProgress;
|
||||
|
||||
V_Reverb Revb; // Reverb Registers
|
||||
V_Reverb Revb; // Reverb Registers
|
||||
|
||||
s32 RevbDownBuf[2][64]; // Downsample buffer for reverb, one for each channel
|
||||
s32 RevbUpBuf[2][64]; // Upsample buffer for reverb, one for each channel
|
||||
|
|
|
@ -207,6 +207,7 @@ void V_Core::Init(int index)
|
|||
Voices[v].Volume = V_VolumeSlideLR(0, 0); // V_VolumeSlideLR::Max;
|
||||
Voices[v].SCurrent = 28;
|
||||
|
||||
Voices[v].ADSR.Counter = 0;
|
||||
Voices[v].ADSR.Value = 0;
|
||||
Voices[v].ADSR.Phase = 0;
|
||||
Voices[v].Pitch = 0x3FFF;
|
||||
|
@ -236,7 +237,7 @@ void V_Voice::Start()
|
|||
void V_Voice::Stop()
|
||||
{
|
||||
ADSR.Value = 0;
|
||||
ADSR.Phase = 0;
|
||||
ADSR.Phase = V_ADSR::PHASE_STOPPED;
|
||||
}
|
||||
|
||||
uint TickInterval = 768;
|
||||
|
@ -255,9 +256,7 @@ __forceinline bool StartQueuedVoice(uint coreidx, uint voiceidx)
|
|||
vc.StartA = (vc.StartA + 0xFFFF8) + 0x8;
|
||||
}
|
||||
|
||||
vc.ADSR.Releasing = false;
|
||||
vc.ADSR.Value = 1;
|
||||
vc.ADSR.Phase = 1;
|
||||
vc.ADSR.Attack();
|
||||
vc.SCurrent = 28;
|
||||
vc.LoopMode = 0;
|
||||
|
||||
|
@ -554,16 +553,18 @@ void V_Core::WriteRegPS1(u32 mem, u16 value)
|
|||
|
||||
case 0x8: // ADSR1 (Envelope)
|
||||
Voices[voice].ADSR.regADSR1 = value;
|
||||
Voices[voice].ADSR.UpdateCache();
|
||||
//ConLog("voice %x regADSR1 write: %x\n", voice, Voices[voice].ADSR.regADSR1);
|
||||
break;
|
||||
|
||||
case 0xa: // ADSR2 (Envelope)
|
||||
Voices[voice].ADSR.regADSR2 = value;
|
||||
Voices[voice].ADSR.UpdateCache();
|
||||
//ConLog("voice %x regADSR2 write: %x\n", voice, Voices[voice].ADSR.regADSR2);
|
||||
break;
|
||||
case 0xc: // Voice 0..23 ADSR Current Volume
|
||||
// not commonly set by games
|
||||
Voices[voice].ADSR.Value = value * 0x10001U;
|
||||
Voices[voice].ADSR.Value = value;
|
||||
if (SPU2::MsgToConsole())
|
||||
SPU2::ConLog("voice %x ADSR.Value write: %x\n", voice, Voices[voice].ADSR.Value);
|
||||
break;
|
||||
|
@ -879,7 +880,7 @@ u16 V_Core::ReadRegPS1(u32 mem)
|
|||
value = Voices[voice].ADSR.regADSR2;
|
||||
break;
|
||||
case 0xc: // Voice 0..23 ADSR Current Volume
|
||||
value = Voices[voice].ADSR.Value >> 16; // no clue
|
||||
value = Voices[voice].ADSR.Value;
|
||||
//if (value != 0) ConLog("voice %d read ADSR.Value result = %x\n", voice, value);
|
||||
break;
|
||||
case 0xe:
|
||||
|
@ -1035,22 +1036,20 @@ static void RegWrite_VoiceParams(u16 value)
|
|||
|
||||
case 3: // ADSR1 (Envelope)
|
||||
thisvoice.ADSR.regADSR1 = value;
|
||||
thisvoice.ADSR.UpdateCache();
|
||||
break;
|
||||
|
||||
case 4: // ADSR2 (Envelope)
|
||||
thisvoice.ADSR.regADSR2 = value;
|
||||
thisvoice.ADSR.UpdateCache();
|
||||
break;
|
||||
|
||||
// REG_VP_ENVX, REG_VP_VOLXL and REG_VP_VOLXR have been confirmed to not be allowed to be written to, so code has been commented out.
|
||||
// REG_VP_ENVX, REG_VP_VOLXL and REG_VP_VOLXR are all writable, only ENVX has any effect when written to.
|
||||
// Colin McRae Rally 2005 triggers case 5 (ADSR), but it doesn't produce issues enabled or disabled.
|
||||
|
||||
case 5:
|
||||
// [Air] : Mysterious ADSR set code. Too bad none of my games ever use it.
|
||||
// (as usual... )
|
||||
//thisvoice.ADSR.Value = (value << 16) | value;
|
||||
//ConLog("* SPU2: Mysterious ADSR Volume Set to 0x%x\n", value);
|
||||
thisvoice.ADSR.Value = value;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
//thisvoice.Volume.Left.RegSet(value);
|
||||
break;
|
||||
|
@ -1863,7 +1862,7 @@ void StopVoices(int core, u32 value)
|
|||
continue;
|
||||
}
|
||||
|
||||
Cores[core].Voices[vc].ADSR.Releasing = true;
|
||||
Cores[core].Voices[vc].ADSR.Release();
|
||||
if (SPU2::MsgKeyOnOff())
|
||||
SPU2::ConLog("* SPU2: KeyOff: Core %d; Voice %d.\n", core, vc);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ enum class FreezeAction
|
|||
// [SAVEVERSION+]
|
||||
// This informs the auto updater that the users savestates will be invalidated.
|
||||
|
||||
static const u32 g_SaveVersion = (0x9A43 << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A44 << 16) | 0x0000;
|
||||
|
||||
|
||||
// the freezing data between submodules and core
|
||||
|
|
Loading…
Reference in New Issue