aboutsummaryrefslogtreecommitdiff
path: root/src/portmod.rs
blob: 125fdab4a6ebdccaedf53feb29beddf3d20c7f67 (plain) (blame)
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 >> 8, 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 >> 8, fxp & 0x0f),
            'I' => Effect::Tremor(fxp >> 8, fxp & 0x0f),
            'J' => Effect::Arpeggio(fxp >> 8, fxp & 0x0f),
            'K' =>
                match (fxp >> 8, 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 >> 8, 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 >> 8, 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 >> 8, 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 >> 8, fxp & 0x0f),
            'R' => Effect::Tremolo(fxp >> 8, fxp & 0x0f),
            'S' =>
                match (fxp >> 8, 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 >> 8, fxp & 0x0f)
                {
                    (0x0, v) => Effect::TempoSlideDown(v),
                    (0x1, v) => Effect::TempoSlideUp(v),
                    _ => Effect::SetTempo(fxp)
                },
            'U' => Effect::VibFine(fxp >> 8, fxp & 0x0f),
            'V' => Effect::SetGlobalVolume(fxp),
            'W' =>
                match (fxp >> 8, 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 >> 8, 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
        }
    }
}