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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
pub enum Slide
{
Up(u8),
Down(u8),
FineUp(u8),
FineDown(u8)
}
pub enum Effect
{
SetSpeed(u8),
PosJump(u8),
PattBreak(u8),
SetVolume(u8),
VolumeSlide(Slide),
PortaDown(u8),
PortaFineDown(u8),
PortaExFineDown(u8),
PortaUp(u8),
PortaFineUp(u8),
PortaExFineUp(u8),
TonePorta(u8),
Vibrato(u8, u8),
Tremor(u8, u8),
Arpeggio(u8, u8),
VolumeSlideVib(Slide),
VolumeSlideTPorta(Slide),
SetChannelVolume(u8),
ChVolSlide(Slide),
SampleOffset(u8),
PanSlide(Slide),
Retrigger(u8, u8),
Tremolo(u8, u8),
GlissandoCtrl(bool),
SetFinetune(u8),
SetVibWaveform(u8),
SetTremWaveform(u8),
SetPanWaveform(u8),
RowExtention(u8),
VirtChanOp(u8),
NNAOverride(u8),
VolumeEnvEnable(bool),
PanEnvEnable(bool),
PitchEnvEnable(bool),
SoundCtrl(u8),
SampleOffsetHigh(u8),
PattLoopStart,
PattLoop(u8),
NoteCut(u8),
NoteDelay(u8),
PattDelay(u8),
SetActiveMacro(u8),
SetTempo(u8),
TempoSlideDown(u8),
TempoSlideUp(u8),
VibFine(u8, u8),
SetGlobalVolume(u8),
GlobalVolumeSlide(Slide),
SetPan(u8),
AutoPan(u8, u8),
MidiMacro(u8),
SmoothMidiMacro(u8),
NoEffect
}
impl Effect
{
pub fn from_it_efx(f: (u8, u8)) -> Effect
{
let (efx, fxp) = f;
match efx as char
{
'A' => Effect::SetSpeed(fxp),
'B' => Effect::PosJump(fxp),
'C' => Effect::PattBreak(fxp),
'D' =>
match (fxp >> 4, fxp & 0x0f)
{
(0, y) => Effect::VolumeSlide(Slide::Down(y)),
(x, 0) => Effect::VolumeSlide(Slide::Up(x)),
(0xf, 0xf) => Effect::NoEffect,
(0xf, y) => Effect::VolumeSlide(Slide::FineDown(y)),
(x, 0xf) => Effect::VolumeSlide(Slide::FineUp(x)),
_ => Effect::NoEffect
},
'E' =>
match fxp & 0xf0
{
0xF0 => Effect::PortaFineDown(fxp & 0x0f),
0xE0 => Effect::PortaExFineDown(fxp & 0x0f),
_ => Effect::PortaDown(fxp)
},
'F' =>
match fxp & 0xf0
{
0xF0 => Effect::PortaFineUp(fxp & 0x0f),
0xE0 => Effect::PortaExFineUp(fxp & 0x0f),
_ => Effect::PortaUp(fxp)
},
'G' => Effect::TonePorta(fxp),
'H' => Effect::Vibrato(fxp >> 4, fxp & 0x0f),
'I' => Effect::Tremor(fxp >> 4, fxp & 0x0f),
'J' => Effect::Arpeggio(fxp >> 4, fxp & 0x0f),
'K' =>
match (fxp >> 4, fxp & 0x0f)
{
(0, y) => Effect::VolumeSlideVib(Slide::Down(y)),
(x, 0) => Effect::VolumeSlideVib(Slide::Up(x)),
(0xf, 0xf) => Effect::NoEffect,
(0xf, y) => Effect::VolumeSlideVib(Slide::FineDown(y)),
(x, 0xf) => Effect::VolumeSlideVib(Slide::FineUp(x)),
_ => Effect::NoEffect
},
'L' =>
match (fxp >> 4, fxp & 0x0f)
{
(0, y) => Effect::VolumeSlideTPorta(Slide::Down(y)),
(x, 0) => Effect::VolumeSlideTPorta(Slide::Up(x)),
(0xf, 0xf) => Effect::NoEffect,
(0xf, y) => Effect::VolumeSlideTPorta(Slide::FineDown(y)),
(x, 0xf) => Effect::VolumeSlideTPorta(Slide::FineUp(x)),
_ => Effect::NoEffect
},
'M' => Effect::SetChannelVolume(fxp),
'N' =>
match (fxp >> 4, fxp & 0x0f)
{
(0, y) => Effect::ChVolSlide(Slide::Down(y)),
(x, 0) => Effect::ChVolSlide(Slide::Up(x)),
(0xf, 0xf) => Effect::NoEffect,
(0xf, y) => Effect::ChVolSlide(Slide::FineDown(y)),
(x, 0xf) => Effect::ChVolSlide(Slide::FineUp(x)),
_ => Effect::NoEffect
},
'O' => Effect::SampleOffset(fxp),
'P' =>
match (fxp >> 4, fxp & 0x0f)
{
(0, y) => Effect::PanSlide(Slide::Up(y)),
(x, 0) => Effect::PanSlide(Slide::Down(x)),
(0xf, 0xf) => Effect::NoEffect,
(0xf, y) => Effect::PanSlide(Slide::FineUp(y)),
(x, 0xf) => Effect::PanSlide(Slide::FineDown(x)),
_ => Effect::NoEffect
},
'Q' => Effect::Retrigger(fxp >> 4, fxp & 0x0f),
'R' => Effect::Tremolo(fxp >> 4, fxp & 0x0f),
'S' =>
match (fxp >> 4, fxp & 0x0f)
{
(0x1, e) => Effect::GlissandoCtrl(e != 0),
(0x2, t) => Effect::SetFinetune(t),
(0x3, w) => Effect::SetVibWaveform(w),
(0x4, w) => Effect::SetTremWaveform(w),
(0x5, w) => Effect::SetPanWaveform(w),
(0x6, d) => Effect::RowExtention(d),
(0x7, x @ 0..=2) => Effect::VirtChanOp(x),
(0x7, x @ 3..=6) => Effect::NNAOverride(x - 3),
(0x7, x @ 7..=8) => Effect::VolumeEnvEnable(x == 8),
(0x7, x @ 9..=10) => Effect::PanEnvEnable(x == 10),
(0x7, x @ 11..=12) => Effect::PitchEnvEnable(x == 10),
(0x8, p) => Effect::SetPan(p * (255 / 15)),
(0x9, c) => Effect::SoundCtrl(c),
(0xa, o) => Effect::SampleOffsetHigh(o),
(0xb, 0x0) => Effect::PattLoopStart,
(0xb, r) => Effect::PattLoop(r),
(0xc, t) => Effect::NoteCut(t),
(0xd, t) => Effect::NoteDelay(t),
(0xe, d) => Effect::PattDelay(d),
(0xf, m) => Effect::SetActiveMacro(m),
_ => Effect::NoEffect
},
'T' =>
match (fxp >> 4, fxp & 0x0f)
{
(0x0, v) => Effect::TempoSlideDown(v),
(0x1, v) => Effect::TempoSlideUp(v),
_ => Effect::SetTempo(fxp)
},
'U' => Effect::VibFine(fxp >> 4, fxp & 0x0f),
'V' => Effect::SetGlobalVolume(fxp),
'W' =>
match (fxp >> 4, fxp & 0x0f)
{
(0, y) => Effect::GlobalVolumeSlide(Slide::Down(y)),
(x, 0) => Effect::GlobalVolumeSlide(Slide::Up(x)),
(0xf, 0xf) => Effect::NoEffect,
(0xf, y) => Effect::GlobalVolumeSlide(Slide::FineDown(y)),
(x, 0xf) => Effect::GlobalVolumeSlide(Slide::FineUp(x)),
_ => Effect::NoEffect
},
'X' => Effect::SetPan(fxp),
'Y' => Effect::AutoPan(fxp >> 4, fxp & 0x0f),
'Z' => Effect::MidiMacro(fxp),
'\\' => Effect::SmoothMidiMacro(fxp),
_ => Effect::NoEffect
}
}
pub fn from_it_vol(v: u8) -> Effect
{
const GMAP: [u8; 10] = [0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60, 0x80, 0xFF];
match v
{
0..=64 => Effect::SetVolume(v),
65..=74 => Effect::VolumeSlide(Slide::FineUp(v - 65)),
75..=84 => Effect::VolumeSlide(Slide::FineDown(v - 75)),
85..=94 => Effect::VolumeSlide(Slide::Up(v - 85)),
95..=104 => Effect::VolumeSlide(Slide::Down(v - 95)),
105..=114 => Effect::PortaDown((v - 105) * 4),
115..=124 => Effect::PortaUp((v - 115) * 4),
128..=192 => Effect::SetPan(v - 128),
193..=202 => Effect::TonePorta(GMAP[(v - 193) as usize]),
203..=212 => Effect::Vibrato(0, v - 203),
_ => Effect::NoEffect
}
}
}
|