blob: 66acf606496d0d7c7e6e841483c63f49409f587d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include "SND_channel.h"
#include "SND_lfo.h"
// TODO remove this extern once we actually know where this table is
extern u8 sSampleDataShiftTable[4];
u16 CalcDecayCoeff(int vol) {
if (vol == 127)
return 0xFFFF;
else if (vol == 126)
return 0x3C00;
else if (vol < 50)
return (u16)(vol * 2 + 1);
else
return (u16)(0x1E00 / (126 - vol));
}
void ExChannelSetup(struct SNDExChannel *chn, SNDExChannelCallback callback, void *callbackUserData, int priority) {
chn->channelLLNext = NULL;
chn->callback = callback;
chn->callbackUserData = callbackUserData;
chn->length = 0;
chn->priority = (u8)priority;
chn->volume = 127;
chn->flags.start = FALSE;
chn->flags.autoSweep = TRUE;
chn->midiKey = 60;
chn->rootMidiKey = 60;
chn->velocity = 127;
chn->initPan = 0;
chn->userDecay = 0;
chn->userDecay2 = 0;
chn->userPitch = 0;
chn->userPan = 0;
chn->panRange = 127;
chn->sweepPitch = 0;
chn->sweepLength = 0;
chn->sweepCounter = 0;
SND_SetExChannelAttack(chn, 127);
SND_SetExChannelDecay(chn, 127);
SND_SetExChannelSustain(chn, 127);
SND_SetExChannelRelease(chn, 127);
SND_InitLfoParam(&chn->lfo.param);
}
void ExChannelStart(struct SNDExChannel *chn, int length) {
chn->envAttenuation = -92544;
chn->envStatus = 0;
chn->length = length;
SND_StartLfo(&chn->lfo);
chn->flags.start = TRUE;
chn->flags.active = TRUE;
}
int ExChannelVolumeCmp(struct SNDExChannel *chn_a, struct SNDExChannel *chn_b) {
int vol_a = chn_a->volume & 0xFF;
int vol_b = chn_b->volume & 0xFF;
vol_a <<= 4;
vol_b <<= 4;
vol_a >>= sSampleDataShiftTable[chn_a->volume >> 8];
vol_b >>= sSampleDataShiftTable[chn_b->volume >> 8];
if (vol_a != vol_b) {
if (vol_a < vol_b)
return 1;
else
return -1;
}
return 0;
}
int ExChannelSweepUpdate(struct SNDExChannel *chn, BOOL step) {
s64 result;
if (chn->sweepPitch == 0) {
result = 0;
} else if (chn->sweepCounter >= chn->sweepLength) {
result = 0;
} else {
result = (s64)chn->sweepPitch * (chn->sweepLength - chn->sweepCounter) / chn->sweepLength;
if (step && chn->flags.autoSweep)
chn->sweepCounter++;
}
return (int)result;
}
int ExChannelLfoUpdate(struct SNDExChannel *chn, BOOL step) {
s64 result = SND_GetLfoValue(&chn->lfo);
if (result != 0) {
switch (chn->lfo.param.target) {
case SND_LFO_VOLUME:
result *= 60;
break;
case SND_LFO_PITCH:
result <<= 6;
break;
case SND_LFO_PAN:
result <<= 6;
break;
}
result >>= 14;
}
if (step) {
SND_UpdateLfo(&chn->lfo);
}
return (int)result;
}
|