-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRobU - MIDI Note Randomizer.lua
More file actions
493 lines (479 loc) · 20.8 KB
/
RobU - MIDI Note Randomizer.lua
File metadata and controls
493 lines (479 loc) · 20.8 KB
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
--[[
@description MIDI Note Randomizer
@about
#### MIDI Note Randomizer
Scale based note randomisation
Move sliders, press buttons
@donation https://www.paypal.me/RobUrquhart
@link Forum Thread http://forum.cockos.com/showthread.php?t=188774
@version 1.1
@author RobU
@changelog
v1.1
bugfixes
@provides
[main=midi_editor] .
[nomain] eugen27771 GUI.lua
Reaper 5.x
Extensions: None
Licenced under the GPL v3
--]]
--------------------------------------------------------------------------------
-- REQUIRES
--------------------------------------------------------------------------------
package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])[^\/]-$]] .."?.lua;".. package.path
require 'eugen27771 GUI'
--------------------------------------------------------------------------------
-- GLOBAL VARIABLES START
--------------------------------------------------------------------------------
m = {}
m.win_x = 700; m.win_y = 280
m.winCol = {0, 0, 0}; m.h1FontCol = {.7, .7, .7, .9}; m.stdFontCol = {.7, .7, .7, .9}
-- default octave, key, and root (root = octave + key)
m.oct = 4; m.key = 1; m.root = 0 -- due to some quirk, m.oct=4 is really octave 3...
-- note tables - b & c for note mangling, a for restoring the original take
m.allNotesF = false
m.notebuf = {a = {}, b = {}, c = {}}
m.dupes = {}
m.notes = {'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C'}
m.scales = {
{0,1,2,3,4,5,6,7,8,9,10,11,12,name="Chromatic"},
{0,2,4,5,7,9,11,12,name="Ionian / Major"},
{0,2,3,5,6,9,10,12,name="Dorian"},
{0,1,3,5,7,8,10,12,name="Phrygian"},
{0,2,4,6,7,9,11,12,name="Lyndian"},
{0,2,4,5,7,9,10,12,name="Mixolydian"},
{0,2,3,5,7,8,10,12,name="Aeolian / Minor"},
{0,1,3,5,6,8,10,12,name="Locrian"},
{0,3,5,6,7,10,12,name="Blues"},
{0,2,4,7,9,12,name="Pentatonic Major"},
{0,3,5,7,10,12,name="Pentatonic Minor"}
-- scales available to the randomization engine, more can be added if required
-- each value is the interval step from the root note of the scale (0) including the octave (12)
-- ToDo: Load / Save to disk (persistence)
-- ToDo: Allow creation of custom user scales within GUI
-- ToDo: Possibly, import and convert from Zmod ReaScale files
}
-- textual list of the available scale's names for the GUI scale list selector
m.scalelist = {}
m.curScaleName = "Chromatic"
-- ToDo get the position of the default scale in the table for the GUI, currently hard-coded elsewhere... :\
m.preNoteProbTable = {}; m.noteProbTable = {}
--------------------------------------------------------------------------------
-- GLOBAL VARIABLES END
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- UTILITY FUNCTIONS START
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- ConMsg(str) - outputs 'str' to the Reaper console
--------------------------------------------------------------------------------
local function ConMsg(str)
reaper.ShowConsoleMsg(str .."\n")
end
--------------------------------------------------------------------------------
-- Wrap(n, max) wrap an integer 'n' to 'max'
--------------------------------------------------------------------------------
local function Wrap (n, max)
n = n % max
if (n < 1) then n = n + max end
return n
end
--------------------------------------------------------------------------------
-- RGB2Packed(r, g, b) - returns a packed rgb
--------------------------------------------------------------------------------
local function RGB2Packed(r, g, b)
g = (g << 8)
b = (b << 16)
return math.floor(r + g + b)
end
--------------------------------------------------------------------------------
-- Packed2RGB(p) - returns r, g, b from a packed rgb value
--------------------------------------------------------------------------------
local function Packed2RGB(p)
local b, lsb, g, lsg, r = 0, 0, 0, 0, 0
b = (p >> 16); lsb = (b << 16); p = p - lsb
g = (p >> 8); lsg = (g << 8); p = p - lsg
return math.floor(p), math.floor(g), math.floor(b)
end
--------------------------------------------------------------------------------
-- RGB2Dec(r, g, b) - returns 8 bit r, g, b as decimal values (0 to 1)
--------------------------------------------------------------------------------
local function RGB2Dec(r, g, b)
if r < 0 or r > 255 then r = wrap(r,255) end
if g < 0 or g > 255 then g = wrap(g,255) end
if b < 0 or b > 255 then b = wrap(b,255) end
return r/255, g/255, b/255
end
--------------------------------------------------------------------------------
-- UTILITY FUNCTIONS END
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- FUNCTIONS START
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- ClearTable(t) - for 2d tables
--------------------------------------------------------------------------------
function ClearTable(t)
for k, v in pairs(t) do
t[k] = nil
end
end
--------------------------------------------------------------------------------
-- GetNotesFromTake(t) - fill note buffer 't' from the active take
--------------------------------------------------------------------------------
function GetNotesFromTake(t)
local i
local activeEditor = reaper.MIDIEditor_GetActive()
local activeTake = reaper.MIDIEditor_GetTake(activeEditor)
local _retval, selected, muted, startppq, endppq, channel, pitch, velocity
if activeTake then
local _retval, num_notes, num_cc, num_sysex = reaper.MIDI_CountEvts(activeTake)
if num_notes > 0 then
ClearTable(t)
for i = 1, num_notes do
_retval, selected, muted, startppq, endppq, channel, pitch, velocity = reaper.MIDI_GetNote(activeTake, i-1)
t[i] = {}
t[i][1] = selected
t[i][2] = muted
t[i][3] = startppq
t[i][4] = endppq
t[i][5] = endppq-startppq
t[i][6] = channel
t[i][7] = pitch
t[i][8] = velocity
end -- for i
end -- num_notes
else -- active take
ConMsg("No Active Take")
end --if activeTake
end
--------------------------------------------------------------------------------
-- CopyNotes(t1, t2) - copies note data from t1 to t2
--------------------------------------------------------------------------------
function CopyNotes(t1, t2)
ClearTable(t2)
local i = 1
while t1[i] do
local j = 1
t2[i] = {}
while (t1[i][j] ~= nil) do
t2[i][j] = t1[i][j]
j = j + 1
end -- while (t1[i][j]
i = i + 1
end -- while t1[i]
end
--------------------------------------------------------------------------------
-- DeleteNotes() - delete all notes from the active take
--------------------------------------------------------------------------------
function DeleteNotes()
local activeEditor = reaper.MIDIEditor_GetActive()
local activeTake = reaper.MIDIEditor_GetTake(activeEditor)
local i = 0
if activeTake then
__, num_notes, __, __ = reaper.MIDI_CountEvts(activeTake)
for i = 0, num_notes do
reaper.MIDI_DeleteNote(activeTake, 0)
end --for
else
ConMsg("Midi Mangler - No Active Take")
end -- activeTake
end
--------------------------------------------------------------------------------
-- SetRootNote(octave, key) - returns new root midi note
--------------------------------------------------------------------------------
function SetRootNote(octave, key)
local o = octave * 12
local k = key - 1
return o + k
end
--------------------------------------------------------------------------------
-- GenProbTable(preProbTable, slidersTable, probTable)
--------------------------------------------------------------------------------
function GenProbTable(preProbTable, sliderTable, probTable)
local i, j, k, l = 1, 1, 1, 1
local floor = math.floor
ClearTable(probTable)
for i, v in ipairs(preProbTable) do
if sliderTable[j].norm_val > 0 then
for l = 1, (sliderTable[j].norm_val * 10) do
probTable[k] = preProbTable[i]
k = k + 1
end -- l
end -- sliderTable[j]
j = j + 1
end
end
--------------------------------------------------------------------------------
-- SetScale()
--------------------------------------------------------------------------------
function SetScale(scaleName, allScales, scale)
-- triggered by scale choice in GUI (Dropbox03)
ClearTable(scale)
for i = 1, #allScales, 1 do
if scaleName == allScales[i].name then
for k, v in pairs(allScales[i]) do
scale[k] = v
end
break
end
end
end
--------------------------------------------------------------------------------
-- UpdateSliderLabels() - Set the note probability slider labels to match the scale
--------------------------------------------------------------------------------
function UpdateSliderLabels(sliderTable, preProbTable)
for k, v in pairs(sliderTable) do
if preProbTable[k] then
sliderTable[k].label = m.notes[Wrap((preProbTable[k] + 1) + m.root, 12)]
if sliderTable[k].norm_val == 0 then sliderTable[k].norm_val = 0.1 end
else
sliderTable[k].label = ""
sliderTable[k].norm_val = 0
end
end
end
--------------------------------------------------------------------------------
-- GetUniqueNote()
--------------------------------------------------------------------------------
function GetUniqueNote(tNotes, noteIdx, noteProbTable)
newNote = m.root + noteProbTable[math.random(1,#noteProbTable)]
if #m.dupes == 0 then
m.dupes.i = 1; m.dupes[m.dupes.i] = {}
m.dupes[m.dupes.i].srtpos = tNotes[noteIdx][3]
m.dupes[m.dupes.i].endpos = tNotes[noteIdx][4]
m.dupes[m.dupes.i].midi = newNote
return newNote
elseif tNotes[noteIdx][3] >= m.dupes[m.dupes.i].srtpos
and tNotes[noteIdx][3] < m.dupes[m.dupes.i].endpos then
m.dupes.i = m.dupes.i + 1; m.dupes[m.dupes.i] = {}
m.dupes[m.dupes.i].srtpos = tNotes[noteIdx][3]
m.dupes[m.dupes.i].endpos = tNotes[noteIdx][4]
unique = false
while not unique do
newNote = m.root + noteProbTable[math.random(1,#noteProbTable)]
unique = true
for i = 1, m.dupes.i - 1 do
if m.dupes[i].midi == newNote then unique = false end
end -- m.dupes.i
end -- not unique
m.dupes[m.dupes.i].midi = newNote
return newNote
else
m.dupes = {}; m.dupes.i = 1; m.dupes[m.dupes.i] = {}
m.dupes[m.dupes.i].srtpos = tNotes[noteIdx][3]
m.dupes[m.dupes.i].endpos = tNotes[noteIdx][4]
m.dupes[m.dupes.i].midi = newNote
return newNote
end
end
--------------------------------------------------------------------------------
-- RandomiizeNotes(notebufs t1,t2, noteProbTable)
--------------------------------------------------------------------------------
function RandomiizeNotes(t1, noteProbTable)
m.dupes.i = 1
local i = 1
while t1[i] do
if t1[i][1] == true or m.allNotesF == true then -- if selected, or all notes flag is true
t1[i][7] = GetUniqueNote(t1, i, noteProbTable)
end
i = i + 1
end -- while t1[i]
InsertNotes(t1)
end
--------------------------------------------------------------------------------
-- InsertNotes(note_buffer) - insert notes in the active take
--------------------------------------------------------------------------------
function InsertNotes(t1)
reaper.MIDIEditor_OnCommand(activeEditor, 40435)
DeleteNotes()
local i = 1
local activeEditor = reaper.MIDIEditor_GetActive()
local active_take = reaper.MIDIEditor_GetTake(activeEditor)
while t1[i] do
reaper.MIDI_InsertNote(active_take, t1[i][1], t1[i][2], t1[i][3], t1[i][4], t1[i][6], t1[i][7], t1[i][8], true)
--1=selected, 2=muted, 3=startppq, 4=endppq, 5=len, 6=chan, 7=pitch, 8=vel, noSort)
i = i + 1
end -- while t1[i]
reaper.MIDI_Sort(active_take)
reaper.MIDIEditor_OnCommand(activeEditor, 40435)
end --function SetNotes
--------------------------------------------------------------------------------
-- FUNCTIONS END
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- GUI - LAYOUT START
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Create GUI Elements
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Main Window
--------------------------------------------------------------------------------
-- Frame
local frameWnd = Frame:new(10, 10, m.win_x - 20, m.win_y - 20, 0.7, 0.7, 0.7, 0.5)
-- Textbox
local txtHeader = Textbox:new(20, 20, m.win_x-40, 30, 0.5, 0.5, 0.5, 0.4, "MIDI Note Randomizer", "Arial", 18, m.h1FontCol)
--------------------------------------------------------------------------------
-- Notes Section
--------------------------------------------------------------------------------
-- Note section Frame
local frameNotes = Frame:new(10, 10, m.win_x - 20, m.win_y - 20, 0.7, 0.7, 0.7, 0.5)
-- root/MIDI note, octave, & scale droplists
dx, dy, dw, dh = 25, 90, 110, 20
local dropKey = Droplist:new(dx, dy, dw, dh, 0.3, 0.5, 0.7, 0.5, "Root Note", "Arial", 15, m.stdFontCol, m.key,m.notes)
local dropOctave = Droplist:new(dx, dy+45, dw, dh, 0.3, 0.5, 0.7, 0.5, "Octave " ,"Arial", 15, m.stdFontCol, m.oct,{0, 1, 2, 3, 4, 5, 6, 7})
local dropScale = Droplist:new(dx, dy+90, dw, dh, 0.3, 0.5, 0.7, 0.5, "Scale", "Arial", 15, m.stdFontCol, 1, m.scalelist)
-- Droplist table
local t_Droplists = {dropKey, dropOctave, dropScale}
-- Buttons
local bx, by, bw, bh = 0, 300, 200, 30
local btnMangle = Button:new(25, 225, 110, 25, 0.3, 0.5, 0.3, 0.5, "Randomize", "Arial", 15, m.stdFontCol)
-- Note weight sliders
local nx, ny, nw, nh, np = 160, 70, 30, 150, 40
local noteSldr01 = Vert_Slider:new(nx, ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr02 = Vert_Slider:new(nx+(np*1), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr03 = Vert_Slider:new(nx+(np*2), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr04 = Vert_Slider:new(nx+(np*3), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr05 = Vert_Slider:new(nx+(np*4), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr06 = Vert_Slider:new(nx+(np*5), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr07 = Vert_Slider:new(nx+(np*6), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr08 = Vert_Slider:new(nx+(np*7), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr09 = Vert_Slider:new(nx+(np*8), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr10 = Vert_Slider:new(nx+(np*9), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr11 = Vert_Slider:new(nx+(np*10), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr12 = Vert_Slider:new(nx+(np*11), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
local noteSldr13 = Vert_Slider:new(nx+(np*12), ny, nw, nh, 0.3, 0.5, 0.7, 0.5, "", "Arial", 15, m.stdFontCol, 0.1)
-- Note weight slider table
local t_noteSliders = {noteSldr01, noteSldr02, noteSldr03, noteSldr04, noteSldr05, noteSldr06, noteSldr07,
noteSldr08, noteSldr09, noteSldr10, noteSldr11, noteSldr12, noteSldr13}
-- Note weight slider label (Textbox)
local txtProbSliderLabel = Textbox:new(nx, 230, 510, 20, 0.5, 0.5, 0.5, 0.4, "Note Weight Sliders", "Arial",15, m.stdFontCol)
--------------------------------------------------------------------------------
-- Shared Element Tables
--------------------------------------------------------------------------------
local t_Buttons = {btnMangle}
local t_Frames = {frameWnd}
local t_Textboxes = {txtHeader, txtProbSliderLabel}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- GUI Element Functions START
--------------------------------------------------------------------------------
-- Buttons
--------------------------------------------------------------------------------
-- Notes
btnMangle.onClick = function()
GetNotesFromTake(m.notebuf.a)
GenProbTable(m.preNoteProbTable, t_noteSliders, m.noteProbTable)
RandomiizeNotes(m.notebuf.a, m.noteProbTable)
end
--------------------------------------------------------------------------------
-- Droplists
--------------------------------------------------------------------------------
-- Root Key
dropKey.onClick = function()
m.key = dropKey.norm_val
m.root = SetRootNote(m.oct, m.key)
UpdateSliderLabels(t_noteSliders, m.preNoteProbTable)
end
-- Octave
dropOctave.onClick = function()
m.oct = dropOctave.norm_val
m.root = SetRootNote(m.oct, m.key)
end
-- Scale
dropScale.onClick = function()
SetScale(dropScale.norm_val2[dropScale.norm_val], m.scales, m.preNoteProbTable)
UpdateSliderLabels(t_noteSliders, m.preNoteProbTable)
end
--------------------------------------------------------------------------------
-- GUI Element Functions END
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- GUI LAYOUT END
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- GUI - Main DRAW function
--------------------------------------------------------------------------------
function DrawGUI()
for key, frame in pairs(t_Frames) do frame:draw() end
for key, btn in pairs(t_Buttons) do btn:draw() end
for key, dlist in pairs(t_Droplists) do dlist:draw() end
for key, nsldrs in pairs(t_noteSliders) do nsldrs:draw() end
for key, textb in pairs(t_Textboxes) do textb:draw() end
end
--------------------------------------------------------------------------------
-- INIT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- InitRandomizer
--------------------------------------------------------------------------------
function InitRandomizer()
math.randomseed(os.time())
for i = 1, 10 do math.random() end -- lua quirk, but the first random call always returns the same value...
reaper.ClearConsole()
m.root = SetRootNote(m.oct, m.key) -- set the root note (should match the gui..)
for k, v in pairs(m.scales) do --create a scale list for the gui
m.scalelist[k] = m.scales[k]["name"]
end
ClearTable(m.preNoteProbTable)
SetScale(m.curScaleName, m.scales, m.preNoteProbTable)
UpdateSliderLabels(t_noteSliders, m.preNoteProbTable)
GenProbTable(m.preNoteProbTable, t_noteSliders, m.noteProbTable)
GetNotesFromTake(m.notebuf.a) --fill note buffer
end
--------------------------------------------------------------------------------
-- InitGFX
--------------------------------------------------------------------------------
function InitGFX()
-- Some gfx Wnd Default Values --
local R, G, B = 0, 0, 0 -- 0..255 form
local Win_Bgd = R + G*256 + B*65536 -- red+green*256+blue*65536
local Win_Title = "RobU - MIDI Note Randomizer (v1.1)"
local Win_Dock, Wnd_X, Wnd_Y = 0, 25, 25
Win_Width, Win_Height = m.win_x, m.win_y -- global values(used for define zoom level)
-- Init window ------
gfx.clear = Win_Bgd
gfx.init( Win_Title, Win_Width,Win_Height, Win_Dock, Wnd_X,Wnd_Y )
-- Init mouse last --
last_mouse_cap = 0
last_x, last_y = 0, 0
mouse_ox, mouse_oy = -1, -1
end
--------------------------------------------------------------------------------
-- Mainloop
--------------------------------------------------------------------------------
function mainloop()
-- zoom level
Z_w, Z_h = gfx.w/Win_Width, gfx.h/Win_Height
if Z_w<0.6 then Z_w = 0.6 elseif Z_w>2 then Z_w = 2 end
if Z_h<0.6 then Z_h = 0.6 elseif Z_h>2 then Z_h = 2 end
-- mouse and modkeys --
if gfx.mouse_cap & 1 == 1 and last_mouse_cap & 1 == 0 or -- L mouse
gfx.mouse_cap & 2 == 2 and last_mouse_cap & 2 == 0 or -- R mouse
gfx.mouse_cap & 64 == 64 and last_mouse_cap & 64 == 0 then -- M mouse
mouse_ox, mouse_oy = gfx.mouse_x, gfx.mouse_y
end
Ctrl = gfx.mouse_cap & 4 == 4
Shift = gfx.mouse_cap & 8 == 8
Alt = gfx.mouse_cap & 16 == 16 -- Shift state
DrawGUI()
-- update mouse
last_mouse_cap = gfx.mouse_cap
last_x, last_y = gfx.mouse_x, gfx.mouse_y
gfx.mouse_wheel = 0 -- reset gfx.mouse_wheel
-- play/stop
char = gfx.getchar()
if char == 32 then reaper.Main_OnCommand(40044, 0) end
-- defer
if char ~= -1 and char ~= 27 then reaper.defer(mainloop) end
gfx.update()
end
--------------------------------------------------------------------------------
-- RUN
--------------------------------------------------------------------------------
InitGFX()
InitRandomizer()
mainloop()
--------------------------------------------------------------------------------