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
package/README.md CHANGED
@@ -2,15 +2,20 @@
2
2
 
3
3
  **A powerful SF2/DLS/MIDI JavaScript library for the browsers.**
4
4
 
5
+ *This is a WebAudioAPI wrapper for the [spessasynth_core](https://github.com/spessasus/spessasynth_core) library.*
6
+
7
+ > **TIP:**
8
+ > Looking for a bare JS version that works without WebAudioAPI? Try [spessasynth_core](https://github.com/spessasus/spessasynth_core)!
9
+
5
10
  ```shell
6
11
  npm install --save spessasynth_lib
7
12
  ```
8
13
 
9
14
  ### [Project site (consider giving it a star!)](https://github.com/spessasus/SpessaSynth)
10
15
 
11
- ### [Demo](https://spessasus.github.io/SpessaSynth)
16
+ ### [Demo](https://spessasus.github.io/spessasynth_lib)
12
17
 
13
- ### [Complete documentation](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library)
18
+ ### [Complete documentation](https://github.com/spessasus/spessasynth_lib/wiki/)
14
19
 
15
20
  #### Basic example: play a single note
16
21
 
@@ -32,126 +37,36 @@ document.getElementById("button").onclick = async () =>
32
37
 
33
38
  ## Current Features
34
39
 
35
- ### Numerous Format Support
36
- Supported formats list:
37
- - `.mid` - Standard MIDI File
38
- - `.kar` - Soft Karaoke MIDI File
39
- - `.sf2` - SoundFont2 File
40
- - `.sf3` - SoundFont2 Compressed File
41
- - `.sfogg` - SF2Pack With Vorbis Compression
42
- - `.dls` - Downloadable Sounds Levels 1 & 2 (as well as Mobile DLS)
43
- - `.rmi` - RIFF MIDI File
44
- - `.rmi` - RIFF MIDI File With Embedded DLS
45
- - `.rmi` - [RIFF MIDI File With Embedded SF2](https://github.com/spessasus/sf2-rmidi-specification)
46
- - `.xmf` - eXtensible Music Format
47
- - `.mxmf` - Mobile eXtensible Music format
48
-
49
- *With [an easy way of converting between them!](https://github.com/spessasus/SpessaSynth/wiki/Converting-Between-Formats)*
50
-
51
- ### Easy Integration
40
+ ### [All the features of spessasynth_core!](https://github.com/spessasus/spessasynth_core?#current-features)
41
+
42
+ ### On top of that...
52
43
  - **Modular design:** *Easy integration into other projects (load what you need)*
53
- - **[Detailed documentation:](https://github.com/spessasus/SpessaSynth/wiki/Home)** *With [examples!](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library#examples)*
54
- - **Flexible:** *It's not just a MIDI player!*
55
- - **Easy to Use:** *Basic setup is just [two lines of code!](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library#minimal-setup)*
56
- - **No dependencies:** *Batteries included!*
57
-
58
- ### Powerful MIDI Synthesizer
59
- - Suitable for both **real-time** and **offline** synthesis
60
- - **Excellent SoundFont support:**
61
- - **Full Generator Support**
62
- - **Full Modulator Support:** *First (to my knowledge) JavaScript SoundFont synth with that feature!*
63
- - **GeneralUserGS Compatible:** *[See more here!](https://github.com/mrbumpy409/GeneralUser-GS/blob/main/documentation/README.md)*
64
- - **SoundFont3 Support:** Play compressed SoundFonts!
65
- - **Experimental SF2Pack Support:** Play soundfonts compressed with BASSMIDI! (*Note: only works with vorbis compression*)
66
- - **Can load very large SoundFonts:** up to 4GB! *Note: Only Firefox handles this well; Chromium has a hard-coded memory limit*
67
- - **Great DLS Support:**
68
- - **DLS Level 1 Support**
69
- - **DLS Level 2 Support**
70
- - **Mobile DLS Support**
71
- - **Correct articulator support:** *Converts articulators to both modulators and generators!*
72
- - **Tested and working with gm.dls!**
73
- - **Correct volume:** *Properly translated to SoundFont volume!*
74
- - **A-Law encoding support**
75
- - **Both unsigned 8-bit and signed 16-bit sample support (24-bit theoretically supported as well!)**
76
- - **Detects special articulator combinations:** *Such as vibratoLfoToPitch*
77
- - **Soundfont manager:** Stack multiple soundfonts!
78
- - **Reverb and chorus support:** [customizable!](https://github.com/spessasus/SpessaSynth/wiki/Synthetizer-Class#effects-configuration-object)
44
+ - **[Detailed documentation:](https://github.com/spessasus/spessasynth_lib/wiki/Home)** *With [examples!](https://github.com/spessasus/spessasynth_lib/wiki/Usage-As-Library#examples)*
45
+ - **Easy to Use:** *Basic setup is just [two lines of code!](https://github.com/spessasus/spessasynth_lib/wiki/Usage-As-Library#minimal-setup)*
46
+ - **No external dependencies:** *Just spessasynth_core!*
47
+ - **Reverb and chorus support:** [customizable!](https://github.com/spessasus/spessasynth_lib/wiki/Synthetizer-Class#effects-configuration-object)
79
48
  - **Export audio files** using [OfflineAudioContext](https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext)
80
- - **[Custom modulators for additional controllers](https://github.com/spessasus/SpessaSynth/wiki/Modulator-Class#default-modulators):** *Why not?*
81
49
  - **Written using AudioWorklets:**
82
50
  - Runs in a **separate thread** for maximum performance
83
51
  - Doesn't stop playing even when the main thread is frozen
84
52
  - Supported by all modern browsers
85
- - **Unlimited channel count:** Your CPU is the limit!
86
- - **Excellent MIDI Standards Support:**
87
- - **MIDI Controller Support:** Default supported controllers [here](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-controllers)
88
- - **Portamento Support:** Glide the notes!
89
- - **Sound Controllers:** Real-time filter and envelope control!
90
- - **MIDI Tuning Standard Support:** [more info here](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#midi-tuning-standard)
91
- - [Full **RPN** and limited **NRPN** support](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-registered-parameters)
92
- - Supports some [**Roland GS** and **Yamaha XG** system exclusives](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-system-exclusives)
93
53
  - **High-performance mode:** Play Rush E! *note: may kill your browser ;)*
94
54
 
95
- ### Powerful and Fast MIDI Sequencer
96
- - **Supports MIDI formats 0, 1, and 2:** *note: format 2 support is experimental as it's very, very rare.*
97
- - **[Multi-Port MIDI](https://github.com/spessasus/SpessaSynth/wiki/About-Multi-Port) support:** More than 16 channels!
98
- - **Smart preloading:** Only preloads the samples used in the MIDI file for smooth playback *(down to key and velocity!)*
99
- - **Lyrics support:** Add karaoke to your program!
100
- - **Raw lyrics available:** Decode in any encoding! *(Kanji? No problem!)*
101
- - **Runs in Audio Thread as well:** Never blocks the main thread
102
- - **Loop points support:** Ensures seamless loops
103
-
104
- ### Read and Write SoundFont and MIDI Files with Ease
105
- #### Read and write MIDI files
106
- - **Smart name detection:** Handles incorrectly formatted and non-standard track names
107
- - **Raw name available:** Decode in any encoding! *(Kanji? No problem!)*
108
- - **Port detection during load time:** Manage ports and channels easily!
109
- - **Used channels on track:** Quickly determine which channels are used
110
- - **Key range detection:** Detect the key range of the MIDI
111
- - **Easy MIDI editing:** Use [helper functions](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#modifymidi) to modify the song to your needs!
112
- - **Loop detection:** Automatically detects loops in MIDIs (e.g., from *Touhou Project*)
113
- - **First note detection:** Skip unnecessary silence at the start by jumping to the first note!
114
- - **Lyrics support:** Both regular MIDI and .kar files!
115
- - **[Write MIDI files from scratch](https://github.com/spessasus/SpessaSynth/wiki/Creating-MIDI-Files)**
116
- - **Easy saving:** Save with just [one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writemidi)
117
-
118
- #### Read and write [RMID files with embedded SF2 soundfonts](https://github.com/spessasus/sf2-rmidi-specification#readme)
119
- - **[Level 4](https://github.com/spessasus/sf2-rmidi-specification#level-4) compliance:** Reads and writes *everything!*
120
- - **Compression and trimming support:** Reduce a MIDI file with a 1GB soundfont to **as small as 5MB**!
121
- - **DLS Version support:** The original legacy format with bank offset detection!
122
- - **Automatic bank shifting and validation:** Every soundfont *just works!*
123
- - **Metadata support:** Add title, artist, album name and cover and more! And of course read them too! *(In any encoding!)*
124
- - **Compatible with [Falcosoft Midi Player 6!](https://falcosoft.hu/softwares.html#midiplayer)**
125
- - **Easy saving:** [As simple as saving a MIDI file!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writermidi)
126
-
127
- #### Read and write SoundFont2 files
128
- - **Easy info access:** Just an [object of strings!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#soundfontinfo)
129
- - **Smart trimming:** Trim the SoundFont to only include samples used in the MIDI *(down to key and velocity!)*
130
- - **sf3 conversion:** Compress SoundFont2 files to SoundFont3 with variable quality!
131
- - **Easy saving:** Also just [one function!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#write)
132
-
133
- #### Read and write SoundFont3 files
134
- - Same features as SoundFont2 but with now with **Ogg Vorbis compression!**
135
- - **Variable compression quality:** You choose between file size and quality!
136
- - **Compression preserving:** Avoid decompressing and recompressing uncompressed samples for minimal quality loss!
137
-
138
- #### Read and write DLS Level One or Two files
139
- - Read DLS (DownLoadable Sounds) files as SF2 files!
140
- - **Works like a normal soundfont:** *Saving it as sf2 is still [just one function!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#write)*
141
- - Converts articulators to both **modulators** and **generators**!
142
- - Works with both unsigned 8-bit samples and signed 16-bit samples!
143
- - A-Law encoding support
144
- - **Covers special generator cases:** *such as modLfoToPitch*!
145
- - **Correct volume:** *looking at you, Viena and gm.sf2!*
146
- - Support built right into the synthesizer!
147
- - **Convert SF2 to DLS:** [with limitations](https://github.com/spessasus/SpessaSynth/wiki/DLS-Conversion-Problem)
148
-
149
- ### Export MIDI as WAV
150
- - Save the MIDI file as WAV audio!
151
- - **Metadata support:** *Embed metadata such as title, artist, album and more!*
152
- - **Cue points:** *Write MIDI loop points as cue points!*
153
- - **Loop multiple times:** *Render two (or more) loops into the file for seamless transitions!*
154
- - *That's right, saving as WAV is also [just one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-Wave-Files#audiobuffertowav)*
55
+ #### TODO
56
+ - Enhance the built-in chorus and reverb effects (suggestions welcome!)
57
+
58
+ ### Special Thanks
59
+ - [FluidSynth](https://github.com/FluidSynth/fluidsynth) - for the source code that helped implement functionality and fixes
60
+ - [Polyphone](https://www.polyphone-soundfonts.com/) - for the soundfont testing and editing tool
61
+ - [Meltysynth](https://github.com/sinshu/meltysynth) - for the initial low-pass filter implementation
62
+ - [RecordingBlogs](https://www.recordingblogs.com/) - for detailed explanations on MIDI messages
63
+ - [stbvorbis.js](https://github.com/hajimehoshi/stbvorbis.js) - for the Vorbis decoder
64
+ - [fflate](https://github.com/101arrowz/fflate) - for the MIT DEFLATE implementation
65
+ - [foo_midi](https://github.com/stuerp/foo_midi) - for useful resources on XMF file format
66
+ - [Falcosoft](https://falcosoft.hu) - for help with the RMIDI format
67
+ - [Christian Collins](https://schristiancollins.com) - for various bug reports regarding the synthesizer
68
+ - **And You!** - for checking out this project. I hope you like it :)
69
+
155
70
 
156
71
  # License
157
72
  Copyright © 2025 Spessasus
@@ -1,6 +1,6 @@
1
- import { Synthetizer } from "../synthetizer/worklet_wrapper/synthetizer.js";
1
+ import { Synthetizer } from "../synthetizer/synthetizer.js";
2
+ import { SpessaSynthCoreUtils as util } from "spessasynth_core";
2
3
  import { consoleColors } from "../utils/other.js";
3
- import { SpessaSynthInfo, SpessaSynthWarn } from "../utils/loggin.js";
4
4
 
5
5
  /**
6
6
  * midi_handler.js
@@ -9,14 +9,14 @@ import { SpessaSynthInfo, SpessaSynthWarn } from "../utils/loggin.js";
9
9
 
10
10
  const NO_INPUT = null;
11
11
 
12
+ // noinspection JSUnusedGlobalSymbols
13
+ /**
14
+ * A class for handling MIDI devices
15
+ */
12
16
  export class MIDIDeviceHandler
13
17
  {
14
- constructor()
15
- {
16
- }
17
-
18
18
  /**
19
- * @returns {Promise<boolean>} if succeded
19
+ * @returns {Promise<boolean>} if succeeded
20
20
  */
21
21
  async createMIDIDeviceHandler()
22
22
  {
@@ -36,12 +36,12 @@ export class MIDIDeviceHandler
36
36
  const response = await navigator.requestMIDIAccess({ sysex: true, software: true });
37
37
  this.inputs = response.inputs;
38
38
  this.outputs = response.outputs;
39
- SpessaSynthInfo("%cMIDI handler created!", consoleColors.recognized);
39
+ util.SpessaSynthInfo("%cMIDI handler created!", consoleColors.recognized);
40
40
  return true;
41
41
  }
42
42
  catch (e)
43
43
  {
44
- SpessaSynthWarn(`Could not get MIDI Devices:`, e);
44
+ util.SpessaSynthWarn(`Could not get MIDI Devices:`, e);
45
45
  this.inputs = [];
46
46
  this.outputs = [];
47
47
  return false;
@@ -49,7 +49,7 @@ export class MIDIDeviceHandler
49
49
  }
50
50
  else
51
51
  {
52
- SpessaSynthWarn("Web MIDI Api not supported!", consoleColors.unrecognized);
52
+ util.SpessaSynthWarn("Web MIDI Api not supported!", consoleColors.unrecognized);
53
53
  this.inputs = [];
54
54
  this.outputs = [];
55
55
  return false;
@@ -65,7 +65,7 @@ export class MIDIDeviceHandler
65
65
  {
66
66
  this.selectedOutput = output;
67
67
  seq.connectMidiOutput(output);
68
- SpessaSynthInfo(
68
+ util.SpessaSynthInfo(
69
69
  `%cPlaying MIDI to %c${output.name}`,
70
70
  consoleColors.info,
71
71
  consoleColors.recognized
@@ -80,7 +80,7 @@ export class MIDIDeviceHandler
80
80
  {
81
81
  this.selectedOutput = NO_INPUT;
82
82
  seq.connectMidiOutput(undefined);
83
- SpessaSynthInfo(
83
+ util.SpessaSynthInfo(
84
84
  "%cDisconnected from MIDI out.",
85
85
  consoleColors.info
86
86
  );
@@ -98,7 +98,7 @@ export class MIDIDeviceHandler
98
98
  {
99
99
  synth.sendMessage(event.data);
100
100
  };
101
- SpessaSynthInfo(
101
+ util.SpessaSynthInfo(
102
102
  `%cListening for messages on %c${input.name}`,
103
103
  consoleColors.info,
104
104
  consoleColors.recognized
@@ -112,7 +112,7 @@ export class MIDIDeviceHandler
112
112
  {
113
113
  this.selectedInput = NO_INPUT;
114
114
  input.onmidimessage = undefined;
115
- SpessaSynthInfo(
115
+ util.SpessaSynthInfo(
116
116
  `%cDisconnected from %c${input.name}`,
117
117
  consoleColors.info,
118
118
  consoleColors.recognized
@@ -1,6 +1,6 @@
1
- import { Synthetizer } from "../synthetizer/worklet_wrapper/synthetizer.js";
1
+ import { Synthetizer } from "../synthetizer/synthetizer.js";
2
2
  import { consoleColors } from "../utils/other.js";
3
- import { SpessaSynthInfo } from "../utils/loggin.js";
3
+ import { SpessaSynthCoreUtils } from "spessasynth_core";
4
4
 
5
5
  /**
6
6
  * web_midi_link.js
@@ -38,6 +38,6 @@ export class WebMIDILinkHandler
38
38
  synth.sendMessage(midiData);
39
39
  });
40
40
 
41
- SpessaSynthInfo("%cWeb MIDI Link handler created!", consoleColors.recognized);
41
+ SpessaSynthCoreUtils.SpessaSynthInfo("%cWeb MIDI Link handler created!", consoleColors.recognized);
42
42
  }
43
43
  }
package/index.js CHANGED
@@ -1,35 +1,38 @@
1
1
  // Import modules
2
- import { loadSoundFont } from "./soundfont/load_soundfont.js";
3
- import { BasicSoundBank } from "./soundfont/basic_soundfont/basic_soundfont.js";
4
- import { BasicSample } from "./soundfont/basic_soundfont/basic_sample.js";
5
- import { BasicInstrumentZone } from "./soundfont/basic_soundfont/basic_zones.js";
6
- import { BasicInstrument } from "./soundfont/basic_soundfont/basic_instrument.js";
7
- import { Generator } from "./soundfont/basic_soundfont/generator.js";
8
- import { Modulator } from "./soundfont/basic_soundfont/modulator.js";
9
- import { BasicPresetZone } from "./soundfont/basic_soundfont/basic_zones.js";
10
- import { BasicPreset } from "./soundfont/basic_soundfont/basic_preset.js";
11
- import { BasicMIDI } from "./midi/basic_midi.js";
12
- import { MIDIMessage } from "./midi/midi_message.js";
13
- import { MIDI } from "./midi/midi_loader.js";
14
- import { RMIDINFOChunks } from "./midi/midi_tools/rmidi_writer.js";
15
- import { MIDIBuilder } from "./midi/midi_builder.js";
16
- import { Synthetizer } from "./synthetizer/worklet_wrapper/synthetizer.js";
17
- import { VOICE_CAP, DEFAULT_PERCUSSION } from "./synthetizer/synth_constants.js";
18
- import { Sequencer } from "./sequencer/worklet_wrapper/sequencer.js";
19
- import { IndexedByteArray } from './utils/indexed_array.js';
20
- import { audioBufferToWav } from './utils/buffer_to_wav.js';
21
- import { SpessaSynthLogging } from './utils/loggin.js';
22
- import { midiControllers, messageTypes } from "./midi/midi_message.js";
23
- import { MIDIDeviceHandler} from "./external_midi/midi_handler.js";
24
- import { WebMIDILinkHandler} from "./external_midi/web_midi_link.js";
25
- import { modulatorSources } from "./soundfont/basic_soundfont/modulator.js";
2
+ import {
3
+ ALL_CHANNELS_OR_DIFFERENT_ACTION,
4
+ BasicInstrument,
5
+ BasicInstrumentZone,
6
+ BasicMIDI,
7
+ BasicPreset,
8
+ BasicPresetZone,
9
+ BasicSample,
10
+ BasicSoundBank,
11
+ ChannelSnapshot,
12
+ DEFAULT_PERCUSSION,
13
+ Generator,
14
+ IndexedByteArray,
15
+ loadSoundFont,
16
+ messageTypes,
17
+ MIDI,
18
+ MIDIBuilder,
19
+ midiControllers,
20
+ MIDIMessage,
21
+ Modulator,
22
+ modulatorSources,
23
+ NON_CC_INDEX_OFFSET,
24
+ RMIDINFOChunks,
25
+ SpessaSynthLogging,
26
+ SynthesizerSnapshot,
27
+ VOICE_CAP
28
+ } from "spessasynth_core";
29
+ import { Synthetizer } from "./synthetizer/synthetizer.js";
30
+ import { Sequencer } from "./sequencer/sequencer.js";
31
+ import { audioBufferToWav } from "./utils/buffer_to_wav.js";
32
+ import { MIDIDeviceHandler } from "./external_midi/midi_handler.js";
33
+ import { WebMIDILinkHandler } from "./external_midi/web_midi_link.js";
26
34
  import { DEFAULT_SYNTH_CONFIG } from "./synthetizer/audio_effects/effects_config.js";
27
- import { WORKLET_URL_ABSOLUTE } from "./synthetizer/worklet_wrapper/worklet_url.js";
28
- import { SynthesizerSnapshot } from "./synthetizer/audio_engine/snapshot/synthesizer_snapshot.js";
29
- import { ChannelSnapshot } from "./synthetizer/audio_engine/snapshot/channel_snapshot.js";
30
- import { SpessaSynthProcessor } from "./synthetizer/audio_engine/main_processor.js";
31
- import { NON_CC_INDEX_OFFSET } from "./synthetizer/audio_engine/engine_components/controller_tables.js";
32
- import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from "./synthetizer/audio_engine/message_protocol/worklet_message.js";
35
+ import { WORKLET_URL_ABSOLUTE } from "./synthetizer/worklet_url.js";
33
36
 
34
37
  // Export modules
35
38
  export {
@@ -44,9 +47,6 @@ export {
44
47
  ALL_CHANNELS_OR_DIFFERENT_ACTION,
45
48
  NON_CC_INDEX_OFFSET,
46
49
 
47
- // Audio Engine
48
- SpessaSynthProcessor,
49
-
50
50
  // SoundFont
51
51
  BasicSoundBank,
52
52
  BasicSample,
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.25.23",
4
- "description": "MIDI and SoundFont2/DLS library with no compromises",
3
+ "version": "3.26.1",
4
+ "description": "MIDI and SoundFont2/DLS library for the browsers with no compromises",
5
5
  "browser": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "build": "./minify_processor.sh"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
12
- "url": "git+https://github.com/spessasus/SpessaSynth.git"
13
+ "url": "git+https://github.com/spessasus/spessasynth_lib.git"
13
14
  },
14
15
  "main": "index.js",
15
16
  "keywords": [
@@ -36,8 +37,20 @@
36
37
  },
37
38
  "license": "Apache-2.0",
38
39
  "bugs": {
39
- "url": "https://github.com/spessasus/SpessaSynth/issues",
40
+ "url": "https://github.com/spessasus/spessasynth_lib/issues",
40
41
  "email": "spesekspesek@gmail.com"
41
42
  },
42
- "homepage": "https://github.com/spessasus/SpessaSynth#readme"
43
+ "homepage": "https://github.com/spessasus/spessasynth_lib#readme",
44
+ "files": [
45
+ "index.js",
46
+ "LICENSE",
47
+ "README.md",
48
+ "sequencer",
49
+ "synthetizer",
50
+ "utils",
51
+ "external_midi"
52
+ ],
53
+ "dependencies": {
54
+ "spessasynth_core": "latest"
55
+ }
43
56
  }
@@ -1,4 +1,4 @@
1
- import { MIDISequenceData } from "./midi_sequence.js";
1
+ import { BasicMIDI, MIDISequenceData } from "spessasynth_core";
2
2
 
3
3
  /**
4
4
  * A simplified version of the MIDI, accessible at all times from the Sequencer.
@@ -1,18 +1,19 @@
1
- import { Synthetizer } from "../../synthetizer/worklet_wrapper/synthetizer.js";
2
- import { messageTypes } from "../../midi/midi_message.js";
1
+ import { Synthetizer } from "../synthetizer/synthetizer.js";
3
2
  import {
4
3
  ALL_CHANNELS_OR_DIFFERENT_ACTION,
5
- workletMessageType
6
- } from "../../synthetizer/audio_engine/message_protocol/worklet_message.js";
4
+ BasicMIDI,
5
+ messageTypes,
6
+ MIDI,
7
+ MIDIMessage,
8
+ SpessaSynthCoreUtils as util
9
+ } from "spessasynth_core";
10
+ import { workletMessageType } from "../synthetizer/worklet_message.js";
7
11
  import {
8
12
  SongChangeType,
9
13
  SpessaSynthSequencerMessageType,
10
14
  SpessaSynthSequencerReturnMessageType
11
15
  } from "./sequencer_message.js";
12
- import { SpessaSynthWarn } from "../../utils/loggin.js";
13
- import { DUMMY_MIDI_DATA, MIDIData } from "../../midi/midi_data.js";
14
- import { BasicMIDI } from "../../midi/basic_midi.js";
15
- import { readBytesAsUintBigEndian } from "../../utils/byte_functions/big_endian.js";
16
+ import { DUMMY_MIDI_DATA, MIDIData } from "./midi_data.js";
16
17
  import { DEFAULT_SEQUENCER_OPTIONS } from "./default_sequencer_options.js";
17
18
 
18
19
  /**
@@ -520,7 +521,7 @@ export class Sequencer
520
521
  }
521
522
  catch (e)
522
523
  {
523
- SpessaSynthWarn(`Failed to execute callback for ${callback[0]}:`, e);
524
+ util.SpessaSynthWarn(`Failed to execute callback for ${callback[0]}:`, e);
524
525
  }
525
526
  }
526
527
  }
@@ -570,7 +571,7 @@ export class Sequencer
570
571
 
571
572
  case SpessaSynthSequencerReturnMessageType.timeChange:
572
573
  // message data is absolute time
573
- const time = this.synth.currentTime - messageData;
574
+ const time = messageData;
574
575
  this._callEvents(this.onTimeChange, time);
575
576
  this._recalculateStartTime(time);
576
577
  if (this.paused && this._preservePlaybackState)
@@ -619,7 +620,7 @@ export class Sequencer
619
620
  {
620
621
  case messageTypes.setTempo:
621
622
  event.messageData.currentIndex = 0;
622
- const bpm = 60000000 / readBytesAsUintBigEndian(event.messageData, 3);
623
+ const bpm = 60000000 / util.readBytesAsUintBigEndian(event.messageData, 3);
623
624
  event.messageData.currentIndex = 0;
624
625
  this.currentTempo = Math.round(bpm * 100) / 100;
625
626
  if (this.onTempoChange)
@@ -769,7 +770,7 @@ export class Sequencer
769
770
  {
770
771
  if (this.paused)
771
772
  {
772
- SpessaSynthWarn("Already paused");
773
+ util.SpessaSynthWarn("Already paused");
773
774
  return;
774
775
  }
775
776
  this.pausedTime = this.currentTime;
@@ -43,7 +43,7 @@ export const SpessaSynthSequencerMessageType = {
43
43
  export const SpessaSynthSequencerReturnMessageType = {
44
44
  midiEvent: 0, // [...midiEventBytes<number>]
45
45
  songChange: 1, // [songIndex<number>, isAutoPlayed<boolean>]
46
- timeChange: 2, // newAbsoluteTime<number>
46
+ timeChange: 2, // newTime<number>
47
47
  pause: 3, // no data
48
48
  getMIDI: 4, // midiData<MIDI>
49
49
  midiError: 5, // errorMSG<string>
@@ -7,4 +7,32 @@ This is the heart of the SpessaSynth library.
7
7
  - `audio_effects` - the WebAudioAPI audio effects.
8
8
  - `worklet_wrapper` - the wrapper for the core synthesis engine using audio worklets.
9
9
 
10
- `worklet_processor.min.js` - the minified worklet processor code to import.
10
+ `worklet_processor.min.js` - the minified worklet processor code to import.
11
+
12
+ # About the message protocol
13
+ Since spessasynth_lib runs in the audioWorklet thread, here is an explanation of how it works:
14
+
15
+ There's one processor per synthesizer, with a `MessagePort` for communication.
16
+ Each processor has a single `SpessaSynthequencer` instance that is idle by default.
17
+
18
+ The `Synthetizer`,
19
+ `Sequencer` and `SoundFontManager` classes are all interfaces
20
+ that do not do anything except sending the commands to te processor.
21
+
22
+ The synthesizer sends the commands (note on, off, etc.) directly to the processor where they are processed and executed.
23
+
24
+ The sequencer sends the commands through the connected synthesizer's messagePort, which then get processed as sequencer messages and routed properly.
25
+
26
+
27
+ ## How it works in spessasynth_lib
28
+ Both `Synthetizer` and `Sequencer` are essentially "remote control"
29
+ for the actual sequencer and synthesizer in the audio worklet thread (here)
30
+ These core components are wrapped in the AudioWorkletProcessor, which is receiving both commands and data (MIDIs, sound banks)
31
+ through the message port, and sends data back (events, time changes, status changes, etc.).
32
+
33
+ For example,
34
+ the playback to WebMIDIAPI is actually the sequencer in the worklet thread
35
+ playing back the sequence and then postMessaging the commands through the synthesizer to the sequencer
36
+ which actually sends them to the specified output.
37
+
38
+ The wonders of separate audio thread...
@@ -1,5 +1,5 @@
1
1
  import { rbCompressed } from "./rb_compressed.min.js";
2
- import { inflateSync } from "../../externals/fflate/fflate.min.js";
2
+ import { SpessaSynthCoreUtils } from "spessasynth_core";
3
3
 
4
4
  // convert the base64 string to array buffer
5
5
  const binaryString = atob(rbCompressed);
@@ -14,5 +14,5 @@ for (let i = 0; i < binaryString.length; i++)
14
14
  * the reverb is zlib compressed, decompress here
15
15
  * @type {ArrayBuffer}
16
16
  */
17
- const reverbBufferBinary = inflateSync(binary).buffer;
17
+ const reverbBufferBinary = SpessaSynthCoreUtils.inflateSync(binary).buffer;
18
18
  export { reverbBufferBinary };
@@ -1,5 +1,14 @@
1
- import { workletMessageType } from "../audio_engine/message_protocol/worklet_message.js";
2
- import { KeyModifier, workletKeyModifierMessageType } from "../audio_engine/engine_components/key_modifier_manager.js";
1
+ import { workletMessageType } from "./worklet_message.js";
2
+ import { KeyModifier } from "spessasynth_core";
3
+
4
+ /**
5
+ * @enum {number}
6
+ */
7
+ export const workletKeyModifierMessageType = {
8
+ addMapping: 0, // [channel<number>, midiNote<number>, mapping<KeyModifier>]
9
+ deleteMapping: 1, // [channel<number>, midiNote<number>]
10
+ clearMappings: 2 // <no data>
11
+ };
3
12
 
4
13
  export class WorkletKeyModifierManagerWrapper
5
14
  {
@@ -1,6 +1,8 @@
1
+ import { synthDisplayTypes } from "spessasynth_core";
2
+
1
3
  /**
2
4
  * synth_event_handler.js
3
- * purpose: manages the synthesizer's event system, calling assinged functions when synthesizer requests dispatching the event
5
+ * purpose: manages the synthesizer's event system, calling assigned functions when synthesizer requests dispatching the event
4
6
  */
5
7
 
6
8
  /**
@@ -56,14 +58,14 @@
56
58
  /**
57
59
  * @typedef {Object} SynthDisplayCallback
58
60
  * @property {Uint8Array} displayData - The data to display.
59
- * @property {SynthDisplayType} displayType - The type of display.
61
+ * @property {synthDisplayTypes} displayType - The type of display.
60
62
  */
61
63
 
62
64
  /**
63
65
  * @typedef {Object} PitchWheelCallback
64
66
  * @property {number} channel - The MIDI channel number.
65
- * @property {number} MSB - The most significant byte of the pitch wheel value.
66
- * @property {number} LSB - The least significant byte of the pitch wheel value.
67
+ * @property {number} MSB - The most significant byte of the pitch-wheel value.
68
+ * @property {number} LSB - The least significant byte of the pitch-wheel value.
67
69
  */
68
70
 
69
71
  /**
@@ -123,15 +125,15 @@ export class EventHandler
123
125
  * @type {Object<EventTypes, Object<string, function(EventCallbackData)>>}
124
126
  */
125
127
  this.events = {
126
- "noteoff": {}, // called on note off message
127
- "noteon": {}, // called on note on message
128
- "pitchwheel": {}, // called on pitch wheel change
129
- "controllerchange": {}, // called on controller change
130
- "programchange": {}, // called on program change
131
- "channelpressure": {}, // called on channel pressure message
132
- "polypressure": {}, // called on poly pressure message
133
- "drumchange": {}, // called when channel type changes
134
- "stopall": {}, // called when synth receives stop all command
128
+ "noteoff": {}, // called on a note off message
129
+ "noteon": {}, // called on a note on message
130
+ "pitchwheel": {}, // called on a pitch-wheel change
131
+ "controllerchange": {}, // called on a controller change
132
+ "programchange": {}, // called on a program change
133
+ "channelpressure": {}, // called on a channel pressure message
134
+ "polypressure": {}, // called on a poly pressure message
135
+ "drumchange": {}, // called when a channel type changes
136
+ "stopall": {}, // called when the synth receives stop all command
135
137
  "newchannel": {}, // called when a new channel is created
136
138
  "mutechannel": {}, // called when a channel is muted/unmuted
137
139
  "presetlistchange": {}, // called when the preset list changes (soundfont gets reloaded)
@@ -158,6 +160,7 @@ export class EventHandler
158
160
  this.events[name][id] = callback;
159
161
  }
160
162
 
163
+ // noinspection JSUnusedGlobalSymbols
161
164
  /**
162
165
  * Removes an event listener
163
166
  * @param name {EventTypes}