spessasynth_core 4.2.1 → 4.2.3
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 +32 -24
- package/dist/index.d.ts +2 -6
- package/dist/index.js +6 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
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
|
|
6
|
+
_A powerful multipurpose SF2/DLS/MIDI JavaScript library. It works with any modern JS environment that supports
|
|
7
7
|
WebAssembly._
|
|
8
8
|
|
|
9
9
|
It allows you to:
|
|
10
10
|
|
|
11
11
|
- Play MIDI files using SF2/SF3/DLS files!
|
|
12
12
|
- Read and write MIDI files!
|
|
13
|
-
-
|
|
13
|
+
- Read and write SF2/SF3 files!
|
|
14
14
|
- Convert DLS to SF2! (and back!)
|
|
15
15
|
- [and more!](#current-features)
|
|
16
16
|
|
|
@@ -23,7 +23,7 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
23
23
|
> Looking for an easy-to-use WebAudioAPI browser wrapper?
|
|
24
24
|
> Try [spessasynth_lib](https://github.com/spessasus/spessasynth_lib)!
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
**[Project site (consider giving it a star!)](https://github.com/spessasus/spessasynth_core)**
|
|
27
27
|
|
|
28
28
|
### Made with spessasynth_core
|
|
29
29
|
|
|
@@ -44,12 +44,12 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
44
44
|
|
|
45
45
|
### Easy Integration
|
|
46
46
|
|
|
47
|
-
- **Modular design:** _Easy integration into other projects (load what you need)_
|
|
47
|
+
- **Modular design:** _Easy integration into other projects (only load what you need)_
|
|
48
48
|
- **Flexible:** _It's not just a MIDI player!_
|
|
49
49
|
- **Easy to Use:** _Basic setup is
|
|
50
50
|
just [two lines of code!](https://spessasus.github.io/spessasynth_core/getting-started#minimal-setup)_
|
|
51
51
|
- **No dependencies:** _Batteries included!_
|
|
52
|
-
- **TypeScript definitions:** _Autocompletion in IDEs!_
|
|
52
|
+
- **Full TypeScript definitions:** _Autocompletion in IDEs!_
|
|
53
53
|
|
|
54
54
|
### Powerful MIDI Synthesizer
|
|
55
55
|
|
|
@@ -57,13 +57,11 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
57
57
|
- **Excellent SoundFont support:**
|
|
58
58
|
- **Full Generator Support**
|
|
59
59
|
- **Full Modulator Support:** _First (to my knowledge) JavaScript SoundFont synth with that feature!_
|
|
60
|
-
- **
|
|
60
|
+
- **GeneralUser-GS Compatible:**
|
|
61
61
|
_[See more here!](https://github.com/mrbumpy409/GeneralUser-GS/blob/main/documentation/README.md)_
|
|
62
62
|
- **SoundFont3 Support:** Play compressed SoundFonts!
|
|
63
63
|
- **Experimental SF2Pack Support:** Play soundfonts compressed with BASSMIDI! (_Note: only works with vorbis
|
|
64
64
|
compression_)
|
|
65
|
-
- **Can load very large SoundFonts:** up to 4GB! _Note: Only Firefox handles this well; Chromium has a hard-coded
|
|
66
|
-
memory limit_
|
|
67
65
|
- **Great DLS Support:**
|
|
68
66
|
- **DLS Level 1 Support**
|
|
69
67
|
- **DLS Level 2 Support**
|
|
@@ -74,14 +72,15 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
74
72
|
- **A-Law encoding support**
|
|
75
73
|
- **Both unsigned 8-bit and signed 16-bit sample support (24-bit theoretically supported as well!)**
|
|
76
74
|
- **Detects special articulator combinations:** _Such as vibratoLfoToPitch_
|
|
77
|
-
- **
|
|
75
|
+
- **Sound bank manager:** Stack multiple sound banks!
|
|
78
76
|
- **Unlimited channel count:** Your CPU is the limit!
|
|
79
77
|
- **Built-in, configurable effects:**
|
|
80
78
|
- **Reverb:** _Multiple characters including delay and panning delay!_
|
|
81
79
|
- **Chorus:** _Modulated delay lines with multiple presets!_
|
|
82
80
|
- **Delay:** _Three delay lines for all of your delay needs!_
|
|
83
81
|
- **Insertion Effects:** _The ultimate effects, they can give your sounds a completely different character! (limited support)_
|
|
84
|
-
- **
|
|
82
|
+
- **GS Compatible:** _MIDI files can configure the effects accurately!_
|
|
83
|
+
- **Replaceable:** _Effects not to your liking? You can replace them with your own!_
|
|
85
84
|
- **Excellent MIDI Standards Support:**
|
|
86
85
|
- **MIDI Controller Support:** Default supported
|
|
87
86
|
controllers [here](https://spessasus.github.io/spessasynth_core/extra/midi-implementation#default-supported-controllers)
|
|
@@ -89,14 +88,13 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
89
88
|
- **Sound Controllers:** _Real-time filter and envelope control!_
|
|
90
89
|
- **MIDI Tuning Standard Support:**
|
|
91
90
|
_[more info here](https://spessasus.github.io/spessasynth_core/extra/midi-implementation#midi-tuning-standard)_
|
|
92
|
-
- [Full **RPN** and
|
|
91
|
+
- [Full **RPN** and extensive **NRPN**
|
|
93
92
|
support](https://spessasus.github.io/spessasynth_core/extra/midi-implementation#supported-registered-parameters)
|
|
94
93
|
- **SoundFont2 NRPN Support**
|
|
95
94
|
- [**AWE32**
|
|
96
95
|
NRPN Compatibility Layer](https://spessasus.github.io/spessasynth_core/extra/midi-implementation#awe32-nrpn-compatibility-layer)
|
|
97
96
|
- [**Roland GS** and **Yamaha XG**
|
|
98
97
|
support!](https://spessasus.github.io/spessasynth_core/extra/midi-implementation#supported-system-exclusives)
|
|
99
|
-
- Built-in effects are GS-Compatible!
|
|
100
98
|
|
|
101
99
|
### Powerful and Fast MIDI Sequencer
|
|
102
100
|
|
|
@@ -181,7 +179,7 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
181
179
|
|
|
182
180
|
### Limitations
|
|
183
181
|
|
|
184
|
-
-
|
|
182
|
+
- Audio engine is written in pure TypeScript, so it may not be as performant as native implementations
|
|
185
183
|
- [SF2 to DLS Conversion limits](https://spessasus.github.io/spessasynth_core/extra/dls-conversion-problem)
|
|
186
184
|
|
|
187
185
|
#### TODO
|
|
@@ -208,6 +206,8 @@ Featuring Reverb, Chorus, Delay, Insertion effects and more!
|
|
|
208
206
|
|
|
209
207
|
### Short example: MIDI to wav converter
|
|
210
208
|
|
|
209
|
+
For use with node.js
|
|
210
|
+
|
|
211
211
|
```ts
|
|
212
212
|
import * as fs from "fs/promises";
|
|
213
213
|
import {
|
|
@@ -226,24 +226,30 @@ if (args.length !== 3) {
|
|
|
226
226
|
);
|
|
227
227
|
process.exit();
|
|
228
228
|
}
|
|
229
|
+
// Read MIDI and sound bank
|
|
229
230
|
const sf = await fs.readFile(args[0]);
|
|
230
231
|
const mid = await fs.readFile(args[1]);
|
|
232
|
+
// Parse the MIDI and sound bank
|
|
231
233
|
const midi = BasicMIDI.fromArrayBuffer(mid.buffer);
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
+
const soundBank = SoundBankLoader.fromArrayBuffer(sf.buffer);
|
|
235
|
+
|
|
236
|
+
// Initialize the synthesizer
|
|
237
|
+
const sampleRate = 48000;
|
|
234
238
|
const synth = new SpessaSynthProcessor(sampleRate, {
|
|
235
|
-
enableEventSystem: false
|
|
236
|
-
enableEffects: false
|
|
239
|
+
enableEventSystem: false
|
|
237
240
|
});
|
|
238
|
-
synth.soundBankManager.addSoundBank(
|
|
239
|
-
SoundBankLoader.fromArrayBuffer(sf.buffer),
|
|
240
|
-
"main"
|
|
241
|
-
);
|
|
241
|
+
synth.soundBankManager.addSoundBank(soundBank, "main");
|
|
242
242
|
await synth.processorInitialized;
|
|
243
|
+
// Enable uncapped voice count
|
|
244
|
+
synth.setMasterParameter("autoAllocateVoices", true);
|
|
245
|
+
|
|
246
|
+
// Initialize the sequencer
|
|
243
247
|
const seq = new SpessaSynthSequencer(synth);
|
|
244
248
|
seq.loadNewSongList([midi]);
|
|
245
249
|
seq.play();
|
|
246
250
|
|
|
251
|
+
// Prepare the output buffers
|
|
252
|
+
const sampleCount = Math.ceil(sampleRate * (midi.duration + 2));
|
|
247
253
|
const outLeft = new Float32Array(sampleCount);
|
|
248
254
|
const outRight = new Float32Array(sampleCount);
|
|
249
255
|
const start = performance.now();
|
|
@@ -252,13 +258,12 @@ let filledSamples = 0;
|
|
|
252
258
|
const BUFFER_SIZE = 128;
|
|
253
259
|
let i = 0;
|
|
254
260
|
const durationRounded = Math.floor(seq.midiData!.duration * 100) / 100;
|
|
255
|
-
const outputArray = [outLeft, outRight];
|
|
256
261
|
while (filledSamples < sampleCount) {
|
|
257
262
|
// Process sequencer
|
|
258
263
|
seq.processTick();
|
|
259
264
|
// Render
|
|
260
265
|
const bufferSize = Math.min(BUFFER_SIZE, sampleCount - filledSamples);
|
|
261
|
-
synth.
|
|
266
|
+
synth.process(outLeft, outRight, filledSamples, bufferSize);
|
|
262
267
|
filledSamples += bufferSize;
|
|
263
268
|
i++;
|
|
264
269
|
// Log progress
|
|
@@ -282,6 +287,8 @@ await fs.writeFile(args[2], new Uint8Array(wave));
|
|
|
282
287
|
console.info(`File written to ${args[2]}`);
|
|
283
288
|
```
|
|
284
289
|
|
|
290
|
+
Read more in the [documentation](https://spessasus.github.io/spessasynth_core)
|
|
291
|
+
|
|
285
292
|
### Building
|
|
286
293
|
|
|
287
294
|
To build the NPM package, do:
|
|
@@ -301,6 +308,7 @@ Licensed under the Apache-2.0 License.
|
|
|
301
308
|
#### Legal
|
|
302
309
|
|
|
303
310
|
This project is in no way endorsed or otherwise affiliated with the MIDI Manufacturers Association,
|
|
304
|
-
Creative Technology Ltd. or E-mu Systems, Inc.,
|
|
311
|
+
Roland Corporation, Yamaha Corporation, Creative Technology Ltd. or E-mu Systems, Inc.,
|
|
312
|
+
or any other organization mentioned.
|
|
305
313
|
SoundFont® is a registered trademark of Creative Technology Ltd.
|
|
306
314
|
All other trademarks are the property of their respective owners.
|
package/dist/index.d.ts
CHANGED
|
@@ -2714,8 +2714,6 @@ declare function dataEntryFine(this: MIDIChannel, dataValue: number): void;
|
|
|
2714
2714
|
* midiControllers table and handling special cases like bank select,
|
|
2715
2715
|
* data entry, and sustain pedal. It also computes modulators for all voices
|
|
2716
2716
|
* in the channel based on the controller change.
|
|
2717
|
-
* If the controller number is greater than 127, it is treated as a channel
|
|
2718
|
-
* configuration controller, and the `force` parameter must be set to true
|
|
2719
2717
|
* to allow changes.
|
|
2720
2718
|
*/
|
|
2721
2719
|
declare function controllerChange(this: MIDIChannel, controllerNumber: MIDIController, controllerValue: number, sendEvent?: boolean): void;
|
|
@@ -3063,10 +3061,9 @@ declare class SynthesizerCore {
|
|
|
3063
3061
|
* Processes a raw MIDI message.
|
|
3064
3062
|
* @param message The message to process.
|
|
3065
3063
|
* @param channelOffset The channel offset for the message.
|
|
3066
|
-
* @param force If true, forces the message to be processed.
|
|
3067
3064
|
* @param options Additional options for scheduling the message.
|
|
3068
3065
|
*/
|
|
3069
|
-
processMessage(message: Uint8Array | number[], channelOffset?: number,
|
|
3066
|
+
processMessage(message: Uint8Array | number[], channelOffset?: number, options?: SynthMethodOptions): void;
|
|
3070
3067
|
destroySynthProcessor(): void;
|
|
3071
3068
|
/**
|
|
3072
3069
|
* @param channel channel to get voices for
|
|
@@ -3654,10 +3651,9 @@ declare class SpessaSynthProcessor {
|
|
|
3654
3651
|
* Processes a raw MIDI message.
|
|
3655
3652
|
* @param message The message to process.
|
|
3656
3653
|
* @param channelOffset The channel offset for the message.
|
|
3657
|
-
* @param force If true, forces the message to be processed.
|
|
3658
3654
|
* @param options Additional options for scheduling the message.
|
|
3659
3655
|
*/
|
|
3660
|
-
readonly processMessage: (message: Uint8Array | number[], channelOffset?: number,
|
|
3656
|
+
readonly processMessage: (message: Uint8Array | number[], channelOffset?: number, options?: SynthMethodOptions) => void;
|
|
3661
3657
|
/**
|
|
3662
3658
|
* Core synthesis engine.
|
|
3663
3659
|
*/
|
package/dist/index.js
CHANGED
|
@@ -4773,7 +4773,6 @@ setResetValue(midiControllers.vibratoDepth, 64);
|
|
|
4773
4773
|
setResetValue(midiControllers.vibratoDelay, 64);
|
|
4774
4774
|
setResetValue(midiControllers.generalPurposeController6, 64);
|
|
4775
4775
|
setResetValue(midiControllers.generalPurposeController8, 64);
|
|
4776
|
-
setResetValue(midiControllers.reverbDepth, 40);
|
|
4777
4776
|
setResetValue(midiControllers.registeredParameterLSB, 127);
|
|
4778
4777
|
setResetValue(midiControllers.registeredParameterMSB, 127);
|
|
4779
4778
|
setResetValue(midiControllers.nonRegisteredParameterLSB, 127);
|
|
@@ -9798,6 +9797,7 @@ function dataEntryCoarse(dataCoarse) {
|
|
|
9798
9797
|
break;
|
|
9799
9798
|
}
|
|
9800
9799
|
// Process NRPNs
|
|
9800
|
+
case dataEntryStates.NRPCoarse:
|
|
9801
9801
|
case dataEntryStates.NRPFine: {
|
|
9802
9802
|
const paramCoarse = this.midiControllers[midiControllers.nonRegisteredParameterMSB] >> 7;
|
|
9803
9803
|
const paramFine = this.midiControllers[midiControllers.nonRegisteredParameterLSB] >> 7;
|
|
@@ -16875,21 +16875,19 @@ var SynthesizerCore = class {
|
|
|
16875
16875
|
* Processes a raw MIDI message.
|
|
16876
16876
|
* @param message The message to process.
|
|
16877
16877
|
* @param channelOffset The channel offset for the message.
|
|
16878
|
-
* @param force If true, forces the message to be processed.
|
|
16879
16878
|
* @param options Additional options for scheduling the message.
|
|
16880
16879
|
*/
|
|
16881
|
-
processMessage(message, channelOffset = 0,
|
|
16880
|
+
processMessage(message, channelOffset = 0, options = DEFAULT_SYNTH_METHOD_OPTIONS) {
|
|
16882
16881
|
const time = options.time;
|
|
16883
16882
|
if (time > this.currentTime) {
|
|
16884
16883
|
this.eventQueue.push({
|
|
16885
16884
|
message,
|
|
16886
16885
|
channelOffset,
|
|
16887
|
-
force,
|
|
16888
16886
|
time
|
|
16889
16887
|
});
|
|
16890
16888
|
this.eventQueue.sort((e1, e2) => e1.time - e2.time);
|
|
16891
16889
|
} else {
|
|
16892
|
-
this.processMessageInternal(message, channelOffset
|
|
16890
|
+
this.processMessageInternal(message, channelOffset);
|
|
16893
16891
|
}
|
|
16894
16892
|
}
|
|
16895
16893
|
destroySynthProcessor() {
|
|
@@ -17050,11 +17048,7 @@ var SynthesizerCore = class {
|
|
|
17050
17048
|
while (this.eventQueue[0]?.time <= time) {
|
|
17051
17049
|
const q = this.eventQueue.shift();
|
|
17052
17050
|
if (q) {
|
|
17053
|
-
this.processMessageInternal(
|
|
17054
|
-
q.message,
|
|
17055
|
-
q.channelOffset,
|
|
17056
|
-
q.force
|
|
17057
|
-
);
|
|
17051
|
+
this.processMessageInternal(q.message, q.channelOffset);
|
|
17058
17052
|
}
|
|
17059
17053
|
}
|
|
17060
17054
|
}
|
|
@@ -17567,7 +17561,7 @@ var SynthesizerCore = class {
|
|
|
17567
17561
|
const p = new proc(this.sampleRate);
|
|
17568
17562
|
this.insertionEffects.set(p.type, p);
|
|
17569
17563
|
}
|
|
17570
|
-
processMessageInternal(message, channelOffset
|
|
17564
|
+
processMessageInternal(message, channelOffset) {
|
|
17571
17565
|
const statusByteData = getEvent(message[0]);
|
|
17572
17566
|
const channelNumber = statusByteData.channel + channelOffset;
|
|
17573
17567
|
switch (statusByteData.status) {
|
|
@@ -17581,11 +17575,7 @@ var SynthesizerCore = class {
|
|
|
17581
17575
|
break;
|
|
17582
17576
|
}
|
|
17583
17577
|
case midiMessageTypes.noteOff: {
|
|
17584
|
-
|
|
17585
|
-
this.midiChannels[channelNumber].killNote(message[1]);
|
|
17586
|
-
} else {
|
|
17587
|
-
this.noteOff(channelNumber, message[1]);
|
|
17588
|
-
}
|
|
17578
|
+
this.noteOff(channelNumber, message[1]);
|
|
17589
17579
|
break;
|
|
17590
17580
|
}
|
|
17591
17581
|
case midiMessageTypes.pitchWheel: {
|
|
@@ -22357,7 +22347,6 @@ var SpessaSynthProcessor = class {
|
|
|
22357
22347
|
* Processes a raw MIDI message.
|
|
22358
22348
|
* @param message The message to process.
|
|
22359
22349
|
* @param channelOffset The channel offset for the message.
|
|
22360
|
-
* @param force If true, forces the message to be processed.
|
|
22361
22350
|
* @param options Additional options for scheduling the message.
|
|
22362
22351
|
*/
|
|
22363
22352
|
processMessage;
|