spessasynth_core 1.1.5 → 1.1.7

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
@@ -9,37 +9,84 @@
9
9
  npm install --save spessasynth_core
10
10
  ```
11
11
 
12
- ### [Project site (consider giving it a star!)](https://github.com/spessasus/spessasynth_core)
12
+ ### [Project site (consider giving it a star!)](https://github.com/spessasus/SpessaSynth)
13
13
 
14
- ### [Demo (using the spessasynth_lib wrapper)](https://spessasus.github.io/SpessaSynth)
14
+ ### [Demo (using the spessasynth_lib wrapper)](https://spessasus.github.io/spessasynth_core)
15
15
 
16
16
  ### [Documentation (in progress!)](https://github.com/spessasus/spessasynth_core/wiki/Home)
17
17
 
18
18
 
19
- > Note: This is the new heart of the SpessaSynth library, after the repository has been split.
20
-
19
+ > Note: This is the new heart of the spessasynth_core library, after the repository has been split.
20
+
21
+ ###
22
+ ```js
23
+ import * as fs from "node:fs";
24
+ import { MIDI } from "../../src/midi/midi_loader.js";
25
+ import { SpessaSynthProcessor } from "../../src/synthetizer/audio_engine/main_processor.js";
26
+ import { SpessaSynthSequencer } from "../../src/sequencer/sequencer_engine.js";
27
+ import { audioToWav } from "../../src/utils/buffer_to_wav.js";
28
+
29
+ // process arguments
30
+ const args = process.argv.slice(2);
31
+ if (args.length !== 3)
32
+ {
33
+ console.log("Usage: node index.js <soundfont path> <midi path> <wav output path>");
34
+ process.exit();
35
+ }
36
+ // load the files
37
+ const sf = fs.readFileSync(args[0]);
38
+ const mid = fs.readFileSync(args[1]);
39
+
40
+ const midi = new MIDI(mid);
41
+ const sampleRate = 44100;
42
+ const sampleCount = 44100 * (midi.duration + 2);
43
+
44
+ const synth = new SpessaSynthProcessor(
45
+ sf,
46
+ sampleRate,
47
+ {},
48
+ false,
49
+ false
50
+ );
51
+ await synth.processorInitialized;
52
+
53
+ const seq = new SpessaSynthSequencer(synth);
54
+ seq.loadNewSongList([midi]);
55
+ seq.loop = false;
56
+
57
+ const outLeft = new Float32Array(sampleCount);
58
+ const outRight = new Float32Array(sampleCount);
59
+ const start = performance.now();
60
+ let filledSamples = 0;
61
+
62
+ const bufSize = 128;
63
+ while (filledSamples + bufSize < sampleCount)
64
+ {
65
+ const bufLeft = new Float32Array(bufSize);
66
+ const bufRight = new Float32Array(bufSize);
67
+ seq.processTick();
68
+ const arr = [bufLeft, bufRight];
69
+ synth.renderAudio(arr, arr, arr);
70
+ outLeft.set(bufLeft, filledSamples);
71
+ outRight.set(bufRight, filledSamples);
72
+ filledSamples += bufSize;
73
+ }
74
+ const wave = audioToWav({
75
+ leftChannel: outLeft,
76
+ rightChannel: outRight,
77
+ sampleRate: sampleRate
78
+ });
79
+ fs.writeFileSync(args[2], new Buffer(wave));
80
+ process.exit();
81
+ ```
21
82
 
22
83
  ## Current Features
23
84
 
24
- ### Numerous Format Support
25
- Supported formats list:
26
- - `.mid` - Standard MIDI File
27
- - `.kar` - Soft Karaoke MIDI File
28
- - `.sf2` - SoundFont2 File
29
- - `.sf3` - SoundFont2 Compressed File
30
- - `.sfogg` - SF2Pack With Vorbis Compression
31
- - `.dls` - Downloadable Sounds Levels 1 & 2 (as well as Mobile DLS)
32
- - `.rmi` - RIFF MIDI File
33
- - `.rmi` - RIFF MIDI File With Embedded DLS
34
- - `.rmi` - [RIFF MIDI File With Embedded SF2](https://github.com/spessasus/sf2-rmidi-specification)
35
- - `.xmf` - eXtensible Music Format
36
- - `.mxmf` - Mobile eXtensible Music format
37
-
38
- *With [an easy way of converting between them!](https://github.com/spessasus/spessasynth_core/wiki/Converting-Between-Formats)*
39
-
40
85
  ### Easy Integration
41
86
  - **Modular design:** *Easy integration into other projects (load what you need)*
87
+ - **[Detailed documentation:](https://github.com/spessasus/spessasynth_core/wiki/Home)** *With [examples!](https://github.com/spessasus/spessasynth_core/wiki/Usage-As-Library#examples)*
42
88
  - **Flexible:** *It's not just a MIDI player!*
89
+ - **Easy to Use:** *Basic setup is just [two lines of code!](https://github.com/spessasus/spessasynth_core/wiki/Usage-As-Library#minimal-setup)*
43
90
  - **No dependencies:** *Batteries included!*
44
91
 
45
92
  ### Powerful MIDI Synthesizer
@@ -50,7 +97,7 @@ Supported formats list:
50
97
  - **GeneralUserGS Compatible:** *[See more here!](https://github.com/mrbumpy409/GeneralUser-GS/blob/main/documentation/README.md)*
51
98
  - **SoundFont3 Support:** Play compressed SoundFonts!
52
99
  - **Experimental SF2Pack Support:** Play soundfonts compressed with BASSMIDI! (*Note: only works with vorbis compression*)
53
- - **Can load very large SoundFonts:** up to 4GB!
100
+ - **Can load very large SoundFonts:** up to 4GB! *Note: Only Firefox handles this well; Chromium has a hard-coded memory limit*
54
101
  - **Great DLS Support:**
55
102
  - **DLS Level 1 Support**
56
103
  - **DLS Level 2 Support**
@@ -62,7 +109,6 @@ Supported formats list:
62
109
  - **Both unsigned 8-bit and signed 16-bit sample support (24-bit theoretically supported as well!)**
63
110
  - **Detects special articulator combinations:** *Such as vibratoLfoToPitch*
64
111
  - **Soundfont manager:** Stack multiple soundfonts!
65
- - **[Custom modulators for additional controllers](https://github.com/spessasus/spessasynth_core/wiki/Modulator-Class#default-modulators):** *Why not?*
66
112
  - **Unlimited channel count:** Your CPU is the limit!
67
113
  - **Excellent MIDI Standards Support:**
68
114
  - **MIDI Controller Support:** Default supported controllers [here](https://github.com/spessasus/spessasynth_core/wiki/MIDI-Implementation#supported-controllers)
@@ -78,7 +124,8 @@ Supported formats list:
78
124
  - **Smart preloading:** Only preloads the samples used in the MIDI file for smooth playback *(down to key and velocity!)*
79
125
  - **Lyrics support:** Add karaoke to your program!
80
126
  - **Raw lyrics available:** Decode in any encoding! *(Kanji? No problem!)*
81
- - **Loop points support:** Ensures seamless loops!
127
+ - **Runs in Audio Thread as well:** Never blocks the main thread
128
+ - **Loop points support:** Ensures seamless loops
82
129
 
83
130
  ### Read and Write SoundFont and MIDI Files with Ease
84
131
  #### Read and write MIDI files
@@ -130,6 +177,7 @@ Supported formats list:
130
177
  - **Metadata support:** *Embed metadata such as title, artist, album and more!*
131
178
  - **Cue points:** *Write MIDI loop points as cue points!*
132
179
  - **Loop multiple times:** *Render two (or more) loops into the file for seamless transitions!*
180
+ - *That's right, saving as WAV is also [just one function!](https://github.com/spessasus/spessasynth_core/wiki/Writing-Wave-Files#audiobuffertowav)*
133
181
 
134
182
  ### Special Thanks
135
183
  - [FluidSynth](https://github.com/FluidSynth/fluidsynth) - for the source code that helped implement functionality and fixes
package/index.js CHANGED
@@ -1,7 +1,22 @@
1
1
  import { SpessaSynthProcessor } from "./src/synthetizer/audio_engine/main_processor.js";
2
2
  import { SpessaSynthSequencer } from "./src/sequencer/sequencer_engine.js";
3
- import { ALL_CHANNELS_OR_DIFFERENT_ACTION, DEFAULT_PERCUSSION, VOICE_CAP } from "./src/synthetizer/synth_constants.js";
4
- import { NON_CC_INDEX_OFFSET } from "./src/synthetizer/audio_engine/engine_components/controller_tables.js";
3
+ import {
4
+ ALL_CHANNELS_OR_DIFFERENT_ACTION,
5
+ DEFAULT_PERCUSSION,
6
+ DEFAULT_SYNTH_MODE,
7
+ MIDI_CHANNEL_COUNT,
8
+ VOICE_CAP
9
+ } from "./src/synthetizer/synth_constants.js";
10
+ import {
11
+ channelConfiguration,
12
+ NON_CC_INDEX_OFFSET
13
+ } from "./src/synthetizer/audio_engine/engine_components/controller_tables.js";
14
+ import { KeyModifier } from "./src/synthetizer/audio_engine/engine_components/key_modifier_manager.js";
15
+ import {
16
+ masterParameterType
17
+ } from "./src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js";
18
+ import { SynthesizerSnapshot } from "./src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js";
19
+ import { ChannelSnapshot } from "./src/synthetizer/audio_engine/snapshot/channel_snapshot.js";
5
20
 
6
21
  import { BasicSoundBank } from "./src/soundfont/basic_soundfont/basic_soundfont.js";
7
22
  import { BasicSample } from "./src/soundfont/basic_soundfont/basic_sample.js";
@@ -9,13 +24,15 @@ import { BasicInstrumentZone, BasicPresetZone } from "./src/soundfont/basic_soun
9
24
  import { BasicInstrument } from "./src/soundfont/basic_soundfont/basic_instrument.js";
10
25
  import { BasicPreset } from "./src/soundfont/basic_soundfont/basic_preset.js";
11
26
  import { Generator } from "./src/soundfont/basic_soundfont/generator.js";
12
- import { Modulator } from "./src/soundfont/basic_soundfont/modulator.js";
27
+ import { Modulator, modulatorSources } from "./src/soundfont/basic_soundfont/modulator.js";
13
28
  import { loadSoundFont } from "./src/soundfont/load_soundfont.js";
14
29
 
15
30
  import { MIDI } from "./src/midi/midi_loader.js";
16
31
  import { BasicMIDI } from "./src/midi/basic_midi.js";
32
+ import { MIDISequenceData } from "./src/midi/midi_sequence.js";
17
33
  import { MIDIBuilder } from "./src/midi/midi_builder.js";
18
34
  import { messageTypes, midiControllers, MIDIMessage } from "./src/midi/midi_message.js";
35
+ import { interpolationTypes, synthDisplayTypes } from "./src/synthetizer/audio_engine/engine_components/enums.js";
19
36
  import { RMIDINFOChunks } from "./src/midi/midi_tools/rmidi_writer.js";
20
37
  import { IndexedByteArray } from "./src/utils/indexed_array.js";
21
38
  import { audioToWav } from "./src/utils/buffer_to_wav.js";
@@ -26,7 +43,9 @@ import {
26
43
  SpessaSynthLogging,
27
44
  SpessaSynthWarn
28
45
  } from "./src/utils/loggin.js";
46
+ import { readBytesAsUintBigEndian } from "./src/utils/byte_functions/big_endian.js";
29
47
  import { consoleColors } from "./src/utils/other.js";
48
+ import { inflateSync } from "./src/externals/fflate/fflate.min.js";
30
49
 
31
50
  // you shouldn't use these...
32
51
  const SpessaSynthCoreUtils = {
@@ -34,17 +53,28 @@ const SpessaSynthCoreUtils = {
34
53
  SpessaSynthInfo,
35
54
  SpessaSynthWarn,
36
55
  SpessaSynthGroupCollapsed,
37
- SpessaSynthGroupEnd
56
+ SpessaSynthGroupEnd,
57
+ readBytesAsUintBigEndian,
58
+ inflateSync
38
59
  };
39
60
 
40
61
  export {
41
62
  // synth and seq
42
63
  SpessaSynthSequencer,
43
64
  SpessaSynthProcessor,
65
+ SynthesizerSnapshot,
66
+ ChannelSnapshot,
67
+ KeyModifier,
68
+ masterParameterType,
69
+ channelConfiguration,
70
+ interpolationTypes,
71
+ synthDisplayTypes,
44
72
  DEFAULT_PERCUSSION,
45
73
  VOICE_CAP,
46
74
  ALL_CHANNELS_OR_DIFFERENT_ACTION,
47
75
  NON_CC_INDEX_OFFSET,
76
+ DEFAULT_SYNTH_MODE,
77
+ MIDI_CHANNEL_COUNT,
48
78
 
49
79
  // sound banks
50
80
  loadSoundFont,
@@ -56,9 +86,11 @@ export {
56
86
  BasicPresetZone,
57
87
  Generator,
58
88
  Modulator,
89
+ modulatorSources,
59
90
 
60
91
  // MIDI
61
92
  MIDI,
93
+ MIDISequenceData,
62
94
  BasicMIDI,
63
95
  MIDIBuilder,
64
96
  MIDIMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_core",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "MIDI and SoundFont2/DLS library with no compromises",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,18 @@
1
+ /**
2
+ *
3
+ * @enum {number}
4
+ */
5
+ export const interpolationTypes = {
6
+ linear: 0,
7
+ nearestNeighbor: 1,
8
+ fourthOrder: 2
9
+ };
10
+ /**
11
+ * The text types for the synth display
12
+ * @enum {number}
13
+ */
14
+ export const synthDisplayTypes = {
15
+ SoundCanvasText: 0,
16
+ XGText: 1,
17
+ SoundCanvasDotDisplay: 2
18
+ };
@@ -3,16 +3,6 @@
3
3
  * purpose: plays back raw audio data at an arbitrary playback rate
4
4
  */
5
5
 
6
- /**
7
- *
8
- * @enum {number}
9
- */
10
- export const interpolationTypes = {
11
- linear: 0,
12
- nearestNeighbor: 1,
13
- fourthOrder: 2
14
- };
15
-
16
6
 
17
7
  export class WavetableOscillator
18
8
  {
@@ -4,8 +4,9 @@ import { generatorTypes } from "../../../soundfont/basic_soundfont/generator.js"
4
4
  import { customControllers } from "../engine_components/controller_tables.js";
5
5
  import { absCentsToHz, timecentsToSeconds } from "../engine_components/unit_converter.js";
6
6
  import { getLFOValue } from "../engine_components/lfo.js";
7
- import { interpolationTypes, WavetableOscillator } from "../engine_components/wavetable_oscillator.js";
7
+ import { WavetableOscillator } from "../engine_components/wavetable_oscillator.js";
8
8
  import { WorkletLowpassFilter } from "../engine_components/lowpass_filter.js";
9
+ import { interpolationTypes } from "../engine_components/enums.js";
9
10
 
10
11
  /**
11
12
  * Renders a voice to the stereo output buffer
@@ -5,6 +5,7 @@ import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from "../../synth_constants.js";
5
5
  import { isSystemXG } from "../../../utils/xg_hacks.js";
6
6
  import { masterParameterType } from "./controller_control/master_parameters.js";
7
7
  import { readBytesAsString } from "../../../utils/byte_functions/string.js";
8
+ import { synthDisplayTypes } from "../engine_components/enums.js";
8
9
 
9
10
  /**
10
11
  * KeyNum: tuning
@@ -39,16 +40,6 @@ function getTuning(byte1, byte2, byte3)
39
40
  return { midiNote: midiNote, centTuning: fraction * 0.0061 };
40
41
  }
41
42
 
42
- /**
43
- * The text types for the synth display
44
- * @enum {number}
45
- */
46
- export const SynthDisplayType = {
47
- SoundCanvasText: 0,
48
- XGText: 1,
49
- SoundCanvasDotDisplay: 2
50
- };
51
-
52
43
 
53
44
  /**
54
45
  * Executes a system exclusive
@@ -547,7 +538,7 @@ export function systemExclusive(messageData, channelOffset = 0)
547
538
  "synthdisplay",
548
539
  {
549
540
  displayData: text,
550
- displayType: SynthDisplayType.SoundCanvasText
541
+ displayType: synthDisplayTypes.SoundCanvasText
551
542
  }
552
543
  );
553
544
  }
@@ -560,7 +551,7 @@ export function systemExclusive(messageData, channelOffset = 0)
560
551
  "synthdisplay",
561
552
  {
562
553
  displayData: dotMatrixData,
563
- displayType: SynthDisplayType.SoundCanvasDotDisplay
554
+ displayType: synthDisplayTypes.SoundCanvasDotDisplay
564
555
  }
565
556
  );
566
557
  SpessaSynthInfo(
@@ -744,7 +735,7 @@ export function systemExclusive(messageData, channelOffset = 0)
744
735
  "synthdisplay",
745
736
  {
746
737
  displayData: textData,
747
- displayType: SynthDisplayType.XGText
738
+ displayType: synthDisplayTypes.XGText
748
739
  }
749
740
  );
750
741
  }
@@ -13,7 +13,6 @@ import { systemExclusive } from "./engine_methods/system_exclusive.js";
13
13
  import { masterParameterType, setMasterParameter } from "./engine_methods/controller_control/master_parameters.js";
14
14
  import { resetAllControllers } from "./engine_methods/controller_control/reset_controllers.js";
15
15
  import { WorkletSoundfontManager } from "./engine_components/soundfont_manager.js";
16
- import { interpolationTypes } from "./engine_components/wavetable_oscillator.js";
17
16
  import { KeyModifierManager } from "./engine_components/key_modifier_manager.js";
18
17
  import { getVoices } from "./engine_components/voice.js";
19
18
  import { PAN_SMOOTHING_FACTOR } from "./engine_components/stereo_panner.js";
@@ -30,6 +29,7 @@ import { createMidiChannel } from "./engine_methods/create_midi_channel.js";
30
29
  import { FILTER_SMOOTHING_FACTOR } from "./engine_components/lowpass_filter.js";
31
30
  import { getEvent, messageTypes } from "../../midi/midi_message.js";
32
31
  import { IndexedByteArray } from "../../utils/indexed_array.js";
32
+ import { interpolationTypes } from "./engine_components/enums.js";
33
33
 
34
34
 
35
35
  /**
@@ -95,7 +95,7 @@ import { IndexedByteArray } from "../../utils/indexed_array.js";
95
95
  /**
96
96
  * @typedef {Object} SynthDisplayCallback
97
97
  * @property {Uint8Array} displayData - The data to display.
98
- * @property {SynthDisplayType} displayType - The type of display.
98
+ * @property {synthDisplayTypes} displayType - The type of display.
99
99
  */
100
100
 
101
101
  /**