1 /*
2 * Copyright (c) 2015-2021 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #include <api_midi.h>
19 #include <api_atom.h>
20 #include <api_forge.h>
21
22 __realtime static int
_lmidiresponder__call(lua_State * L)23 _lmidiresponder__call(lua_State *L)
24 {
25 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
26 const bool *through = lua_touserdata(L, 1);
27
28 lua_settop(L, 4); // discard superfluous arguments
29 // 1: self
30 // 2: frames
31 // 3: forge
32 // 4: atom
33
34 latom_t *latom = NULL;
35 if(luaL_testudata(L, 4, "latom"))
36 latom = lua_touserdata(L, 4);
37 lua_pop(L, 1); // atom
38
39 // check for valid atom and event type
40 if( !latom
41 || (latom->atom->type != moony->uris.midi_event) )
42 {
43 lua_pushboolean(L, 0); // not handled
44 return 1;
45 }
46
47 const uint8_t *midi = latom->body.raw;
48 const uint8_t status = midi[0];
49 const uint8_t command = status & 0xf0;
50 const bool is_system = command == 0xf0;
51
52 // replace self with its uservalue
53 lua_getuservalue(L, 1);
54 lua_replace(L, 1);
55
56 if(lua_geti(L, 1, is_system ? status : command) != LUA_TNIL)
57 {
58 lua_insert(L, 1);
59 if(is_system)
60 lua_pushnil(L); // system messages have no channel
61 else
62 lua_pushinteger(L, status & 0x0f); // 4: channel
63
64 for(unsigned i=1; i<latom->atom->size; i++)
65 lua_pushinteger(L, midi[i]);
66
67 lua_call(L, 4 + latom->atom->size - 1, 0);
68 }
69 else if(*through) // through
70 {
71 const int64_t frames = luaL_checkinteger(L, 2);
72 lforge_t *lforge = luaL_checkudata(L, 3, "lforge");
73
74 if(frames < lforge->last.frames)
75 luaL_error(L, "invalid frame time, must not decrease");
76 lforge->last.frames = frames;
77
78 if( !lv2_atom_forge_frame_time(lforge->forge, frames)
79 || !lv2_atom_forge_atom(lforge->forge, latom->atom->size, latom->atom->type)
80 || !lv2_atom_forge_write(lforge->forge, latom->body.raw, latom->atom->size) )
81 luaL_error(L, forge_buffer_overflow);
82 }
83
84 lua_pushboolean(L, 1); // handled
85 return 1;
86 }
87
88 __realtime static int
_lmidiresponder__index(lua_State * L)89 _lmidiresponder__index(lua_State *L)
90 {
91 const bool *through = lua_touserdata(L, 1);
92 const char *key = luaL_checkstring(L, 2);
93 // 1: self
94 // 2: key
95
96 if(!strcmp(key, "through"))
97 {
98 lua_pushboolean(L, *through);
99 }
100 else
101 {
102 lua_pushnil(L);
103 }
104
105 return 1;
106 }
107
108 __realtime static int
_lmidiresponder__newindex(lua_State * L)109 _lmidiresponder__newindex(lua_State *L)
110 {
111 // 1: self
112 // 2: key
113 // 3: val
114 bool *through = lua_touserdata(L, 1);
115 const char *key = luaL_checkstring(L, 2);
116
117 if(!strcmp(key, "through"))
118 {
119 *through = lua_toboolean(L, 3);
120 }
121
122 return 0;
123 }
124
125 __realtime int
_lmidiresponder(lua_State * L)126 _lmidiresponder(lua_State *L)
127 {
128 //moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
129
130 lua_settop(L, 2); // discard superfluous arguments
131
132 const bool _through = lua_toboolean(L, 2);
133 lua_pop(L, 1); // bool
134
135 // o = new
136 bool *through = lua_newuserdata(L, sizeof(bool));
137 *through= _through;
138
139 // o.uservalue = uservalue
140 lua_insert(L, 1);
141 lua_setuservalue(L, -2);
142
143 // setmetatable(o, self)
144 luaL_getmetatable(L, "lmidiresponder");
145 lua_setmetatable(L, -2);
146
147 // return o
148 return 1;
149 }
150
151 const luaL_Reg lmidiresponder_mt [] = {
152 {"__call", _lmidiresponder__call},
153 {"__index", _lmidiresponder__index},
154 {"__newindex", _lmidiresponder__newindex},
155 {NULL, NULL}
156 };
157
158 const midi_msg_t midi_msgs [] = {
159 { LV2_MIDI_MSG_NOTE_OFF , "NoteOff" },
160 { LV2_MIDI_MSG_NOTE_ON , "NoteOn" },
161 { LV2_MIDI_MSG_NOTE_PRESSURE , "NotePressure" },
162 { LV2_MIDI_MSG_CONTROLLER , "Controller" },
163 { LV2_MIDI_MSG_PGM_CHANGE , "ProgramChange" },
164 { LV2_MIDI_MSG_CHANNEL_PRESSURE , "ChannelPressure" },
165 { LV2_MIDI_MSG_BENDER , "Bender" },
166 { LV2_MIDI_MSG_SYSTEM_EXCLUSIVE , "SystemExclusive" },
167 { LV2_MIDI_MSG_MTC_QUARTER , "QuarterFrame" },
168 { LV2_MIDI_MSG_SONG_POS , "SongPosition" },
169 { LV2_MIDI_MSG_SONG_SELECT , "SongSelect" },
170 { LV2_MIDI_MSG_TUNE_REQUEST , "TuneRequest" },
171 { LV2_MIDI_MSG_CLOCK , "Clock" },
172 { LV2_MIDI_MSG_START , "Start" },
173 { LV2_MIDI_MSG_CONTINUE , "Continue" },
174 { LV2_MIDI_MSG_STOP , "Stop" },
175 { LV2_MIDI_MSG_ACTIVE_SENSE , "ActiveSense" },
176 { LV2_MIDI_MSG_RESET , "Reset" },
177 { 0xf7 , "EndOfExclusive" },
178
179 { 0, NULL} // sentinel
180 };
181
182 const midi_msg_t controllers [] = {
183 { LV2_MIDI_CTL_MSB_BANK , "BankSelection_MSB" },
184 { LV2_MIDI_CTL_MSB_MODWHEEL , "Modulation_MSB" },
185 { LV2_MIDI_CTL_MSB_BREATH , "Breath_MSB" },
186 { LV2_MIDI_CTL_MSB_FOOT , "Foot_MSB" },
187 { LV2_MIDI_CTL_MSB_PORTAMENTO_TIME , "PortamentoTime_MSB" },
188 { LV2_MIDI_CTL_MSB_DATA_ENTRY , "DataEntry_MSB" },
189 { LV2_MIDI_CTL_MSB_MAIN_VOLUME , "MainVolume_MSB" },
190 { LV2_MIDI_CTL_MSB_BALANCE , "Balance_MSB" },
191 { LV2_MIDI_CTL_MSB_PAN , "Panpot_MSB" },
192 { LV2_MIDI_CTL_MSB_EXPRESSION , "Expression_MSB" },
193 { LV2_MIDI_CTL_MSB_EFFECT1 , "Effect1_MSB" },
194 { LV2_MIDI_CTL_MSB_EFFECT2 , "Effect2_MSB" },
195 { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 , "GeneralPurpose1_MSB" },
196 { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 , "GeneralPurpose2_MSB" },
197 { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 , "GeneralPurpose3_MSB" },
198 { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 , "GeneralPurpose4_MSB" },
199
200 { LV2_MIDI_CTL_LSB_BANK , "BankSelection_LSB" },
201 { LV2_MIDI_CTL_LSB_MODWHEEL , "Modulation_LSB" },
202 { LV2_MIDI_CTL_LSB_BREATH , "Breath_LSB" },
203 { LV2_MIDI_CTL_LSB_FOOT , "Foot_LSB" },
204 { LV2_MIDI_CTL_LSB_PORTAMENTO_TIME , "PortamentoTime_LSB" },
205 { LV2_MIDI_CTL_LSB_DATA_ENTRY , "DataEntry_LSB" },
206 { LV2_MIDI_CTL_LSB_MAIN_VOLUME , "MainVolume_LSB" },
207 { LV2_MIDI_CTL_LSB_BALANCE , "Balance_LSB" },
208 { LV2_MIDI_CTL_LSB_PAN , "Panpot_LSB" },
209 { LV2_MIDI_CTL_LSB_EXPRESSION , "Expression_LSB" },
210 { LV2_MIDI_CTL_LSB_EFFECT1 , "Effect1_LSB" },
211 { LV2_MIDI_CTL_LSB_EFFECT2 , "Effect2_LSB" },
212 { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 , "GeneralPurpose1_LSB" },
213 { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 , "GeneralPurpose2_LSB" },
214 { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 , "GeneralPurpose3_LSB" },
215 { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 , "GeneralPurpose4_LSB" },
216
217 { LV2_MIDI_CTL_SUSTAIN , "SustainPedal" },
218 { LV2_MIDI_CTL_PORTAMENTO , "Portamento" },
219 { LV2_MIDI_CTL_SOSTENUTO , "Sostenuto" },
220 { LV2_MIDI_CTL_SOFT_PEDAL , "SoftPedal" },
221 { LV2_MIDI_CTL_LEGATO_FOOTSWITCH , "LegatoFootSwitch" },
222 { LV2_MIDI_CTL_HOLD2 , "Hold2" },
223
224 { LV2_MIDI_CTL_SC1_SOUND_VARIATION , "SoundVariation" },
225 { LV2_MIDI_CTL_SC3_RELEASE_TIME , "ReleaseTime" },
226 { LV2_MIDI_CTL_SC2_TIMBRE , "Timbre" },
227 { LV2_MIDI_CTL_SC4_ATTACK_TIME , "AttackTime" },
228 { LV2_MIDI_CTL_SC5_BRIGHTNESS , "Brightness" },
229 { LV2_MIDI_CTL_SC1_SOUND_VARIATION , "SC1" },
230 { LV2_MIDI_CTL_SC2_TIMBRE , "SC2" },
231 { LV2_MIDI_CTL_SC3_RELEASE_TIME , "SC3" },
232 { LV2_MIDI_CTL_SC4_ATTACK_TIME , "SC4" },
233 { LV2_MIDI_CTL_SC5_BRIGHTNESS , "SC5" },
234 { LV2_MIDI_CTL_SC6 , "SC6" },
235 { LV2_MIDI_CTL_SC7 , "SC7" },
236 { LV2_MIDI_CTL_SC8 , "SC8" },
237 { LV2_MIDI_CTL_SC9 , "SC9" },
238 { LV2_MIDI_CTL_SC10 , "SC10" },
239
240 { LV2_MIDI_CTL_GENERAL_PURPOSE5 , "GeneralPurpose5" },
241 { LV2_MIDI_CTL_GENERAL_PURPOSE6 , "GeneralPurpose6" },
242 { LV2_MIDI_CTL_GENERAL_PURPOSE7 , "GeneralPurpose7" },
243 { LV2_MIDI_CTL_GENERAL_PURPOSE8 , "GeneralPurpose8" },
244 { LV2_MIDI_CTL_PORTAMENTO_CONTROL , "PortamentoControl" },
245
246 { LV2_MIDI_CTL_E1_REVERB_DEPTH , "ReverbDepth" },
247 { LV2_MIDI_CTL_E2_TREMOLO_DEPTH , "TremoloDepth" },
248 { LV2_MIDI_CTL_E3_CHORUS_DEPTH , "ChorusDepth" },
249 { LV2_MIDI_CTL_E4_DETUNE_DEPTH , "DetuneDepth" },
250 { LV2_MIDI_CTL_E5_PHASER_DEPTH , "PhaserDepth" },
251 { LV2_MIDI_CTL_E1_REVERB_DEPTH , "E1" },
252 { LV2_MIDI_CTL_E2_TREMOLO_DEPTH , "E2" },
253 { LV2_MIDI_CTL_E3_CHORUS_DEPTH , "E3" },
254 { LV2_MIDI_CTL_E4_DETUNE_DEPTH , "E4" },
255 { LV2_MIDI_CTL_E5_PHASER_DEPTH , "E5" },
256
257 { LV2_MIDI_CTL_DATA_INCREMENT , "DataIncrement" },
258 { LV2_MIDI_CTL_DATA_DECREMENT , "DataDecrement" },
259
260 { LV2_MIDI_CTL_NRPN_LSB , "NRPN_LSB" },
261 { LV2_MIDI_CTL_NRPN_MSB , "NRPN_MSB" },
262
263 { LV2_MIDI_CTL_RPN_LSB , "RPN_LSB" },
264 { LV2_MIDI_CTL_RPN_MSB , "RPN_MSB" },
265
266 { LV2_MIDI_CTL_ALL_SOUNDS_OFF , "AllSoundsOff" },
267 { LV2_MIDI_CTL_RESET_CONTROLLERS , "ResetControllers" },
268 { LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH , "LocalControlSwitch" },
269 { LV2_MIDI_CTL_ALL_NOTES_OFF , "AllNotesOff" },
270 { LV2_MIDI_CTL_OMNI_OFF , "OmniOff" },
271 { LV2_MIDI_CTL_OMNI_ON , "OmniOn" },
272 { LV2_MIDI_CTL_MONO1 , "Mono1" },
273 { LV2_MIDI_CTL_MONO2 , "Mono2" },
274
275 { 0, NULL} // sentinel
276 };
277