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.
- package/midi_parser/basic_midi.js +457 -68
- package/midi_parser/midi_loader.js +18 -503
- package/midi_parser/midi_message.js +18 -5
- package/midi_parser/midi_sequence.js +2 -2
- package/package.json +1 -1
- package/sequencer/worklet_sequencer/process_event.js +1 -6
- package/synthetizer/synthetizer.js +13 -7
- package/synthetizer/worklet_processor.min.js +12 -12
- package/synthetizer/worklet_system/README.md +2 -2
- package/synthetizer/worklet_system/main_processor.js +106 -95
- package/synthetizer/worklet_system/message_protocol/handle_message.js +22 -17
- package/synthetizer/worklet_system/message_protocol/worklet_message.js +2 -1
- package/synthetizer/worklet_system/snapshot/apply_synthesizer_snapshot.js +14 -0
- package/synthetizer/worklet_system/snapshot/channel_snapshot.js +166 -0
- package/synthetizer/worklet_system/snapshot/send_synthesizer_snapshot.js +14 -0
- package/synthetizer/worklet_system/snapshot/synthesizer_snapshot.js +121 -0
- package/synthetizer/worklet_system/worklet_methods/controller_control/controller_change.js +196 -0
- package/synthetizer/worklet_system/worklet_methods/controller_control/master_parameters.js +34 -0
- package/synthetizer/worklet_system/worklet_methods/{reset_controllers.js → controller_control/reset_controllers.js} +33 -39
- package/synthetizer/worklet_system/worklet_methods/create_worklet_channel.js +26 -0
- package/synthetizer/worklet_system/worklet_methods/{data_entry.js → data_entry/data_entry_coarse.js} +38 -105
- package/synthetizer/worklet_system/worklet_methods/data_entry/data_entry_fine.js +64 -0
- package/synthetizer/worklet_system/worklet_methods/mute_channel.js +17 -0
- package/synthetizer/worklet_system/worklet_methods/note_on.js +36 -34
- package/synthetizer/worklet_system/worklet_methods/program_change.js +49 -0
- package/synthetizer/worklet_system/worklet_methods/{voice_control.js → render_voice.js} +37 -120
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/clear_sound_font.js +35 -0
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/get_preset.js +20 -0
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js +43 -0
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/send_preset_list.js +31 -0
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/set_embedded_sound_font.js +21 -0
- package/synthetizer/worklet_system/worklet_methods/stopping_notes/kill_note.js +20 -0
- package/synthetizer/worklet_system/worklet_methods/stopping_notes/note_off.js +55 -0
- package/synthetizer/worklet_system/worklet_methods/stopping_notes/stop_all_channels.js +16 -0
- package/synthetizer/worklet_system/worklet_methods/stopping_notes/stop_all_notes.js +30 -0
- package/synthetizer/worklet_system/worklet_methods/stopping_notes/voice_killing.js +63 -0
- package/synthetizer/worklet_system/worklet_methods/system_exclusive.js +31 -30
- package/synthetizer/worklet_system/worklet_methods/tuning_control/channel_pressure.js +24 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/pitch_wheel.js +33 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/poly_pressure.js +31 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/set_master_tuning.js +15 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/set_modulation_depth.js +27 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/set_octave_tuning.js +15 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/set_tuning.js +24 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/set_tuning_semitones.js +19 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/transpose_all_channels.js +15 -0
- package/synthetizer/worklet_system/worklet_methods/tuning_control/transpose_channel.js +31 -0
- package/synthetizer/worklet_system/worklet_utilities/controller_tables.js +10 -1
- package/synthetizer/worklet_system/worklet_utilities/lfo.js +2 -1
- package/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +4 -4
- package/synthetizer/worklet_system/worklet_utilities/modulator_curves.js +4 -5
- package/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +18 -18
- package/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +210 -206
- package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +354 -108
- package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +22 -9
- package/synthetizer/worklet_system/snapshot/snapshot.js +0 -311
- package/synthetizer/worklet_system/worklet_methods/controller_control.js +0 -260
- package/synthetizer/worklet_system/worklet_methods/note_off.js +0 -119
- package/synthetizer/worklet_system/worklet_methods/program_control.js +0 -282
- package/synthetizer/worklet_system/worklet_methods/tuning_control.js +0 -233
- 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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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.
|
|
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
|
-
|
|
96
|
-
|
|
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
|
-
|
|
238
|
+
if (!this.lockPreset)
|
|
239
|
+
{
|
|
240
|
+
this.bank = bank;
|
|
241
|
+
}
|
|
103
242
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
{
|
|
112
|
-
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
|