spessasynth_lib 3.25.22 → 3.26.0

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 (168) hide show
  1. package/README.md +29 -114
  2. package/index.js +33 -33
  3. package/package.json +16 -6
  4. package/external_midi/README.md +0 -4
  5. package/external_midi/midi_handler.js +0 -130
  6. package/external_midi/web_midi_link.js +0 -43
  7. package/externals/fflate/LICENSE +0 -21
  8. package/externals/fflate/fflate.min.js +0 -1
  9. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  10. package/externals/stbvorbis_sync/LICENSE +0 -202
  11. package/externals/stbvorbis_sync/NOTICE +0 -6
  12. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  13. package/midi/README.md +0 -32
  14. package/midi/basic_midi.js +0 -565
  15. package/midi/midi_builder.js +0 -202
  16. package/midi/midi_data.js +0 -63
  17. package/midi/midi_loader.js +0 -324
  18. package/midi/midi_message.js +0 -254
  19. package/midi/midi_sequence.js +0 -225
  20. package/midi/midi_tools/get_note_times.js +0 -154
  21. package/midi/midi_tools/midi_editor.js +0 -611
  22. package/midi/midi_tools/midi_writer.js +0 -99
  23. package/midi/midi_tools/rmidi_writer.js +0 -567
  24. package/midi/midi_tools/used_keys_loaded.js +0 -238
  25. package/midi/xmf_loader.js +0 -454
  26. package/sequencer/README.md +0 -32
  27. package/sequencer/sequencer_engine/events.js +0 -207
  28. package/sequencer/sequencer_engine/play.js +0 -353
  29. package/sequencer/sequencer_engine/process_event.js +0 -169
  30. package/sequencer/sequencer_engine/process_tick.js +0 -106
  31. package/sequencer/sequencer_engine/sequencer_engine.js +0 -337
  32. package/sequencer/sequencer_engine/song_control.js +0 -229
  33. package/sequencer/worklet_wrapper/default_sequencer_options.js +0 -8
  34. package/sequencer/worklet_wrapper/sequencer.js +0 -807
  35. package/sequencer/worklet_wrapper/sequencer_message.js +0 -53
  36. package/soundfont/README.md +0 -13
  37. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  38. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  39. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  40. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  41. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  42. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  43. package/soundfont/basic_soundfont/generator.js +0 -220
  44. package/soundfont/basic_soundfont/modulator.js +0 -378
  45. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  46. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  47. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  48. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  49. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  50. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  51. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  52. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  53. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  54. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  55. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  56. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  57. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  58. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  59. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  60. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  61. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  62. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  63. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  64. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  65. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  66. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  67. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  68. package/soundfont/dls/articulator_converter.js +0 -396
  69. package/soundfont/dls/dls_destinations.js +0 -38
  70. package/soundfont/dls/dls_preset.js +0 -44
  71. package/soundfont/dls/dls_sample.js +0 -75
  72. package/soundfont/dls/dls_soundfont.js +0 -186
  73. package/soundfont/dls/dls_sources.js +0 -62
  74. package/soundfont/dls/dls_zone.js +0 -95
  75. package/soundfont/dls/read_articulation.js +0 -299
  76. package/soundfont/dls/read_instrument.js +0 -121
  77. package/soundfont/dls/read_instrument_list.js +0 -17
  78. package/soundfont/dls/read_lart.js +0 -35
  79. package/soundfont/dls/read_region.js +0 -152
  80. package/soundfont/dls/read_samples.js +0 -270
  81. package/soundfont/load_soundfont.js +0 -21
  82. package/soundfont/read_sf2/generators.js +0 -46
  83. package/soundfont/read_sf2/instruments.js +0 -66
  84. package/soundfont/read_sf2/modulators.js +0 -36
  85. package/soundfont/read_sf2/presets.js +0 -80
  86. package/soundfont/read_sf2/samples.js +0 -304
  87. package/soundfont/read_sf2/soundfont.js +0 -305
  88. package/soundfont/read_sf2/zones.js +0 -263
  89. package/synthetizer/README.md +0 -10
  90. package/synthetizer/audio_effects/effects_config.js +0 -25
  91. package/synthetizer/audio_effects/fancy_chorus.js +0 -162
  92. package/synthetizer/audio_effects/rb_compressed.min.js +0 -1
  93. package/synthetizer/audio_effects/reverb.js +0 -35
  94. package/synthetizer/audio_effects/reverb_as_binary.js +0 -18
  95. package/synthetizer/audio_engine/README.md +0 -25
  96. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  97. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  98. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  99. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  100. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  101. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  102. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  103. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  104. package/synthetizer/audio_engine/engine_components/soundfont_manager/sfman_message.js +0 -9
  105. package/synthetizer/audio_engine/engine_components/soundfont_manager/soundfont_manager.js +0 -254
  106. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  107. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  108. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  109. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  110. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  111. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  112. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  113. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  114. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  115. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  116. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  117. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  118. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -174
  119. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  120. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  121. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  122. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  123. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  124. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  127. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  128. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  129. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  132. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -744
  133. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  134. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  135. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  142. package/synthetizer/audio_engine/main_processor.js +0 -765
  143. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  144. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  145. package/synthetizer/audio_engine/message_protocol/worklet_message.js +0 -107
  146. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  147. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  148. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  149. package/synthetizer/synth_constants.js +0 -20
  150. package/synthetizer/worklet_processor.min.js +0 -21
  151. package/synthetizer/worklet_wrapper/key_modifier_manager.js +0 -104
  152. package/synthetizer/worklet_wrapper/synth_event_handler.js +0 -214
  153. package/synthetizer/worklet_wrapper/synth_soundfont_manager.js +0 -111
  154. package/synthetizer/worklet_wrapper/synthetizer.js +0 -1027
  155. package/synthetizer/worklet_wrapper/worklet_processor.js +0 -340
  156. package/synthetizer/worklet_wrapper/worklet_url.js +0 -16
  157. package/utils/README.md +0 -5
  158. package/utils/buffer_to_wav.js +0 -186
  159. package/utils/byte_functions/big_endian.js +0 -32
  160. package/utils/byte_functions/little_endian.js +0 -77
  161. package/utils/byte_functions/string.js +0 -107
  162. package/utils/byte_functions/variable_length_quantity.js +0 -42
  163. package/utils/fill_with_defaults.js +0 -21
  164. package/utils/indexed_array.js +0 -52
  165. package/utils/loggin.js +0 -79
  166. package/utils/other.js +0 -92
  167. package/utils/sysex_detector.js +0 -58
  168. package/utils/xg_hacks.js +0 -193
@@ -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/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 < 127; 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 };