1const NOTE_NONE:u8 = 0;
9const NOTE_MIN:u8 = 1;
10const NOTE_MAX:u8 = 120;
11const NOTE_MIDDLEC:u8 = 5 * 12 + NOTE_MIN;
12const NOTE_KEYOFF:u8 = 0xFF;
13const NOTE_NOTECUT:u8 = 0xFE;
14const NOTE_FADE:u8 = 0xFD;
15const NOTE_PC:u8 = 0xFC;
16const NOTE_PCS:u8 = 0xFB;
17
18pub struct ModCommand {
19 pub note : Note,
20 pub instr: u8,
21 pub volcmd: VolumeCommand,
22 pub command: EffectCommand,
23}
24
25impl ModCommand {
26 pub fn new(note : u8, instr : u8, volcmd : u8, command : u8, vol : u8, param : u8) -> Result<ModCommand, String> {
40 let note_type = ModCommand::note_from_value(note);
41 let note_type = match note_type {
42 Ok(n) => n,
43 Err(e) => return Err(e),
44 };
45
46 let vol_type = ModCommand::volume_from_command_param(volcmd, vol);
47 let vol_type = match vol_type {
48 Ok(v) => v,
49 Err(e) => return Err(e),
50 };
51
52 let effect_type = ModCommand::effect_from_command_param(command, param);
53 let effect_type = match effect_type {
54 Ok(c) => c,
55 Err(e) => return Err(e),
56 };
57
58 Ok(ModCommand {
59 note: note_type,
60 instr: instr,
61 volcmd: vol_type,
62 command: effect_type,
63 })
64 }
65
66 pub fn middle_c() -> u8 {
68 NOTE_MIDDLEC
69 }
70
71 fn note_from_value(note_val : u8) -> Result<Note, String> {
72 match note_val {
73 NOTE_NONE => Ok(Note::None),
74 NOTE_MIN...NOTE_MAX => Ok(Note::Note(note_val)),
75 NOTE_KEYOFF => Ok(Note::Special(SpecialNote::KeyOff)),
76 NOTE_NOTECUT => Ok(Note::Special(SpecialNote::NoteCut)),
77 NOTE_FADE => Ok(Note::Special(SpecialNote::Fade)),
78 NOTE_PC => Ok(Note::Special(SpecialNote::ParamControl)),
79 NOTE_PCS => Ok(Note::Special(SpecialNote::ParamControlSmooth)),
80 _ => Err("Invalid note".to_owned()),
81 }
82 }
83
84 fn effect_from_command_param(cmd : u8, param : u8) -> Result<EffectCommand, String> {
85 let nibble_x = (param & 0xF0) >> 4;
86 let nibble_y = param & 0x0F;
87
88 match cmd {
89 0 => Ok(EffectCommand::None),
90 1 => Ok(EffectCommand::Arpeggio(nibble_x, nibble_y)),
91 2 => Ok(EffectCommand::PortamentoUp(param)),
92 3 => Ok(EffectCommand::PortamentoDown(param)),
93 4 => Ok(EffectCommand::TonePortamento(param)),
94 5 => Ok(EffectCommand::Vibrato(nibble_x, nibble_y)),
95 6 => Ok(EffectCommand::TonePortaVol(nibble_x, nibble_y)),
96 7 => Ok(EffectCommand::VibratoVol(nibble_x, nibble_y)),
97 8 => Ok(EffectCommand::Tremolo(nibble_x, nibble_y)),
98 9 => Ok(EffectCommand::Panning8(param)),
99 10 => Ok(EffectCommand::Offset(param)),
100 11 => Ok(EffectCommand::VolumeSlide(nibble_x, nibble_y)),
101 12 => Ok(EffectCommand::PositionJump(param)),
102 13 => Ok(EffectCommand::Volume(param)),
103 14 => Ok(EffectCommand::PatternBreak(param)),
104 15 => Ok(EffectCommand::Retrig(nibble_x, nibble_y)),
105 16 => Ok(EffectCommand::Speed(param)),
106 17 => Ok(EffectCommand::Tempo(param)),
107 18 => Ok(EffectCommand::Tremor(nibble_x, nibble_y)),
108 19 => Ok(EffectCommand::ModCmdEX(nibble_x, nibble_y)),
109 20 => Ok(EffectCommand::S3MCmdEX(nibble_x, nibble_y)),
110 21 => Ok(EffectCommand::ChannelVolume(param)),
111 22 => Ok(EffectCommand::ChannelVolSlide(nibble_x, nibble_y)),
112 23 => Ok(EffectCommand::GlobalVolume(param)),
113 24 => Ok(EffectCommand::GlobalVolSlide(nibble_x, nibble_y)),
114 25 => Ok(EffectCommand::KeyOff(param)),
115 26 => Ok(EffectCommand::FineVibrato(nibble_x, nibble_y)),
116 27 => Ok(EffectCommand::Panbrello(nibble_x, nibble_y)),
117 28 => Ok(EffectCommand::XFinePortaUpDown(nibble_x, nibble_y)),
118 29 => Ok(EffectCommand::PanningSlide(nibble_x, nibble_y)),
119 30 => Ok(EffectCommand::SetEnvPosition(param)),
120 31 => Ok(EffectCommand::Midi(param)),
121 32 => Ok(EffectCommand::SmoothMidi(param)),
122 33 => Ok(EffectCommand::DelayCut(nibble_x, nibble_y)),
123 34 => Ok(EffectCommand::XParam(param)),
124 35 => Ok(EffectCommand::NoteSlideUp(nibble_x, nibble_y)),
125 36 => Ok(EffectCommand::NoteSlideUpRetrig(nibble_x, nibble_y)),
126 37 => Ok(EffectCommand::NoteSlideDown(nibble_x, nibble_y)),
127 38 => Ok(EffectCommand::NoteSlideDownRetrig(nibble_x, nibble_y)),
128 39 => Ok(EffectCommand::ReverseOffset(param)),
129 40 => Ok(EffectCommand::DBMEcho(nibble_x, nibble_y)),
130 41 => Ok(EffectCommand::OffsetPercentage(param)),
131 _ => Err("Invalid effect".to_owned()),
132 }
133 }
134
135 fn volume_from_command_param(cmd : u8, param : u8) -> Result<VolumeCommand, String> {
136 match cmd {
137 0 => Ok(VolumeCommand::None),
138 1 => Ok(VolumeCommand::Volume(param)),
139 2 => Ok(VolumeCommand::Panning(param)),
140 3 => Ok(VolumeCommand::VolSlideUp(param)),
141 4 => Ok(VolumeCommand::VolSlideDown(param)),
142 5 => Ok(VolumeCommand::FineVolUp(param)),
143 6 => Ok(VolumeCommand::FineVolDown(param)),
144 7 => Ok(VolumeCommand::VibratoSpeed(param)),
145 8 => Ok(VolumeCommand::VibratoDepth(param)),
146 9 => Ok(VolumeCommand::PanSlideLeft(param)),
147 10 => Ok(VolumeCommand::PanSlideRight(param)),
148 11 => Ok(VolumeCommand::TonePortamento(param)),
149 12 => Ok(VolumeCommand::PortaUp(param)),
150 13 => Ok(VolumeCommand::PortaDown(param)),
151 14 => Ok(VolumeCommand::DelayCut(param)),
152 15 => Ok(VolumeCommand::Offset(param)),
153 _ => Err("Invalid volume command".to_owned()),
154 }
155 }
156}
157
158pub enum Note {
160 None,
161 Note(u8),
162 Special(SpecialNote),
163}
164
165pub enum SpecialNote {
167 KeyOff,
168 NoteCut,
169 Fade,
170 ParamControl,
171 ParamControlSmooth,
172}
173
174pub enum VolumeCommand {
186 None,
187 Volume(u8),
188 Panning(u8),
189 VolSlideUp(u8),
190 VolSlideDown(u8),
191 FineVolUp(u8),
192 FineVolDown(u8),
193 VibratoSpeed(u8),
194 VibratoDepth(u8),
195 PanSlideLeft(u8),
196 PanSlideRight(u8),
197 TonePortamento(u8),
199 PortaUp(u8),
201 PortaDown(u8),
203 DelayCut(u8),
205 Offset(u8),
206}
207
208pub enum EffectCommand {
221 None,
222 Arpeggio (u8, u8),
224 PortamentoUp (u8),
228 PortamentoDown (u8),
232 TonePortamento (u8),
236 Vibrato (u8, u8),
240 TonePortaVol (u8, u8),
242 VibratoVol (u8, u8),
244 Tremolo (u8, u8),
246 Panning8 (u8),
248 Offset(u8),
250 VolumeSlide(u8, u8),
252 PositionJump(u8),
254 Volume(u8),
256 PatternBreak(u8),
258 Retrig(u8, u8),
260 Speed(u8),
262 Tempo(u8),
264 Tremor(u8, u8),
266 ModCmdEX(u8, u8),
268 S3MCmdEX(u8, u8),
270 ChannelVolume(u8),
272 ChannelVolSlide(u8, u8),
274 GlobalVolume(u8),
276 GlobalVolSlide(u8, u8),
278 KeyOff(u8),
280 FineVibrato(u8, u8),
282 Panbrello(u8, u8),
284 XFinePortaUpDown(u8, u8),
286 PanningSlide(u8, u8),
290 SetEnvPosition(u8),
292 Midi(u8),
294 SmoothMidi(u8),
296 DelayCut(u8, u8),
300 XParam(u8),
302 NoteSlideUp(u8, u8),
303 NoteSlideDown(u8, u8),
304 NoteSlideUpRetrig(u8, u8),
305 NoteSlideDownRetrig(u8, u8),
306 ReverseOffset(u8),
307 DBMEcho(u8, u8),
309 OffsetPercentage(u8),
310}