@gorilla-engine-sdk/create-gorilla-engine-plugin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/LICENSE.md +64 -0
  2. package/README.md +103 -0
  3. package/generator-gorilla-engine-plugin/app/index.js +338 -0
  4. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/SKILL.md +295 -0
  5. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/effects-filters.md +186 -0
  6. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/indexing.md +129 -0
  7. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/instrument-files.md +547 -0
  8. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/key-rules.md +81 -0
  9. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/modulation.md +210 -0
  10. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/module-control.md +217 -0
  11. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/module-reference-bus-effects.md +663 -0
  12. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/module-reference-core.md +145 -0
  13. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/module-reference-misc.md +59 -0
  14. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/module-reference-modulation.md +85 -0
  15. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/module-reference-voice-effects.md +407 -0
  16. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/note-events.md +278 -0
  17. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/properties.md +230 -0
  18. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/script-patterns.md +494 -0
  19. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-dsp/references/time-tempo.md +209 -0
  20. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/SKILL.md +104 -0
  21. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/advanced-controls.md +194 -0
  22. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/base-props.md +167 -0
  23. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/basic-controls.md +230 -0
  24. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/bindings.md +183 -0
  25. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/composite-components.md +258 -0
  26. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/containers.md +149 -0
  27. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/editors.md +191 -0
  28. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/event-handlers.md +150 -0
  29. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/getting-started.md +143 -0
  30. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/gorilla-engine-api.md +147 -0
  31. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/instrument-api.md +250 -0
  32. package/generator-gorilla-engine-plugin/app/templates/.agents/skills/gorilla-engine-ui/references/visualization.md +209 -0
  33. package/generator-gorilla-engine-plugin/app/templates/.prettierignore +13 -0
  34. package/generator-gorilla-engine-plugin/app/templates/.vscode/settings.json +14 -0
  35. package/generator-gorilla-engine-plugin/app/templates/.vscode_input/launch.json +89 -0
  36. package/generator-gorilla-engine-plugin/app/templates/README.md +36 -0
  37. package/generator-gorilla-engine-plugin/app/templates/assets/fonts/OFL.txt +93 -0
  38. package/generator-gorilla-engine-plugin/app/templates/assets/fonts/Roboto-Bold.otf +0 -0
  39. package/generator-gorilla-engine-plugin/app/templates/assets/fonts/Roboto-Medium.otf +0 -0
  40. package/generator-gorilla-engine-plugin/app/templates/assets/fonts/Roboto-Regular.otf +0 -0
  41. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/Presets/Factory/Category 1/Init.preset +1 -0
  42. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/Presets/Factory/Category 1/Three Quarters.preset +1 -0
  43. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/Horizontal Slider.png +0 -0
  44. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/Horizontal Slider@2x.png +0 -0
  45. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/Rotary Bipolar.png +0 -0
  46. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/Rotary-Bipolar@2x.png +0 -0
  47. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/Rotary.png +0 -0
  48. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/Rotary@2x.png +0 -0
  49. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-down-default.png +0 -0
  50. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-down-default@2x.png +0 -0
  51. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-down-hover.png +0 -0
  52. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-down-hover@2x.png +0 -0
  53. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-down-pressed.png +0 -0
  54. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-down-pressed@2x.png +0 -0
  55. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-up-default.png +0 -0
  56. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-up-default@2x.png +0 -0
  57. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-up-hover.png +0 -0
  58. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-up-hover@2x.png +0 -0
  59. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-up-pressed.png +0 -0
  60. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/arrow-up-pressed@2x.png +0 -0
  61. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/toggle-default.png +0 -0
  62. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/toggle-default@2x.png +0 -0
  63. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/toggle-pressed.png +0 -0
  64. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/images/toggle-pressed@2x.png +0 -0
  65. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/instruments/Basic Synth Example_part1.blob +0 -0
  66. package/generator-gorilla-engine-plugin/app/templates/basic-synth/assets/instruments/Basic Synth Example_part2.blob +1 -0
  67. package/generator-gorilla-engine-plugin/app/templates/basic-synth/instrument/Basic Synth Example.inst +157 -0
  68. package/generator-gorilla-engine-plugin/app/templates/basic-synth/instrument/Basic Synth Example.txt +184 -0
  69. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/app/Root.tsx +35 -0
  70. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/app/components/ErrorBoundary.tsx +138 -0
  71. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/app/components/UserInterface.tsx +338 -0
  72. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/app/pluginConfig.ts +4 -0
  73. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/dialogsCustomStyle.ts +98 -0
  74. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/index.tsx +217 -0
  75. package/generator-gorilla-engine-plugin/app/templates/basic-synth/src/presetBrowserCustomStyle.ts +124 -0
  76. package/generator-gorilla-engine-plugin/app/templates/build.ugep +173 -0
  77. package/generator-gorilla-engine-plugin/app/templates/effect/assets/Presets/Factory/Category 1/01 - All The Way Down.preset +1 -0
  78. package/generator-gorilla-engine-plugin/app/templates/effect/assets/Presets/Factory/Category 1/02 - About Half.preset +1 -0
  79. package/generator-gorilla-engine-plugin/app/templates/effect/assets/Presets/Factory/Category 1/03 - Three Quarters.preset +1 -0
  80. package/generator-gorilla-engine-plugin/app/templates/effect/assets/Presets/Factory/Category 1/04 - All The Way Up.preset +1 -0
  81. package/generator-gorilla-engine-plugin/app/templates/effect/assets/images/Rotary.png +0 -0
  82. package/generator-gorilla-engine-plugin/app/templates/effect/assets/images/Rotary@2x.png +0 -0
  83. package/generator-gorilla-engine-plugin/app/templates/effect/assets/instruments/Reverb Example_part1.blob +0 -0
  84. package/generator-gorilla-engine-plugin/app/templates/effect/assets/instruments/Reverb Example_part2.blob +1 -0
  85. package/generator-gorilla-engine-plugin/app/templates/effect/instrument/Reverb Example.inst +73 -0
  86. package/generator-gorilla-engine-plugin/app/templates/effect/instrument/Reverb Example.txt +21 -0
  87. package/generator-gorilla-engine-plugin/app/templates/effect/src/app/Root.tsx +35 -0
  88. package/generator-gorilla-engine-plugin/app/templates/effect/src/app/components/ErrorBoundary.tsx +114 -0
  89. package/generator-gorilla-engine-plugin/app/templates/effect/src/app/components/UserInterface.tsx +85 -0
  90. package/generator-gorilla-engine-plugin/app/templates/effect/src/app/pluginConfig.ts +4 -0
  91. package/generator-gorilla-engine-plugin/app/templates/effect/src/dialogsCustomStyle.ts +101 -0
  92. package/generator-gorilla-engine-plugin/app/templates/effect/src/index.tsx +214 -0
  93. package/generator-gorilla-engine-plugin/app/templates/effect/src/presetBrowserCustomStyle.ts +124 -0
  94. package/generator-gorilla-engine-plugin/app/templates/gitignore +9 -0
  95. package/generator-gorilla-engine-plugin/app/templates/licence.txt +0 -0
  96. package/generator-gorilla-engine-plugin/app/templates/package.json +38 -0
  97. package/generator-gorilla-engine-plugin/app/templates/prettierrc +9 -0
  98. package/generator-gorilla-engine-plugin/app/templates/tsconfig.json +20 -0
  99. package/generator-gorilla-engine-plugin/package.json +17 -0
  100. package/index.js +72 -0
  101. package/package.json +42 -0
@@ -0,0 +1,230 @@
1
+ # Properties Reference
2
+
3
+ Properties are declared in `on init` and serve as both script variables and plugin parameters. They bridge the script to the UI — when a user changes a knob/slider bound to a property, the script receives the new value in an `on <property>` callback.
4
+
5
+ ## Property Types
6
+
7
+ ### prop_linear — Linear Range
8
+
9
+ ```
10
+ prop_linear <name>(min, max, scaling) [= default]
11
+ ```
12
+
13
+ Display = value / scaling. Most common property type.
14
+
15
+ ```
16
+ prop_linear Volume(0, 1000, 10) = 500 ' display 0.0 to 100.0, default 50.0
17
+ prop_linear Tune(-1200, 1200, 100) ' display -12.00 to 12.00
18
+ prop_linear Mix(0, 100, 1) = 50 ' display 0 to 100
19
+ set_prop_param(Mix, PROP_UNITS, "%")
20
+ ```
21
+
22
+ ### prop_boolean — On/Off Switch
23
+
24
+ ```
25
+ prop_boolean <name> [= default]
26
+ ```
27
+
28
+ Value is 0 or 1.
29
+
30
+ ```
31
+ prop_boolean Mute
32
+ prop_boolean Retrigger = 1
33
+ ```
34
+
35
+ ### prop_exp — Exponential (Frequencies, Rates, Envelope Times)
36
+
37
+ ```
38
+ prop_exp <name>(max, displayMin, displayMax) [= default]
39
+ ```
40
+
41
+ Value is linear 0..max in script. Display is exponential displayMin/1000 to displayMax/1000. Negative displayMin means display 0 at zero and -displayMin/1000 at 1% position.
42
+
43
+ ```
44
+ prop_exp Cutoff(1000000, 20000, 25000000) = 549000 ' 20 Hz to 25 kHz, default ~1 kHz
45
+ prop_exp Rate(1000000, 10, 100000) = 500000 ' 0.01 to 100 Hz, default 1 Hz
46
+ prop_exp Decay(1000000, -10, 16000) ' 0.0 to 16.0 sec, 10ms at 1%
47
+ prop_exp Glide_Time(1000000, 0, 10000) = 250000
48
+ set_prop_param(Glide_Time, PROP_UNITS, "sec")
49
+ ```
50
+
51
+ ### prop_decibels — Volume in dB
52
+
53
+ ```
54
+ prop_decibels <name>(max, dBmax) [= default]
55
+ ```
56
+
57
+ Cube-law dB display. Value is linear 0..max. Display is -inf to dBmax.
58
+
59
+ ```
60
+ prop_decibels Volume(1000000, 12) ' 0 to +12.0 dB
61
+ prop_decibels Master(1000000, 0) ' -inf to 0.0 dB
62
+ ```
63
+
64
+ ### prop_squared — Square-Law (Pre-Delay, Ratios)
65
+
66
+ ```
67
+ prop_squared <name>(min, max, displayMin, displayMax) [= default]
68
+ ```
69
+
70
+ Square-law display. Midpoint of slider = 25% of max.
71
+
72
+ ```
73
+ prop_squared Delay(0, 1000000, 0, 25) ' 0.0 to 25.0 ms
74
+ prop_squared Ratio(0, 1000000, 1, 20) ' 1.0 to 20.0
75
+ prop_squared Depth(-1000000, 1000000, -100, 100) ' bipolar with square scaling
76
+ ```
77
+
78
+ ### prop_stepped — Discrete Named Steps
79
+
80
+ ```
81
+ prop_stepped <name> [= default]
82
+ add_step(<name>, "label")
83
+ ```
84
+
85
+ Values are 0, 1, 2... in order of `add_step()` calls.
86
+
87
+ ```
88
+ prop_stepped Mode = 1
89
+ add_step(Mode, "Retrig"); const MODE_RETRIG = 0
90
+ add_step(Mode, "Legato"); const MODE_LEGATO = 1
91
+ add_step(Mode, "Repitch"); const MODE_REPITCH = 2
92
+
93
+ prop_stepped Rate = 6
94
+ add_step(Rate, "1/4")
95
+ add_step(Rate, "1/8")
96
+ add_step(Rate, "1/16")
97
+ var rateToPPQ[3] = (960, 480, 240)
98
+ ```
99
+
100
+ ### prop_array — Array Property
101
+
102
+ ```
103
+ prop_array <name>[size](min, max, scaling) [= (...)]
104
+ ```
105
+
106
+ Cannot be automated. Expose individual values for automation.
107
+
108
+ ```
109
+ prop_array Velocity_Curve[128](1, 127, 1)
110
+ prop_array Step_Seq[16](-12, 12, 1) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
111
+ ```
112
+
113
+ ### prop_text — Text String
114
+
115
+ ```
116
+ prop_text <name>
117
+ ```
118
+
119
+ ```
120
+ prop_text Name
121
+ prop_text Status
122
+ set_prop_param(Status, PROP_SET_BY, SET_BY_SCRIPT) ' read-only display
123
+ ```
124
+
125
+ ### prop_meter — Real-Time Measurement
126
+
127
+ ```
128
+ prop_meter <name> [size]
129
+ attach_meter(<name>, module, submodule)
130
+ ```
131
+
132
+ ```
133
+ prop_meter Level; attach_meter(Level, M_BUS+1, 0) ' bus level
134
+ prop_meter Level[2]; attach_meter(Level, M_BUS+3, 0) ' stereo
135
+ prop_meter GR; attach_meter(GR, M_BUS+1, M_EFFECT+1) ' gain reduction
136
+ prop_meter Pos; attach_meter(Pos, M_GROUP+0, 0) ' playback position
137
+ ```
138
+
139
+ ### prop_waveform — Waveform Display
140
+
141
+ ```
142
+ prop_waveform <name> [(group)]
143
+ ```
144
+
145
+ ```
146
+ prop_waveform Wave_Display
147
+ set_waveform(Wave_Display, -1, 60, 100) ' group/mapping, key, vel
148
+ ```
149
+
150
+ ## Property Configuration
151
+
152
+ ### set_prop_param(property, param, value)
153
+
154
+ **Numeric parameters:**
155
+
156
+ | Param | Description |
157
+ |-------|-------------|
158
+ | `PROP_MIDI_CC` | Assign MIDI CC (1-119) to property |
159
+ | `PROP_SET_BY` | Control who can modify (see SET_BY flags) |
160
+ | `PROP_NON_REALTIME` | Set to 1 for non-realtime-safe properties |
161
+ | `PROP_MIN` | Override minimum value |
162
+ | `PROP_MAX` | Override maximum value |
163
+
164
+ **Text parameters:**
165
+
166
+ | Param | Description |
167
+ |-------|-------------|
168
+ | `PROP_NAME` | Display name (default: name with `_` → spaces) |
169
+ | `PROP_UNITS` | Units suffix (e.g. `"%"`, `"sec"`, `"semi"`, `"Hz"`) |
170
+ | `PROP_VALUE_TEXT` | Custom display text replacing value+units |
171
+ | `PROP_GROUP` | Automation group name |
172
+ | `PROP_METADATA` | Additional info for UI |
173
+
174
+ Special units: `"L|R"` for pan controls (displays L/R instead of -/+).
175
+
176
+ ### SET_BY Flags
177
+
178
+ | Flag | Description |
179
+ |------|-------------|
180
+ | `SET_BY_HOST` | Value set externally, script receives it |
181
+ | `SET_BY_SONG` | Stored/recalled with DAW session |
182
+ | `SET_BY_PATCH` | Stored/recalled with presets |
183
+ | `SET_BY_REMOTE_AUTO` | Can be automated |
184
+ | `SET_BY_SCRIPT` | Script sets value, displayed on GUI (read-only to user) |
185
+ | `SET_BY_GUI` | GUI controls set value, script does NOT receive callback |
186
+
187
+ **Default:** `SET_BY_HOST + SET_BY_SONG + SET_BY_PATCH + SET_BY_REMOTE_AUTO`
188
+
189
+ ```
190
+ ' Read-only display property
191
+ prop_text Status
192
+ set_prop_param(Status, PROP_SET_BY, SET_BY_SCRIPT)
193
+
194
+ ' Non-automatable property
195
+ const NO_AUTO = SET_BY_HOST + SET_BY_SONG + SET_BY_PATCH
196
+ prop_stepped Source
197
+ set_prop_param(Source, PROP_SET_BY, NO_AUTO)
198
+ ```
199
+
200
+ ## Property Callbacks
201
+
202
+ Every declared property automatically gets a callback:
203
+
204
+ ```
205
+ prop_linear Volume(0, 1000000, 1) = 500000
206
+
207
+ on Volume
208
+ set_module_param(M_INST, 0, 0, 3, Volume) ' update instrument volume
209
+ end on
210
+ ```
211
+
212
+ The callback runs when:
213
+ - The UI changes the property
214
+ - The host automates the property
215
+ - The script assigns a new value to the property
216
+ - A preset is loaded
217
+
218
+ ## Property ↔ UI Binding
219
+
220
+ Properties declared in the script become instrument parameters that the React UI can bind to using `useInstrumentProperty()` or `bindings`. The property name in UI is **always lowercase**, even if declared uppercase in the script.
221
+
222
+ Script:
223
+ ```
224
+ prop_linear Cutoff(0, 1000000, 1)
225
+ ```
226
+
227
+ React UI:
228
+ ```tsx
229
+ const [cutoff, setCutoff] = useInstrumentProperty(instrument, 'cutoff');
230
+ ```
@@ -0,0 +1,494 @@
1
+ # Script Patterns Reference
2
+
3
+ Real-world patterns for common audio DSP tasks in Gorilla Engine scripts.
4
+
5
+ ## Arpeggiator
6
+
7
+ Uses `delay_ppq()` in a `while` loop to step through held notes at musical intervals. Cancel with `end_delay()`.
8
+
9
+ ```
10
+ on init
11
+ var seqCallback
12
+ var seqEvent = -1
13
+ var seqPos
14
+ var heldKeys[16]
15
+ var numHeldKeys
16
+ var i
17
+
18
+ prop_stepped Rate = 6
19
+ add_step(Rate, "1/4")
20
+ add_step(Rate, "1/8")
21
+ add_step(Rate, "1/16")
22
+ var rateToPPQ[3] = (960, 480, 240)
23
+
24
+ prop_linear Gate(0, 100, 1) = 75
25
+ set_prop_param(Gate, PROP_UNITS, "%")
26
+
27
+ prop_stepped Mode
28
+ add_step(Mode, "Up")
29
+ add_step(Mode, "Down")
30
+ add_step(Mode, "Random")
31
+ end on
32
+
33
+ function NextStep
34
+ release_note(seqEvent)
35
+
36
+ ' advance position
37
+ select Mode
38
+ case 0 ' Up
39
+ inc(seqPos)
40
+ if seqPos >= numHeldKeys
41
+ seqPos = 0
42
+ end if
43
+ case 1 ' Down
44
+ dec(seqPos)
45
+ if seqPos < 0
46
+ seqPos = numHeldKeys - 1
47
+ end if
48
+ case 2 ' Random
49
+ seqPos = random(0, numHeldKeys - 1)
50
+ end select
51
+
52
+ seqEvent = new_note(heldKeys[seqPos], 100, 0, 0)
53
+ group_on(seqEvent, ALL_GROUPS)
54
+
55
+ i = rateToPPQ[Rate]
56
+ delay_ppq((i * Gate) / 100) ' gate portion
57
+
58
+ if seqCallback = CALLBACK_ID
59
+ release_note(seqEvent)
60
+ delay_ppq(i - (i * Gate) / 100) ' rest
61
+ end if
62
+ end function
63
+
64
+ function StopSequence
65
+ var temp = seqCallback
66
+ seqCallback = 0
67
+ end_delay(temp, 0)
68
+ release_note(temp)
69
+ release_note(seqEvent)
70
+ end function
71
+
72
+ function StartSequence
73
+ if seqCallback
74
+ StopSequence()
75
+ end if
76
+ seqPos = -1
77
+ seqCallback = CALLBACK_ID
78
+ while seqCallback = CALLBACK_ID
79
+ NextStep()
80
+ end while
81
+ end function
82
+
83
+ on note
84
+ ' ... add to heldKeys, then:
85
+ group_off(EVENT_ID, ALL_GROUPS)
86
+ StartSequence()
87
+ end on
88
+
89
+ on release
90
+ ' ... remove from heldKeys
91
+ if numHeldKeys = 0
92
+ StopSequence()
93
+ else if EVENT_ID = seqCallback
94
+ ignore_event(EVENT_ID)
95
+ end if
96
+ end on
97
+ ```
98
+
99
+ ## Mono / Legato / Glide
100
+
101
+ Maintains a held-note stack. When in mono mode, one voice is re-used with pitch changes instead of creating new voices.
102
+
103
+ ### Simple Mono with Glide via EVENT_PARAM
104
+
105
+ ```
106
+ on init
107
+ prop_boolean Mono = 1
108
+ prop_exp Glide_Time(1000000, 0, 10000) = 250000
109
+ set_prop_param(Glide_Time, PROP_UNITS, "sec")
110
+
111
+ var heldNotes[128]
112
+ var numHeldNotes
113
+ var currentEvent = 0
114
+ var i
115
+ end on
116
+
117
+ on Glide_Time
118
+ ' Set smoothing on the mod routing from Event Param 0 to Tune
119
+ set_module_param(M_GROUP+0, 0, M_MOD+4, 6, Glide_Time)
120
+ end on
121
+
122
+ on note
123
+ ' ... add EVENT_KEY to heldNotes ...
124
+ if Mono
125
+ ignore_event(EVENT_ID)
126
+ if currentEvent = 0
127
+ currentEvent = new_note(60, EVENT_VEL, 0, 0)
128
+ end if
129
+ set_event_param(currentEvent, EVENT_PARAM_0, 83333 * (EVENT_KEY - 60))
130
+ end if
131
+ end on
132
+
133
+ on release
134
+ ' ... remove from heldNotes ...
135
+ if Mono and numHeldNotes
136
+ set_event_param(currentEvent, EVENT_PARAM_0, 83333 * (heldNotes[numHeldNotes-1] - 60))
137
+ else if currentEvent
138
+ release_note(currentEvent)
139
+ currentEvent = 0
140
+ end if
141
+ end on
142
+ ```
143
+
144
+ ### Glide via ModSourceCustom + set_controller (CC Bridge)
145
+
146
+ A second approach where the glide curve shape and speed are controlled by a `ModSourceCustom` whose internal timing is driven by a MIDI CC. The script forwards a UI property to the CC; the instrument's mod matrix does the rest.
147
+
148
+ **Required .inst topology** — set up in Gorilla Editor (`ModSourceCustom` is Tier 3 and cannot be written as JSON):
149
+ 1. Add a `ModSourceCustom` to the group (e.g. `"Glide Curve"`)
150
+ 2. Inside it, add a `ModRouting`: `Source: "MIDI CC"`, `CC: 5`, `Dest: "Time 1"`, `Curve Active: "On"` with a timing curve baked in
151
+ 3. Add a group-level `ModRouting` from this mod source to `Dest: "Tune"`
152
+
153
+ ```
154
+ on init
155
+ prop_linear Glide_Time(0, 127, 1) = 64 ' range matches CC 0–127
156
+ end on
157
+
158
+ on Glide_Time
159
+ set_controller(5, Glide_Time) ' CC 5 → Custom Env "Time 1" → glide speed
160
+ end on
161
+ ```
162
+
163
+ **Advantage over EVENT_PARAM + Smooth:** The glide curve shape is fully editable in the editor; you can have non-linear glide responses without any additional script logic.
164
+
165
+ **General CC Bridge rule:** `set_controller(cc, value)` broadcasts to all mod routings with a matching MIDI CC source — one script line drives any number of mod matrix destinations simultaneously.
166
+
167
+ ```
168
+ prop_stepped Mono_Mode = 2
169
+ add_step(Mono_Mode, "Retrig") ' release + new note
170
+ add_step(Mono_Mode, "Repitch") ' set_tune on existing voice
171
+ add_step(Mono_Mode, "Xfade") ' crossfade old→new at playback position
172
+
173
+ function legatoTrigger
174
+ select Mono_Mode
175
+ case 0 ' Retrig
176
+ release_note(monoEvent)
177
+ monoEvent = new_note(newKey, newVel, 0, 0)
178
+
179
+ case 1 ' Repitch
180
+ set_event_param(monoEvent, EVENT_PARAM_0, ...)
181
+
182
+ case 2 ' Crossfade
183
+ fade_out(monoEvent, 1000 * Xfade_Length, 1)
184
+ monoEvent = new_note(newKey, newVel, get_event_param(monoEvent, EVENT_PARAM_PLAY_POS), 0)
185
+ fade_in(monoEvent, 1000 * Xfade_Length)
186
+ delay(1)
187
+ set_mod_sources(monoEvent, oldEvent, 1023, 0) ' copy envelope state
188
+ end select
189
+ end function
190
+ ```
191
+
192
+ ## Round Robin
193
+
194
+ Cycle through alternate sample sets using `EVENT_PARAM_ALT_MAPPING`.
195
+
196
+ ```
197
+ on init
198
+ const MAX_RR = 5
199
+ var rr_value
200
+ var rr_time
201
+
202
+ prop_stepped RR_Mode
203
+ add_step(RR_Mode, "Cycle")
204
+ add_step(RR_Mode, "Random")
205
+ add_step(RR_Mode, "Random Excl.")
206
+
207
+ prop_linear RR_Min_Time(0, 100, 1) = 50
208
+ set_prop_param(RR_Min_Time, PROP_UNITS, "ms")
209
+ end on
210
+
211
+ on note
212
+ var now = TIME_MSEC
213
+ if now - rr_time >= RR_Min_Time
214
+ select RR_Mode
215
+ case 0; rr_value = (rr_value + 1) mod MAX_RR
216
+ case 1; rr_value = random(0, MAX_RR - 1)
217
+ case 2; rr_value = (rr_value + random(1, MAX_RR - 1)) mod MAX_RR
218
+ end select
219
+ rr_time = now
220
+ end if
221
+ set_event_param(EVENT_ID, EVENT_PARAM_ALT_MAPPING, rr_value)
222
+ end on
223
+ ```
224
+
225
+ ## Crossfade Between Layers
226
+
227
+ Crossfade between groups using MIDI CCs or direct module params.
228
+
229
+ ### Using CC-controlled mod routings
230
+
231
+ ```
232
+ ' Each group has a mod routing: CC(n) → Volume
233
+ ' Script sets CC values for each group to control crossfade
234
+
235
+ on init
236
+ const MAX_LAYERS = 5
237
+ var currentLayer
238
+ var x
239
+
240
+ prop_linear Num_Layers(1, MAX_LAYERS, 1) = MAX_LAYERS
241
+ prop_boolean Equal_Power = 1
242
+ end on
243
+
244
+ function update_crossfade
245
+ if x = 127
246
+ x = 128 * (Num_Layers - 1)
247
+ else
248
+ x = x * (Num_Layers - 1)
249
+ end if
250
+
251
+ var layer = x >> 7
252
+ var fade = x .and. 127
253
+
254
+ ' Silence old layers
255
+ if currentLayer != layer
256
+ set_controller(currentLayer, 0)
257
+ set_controller(currentLayer + 1, 0)
258
+ currentLayer = layer
259
+ end if
260
+
261
+ var ep = 0
262
+ if Equal_Power
263
+ ep = (fade * (127 - fade)) / 152
264
+ end if
265
+
266
+ set_controller(currentLayer, 127 - fade + ep)
267
+ set_controller(currentLayer + 1, fade + ep)
268
+ end function
269
+
270
+ on controller
271
+ if EVENT_CC = 1
272
+ x = CC[1]
273
+ update_crossfade()
274
+ end if
275
+ end on
276
+ ```
277
+
278
+ ### Using FilterDownmix (multi-channel crossfade)
279
+
280
+ ```
281
+ ' For multi-channel samples with a Downmix voice effect
282
+ function set_channel_mix
283
+ set_module_param(M_GROUP+0, M_FILTER+1, 0, param, value) ' L
284
+ set_module_param(M_GROUP+0, M_FILTER+1, 0, param + 1, value) ' R
285
+ end function
286
+ ```
287
+
288
+ ## Step Sequencer
289
+
290
+ Step through a pitch sequence using held notes as the base key.
291
+
292
+ ```
293
+ on init
294
+ prop_array Step_Seq[16](-12, 12, 1) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
295
+ prop_linear Steps(1, 16, 1) = 16
296
+
297
+ var seqPos
298
+ var seqEvent = -1
299
+ ' ... sequencer variables ...
300
+ end on
301
+
302
+ function NextStep
303
+ release_note(seqEvent)
304
+ inc(seqPos)
305
+ if seqPos >= Steps
306
+ seqPos = 0
307
+ end if
308
+ seqEvent = new_note(heldKeys[numHeldKeys-1] + Step_Seq[seqPos], seqVel, 0, 0)
309
+ group_on(seqEvent, ALL_GROUPS)
310
+ delay_ppq(rateToPPQ[Rate])
311
+ end function
312
+ ```
313
+
314
+ ## Sliced Loop Playback
315
+
316
+ Play tempo-synced slices from a sample with markers.
317
+
318
+ ```
319
+ on init
320
+ const FADE_LEN = 5000
321
+ var zoneID = -1000000 + 1 ' mapping 1, zone 1
322
+ var sliceEvent
323
+ var sliceIndex
324
+ end on
325
+
326
+ on note
327
+ group_off(EVENT_ID, ALL_GROUPS)
328
+
329
+ sliceIndex = 0
330
+ var start = zone_slice_start(zoneID, sliceIndex)
331
+ var length = zone_slice_length(zoneID, sliceIndex)
332
+
333
+ while length
334
+ sliceEvent = new_note(EVENT_KEY, EVENT_VEL, start, -1)
335
+ group_on(sliceEvent, 0)
336
+ inc(sliceIndex)
337
+
338
+ var sliceEnd = zone_slice_start(zoneID, sliceIndex)
339
+ if sliceEnd < 0 ' end of loop
340
+ sliceIndex = 0
341
+ sliceEnd = -sliceEnd
342
+ end if
343
+ fade_out_after(sliceEvent, sliceEnd - start - FADE_LEN, FADE_LEN)
344
+
345
+ delay(length) ' tempo-synced wait
346
+
347
+ fade_out(sliceEvent, FADE_LEN, 1)
348
+ start = zone_slice_start(zoneID, sliceIndex)
349
+ length = zone_slice_length(zoneID, sliceIndex)
350
+ end while
351
+ end on
352
+ ```
353
+
354
+ ## Velocity Curve
355
+
356
+ Scale incoming velocities with a custom curve.
357
+
358
+ ### Simple 3-point curve
359
+
360
+ ```
361
+ on init
362
+ prop_linear Velocity_Min(1, 127, 1) = 1
363
+ prop_linear Velocity_Mid(1, 127, 1) = 64
364
+ prop_linear Velocity_Max(1, 127, 1) = 127
365
+ end on
366
+
367
+ on note
368
+ var vel = EVENT_VEL
369
+ if vel < 64
370
+ vel = Velocity_Min + (vel * (Velocity_Mid - Velocity_Min)) / 64
371
+ else
372
+ vel = Velocity_Mid + ((vel - 63) * (Velocity_Max - Velocity_Mid)) / 64
373
+ end if
374
+ set_vel(EVENT_ID, vel)
375
+ end on
376
+ ```
377
+
378
+ ### Full 127-point lookup table
379
+
380
+ ```
381
+ on init
382
+ prop_array Velocity_Curve[128](1, 127, 1)
383
+ var vel = 1
384
+ while vel < 128
385
+ Velocity_Curve[vel] = vel
386
+ inc(vel)
387
+ end while
388
+ end on
389
+
390
+ on note
391
+ set_vel(EVENT_ID, Velocity_Curve[EVENT_VEL])
392
+ end on
393
+ ```
394
+
395
+ ## Global LFO (Mod Source Shared Across Groups)
396
+
397
+ Convert a group's mod source output to a MIDI CC so other groups and effects can use it.
398
+
399
+ ```
400
+ on init
401
+ var globalModEvent = TAG_1 ' no event yet
402
+ end on
403
+
404
+ on note
405
+ ' ... manage held notes ...
406
+ if numHeldNotes = 1 ' first note
407
+ fade_out(globalModEvent, 0, 1)
408
+ globalModEvent = new_note(EVENT_KEY, EVENT_VEL, 0, 0)
409
+ group_off(globalModEvent, ALL_GROUPS)
410
+ group_on(globalModEvent, 0) ' group 0 has the LFO → CC99 routing
411
+ end if
412
+ group_off(EVENT_ID, 0) ' normal notes skip group 0
413
+ end on
414
+
415
+ on controller
416
+ if EVENT_CC = 99
417
+ ignore_controller() ' block external CC99
418
+ end if
419
+ end on
420
+ ```
421
+
422
+ ## Held-Notes Stack (Reusable Pattern)
423
+
424
+ Most mono/arpeggiator scripts maintain a list of currently held MIDI keys:
425
+
426
+ ```
427
+ on init
428
+ const MAX_HELD = 32
429
+ var heldNotes[MAX_HELD]
430
+ var numHeldNotes
431
+ var i
432
+ end on
433
+
434
+ function removeFromHeldNotes
435
+ i = 0
436
+ while i < numHeldNotes
437
+ if heldNotes[i] = EVENT_KEY
438
+ dec(numHeldNotes)
439
+ while i < numHeldNotes
440
+ heldNotes[i] = heldNotes[i + 1]
441
+ inc(i)
442
+ end while
443
+ return
444
+ end if
445
+ inc(i)
446
+ end while
447
+ end function
448
+
449
+ on note
450
+ removeFromHeldNotes() ' in case duplicate (sustain pedal, etc.)
451
+ heldNotes[numHeldNotes] = EVENT_KEY
452
+ inc(numHeldNotes)
453
+ end on
454
+
455
+ on release
456
+ removeFromHeldNotes()
457
+ end on
458
+
459
+ on controller
460
+ if EVENT_CC = 123
461
+ numHeldNotes = 0
462
+ end if
463
+ end on
464
+ ```
465
+
466
+ ## MPE (MIDI Polyphonic Expression)
467
+
468
+ Enable per-note modulation by setting "Use MIDI Channel" on mod routings. Handle RPN 6 for MPE configuration:
469
+
470
+ ```
471
+ on init
472
+ var mpeMasterChannel = -1
473
+ prop_linear Pitch_Bend_Range(0, 96, 1) = 48
474
+ end on
475
+
476
+ on controller
477
+ if EVENT_CC = CC_PITCHBEND and EVENT_CHAN = mpeMasterChannel
478
+ ' Master pitch bend → apply to all voices via CC
479
+ set_controller_hd(0, 100, Master_Bend_Range * CC[CC_PITCHBEND], 8192 * 12)
480
+ ignore_controller()
481
+ end if
482
+ end on
483
+ ```
484
+
485
+ ## Piano Behaviours (Voice Stealing)
486
+
487
+ Intelligent voice stealing based on velocity and decay:
488
+
489
+ ```
490
+ ' Track all playing notes with their trigger time
491
+ ' When max polyphony reached, steal the quietest:
492
+ ' quietness = (current_time - note_time) * decay_rate[key]
493
+ ' Prefer stealing a repeated key over a different note
494
+ ```