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.
- package/README.md +29 -114
- package/external_midi/midi_handler.js +14 -14
- package/external_midi/web_midi_link.js +3 -3
- package/index.js +33 -33
- package/package.json +19 -6
- package/{midi → sequencer}/midi_data.js +1 -1
- package/sequencer/{worklet_wrapper/sequencer.js → sequencer.js} +13 -12
- package/sequencer/{worklet_wrapper/sequencer_message.js → sequencer_message.js} +1 -1
- package/synthetizer/README.md +29 -1
- package/synthetizer/audio_effects/reverb_as_binary.js +2 -2
- package/synthetizer/{worklet_wrapper/key_modifier_manager.js → key_modifier_manager.js} +11 -2
- package/synthetizer/{worklet_wrapper/synth_event_handler.js → synth_event_handler.js} +16 -13
- package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js} +8 -5
- package/synthetizer/{worklet_wrapper/synthetizer.js → synthetizer.js} +29 -23
- package/synthetizer/{audio_engine/message_protocol/worklet_message.js → worklet_message.js} +15 -2
- package/synthetizer/{worklet_wrapper/worklet_processor.js → worklet_processor.js} +214 -31
- package/synthetizer/worklet_processor.min.js +13 -12
- package/synthetizer/worklet_processor.min.js.map +7 -0
- package/synthetizer/{worklet_wrapper/worklet_url.js → worklet_url.js} +2 -0
- package/utils/buffer_to_wav.js +7 -165
- package/utils/other.js +3 -84
- package/externals/fflate/LICENSE +0 -21
- package/externals/fflate/fflate.min.js +0 -1
- package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
- package/externals/stbvorbis_sync/LICENSE +0 -202
- package/externals/stbvorbis_sync/NOTICE +0 -6
- package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
- package/midi/README.md +0 -32
- package/midi/basic_midi.js +0 -565
- package/midi/midi_builder.js +0 -202
- package/midi/midi_loader.js +0 -324
- package/midi/midi_message.js +0 -254
- package/midi/midi_sequence.js +0 -225
- package/midi/midi_tools/get_note_times.js +0 -154
- package/midi/midi_tools/midi_editor.js +0 -611
- package/midi/midi_tools/midi_writer.js +0 -99
- package/midi/midi_tools/rmidi_writer.js +0 -567
- package/midi/midi_tools/used_keys_loaded.js +0 -238
- package/midi/xmf_loader.js +0 -454
- package/sequencer/sequencer_engine/events.js +0 -104
- package/sequencer/sequencer_engine/play.js +0 -353
- package/sequencer/sequencer_engine/process_event.js +0 -169
- package/sequencer/sequencer_engine/process_tick.js +0 -106
- package/sequencer/sequencer_engine/sequencer_engine.js +0 -335
- package/sequencer/sequencer_engine/song_control.js +0 -229
- package/soundfont/README.md +0 -13
- package/soundfont/basic_soundfont/basic_instrument.js +0 -77
- package/soundfont/basic_soundfont/basic_preset.js +0 -336
- package/soundfont/basic_soundfont/basic_sample.js +0 -197
- package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
- package/soundfont/basic_soundfont/basic_zone.js +0 -64
- package/soundfont/basic_soundfont/basic_zones.js +0 -43
- package/soundfont/basic_soundfont/generator.js +0 -220
- package/soundfont/basic_soundfont/modulator.js +0 -378
- package/soundfont/basic_soundfont/riff_chunk.js +0 -149
- package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
- package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
- package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
- package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
- package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
- package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
- package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
- package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
- package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
- package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
- package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
- package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
- package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
- package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
- package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
- package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
- package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
- package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
- package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
- package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
- package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
- package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
- package/soundfont/dls/articulator_converter.js +0 -396
- package/soundfont/dls/dls_destinations.js +0 -38
- package/soundfont/dls/dls_preset.js +0 -44
- package/soundfont/dls/dls_sample.js +0 -75
- package/soundfont/dls/dls_soundfont.js +0 -186
- package/soundfont/dls/dls_sources.js +0 -62
- package/soundfont/dls/dls_zone.js +0 -95
- package/soundfont/dls/read_articulation.js +0 -299
- package/soundfont/dls/read_instrument.js +0 -121
- package/soundfont/dls/read_instrument_list.js +0 -17
- package/soundfont/dls/read_lart.js +0 -35
- package/soundfont/dls/read_region.js +0 -152
- package/soundfont/dls/read_samples.js +0 -270
- package/soundfont/load_soundfont.js +0 -21
- package/soundfont/read_sf2/generators.js +0 -46
- package/soundfont/read_sf2/instruments.js +0 -66
- package/soundfont/read_sf2/modulators.js +0 -36
- package/soundfont/read_sf2/presets.js +0 -80
- package/soundfont/read_sf2/samples.js +0 -304
- package/soundfont/read_sf2/soundfont.js +0 -305
- package/soundfont/read_sf2/zones.js +0 -263
- package/synthetizer/audio_engine/README.md +0 -25
- package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
- package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
- package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
- package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
- package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
- package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
- package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
- package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
- package/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -228
- package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
- package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
- package/synthetizer/audio_engine/engine_components/voice.js +0 -519
- package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
- package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
- package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
- package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
- package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
- package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
- package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
- package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
- package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
- package/synthetizer/audio_engine/engine_methods/note_on.js +0 -175
- package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
- package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
- package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
- package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
- package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
- package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
- package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
- package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
- package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
- package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
- package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
- package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
- package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
- package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -776
- package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
- package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
- package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
- package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
- package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
- package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
- package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
- package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
- package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
- package/synthetizer/audio_engine/main_processor.js +0 -765
- package/synthetizer/audio_engine/message_protocol/README.md +0 -13
- package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
- package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
- package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
- package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
- package/synthetizer/synth_constants.js +0 -20
- package/utils/README.md +0 -5
- package/utils/byte_functions/big_endian.js +0 -32
- package/utils/byte_functions/little_endian.js +0 -77
- package/utils/byte_functions/string.js +0 -107
- package/utils/byte_functions/variable_length_quantity.js +0 -42
- package/utils/indexed_array.js +0 -52
- package/utils/loggin.js +0 -79
- package/utils/sysex_detector.js +0 -58
- package/utils/xg_hacks.js +0 -193
- /package/sequencer/{worklet_wrapper/default_sequencer_options.js → default_sequencer_options.js} +0 -0
- /package/synthetizer/{worklet_wrapper/sfman_message.js → sfman_message.js} +0 -0
package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { workletMessageType } from "
|
|
1
|
+
import { workletMessageType } from "./worklet_message.js";
|
|
2
2
|
import { WorkletSoundfontManagerMessageType } from "./sfman_message.js";
|
|
3
|
-
import {
|
|
3
|
+
import { SpessaSynthCoreUtils } from "spessasynth_core";
|
|
4
4
|
|
|
5
5
|
export class SoundfontManager
|
|
6
6
|
{
|
|
@@ -46,6 +46,7 @@ export class SoundfontManager
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// noinspection JSUnusedGlobalSymbols
|
|
49
50
|
/**
|
|
50
51
|
* Adds a new soundfont buffer with a given ID
|
|
51
52
|
* @param soundfontBuffer {ArrayBuffer} - the soundfont's buffer
|
|
@@ -66,6 +67,7 @@ export class SoundfontManager
|
|
|
66
67
|
});
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
// noinspection JSUnusedGlobalSymbols
|
|
69
71
|
/**
|
|
70
72
|
* Deletes a soundfont with the given ID
|
|
71
73
|
* @param id {string} - the soundfont to delete
|
|
@@ -74,17 +76,18 @@ export class SoundfontManager
|
|
|
74
76
|
{
|
|
75
77
|
if (this.soundfontList.length === 0)
|
|
76
78
|
{
|
|
77
|
-
SpessaSynthWarn("1 soundfont left. Aborting!");
|
|
79
|
+
SpessaSynthCoreUtils.SpessaSynthWarn("1 soundfont left. Aborting!");
|
|
78
80
|
return;
|
|
79
81
|
}
|
|
80
82
|
if (this.soundfontList.findIndex(s => s.id === id) === -1)
|
|
81
83
|
{
|
|
82
|
-
SpessaSynthWarn(`No soundfont with id of "${id}" found. Aborting!`);
|
|
84
|
+
SpessaSynthCoreUtils.SpessaSynthWarn(`No soundfont with id of "${id}" found. Aborting!`);
|
|
83
85
|
return;
|
|
84
86
|
}
|
|
85
87
|
this._sendToWorklet(WorkletSoundfontManagerMessageType.deleteSoundFont, id);
|
|
86
88
|
}
|
|
87
89
|
|
|
90
|
+
// noinspection JSUnusedGlobalSymbols
|
|
88
91
|
/**
|
|
89
92
|
* Rearranges the soundfonts in a given order
|
|
90
93
|
* @param newList {string[]} the order of soundfonts, a list of identifiers, first overwrites second
|
|
@@ -98,7 +101,7 @@ export class SoundfontManager
|
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
/**
|
|
101
|
-
* DELETES ALL SOUNDFONTS
|
|
104
|
+
* DELETES ALL SOUNDFONTS! and creates a new one with id "main"
|
|
102
105
|
* @param newBuffer {ArrayBuffer}
|
|
103
106
|
*/
|
|
104
107
|
async reloadManager(newBuffer)
|
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
import { consoleColors } from "
|
|
2
|
-
import { messageTypes, midiControllers } from "../../midi/midi_message.js";
|
|
3
|
-
import { EventHandler } from "./synth_event_handler.js";
|
|
4
|
-
import { FancyChorus } from "../audio_effects/fancy_chorus.js";
|
|
5
|
-
import { getReverbProcessor } from "../audio_effects/reverb.js";
|
|
1
|
+
import { consoleColors } from "../utils/other.js";
|
|
6
2
|
import {
|
|
7
3
|
ALL_CHANNELS_OR_DIFFERENT_ACTION,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
BasicMIDI,
|
|
5
|
+
channelConfiguration,
|
|
6
|
+
DEFAULT_PERCUSSION,
|
|
7
|
+
DEFAULT_SYNTH_MODE,
|
|
8
|
+
interpolationTypes,
|
|
9
|
+
masterParameterType,
|
|
10
|
+
messageTypes,
|
|
11
|
+
MIDI_CHANNEL_COUNT,
|
|
12
|
+
midiControllers,
|
|
13
|
+
SpessaSynthCoreUtils as util,
|
|
14
|
+
SynthesizerSnapshot,
|
|
15
|
+
VOICE_CAP
|
|
16
|
+
} from "spessasynth_core";
|
|
17
|
+
import { EventHandler } from "./synth_event_handler.js";
|
|
18
|
+
import { FancyChorus } from "./audio_effects/fancy_chorus.js";
|
|
19
|
+
import { getReverbProcessor } from "./audio_effects/reverb.js";
|
|
20
|
+
import { returnMessageType, workletMessageType } from "./worklet_message.js";
|
|
21
|
+
import { DEFAULT_SYNTH_CONFIG } from "./audio_effects/effects_config.js";
|
|
13
22
|
import { SoundfontManager } from "./synth_soundfont_manager.js";
|
|
14
23
|
import { WorkletKeyModifierManagerWrapper } from "./key_modifier_manager.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { BasicMIDI } from "../../midi/basic_midi.js";
|
|
18
|
-
import { fillWithDefaults } from "../../utils/fill_with_defaults.js";
|
|
19
|
-
import { DEFAULT_SEQUENCER_OPTIONS } from "../../sequencer/worklet_wrapper/default_sequencer_options.js";
|
|
24
|
+
import { fillWithDefaults } from "../utils/fill_with_defaults.js";
|
|
25
|
+
import { DEFAULT_SEQUENCER_OPTIONS } from "../sequencer/default_sequencer_options.js";
|
|
20
26
|
import { WORKLET_PROCESSOR_NAME } from "./worklet_url.js";
|
|
21
|
-
import { masterParameterType } from "../audio_engine/engine_methods/controller_control/master_parameters.js";
|
|
22
27
|
|
|
23
28
|
|
|
24
29
|
/**
|
|
@@ -40,6 +45,7 @@ const DEFAULT_SYNTH_METHOD_OPTIONS = {
|
|
|
40
45
|
|
|
41
46
|
|
|
42
47
|
// the "remote controller" of the worklet processor in the audio thread from the main thread
|
|
48
|
+
// noinspection JSUnusedGlobalSymbols
|
|
43
49
|
export class Synthetizer
|
|
44
50
|
{
|
|
45
51
|
|
|
@@ -67,7 +73,7 @@ export class Synthetizer
|
|
|
67
73
|
_destroyed = false;
|
|
68
74
|
|
|
69
75
|
/**
|
|
70
|
-
* the new channels will have their audio sent to the
|
|
76
|
+
* the new channels will have their audio sent to the modulated output by this constant.
|
|
71
77
|
* what does that mean?
|
|
72
78
|
* e.g., if outputsAmount is 16, then channel's 16 audio data will be sent to channel 0
|
|
73
79
|
* @type {number}
|
|
@@ -110,7 +116,7 @@ export class Synthetizer
|
|
|
110
116
|
startRenderingData = undefined,
|
|
111
117
|
synthConfig = DEFAULT_SYNTH_CONFIG)
|
|
112
118
|
{
|
|
113
|
-
SpessaSynthInfo("%cInitializing SpessaSynth synthesizer...", consoleColors.info);
|
|
119
|
+
util.SpessaSynthInfo("%cInitializing SpessaSynth synthesizer...", consoleColors.info);
|
|
114
120
|
this.context = targetNode.context;
|
|
115
121
|
this.targetNode = targetNode;
|
|
116
122
|
|
|
@@ -446,7 +452,7 @@ export class Synthetizer
|
|
|
446
452
|
break;
|
|
447
453
|
|
|
448
454
|
case returnMessageType.soundfontError:
|
|
449
|
-
SpessaSynthWarn(new Error(messageData));
|
|
455
|
+
util.SpessaSynthWarn(new Error(messageData));
|
|
450
456
|
this.eventHandler.callEvent("soundfonterror", messageData);
|
|
451
457
|
break;
|
|
452
458
|
}
|
|
@@ -565,7 +571,7 @@ export class Synthetizer
|
|
|
565
571
|
*/
|
|
566
572
|
debugMessage()
|
|
567
573
|
{
|
|
568
|
-
SpessaSynthInfo(this);
|
|
574
|
+
util.SpessaSynthInfo(this);
|
|
569
575
|
this.post({
|
|
570
576
|
channelNumber: 0,
|
|
571
577
|
messageType: workletMessageType.debugMessage,
|
|
@@ -748,7 +754,7 @@ export class Synthetizer
|
|
|
748
754
|
}
|
|
749
755
|
|
|
750
756
|
/**
|
|
751
|
-
* Transposes the
|
|
757
|
+
* Transposes the synthesizer's pitch by given the semitone amount (percussion channels don’t get affected).
|
|
752
758
|
* @param semitones {number} the semitones to transpose by.
|
|
753
759
|
* It can be a floating point number for more precision.
|
|
754
760
|
*/
|
|
@@ -783,7 +789,7 @@ export class Synthetizer
|
|
|
783
789
|
|
|
784
790
|
/**
|
|
785
791
|
* Sets the master stereo panning.
|
|
786
|
-
* @param pan {number} (-1 to 1), the pan (-1 is left, 0 is
|
|
792
|
+
* @param pan {number} (-1 to 1), the pan (-1 is left, 0 is middle, 1 is right)
|
|
787
793
|
*/
|
|
788
794
|
setMasterPan(pan)
|
|
789
795
|
{
|
|
@@ -878,7 +884,7 @@ export class Synthetizer
|
|
|
878
884
|
*/
|
|
879
885
|
async reloadSoundFont(soundFontBuffer)
|
|
880
886
|
{
|
|
881
|
-
SpessaSynthWarn("reloadSoundFont is deprecated. Please use the soundfontManager property instead.");
|
|
887
|
+
util.SpessaSynthWarn("reloadSoundFont is deprecated. Please use the soundfontManager property instead.");
|
|
882
888
|
await this.soundfontManager.reloadManager(soundFontBuffer);
|
|
883
889
|
}
|
|
884
890
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SynthesizerSnapshot } from "spessasynth_core";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @enum {number}
|
|
3
5
|
* // NOTE: Every message needs a channel number (if not relevant or all, set to -1)
|
|
@@ -33,7 +35,7 @@ export const workletMessageType = {
|
|
|
33
35
|
killNotes: 11,
|
|
34
36
|
muteChannel: 12,
|
|
35
37
|
addNewChannel: 13,
|
|
36
|
-
|
|
38
|
+
customCcChange: 14,
|
|
37
39
|
debugMessage: 15,
|
|
38
40
|
// free slot here
|
|
39
41
|
setMasterParameter: 17,
|
|
@@ -50,7 +52,6 @@ export const workletMessageType = {
|
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
|
|
53
|
-
export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
54
55
|
/**
|
|
55
56
|
* @typedef {{
|
|
56
57
|
* channelNumber: number
|
|
@@ -71,6 +72,18 @@ export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
|
71
72
|
* }} WorkletMessage
|
|
72
73
|
*/
|
|
73
74
|
|
|
75
|
+
/**
|
|
76
|
+
* @typedef {Object} ChannelProperty
|
|
77
|
+
* @property {number} voicesAmount - the channel's current voice amount
|
|
78
|
+
* @property {number} pitchBend - the channel's current pitch bend from -8192 do 8192
|
|
79
|
+
* @property {number} pitchBendRangeSemitones - the pitch bend's range, in semitones
|
|
80
|
+
* @property {boolean} isMuted - indicates whether the channel is muted
|
|
81
|
+
* @property {boolean} isDrum - indicates whether the channel is a drum channel
|
|
82
|
+
* @property {number} transposition - the channel's transposition, in semitones
|
|
83
|
+
* @property {number} bank - the bank number of the current preset
|
|
84
|
+
* @property {number} program - the MIDI program number of the current preset
|
|
85
|
+
*/
|
|
86
|
+
|
|
74
87
|
/**
|
|
75
88
|
* @typedef {Object} WorkletReturnMessage
|
|
76
89
|
* @property {returnMessageType} messageType - the message's type
|
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import { consoleColors } from "
|
|
2
|
-
import { SpessaSynthInfo, SpessaSynthLogging, SpessaSynthWarn } from "../../utils/loggin.js";
|
|
3
|
-
import { SpessaSynthProcessor } from "../audio_engine/main_processor.js";
|
|
1
|
+
import { consoleColors } from "../utils/other.js";
|
|
4
2
|
import {
|
|
5
3
|
ALL_CHANNELS_OR_DIFFERENT_ACTION,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
BasicMIDI,
|
|
5
|
+
masterParameterType,
|
|
6
|
+
MIDI,
|
|
7
|
+
MIDI_CHANNEL_COUNT,
|
|
8
|
+
SpessaSynthCoreUtils as util,
|
|
9
|
+
SpessaSynthLogging,
|
|
10
|
+
SpessaSynthProcessor,
|
|
11
|
+
SpessaSynthSequencer,
|
|
12
|
+
SynthesizerSnapshot
|
|
13
|
+
} from "spessasynth_core";
|
|
14
|
+
import { returnMessageType, workletMessageType } from "./worklet_message.js";
|
|
10
15
|
import { WORKLET_PROCESSOR_NAME } from "./worklet_url.js";
|
|
11
|
-
import {
|
|
12
|
-
import { workletKeyModifierMessageType } from "../audio_engine/engine_components/key_modifier_manager.js";
|
|
13
|
-
import { masterParameterType } from "../audio_engine/engine_methods/controller_control/master_parameters.js";
|
|
16
|
+
import { workletKeyModifierMessageType } from "./key_modifier_manager.js";
|
|
14
17
|
import { WorkletSoundfontManagerMessageType } from "./sfman_message.js";
|
|
15
18
|
import {
|
|
16
19
|
SongChangeType,
|
|
17
20
|
SpessaSynthSequencerMessageType,
|
|
18
21
|
SpessaSynthSequencerReturnMessageType
|
|
19
|
-
} from "
|
|
22
|
+
} from "../sequencer/sequencer_message.js";
|
|
23
|
+
import { fillWithDefaults } from "../utils/fill_with_defaults.js";
|
|
24
|
+
import { DEFAULT_SEQUENCER_OPTIONS } from "../sequencer/default_sequencer_options.js";
|
|
25
|
+
import { MIDIData } from "../sequencer/midi_data.js";
|
|
20
26
|
|
|
21
27
|
|
|
22
28
|
// a worklet processor wrapper for the synthesizer core
|
|
@@ -53,24 +59,165 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
53
59
|
// one output is indicated by setting midiChannels to 1
|
|
54
60
|
this.oneOutputMode = opts.midiChannels === 1;
|
|
55
61
|
|
|
62
|
+
// prepare synthesizer connections
|
|
63
|
+
/**
|
|
64
|
+
* @param t {returnMessageType}
|
|
65
|
+
* @param d {any}
|
|
66
|
+
*/
|
|
67
|
+
const postSyn = (t, d) =>
|
|
68
|
+
{
|
|
69
|
+
// noinspection JSCheckFunctionSignatures
|
|
70
|
+
this.postMessageToMainThread({
|
|
71
|
+
messageType: t,
|
|
72
|
+
messageData: d
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// start rendering data
|
|
77
|
+
const startRenderingData = opts?.startRenderingData;
|
|
78
|
+
/**
|
|
79
|
+
* The snapshot that synth was restored from
|
|
80
|
+
* @type {SynthesizerSnapshot|undefined}
|
|
81
|
+
* @private
|
|
82
|
+
*/
|
|
83
|
+
const snapshot = startRenderingData?.snapshot;
|
|
84
|
+
|
|
56
85
|
// noinspection JSUnresolvedReference
|
|
57
86
|
/**
|
|
58
87
|
* Initialize the synthesis engine
|
|
59
88
|
* @type {SpessaSynthProcessor}
|
|
60
89
|
*/
|
|
61
90
|
this.synthesizer = new SpessaSynthProcessor(
|
|
62
|
-
MIDI_CHANNEL_COUNT, // midi channel count (16)
|
|
63
91
|
opts.soundfont, // initial sound bank
|
|
64
92
|
sampleRate, // AudioWorkletGlobalScope
|
|
65
|
-
|
|
93
|
+
{
|
|
94
|
+
eventCall: (t, d) =>
|
|
95
|
+
{
|
|
96
|
+
postSyn(returnMessageType.eventCall, {
|
|
97
|
+
eventName: t,
|
|
98
|
+
eventData: d
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
ready: this.postReady.bind(this),
|
|
102
|
+
channelPropertyChange: (p, n) => postSyn(returnMessageType.channelPropertyChange, [n, p]),
|
|
103
|
+
masterParameterChange: (t, v) => postSyn(returnMessageType.masterParameterChange, [t, v])
|
|
104
|
+
},
|
|
66
105
|
!this.oneOutputMode, // one output mode disables effects
|
|
67
106
|
opts?.enableEventSystem, // enable message port?
|
|
68
|
-
|
|
69
|
-
|
|
107
|
+
currentTime, // AudioWorkletGlobalScope, sync with audioContext time
|
|
108
|
+
MIDI_CHANNEL_COUNT, // midi channel count (16)
|
|
109
|
+
snapshot
|
|
70
110
|
);
|
|
71
111
|
|
|
112
|
+
// initialize the sequencer engine
|
|
113
|
+
this.sequencer = new SpessaSynthSequencer(this.synthesizer);
|
|
114
|
+
|
|
115
|
+
const postSeq = (type, data) =>
|
|
116
|
+
{
|
|
117
|
+
this.postMessageToMainThread({
|
|
118
|
+
messageType: returnMessageType.sequencerSpecific,
|
|
119
|
+
messageData: {
|
|
120
|
+
messageType: type,
|
|
121
|
+
messageData: data
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
72
126
|
// receive messages from the main thread
|
|
73
127
|
this.port.onmessage = e => this.handleMessage(e.data);
|
|
128
|
+
|
|
129
|
+
// sequencer events
|
|
130
|
+
this.sequencer.onMIDIMessage = m =>
|
|
131
|
+
{
|
|
132
|
+
postSeq(SpessaSynthSequencerReturnMessageType.midiEvent, m);
|
|
133
|
+
};
|
|
134
|
+
this.sequencer.onTimeChange = t =>
|
|
135
|
+
{
|
|
136
|
+
postSeq(SpessaSynthSequencerReturnMessageType.timeChange, t);
|
|
137
|
+
};
|
|
138
|
+
this.sequencer.onPlaybackStop = p =>
|
|
139
|
+
{
|
|
140
|
+
postSeq(SpessaSynthSequencerReturnMessageType.pause, p);
|
|
141
|
+
};
|
|
142
|
+
this.sequencer.onSongChange = (i, a) =>
|
|
143
|
+
{
|
|
144
|
+
postSeq(SpessaSynthSequencerReturnMessageType.songChange, [i, a]);
|
|
145
|
+
};
|
|
146
|
+
this.sequencer.onMetaEvent = (e, i) =>
|
|
147
|
+
{
|
|
148
|
+
postSeq(SpessaSynthSequencerReturnMessageType.metaEvent, [e, i]);
|
|
149
|
+
};
|
|
150
|
+
this.sequencer.onLoopCountChange = c =>
|
|
151
|
+
{
|
|
152
|
+
postSeq(SpessaSynthSequencerReturnMessageType.loopCountChange, c);
|
|
153
|
+
};
|
|
154
|
+
this.sequencer.onSongListChange = l =>
|
|
155
|
+
{
|
|
156
|
+
const midiDataList = l.map(s => new MIDIData(s));
|
|
157
|
+
this.postMessageToMainThread({
|
|
158
|
+
messageType: returnMessageType.sequencerSpecific,
|
|
159
|
+
messageData: {
|
|
160
|
+
messageType: SpessaSynthSequencerReturnMessageType.songListChange,
|
|
161
|
+
messageData: midiDataList
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// if sent, start rendering
|
|
167
|
+
if (startRenderingData)
|
|
168
|
+
{
|
|
169
|
+
if (snapshot !== undefined)
|
|
170
|
+
{
|
|
171
|
+
this.synthesizer.applySynthesizerSnapshot(snapshot);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
util.SpessaSynthInfo("%cRendering enabled! Starting render.", consoleColors.info);
|
|
175
|
+
if (startRenderingData.parsedMIDI)
|
|
176
|
+
{
|
|
177
|
+
if (startRenderingData?.loopCount !== undefined)
|
|
178
|
+
{
|
|
179
|
+
this.sequencer.loopCount = startRenderingData?.loopCount;
|
|
180
|
+
this.sequencer.loop = true;
|
|
181
|
+
}
|
|
182
|
+
else
|
|
183
|
+
{
|
|
184
|
+
this.sequencer.loop = false;
|
|
185
|
+
}
|
|
186
|
+
// set voice cap to unlimited
|
|
187
|
+
this.synthesizer.voiceCap = Infinity;
|
|
188
|
+
this.synthesizer.processorInitialized.then(() =>
|
|
189
|
+
{
|
|
190
|
+
/**
|
|
191
|
+
* set options
|
|
192
|
+
* @type {SequencerOptions}
|
|
193
|
+
*/
|
|
194
|
+
const seqOptions = fillWithDefaults(
|
|
195
|
+
startRenderingData.sequencerOptions,
|
|
196
|
+
DEFAULT_SEQUENCER_OPTIONS
|
|
197
|
+
);
|
|
198
|
+
this.sequencer.skipToFirstNoteOn = seqOptions.skipToFirstNoteOn;
|
|
199
|
+
this.sequencer.preservePlaybackState = seqOptions.preservePlaybackState;
|
|
200
|
+
// autoplay is ignored
|
|
201
|
+
try
|
|
202
|
+
{
|
|
203
|
+
this.sequencer.loadNewSongList([startRenderingData.parsedMIDI]);
|
|
204
|
+
}
|
|
205
|
+
catch (e)
|
|
206
|
+
{
|
|
207
|
+
console.error(e);
|
|
208
|
+
postSeq(SpessaSynthSequencerReturnMessageType.midiError, e);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
postReady()
|
|
216
|
+
{
|
|
217
|
+
this.postMessageToMainThread({
|
|
218
|
+
messageType: returnMessageType.isFullyInitialized,
|
|
219
|
+
messageData: undefined
|
|
220
|
+
});
|
|
74
221
|
}
|
|
75
222
|
|
|
76
223
|
/**
|
|
@@ -89,16 +236,14 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
89
236
|
{
|
|
90
237
|
const data = message.messageData;
|
|
91
238
|
const channel = message.channelNumber;
|
|
92
|
-
|
|
93
|
-
* @type {MidiAudioChannel}
|
|
94
|
-
*/
|
|
239
|
+
|
|
95
240
|
let channelObject;
|
|
96
241
|
if (channel >= 0)
|
|
97
242
|
{
|
|
98
243
|
channelObject = this.synthesizer.midiAudioChannels[channel];
|
|
99
244
|
if (channelObject === undefined)
|
|
100
245
|
{
|
|
101
|
-
SpessaSynthWarn(`Trying to access channel ${channel} which does not exist... ignoring!`);
|
|
246
|
+
util.SpessaSynthWarn(`Trying to access channel ${channel} which does not exist... ignoring!`);
|
|
102
247
|
return;
|
|
103
248
|
}
|
|
104
249
|
}
|
|
@@ -108,7 +253,7 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
108
253
|
this.synthesizer.processMessage(...data);
|
|
109
254
|
break;
|
|
110
255
|
|
|
111
|
-
case workletMessageType.
|
|
256
|
+
case workletMessageType.customCcChange:
|
|
112
257
|
// custom controller change
|
|
113
258
|
channelObject.setCustomController(data[0], data[1]);
|
|
114
259
|
channelObject.updateChannelTuning();
|
|
@@ -175,7 +320,7 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
175
320
|
break;
|
|
176
321
|
|
|
177
322
|
case workletMessageType.debugMessage:
|
|
178
|
-
this.synthesizer
|
|
323
|
+
console.debug(this.synthesizer);
|
|
179
324
|
break;
|
|
180
325
|
|
|
181
326
|
case workletMessageType.setMasterParameter:
|
|
@@ -218,7 +363,7 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
218
363
|
break;
|
|
219
364
|
|
|
220
365
|
case workletMessageType.sequencerSpecific:
|
|
221
|
-
const seq = this.
|
|
366
|
+
const seq = this.sequencer;
|
|
222
367
|
const messageData = data.messageData;
|
|
223
368
|
const messageType = data.messageType;
|
|
224
369
|
switch (messageType)
|
|
@@ -227,7 +372,33 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
227
372
|
break;
|
|
228
373
|
|
|
229
374
|
case SpessaSynthSequencerMessageType.loadNewSongList:
|
|
230
|
-
|
|
375
|
+
try
|
|
376
|
+
{
|
|
377
|
+
/**
|
|
378
|
+
* @type {(BasicMIDI|{binary: ArrayBuffer, altName: string})[]}
|
|
379
|
+
*/
|
|
380
|
+
const sList = messageData[0];
|
|
381
|
+
const songMap = sList.map(s =>
|
|
382
|
+
{
|
|
383
|
+
if (s.duration)
|
|
384
|
+
{
|
|
385
|
+
return s;
|
|
386
|
+
}
|
|
387
|
+
return new MIDI(s.binary, s.altName);
|
|
388
|
+
});
|
|
389
|
+
seq.loadNewSongList(songMap, messageData[1]);
|
|
390
|
+
}
|
|
391
|
+
catch (e)
|
|
392
|
+
{
|
|
393
|
+
console.error(e);
|
|
394
|
+
this.postMessageToMainThread({
|
|
395
|
+
messageType: returnMessageType.sequencerSpecific,
|
|
396
|
+
messageData: {
|
|
397
|
+
messageType: SpessaSynthSequencerReturnMessageType.midiError,
|
|
398
|
+
messageData: e
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
231
402
|
break;
|
|
232
403
|
|
|
233
404
|
case SpessaSynthSequencerMessageType.pause:
|
|
@@ -298,7 +469,13 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
298
469
|
break;
|
|
299
470
|
|
|
300
471
|
case SpessaSynthSequencerMessageType.getMIDI:
|
|
301
|
-
|
|
472
|
+
this.postMessageToMainThread({
|
|
473
|
+
messageType: returnMessageType.sequencerSpecific,
|
|
474
|
+
messageData: {
|
|
475
|
+
messageType: SpessaSynthSequencerReturnMessageType.getMIDI,
|
|
476
|
+
messageData: seq.midiData
|
|
477
|
+
}
|
|
478
|
+
});
|
|
302
479
|
break;
|
|
303
480
|
|
|
304
481
|
case SpessaSynthSequencerMessageType.setSkipToFirstNote:
|
|
@@ -313,25 +490,25 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
313
490
|
case workletMessageType.soundFontManager:
|
|
314
491
|
try
|
|
315
492
|
{
|
|
316
|
-
const
|
|
493
|
+
const sfManager = this.synthesizer.soundfontManager;
|
|
317
494
|
const type = data[0];
|
|
318
495
|
const messageData = data[1];
|
|
319
496
|
switch (type)
|
|
320
497
|
{
|
|
321
498
|
case WorkletSoundfontManagerMessageType.addNewSoundFont:
|
|
322
|
-
|
|
499
|
+
sfManager.addNewSoundFont(messageData[0], messageData[1], messageData[2]);
|
|
323
500
|
break;
|
|
324
501
|
|
|
325
502
|
case WorkletSoundfontManagerMessageType.reloadSoundFont:
|
|
326
|
-
|
|
503
|
+
sfManager.reloadManager(messageData);
|
|
327
504
|
break;
|
|
328
505
|
|
|
329
506
|
case WorkletSoundfontManagerMessageType.deleteSoundFont:
|
|
330
|
-
|
|
507
|
+
sfManager.deleteSoundFont(messageData);
|
|
331
508
|
break;
|
|
332
509
|
|
|
333
510
|
case WorkletSoundfontManagerMessageType.rearrangeSoundFonts:
|
|
334
|
-
|
|
511
|
+
sfManager.rearrangeSoundFonts(messageData);
|
|
335
512
|
}
|
|
336
513
|
}
|
|
337
514
|
catch (e)
|
|
@@ -389,10 +566,13 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
389
566
|
case workletMessageType.destroyWorklet:
|
|
390
567
|
this.alive = false;
|
|
391
568
|
this.synthesizer.destroySynthProcessor();
|
|
569
|
+
delete this.synthesizer;
|
|
570
|
+
delete this.sequencer.midiData;
|
|
571
|
+
delete this.sequencer;
|
|
392
572
|
break;
|
|
393
573
|
|
|
394
574
|
default:
|
|
395
|
-
SpessaSynthWarn("Unrecognized event:", data);
|
|
575
|
+
util.SpessaSynthWarn("Unrecognized event:", data);
|
|
396
576
|
break;
|
|
397
577
|
}
|
|
398
578
|
}
|
|
@@ -410,6 +590,9 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
410
590
|
{
|
|
411
591
|
return false;
|
|
412
592
|
}
|
|
593
|
+
// process sequencer
|
|
594
|
+
this.sequencer.processTick();
|
|
595
|
+
|
|
413
596
|
if (this.oneOutputMode)
|
|
414
597
|
{
|
|
415
598
|
const out = outputs[0];
|
|
@@ -451,4 +634,4 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
|
|
|
451
634
|
|
|
452
635
|
// noinspection JSUnresolvedReference
|
|
453
636
|
registerProcessor(WORKLET_PROCESSOR_NAME, WorkletSpessaProcessor);
|
|
454
|
-
SpessaSynthInfo("%cProcessor
|
|
637
|
+
util.SpessaSynthInfo("%cProcessor successfully registered!", consoleColors.recognized);
|