mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
183 lines
3.5 KiB
C++
183 lines
3.5 KiB
C++
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "SPU2/defs.h"
|
|
|
|
#include "common/Assertions.h"
|
|
|
|
static constexpr s32 ADSR_MAX_VOL = 0x7fff;
|
|
|
|
void V_ADSR::UpdateCache()
|
|
{
|
|
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;
|
|
|
|
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;
|
|
|
|
CachedPhases[PHASE_SUSTAIN].Decr = SustainDir;
|
|
CachedPhases[PHASE_SUSTAIN].Exp = SustainMode;
|
|
CachedPhases[PHASE_SUSTAIN].Shift = SustainShift;
|
|
CachedPhases[PHASE_SUSTAIN].Step = 7 - SustainStep;
|
|
|
|
if (CachedPhases[PHASE_SUSTAIN].Decr)
|
|
CachedPhases[PHASE_SUSTAIN].Step = ~CachedPhases[PHASE_SUSTAIN].Step;
|
|
|
|
CachedPhases[PHASE_SUSTAIN].Target = 0;
|
|
|
|
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);
|
|
|
|
auto& p = CachedPhases.at(Phase);
|
|
|
|
// maybe not correct for the "infinite" settings
|
|
u32 counter_inc = 0x8000 >> std::max(0, p.Shift - 11);
|
|
s32 level_inc = 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)
|
|
{
|
|
Value = SignExtend16(src << 1);
|
|
}
|
|
}
|
|
|
|
void V_VolumeSlide::Update()
|
|
{
|
|
if (!Enable)
|
|
return;
|
|
|
|
s32 step_size = 7 - Step;
|
|
|
|
if (Decr)
|
|
{
|
|
step_size = ~step_size;
|
|
}
|
|
|
|
u32 counter_inc = 0x8000 >> std::max(0, Shift - 11);
|
|
s32 level_inc = step_size << std::max(0, 11 - Shift);
|
|
|
|
if (Exp)
|
|
{
|
|
if (!Decr && Value > 0x6000)
|
|
{
|
|
counter_inc >>= 2;
|
|
}
|
|
|
|
if (Decr)
|
|
{
|
|
level_inc = (s16)((level_inc * Value) >> 15);
|
|
}
|
|
}
|
|
|
|
// Allow counter_inc to be zero only in when all bits
|
|
// of the rate field are set
|
|
if (Step != 3 && Shift != 0x1f)
|
|
{
|
|
counter_inc = std::max<u32>(1, counter_inc);
|
|
}
|
|
Counter += counter_inc;
|
|
|
|
// If negative phase "increase" to -0x8000 or "decrease" towards 0
|
|
// Unless in Exp + Decr modes
|
|
if (!(Exp && Decr))
|
|
{
|
|
level_inc = Phase ? -level_inc : level_inc;
|
|
}
|
|
|
|
if (Counter >= 0x8000)
|
|
{
|
|
Counter = 0;
|
|
|
|
if (!Decr)
|
|
{
|
|
Value = std::clamp<s32>(Value + level_inc, INT16_MIN, INT16_MAX);
|
|
}
|
|
else
|
|
{
|
|
s32 low = Phase ? INT16_MIN : 0;
|
|
s32 high = Phase ? 0 : INT16_MAX;
|
|
if (Exp)
|
|
{
|
|
low = 0;
|
|
high = INT16_MAX;
|
|
}
|
|
Value = std::clamp<s32>(Value + level_inc, low, high);
|
|
}
|
|
}
|
|
}
|