spessasynth_lib 0.0.1

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 (154) hide show
  1. package/.idea/modules.xml +8 -0
  2. package/.idea/spessasynth_lib.iml +12 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/copy_version.sh +38 -0
  5. package/index.js +73 -0
  6. package/package/@types/externals/stbvorbis_sync/stbvorbis_sync.min.d.ts +1 -0
  7. package/package/@types/index.d.ts +34 -0
  8. package/package/@types/midi_handler/midi_handler.d.ts +39 -0
  9. package/package/@types/midi_handler/web_midi_link.d.ts +12 -0
  10. package/package/@types/midi_parser/midi_data.d.ts +95 -0
  11. package/package/@types/midi_parser/midi_editor.d.ts +45 -0
  12. package/package/@types/midi_parser/midi_loader.d.ts +100 -0
  13. package/package/@types/midi_parser/midi_message.d.ts +154 -0
  14. package/package/@types/midi_parser/midi_writer.d.ts +6 -0
  15. package/package/@types/midi_parser/rmidi_writer.d.ts +9 -0
  16. package/package/@types/midi_parser/used_keys_loaded.d.ts +7 -0
  17. package/package/@types/sequencer/sequencer.d.ts +180 -0
  18. package/package/@types/sequencer/worklet_sequencer/sequencer_message.d.ts +28 -0
  19. package/package/@types/soundfont/read/generators.d.ts +98 -0
  20. package/package/@types/soundfont/read/instruments.d.ts +50 -0
  21. package/package/@types/soundfont/read/modulators.d.ts +73 -0
  22. package/package/@types/soundfont/read/presets.d.ts +87 -0
  23. package/package/@types/soundfont/read/riff_chunk.d.ts +31 -0
  24. package/package/@types/soundfont/read/samples.d.ts +134 -0
  25. package/package/@types/soundfont/read/zones.d.ts +141 -0
  26. package/package/@types/soundfont/soundfont.d.ts +76 -0
  27. package/package/@types/soundfont/write/ibag.d.ts +6 -0
  28. package/package/@types/soundfont/write/igen.d.ts +6 -0
  29. package/package/@types/soundfont/write/imod.d.ts +6 -0
  30. package/package/@types/soundfont/write/inst.d.ts +6 -0
  31. package/package/@types/soundfont/write/pbag.d.ts +6 -0
  32. package/package/@types/soundfont/write/pgen.d.ts +6 -0
  33. package/package/@types/soundfont/write/phdr.d.ts +6 -0
  34. package/package/@types/soundfont/write/pmod.d.ts +6 -0
  35. package/package/@types/soundfont/write/sdta.d.ts +11 -0
  36. package/package/@types/soundfont/write/shdr.d.ts +8 -0
  37. package/package/@types/soundfont/write/soundfont_trimmer.d.ts +6 -0
  38. package/package/@types/soundfont/write/write.d.ts +21 -0
  39. package/package/@types/synthetizer/audio_effects/effects_config.d.ts +29 -0
  40. package/package/@types/synthetizer/audio_effects/fancy_chorus.d.ts +93 -0
  41. package/package/@types/synthetizer/audio_effects/reverb.d.ts +7 -0
  42. package/package/@types/synthetizer/synth_event_handler.d.ts +161 -0
  43. package/package/@types/synthetizer/synthetizer.d.ts +294 -0
  44. package/package/@types/synthetizer/worklet_system/message_protocol/worklet_message.d.ts +89 -0
  45. package/package/@types/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.d.ts +134 -0
  46. package/package/@types/synthetizer/worklet_url.d.ts +5 -0
  47. package/package/@types/utils/buffer_to_wav.d.ts +8 -0
  48. package/package/@types/utils/byte_functions/big_endian.d.ts +13 -0
  49. package/package/@types/utils/byte_functions/little_endian.d.ts +35 -0
  50. package/package/@types/utils/byte_functions/string.d.ts +22 -0
  51. package/package/@types/utils/byte_functions/variable_length_quantity.d.ts +12 -0
  52. package/package/@types/utils/indexed_array.d.ts +21 -0
  53. package/package/@types/utils/loggin.d.ts +26 -0
  54. package/package/@types/utils/other.d.ts +32 -0
  55. package/package/LICENSE +26 -0
  56. package/package/README.md +84 -0
  57. package/package/externals/NOTICE +9 -0
  58. package/package/externals/libvorbis/@types/OggVorbisEncoder.d.ts +34 -0
  59. package/package/externals/libvorbis/OggVorbisEncoder.min.js +1 -0
  60. package/package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +12 -0
  61. package/package/externals/stbvorbis_sync/LICENSE +202 -0
  62. package/package/externals/stbvorbis_sync/stbvorbis_sync.min.js +1 -0
  63. package/package/index.js +73 -0
  64. package/package/midi_handler/README.md +3 -0
  65. package/package/midi_handler/midi_handler.js +118 -0
  66. package/package/midi_handler/web_midi_link.js +41 -0
  67. package/package/midi_parser/README.md +3 -0
  68. package/package/midi_parser/midi_data.js +121 -0
  69. package/package/midi_parser/midi_editor.js +557 -0
  70. package/package/midi_parser/midi_loader.js +502 -0
  71. package/package/midi_parser/midi_message.js +234 -0
  72. package/package/midi_parser/midi_writer.js +95 -0
  73. package/package/midi_parser/rmidi_writer.js +271 -0
  74. package/package/midi_parser/used_keys_loaded.js +172 -0
  75. package/package/package.json +43 -0
  76. package/package/sequencer/README.md +23 -0
  77. package/package/sequencer/sequencer.js +439 -0
  78. package/package/sequencer/worklet_sequencer/events.js +92 -0
  79. package/package/sequencer/worklet_sequencer/play.js +309 -0
  80. package/package/sequencer/worklet_sequencer/process_event.js +167 -0
  81. package/package/sequencer/worklet_sequencer/process_tick.js +85 -0
  82. package/package/sequencer/worklet_sequencer/sequencer_message.js +39 -0
  83. package/package/sequencer/worklet_sequencer/song_control.js +193 -0
  84. package/package/sequencer/worklet_sequencer/worklet_sequencer.js +218 -0
  85. package/package/soundfont/README.md +8 -0
  86. package/package/soundfont/read/generators.js +212 -0
  87. package/package/soundfont/read/instruments.js +125 -0
  88. package/package/soundfont/read/modulators.js +249 -0
  89. package/package/soundfont/read/presets.js +300 -0
  90. package/package/soundfont/read/riff_chunk.js +81 -0
  91. package/package/soundfont/read/samples.js +398 -0
  92. package/package/soundfont/read/zones.js +310 -0
  93. package/package/soundfont/soundfont.js +357 -0
  94. package/package/soundfont/write/ibag.js +39 -0
  95. package/package/soundfont/write/igen.js +75 -0
  96. package/package/soundfont/write/imod.js +46 -0
  97. package/package/soundfont/write/inst.js +34 -0
  98. package/package/soundfont/write/pbag.js +39 -0
  99. package/package/soundfont/write/pgen.js +77 -0
  100. package/package/soundfont/write/phdr.js +42 -0
  101. package/package/soundfont/write/pmod.js +46 -0
  102. package/package/soundfont/write/sdta.js +72 -0
  103. package/package/soundfont/write/shdr.js +54 -0
  104. package/package/soundfont/write/soundfont_trimmer.js +169 -0
  105. package/package/soundfont/write/write.js +180 -0
  106. package/package/synthetizer/README.md +6 -0
  107. package/package/synthetizer/audio_effects/effects_config.js +21 -0
  108. package/package/synthetizer/audio_effects/fancy_chorus.js +120 -0
  109. package/package/synthetizer/audio_effects/impulse_response_2.flac +0 -0
  110. package/package/synthetizer/audio_effects/reverb.js +24 -0
  111. package/package/synthetizer/synth_event_handler.js +156 -0
  112. package/package/synthetizer/synthetizer.js +766 -0
  113. package/package/synthetizer/worklet_processor.min.js +13 -0
  114. package/package/synthetizer/worklet_system/README.md +6 -0
  115. package/package/synthetizer/worklet_system/main_processor.js +363 -0
  116. package/package/synthetizer/worklet_system/message_protocol/handle_message.js +197 -0
  117. package/package/synthetizer/worklet_system/message_protocol/message_sending.js +74 -0
  118. package/package/synthetizer/worklet_system/message_protocol/worklet_message.js +121 -0
  119. package/package/synthetizer/worklet_system/minify_processor.sh +4 -0
  120. package/package/synthetizer/worklet_system/worklet_methods/controller_control.js +230 -0
  121. package/package/synthetizer/worklet_system/worklet_methods/data_entry.js +277 -0
  122. package/package/synthetizer/worklet_system/worklet_methods/note_off.js +109 -0
  123. package/package/synthetizer/worklet_system/worklet_methods/note_on.js +91 -0
  124. package/package/synthetizer/worklet_system/worklet_methods/program_control.js +183 -0
  125. package/package/synthetizer/worklet_system/worklet_methods/reset_controllers.js +177 -0
  126. package/package/synthetizer/worklet_system/worklet_methods/snapshot.js +129 -0
  127. package/package/synthetizer/worklet_system/worklet_methods/system_exclusive.js +272 -0
  128. package/package/synthetizer/worklet_system/worklet_methods/tuning_control.js +195 -0
  129. package/package/synthetizer/worklet_system/worklet_methods/vibrato_control.js +29 -0
  130. package/package/synthetizer/worklet_system/worklet_methods/voice_control.js +233 -0
  131. package/package/synthetizer/worklet_system/worklet_processor.js +9 -0
  132. package/package/synthetizer/worklet_system/worklet_utilities/lfo.js +23 -0
  133. package/package/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +130 -0
  134. package/package/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +73 -0
  135. package/package/synthetizer/worklet_system/worklet_utilities/modulator_curves.js +86 -0
  136. package/package/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +81 -0
  137. package/package/synthetizer/worklet_system/worklet_utilities/unit_converter.js +66 -0
  138. package/package/synthetizer/worklet_system/worklet_utilities/volume_envelope.js +265 -0
  139. package/package/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +83 -0
  140. package/package/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +234 -0
  141. package/package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +116 -0
  142. package/package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +272 -0
  143. package/package/synthetizer/worklet_url.js +5 -0
  144. package/package/utils/README.md +4 -0
  145. package/package/utils/buffer_to_wav.js +101 -0
  146. package/package/utils/byte_functions/big_endian.js +28 -0
  147. package/package/utils/byte_functions/little_endian.js +74 -0
  148. package/package/utils/byte_functions/string.js +97 -0
  149. package/package/utils/byte_functions/variable_length_quantity.js +37 -0
  150. package/package/utils/encode_vorbis.js +30 -0
  151. package/package/utils/indexed_array.js +41 -0
  152. package/package/utils/loggin.js +79 -0
  153. package/package/utils/other.js +54 -0
  154. package/package.json +43 -0
@@ -0,0 +1,363 @@
1
+ import { DEFAULT_PERCUSSION, DEFAULT_SYNTH_MODE, VOICE_CAP } from '../synthetizer.js'
2
+ import {
3
+ createWorkletChannel,
4
+ } from './worklet_utilities/worklet_processor_channel.js'
5
+
6
+ import { SoundFont2 } from '../../soundfont/soundfont.js'
7
+ import { handleMessage } from './message_protocol/handle_message.js'
8
+ import { systemExclusive } from './worklet_methods/system_exclusive.js'
9
+ import { noteOn } from './worklet_methods/note_on.js'
10
+ import { dataEntryCoarse, dataEntryFine } from './worklet_methods/data_entry.js'
11
+ import { killNote, noteOff, stopAll, stopAllChannels } from './worklet_methods/note_off.js'
12
+ import {
13
+ controllerChange, muteChannel, setMasterGain, setMasterPan, setMIDIVolume,
14
+ } from './worklet_methods/controller_control.js'
15
+ import { callEvent, post, sendChannelProperties } from './message_protocol/message_sending.js'
16
+ import {
17
+ channelPressure,
18
+ pitchWheel, polyPressure,
19
+ setChannelTuning, setChannelTuningSemitones,
20
+ setMasterTuning, setModulationDepth,
21
+ transposeAllChannels,
22
+ transposeChannel,
23
+ } from './worklet_methods/tuning_control.js'
24
+ import {
25
+ programChange,
26
+ reloadSoundFont,
27
+ sampleDump,
28
+ sendPresetList,
29
+ setDrums,
30
+ setPreset,
31
+ } from './worklet_methods/program_control.js'
32
+ import { disableAndLockVibrato, setVibrato } from './worklet_methods/vibrato_control.js'
33
+ import { WorkletSequencer } from '../../sequencer/worklet_sequencer/worklet_sequencer.js'
34
+ import { SpessaSynthInfo } from '../../utils/loggin.js'
35
+ import { applySynthesizerSnapshot, sendSynthesizerSnapshot } from './worklet_methods/snapshot.js'
36
+ import { consoleColors } from '../../utils/other.js'
37
+ import { PAN_SMOOTHING_FACTOR, releaseVoice, renderVoice, voiceKilling } from './worklet_methods/voice_control.js'
38
+ import { returnMessageType } from './message_protocol/worklet_message.js'
39
+ import { stbvorbis } from '../../externals/stbvorbis_sync/stbvorbis_sync.min.js'
40
+ import { VOLUME_ENVELOPE_SMOOTHING_FACTOR } from './worklet_utilities/volume_envelope.js'
41
+ import { resetAllControllers, resetControllers, resetParameters } from './worklet_methods/reset_controllers.js'
42
+
43
+
44
+ /**
45
+ * worklet_processor.js
46
+ * purpose: manages the synthesizer (and worklet sequencer) from the AudioWorkletGlobalScope and renders the audio data
47
+ */
48
+
49
+ export const MIN_NOTE_LENGTH = 0.07; // if the note is released faster than that, it forced to last that long
50
+
51
+ export const SYNTHESIZER_GAIN = 1.0;
52
+
53
+ class SpessaSynthProcessor extends AudioWorkletProcessor {
54
+ /**
55
+ * Creates a new worklet synthesis system. contains all channels
56
+ * @param options {{
57
+ * processorOptions: {
58
+ * midiChannels: number,
59
+ * soundfont: ArrayBuffer,
60
+ * enableEventSystem: boolean,
61
+ * startRenderingData: {
62
+ * parsedMIDI: MIDI,
63
+ * snapshot: SynthesizerSnapshot,
64
+ * oneOutput: boolean
65
+ * }
66
+ * }}}
67
+ */
68
+ constructor(options) {
69
+ super();
70
+ this.oneOutputMode = options.processorOptions?.startRenderingData?.oneOutput === true;
71
+ this._outputsAmount = this.oneOutputMode ? 1 : options.processorOptions.midiChannels;
72
+
73
+ this.enableEventSystem = options.processorOptions.enableEventSystem;
74
+
75
+ /**
76
+ * @type {function}
77
+ */
78
+ this.processTickCallback = undefined;
79
+
80
+ this.sequencer = new WorkletSequencer(this);
81
+
82
+ this.transposition = 0;
83
+
84
+ /**
85
+ * The volume gain, set by user
86
+ * @type {number}
87
+ */
88
+ this.masterGain = SYNTHESIZER_GAIN;
89
+
90
+ this.midiVolume = 1;
91
+
92
+ /**
93
+ * Maximum number of voices allowed at once
94
+ * @type {number}
95
+ */
96
+ this.voiceCap = VOICE_CAP;
97
+
98
+ /**
99
+ * -1 to 1
100
+ * @type {number}
101
+ */
102
+ this.pan = 0.0;
103
+ /**
104
+ * the pan of the left channel
105
+ * @type {number}
106
+ */
107
+ this.panLeft = 0.5 * this.currentGain;
108
+
109
+ this.highPerformanceMode = false;
110
+
111
+ /**
112
+ * the pan of the right channel
113
+ * @type {number}
114
+ */
115
+ this.panRight = 0.5 * this.currentGain;
116
+ try
117
+ {
118
+ /**
119
+ * @type {SoundFont2}
120
+ */
121
+ this.soundfont = new SoundFont2(options.processorOptions.soundfont);
122
+ }
123
+ catch (e)
124
+ {
125
+ this.post({
126
+ messageType: returnMessageType.soundfontError,
127
+ messageData: e
128
+ });
129
+ throw e;
130
+ }
131
+ this.sendPresetList();
132
+
133
+ this.defaultPreset = this.soundfont.getPreset(0, 0);
134
+ this.drumPreset = this.soundfont.getPreset(128, 0);
135
+
136
+ /**
137
+ * @type {Float32Array[]}
138
+ */
139
+ this.workletDumpedSamplesList = [];
140
+ /**
141
+ * contains all the channels with their voices on the processor size
142
+ * @type {WorkletProcessorChannel[]}
143
+ */
144
+ this.workletProcessorChannels = [];
145
+ for (let i = 0; i < options.processorOptions.midiChannels; i++)
146
+ {
147
+ this.createWorkletChannel(false);
148
+ }
149
+
150
+ this.workletProcessorChannels[DEFAULT_PERCUSSION].preset = this.drumPreset;
151
+ this.workletProcessorChannels[DEFAULT_PERCUSSION].drumChannel = true;
152
+
153
+ // in seconds, time between two samples (very, very short)
154
+ this.sampleTime = 1 / sampleRate;
155
+
156
+ // these smoothing factors were tested on 44100Hz, adjust them here
157
+ this.volumeEnvelopeSmoothingFactor = VOLUME_ENVELOPE_SMOOTHING_FACTOR * (sampleRate / 44100);
158
+ this.panSmoothingFactor = PAN_SMOOTHING_FACTOR * (sampleRate / 44100);
159
+
160
+ /**
161
+ * Controls the system
162
+ * @typedef {"gm"|"gm2"|"gs"|"xg"} SynthSystem
163
+ */
164
+ /*
165
+ * @type {SynthSystem}
166
+ */
167
+ this.system = DEFAULT_SYNTH_MODE;
168
+
169
+ this.totalVoicesAmount = 0;
170
+
171
+ this.port.onmessage = e => this.handleMessage(e.data);
172
+
173
+ // if sent, start rendering
174
+ if(options.processorOptions.startRenderingData)
175
+ {
176
+ if (options.processorOptions.startRenderingData.snapshot)
177
+ {
178
+ this.applySynthesizerSnapshot(options.processorOptions.startRenderingData.snapshot);
179
+ this.resetAllControllers();
180
+ }
181
+
182
+ SpessaSynthInfo("%cRendering enabled! Starting render.", consoleColors.info)
183
+ if (options.processorOptions.startRenderingData.parsedMIDI)
184
+ {
185
+ this.sequencer.loadNewSongList([options.processorOptions.startRenderingData.parsedMIDI]);
186
+ this.sequencer.loop = false;
187
+ }
188
+ }
189
+
190
+ stbvorbis.isInitialized.then(() => {
191
+ this.post({
192
+ messageType: returnMessageType.ready,
193
+ messageData: undefined
194
+ });
195
+ SpessaSynthInfo("%cSpessaSynth is ready!", consoleColors.recognized);
196
+ });
197
+ }
198
+
199
+ /**
200
+ * @returns {number}
201
+ */
202
+ get currentGain()
203
+ {
204
+ return this.masterGain * this.midiVolume;
205
+ }
206
+
207
+ debugMessage()
208
+ {
209
+ SpessaSynthInfo({
210
+ channels: this.workletProcessorChannels,
211
+ voicesAmount: this.totalVoicesAmount,
212
+ outputAmount: this._outputsAmount,
213
+ dumpedSamples: this.workletDumpedSamplesList
214
+ });
215
+ }
216
+
217
+ /**
218
+ * Syntesizes the voice to buffers
219
+ * @param inputs {Float32Array[][]} required by WebAudioAPI
220
+ * @param outputs {Float32Array[][]} the outputs to write to, only the first 2 channels are populated
221
+ * @returns {boolean} true
222
+ */
223
+ process(inputs, outputs) {
224
+ if(this.processTickCallback)
225
+ {
226
+ this.processTickCallback();
227
+ }
228
+
229
+ // for every channel
230
+ let totalCurrentVoices = 0;
231
+ this.workletProcessorChannels.forEach((channel, index) => {
232
+ if(channel.voices.length < 1 || channel.isMuted)
233
+ {
234
+ // skip the channels
235
+ return;
236
+ }
237
+ let outputIndex;
238
+ let outputLeft;
239
+ let outputRight;
240
+ let reverbChannels;
241
+ let chorusChannels;
242
+ if(this.oneOutputMode)
243
+ {
244
+ // first output only
245
+ const output = outputs[0];
246
+ // reverb and chorus are disabled. 32 output channels: two for each midi channels
247
+ outputIndex = (index % 16) * 2;
248
+ outputLeft = output[outputIndex];
249
+ outputRight = output[outputIndex + 1];
250
+ }
251
+ else
252
+ {
253
+ // 2 first outputs are reverb and chorus, other are for channels
254
+ outputIndex = (index % this._outputsAmount) + 2;
255
+ outputLeft = outputs[outputIndex][0];
256
+ outputRight = outputs[outputIndex][1];
257
+ reverbChannels = outputs[0];
258
+ chorusChannels = outputs[1];
259
+ }
260
+
261
+ const tempV = channel.voices;
262
+
263
+ // reset voices
264
+ channel.voices = [];
265
+
266
+ // for every voice
267
+ tempV.forEach(v => {
268
+ // render voice
269
+ this.renderVoice(
270
+ channel,
271
+ v,
272
+ outputLeft, outputRight,
273
+ reverbChannels,
274
+ chorusChannels
275
+ );
276
+ if(!v.finished)
277
+ {
278
+ // if not finished, add it back
279
+ channel.voices.push(v);
280
+ }
281
+ });
282
+
283
+ totalCurrentVoices += tempV.length;
284
+ });
285
+
286
+ // if voice count changed, update voice amount
287
+ if(totalCurrentVoices !== this.totalVoicesAmount)
288
+ {
289
+ this.totalVoicesAmount = totalCurrentVoices;
290
+ this.sendChannelProperties();
291
+ }
292
+ return true;
293
+ }
294
+ }
295
+
296
+ // include other methods
297
+ // voice related
298
+ SpessaSynthProcessor.prototype.renderVoice = renderVoice;
299
+ SpessaSynthProcessor.prototype.releaseVoice = releaseVoice;
300
+ SpessaSynthProcessor.prototype.voiceKilling = voiceKilling;
301
+
302
+ // message port related
303
+ SpessaSynthProcessor.prototype.handleMessage = handleMessage;
304
+ SpessaSynthProcessor.prototype.post = post;
305
+ SpessaSynthProcessor.prototype.sendChannelProperties = sendChannelProperties;
306
+ SpessaSynthProcessor.prototype.callEvent = callEvent;
307
+
308
+ // system exlcusive related
309
+ SpessaSynthProcessor.prototype.systemExclusive = systemExclusive;
310
+
311
+ // note messages related
312
+ SpessaSynthProcessor.prototype.noteOn = noteOn;
313
+ SpessaSynthProcessor.prototype.noteOff = noteOff;
314
+ SpessaSynthProcessor.prototype.polyPressure = polyPressure;
315
+ SpessaSynthProcessor.prototype.killNote = killNote;
316
+ SpessaSynthProcessor.prototype.stopAll = stopAll;
317
+ SpessaSynthProcessor.prototype.stopAllChannels = stopAllChannels;
318
+ SpessaSynthProcessor.prototype.muteChannel = muteChannel;
319
+
320
+ // custom vibrato related
321
+ SpessaSynthProcessor.prototype.setVibrato = setVibrato;
322
+ SpessaSynthProcessor.prototype.disableAndLockVibrato = disableAndLockVibrato;
323
+
324
+ // data entry related
325
+ SpessaSynthProcessor.prototype.dataEntryCoarse = dataEntryCoarse;
326
+ SpessaSynthProcessor.prototype.dataEntryFine = dataEntryFine;
327
+
328
+ // channel related
329
+ SpessaSynthProcessor.prototype.createWorkletChannel = createWorkletChannel;
330
+ SpessaSynthProcessor.prototype.controllerChange = controllerChange;
331
+ SpessaSynthProcessor.prototype.channelPressure = channelPressure;
332
+ SpessaSynthProcessor.prototype.resetAllControllers = resetAllControllers;
333
+ SpessaSynthProcessor.prototype.resetControllers = resetControllers;
334
+ SpessaSynthProcessor.prototype.resetParameters = resetParameters;
335
+
336
+ // master parameter related
337
+ SpessaSynthProcessor.prototype.setMasterGain = setMasterGain;
338
+ SpessaSynthProcessor.prototype.setMasterPan = setMasterPan;
339
+ SpessaSynthProcessor.prototype.setMIDIVolume = setMIDIVolume;
340
+
341
+ // tuning related
342
+ SpessaSynthProcessor.prototype.transposeAllChannels = transposeAllChannels;
343
+ SpessaSynthProcessor.prototype.transposeChannel = transposeChannel;
344
+ SpessaSynthProcessor.prototype.setChannelTuning = setChannelTuning;
345
+ SpessaSynthProcessor.prototype.setChannelTuningSemitones = setChannelTuningSemitones;
346
+ SpessaSynthProcessor.prototype.setMasterTuning = setMasterTuning;
347
+ SpessaSynthProcessor.prototype.setModulationDepth = setModulationDepth;
348
+ SpessaSynthProcessor.prototype.pitchWheel = pitchWheel;
349
+
350
+ // program related
351
+ SpessaSynthProcessor.prototype.programChange = programChange;
352
+ SpessaSynthProcessor.prototype.setPreset = setPreset;
353
+ SpessaSynthProcessor.prototype.setDrums = setDrums;
354
+ SpessaSynthProcessor.prototype.reloadSoundFont = reloadSoundFont;
355
+ SpessaSynthProcessor.prototype.sampleDump = sampleDump;
356
+ SpessaSynthProcessor.prototype.sendPresetList = sendPresetList;
357
+
358
+ // snapshot related
359
+ SpessaSynthProcessor.prototype.sendSynthesizerSnapshot = sendSynthesizerSnapshot;
360
+ SpessaSynthProcessor.prototype.applySynthesizerSnapshot = applySynthesizerSnapshot;
361
+
362
+
363
+ export { SpessaSynthProcessor }
@@ -0,0 +1,197 @@
1
+ import { ALL_CHANNELS_OR_DIFFERENT_ACTION, masterParameterType, workletMessageType } from './worklet_message.js'
2
+ import { SpessaSynthLogging, SpessaSynthWarn } from '../../../utils/loggin.js'
3
+
4
+ /**
5
+ * @this {SpessaSynthProcessor}
6
+ * @param message
7
+ */
8
+ export function handleMessage(message)
9
+ {
10
+ const data = message.messageData;
11
+ const channel = message.channelNumber;
12
+ /**
13
+ * @type {WorkletProcessorChannel}
14
+ */
15
+ let channelObject = {};
16
+ if(channel >= 0)
17
+ {
18
+ channelObject = this.workletProcessorChannels[channel];
19
+ }
20
+ switch (message.messageType) {
21
+ case workletMessageType.noteOn:
22
+ this.noteOn(channel, data[0], data[1], data[2]);
23
+ break;
24
+
25
+ case workletMessageType.noteOff:
26
+ this.noteOff(channel, data);
27
+ break;
28
+
29
+ case workletMessageType.pitchWheel:
30
+ this.pitchWheel(channel, data[0], data[1]);
31
+ break;
32
+
33
+ case workletMessageType.ccChange:
34
+ this.controllerChange(channel, data[0], data[1], data[2]);
35
+ break;
36
+
37
+ case workletMessageType.customcCcChange:
38
+ // custom controller change
39
+ channelObject.customControllers[data[0]] = data[1];
40
+ break;
41
+
42
+ case workletMessageType.killNote:
43
+ this.killNote(channel, data);
44
+ break;
45
+
46
+ case workletMessageType.programChange:
47
+ this.programChange(channel, data[0], data[1]);
48
+ break;
49
+
50
+ case workletMessageType.channelPressure:
51
+ this.channelPressure(channel, data);
52
+ break;
53
+
54
+ case workletMessageType.polyPressure:
55
+ this.polyPressure(channel, data[0], data[1]);
56
+ break;
57
+
58
+ case workletMessageType.ccReset:
59
+ if(channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
60
+ {
61
+ this.resetAllControllers();
62
+ }
63
+ else
64
+ {
65
+ this.resetControllers(channel);
66
+ }
67
+ break;
68
+
69
+ case workletMessageType.systemExclusive:
70
+ this.systemExclusive(data);
71
+ break;
72
+
73
+ case workletMessageType.setChannelVibrato:
74
+ if(channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
75
+ {
76
+ for (let i = 0; i < this.workletProcessorChannels.length; i++)
77
+ {
78
+ if(data.rate === -1)
79
+ {
80
+ this.disableAndLockVibrato(i);
81
+ }
82
+ else
83
+ {
84
+ this.setVibrato(i, data.depth, data.rate, data.delay);
85
+ }
86
+ }
87
+ }
88
+ if(data.rate === -1)
89
+ {
90
+ this.disableAndLockVibrato(channel);
91
+ }
92
+ else
93
+ {
94
+ this.setVibrato(channel, data.depth, data.rate, data.delay);
95
+ }
96
+ break;
97
+
98
+ case workletMessageType.reloadSoundFont:
99
+ this.reloadSoundFont(data);
100
+ break;
101
+
102
+ case workletMessageType.stopAll:
103
+ if(channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
104
+ {
105
+ this.stopAllChannels(data === 1);
106
+ }
107
+ else
108
+ {
109
+ this.stopAll(channel, data === 1);
110
+ }
111
+ break;
112
+
113
+ case workletMessageType.killNotes:
114
+ this.voiceKilling(data);
115
+ break;
116
+
117
+ case workletMessageType.muteChannel:
118
+ this.muteChannel(channel, data);
119
+ break;
120
+
121
+ case workletMessageType.addNewChannel:
122
+ this.createWorkletChannel(true);
123
+ break;
124
+
125
+ case workletMessageType.debugMessage:
126
+ this.debugMessage();
127
+ break;
128
+
129
+ case workletMessageType.setMasterParameter:
130
+ /**
131
+ * @type {masterParameterType}
132
+ */
133
+ const type = data[0];
134
+ const value = data[1];
135
+ switch (type)
136
+ {
137
+ case masterParameterType.masterPan:
138
+ this.setMasterPan(value);
139
+ break;
140
+
141
+ case masterParameterType.mainVolume:
142
+ this.setMasterGain(value);
143
+ break;
144
+
145
+ case masterParameterType.voicesCap:
146
+ this.voiceCap = value;
147
+ break;
148
+ }
149
+ break;
150
+
151
+ case workletMessageType.setDrums:
152
+ this.setDrums(channel, data);
153
+ break;
154
+
155
+ case workletMessageType.transpose:
156
+ if(channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
157
+ {
158
+ this.transposeAllChannels(data[0], data[1]);
159
+ }
160
+ else
161
+ {
162
+ this.transposeChannel(channel, data[0], data[1]);
163
+ }
164
+ break;
165
+
166
+ case workletMessageType.highPerformanceMode:
167
+ this.highPerformanceMode = data;
168
+ break;
169
+
170
+ case workletMessageType.lockController:
171
+ if(data[0] === ALL_CHANNELS_OR_DIFFERENT_ACTION)
172
+ {
173
+ channelObject.lockPreset = data[1];
174
+ }
175
+ else
176
+ {
177
+ channelObject.lockedControllers[data[0]] = data[1];
178
+ }
179
+ break;
180
+
181
+ case workletMessageType.sequencerSpecific:
182
+ this.sequencer.processMessage(data.messageType, data.messageData);
183
+ break;
184
+
185
+ case workletMessageType.requestSynthesizerSnapshot:
186
+ this.sendSynthesizerSnapshot();
187
+ break;
188
+
189
+ case workletMessageType.setLogLevel:
190
+ SpessaSynthLogging(data[0], data[1], data[2], data[3]);
191
+ break;
192
+
193
+ default:
194
+ SpessaSynthWarn("Unrecognized event:", data);
195
+ break;
196
+ }
197
+ }
@@ -0,0 +1,74 @@
1
+ import { returnMessageType } from './worklet_message.js'
2
+ import { NON_CC_INDEX_OFFSET } from '../worklet_utilities/worklet_processor_channel.js'
3
+ import { modulatorSources } from '../../../soundfont/read/modulators.js'
4
+
5
+ /**
6
+ * Calls synth event from the worklet side
7
+ * @param eventName {EventTypes} the event name
8
+ * @param eventData {any}
9
+ * @this {SpessaSynthProcessor}
10
+ */
11
+ export function callEvent(eventName, eventData)
12
+ {
13
+ if(!this.enableEventSystem)
14
+ {
15
+ return;
16
+ }
17
+ this.post({
18
+ messageType: returnMessageType.eventCall,
19
+ messageData: {
20
+ eventName: eventName,
21
+ eventData: eventData
22
+ }
23
+ })
24
+ }
25
+
26
+ /**
27
+ * @param data {WorkletReturnMessage}
28
+ * @this {SpessaSynthProcessor}
29
+ */
30
+ export function post(data)
31
+ {
32
+ if(!this.enableEventSystem)
33
+ {
34
+ return;
35
+ }
36
+ this.port.postMessage(data);
37
+ }
38
+
39
+ /**
40
+ * @typedef {Object} ChannelProperty
41
+ * @property {number} voicesAmount
42
+ * @property {number} pitchBend - from -8192 do 8192
43
+ * @property {number} pitchBendRangeSemitones - in semitones
44
+ * @property {boolean} isMuted
45
+ * @property {boolean} isDrum
46
+ */
47
+
48
+ /**
49
+ * @this {SpessaSynthProcessor}
50
+ */
51
+ export function sendChannelProperties()
52
+ {
53
+ if(!this.enableEventSystem)
54
+ {
55
+ return;
56
+ }
57
+ /**
58
+ * @type {ChannelProperty[]}
59
+ */
60
+ const data = this.workletProcessorChannels.map(c => {
61
+ const range = (c.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange] >> 7) + (c.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange] & 0x7F) / 127;
62
+ return {
63
+ voicesAmount: c.voices.length,
64
+ pitchBend: c.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel],
65
+ pitchBendRangeSemitones: range,
66
+ isMuted: c.isMuted,
67
+ isDrum: c.drumChannel
68
+ }
69
+ });
70
+ this.post({
71
+ messageType: returnMessageType.channelProperties,
72
+ messageData: data
73
+ });
74
+ }