spessasynth_lib 3.25.23 → 3.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +29 -114
  2. package/external_midi/midi_handler.js +14 -14
  3. package/external_midi/web_midi_link.js +3 -3
  4. package/index.js +33 -33
  5. package/package.json +19 -6
  6. package/{midi → sequencer}/midi_data.js +1 -1
  7. package/sequencer/{worklet_wrapper/sequencer.js → sequencer.js} +13 -12
  8. package/sequencer/{worklet_wrapper/sequencer_message.js → sequencer_message.js} +1 -1
  9. package/synthetizer/README.md +29 -1
  10. package/synthetizer/audio_effects/reverb_as_binary.js +2 -2
  11. package/synthetizer/{worklet_wrapper/key_modifier_manager.js → key_modifier_manager.js} +11 -2
  12. package/synthetizer/{worklet_wrapper/synth_event_handler.js → synth_event_handler.js} +16 -13
  13. package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js} +8 -5
  14. package/synthetizer/{worklet_wrapper/synthetizer.js → synthetizer.js} +29 -23
  15. package/synthetizer/{audio_engine/message_protocol/worklet_message.js → worklet_message.js} +15 -2
  16. package/synthetizer/{worklet_wrapper/worklet_processor.js → worklet_processor.js} +214 -31
  17. package/synthetizer/worklet_processor.min.js +13 -12
  18. package/synthetizer/worklet_processor.min.js.map +7 -0
  19. package/synthetizer/{worklet_wrapper/worklet_url.js → worklet_url.js} +2 -0
  20. package/utils/buffer_to_wav.js +7 -165
  21. package/utils/other.js +3 -84
  22. package/externals/fflate/LICENSE +0 -21
  23. package/externals/fflate/fflate.min.js +0 -1
  24. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  25. package/externals/stbvorbis_sync/LICENSE +0 -202
  26. package/externals/stbvorbis_sync/NOTICE +0 -6
  27. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  28. package/midi/README.md +0 -32
  29. package/midi/basic_midi.js +0 -565
  30. package/midi/midi_builder.js +0 -202
  31. package/midi/midi_loader.js +0 -324
  32. package/midi/midi_message.js +0 -254
  33. package/midi/midi_sequence.js +0 -225
  34. package/midi/midi_tools/get_note_times.js +0 -154
  35. package/midi/midi_tools/midi_editor.js +0 -611
  36. package/midi/midi_tools/midi_writer.js +0 -99
  37. package/midi/midi_tools/rmidi_writer.js +0 -567
  38. package/midi/midi_tools/used_keys_loaded.js +0 -238
  39. package/midi/xmf_loader.js +0 -454
  40. package/sequencer/sequencer_engine/events.js +0 -104
  41. package/sequencer/sequencer_engine/play.js +0 -353
  42. package/sequencer/sequencer_engine/process_event.js +0 -169
  43. package/sequencer/sequencer_engine/process_tick.js +0 -106
  44. package/sequencer/sequencer_engine/sequencer_engine.js +0 -335
  45. package/sequencer/sequencer_engine/song_control.js +0 -229
  46. package/soundfont/README.md +0 -13
  47. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  48. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  49. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  50. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  51. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  52. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  53. package/soundfont/basic_soundfont/generator.js +0 -220
  54. package/soundfont/basic_soundfont/modulator.js +0 -378
  55. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  56. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  57. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  58. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  59. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  60. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  61. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  62. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  63. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  64. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  65. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  66. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  67. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  68. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  69. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  70. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  71. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  72. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  73. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  74. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  75. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  76. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  77. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  78. package/soundfont/dls/articulator_converter.js +0 -396
  79. package/soundfont/dls/dls_destinations.js +0 -38
  80. package/soundfont/dls/dls_preset.js +0 -44
  81. package/soundfont/dls/dls_sample.js +0 -75
  82. package/soundfont/dls/dls_soundfont.js +0 -186
  83. package/soundfont/dls/dls_sources.js +0 -62
  84. package/soundfont/dls/dls_zone.js +0 -95
  85. package/soundfont/dls/read_articulation.js +0 -299
  86. package/soundfont/dls/read_instrument.js +0 -121
  87. package/soundfont/dls/read_instrument_list.js +0 -17
  88. package/soundfont/dls/read_lart.js +0 -35
  89. package/soundfont/dls/read_region.js +0 -152
  90. package/soundfont/dls/read_samples.js +0 -270
  91. package/soundfont/load_soundfont.js +0 -21
  92. package/soundfont/read_sf2/generators.js +0 -46
  93. package/soundfont/read_sf2/instruments.js +0 -66
  94. package/soundfont/read_sf2/modulators.js +0 -36
  95. package/soundfont/read_sf2/presets.js +0 -80
  96. package/soundfont/read_sf2/samples.js +0 -304
  97. package/soundfont/read_sf2/soundfont.js +0 -305
  98. package/soundfont/read_sf2/zones.js +0 -263
  99. package/synthetizer/audio_engine/README.md +0 -25
  100. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  101. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  102. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  103. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  104. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  105. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  106. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  107. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  108. package/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -228
  109. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  110. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  111. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  112. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  113. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  114. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  115. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  116. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  117. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  118. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  119. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  120. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  121. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -175
  122. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  123. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  124. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  127. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  128. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  129. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  132. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  133. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  134. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  135. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -776
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  142. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  143. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  144. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  145. package/synthetizer/audio_engine/main_processor.js +0 -765
  146. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  147. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  148. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  149. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  150. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  151. package/synthetizer/synth_constants.js +0 -20
  152. package/utils/README.md +0 -5
  153. package/utils/byte_functions/big_endian.js +0 -32
  154. package/utils/byte_functions/little_endian.js +0 -77
  155. package/utils/byte_functions/string.js +0 -107
  156. package/utils/byte_functions/variable_length_quantity.js +0 -42
  157. package/utils/indexed_array.js +0 -52
  158. package/utils/loggin.js +0 -79
  159. package/utils/sysex_detector.js +0 -58
  160. package/utils/xg_hacks.js +0 -193
  161. /package/sequencer/{worklet_wrapper/default_sequencer_options.js → default_sequencer_options.js} +0 -0
  162. /package/synthetizer/{worklet_wrapper/sfman_message.js → sfman_message.js} +0 -0
@@ -1,6 +1,6 @@
1
- import { workletMessageType } from "../audio_engine/message_protocol/worklet_message.js";
1
+ import { workletMessageType } from "./worklet_message.js";
2
2
  import { WorkletSoundfontManagerMessageType } from "./sfman_message.js";
3
- import { SpessaSynthWarn } from "../../utils/loggin.js";
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!! and creates a new one with id "main"
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 "../../utils/other.js";
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
- returnMessageType,
9
- workletMessageType
10
- } from "../audio_engine/message_protocol/worklet_message.js";
11
- import { SpessaSynthInfo, SpessaSynthWarn } from "../../utils/loggin.js";
12
- import { DEFAULT_SYNTH_CONFIG } from "../audio_effects/effects_config.js";
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 { channelConfiguration } from "../audio_engine/engine_components/controller_tables.js";
16
- import { DEFAULT_PERCUSSION, DEFAULT_SYNTH_MODE, MIDI_CHANNEL_COUNT, VOICE_CAP } from "../synth_constants.js";
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 moduled output by this constant.
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 synthetizer's pitch by given semitones amount (percussion channels don’t get affected).
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 midde, 1 is right)
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
- customcCcChange: 14,
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 "../../utils/other.js";
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
- returnMessageType,
7
- workletMessageType
8
- } from "../audio_engine/message_protocol/worklet_message.js";
9
- import { SynthesizerSnapshot } from "../audio_engine/snapshot/synthesizer_snapshot.js";
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 { MIDI_CHANNEL_COUNT } from "../synth_constants.js";
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 "../../sequencer/worklet_wrapper/sequencer_message.js";
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
- this.postMessageToMainThread.bind(this), // connect to message port
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
- opts?.startRenderingData, // start rendering?
69
- currentTime // AudioWorkletGlobalScope, sync with audioContext time
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.customcCcChange:
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.debugMessage();
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.synthesizer.sequencer;
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
- seq.loadNewSongList(messageData[0], messageData[1]);
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
- seq.post(SpessaSynthSequencerReturnMessageType.getMIDI, seq.midiData);
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 sfman = this.synthesizer.soundfontManager;
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
- sfman.addNewSoundFont(messageData[0], messageData[1], messageData[2]);
499
+ sfManager.addNewSoundFont(messageData[0], messageData[1], messageData[2]);
323
500
  break;
324
501
 
325
502
  case WorkletSoundfontManagerMessageType.reloadSoundFont:
326
- sfman.reloadManager(messageData);
503
+ sfManager.reloadManager(messageData);
327
504
  break;
328
505
 
329
506
  case WorkletSoundfontManagerMessageType.deleteSoundFont:
330
- sfman.deleteSoundFont(messageData);
507
+ sfManager.deleteSoundFont(messageData);
331
508
  break;
332
509
 
333
510
  case WorkletSoundfontManagerMessageType.rearrangeSoundFonts:
334
- sfman.rearrangeSoundFonts(messageData);
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 succesfully registered!", consoleColors.recognized);
637
+ util.SpessaSynthInfo("%cProcessor successfully registered!", consoleColors.recognized);