Skip to content

Commit 8dd6db6

Browse files
authored
Merge pull request #1572 from johnbaumann/spu_rework_again
More enums, some tidy on registers.cc, dr. hell adsr
2 parents e8f45b6 + 7284bb9 commit 8dd6db6

File tree

5 files changed

+287
-174
lines changed

5 files changed

+287
-174
lines changed

src/spu/adsr.cc

Lines changed: 128 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -35,145 +35,198 @@
3535

3636
#include "spu/adsr.h"
3737

38+
#include <stdint.h>
39+
40+
#include <utility>
41+
3842
#include "spu/externals.h"
3943
#include "spu/interface.h"
4044

41-
enum ADSRState : int32_t {
42-
Attack = 0,
43-
Decay = 1,
44-
Sustain = 2,
45-
Release = 3,
45+
namespace EnvelopeTables {
46+
// Generate ADSR envelope tables at compile time with some magic(thanks Nic)
47+
template <std::size_t N>
48+
struct Table {
49+
int32_t data[N];
4650
};
4751

52+
template <std::size_t N, typename Generator, std::size_t... Is>
53+
constexpr Table<N> generateTable(std::index_sequence<Is...>) {
54+
return {{Generator::calculateValue(Is)...}};
55+
}
56+
57+
template <std::size_t N, typename Generator>
58+
constexpr Table<N> generateTable() {
59+
return generateTable<N, Generator>(std::make_index_sequence<128>{});
60+
}
61+
62+
struct DenominatorGenerator {
63+
static constexpr int32_t calculateValue(std::size_t rate) { return (rate < 48) ? 1 : (1 << ((rate >> 2) - 11)); }
64+
};
65+
66+
struct NumeratorIncreaseGenerator {
67+
static constexpr int32_t calculateValue(std::size_t rate) {
68+
return (rate < 48) ? (7 - (rate & 3)) << (11 - (rate >> 2)) : (7 - (rate & 3));
69+
}
70+
};
71+
72+
struct NumeratorDecreaseGenerator {
73+
static constexpr int32_t calculateValue(std::size_t rate) {
74+
return (rate < 48) ? (-8 + (rate & 3)) << (11 - (rate >> 2)) : (-8 + (rate & 3));
75+
}
76+
};
77+
78+
constexpr auto denominator = generateTable<128, DenominatorGenerator>();
79+
constexpr auto numerator_increase = generateTable<128, NumeratorIncreaseGenerator>();
80+
constexpr auto numerator_decrease = generateTable<128, NumeratorDecreaseGenerator>();
81+
} // namespace EnvelopeTables
82+
4883
inline int PCSX::SPU::ADSR::Attack(SPUCHAN *ch) {
49-
uint32_t disp;
84+
int rate = ch->ADSRX.get<exAttackRate>().value;
5085
int32_t EnvelopeVol = ch->ADSRX.get<exEnvelopeVol>().value;
86+
int32_t EnvelopeVolF = ch->ADSRX.get<exEnvelopeVolF>().value;
87+
const int32_t attack_mode_exp = ch->ADSRX.get<exAttackModeExp>().value;
5188

52-
if (ch->ADSRX.get<exAttackModeExp>().value && EnvelopeVol >= 0x60000000) {
53-
// Exponential Increase
54-
disp = -0x18 + 32;
55-
} else {
56-
// Linear Increase
57-
disp = -0x10 + 32;
89+
// Exponential increase
90+
if (attack_mode_exp && EnvelopeVol >= 0x6000) {
91+
rate += 8;
5892
}
5993

60-
EnvelopeVol += m_table[ch->ADSRX.get<exAttackRate>().value + disp];
94+
EnvelopeVolF++;
95+
if (EnvelopeVolF >= EnvelopeTables::denominator.data[rate]) {
96+
EnvelopeVolF = 0;
97+
EnvelopeVol += EnvelopeTables::numerator_increase.data[rate];
98+
}
6199

62-
if (EnvelopeVol < 0) {
63-
EnvelopeVol = 0x7FFFFFFF;
100+
if (EnvelopeVol >= 32767L) {
101+
EnvelopeVol = 32767L;
64102
ch->ADSRX.get<exState>().value = ADSRState::Decay;
65103
}
66104

67105
ch->ADSRX.get<exEnvelopeVol>().value = EnvelopeVol;
68-
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 21);
106+
ch->ADSRX.get<exEnvelopeVolF>().value = EnvelopeVolF;
107+
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 5);
108+
69109
return EnvelopeVol;
70110
}
71111

72112
inline int PCSX::SPU::ADSR::Decay(SPUCHAN *ch) {
73-
uint32_t disp;
113+
const int rate = ch->ADSRX.get<exDecayRate>().value * 4;
74114
int32_t EnvelopeVol = ch->ADSRX.get<exEnvelopeVol>().value;
115+
int32_t EnvelopeVolF = ch->ADSRX.get<exEnvelopeVolF>().value;
116+
const int32_t release_mode_exp = ch->ADSRX.get<exReleaseModeExp>().value;
75117

76-
disp = m_tableDisp[(EnvelopeVol >> 28) & 0x7];
77-
EnvelopeVol -= m_table[ch->ADSRX.get<exDecayRate>().value + disp];
118+
EnvelopeVolF++;
119+
if (EnvelopeVolF >= EnvelopeTables::denominator.data[rate]) {
120+
EnvelopeVolF = 0;
78121

79-
if (EnvelopeVol < 0) EnvelopeVol = 0;
122+
if (release_mode_exp) {
123+
// Exponential decrease
124+
EnvelopeVol += (EnvelopeTables::numerator_decrease.data[rate] * EnvelopeVol) >> 15;
125+
} else {
126+
EnvelopeVol += EnvelopeTables::numerator_decrease.data[rate];
127+
}
128+
}
129+
130+
if (EnvelopeVol < 0) {
131+
EnvelopeVol = 0;
132+
}
80133

81-
// FF7 Cursor / Vagrant Story footsteps - use Neill's 4-bit accuracy
82-
if ((EnvelopeVol & 0x78000000) <= ch->ADSRX.get<exSustainLevel>().value) {
134+
if (((EnvelopeVol >> 11) & 0xf) <= ch->ADSRX.get<exSustainLevel>().value) {
83135
ch->ADSRX.get<exState>().value = ADSRState::Sustain;
84136
}
85137

86138
ch->ADSRX.get<exEnvelopeVol>().value = EnvelopeVol;
87-
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 21);
139+
ch->ADSRX.get<exEnvelopeVolF>().value = EnvelopeVolF;
140+
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 5);
141+
88142
return EnvelopeVol;
89143
}
90144

91145
inline int PCSX::SPU::ADSR::Sustain(SPUCHAN *ch) {
92-
uint32_t disp;
146+
int rate = ch->ADSRX.get<exSustainRate>().value;
93147
int32_t EnvelopeVol = ch->ADSRX.get<exEnvelopeVol>().value;
148+
int32_t EnvelopeVolF = ch->ADSRX.get<exEnvelopeVolF>().value;
149+
const int32_t sustain_mode_exp = ch->ADSRX.get<exSustainModeExp>().value;
150+
const int32_t sustain_increase = ch->ADSRX.get<exSustainIncrease>().value;
151+
152+
if (sustain_increase) {
153+
// Exponential increase
154+
if (sustain_mode_exp && (EnvelopeVol >= 0x6000)) {
155+
rate += 8;
156+
}
94157

95-
if (ch->ADSRX.get<exSustainIncrease>().value) {
96-
disp = -0x10 + 32;
97-
if (ch->ADSRX.get<exSustainModeExp>().value) {
98-
if (EnvelopeVol >= 0x60000000) disp = -0x18 + 32;
158+
EnvelopeVolF++;
159+
if (EnvelopeVolF >= EnvelopeTables::denominator.data[rate]) {
160+
EnvelopeVolF = 0;
161+
EnvelopeVol += EnvelopeTables::numerator_increase.data[rate];
99162
}
100-
EnvelopeVol += m_table[ch->ADSRX.get<exSustainRate>().value + disp];
101163

102-
if (EnvelopeVol < 0) {
103-
EnvelopeVol = 0x7FFFFFFF;
164+
if (EnvelopeVol > 32767L) {
165+
EnvelopeVol = 32767L;
104166
}
167+
105168
} else {
106-
if (ch->ADSRX.get<exSustainModeExp>().value) {
107-
disp = m_tableDisp[((EnvelopeVol >> 28) & 0x7) + 8];
108-
} else {
109-
disp = -0x0F + 32;
169+
EnvelopeVolF++;
170+
if (EnvelopeVolF >= EnvelopeTables::denominator.data[rate]) {
171+
EnvelopeVolF = 0;
172+
173+
// Exponential decrease
174+
if (sustain_mode_exp) {
175+
EnvelopeVol += (EnvelopeTables::numerator_decrease.data[rate] * EnvelopeVol) >> 15;
176+
} else {
177+
EnvelopeVol += EnvelopeTables::numerator_decrease.data[rate];
178+
}
110179
}
111-
EnvelopeVol -= m_table[ch->ADSRX.get<exSustainRate>().value + disp];
112180

113-
if (EnvelopeVol < 0) {
181+
if (EnvelopeVol < 0L) {
114182
EnvelopeVol = 0;
115183
}
116184
}
185+
117186
ch->ADSRX.get<exEnvelopeVol>().value = EnvelopeVol;
118-
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 21);
187+
ch->ADSRX.get<exEnvelopeVolF>().value = EnvelopeVolF;
188+
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 5);
189+
119190
return EnvelopeVol;
120191
}
121192

122193
inline int PCSX::SPU::ADSR::Release(SPUCHAN *ch) {
123-
uint32_t disp;
194+
int rate = ch->ADSRX.get<exReleaseRate>().value * 4;
124195
int32_t EnvelopeVol = ch->ADSRX.get<exEnvelopeVol>().value;
196+
int32_t EnvelopeVolF = ch->ADSRX.get<exEnvelopeVolF>().value;
197+
const int32_t release_mode_exp = ch->ADSRX.get<exReleaseModeExp>().value;
125198

126-
if (ch->ADSRX.get<exReleaseModeExp>().value) {
127-
disp = m_tableDisp[(EnvelopeVol >> 28) & 0x7];
128-
} else {
129-
disp = -0x0C + 32;
199+
EnvelopeVolF++;
200+
if (EnvelopeVolF >= EnvelopeTables::denominator.data[rate]) {
201+
EnvelopeVolF = 0;
202+
203+
// Exponential decrease
204+
if (release_mode_exp) {
205+
EnvelopeVol += (EnvelopeTables::numerator_decrease.data[rate] * EnvelopeVol) >> 15;
206+
} else {
207+
EnvelopeVol += EnvelopeTables::numerator_decrease.data[rate];
208+
}
130209
}
131-
EnvelopeVol -= m_table[ch->ADSRX.get<exReleaseRate>().value + disp];
132210

133-
if (EnvelopeVol < 0) {
211+
if (EnvelopeVol < 0L) {
212+
ch->ADSRX.get<exState>().value = ADSRState::Stopped;
134213
EnvelopeVol = 0;
135214
ch->data.get<Chan::On>().value = false;
136215
}
137216

138217
ch->ADSRX.get<exEnvelopeVol>().value = EnvelopeVol;
139-
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 21);
140-
return EnvelopeVol;
141-
}
142-
143-
// Init ADSR
144-
PCSX::SPU::ADSR::Table::Table() {
145-
memset(m_table, 0,
146-
sizeof(uint32_t) * 160); // build the rate table according to Neill's rules (see at bottom of file)
147-
148-
uint32_t r = 3;
149-
uint32_t rs = 1;
150-
uint32_t rd = 0;
151-
152-
// we start at pos 32 with the real values... everything before is 0
153-
for (int i = 32; i < 160; i++) {
154-
if (r < 0x3FFFFFFF) {
155-
r += rs;
156-
rd++;
157-
158-
if (rd == 5) {
159-
rd = 1;
160-
rs *= 2;
161-
}
162-
}
163-
164-
if (r > 0x3FFFFFFF) {
165-
r = 0x3FFFFFFF;
166-
}
218+
ch->ADSRX.get<exEnvelopeVolF>().value = EnvelopeVolF;
219+
ch->ADSRX.get<exVolume>().value = (EnvelopeVol >>= 5);
167220

168-
m_table[i] = r;
169-
}
221+
return EnvelopeVol;
170222
}
171223

172224
void PCSX::SPU::ADSR::start(SPUCHAN *pChannel) // MIX ADSR
173225
{
174226
pChannel->ADSRX.get<exVolume>().value = 1; // and init some adsr vars
175227
pChannel->ADSRX.get<exState>().value = ADSRState::Attack;
176228
pChannel->ADSRX.get<exEnvelopeVol>().value = 0;
229+
pChannel->ADSRX.get<exEnvelopeVolF>().value = 0;
177230
}
178231

179232
int PCSX::SPU::ADSR::mix(SPUCHAN *ch) {

src/spu/adsr.h

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,16 @@ class ADSR {
3939
int mix(SPUCHAN* pChannel);
4040

4141
private:
42-
static inline const uint32_t m_tableDisp[] = {
43-
-0x18 + 0 + 32, -0x18 + 4 + 32, -0x18 + 6 + 32, -0x18 + 8 + 32, // release/decay
44-
-0x18 + 9 + 32, -0x18 + 10 + 32, -0x18 + 11 + 32, -0x18 + 12 + 32,
45-
46-
-0x1B + 0 + 32, -0x1B + 4 + 32, -0x1B + 6 + 32, -0x1B + 8 + 32, // sustain
47-
-0x1B + 9 + 32, -0x1B + 10 + 32, -0x1B + 11 + 32, -0x1B + 12 + 32,
42+
struct ADSRState {
43+
enum : int32_t {
44+
Attack = 0,
45+
Decay = 1,
46+
Sustain = 2,
47+
Release = 3,
48+
Stopped = 4,
49+
};
4850
};
4951

50-
class Table {
51-
public:
52-
Table();
53-
const uint32_t& operator[](size_t index) const { return m_table[index]; }
54-
55-
private:
56-
uint32_t m_table[160];
57-
};
58-
59-
const Table m_table;
60-
6152
int Attack(SPUCHAN* ch);
6253
int Decay(SPUCHAN* ch);
6354
int Sustain(SPUCHAN* ch);

src/spu/interface.h

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,36 +83,62 @@ class impl final : public SPUInterface {
8383
void waitForGoal(uint32_t goal) override { m_audioOut.waitForGoal(goal); }
8484

8585
private:
86+
struct ADSRFlags {
87+
enum : uint16_t {
88+
AttackMode = 1 << 15, // 15 0=Linear, 1=Exponential
89+
AttackShiftMask = 0x7c00, // 14-10 0..1Fh = Fast..Slow
90+
AttackStepMask = 0x300, // 9-8 0..3 = "+7,+6,+5,+4"
91+
DecayShiftMask = 0xf0, // 7-4 0..0Fh = Fast..Slow
92+
SustainLevelMask = 0xf, // 3-0 0..0Fh ;Level=(N+1)*800h
93+
// Flags for upper 16-bits of reg, shifted right 16-bits
94+
SustainMode = 1 << 15, // 31 0=Linear, 1=Exponential
95+
SustainDirection = 1 << 14, // 30 0=Increase, 1=Decrease (until Key OFF flag)
96+
SustainShiftMask = 0x1f00, // 28-24 0..1Fh = Fast..Slow
97+
SustainStepMask = 0xc0, // 23-22 0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
98+
ReleaseMode = 1 << 5, // 21 0=Linear, 1=Exponential
99+
ReleaseShiftMask = 0x1f // 20-16 0..1Fh = Fast..Slow
100+
};
101+
};
102+
86103
struct ControlFlags {
87104
enum : uint16_t {
88-
CDAudioEnable = 1 << 0, // 0 0x0001 (0=Off, 1=On) (for CD-DA and XA-ADPCM)
89-
ExternalAudioEnable = 1 << 1, // 1 0x0002 (0=Off, 1=On)
90-
CDReverbEnable = 1 << 2, // 2 0x0004 (0=Off, 1=On) (for CD-DA and XA-ADPCM)
91-
ExternalReverbEnable = 1 << 3, // 3 0x0008 (0=Off, 1=On)
92-
RAMTransferMode = 0x0030, // 5-4 0x0030 RAM Transfer Mode (0=Stop, 1=ManualWrite, 2=DMAwrite, 3=DMAread)
93-
IRQEnable = 1 << 6, // 6 0x0040 (0=Disabled/Acknowledge, 1=Enabled; only when Bit15=1)
94-
ReverbMasterEnable = 1 << 7, // 7 0x0080 (0=Disabled, 1=Enabled)
95-
NoiseStep = 0x0300, // 9-8 0x0300 Noise Frequency Step (0..03h = Step "4,5,6,7")
96-
NoiseShift = 0x3c00, // 13-10 0x3c00 Noise Frequency Shift (0..0Fh = Low .. High Frequency)
97-
Mute = 1 << 14, // 14 0x4000 (0=Mute, 1=Unmute)
98-
Enable = 1 << 15 // 15 0x8000 (0=Off, 1=On)
105+
CDAudioEnable = 1 << 0, // 0 0=Off, 1=On (for CD-DA and XA-ADPCM)
106+
ExternalAudioEnable = 1 << 1, // 1 0=Off, 1=On
107+
CDReverbEnable = 1 << 2, // 20=Off, 1=On (for CD-DA and XA-ADPCM)
108+
ExternalReverbEnable = 1 << 3, // 3 0=Off, 1=On
109+
RAMTransferModeMask = 0x0030, // 5-4 0=Stop, 1=ManualWrite, 2=DMAwrite, 3=DMAread
110+
IRQEnable = 1 << 6, // 6 0=Disabled/Acknowledge, 1=Enabled; only when Bit15=1
111+
ReverbMasterEnable = 1 << 7, // 7 0=Disabled, 1=Enabled
112+
NoiseStepMask = 0x0300, // 9-8 0..03h = Step "4,5,6,7"
113+
NoiseShiftMask = 0x3c00, // 13-10 0..0Fh = Low .. High Frequency
114+
Mute = 1 << 14, // 14 0=Mute, 1=Unmute
115+
Enable = 1 << 15 // 15 0=Off, 1=On
99116
};
100117
};
101118

102119
struct StatusFlags {
103120
enum : uint16_t {
104-
// 5-0 Current SPU Mode(same as SPUCNT.Bit5 - 0, but, applied a bit delayed)
105-
CDAudioEnable = 1 << 0, // 0 0x0001 (0=Off, 1=On) (for CD-DA and XA-ADPCM)
106-
ExternalAudioEnable = 1 << 1, // 1 0x0002 (0=Off, 1=On)
107-
CDReverbEnable = 1 << 2, // 2 0x0004 (0=Off, 1=On) (for CD-DA and XA-ADPCM)
108-
ExternalReverbEnable = 1 << 3, // 3 0x0008 (0=Off, 1=On)
109-
RAMTransferMode = 0x0030, // 5-4 0x0030 RAM Transfer Mode (0=Stop, 1=ManualWrite, 2=DMAwrite, 3=DMAread)
110-
IRQFlag = 1 << 6, // 6 0x0040 IRQ9 Flag (0=No, 1=Interrupt Request)
121+
SPUModeMask = 0x3f, // 5-0 Current SPU Mode(same as SPUCNT.Bit5 - 0, but, applied a bit delayed)
122+
IRQFlag = 1 << 6, // 6 IRQ9 Flag (0=No, 1=Interrupt Request)
111123
DMARWRequest = 1 << 7, // 7 Data Transfer DMA Read/Write Request seems to be same as SPUCNT.Bit5
112124
DMAWriteRequest = 1 << 8, // 8 Data Transfer DMA Write Request (0=No, 1=Yes)
113125
DMAReadRequest = 1 << 9, // 9 Data Transfer DMA Read Request (0=No, 1=Yes)
114126
DMABusy = 1 << 10, // 10 Data Transfer Busy Flag (0=Ready, 1=Busy)
115-
CBIndex = 11 << 11, // 11 Writing to First/Second half of Capture Buffers
127+
CBIndex = 11 << 11, // 11 Writing to First/Second half of Capture Buffers (0=First, 1=Second)
128+
// 15-12 Unknown/Unused (seems to be usually zero)
129+
};
130+
};
131+
132+
struct VolumeFlags {
133+
enum : uint16_t {
134+
VolumeMode = 1 << 15, // 15 1=Sweep Mode
135+
SweepMode = 1 << 14, // 14 0=Linear, 1=Exponential
136+
SweepDirection = 1 << 13, // 13 0=Increase, 1=Decrease
137+
SweepPhase = 1 << 12, // 12 0=Positive, 1=Negative
138+
Unknown = 0xf80, // 7-11 Not used? (should be zero)
139+
SweepShiftMask = 0x7c, // 6-2 0..1Fh = Fast..Slow
140+
SweepStepMask = 0x3 // 1-0 0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
141+
116142
};
117143
};
118144

0 commit comments

Comments
 (0)