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