spessasynth_lib 3.24.13 → 3.24.16

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 (61) hide show
  1. package/midi_parser/basic_midi.js +457 -68
  2. package/midi_parser/midi_loader.js +18 -503
  3. package/midi_parser/midi_message.js +18 -5
  4. package/midi_parser/midi_sequence.js +2 -2
  5. package/package.json +1 -1
  6. package/sequencer/worklet_sequencer/process_event.js +1 -6
  7. package/synthetizer/synthetizer.js +13 -7
  8. package/synthetizer/worklet_processor.min.js +12 -12
  9. package/synthetizer/worklet_system/README.md +2 -2
  10. package/synthetizer/worklet_system/main_processor.js +106 -95
  11. package/synthetizer/worklet_system/message_protocol/handle_message.js +22 -17
  12. package/synthetizer/worklet_system/message_protocol/worklet_message.js +2 -1
  13. package/synthetizer/worklet_system/snapshot/apply_synthesizer_snapshot.js +14 -0
  14. package/synthetizer/worklet_system/snapshot/channel_snapshot.js +166 -0
  15. package/synthetizer/worklet_system/snapshot/send_synthesizer_snapshot.js +14 -0
  16. package/synthetizer/worklet_system/snapshot/synthesizer_snapshot.js +121 -0
  17. package/synthetizer/worklet_system/worklet_methods/controller_control/controller_change.js +196 -0
  18. package/synthetizer/worklet_system/worklet_methods/controller_control/master_parameters.js +34 -0
  19. package/synthetizer/worklet_system/worklet_methods/{reset_controllers.js → controller_control/reset_controllers.js} +33 -39
  20. package/synthetizer/worklet_system/worklet_methods/create_worklet_channel.js +26 -0
  21. package/synthetizer/worklet_system/worklet_methods/{data_entry.js → data_entry/data_entry_coarse.js} +38 -105
  22. package/synthetizer/worklet_system/worklet_methods/data_entry/data_entry_fine.js +64 -0
  23. package/synthetizer/worklet_system/worklet_methods/mute_channel.js +17 -0
  24. package/synthetizer/worklet_system/worklet_methods/note_on.js +36 -34
  25. package/synthetizer/worklet_system/worklet_methods/program_change.js +49 -0
  26. package/synthetizer/worklet_system/worklet_methods/{voice_control.js → render_voice.js} +37 -120
  27. package/synthetizer/worklet_system/worklet_methods/soundfont_management/clear_sound_font.js +35 -0
  28. package/synthetizer/worklet_system/worklet_methods/soundfont_management/get_preset.js +20 -0
  29. package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js +43 -0
  30. package/synthetizer/worklet_system/worklet_methods/soundfont_management/send_preset_list.js +31 -0
  31. package/synthetizer/worklet_system/worklet_methods/soundfont_management/set_embedded_sound_font.js +21 -0
  32. package/synthetizer/worklet_system/worklet_methods/stopping_notes/kill_note.js +20 -0
  33. package/synthetizer/worklet_system/worklet_methods/stopping_notes/note_off.js +55 -0
  34. package/synthetizer/worklet_system/worklet_methods/stopping_notes/stop_all_channels.js +16 -0
  35. package/synthetizer/worklet_system/worklet_methods/stopping_notes/stop_all_notes.js +30 -0
  36. package/synthetizer/worklet_system/worklet_methods/stopping_notes/voice_killing.js +63 -0
  37. package/synthetizer/worklet_system/worklet_methods/system_exclusive.js +31 -30
  38. package/synthetizer/worklet_system/worklet_methods/tuning_control/channel_pressure.js +24 -0
  39. package/synthetizer/worklet_system/worklet_methods/tuning_control/pitch_wheel.js +33 -0
  40. package/synthetizer/worklet_system/worklet_methods/tuning_control/poly_pressure.js +31 -0
  41. package/synthetizer/worklet_system/worklet_methods/tuning_control/set_master_tuning.js +15 -0
  42. package/synthetizer/worklet_system/worklet_methods/tuning_control/set_modulation_depth.js +27 -0
  43. package/synthetizer/worklet_system/worklet_methods/tuning_control/set_octave_tuning.js +15 -0
  44. package/synthetizer/worklet_system/worklet_methods/tuning_control/set_tuning.js +24 -0
  45. package/synthetizer/worklet_system/worklet_methods/tuning_control/set_tuning_semitones.js +19 -0
  46. package/synthetizer/worklet_system/worklet_methods/tuning_control/transpose_all_channels.js +15 -0
  47. package/synthetizer/worklet_system/worklet_methods/tuning_control/transpose_channel.js +31 -0
  48. package/synthetizer/worklet_system/worklet_utilities/controller_tables.js +10 -1
  49. package/synthetizer/worklet_system/worklet_utilities/lfo.js +2 -1
  50. package/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +4 -4
  51. package/synthetizer/worklet_system/worklet_utilities/modulator_curves.js +4 -5
  52. package/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +18 -18
  53. package/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +210 -206
  54. package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +354 -108
  55. package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +22 -9
  56. package/synthetizer/worklet_system/snapshot/snapshot.js +0 -311
  57. package/synthetizer/worklet_system/worklet_methods/controller_control.js +0 -260
  58. package/synthetizer/worklet_system/worklet_methods/note_off.js +0 -119
  59. package/synthetizer/worklet_system/worklet_methods/program_control.js +0 -282
  60. package/synthetizer/worklet_system/worklet_methods/tuning_control.js +0 -233
  61. package/synthetizer/worklet_system/worklet_methods/vibrato_control.js +0 -29
@@ -1,125 +1,371 @@
1
1
  import { CONTROLLER_TABLE_SIZE, CUSTOM_CONTROLLER_TABLE_SIZE, dataEntryStates } from "./controller_tables.js";
2
+ import { resetControllers, resetParameters } from "../worklet_methods/controller_control/reset_controllers.js";
3
+ import { renderVoice } from "../worklet_methods/render_voice.js";
4
+ import { panVoice } from "./stereo_panner.js";
5
+ import { killNote } from "../worklet_methods/stopping_notes/kill_note.js";
6
+ import { setTuning } from "../worklet_methods/tuning_control/set_tuning.js";
7
+ import { setModulationDepth } from "../worklet_methods/tuning_control/set_modulation_depth.js";
8
+ import { dataEntryFine } from "../worklet_methods/data_entry/data_entry_fine.js";
9
+ import { setTuningSemitones } from "../worklet_methods/tuning_control/set_tuning_semitones.js";
10
+ import { controllerChange } from "../worklet_methods/controller_control/controller_change.js";
11
+ import { stopAllNotes } from "../worklet_methods/stopping_notes/stop_all_notes.js";
12
+ import { muteChannel } from "../worklet_methods/mute_channel.js";
13
+ import { transposeChannel } from "../worklet_methods/tuning_control/transpose_channel.js";
14
+ import { dataEntryCoarse } from "../worklet_methods/data_entry/data_entry_coarse.js";
15
+ import { noteOn } from "../worklet_methods/note_on.js";
16
+ import { noteOff } from "../worklet_methods/stopping_notes/note_off.js";
17
+ import { polyPressure } from "../worklet_methods/tuning_control/poly_pressure.js";
18
+ import { channelPressure } from "../worklet_methods/tuning_control/channel_pressure.js";
19
+ import { pitchWheel } from "../worklet_methods/tuning_control/pitch_wheel.js";
20
+ import { setOctaveTuning } from "../worklet_methods/tuning_control/set_octave_tuning.js";
21
+ import { programChange } from "../worklet_methods/program_change.js";
2
22
 
3
23
  /**
4
- * @typedef {Object} WorkletProcessorChannel
5
- * @property {Int16Array} midiControllers - array of MIDI controller values + the values used by modulators as the source (pitch bend, bend range etc.).
6
- * 14-bit values.
7
- * @property {boolean[]} lockedControllers - array indicating if a controller is locked
8
- * @property {Float32Array} customControllers -
9
- * array of custom (not sf2) control values such as RPN pitch tuning, transpose, modulation depth, etc.
10
- *
11
- * @property {number} channelTransposeKeyShift - key shift of the channel
12
- * @property {Int8Array} channelOctaveTuning - the tuning for octave on this channel
13
- * @property {Int16Array} keyCentTuning - tuning of individual keys in cents
14
- * @property {boolean} holdPedal - indicates whether the hold pedal is active
15
- * @property {boolean} drumChannel - indicates whether the channel is a drum channel
16
- * @property {number} velocityOverride - overrides velocity if > 0 otherwise disabled
17
- * @property {boolean} randomPan - enables random panning for every note
18
- *
19
- * @property {dataEntryStates} dataEntryState - the current state of the data entry
20
- * @property {number} NRPCoarse - the current coarse value of the Non-Registered Parameter
21
- * @property {number} NRPFine - the current fine value of the Non-Registered Parameter
22
- * @property {number} RPValue - the current value of the Registered Parameter
23
- *
24
- * @property {number} bank - the channel's bank number
25
- * @property {BasicPreset} preset - the channel's preset
26
- * @property {boolean} lockPreset - indicates whether the program on the channel is locked
27
- * @property {boolean} presetUsesOverride - indcates if the channel uses a preset from the override soundfont.
28
- *
29
- * @property {boolean} lockGSNRPNParams - indicates whether the GS NRPN parameters are enabled
30
- * @property {Object} channelVibrato - vibrato settings for the channel
31
- * @property {number} channelVibrato.depth - depth of the vibrato effect (cents)
32
- * @property {number} channelVibrato.delay - delay before the vibrato effect starts (seconds)
33
- * @property {number} channelVibrato.rate - rate of the vibrato oscillation (Hz)
34
-
35
- * @property {boolean} isMuted - indicates whether the channel is muted
36
- * @property {WorkletVoice[]} voices - array of voices currently active on the channel
37
- * @property {WorkletVoice[]} sustainedVoices - array of voices that are sustained on the channel
38
- * @property {WorkletVoice[][][]} cachedVoices - first is midi note, second is velocity.
39
- * output is an array of WorkletVoices
24
+ * This class represents a single MIDI Channel within the synthesizer.
40
25
  */
41
-
42
- /**
43
- * @param sendEvent {boolean}
44
- * @this {SpessaSynthProcessor}
45
- */
46
- export function createWorkletChannel(sendEvent = false)
26
+ class WorkletProcessorChannel
47
27
  {
48
28
  /**
49
- * @type {WorkletProcessorChannel}
29
+ * An array of MIDI controller values and values used by modulators as the source (e.g., pitch bend, bend range, etc.).
30
+ * These are stored as 14-bit values.
31
+ * Refer to controller_tables.js for the index definitions.
32
+ * @type {Int16Array}
50
33
  */
51
- const channel = {
52
- midiControllers: new Int16Array(CONTROLLER_TABLE_SIZE),
53
- lockedControllers: Array(CONTROLLER_TABLE_SIZE).fill(false),
54
- customControllers: new Float32Array(CUSTOM_CONTROLLER_TABLE_SIZE),
55
-
56
- NRPCoarse: 0,
57
- NRPFine: 0,
58
- RPValue: 0,
59
- dataEntryState: dataEntryStates.Idle,
60
-
61
- voices: [],
62
- sustainedVoices: [],
63
- cachedVoices: [],
64
- preset: this.defaultPreset,
65
- presetUsesOverride: false,
66
-
67
- channelTransposeKeyShift: 0,
68
- channelOctaveTuning: new Int8Array(12),
69
- keyCentTuning: new Int16Array(128),
70
- channelVibrato: { delay: 0, depth: 0, rate: 0 },
71
- randomPan: false,
72
- velocityOverride: 0,
73
-
74
- lockGSNRPNParams: false,
75
- holdPedal: false,
76
- isMuted: false,
77
- drumChannel: false,
78
- lockPreset: false
79
-
80
- };
81
- for (let i = 0; i < 128; i++)
34
+ midiControllers = new Int16Array(CONTROLLER_TABLE_SIZE);
35
+
36
+ /**
37
+ * An array indicating if a controller, at the equivalent index in the midiControllers array, is locked
38
+ * (i.e., not allowed to change).
39
+ * A locked controller cannot be modified.
40
+ * @type {boolean[]}
41
+ */
42
+ lockedControllers = Array(CONTROLLER_TABLE_SIZE).fill(false);
43
+
44
+ /**
45
+ * An array of custom (non-SF2) control values such as RPN pitch tuning, transpose, modulation depth, etc.
46
+ * Refer to controller_tables.js for the index definitions.
47
+ * @type {Float32Array}
48
+ */
49
+ customControllers = new Float32Array(CUSTOM_CONTROLLER_TABLE_SIZE);
50
+
51
+ /**
52
+ * The key shift of the channel (in semitones).
53
+ * @type {number}
54
+ */
55
+ channelTransposeKeyShift = 0;
56
+
57
+ /**
58
+ * An array of octave tuning values for each note on the channel.
59
+ * Each index corresponds to a note (0 = C, 1 = C#, ..., 11 = B).
60
+ * @type {Int8Array}
61
+ */
62
+ channelOctaveTuning = new Int8Array(12);
63
+
64
+ /**
65
+ * An array representing the tuning of individual keys in cents.
66
+ * Each index corresponds to a MIDI note number (0-127).
67
+ * @type {Int16Array}
68
+ */
69
+ keyCentTuning = new Int16Array(128);
70
+
71
+ /**
72
+ * Indicates whether the sustain (hold) pedal is active.
73
+ * @type {boolean}
74
+ */
75
+ holdPedal = false;
76
+
77
+ /**
78
+ * Indicates whether this channel is a drum channel.
79
+ * @type {boolean}
80
+ */
81
+ drumChannel = false;
82
+
83
+ /**
84
+ * If greater than 0, overrides the velocity value for the channel, otherwise it's disabled.
85
+ * @type {number}
86
+ */
87
+ velocityOverride = 0;
88
+
89
+ /**
90
+ * Enables random panning for every note played on this channel.
91
+ * @type {boolean}
92
+ */
93
+ randomPan = false;
94
+
95
+ /**
96
+ * The current state of the data entry for the channel.
97
+ * @type {dataEntryStates}
98
+ */
99
+ dataEntryState = dataEntryStates.Idle;
100
+
101
+ /**
102
+ * The current coarse value of the Non-Registered Parameter (NRPN).
103
+ * @type {number}
104
+ */
105
+ NRPCoarse = 0;
106
+
107
+ /**
108
+ * The current fine value of the Non-Registered Parameter (NRPN).
109
+ * @type {number}
110
+ */
111
+ NRPFine = 0;
112
+
113
+ /**
114
+ * The current value of the Registered Parameter (RP).
115
+ * @type {number}
116
+ */
117
+ RPValue = 0;
118
+
119
+ /**
120
+ * The bank number of the channel (used for patch changes).
121
+ * @type {number}
122
+ */
123
+ bank = 0;
124
+
125
+ /**
126
+ * The preset currently assigned to the channel.
127
+ * @type {BasicPreset}
128
+ */
129
+ preset = undefined;
130
+
131
+ /**
132
+ * Indicates whether the program on this channel is locked.
133
+ * @type {boolean}
134
+ */
135
+ lockPreset = false;
136
+
137
+ /**
138
+ * Indicates whether the channel uses a preset from the override soundfont.
139
+ * @type {boolean}
140
+ */
141
+ presetUsesOverride = false;
142
+
143
+ /**
144
+ * Indicates whether the GS NRPN parameters are enabled for this channel.
145
+ * @type {boolean}
146
+ */
147
+ lockGSNRPNParams = false;
148
+
149
+ /**
150
+ * The vibrato settings for the channel.
151
+ * @type {Object}
152
+ * @property {number} depth - Depth of the vibrato effect in cents.
153
+ * @property {number} delay - Delay before the vibrato effect starts (in seconds).
154
+ * @property {number} rate - Rate of the vibrato oscillation (in Hz).
155
+ */
156
+ channelVibrato = { delay: 0, depth: 0, rate: 0 };
157
+
158
+ /**
159
+ * Indicates whether the channel is muted.
160
+ * @type {boolean}
161
+ */
162
+ isMuted = false;
163
+
164
+ /**
165
+ * An array of voices currently active on the channel.
166
+ * @type {WorkletVoice[]}
167
+ */
168
+ voices = [];
169
+
170
+ /**
171
+ * An array of voices that are sustained on the channel.
172
+ * @type {WorkletVoice[]}
173
+ */
174
+ sustainedVoices = [];
175
+
176
+ /**
177
+ * A 3D array (MIDI note -> velocity -> WorkletVoices) for cached voices for each note and velocity.
178
+ * @type {WorkletVoice[][][]}
179
+ */
180
+ cachedVoices = [];
181
+
182
+ /**
183
+ * The channel's number (0-based index)
184
+ * @type {number}
185
+ */
186
+ channelNumber;
187
+
188
+ /**
189
+ * Parent processor instance.
190
+ * @type {SpessaSynthProcessor}
191
+ */
192
+ synth;
193
+
194
+ /**
195
+ * Constructs a new MIDI channel
196
+ * @param synth {SpessaSynthProcessor}
197
+ * @param preset {BasicPreset}
198
+ * @param channelNumber {number}
199
+ */
200
+ constructor(synth, preset, channelNumber)
82
201
  {
83
- channel.cachedVoices.push([]);
202
+ this.synth = synth;
203
+ this.preset = preset;
204
+ this.channelNumber = channelNumber;
205
+ for (let i = 0; i < 128; i++)
206
+ {
207
+ this.cachedVoices.push([]);
208
+ }
84
209
  }
85
- this.workletProcessorChannels.push(channel);
86
- this.resetControllers(this.workletProcessorChannels.length - 1);
87
- this.sendChannelProperties();
88
- if (sendEvent)
210
+
211
+ /**
212
+ * @param outputLeft {Float32Array} the left output buffer
213
+ * @param outputRight {Float32Array} the right output buffer
214
+ * @param reverbOutputLeft {Float32Array} left output for reverb
215
+ * @param reverbOutputRight {Float32Array} right output for reverb
216
+ * @param chorusOutputLeft {Float32Array} left output for chorus
217
+ * @param chorusOutputRight {Float32Array} right output for chorus
218
+ */
219
+ renderAudio(
220
+ outputLeft, outputRight,
221
+ reverbOutputLeft, reverbOutputRight,
222
+ chorusOutputLeft, chorusOutputRight
223
+ )
89
224
  {
90
- this.callEvent("newchannel", undefined);
225
+ this.voices = this.voices.filter(v => !this.renderVoice(
226
+ v,
227
+ outputLeft, outputRight,
228
+ reverbOutputLeft, reverbOutputRight,
229
+ chorusOutputLeft, chorusOutputRight
230
+ ));
91
231
  }
92
- }
93
-
94
- /**
95
- * @param channel {WorkletProcessorChannel}
96
- * @param bank {number}
97
- */
98
- export function setBankSelect(channel, bank)
99
- {
100
- if (!channel.lockPreset)
232
+
233
+ /**
234
+ * @param bank {number}
235
+ */
236
+ setBankSelect(bank)
101
237
  {
102
- channel.bank = bank;
238
+ if (!this.lockPreset)
239
+ {
240
+ this.bank = bank;
241
+ }
103
242
  }
104
- }
105
-
106
- /**
107
- * @param channel {WorkletProcessorChannel}
108
- * @returns {number}
109
- */
110
- export function getBankSelect(channel)
111
- {
112
- if (channel.drumChannel)
243
+
244
+ /**
245
+ * @returns {number}
246
+ */
247
+ getBankSelect()
248
+ {
249
+ if (this.drumChannel)
250
+ {
251
+ return 128;
252
+ }
253
+ return this.bank;
254
+ }
255
+
256
+ /**
257
+ * Changes a preset of this channel
258
+ * @param preset {BasicPreset}
259
+ */
260
+ setPreset(preset)
261
+ {
262
+ if (this.lockPreset)
263
+ {
264
+ return;
265
+ }
266
+ delete this.preset;
267
+ this.preset = preset;
268
+
269
+ // reset cached voices
270
+ this.cachedVoices = [];
271
+ for (let i = 0; i < 128; i++)
272
+ {
273
+ this.cachedVoices.push([]);
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Sets drums on channel.
279
+ * @param isDrum {boolean}
280
+ */
281
+ setDrums(isDrum)
113
282
  {
114
- return 128;
283
+ if (this.lockPreset)
284
+ {
285
+ return;
286
+ }
287
+ if (this.drumChannel === isDrum)
288
+ {
289
+ return;
290
+ }
291
+ if (isDrum)
292
+ {
293
+ // clear transpose
294
+ this.channelTransposeKeyShift = 0;
295
+ this.drumChannel = true;
296
+ this.setPreset(this.synth.getPreset(this.getBankSelect(), this.preset.program));
297
+ }
298
+ else
299
+ {
300
+ this.drumChannel = false;
301
+ this.setPreset(
302
+ this.synth.getPreset(
303
+ this.getBankSelect(),
304
+ this.preset.program
305
+ )
306
+ );
307
+ }
308
+ this.presetUsesOverride = false;
309
+ this.synth.callEvent("drumchange", {
310
+ channel: this.channelNumber,
311
+ isDrumChannel: this.drumChannel
312
+ });
313
+ this.synth.sendChannelProperties();
314
+ }
315
+
316
+ /**
317
+ * Sets a custom vibrato
318
+ * @param depth {number} cents
319
+ * @param rate {number} Hz
320
+ * @param delay {number} seconds
321
+ */
322
+ setVibrato(depth, rate, delay)
323
+ {
324
+ if (this.lockGSNRPNParams)
325
+ {
326
+ return;
327
+ }
328
+ this.channelVibrato.rate = rate;
329
+ this.channelVibrato.delay = delay;
330
+ this.channelVibrato.depth = depth;
331
+ }
332
+
333
+ disableAndLockGSNRPN()
334
+ {
335
+ this.lockGSNRPNParams = true;
336
+ this.channelVibrato.rate = 0;
337
+ this.channelVibrato.delay = 0;
338
+ this.channelVibrato.depth = 0;
115
339
  }
116
- return channel.bank;
117
340
  }
118
341
 
119
- /**
120
- * This is a channel configuration enum, it is internally sent from Synthetizer via controller change
121
- * @enum {number}
122
- */
123
- export const channelConfiguration = {
124
- velocityOverride: 128 // overrides velocity for the given channel
125
- };
342
+ // voice
343
+ WorkletProcessorChannel.prototype.renderVoice = renderVoice;
344
+ WorkletProcessorChannel.prototype.panVoice = panVoice;
345
+ WorkletProcessorChannel.prototype.killNote = killNote;
346
+ WorkletProcessorChannel.prototype.stopAllNotes = stopAllNotes;
347
+ WorkletProcessorChannel.prototype.muteChannel = muteChannel;
348
+
349
+ // MIDI messages
350
+ WorkletProcessorChannel.prototype.noteOn = noteOn;
351
+ WorkletProcessorChannel.prototype.noteOff = noteOff;
352
+ WorkletProcessorChannel.prototype.polyPressure = polyPressure;
353
+ WorkletProcessorChannel.prototype.channelPressure = channelPressure;
354
+ WorkletProcessorChannel.prototype.pitchWheel = pitchWheel;
355
+ WorkletProcessorChannel.prototype.programChange = programChange;
356
+
357
+ // Tuning
358
+ WorkletProcessorChannel.prototype.setTuning = setTuning;
359
+ WorkletProcessorChannel.prototype.setTuningSemitones = setTuningSemitones;
360
+ WorkletProcessorChannel.prototype.setOctaveTuning = setOctaveTuning;
361
+ WorkletProcessorChannel.prototype.setModulationDepth = setModulationDepth;
362
+ WorkletProcessorChannel.prototype.transposeChannel = transposeChannel;
363
+
364
+ // CC
365
+ WorkletProcessorChannel.prototype.controllerChange = controllerChange;
366
+ WorkletProcessorChannel.prototype.resetControllers = resetControllers;
367
+ WorkletProcessorChannel.prototype.resetParameters = resetParameters;
368
+ WorkletProcessorChannel.prototype.dataEntryFine = dataEntryFine;
369
+ WorkletProcessorChannel.prototype.dataEntryCoarse = dataEntryCoarse;
370
+
371
+ export { WorkletProcessorChannel };
@@ -3,6 +3,13 @@
3
3
  * purpose: prepares workletvoices from sample and generator data and manages sample dumping
4
4
  * note: sample dumping means sending it over to the AudioWorkletGlobalScope
5
5
  */
6
+ import { MIN_NOTE_LENGTH } from "../main_processor.js";
7
+ import { SpessaSynthTable, SpessaSynthWarn } from "../../../utils/loggin.js";
8
+ import { WorkletLowpassFilter } from "./lowpass_filter.js";
9
+ import { WorkletVolumeEnvelope } from "./volume_envelope.js";
10
+ import { WorkletModulationEnvelope } from "./modulation_envelope.js";
11
+ import { addAndClampGenerator, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
12
+ import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
6
13
 
7
14
  class WorkletSample
8
15
  {
@@ -89,13 +96,6 @@ class WorkletSample
89
96
  }
90
97
  }
91
98
 
92
- import { SpessaSynthTable, SpessaSynthWarn } from "../../../utils/loggin.js";
93
- import { WorkletLowpassFilter } from "./lowpass_filter.js";
94
- import { WorkletVolumeEnvelope } from "./volume_envelope.js";
95
- import { WorkletModulationEnvelope } from "./modulation_envelope.js";
96
- import { addAndClampGenerator, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
97
- import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
98
-
99
99
 
100
100
  /**
101
101
  * WorkletVoice represents a single instance of the
@@ -323,13 +323,26 @@ class WorkletVoice
323
323
  voice.modulators.map(m => Modulator.copy(m))
324
324
  );
325
325
  }
326
+
327
+ /**
328
+ * Stops the voice
329
+ * @param minNoteLength {number} minimum note length in seconds
330
+ */
331
+ release(minNoteLength = MIN_NOTE_LENGTH)
332
+ {
333
+ this.releaseStartTime = currentTime;
334
+ // check if the note is shorter than the min note time, if so, extend it
335
+ if (this.releaseStartTime - this.startTime < minNoteLength)
336
+ {
337
+ this.releaseStartTime = this.startTime + minNoteLength;
338
+ }
339
+ }
326
340
  }
327
341
 
328
342
  /**
329
343
  * @param channel {number} a hint for the processor to recalculate sample cursors when sample dumping
330
344
  * @param midiNote {number} the MIDI note to use
331
345
  * @param velocity {number} the velocity to use
332
- * @param channelObject {WorkletProcessorChannel} the channel this will belong to
333
346
  * @param currentTime {number} the current time in seconds
334
347
  * @param realKey {number} the real MIDI note if the "midiNote" was changed by MIDI Tuning Standard
335
348
  * @param debug {boolean} enable debugging?
@@ -339,7 +352,6 @@ class WorkletVoice
339
352
  export function getWorkletVoices(channel,
340
353
  midiNote,
341
354
  velocity,
342
- channelObject,
343
355
  currentTime,
344
356
  realKey,
345
357
  debug = false)
@@ -348,6 +360,7 @@ export function getWorkletVoices(channel,
348
360
  * @type {WorkletVoice[]}
349
361
  */
350
362
  let workletVoices;
363
+ const channelObject = this.workletProcessorChannels[channel];
351
364
 
352
365
  const cached = channelObject.cachedVoices[midiNote]?.[velocity];
353
366