spessasynth_lib 3.25.23 → 3.26.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 (162) hide show
  1. package/README.md +29 -114
  2. package/external_midi/midi_handler.js +14 -14
  3. package/external_midi/web_midi_link.js +3 -3
  4. package/index.js +33 -33
  5. package/package.json +19 -6
  6. package/{midi → sequencer}/midi_data.js +1 -1
  7. package/sequencer/{worklet_wrapper/sequencer.js → sequencer.js} +13 -12
  8. package/sequencer/{worklet_wrapper/sequencer_message.js → sequencer_message.js} +1 -1
  9. package/synthetizer/README.md +29 -1
  10. package/synthetizer/audio_effects/reverb_as_binary.js +2 -2
  11. package/synthetizer/{worklet_wrapper/key_modifier_manager.js → key_modifier_manager.js} +11 -2
  12. package/synthetizer/{worklet_wrapper/synth_event_handler.js → synth_event_handler.js} +16 -13
  13. package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js} +8 -5
  14. package/synthetizer/{worklet_wrapper/synthetizer.js → synthetizer.js} +29 -23
  15. package/synthetizer/{audio_engine/message_protocol/worklet_message.js → worklet_message.js} +15 -2
  16. package/synthetizer/{worklet_wrapper/worklet_processor.js → worklet_processor.js} +214 -31
  17. package/synthetizer/worklet_processor.min.js +13 -12
  18. package/synthetizer/worklet_processor.min.js.map +7 -0
  19. package/synthetizer/{worklet_wrapper/worklet_url.js → worklet_url.js} +2 -0
  20. package/utils/buffer_to_wav.js +7 -165
  21. package/utils/other.js +3 -84
  22. package/externals/fflate/LICENSE +0 -21
  23. package/externals/fflate/fflate.min.js +0 -1
  24. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  25. package/externals/stbvorbis_sync/LICENSE +0 -202
  26. package/externals/stbvorbis_sync/NOTICE +0 -6
  27. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  28. package/midi/README.md +0 -32
  29. package/midi/basic_midi.js +0 -565
  30. package/midi/midi_builder.js +0 -202
  31. package/midi/midi_loader.js +0 -324
  32. package/midi/midi_message.js +0 -254
  33. package/midi/midi_sequence.js +0 -225
  34. package/midi/midi_tools/get_note_times.js +0 -154
  35. package/midi/midi_tools/midi_editor.js +0 -611
  36. package/midi/midi_tools/midi_writer.js +0 -99
  37. package/midi/midi_tools/rmidi_writer.js +0 -567
  38. package/midi/midi_tools/used_keys_loaded.js +0 -238
  39. package/midi/xmf_loader.js +0 -454
  40. package/sequencer/sequencer_engine/events.js +0 -104
  41. package/sequencer/sequencer_engine/play.js +0 -353
  42. package/sequencer/sequencer_engine/process_event.js +0 -169
  43. package/sequencer/sequencer_engine/process_tick.js +0 -106
  44. package/sequencer/sequencer_engine/sequencer_engine.js +0 -335
  45. package/sequencer/sequencer_engine/song_control.js +0 -229
  46. package/soundfont/README.md +0 -13
  47. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  48. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  49. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  50. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  51. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  52. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  53. package/soundfont/basic_soundfont/generator.js +0 -220
  54. package/soundfont/basic_soundfont/modulator.js +0 -378
  55. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  56. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  57. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  58. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  59. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  60. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  61. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  62. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  63. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  64. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  65. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  66. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  67. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  68. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  69. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  70. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  71. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  72. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  73. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  74. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  75. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  76. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  77. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  78. package/soundfont/dls/articulator_converter.js +0 -396
  79. package/soundfont/dls/dls_destinations.js +0 -38
  80. package/soundfont/dls/dls_preset.js +0 -44
  81. package/soundfont/dls/dls_sample.js +0 -75
  82. package/soundfont/dls/dls_soundfont.js +0 -186
  83. package/soundfont/dls/dls_sources.js +0 -62
  84. package/soundfont/dls/dls_zone.js +0 -95
  85. package/soundfont/dls/read_articulation.js +0 -299
  86. package/soundfont/dls/read_instrument.js +0 -121
  87. package/soundfont/dls/read_instrument_list.js +0 -17
  88. package/soundfont/dls/read_lart.js +0 -35
  89. package/soundfont/dls/read_region.js +0 -152
  90. package/soundfont/dls/read_samples.js +0 -270
  91. package/soundfont/load_soundfont.js +0 -21
  92. package/soundfont/read_sf2/generators.js +0 -46
  93. package/soundfont/read_sf2/instruments.js +0 -66
  94. package/soundfont/read_sf2/modulators.js +0 -36
  95. package/soundfont/read_sf2/presets.js +0 -80
  96. package/soundfont/read_sf2/samples.js +0 -304
  97. package/soundfont/read_sf2/soundfont.js +0 -305
  98. package/soundfont/read_sf2/zones.js +0 -263
  99. package/synthetizer/audio_engine/README.md +0 -25
  100. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  101. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  102. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  103. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  104. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  105. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  106. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  107. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  108. package/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -228
  109. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  110. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  111. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  112. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  113. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  114. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  115. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  116. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  117. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  118. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  119. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  120. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  121. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -175
  122. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  123. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  124. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  127. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  128. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  129. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  132. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  133. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  134. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  135. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -776
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  142. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  143. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  144. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  145. package/synthetizer/audio_engine/main_processor.js +0 -765
  146. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  147. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  148. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  149. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  150. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  151. package/synthetizer/synth_constants.js +0 -20
  152. package/utils/README.md +0 -5
  153. package/utils/byte_functions/big_endian.js +0 -32
  154. package/utils/byte_functions/little_endian.js +0 -77
  155. package/utils/byte_functions/string.js +0 -107
  156. package/utils/byte_functions/variable_length_quantity.js +0 -42
  157. package/utils/indexed_array.js +0 -52
  158. package/utils/loggin.js +0 -79
  159. package/utils/sysex_detector.js +0 -58
  160. package/utils/xg_hacks.js +0 -193
  161. /package/sequencer/{worklet_wrapper/default_sequencer_options.js → default_sequencer_options.js} +0 -0
  162. /package/synthetizer/{worklet_wrapper/sfman_message.js → sfman_message.js} +0 -0
@@ -1,765 +0,0 @@
1
- import { SpessaSynthSequencer } from "../../sequencer/sequencer_engine/sequencer_engine.js";
2
- import { SpessaSynthInfo } from "../../utils/loggin.js";
3
- import { consoleColors } from "../../utils/other.js";
4
- import { voiceKilling } from "./engine_methods/stopping_notes/voice_killing.js";
5
- import { ALL_CHANNELS_OR_DIFFERENT_ACTION, returnMessageType } from "./message_protocol/worklet_message.js";
6
- import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
7
- import { VOLUME_ENVELOPE_SMOOTHING_FACTOR } from "./engine_components/volume_envelope.js";
8
- import { callEvent } from "./message_protocol/message_sending.js";
9
- import { systemExclusive } from "./engine_methods/system_exclusive.js";
10
- import { masterParameterType, setMasterParameter } from "./engine_methods/controller_control/master_parameters.js";
11
- import { resetAllControllers } from "./engine_methods/controller_control/reset_controllers.js";
12
- import { WorkletSoundfontManager } from "./engine_components/soundfont_manager.js";
13
- import { interpolationTypes } from "./engine_components/wavetable_oscillator.js";
14
- import { KeyModifierManager } from "./engine_components/key_modifier_manager.js";
15
- import { getVoices } from "./engine_components/voice.js";
16
- import { PAN_SMOOTHING_FACTOR } from "./engine_components/stereo_panner.js";
17
- import { stopAllChannels } from "./engine_methods/stopping_notes/stop_all_channels.js";
18
- import { setEmbeddedSoundFont } from "./engine_methods/soundfont_management/set_embedded_sound_font.js";
19
- import { reloadSoundFont } from "./engine_methods/soundfont_management/reload_sound_font.js";
20
- import { clearSoundFont } from "./engine_methods/soundfont_management/clear_sound_font.js";
21
- import { sendPresetList } from "./engine_methods/soundfont_management/send_preset_list.js";
22
- import { getPreset } from "./engine_methods/soundfont_management/get_preset.js";
23
- import { transposeAllChannels } from "./engine_methods/tuning_control/transpose_all_channels.js";
24
- import { setMasterTuning } from "./engine_methods/tuning_control/set_master_tuning.js";
25
- import { applySynthesizerSnapshot } from "./snapshot/apply_synthesizer_snapshot.js";
26
- import { createMidiChannel } from "./engine_methods/create_midi_channel.js";
27
- import { FILTER_SMOOTHING_FACTOR } from "./engine_components/lowpass_filter.js";
28
- import { DEFAULT_PERCUSSION, DEFAULT_SYNTH_MODE, VOICE_CAP } from "../synth_constants.js";
29
- import { fillWithDefaults } from "../../utils/fill_with_defaults.js";
30
- import { DEFAULT_SEQUENCER_OPTIONS } from "../../sequencer/worklet_wrapper/default_sequencer_options.js";
31
- import { getEvent, messageTypes } from "../../midi/midi_message.js";
32
- import { IndexedByteArray } from "../../utils/indexed_array.js";
33
-
34
-
35
- /**
36
- * @typedef {"gm"|"gm2"|"gs"|"xg"} SynthSystem
37
- */
38
-
39
- /**
40
- * main_processor.js
41
- * purpose: the core synthesis engine
42
- */
43
-
44
- // if the note is released faster than that, it forced to last that long
45
- // this is used mostly for drum channels, where a lot of midis like to send instant note off after a note on
46
- export const MIN_NOTE_LENGTH = 0.03;
47
- // this sounds way nicer for an instant hi-hat cutoff
48
- export const MIN_EXCLUSIVE_LENGTH = 0.07;
49
-
50
- export const SYNTHESIZER_GAIN = 1.0;
51
-
52
-
53
- // the core synthesis engine of spessasynth.
54
- class SpessaSynthProcessor
55
- {
56
-
57
- /**
58
- * Cached voices for all presets for this synthesizer.
59
- * Nesting goes like this:
60
- * this.cachedVoices[bankNumber][programNumber][midiNote][velocity] = a list of Voices for that.
61
- * @type {Voice[][][][][]}
62
- */
63
- cachedVoices = [];
64
-
65
- /**
66
- * Synth's device id: -1 means all
67
- * @type {number}
68
- */
69
- deviceID = ALL_CHANNELS_OR_DIFFERENT_ACTION;
70
-
71
- /**
72
- * Synth's event queue from the main thread
73
- * @type {{callback: function(), time: number}[]}
74
- */
75
- eventQueue = [];
76
-
77
- /**
78
- * Interpolation type used
79
- * @type {interpolationTypes}
80
- */
81
- interpolationType = interpolationTypes.fourthOrder;
82
-
83
- /**
84
- * The sequencer attached to this processor
85
- * @type {SpessaSynthSequencer}
86
- */
87
- sequencer = new SpessaSynthSequencer(this);
88
-
89
- /**
90
- * Global transposition in semitones
91
- * @type {number}
92
- */
93
- transposition = 0;
94
-
95
- /**
96
- * this.tunings[program][key] = tuning
97
- * @type {MTSProgramTuning[]}
98
- */
99
- tunings = [];
100
-
101
-
102
- /**
103
- * Bank offset for things like embedded RMIDIS. Added for every program change
104
- * @type {number}
105
- */
106
- soundfontBankOffset = 0;
107
-
108
-
109
- /**
110
- * The volume gain, set by user
111
- * @type {number}
112
- */
113
- masterGain = SYNTHESIZER_GAIN;
114
-
115
- /**
116
- * The volume gain, set by MIDI sysEx
117
- * @type {number}
118
- */
119
- midiVolume = 1;
120
-
121
- /**
122
- * Reverb linear gain
123
- * @type {number}
124
- */
125
- reverbGain = 1;
126
- /**
127
- * Chorus linear gain
128
- * @type {number}
129
- */
130
- chorusGain = 1;
131
-
132
- /**
133
- * Maximum number of voices allowed at once
134
- * @type {number}
135
- */
136
- voiceCap = VOICE_CAP;
137
-
138
- /**
139
- * (-1 to 1)
140
- * @type {number}
141
- */
142
- pan = 0.0;
143
- /**
144
- * the pan of the left channel
145
- * @type {number}
146
- */
147
- panLeft = 0.5;
148
-
149
- /**
150
- * the pan of the right channel
151
- * @type {number}
152
- */
153
- panRight = 0.5;
154
-
155
- /**
156
- * forces note killing instead of releasing
157
- * @type {boolean}
158
- */
159
- highPerformanceMode = false;
160
-
161
- /**
162
- * Handlese custom key overrides: velocity and preset
163
- * @type {KeyModifierManager}
164
- */
165
- keyModifierManager = new KeyModifierManager();
166
-
167
- /**
168
- * Overrides the main soundfont (embedded, for example)
169
- * @type {BasicSoundBank}
170
- */
171
- overrideSoundfont = undefined;
172
-
173
- /**
174
- * contains all the channels with their voices on the processor size
175
- * @type {MidiAudioChannel[]}
176
- */
177
- midiAudioChannels = [];
178
-
179
- /**
180
- * Controls the bank selection & SysEx
181
- * @type {SynthSystem}
182
- */
183
- system = DEFAULT_SYNTH_MODE;
184
- /**
185
- * Current total voices amount
186
- * @type {number}
187
- */
188
- totalVoicesAmount = 0;
189
-
190
- /**
191
- * Synth's default (reset) preset
192
- * @type {BasicPreset}
193
- */
194
- defaultPreset;
195
-
196
- defaultPresetUsesOverride = false;
197
-
198
- /**
199
- * Synth's default (reset) drum preset
200
- * @type {BasicPreset}
201
- */
202
- drumPreset;
203
-
204
- defaultDrumsUsesOverride = false;
205
-
206
- /**
207
- * Controls if the worklet processor is fully initialized
208
- * @type {Promise<boolean>}
209
- */
210
- processorInitialized = stbvorbis.isInitialized;
211
-
212
- /**
213
- * Current audio time
214
- * @type {number}
215
- */
216
- currentSynthTime = 0;
217
-
218
- /**
219
- * in hertz
220
- * @type {number}
221
- */
222
- sampleRate;
223
-
224
- /**
225
- * Creates a new worklet synthesis system. contains all channels
226
- * @param midiChannels {number}
227
- * @param soundfont {ArrayBuffer}
228
- * @param enableEventSystem {boolean}
229
- * @param startRenderingData {StartRenderingDataConfig}
230
- * @param postCallback {function(data: WorkletReturnMessage)}
231
- * @param sampleRate {number}
232
- * @param initialTime {number}
233
- * @param effectsEnabled {boolean}
234
- */
235
- constructor(midiChannels,
236
- soundfont,
237
- sampleRate,
238
- postCallback,
239
- effectsEnabled = true,
240
- enableEventSystem = true,
241
- startRenderingData = {},
242
- initialTime = 0)
243
- {
244
- /**
245
- * Midi output count
246
- * @type {number}
247
- */
248
- this.midiOutputsCount = midiChannels;
249
- /**
250
- * are the chorus and reverb effects enabled?
251
- * @type {boolean}
252
- */
253
- this.effectsEnabled = effectsEnabled;
254
- let initialChannelCount = this.midiOutputsCount;
255
- /**
256
- * @type {function(WorkletReturnMessage)}
257
- */
258
- this.postCallback = postCallback;
259
-
260
- this.currentSynthTime = initialTime;
261
- this.sampleRate = sampleRate;
262
-
263
- /**
264
- * Sample time in seconds
265
- * @type {number}
266
- */
267
- this.sampleTime = 1 / sampleRate;
268
-
269
- this.enableEventSystem = enableEventSystem && typeof postCallback === "function";
270
-
271
-
272
- for (let i = 0; i < 128; i++)
273
- {
274
- this.tunings.push([]);
275
- }
276
-
277
- try
278
- {
279
- /**
280
- * @type {WorkletSoundfontManager}
281
- */
282
- this.soundfontManager = new WorkletSoundfontManager(
283
- soundfont,
284
- this.postReady.bind(this)
285
- );
286
- }
287
- catch (e)
288
- {
289
- this.post({
290
- messageType: returnMessageType.soundfontError,
291
- messageData: e
292
- });
293
- throw e;
294
- }
295
- this.sendPresetList();
296
-
297
- this.getDefaultPresets();
298
-
299
-
300
- for (let i = 0; i < initialChannelCount; i++)
301
- {
302
- this.createWorkletChannel(false);
303
- }
304
-
305
- this.midiAudioChannels[DEFAULT_PERCUSSION].preset = this.drumPreset;
306
- this.midiAudioChannels[DEFAULT_PERCUSSION].drumChannel = true;
307
-
308
- // these smoothing factors were tested on 44,100 Hz, adjust them to target sample rate here
309
- this.volumeEnvelopeSmoothingFactor = VOLUME_ENVELOPE_SMOOTHING_FACTOR * (44100 / sampleRate);
310
- this.panSmoothingFactor = PAN_SMOOTHING_FACTOR * (44100 / sampleRate);
311
- this.filterSmoothingFactor = FILTER_SMOOTHING_FACTOR * (44100 / sampleRate);
312
-
313
- /**
314
- * The snapshot that synth was restored from
315
- * @type {SynthesizerSnapshot|undefined}
316
- * @private
317
- */
318
- this._snapshot = startRenderingData?.snapshot;
319
-
320
- // if sent, start rendering
321
- if (startRenderingData)
322
- {
323
- if (this._snapshot !== undefined)
324
- {
325
- this.applySynthesizerSnapshot(this._snapshot);
326
- this.resetAllControllers();
327
- }
328
-
329
- SpessaSynthInfo("%cRendering enabled! Starting render.", consoleColors.info);
330
- if (startRenderingData.parsedMIDI)
331
- {
332
- if (startRenderingData?.loopCount !== undefined)
333
- {
334
- this.sequencer.loopCount = startRenderingData?.loopCount;
335
- this.sequencer.loop = true;
336
- }
337
- else
338
- {
339
- this.sequencer.loop = false;
340
- }
341
- // set voice cap to unlimited
342
- this.voiceCap = Infinity;
343
- this.processorInitialized.then(() =>
344
- {
345
- /**
346
- * set options
347
- * @type {SequencerOptions}
348
- */
349
- const seqOptions = fillWithDefaults(
350
- startRenderingData.sequencerOptions,
351
- DEFAULT_SEQUENCER_OPTIONS
352
- );
353
- this.sequencer.skipToFirstNoteOn = seqOptions.skipToFirstNoteOn;
354
- this.sequencer.preservePlaybackState = seqOptions.preservePlaybackState;
355
- // autoplay is ignored
356
- this.sequencer.loadNewSongList([startRenderingData.parsedMIDI]);
357
- });
358
- }
359
- }
360
-
361
- this.postReady();
362
- }
363
-
364
- /**
365
- * @returns {number}
366
- */
367
- get currentGain()
368
- {
369
- return this.masterGain * this.midiVolume;
370
- }
371
-
372
- getDefaultPresets()
373
- {
374
- // override this to XG, to set the default preset to NOT be XG drums!
375
- const sys = this.system;
376
- this.system = "xg";
377
- this.defaultPreset = this.getPreset(0, 0);
378
- this.defaultPresetUsesOverride = this.overrideSoundfont?.presets?.indexOf(this.defaultPreset) >= 0;
379
- this.system = sys;
380
- this.drumPreset = this.getPreset(128, 0);
381
- this.defaultDrumsUsesOverride = this.overrideSoundfont?.presets?.indexOf(this.drumPreset) >= 0;
382
- }
383
-
384
- /**
385
- * @param value {SynthSystem}
386
- */
387
- setSystem(value)
388
- {
389
- this.system = value;
390
- this.post({
391
- messageType: returnMessageType.masterParameterChange,
392
- messageData: [masterParameterType.midiSystem, this.system]
393
- });
394
- }
395
-
396
- /**
397
- * @param bank {number}
398
- * @param program {number}
399
- * @param midiNote {number}
400
- * @param velocity {number}
401
- * @returns {Voice[]|undefined}
402
- */
403
- getCachedVoice(bank, program, midiNote, velocity)
404
- {
405
- return this.cachedVoices?.[bank]?.[program]?.[midiNote]?.[velocity];
406
- }
407
-
408
- /**
409
- * @param bank {number}
410
- * @param program {number}
411
- * @param midiNote {number}
412
- * @param velocity {number}
413
- * @param voices {Voice[]}
414
- */
415
- setCachedVoice(bank, program, midiNote, velocity, voices)
416
- {
417
- // make sure that it exists
418
- if (!this.cachedVoices)
419
- {
420
- this.cachedVoices = [];
421
- }
422
- if (!this.cachedVoices[bank])
423
- {
424
- this.cachedVoices[bank] = [];
425
- }
426
- if (!this.cachedVoices[bank][program])
427
- {
428
- this.cachedVoices[bank][program] = [];
429
- }
430
- if (!this.cachedVoices[bank][program][midiNote])
431
- {
432
- this.cachedVoices[bank][program][midiNote] = [];
433
- }
434
-
435
- // cache
436
- this.cachedVoices[bank][program][midiNote][velocity] = voices;
437
- }
438
-
439
-
440
- /**
441
- * @param data {WorkletReturnMessage}
442
- * @param force {boolean}
443
- */
444
- post(data, force = false)
445
- {
446
- if (!this.enableEventSystem && !force)
447
- {
448
- return;
449
- }
450
- if (this.postCallback)
451
- {
452
- this.postCallback(data);
453
- }
454
- }
455
-
456
- postReady()
457
- {
458
- // ensure stbvorbis is fully initialized
459
- this.processorInitialized.then(() =>
460
- {
461
- // post-ready cannot be constrained by the event system
462
- this.post({
463
- messageType: returnMessageType.isFullyInitialized,
464
- messageData: undefined
465
- }, true);
466
- SpessaSynthInfo("%cSpessaSynth is ready!", consoleColors.recognized);
467
- });
468
- }
469
-
470
- debugMessage()
471
- {
472
- SpessaSynthInfo({
473
- channels: this.midiAudioChannels,
474
- voicesAmount: this.totalVoicesAmount
475
- });
476
- }
477
-
478
- // noinspection JSUnusedGlobalSymbols
479
- /**
480
- * Renders float32 audio data to stereo outputs; buffer size of 128 is recommended
481
- * All float arrays must have the same length
482
- * @param outputs {Float32Array[]} output stereo channels (L, R)
483
- * @param reverb {Float32Array[]} reverb stereo channels (L, R)
484
- * @param chorus {Float32Array[]} chorus stereo channels (L, R)
485
- */
486
- renderAudio(outputs, reverb, chorus)
487
- {
488
- this.renderAudioSplit(reverb, chorus, Array(16).fill(outputs));
489
- }
490
-
491
- /**
492
- * Renders the float32 audio data of each channel; buffer size of 128 is recommended
493
- * All float arrays must have the same length
494
- * @param reverbChannels {Float32Array[]} reverb stereo channels (L, R)
495
- * @param chorusChannels {Float32Array[]} chorus stereo channels (L, R)
496
- * @param separateChannels {Float32Array[][]} a total of 16 stereo pairs (L, R) for each MIDI channel
497
- */
498
- renderAudioSplit(reverbChannels, chorusChannels, separateChannels)
499
- {
500
- // process the sequencer playback
501
- this.sequencer.processTick();
502
-
503
- // process event queue
504
- const time = this.currentSynthTime;
505
- while (this.eventQueue[0]?.time <= time)
506
- {
507
- this.eventQueue.shift().callback();
508
- }
509
- const revL = reverbChannels[0];
510
- const revR = reverbChannels[1];
511
- const chrL = chorusChannels[0];
512
- const chrR = chorusChannels[1];
513
-
514
- // for every channel
515
- this.totalVoicesAmount = 0;
516
- this.midiAudioChannels.forEach((channel, index) =>
517
- {
518
- if (channel.voices.length < 1 || channel.isMuted)
519
- {
520
- // there's nothing to do!
521
- return;
522
- }
523
- let voiceCount = channel.voices.length;
524
- const ch = index % 16;
525
-
526
- // render to the appropriate output
527
- channel.renderAudio(
528
- separateChannels[ch][0], separateChannels[ch][1],
529
- revL, revR,
530
- chrL, chrR
531
- );
532
-
533
- this.totalVoicesAmount += channel.voices.length;
534
- // if voice count changed, update voice amount
535
- if (channel.voices.length !== voiceCount)
536
- {
537
- channel.sendChannelProperty();
538
- }
539
- });
540
-
541
- // advance the time appropriately
542
- this.currentSynthTime += separateChannels[0][0].length * this.sampleTime;
543
- }
544
-
545
- destroySynthProcessor()
546
- {
547
- this.midiAudioChannels.forEach(c =>
548
- {
549
- delete c.midiControllers;
550
- delete c.voices;
551
- delete c.sustainedVoices;
552
- delete c.lockedControllers;
553
- delete c.preset;
554
- delete c.customControllers;
555
- });
556
- delete this.cachedVoices;
557
- delete this.midiAudioChannels;
558
- delete this.sequencer.midiData;
559
- delete this.sequencer;
560
- this.soundfontManager.destroyManager();
561
- delete this.soundfontManager;
562
- }
563
-
564
- /**
565
- * @param channel {number}
566
- * @param controllerNumber {number}
567
- * @param controllerValue {number}
568
- * @param force {boolean}
569
- */
570
- controllerChange(channel, controllerNumber, controllerValue, force = false)
571
- {
572
- this.midiAudioChannels[channel].controllerChange(controllerNumber, controllerValue, force);
573
- }
574
-
575
- /**
576
- * @param channel {number}
577
- * @param midiNote {number}
578
- * @param velocity {number}
579
- */
580
- noteOn(channel, midiNote, velocity)
581
- {
582
- this.midiAudioChannels[channel].noteOn(midiNote, velocity);
583
- }
584
-
585
- /**
586
- * @param channel {number}
587
- * @param midiNote {number}
588
- */
589
- noteOff(channel, midiNote)
590
- {
591
- this.midiAudioChannels[channel].noteOff(midiNote);
592
- }
593
-
594
- /**
595
- * @param channel {number}
596
- * @param midiNote {number}
597
- * @param pressure {number}
598
- */
599
- polyPressure(channel, midiNote, pressure)
600
- {
601
- this.midiAudioChannels[channel].polyPressure(midiNote, pressure);
602
- }
603
-
604
- /**
605
- * @param channel {number}
606
- * @param pressure {number}
607
- */
608
- channelPressure(channel, pressure)
609
- {
610
- this.midiAudioChannels[channel].channelPressure(pressure);
611
- }
612
-
613
- /**
614
- * @param channel {number}
615
- * @param MSB {number}
616
- * @param LSB {number}
617
- */
618
- pitchWheel(channel, MSB, LSB)
619
- {
620
- this.midiAudioChannels[channel].pitchWheel(MSB, LSB);
621
- }
622
-
623
- /**
624
- * @param channel {number}
625
- * @param programNumber {number}
626
- */
627
- programChange(channel, programNumber)
628
- {
629
- this.midiAudioChannels[channel].programChange(programNumber);
630
- }
631
-
632
- /**
633
- * @param message {Uint8Array}
634
- * @param channelOffset {number}
635
- * @param force {boolean} cool stuff
636
- * @param options {SynthMethodOptions}
637
- */
638
- processMessage(message, channelOffset, force, options)
639
- {
640
- const call = () =>
641
- {
642
- const statusByteData = getEvent(message[0]);
643
-
644
- const channel = statusByteData.channel + channelOffset;
645
- // process the event
646
- switch (statusByteData.status)
647
- {
648
- case messageTypes.noteOn:
649
- const velocity = message[2];
650
- if (velocity > 0)
651
- {
652
- this.noteOn(channel, message[1], velocity);
653
- }
654
- else
655
- {
656
- this.noteOff(channel, message[1]);
657
- }
658
- break;
659
-
660
- case messageTypes.noteOff:
661
- if (force)
662
- {
663
- this.midiAudioChannels[channel].killNote(message[1]);
664
- }
665
- else
666
- {
667
- this.noteOff(channel, message[1]);
668
- }
669
- break;
670
-
671
- case messageTypes.pitchBend:
672
- this.pitchWheel(channel, message[2], message[1]);
673
- break;
674
-
675
- case messageTypes.controllerChange:
676
- this.controllerChange(channel, message[1], message[2], force);
677
- break;
678
-
679
- case messageTypes.programChange:
680
- this.programChange(channel, message[1]);
681
- break;
682
-
683
- case messageTypes.polyPressure:
684
- this.polyPressure(channel, message[0], message[1]);
685
- break;
686
-
687
- case messageTypes.channelPressure:
688
- this.channelPressure(channel, message[1]);
689
- break;
690
-
691
- case messageTypes.systemExclusive:
692
- this.systemExclusive(new IndexedByteArray(message.slice(1)), channelOffset);
693
- break;
694
-
695
- case messageTypes.reset:
696
- this.stopAllChannels(true);
697
- this.resetAllControllers();
698
- break;
699
-
700
- default:
701
- break;
702
- }
703
- };
704
-
705
- const time = options.time;
706
- if (time > this.currentSynthTime)
707
- {
708
- this.eventQueue.push({
709
- callback: call.bind(this),
710
- time: time
711
- });
712
- this.eventQueue.sort((e1, e2) => e1.time - e2.time);
713
- }
714
- else
715
- {
716
- call();
717
- }
718
- }
719
-
720
- /**
721
- * @param volume {number} 0 to 1
722
- */
723
- setMIDIVolume(volume)
724
- {
725
- // GM2 specification, section 4.1: volume is squared.
726
- // though, according to my own testing, Math.E seems like a better choice
727
- this.midiVolume = Math.pow(volume, Math.E);
728
- this.setMasterParameter(masterParameterType.masterPan, this.pan);
729
- }
730
- }
731
-
732
- // include other methods
733
- // voice related
734
- SpessaSynthProcessor.prototype.voiceKilling = voiceKilling;
735
- SpessaSynthProcessor.prototype.getVoices = getVoices;
736
-
737
- // message port related
738
- SpessaSynthProcessor.prototype.callEvent = callEvent;
739
-
740
- // system-exclusive related
741
- SpessaSynthProcessor.prototype.systemExclusive = systemExclusive;
742
-
743
- // channel related
744
- SpessaSynthProcessor.prototype.stopAllChannels = stopAllChannels;
745
- SpessaSynthProcessor.prototype.createWorkletChannel = createMidiChannel;
746
- SpessaSynthProcessor.prototype.resetAllControllers = resetAllControllers;
747
-
748
- // master parameter related
749
- SpessaSynthProcessor.prototype.setMasterParameter = setMasterParameter;
750
-
751
- // tuning related
752
- SpessaSynthProcessor.prototype.transposeAllChannels = transposeAllChannels;
753
- SpessaSynthProcessor.prototype.setMasterTuning = setMasterTuning;
754
-
755
- // program related
756
- SpessaSynthProcessor.prototype.getPreset = getPreset;
757
- SpessaSynthProcessor.prototype.reloadSoundFont = reloadSoundFont;
758
- SpessaSynthProcessor.prototype.clearSoundFont = clearSoundFont;
759
- SpessaSynthProcessor.prototype.setEmbeddedSoundFont = setEmbeddedSoundFont;
760
- SpessaSynthProcessor.prototype.sendPresetList = sendPresetList;
761
-
762
- // snapshot related
763
- SpessaSynthProcessor.prototype.applySynthesizerSnapshot = applySynthesizerSnapshot;
764
-
765
- export { SpessaSynthProcessor };