spessasynth_lib 4.0.20 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,38 +3,30 @@
3
3
  <img src='https://raw.githubusercontent.com/spessasus/SpessaSynth/refs/heads/master/src/website/spessasynth_logo_rounded.png' width='300' alt='SpessaSynth logo'>
4
4
  </p>
5
5
 
6
- *A powerful SF2/DLS/MIDI JavaScript library for the browsers, based on spessasynth_core.
7
- This is a WebAudioAPI wrapper for the [spessasynth_core](https://github.com/spessasus/spessasynth_core) library.*
8
-
9
- **v4.0.0 TypeScript Update is here! The NPM package now contains type declarations for easier developing!**
10
- [**Read about breaking changes here**](https://spessasus.github.io/spessasynth_lib/extra/4-0-migration-guide)
11
-
6
+ _A powerful SF2/DLS/MIDI TypeScript/JavaScript library for the browsers, based on spessasynth_core.
7
+ This is a WebAudioAPI wrapper for the [spessasynth_core](https://github.com/spessasus/spessasynth_core) library._
12
8
 
13
9
  It allows you to:
10
+
14
11
  - Play MIDI files using SF2/SF3/DLS files!
15
12
  - Read and write MIDI files!
16
13
  - Write SF2/SF3 files!
17
14
  - Convert DLS to SF2! (and back!)
18
15
  - [and more!](#current-features)
19
16
 
20
-
21
17
  > **TIP:**
22
- >
18
+ >
23
19
  > Looking for a bare JS version that works without WebAudioAPI? Try [spessasynth_core](https://github.com/spessasus/spessasynth_core)!
24
20
 
25
-
26
-
27
21
  ### [Project site (consider giving it a star!)](https://github.com/spessasus/spessasynth_lib)
28
22
 
29
23
  ### Made with spessasynth_lib
24
+
30
25
  - [SpessaSynth - Online SF2/DLS MIDI Player](https://spessasus.github.io/SpessaSynth)
31
26
  - [SpessaFont - Online SoundFont/DLS Editor](https://spessasus.github.io/SpessaFont)
32
27
 
33
-
34
28
  ### [Documentation](https://spessasus.github.io/spessasynth_lib)
35
29
 
36
-
37
-
38
30
  **SpessaSynth Project index**
39
31
 
40
32
  - [spessasynth_core](https://github.com/spessasus/spessasynth_core) - SF2/DLS/MIDI library
@@ -47,25 +39,27 @@ It allows you to:
47
39
  ### [All the features of spessasynth_core!](https://github.com/spessasus/spessasynth_core?#current-features)
48
40
 
49
41
  ### On top of that...
50
- - **Fully typed:** *Faster development and IDE auto-completion!*
51
- - **Modular design:** *Easy integration into other projects (load what you need)*
52
- - **[Detailed documentation:](https://spessasus.github.io/spessasynth_lib/)** *With [examples!](https://spessasus.github.io/spessasynth_lib/getting-started/#examples)*
53
- - **Easy to Use:** *Basic setup is just [two lines of code!](https://spessasus.github.io/spessasynth_lib/getting-started/#minimal-setup)*
54
- - **No external dependencies:** *Just spessasynth_core!*
42
+
43
+ - **Fully typed:** _Faster development and IDE auto-completion!_
44
+ - **Modular design:** _Easy integration into other projects (load what you need)_
45
+ - **[Detailed documentation:](https://spessasus.github.io/spessasynth_lib/)** _With [examples!](https://spessasus.github.io/spessasynth_lib/getting-started/#examples)_
46
+ - **Easy to Use:** _Basic setup is just [two lines of code!](https://spessasus.github.io/spessasynth_lib/getting-started/#minimal-setup)_
47
+ - **No external dependencies:** _Just spessasynth_core!_
55
48
  - **Reverb and chorus support:** [customizable](https://spessasus.github.io/spessasynth_lib/synthesizer/#effects-configuration-object) and can be used standalone!
56
49
  - **Export audio files** using [OfflineAudioContext](https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext)!
57
- - **AudioWorklet synthesizer:**
58
- - Runs in a **separate thread** for maximum performance!
59
- - Does not stop playing even when the main thread is frozen!
60
- - Supported by all modern browsers!
61
- - **Web Worker synthesizer:**
62
- - Synthesize directly in the Web Worker!
63
- - Direct audio engine access!
64
- - Export audio automatically in the worker!
65
- - Avoids [Chromium Audio Bugs](https://issues.chromium.org/issues/367304685)!
66
- - **High-performance mode:** Play Rush E! *note: may kill your browser ;)*
50
+ - **AudioWorklet synthesizer:**
51
+ - Runs in a **separate thread** for maximum performance!
52
+ - Does not stop playing even when the main thread is frozen!
53
+ - Supported by all modern browsers!
54
+ - **Web Worker synthesizer:**
55
+ - Synthesize directly in the Web Worker!
56
+ - Direct audio engine access!
57
+ - Export audio automatically in the worker!
58
+ - Avoids [Chromium Audio Bugs](https://issues.chromium.org/issues/367304685)!
59
+ - **High-performance mode:** Play Rush E! _note: may kill your browser ;)_
67
60
 
68
61
  ### Special Thanks
62
+
69
63
  - [FluidSynth](https://github.com/FluidSynth/fluidsynth) - for the source code that helped implement functionality and fixes
70
64
  - [Polyphone](https://www.polyphone-soundfonts.com/) - for the sound bank testing and editing tool
71
65
  - [Meltysynth](https://github.com/sinshu/meltysynth) - for the initial low-pass filter implementation
@@ -78,11 +72,10 @@ It allows you to:
78
72
  - [Christian Collins](https://schristiancollins.com) - for various bug reports regarding the synthesizer
79
73
  - **And You!** - for checking out this project. I hope you like it :)
80
74
 
81
-
82
75
  ### Basic example: play a single note
83
76
 
84
77
  ```js
85
- import { WorkletSynthesizer } from "spessasynth_lib"
78
+ import { WorkletSynthesizer } from "spessasynth_lib";
86
79
 
87
80
  // SF2, SF3, SFOGG and DLS files are all supported!
88
81
  const sfont = await (await fetch("soundfont.sf3")).arrayBuffer();
@@ -92,16 +85,16 @@ await ctx.audioWorklet.addModule("./spessasynth_processor.min.js");
92
85
  const synth = new WorkletSynthesizer(ctx);
93
86
  await synth.soundBankManager.addSoundBank(sfont, "main");
94
87
  await synth.isReady;
95
- document.getElementById("button").onclick = async () =>
96
- {
88
+ document.getElementById("button").onclick = async () => {
97
89
  await ctx.resume();
98
90
  synth.programChange(0, 48); // strings ensemble
99
91
  synth.noteOn(0, 52, 127);
100
- }
92
+ };
101
93
  ```
102
94
 
103
95
  # License
96
+
104
97
  Copyright © 2026 Spessasus
105
98
  Licensed under the Apache-2.0 License.
106
99
 
107
- SoundFont® is a registered trademark of Creative Technology Ltd.
100
+ SoundFont® is a registered trademark of Creative Technology Ltd.
package/dist/index.d.ts CHANGED
@@ -100,6 +100,7 @@ declare class SynthEventHandler {
100
100
  /**
101
101
  * Calls the given event.
102
102
  * INTERNAL USE ONLY!
103
+ * @internal
103
104
  */
104
105
  callEventInternal<T extends keyof SynthProcessorEventData>(name: T, eventData: SynthProcessorEventData[T]): void;
105
106
  }
@@ -150,6 +151,7 @@ type SequencerMessage = {
150
151
  [K in keyof SequencerMessageData]: {
151
152
  type: K;
152
153
  data: SequencerMessageData[K];
154
+ id: number;
153
155
  };
154
156
  }[keyof SequencerMessageData];
155
157
  interface SequencerMessageData {
@@ -167,12 +169,16 @@ interface SequencerMessageData {
167
169
  getMIDI: null;
168
170
  setSkipToFirstNote: boolean;
169
171
  }
170
- type SequencerReturnMessage = SequencerEvent | {
172
+ type SequencerReturnMessage = (SequencerEvent & {
173
+ id: number;
174
+ }) | {
171
175
  type: "getMIDI";
172
176
  data: BasicMIDI;
177
+ id: number;
173
178
  } | {
174
179
  type: "midiError";
175
180
  data: Error;
181
+ id: number;
176
182
  };
177
183
  /**
178
184
  * Sequencer.js
@@ -227,7 +233,7 @@ type PostMessageSynthCore = (data: BasicSynthesizerReturnMessage, transfer?: Tra
227
233
  */
228
234
  declare abstract class BasicSynthesizerCore {
229
235
  readonly synthesizer: SpessaSynthProcessor;
230
- readonly sequencer: SpessaSynthSequencer;
236
+ readonly sequencers: SpessaSynthSequencer[];
231
237
  protected readonly post: PostMessageSynthCore;
232
238
  /**
233
239
  * Indicates if the processor is alive.
@@ -235,6 +241,7 @@ declare abstract class BasicSynthesizerCore {
235
241
  */
236
242
  protected alive: boolean;
237
243
  protected constructor(sampleRate: number, options: SynthProcessorOptions, postMessage: PostMessageSynthCore);
244
+ protected createNewSequencer(): void;
238
245
  protected postReady<K extends keyof SynthesizerReturn>(type: K, data: SynthesizerReturn[K], transferable?: Transferable[]): void;
239
246
  protected postProgress<K extends keyof SynthesizerProgress>(type: K, data: SynthesizerProgress[K]): void;
240
247
  protected destroy(): void;
@@ -299,6 +306,10 @@ interface WorkerRenderAudioOptions {
299
306
  * If the effects should be enabled.
300
307
  */
301
308
  enableEffects: boolean;
309
+ /**
310
+ * Which sequencer to render. Defaults to the first one (0).
311
+ */
312
+ sequencerID: number;
302
313
  }
303
314
 
304
315
  interface PassedProcessorParameters {
@@ -369,6 +380,10 @@ interface WorkerBankWriteOptions {
369
380
  * Trim the sound bank to only include samples used in the current MIDI file.
370
381
  */
371
382
  trim: boolean;
383
+ /**
384
+ * Which sequencer to grab the MIDI from if trimming. Defaults to the first one (0).
385
+ */
386
+ sequencerID: number;
372
387
  /**
373
388
  * The sound bank ID in the sound bank manager to write.
374
389
  */
@@ -417,7 +432,6 @@ interface BasicSynthesizerMessageData {
417
432
  delay: number;
418
433
  };
419
434
  stopAll: number;
420
- killNotes: number;
421
435
  muteChannel: boolean;
422
436
  addNewChannel: null;
423
437
  customCcChange: {
@@ -435,6 +449,7 @@ interface BasicSynthesizerMessageData {
435
449
  };
436
450
  sequencerSpecific: SequencerMessage;
437
451
  requestSynthesizerSnapshot: null;
452
+ requestNewSequencer: null;
438
453
  setLogLevel: {
439
454
  enableInfo: boolean;
440
455
  enableWarning: boolean;
@@ -710,8 +725,10 @@ declare abstract class BasicSynthesizer {
710
725
  presetList: PresetList;
711
726
  /**
712
727
  * INTERNAL USE ONLY!
728
+ * @internal
729
+ * All sequencer callbacks
713
730
  */
714
- sequencerCallbackFunction?: (m: SequencerReturnMessage) => unknown;
731
+ sequencers: ((m: SequencerReturnMessage) => unknown)[];
715
732
  /**
716
733
  * Resolves when the synthesizer is ready.
717
734
  */
@@ -728,6 +745,7 @@ declare abstract class BasicSynthesizer {
728
745
  readonly chorusProcessor?: ChorusProcessor;
729
746
  /**
730
747
  * INTERNAL USE ONLY!
748
+ * @internal
731
749
  */
732
750
  readonly post: (data: BasicSynthesizerMessage, transfer?: Transferable[]) => unknown;
733
751
  protected readonly worklet: AudioWorkletNode;
@@ -957,8 +975,15 @@ declare abstract class BasicSynthesizer {
957
975
  * INTERNAL USE ONLY!
958
976
  * @param type INTERNAL USE ONLY!
959
977
  * @param resolve INTERNAL USE ONLY!
978
+ * @internal
960
979
  */
961
980
  awaitWorkerResponse<K extends keyof SynthesizerReturn>(type: K, resolve: (data: SynthesizerReturn[K]) => unknown): void;
981
+ /**
982
+ * INTERNAL USE ONLY!
983
+ * @param callback the sequencer callback
984
+ * @internal
985
+ */
986
+ assignNewSequencer(callback: (m: SequencerReturnMessage) => unknown): number;
962
987
  protected assignProgressTracker<K extends keyof SynthesizerProgress>(type: K, progressFunction: (args: SynthesizerProgress[K]) => unknown): void;
963
988
  protected revokeProgressTracker<K extends keyof SynthesizerProgress>(type: K): void;
964
989
  protected _sendInternal(message: Iterable<number>, channelOffset: number, force: boolean | undefined, eventOptions: Partial<SynthMethodOptions>): void;
@@ -1079,6 +1104,7 @@ declare class SeqEventHandler {
1079
1104
  /**
1080
1105
  * Calls the given event.
1081
1106
  * Internal use only.
1107
+ * @internal
1082
1108
  */
1083
1109
  callEventInternal<T extends keyof WorkletSequencerEventType>(name: T, eventData: WorkletSequencerEventType[T]): void;
1084
1110
  }
@@ -1120,6 +1146,10 @@ declare class Sequencer {
1120
1146
  * Absolute playback startTime, bases on the synth's time.
1121
1147
  */
1122
1148
  private absoluteStartTime;
1149
+ /**
1150
+ * For sending the messages to the correct SpessaSynthSequencer in core
1151
+ */
1152
+ private readonly sequencerID;
1123
1153
  /**
1124
1154
  * Creates a new MIDI sequencer for playing back MIDI files.
1125
1155
  * @param synth synth to send events to.
@@ -1135,7 +1165,7 @@ declare class Sequencer {
1135
1165
  * The current song number in the playlist.
1136
1166
  */
1137
1167
  set songIndex(value: number);
1138
- protected _currentTempo: number;
1168
+ private _currentTempo;
1139
1169
  /**
1140
1170
  * Current song's tempo in BPM.
1141
1171
  */
@@ -1144,9 +1174,9 @@ declare class Sequencer {
1144
1174
  * The current sequence's length, in seconds.
1145
1175
  */
1146
1176
  get duration(): number;
1147
- protected _songsAmount: number;
1177
+ private _songsAmount;
1148
1178
  get songsAmount(): number;
1149
- protected _skipToFirstNoteOn: boolean;
1179
+ private _skipToFirstNoteOn;
1150
1180
  /**
1151
1181
  * Indicates if the sequencer should skip to first note on.
1152
1182
  */
@@ -1158,7 +1188,7 @@ declare class Sequencer {
1158
1188
  /**
1159
1189
  * Internal loop count marker (-1 is infinite).
1160
1190
  */
1161
- protected _loopCount: number;
1191
+ private _loopCount;
1162
1192
  /**
1163
1193
  * The current remaining number of loops. -1 means infinite looping.
1164
1194
  */
@@ -1170,7 +1200,7 @@ declare class Sequencer {
1170
1200
  /**
1171
1201
  * Controls the playback's rate.
1172
1202
  */
1173
- protected _playbackRate: number;
1203
+ private _playbackRate;
1174
1204
  /**
1175
1205
  * Controls the playback's rate.
1176
1206
  */
@@ -1179,7 +1209,7 @@ declare class Sequencer {
1179
1209
  * Controls the playback's rate.
1180
1210
  */
1181
1211
  set playbackRate(value: number);
1182
- protected _shuffleSongs: boolean;
1212
+ private _shuffleSongs;
1183
1213
  /**
1184
1214
  * Indicates if the song order is random.
1185
1215
  */
@@ -1229,9 +1259,9 @@ declare class Sequencer {
1229
1259
  * Starts or resumes the playback.
1230
1260
  */
1231
1261
  play(): void;
1232
- protected handleMessage(m: SequencerReturnMessage): void;
1233
- protected callEventInternal<EventType extends keyof WorkletSequencerEventType>(type: EventType, data: WorkletSequencerEventType[EventType]): void;
1234
- protected resetMIDIOutput(): void;
1262
+ private handleMessage;
1263
+ private callEventInternal;
1264
+ private resetMIDIOutput;
1235
1265
  private recalculateStartTime;
1236
1266
  private sendMessage;
1237
1267
  }