spessasynth_lib 4.0.20 → 4.1.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 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,20 @@ 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;
182
+ } | {
183
+ type: "sync";
184
+ data: number;
185
+ id: number;
176
186
  };
177
187
  /**
178
188
  * Sequencer.js
@@ -227,14 +237,16 @@ type PostMessageSynthCore = (data: BasicSynthesizerReturnMessage, transfer?: Tra
227
237
  */
228
238
  declare abstract class BasicSynthesizerCore {
229
239
  readonly synthesizer: SpessaSynthProcessor;
230
- readonly sequencer: SpessaSynthSequencer;
240
+ readonly sequencers: SpessaSynthSequencer[];
231
241
  protected readonly post: PostMessageSynthCore;
242
+ protected lastSequencerSync: number;
232
243
  /**
233
244
  * Indicates if the processor is alive.
234
245
  * @protected
235
246
  */
236
247
  protected alive: boolean;
237
248
  protected constructor(sampleRate: number, options: SynthProcessorOptions, postMessage: PostMessageSynthCore);
249
+ protected createNewSequencer(): void;
238
250
  protected postReady<K extends keyof SynthesizerReturn>(type: K, data: SynthesizerReturn[K], transferable?: Transferable[]): void;
239
251
  protected postProgress<K extends keyof SynthesizerProgress>(type: K, data: SynthesizerProgress[K]): void;
240
252
  protected destroy(): void;
@@ -269,7 +281,7 @@ declare class WorkerSynthesizerCore extends BasicSynthesizerCore {
269
281
  protected stopAudioLoop(): void;
270
282
  protected startAudioLoop(): void;
271
283
  protected destroy(): void;
272
- protected renderAndSendChunk(): void;
284
+ protected process(): void;
273
285
  }
274
286
 
275
287
  interface WorkerRenderAudioOptions {
@@ -299,6 +311,10 @@ interface WorkerRenderAudioOptions {
299
311
  * If the effects should be enabled.
300
312
  */
301
313
  enableEffects: boolean;
314
+ /**
315
+ * Which sequencer to render. Defaults to the first one (0).
316
+ */
317
+ sequencerID: number;
302
318
  }
303
319
 
304
320
  interface PassedProcessorParameters {
@@ -369,6 +385,10 @@ interface WorkerBankWriteOptions {
369
385
  * Trim the sound bank to only include samples used in the current MIDI file.
370
386
  */
371
387
  trim: boolean;
388
+ /**
389
+ * Which sequencer to grab the MIDI from if trimming. Defaults to the first one (0).
390
+ */
391
+ sequencerID: number;
372
392
  /**
373
393
  * The sound bank ID in the sound bank manager to write.
374
394
  */
@@ -417,7 +437,6 @@ interface BasicSynthesizerMessageData {
417
437
  delay: number;
418
438
  };
419
439
  stopAll: number;
420
- killNotes: number;
421
440
  muteChannel: boolean;
422
441
  addNewChannel: null;
423
442
  customCcChange: {
@@ -435,6 +454,7 @@ interface BasicSynthesizerMessageData {
435
454
  };
436
455
  sequencerSpecific: SequencerMessage;
437
456
  requestSynthesizerSnapshot: null;
457
+ requestNewSequencer: null;
438
458
  setLogLevel: {
439
459
  enableInfo: boolean;
440
460
  enableWarning: boolean;
@@ -710,8 +730,10 @@ declare abstract class BasicSynthesizer {
710
730
  presetList: PresetList;
711
731
  /**
712
732
  * INTERNAL USE ONLY!
733
+ * @internal
734
+ * All sequencer callbacks
713
735
  */
714
- sequencerCallbackFunction?: (m: SequencerReturnMessage) => unknown;
736
+ sequencers: ((m: SequencerReturnMessage) => unknown)[];
715
737
  /**
716
738
  * Resolves when the synthesizer is ready.
717
739
  */
@@ -728,6 +750,7 @@ declare abstract class BasicSynthesizer {
728
750
  readonly chorusProcessor?: ChorusProcessor;
729
751
  /**
730
752
  * INTERNAL USE ONLY!
753
+ * @internal
731
754
  */
732
755
  readonly post: (data: BasicSynthesizerMessage, transfer?: Transferable[]) => unknown;
733
756
  protected readonly worklet: AudioWorkletNode;
@@ -957,8 +980,15 @@ declare abstract class BasicSynthesizer {
957
980
  * INTERNAL USE ONLY!
958
981
  * @param type INTERNAL USE ONLY!
959
982
  * @param resolve INTERNAL USE ONLY!
983
+ * @internal
960
984
  */
961
985
  awaitWorkerResponse<K extends keyof SynthesizerReturn>(type: K, resolve: (data: SynthesizerReturn[K]) => unknown): void;
986
+ /**
987
+ * INTERNAL USE ONLY!
988
+ * @param callback the sequencer callback
989
+ * @internal
990
+ */
991
+ assignNewSequencer(callback: (m: SequencerReturnMessage) => unknown): number;
962
992
  protected assignProgressTracker<K extends keyof SynthesizerProgress>(type: K, progressFunction: (args: SynthesizerProgress[K]) => unknown): void;
963
993
  protected revokeProgressTracker<K extends keyof SynthesizerProgress>(type: K): void;
964
994
  protected _sendInternal(message: Iterable<number>, channelOffset: number, force: boolean | undefined, eventOptions: Partial<SynthMethodOptions>): void;
@@ -1079,6 +1109,7 @@ declare class SeqEventHandler {
1079
1109
  /**
1080
1110
  * Calls the given event.
1081
1111
  * Internal use only.
1112
+ * @internal
1082
1113
  */
1083
1114
  callEventInternal<T extends keyof WorkletSequencerEventType>(name: T, eventData: WorkletSequencerEventType[T]): void;
1084
1115
  }
@@ -1120,6 +1151,10 @@ declare class Sequencer {
1120
1151
  * Absolute playback startTime, bases on the synth's time.
1121
1152
  */
1122
1153
  private absoluteStartTime;
1154
+ /**
1155
+ * For sending the messages to the correct SpessaSynthSequencer in core
1156
+ */
1157
+ private readonly sequencerID;
1123
1158
  /**
1124
1159
  * Creates a new MIDI sequencer for playing back MIDI files.
1125
1160
  * @param synth synth to send events to.
@@ -1135,7 +1170,7 @@ declare class Sequencer {
1135
1170
  * The current song number in the playlist.
1136
1171
  */
1137
1172
  set songIndex(value: number);
1138
- protected _currentTempo: number;
1173
+ private _currentTempo;
1139
1174
  /**
1140
1175
  * Current song's tempo in BPM.
1141
1176
  */
@@ -1144,9 +1179,9 @@ declare class Sequencer {
1144
1179
  * The current sequence's length, in seconds.
1145
1180
  */
1146
1181
  get duration(): number;
1147
- protected _songsAmount: number;
1182
+ private _songsAmount;
1148
1183
  get songsAmount(): number;
1149
- protected _skipToFirstNoteOn: boolean;
1184
+ private _skipToFirstNoteOn;
1150
1185
  /**
1151
1186
  * Indicates if the sequencer should skip to first note on.
1152
1187
  */
@@ -1158,7 +1193,7 @@ declare class Sequencer {
1158
1193
  /**
1159
1194
  * Internal loop count marker (-1 is infinite).
1160
1195
  */
1161
- protected _loopCount: number;
1196
+ private _loopCount;
1162
1197
  /**
1163
1198
  * The current remaining number of loops. -1 means infinite looping.
1164
1199
  */
@@ -1170,7 +1205,7 @@ declare class Sequencer {
1170
1205
  /**
1171
1206
  * Controls the playback's rate.
1172
1207
  */
1173
- protected _playbackRate: number;
1208
+ private _playbackRate;
1174
1209
  /**
1175
1210
  * Controls the playback's rate.
1176
1211
  */
@@ -1179,7 +1214,7 @@ declare class Sequencer {
1179
1214
  * Controls the playback's rate.
1180
1215
  */
1181
1216
  set playbackRate(value: number);
1182
- protected _shuffleSongs: boolean;
1217
+ private _shuffleSongs;
1183
1218
  /**
1184
1219
  * Indicates if the song order is random.
1185
1220
  */
@@ -1229,9 +1264,9 @@ declare class Sequencer {
1229
1264
  * Starts or resumes the playback.
1230
1265
  */
1231
1266
  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;
1267
+ private handleMessage;
1268
+ private callEventInternal;
1269
+ private resetMIDIOutput;
1235
1270
  private recalculateStartTime;
1236
1271
  private sendMessage;
1237
1272
  }