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 +27 -34
- package/dist/index.d.ts +49 -14
- package/dist/index.js +273 -165
- package/dist/index.js.map +1 -1
- package/dist/spessasynth_processor.min.js +13 -12
- package/dist/spessasynth_processor.min.js.map +4 -4
- package/package.json +17 -4
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
|
-
|
|
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
|
-
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- **Web Worker synthesizer:**
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- **High-performance mode:** Play Rush E!
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1182
|
+
private _songsAmount;
|
|
1148
1183
|
get songsAmount(): number;
|
|
1149
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1267
|
+
private handleMessage;
|
|
1268
|
+
private callEventInternal;
|
|
1269
|
+
private resetMIDIOutput;
|
|
1235
1270
|
private recalculateStartTime;
|
|
1236
1271
|
private sendMessage;
|
|
1237
1272
|
}
|