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,311 +0,0 @@
1
- import { returnMessageType } from "../message_protocol/worklet_message.js";
2
- import { SpessaSynthInfo } from "../../../utils/loggin.js";
3
- import { consoleColors } from "../../../utils/other.js";
4
- import { getBankSelect, setBankSelect } from "../worklet_utilities/worklet_processor_channel.js";
5
-
6
- /**
7
- * Represents a snapshot of a single channel's state in the synthesizer.
8
- */
9
- class ChannelSnapshot
10
- {
11
- /**
12
- * The channel's MIDI program number.
13
- * @type {number}
14
- */
15
- program;
16
-
17
- /**
18
- * The channel's bank number.
19
- * @type {number}
20
- */
21
- bank;
22
-
23
- /**
24
- * The name of the patch currently loaded in the channel.
25
- * @type {string}
26
- */
27
- patchName;
28
-
29
- /**
30
- * Indicates whether the channel's program change is disabled.
31
- * @type {boolean}
32
- */
33
- lockPreset;
34
-
35
- /**
36
- * The array of all MIDI controllers (in 14-bit values) with the modulator sources at the end.
37
- * @type {Int16Array}
38
- */
39
- midiControllers;
40
-
41
- /**
42
- * An array of booleans, indicating if the controller with a current index is locked.
43
- * @type {boolean[]}
44
- */
45
- lockedControllers;
46
-
47
- /**
48
- * Array of custom (not SF2) control values such as RPN pitch tuning, transpose, modulation depth, etc.
49
- * @type {Float32Array}
50
- */
51
- customControllers;
52
-
53
- /**
54
- * Indicates whether the channel vibrato is locked.
55
- * @type {boolean}
56
- */
57
- lockVibrato;
58
-
59
- /**
60
- * The channel's vibrato settings.
61
- * @type {Object}
62
- * @property {number} depth - Vibrato depth, in gain.
63
- * @property {number} delay - Vibrato delay from note on in seconds.
64
- * @property {number} rate - Vibrato rate in Hz.
65
- */
66
- channelVibrato;
67
-
68
- /**
69
- * Key shift for the channel.
70
- * @type {number}
71
- */
72
- channelTransposeKeyShift;
73
-
74
- /**
75
- * The channel's octave tuning in cents.
76
- * @type {Int8Array}
77
- */
78
- channelOctaveTuning;
79
-
80
- /**
81
- * Tuning of individual keys in cents.
82
- * @type {Int16Array}
83
- */
84
- keyCentTuning;
85
-
86
- /**
87
- * Indicates whether the channel is muted.
88
- * @type {boolean}
89
- */
90
- isMuted;
91
-
92
- /**
93
- * Overrides velocity if greater than 0, otherwise disabled.
94
- * @type {number}
95
- */
96
- velocityOverride;
97
-
98
- /**
99
- * Indicates whether the channel is a drum channel.
100
- * @type {boolean}
101
- */
102
- drumChannel;
103
-
104
- /**
105
- * Creates a snapshot of a single channel's state in the synthesizer.
106
- * @param workletProcessor {SpessaSynthProcessor}
107
- * @param channelNumber {number}
108
- * @returns {ChannelSnapshot}
109
- */
110
- static getChannelSnapshot(workletProcessor, channelNumber)
111
- {
112
- const channel = workletProcessor.workletProcessorChannels[channelNumber];
113
- const channelSnapshot = new ChannelSnapshot();
114
- // program data
115
- channelSnapshot.program = channel.preset.program;
116
- channelSnapshot.bank = getBankSelect(channel);
117
- channelSnapshot.lockPreset = channel.lockPreset;
118
- channelSnapshot.patchName = channel.preset.presetName;
119
-
120
- // controller data
121
- channelSnapshot.midiControllers = channel.midiControllers;
122
- channelSnapshot.lockedControllers = channel.lockedControllers;
123
- channelSnapshot.customControllers = channel.customControllers;
124
-
125
- // vibrato data
126
- channelSnapshot.channelVibrato = channel.channelVibrato;
127
- channelSnapshot.lockVibrato = channel.lockGSNRPNParams;
128
-
129
- // tuning and transpose data
130
- channelSnapshot.channelTransposeKeyShift = channel.channelTransposeKeyShift;
131
- channelSnapshot.channelOctaveTuning = channel.channelOctaveTuning;
132
- channelSnapshot.keyCentTuning = channel.keyCentTuning;
133
-
134
- // other data
135
- channelSnapshot.isMuted = channel.isMuted;
136
- channelSnapshot.velocityOverride = channel.velocityOverride;
137
- channelSnapshot.drumChannel = channel.drumChannel;
138
- return channelSnapshot;
139
- }
140
-
141
- /**
142
- * Applies the snapshot to the specified channel.
143
- * @param workletProcessor {SpessaSynthProcessor}
144
- * @param channelNumber {number}
145
- * @param channelSnapshot {ChannelSnapshot}
146
- */
147
- static applyChannelSnapshot(workletProcessor, channelNumber, channelSnapshot)
148
- {
149
- const channelObject = workletProcessor.workletProcessorChannels[channelNumber];
150
- workletProcessor.muteChannel(channelNumber, channelSnapshot.isMuted);
151
- workletProcessor.setDrums(channelNumber, channelSnapshot.drumChannel);
152
-
153
- // restore controllers
154
- channelObject.midiControllers = channelSnapshot.midiControllers;
155
- channelObject.lockedControllers = channelSnapshot.lockedControllers;
156
- channelObject.customControllers = channelSnapshot.customControllers;
157
-
158
- // restore vibrato and transpose
159
- channelObject.channelVibrato = channelSnapshot.channelVibrato;
160
- channelObject.lockGSNRPNParams = channelSnapshot.lockVibrato;
161
- channelObject.channelTransposeKeyShift = channelSnapshot.channelTransposeKeyShift;
162
- channelObject.channelOctaveTuning = channelSnapshot.channelOctaveTuning;
163
- channelObject.velocityOverride = channelSnapshot.velocityOverride;
164
-
165
- // restore preset and lock
166
- channelObject.lockPreset = false;
167
- setBankSelect(channelObject, channelSnapshot.bank);
168
- workletProcessor.programChange(channelNumber, channelSnapshot.program);
169
- channelObject.lockPreset = channelSnapshot.lockPreset;
170
- }
171
- }
172
-
173
- /**
174
- * Represents a snapshot of the synthesizer's state.
175
- */
176
- class SynthesizerSnapshot
177
- {
178
- /**
179
- * The individual channel snapshots.
180
- * @type {ChannelSnapshot[]}
181
- */
182
- channelSnapshots;
183
-
184
- /**
185
- * Key modifiers.
186
- * @type {KeyModifier[][]}
187
- */
188
- keyMappings;
189
-
190
- /**
191
- * Main synth volume (set by MIDI), from 0 to 1.
192
- * @type {number}
193
- */
194
- mainVolume;
195
-
196
- /**
197
- * Master stereo panning, from -1 to 1.
198
- * @type {number}
199
- */
200
- pan;
201
-
202
- /**
203
- * The synth's interpolation type.
204
- * @type {interpolationTypes}
205
- */
206
- interpolation;
207
-
208
- /**
209
- * The synth's system. Values can be "gs", "gm", "gm2" or "xg".
210
- * @type {SynthSystem}
211
- */
212
- system;
213
-
214
- /**
215
- * The current synth transposition in semitones. Can be a float.
216
- * @type {number}
217
- */
218
- transposition;
219
-
220
- /**
221
- * The effects configuration object.
222
- * @type {SynthConfig}
223
- */
224
- effectsConfig;
225
-
226
-
227
- /**
228
- * Creates a snapshot of the synthesizer's state.
229
- * @param workletProcessor {SpessaSynthProcessor}
230
- * @returns {SynthesizerSnapshot}
231
- */
232
- static createSynthesizerSnapshot(workletProcessor)
233
- {
234
- const snapshot = new SynthesizerSnapshot();
235
- // channel snapshots
236
- snapshot.channelSnapshots =
237
- workletProcessor.workletProcessorChannels.map((_, i) =>
238
- ChannelSnapshot.getChannelSnapshot(workletProcessor, i));
239
-
240
- // key mappings
241
- snapshot.keyMappings = workletProcessor.keyModifierManager.getMappings();
242
- // pan and volume
243
- snapshot.mainVolume = workletProcessor.midiVolume;
244
- snapshot.pan = workletProcessor.pan;
245
-
246
- // others
247
- snapshot.system = workletProcessor.system;
248
- snapshot.interpolation = workletProcessor.interpolationType;
249
- snapshot.transposition = workletProcessor.transposition;
250
-
251
- // effects config is stored on the main thread, leave it empty
252
- snapshot.effectsConfig = {};
253
- return snapshot;
254
-
255
- }
256
-
257
- /**
258
- * Applies the snapshot to the synthesizer.
259
- * @param workletProcessor {SpessaSynthProcessor}
260
- * @param snapshot {SynthesizerSnapshot}
261
- */
262
- static applySnapshot(workletProcessor, snapshot)
263
- {
264
- // restore system
265
- workletProcessor.system = snapshot.system;
266
-
267
- // restore pan and volume
268
- workletProcessor.setMasterGain(snapshot.mainVolume);
269
- workletProcessor.setMasterPan(snapshot.pan);
270
- workletProcessor.transposeAllChannels(snapshot.transposition);
271
- workletProcessor.interpolationType = snapshot.interpolation;
272
- workletProcessor.keyModifierManager.setMappings(snapshot.keyMappings);
273
-
274
- // add channels if more needed
275
- while (workletProcessor.workletProcessorChannels.length < snapshot.channelSnapshots.length)
276
- {
277
- workletProcessor.createWorkletChannel();
278
- }
279
-
280
- // restore channels
281
- snapshot.channelSnapshots.forEach((channelSnapshot, index) =>
282
- {
283
- ChannelSnapshot.applyChannelSnapshot(workletProcessor, index, channelSnapshot);
284
- });
285
-
286
- SpessaSynthInfo("%cFinished restoring controllers!", consoleColors.info);
287
- }
288
- }
289
-
290
- /**
291
- * sends a snapshot of the current controller values of the synth (used to copy that data to OfflineAudioContext when rendering)
292
- * @this {SpessaSynthProcessor}
293
- */
294
- export function sendSynthesizerSnapshot()
295
- {
296
- this.post({
297
- messageType: returnMessageType.synthesizerSnapshot,
298
- messageData: SynthesizerSnapshot.createSynthesizerSnapshot(this)
299
- });
300
- }
301
-
302
- /**
303
- * Applies the snapshot to the synth
304
- * @param snapshot {SynthesizerSnapshot}
305
- * @this {SpessaSynthProcessor}
306
- */
307
- export function applySynthesizerSnapshot(snapshot)
308
- {
309
- SynthesizerSnapshot.applySnapshot(this, snapshot);
310
- SpessaSynthInfo("%cFinished applying snapshot!", consoleColors.info);
311
- }
@@ -1,260 +0,0 @@
1
- import { consoleColors } from "../../../utils/other.js";
2
- import { midiControllers } from "../../../midi_parser/midi_message.js";
3
- import { channelConfiguration, getBankSelect, setBankSelect } from "../worklet_utilities/worklet_processor_channel.js";
4
- import { computeModulators } from "../worklet_utilities/worklet_modulator.js";
5
- import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
6
- import { SYNTHESIZER_GAIN } from "../main_processor.js";
7
- import { DEFAULT_PERCUSSION } from "../../synthetizer.js";
8
- import { dataEntryStates } from "../worklet_utilities/controller_tables.js";
9
-
10
- /**
11
- * @param channel {number}
12
- * @param controllerNumber {number}
13
- * @param controllerValue {number}
14
- * @param force {boolean}
15
- * @this {SpessaSynthProcessor}
16
- */
17
- export function controllerChange(channel, controllerNumber, controllerValue, force = false)
18
- {
19
- /**
20
- * @type {WorkletProcessorChannel}
21
- */
22
- const channelObject = this.workletProcessorChannels[channel];
23
- if (channelObject === undefined)
24
- {
25
- SpessaSynthWarn(`Trying to access channel ${channel} which does not exist... ignoring!`);
26
- return;
27
- }
28
- if (controllerNumber > 127)
29
- {
30
- // channel configuration. force must be set to true
31
- if (!force)
32
- {
33
- return;
34
- }
35
- switch (controllerNumber)
36
- {
37
- default:
38
- return;
39
-
40
- case channelConfiguration.velocityOverride:
41
- channelObject.velocityOverride = controllerValue;
42
- }
43
- }
44
-
45
- // lsb controller values: append them as the lower nibble of the 14-bit value
46
- // excluding bank select and data entry as it's handled separately
47
- if (
48
- controllerNumber >= midiControllers.lsbForControl1ModulationWheel
49
- && controllerNumber <= midiControllers.lsbForControl13EffectControl2
50
- && controllerNumber !== midiControllers.lsbForControl6DataEntry
51
- )
52
- {
53
- const actualCCNum = controllerNumber - 32;
54
- if (channelObject.lockedControllers[actualCCNum])
55
- {
56
- return;
57
- }
58
- // append the lower nibble to the main controller
59
- channelObject.midiControllers[actualCCNum] = (channelObject.midiControllers[actualCCNum] & 0x3F80) | (controllerValue & 0x7F);
60
- channelObject.voices.forEach(v => computeModulators(v, channelObject.midiControllers, 1, actualCCNum));
61
- }
62
- switch (controllerNumber)
63
- {
64
- case midiControllers.allNotesOff:
65
- this.stopAll(channel);
66
- break;
67
-
68
- case midiControllers.allSoundOff:
69
- this.stopAll(channel, true);
70
- break;
71
-
72
- // special case: bank select
73
- case midiControllers.bankSelect:
74
- let bankNr = controllerValue;
75
- if (!force)
76
- {
77
- switch (this.system)
78
- {
79
- case "gm":
80
- // gm ignores bank select
81
- SpessaSynthInfo(
82
- `%cIgnoring the Bank Select (${controllerValue}), as the synth is in GM mode.`,
83
- consoleColors.info
84
- );
85
- return;
86
-
87
- case "xg":
88
- // for xg, if msb is 120, 126 or 127, then it's drums
89
- if (bankNr === 120 || bankNr === 126 || bankNr === 127)
90
- {
91
- this.setDrums(channel, true);
92
- }
93
- else
94
- {
95
- // drums shall not be disabled on channel 9
96
- if (channel % 16 !== DEFAULT_PERCUSSION)
97
- {
98
- this.setDrums(channel, false);
99
- }
100
- }
101
- break;
102
-
103
- case "gm2":
104
- if (bankNr === 120)
105
- {
106
- this.setDrums(channel, true);
107
- }
108
- }
109
-
110
- if (channelObject.drumChannel)
111
- {
112
- // 128 for percussion channel
113
- bankNr = 128;
114
- }
115
- if (bankNr === 128 && !channelObject.drumChannel)
116
- {
117
- // if a channel is not for percussion, default to bank current
118
- bankNr = getBankSelect(channelObject);
119
- }
120
- }
121
-
122
- setBankSelect(channelObject, bankNr);
123
- break;
124
-
125
- case midiControllers.lsbForControl0BankSelect:
126
- if (this.system === "xg")
127
- {
128
- if (!channelObject.drumChannel)
129
- {
130
- // some soundfonts use 127 as drums and
131
- // if it's not marked as drums by bank MSB (line 47), then we DO NOT want the drums!
132
- if (controllerValue !== 127)
133
- {
134
- setBankSelect(channelObject, controllerValue);
135
- }
136
- }
137
- }
138
- else if (this.system === "gm2")
139
- {
140
- setBankSelect(channelObject, controllerValue);
141
- }
142
- break;
143
-
144
- // check for RPN and NPRN and data entry
145
- case midiControllers.RPNLsb:
146
- channelObject.RPValue = channelObject.RPValue << 7 | controllerValue;
147
- channelObject.dataEntryState = dataEntryStates.RPFine;
148
- break;
149
-
150
- case midiControllers.RPNMsb:
151
- channelObject.RPValue = controllerValue;
152
- channelObject.dataEntryState = dataEntryStates.RPCoarse;
153
- break;
154
-
155
- case midiControllers.NRPNMsb:
156
- channelObject.NRPCoarse = controllerValue;
157
- channelObject.dataEntryState = dataEntryStates.NRPCoarse;
158
- break;
159
-
160
- case midiControllers.NRPNLsb:
161
- channelObject.NRPFine = controllerValue;
162
- channelObject.dataEntryState = dataEntryStates.NRPFine;
163
- break;
164
-
165
- case midiControllers.dataEntryMsb:
166
- this.dataEntryCoarse(channel, controllerValue);
167
- break;
168
-
169
- case midiControllers.lsbForControl6DataEntry:
170
- this.dataEntryFine(channel, controllerValue);
171
- break;
172
-
173
- case midiControllers.resetAllControllers:
174
- this.resetControllers(channel);
175
- break;
176
-
177
- case midiControllers.sustainPedal:
178
- if (controllerValue >= 64)
179
- {
180
- channelObject.holdPedal = true;
181
- }
182
- else
183
- {
184
- channelObject.holdPedal = false;
185
- channelObject.sustainedVoices.forEach(v =>
186
- {
187
- this.releaseVoice(v);
188
- });
189
- channelObject.sustainedVoices = [];
190
- }
191
- break;
192
-
193
- // default: apply the controller to the table
194
- default:
195
- if (channelObject.lockedControllers[controllerNumber])
196
- {
197
- return;
198
- }
199
- channelObject.midiControllers[controllerNumber] = controllerValue << 7;
200
- channelObject.voices.forEach(v => computeModulators(v, channelObject.midiControllers, 1, controllerNumber));
201
- break;
202
- }
203
- this.callEvent("controllerchange", {
204
- channel: channel,
205
- controllerNumber: controllerNumber,
206
- controllerValue: controllerValue
207
- });
208
- }
209
-
210
- /**
211
- * @param volume {number} 0 to 1
212
- * @this {SpessaSynthProcessor}
213
- */
214
- export function setMIDIVolume(volume)
215
- {
216
- this.midiVolume = volume;
217
- this.setMasterPan(this.pan);
218
- }
219
-
220
- /**
221
- * @param volume {number} 0-1
222
- * @this {SpessaSynthProcessor}
223
- */
224
- export function setMasterGain(volume)
225
- {
226
- this.masterGain = volume * SYNTHESIZER_GAIN;
227
- this.setMasterPan(this.pan);
228
- }
229
-
230
- /**
231
- * @param pan {number} -1 to one
232
- * @this {SpessaSynthProcessor}
233
- */
234
- export function setMasterPan(pan)
235
- {
236
- this.pan = pan;
237
- // clamp to 0-1 (0 is left)
238
- pan = (pan / 2) + 0.5;
239
- this.panLeft = (1 - pan);
240
- this.panRight = (pan);
241
- }
242
-
243
- /**
244
- * @param channel {number}
245
- * @param isMuted {boolean}
246
- * @this {SpessaSynthProcessor}
247
- */
248
- export function muteChannel(channel, isMuted)
249
- {
250
- if (isMuted)
251
- {
252
- this.stopAll(channel, true);
253
- }
254
- this.workletProcessorChannels[channel].isMuted = isMuted;
255
- this.sendChannelProperties();
256
- this.callEvent("mutechannel", {
257
- channel: channel,
258
- isMuted: isMuted
259
- });
260
- }
@@ -1,119 +0,0 @@
1
- import { consoleColors } from "../../../utils/other.js";
2
- import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
3
- import { generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
4
-
5
- /**
6
- * Release a note
7
- * @param channel {number}
8
- * @param midiNote {number}
9
- * @this {SpessaSynthProcessor}
10
- */
11
- export function noteOff(channel, midiNote)
12
- {
13
- if (midiNote > 127 || midiNote < 0)
14
- {
15
- SpessaSynthWarn(`Received a noteOn for note`, midiNote, "Ignoring.");
16
- return;
17
- }
18
-
19
- let realKey = midiNote + this.workletProcessorChannels[channel].channelTransposeKeyShift;
20
-
21
- // if high performance mode, kill notes instead of stopping them
22
- if (this.highPerformanceMode)
23
- {
24
- // if the channel is percussion channel, do not kill the notes
25
- if (!this.workletProcessorChannels[channel].drumChannel)
26
- {
27
- this.killNote(channel, realKey);
28
- return;
29
- }
30
- }
31
-
32
- const channelVoices = this.workletProcessorChannels[channel].voices;
33
- channelVoices.forEach(v =>
34
- {
35
- if (v.realKey !== realKey || v.isInRelease === true)
36
- {
37
- return;
38
- }
39
- // if hold pedal, move to sustain
40
- if (this.workletProcessorChannels[channel].holdPedal)
41
- {
42
- this.workletProcessorChannels[channel].sustainedVoices.push(v);
43
- }
44
- else
45
- {
46
- this.releaseVoice(v);
47
- }
48
- });
49
- this.callEvent("noteoff", {
50
- midiNote: midiNote,
51
- channel: channel
52
- });
53
- }
54
-
55
- /**
56
- * Stops a note nearly instantly
57
- * @param channel {number}
58
- * @param midiNote {number}
59
- * @this {SpessaSynthProcessor}
60
- */
61
- export function killNote(channel, midiNote)
62
- {
63
- this.workletProcessorChannels[channel].voices.forEach(v =>
64
- {
65
- if (v.realKey !== midiNote)
66
- {
67
- return;
68
- }
69
- v.modulatedGenerators[generatorTypes.releaseVolEnv] = -12000; // set release to be very short
70
- this.releaseVoice(v);
71
- });
72
- }
73
-
74
- /**
75
- * stops all notes on a given channel
76
- * @param channel {number}
77
- * @param force {boolean}
78
- * @this {SpessaSynthProcessor}
79
- */
80
- export function stopAll(channel, force = false)
81
- {
82
- const channelVoices = this.workletProcessorChannels[channel].voices;
83
- if (force)
84
- {
85
- // force stop all
86
- channelVoices.length = 0;
87
- this.workletProcessorChannels[channel].sustainedVoices.length = 0;
88
- this.sendChannelProperties();
89
- }
90
- else
91
- {
92
- channelVoices.forEach(v =>
93
- {
94
- if (v.isInRelease)
95
- {
96
- return;
97
- }
98
- this.releaseVoice(v);
99
- });
100
- this.workletProcessorChannels[channel].sustainedVoices.forEach(v =>
101
- {
102
- this.releaseVoice(v);
103
- });
104
- }
105
- }
106
-
107
- /**
108
- * @this {SpessaSynthProcessor}
109
- * @param force {boolean}
110
- */
111
- export function stopAllChannels(force = false)
112
- {
113
- SpessaSynthInfo("%cStop all received!", consoleColors.info);
114
- for (let i = 0; i < this.workletProcessorChannels.length; i++)
115
- {
116
- this.stopAll(i, force);
117
- }
118
- this.callEvent("stopall", undefined);
119
- }