-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprogram_decode.erl
233 lines (205 loc) · 8.23 KB
/
program_decode.erl
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
-module(program_decode).
-export([to_map/1]).
to_map(ProgramData) ->
<<Name:12/bytes, _:16, ArpCtrlData:2/bytes,
_:2, VoiceMode:2, 0:4, ScaleKey:4, ScaleType:4, _:8,
DelayFx:4/bytes, ModFx:3/bytes, Eq:4/bytes, Arp:7/bytes,
KbdOctave/signed-integer, VoicesParams:216/bytes>> = ProgramData,
Mode = enums:voice_mode(VoiceMode),
#{name => Name,
arpctrl => arpctrl(ArpCtrlData),
voice_mode => Mode,
scale_key => enums:scale_key(ScaleKey),
scale_type => ScaleType,
delayfx => delayfx(DelayFx),
modfx => modfx(ModFx),
eq => eq(Eq),
arp => arp(Arp),
kbd_oct => KbdOctave,
voices => voices_to_list(Mode, VoicesParams)}.
arpctrl(<<0:5, Len:3, T1:1,T2:1,T3:1,T4:1,T5:1,T6:1,T7:1,T8:1>>) ->
#{len => Len+1, pattern => [T1,T2,T3,T4,T5,T6,T7,T8]}.
delayfx(<<Sync:1, 0:3, TimeBase:4,Time:8,Depth:8,Type:8>>) ->
#{sync => enums:onoff(Sync),
timebase => enums:delay_timebase(TimeBase),
time => Time,
depth => Depth,
type => enums:delay_type(Type)}.
modfx(<<LFOSpeed:8,Depth:8,Type:8>>) ->
#{lfo_speed => LFOSpeed,
depth => Depth,
type => enums:mod_type(Type)}.
eq(<<HiFreq:8,HiGain:8,LoFreq:8,LoGain:8>>) ->
#{hifreq => enums:hifreqs(HiFreq),
higain => gain(HiGain),
lofreq => enums:lofreqs(LoFreq),
logain => gain(LoGain)}.
gain(N) when N >= 64-12, N =< 64+12 -> N-64.
arp(<<Tempo:16, OnOff:1, Latch:1, Target:2, 0:3, KeySync:1,
Range:4, Type:4, GateTime:8, Resolution:8, Swing/signed-integer>>)
when Tempo >= 20, Tempo =< 300, GateTime =< 100,
Swing >= -100, Swing =< 100 ->
#{tempo => Tempo,
onoff => enums:onoff(OnOff),
latch => enums:onoff(Latch),
target => enums:arp_target(Target),
keysync => enums:onoff(KeySync),
range => Range+1,
type => enums:arp_type(Type),
gate_time => GateTime,
resolution => enums:arp_reso(Resolution),
swing => Swing}.
voices_to_list(single, <<Timbre1:108/bytes, _:108/bytes>>) ->
[timbre_to_map(Timbre1)];
voices_to_list(double, <<Timbre1:108/bytes, Timbre2:108/bytes>>) ->
[timbre_to_map(Timbre1), timbre_to_map(Timbre2)];
voices_to_list(vocoder, <<Vocoder:142/bytes, _:74/bytes>>) ->
[vocoder_to_map(Vocoder)].
timbre_to_map(<<MidiCh/signed-integer,
AssignMode:2, EG2Reset:1, EG1Reset:1, TriggerMode:1,
_:1, KeyPriority:2, UnisonDetune:8, Pitch:4/bytes, Osc1:5/bytes,
Osc2:3/bytes, 0:1, PortamentoTime:7, Mixer:3/bytes,
Filter:6/bytes, Amp:5/bytes, EG1:4/bytes, EG2:4/bytes,
LFO1:3/bytes, LFO2:3/bytes, Patch:8/bytes, _:56/bytes>>)
when UnisonDetune =< 99 ->
#{midi_ch => timbre_midich(MidiCh),
assign_mode => enums:timbre_assign(AssignMode),
eg2_reset => enums:onoff(EG2Reset),
eg1_reset => enums:onoff(EG1Reset),
trigger_mode => enums:timbre_trigger(TriggerMode),
key_priority => timbre_keypriority(KeyPriority),
unison_detune => UnisonDetune,
pitch => timbre_pitch(Pitch),
osc1 => timbre_osc1(Osc1),
osc2 => timbre_osc2(Osc2),
porta_time => PortamentoTime,
mixer => timbre_mixer(Mixer),
filter => timbre_filter(Filter),
amp => timbre_amp(Amp),
eg1 => timbre_eg(EG1),
eg2 => timbre_eg(EG2),
lfo1 => timbre_lfo(1, LFO1),
lfo2 => timbre_lfo(2, LFO2),
patch => timbre_patch(Patch)}.
timbre_midich(-1) -> global;
timbre_midich(N) when N >= 0 -> N.
timbre_keypriority(0) -> last;
timbre_keypriority(N) -> N.
timbre_pitch(<<Tune:8,Bend:8,Trans:8,Vibrato:8>>)
when abs(Tune-64) =< 50, abs(Bend-64) =< 12,
abs(Trans-64) =< 24, abs(Vibrato-64) =< 63 ->
#{tune => Tune-64, bend => Bend-64,
transpose => Trans-64, vibrato => Vibrato-64}.
timbre_osc1(<<Wave:8,WaveCtrl1:8,WaveCtrl2:8,DWGS:8,_:8>>) ->
#{wave => enums:timbre1_wave(Wave),
ctrl1 => WaveCtrl1,
ctrl2 => WaveCtrl2,
dwgs => DWGS+1}.
timbre_osc2(<<0:2,ModSelect:2,0:2,Wave:2,Semitone:8,Tune:8>>)
when abs(Semitone-64) =< 24, abs(Tune-64) =< 63 ->
#{modselect => enums:timbre2_modselect(ModSelect),
wave => enums:timbre2_wave(Wave),
semitone => Semitone-64,
tune => Tune-64}.
timbre_mixer(<<Osc1Level:8, Osc2Level:8, Noise:8>>) ->
#{osc1_lvl => Osc1Level,
osc2_lvl => Osc2Level,
noise => Noise}.
timbre_filter(<<Type:8,Cutoff:8,Reso:8,EG1Int:8,VelSens:8,KeyTrack:8>>)
when abs(EG1Int-64) =< 63, abs(KeyTrack-64) =< 63 ->
#{type => enums:filter_type(Type),
cutoff => Cutoff,
reso => Reso,
eg1_intensity => EG1Int-64,
velocity_sense => VelSens-64,
key_track => KeyTrack-64}.
timbre_amp(<<Level:8,Pan:8,0:1,SW:1,0:5,Dist:1,VelSense:8,KeyTrack:8>>)
when abs(KeyTrack-64) =< 63 ->
#{level => Level,
pan => Pan-64,
sw => SW,
distortion => enums:onoff(Dist),
velocity_sense => VelSense-64,
key_track => KeyTrack-64}.
timbre_eg(<<Attack:8,Decay:8,Sustain:8,Release:8>>) ->
#{attack => Attack, decay => Decay,
sustain => Sustain, release => Release}.
timbre_lfo(N, <<0:2, KeySync:2, 0:2, Wave:2, Freq:8,
TempoSync:1, 0:2, SyncNote:5>>) ->
#{keysync => enums:lfo_keysync(KeySync),
wave => enums:lfo_wave(N, Wave),
freq => Freq,
tempo_sync => enums:onoff(TempoSync),
sync_note => enums:lfo_syncnote(SyncNote)}.
timbre_patch(<<Cable1:2/bytes, Cable2:2/bytes,
Cable3:2/bytes, Cable4:2/bytes>>) ->
{patch_cable(Cable1), patch_cable(Cable2),
patch_cable(Cable3), patch_cable(Cable4)}.
patch_cable(<<Destination:4, Source:4, Intensity:8>>)
when abs(Intensity-64) =< 63 ->
#{destination => enums:cable_dest(Destination),
source => enums:cable_source(Source),
intensity => Intensity - 64}.
vocoder_to_map(<<MidiCh/signed-integer,
AssignMode:2, EG2Reset:1, EG1Reset:1, TriggerMode:1,
_:1, KeyPriority:2, UnisonDetune:8, Pitch:4/bytes, Osc1:5/bytes,
_:7, AudioIn1HPFGate:1, _:8, 0:1, PortamentoTime:7,
Mixer:3/bytes, AudioIn1:3/bytes, Filter:6/bytes,
Amp:5/bytes, _EG1:4/bytes, EG2:4/bytes,
LFO1:3/bytes, LFO2:3/bytes, ChLevels:16/bytes,
PanLeves:16/bytes, HoldLevels:64/bytes>>)
when UnisonDetune =< 99 ->
#{midi_ch => timbre_midich(MidiCh),
assign_mode => enums:timbre_assign(AssignMode),
eg2_reset => enums:onoff(EG2Reset),
eg1_reset => enums:onoff(EG1Reset),
trigger_mode => enums:timbre_trigger(TriggerMode),
key_priority => timbre_keypriority(KeyPriority),
unison_detune => UnisonDetune,
pitch => timbre_pitch(Pitch),
osc1 => timbre_osc1(Osc1),
audioin1_hpfgate => enums:onoff(AudioIn1HPFGate),
porta_time => PortamentoTime,
mixer => vocoder_mixer(Mixer),
audioin1 => vocoder_audioin1(AudioIn1),
filter => vocoder_filter(Filter),
amp => vocoder_amp(Amp),
eg2 => timbre_eg(EG2),
lfo1 => timbre_lfo(1, LFO1),
lfo2 => timbre_lfo(2, LFO2),
ch_levels => binary_to_list(ChLevels),
pan_levels => lists:map(fun (X) -> X-64 end,
binary_to_list(PanLeves)),
hold_levels => [X || <<X:32/big-integer>> <= HoldLevels]}.
vocoder_mixer(<<Osc1Level:8, Ext1Level:8, Noise:8>>) ->
#{osc1_lvl => Osc1Level,
ext1_lvl => Ext1Level,
noise => Noise}.
vocoder_audioin1(<<HPFLevel:8, GateSense:8, Threshold:8>>) ->
#{hpf_lvl => HPFLevel,
gate_sense => GateSense,
threshold => Threshold}.
vocoder_filter(<<Shift:8, Cutoff:8, Resonance:8,
ModSource:8, Intensity:8, EFSense:8>>)
when Shift =< 4, abs(Cutoff-64) =< 63, Resonance =< 127,
abs(Intensity-64) =< 63, EFSense =< 127 ->
#{shift => vocoder_filter_shift(Shift),
cutoff => Cutoff - 64,
resonance => Resonance,
modsource => enums:vocoder_filter_modsource(ModSource),
intensity => Intensity - 64,
efsense => vocoder_filter_efsense(EFSense)}.
vocoder_filter_shift(0) -> 0;
vocoder_filter_shift(1) -> 1;
vocoder_filter_shift(2) -> 2;
vocoder_filter_shift(3) -> -1;
vocoder_filter_shift(4) -> -2.
vocoder_filter_efsense(127) -> hold;
vocoder_filter_efsense(N) -> N.
vocoder_amp(<<Level:8, DirectLevel:8, 0:7, Distortion:1, VelSense:8, KeyTrack:8>>)
when Level =< 127, DirectLevel =< 127, abs(KeyTrack-64) =< 63 ->
#{level => Level,
direct_level => DirectLevel,
distortion => enums:onoff(Distortion),
velocity_sense => VelSense - 64,
key_track => KeyTrack - 64}.