spessasynth_lib 3.17.0 → 3.20.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/@types/index.d.ts +2 -1
- package/@types/soundfont/basic_soundfont/basic_sample.d.ts +2 -2
- package/@types/soundfont/basic_soundfont/basic_zone.d.ts +12 -12
- package/@types/soundfont/basic_soundfont/basic_zones.d.ts +4 -0
- package/@types/soundfont/basic_soundfont/riff_chunk.d.ts +6 -0
- package/@types/soundfont/dls/articulator_converter.d.ts +10 -0
- package/@types/soundfont/dls/dls_destinations.d.ts +29 -0
- package/@types/soundfont/dls/dls_preset.d.ts +7 -5
- package/@types/soundfont/dls/dls_sample.d.ts +18 -0
- package/@types/soundfont/dls/dls_soundfont.d.ts +9 -2
- package/@types/soundfont/dls/dls_sources.d.ts +22 -0
- package/@types/soundfont/dls/dls_zone.d.ts +22 -0
- package/@types/soundfont/dls/read_articulation.d.ts +12 -0
- package/@types/soundfont/dls/read_instrument_list.d.ts +2 -2
- package/@types/soundfont/dls/read_lart.d.ts +7 -0
- package/@types/soundfont/dls/read_region.d.ts +7 -0
- package/@types/soundfont/dls/read_samples.d.ts +5 -0
- package/@types/soundfont/read_sf2/generators.d.ts +18 -5
- package/@types/soundfont/read_sf2/modulators.d.ts +1 -0
- package/README.md +11 -1
- package/external_midi/web_midi_link.js +2 -1
- package/index.js +2 -0
- package/midi_parser/midi_loader.js +30 -3
- package/package.json +1 -1
- package/soundfont/README.md +6 -2
- package/soundfont/basic_soundfont/basic_sample.js +3 -3
- package/soundfont/basic_soundfont/basic_zone.js +28 -28
- package/soundfont/basic_soundfont/basic_zones.js +15 -19
- package/soundfont/basic_soundfont/riff_chunk.js +18 -2
- package/soundfont/dls/articulator_converter.js +311 -0
- package/soundfont/dls/dls_destinations.js +38 -0
- package/soundfont/dls/dls_preset.js +15 -8
- package/soundfont/dls/dls_sample.js +66 -0
- package/soundfont/dls/dls_soundfont.js +68 -11
- package/soundfont/dls/dls_sources.js +26 -0
- package/soundfont/dls/dls_zone.js +77 -0
- package/soundfont/dls/read_articulation.js +327 -0
- package/soundfont/dls/read_instrument.js +82 -4
- package/soundfont/dls/read_instrument_list.js +6 -6
- package/soundfont/dls/read_lart.js +35 -0
- package/soundfont/dls/read_region.js +129 -0
- package/soundfont/dls/read_samples.js +174 -0
- package/soundfont/read_sf2/generators.js +41 -6
- package/soundfont/read_sf2/modulators.js +3 -3
- package/synthetizer/worklet_processor.min.js +10 -8
- package/utils/buffer_to_wav.js +5 -26
package/@types/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Sequencer } from './sequencer/sequencer.js';
|
|
|
2
2
|
import { Synthetizer } from './synthetizer/synthetizer.js';
|
|
3
3
|
import { DEFAULT_PERCUSSION } from './synthetizer/synthetizer.js';
|
|
4
4
|
import { VOICE_CAP } from './synthetizer/synthetizer.js';
|
|
5
|
+
import { BasicSoundFont } from "./soundfont/basic_soundfont/basic_soundfont.js";
|
|
5
6
|
import { loadSoundFont } from "./soundfont/load_soundfont.js";
|
|
6
7
|
import { trimSoundfont } from "./soundfont/basic_soundfont/write_sf2/soundfont_trimmer.js";
|
|
7
8
|
import { modulatorSources } from "./soundfont/read_sf2/modulators.js";
|
|
@@ -33,4 +34,4 @@ import { readBytesAsUintBigEndian } from './utils/byte_functions/big_endian.js';
|
|
|
33
34
|
import { NON_CC_INDEX_OFFSET } from './synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js';
|
|
34
35
|
import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from './synthetizer/worklet_system/message_protocol/worklet_message.js';
|
|
35
36
|
import { WORKLET_URL_ABSOLUTE } from './synthetizer/worklet_url.js';
|
|
36
|
-
export { Sequencer, Synthetizer, DEFAULT_PERCUSSION, VOICE_CAP, loadSoundFont, trimSoundfont, modulatorSources, encodeVorbis, MIDI, MIDIBuilder, IndexedByteArray, writeMIDIFile, writeRMIDI, applySnapshotToMIDI, modifyMIDI, audioBufferToWav, SpessaSynthLogging, SpessaSynthGroup, SpessaSynthTable, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn, SpessaSynthGroupCollapsed, midiControllers, messageTypes, MIDIDeviceHandler, WebMidiLinkHandler, arrayToHexString, consoleColors, formatTitle, formatTime, readBytesAsUintBigEndian, NON_CC_INDEX_OFFSET, ALL_CHANNELS_OR_DIFFERENT_ACTION, WORKLET_URL_ABSOLUTE };
|
|
37
|
+
export { Sequencer, Synthetizer, DEFAULT_PERCUSSION, VOICE_CAP, BasicSoundFont, loadSoundFont, trimSoundfont, modulatorSources, encodeVorbis, MIDI, MIDIBuilder, IndexedByteArray, writeMIDIFile, writeRMIDI, applySnapshotToMIDI, modifyMIDI, audioBufferToWav, SpessaSynthLogging, SpessaSynthGroup, SpessaSynthTable, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn, SpessaSynthGroupCollapsed, midiControllers, messageTypes, MIDIDeviceHandler, WebMidiLinkHandler, arrayToHexString, consoleColors, formatTitle, formatTime, readBytesAsUintBigEndian, NON_CC_INDEX_OFFSET, ALL_CHANNELS_OR_DIFFERENT_ACTION, WORKLET_URL_ABSOLUTE };
|
|
@@ -42,12 +42,12 @@ export class BasicSample {
|
|
|
42
42
|
*/
|
|
43
43
|
sampleType: number;
|
|
44
44
|
/**
|
|
45
|
-
* Relative to start of the sample, bytes
|
|
45
|
+
* Relative to start of the sample, bytes assuming 16 bit
|
|
46
46
|
* @type {number}
|
|
47
47
|
*/
|
|
48
48
|
sampleLoopStartIndex: number;
|
|
49
49
|
/**
|
|
50
|
-
* Relative to start of the sample, in bytes
|
|
50
|
+
* Relative to start of the sample, in bytes assuming 16 bit
|
|
51
51
|
* @type {number}
|
|
52
52
|
*/
|
|
53
53
|
sampleLoopEndIndex: number;
|
|
@@ -5,30 +5,30 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export class BasicZone {
|
|
7
7
|
/**
|
|
8
|
-
* The zone's
|
|
9
|
-
* @type {
|
|
8
|
+
* The zone's velocity range
|
|
9
|
+
* @type {SoundFontRange}
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
velRange: SoundFontRange;
|
|
12
12
|
/**
|
|
13
|
-
* The zone's
|
|
14
|
-
* @type {
|
|
13
|
+
* The zone's key range
|
|
14
|
+
* @type {SoundFontRange}
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
keyRange: SoundFontRange;
|
|
17
17
|
/**
|
|
18
18
|
* Indicates if the zone is global
|
|
19
19
|
* @type {boolean}
|
|
20
20
|
*/
|
|
21
21
|
isGlobal: boolean;
|
|
22
22
|
/**
|
|
23
|
-
* The zone's
|
|
24
|
-
* @type {
|
|
23
|
+
* The zone's generators
|
|
24
|
+
* @type {Generator[]}
|
|
25
25
|
*/
|
|
26
|
-
|
|
26
|
+
generators: Generator[];
|
|
27
27
|
/**
|
|
28
|
-
* The zone's
|
|
29
|
-
* @type {
|
|
28
|
+
* The zone's modulators
|
|
29
|
+
* @type {Modulator[]}
|
|
30
30
|
*/
|
|
31
|
-
|
|
31
|
+
modulators: Modulator[];
|
|
32
32
|
}
|
|
33
33
|
export type SoundFontRange = {
|
|
34
34
|
/**
|
|
@@ -18,6 +18,12 @@ export function writeRIFFChunk(chunk: RiffChunk, prepend?: IndexedByteArray): In
|
|
|
18
18
|
* @returns {IndexedByteArray}
|
|
19
19
|
*/
|
|
20
20
|
export function writeRIFFOddSize(header: string, data: Uint8Array, addZeroByte?: boolean): IndexedByteArray;
|
|
21
|
+
/**
|
|
22
|
+
* @param collection {RiffChunk[]}
|
|
23
|
+
* @param type {string}
|
|
24
|
+
* @returns {RiffChunk|undefined}
|
|
25
|
+
*/
|
|
26
|
+
export function findRIFFListType(collection: RiffChunk[], type: string): RiffChunk | undefined;
|
|
21
27
|
/**
|
|
22
28
|
* riff_chunk.js
|
|
23
29
|
* reads a riff read and stores it as a class
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param source {number}
|
|
3
|
+
* @param control {number}
|
|
4
|
+
* @param destination {number}
|
|
5
|
+
* @param transform {number}
|
|
6
|
+
* @param value {number}
|
|
7
|
+
* @returns {Modulator|undefined}
|
|
8
|
+
*/
|
|
9
|
+
export function getSF2ModulatorFromArticulator(source: number, control: number, destination: number, transform: number, value: number): Modulator | undefined;
|
|
10
|
+
import { Modulator } from '../read_sf2/modulators.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type DLSDestinations = number;
|
|
2
|
+
export namespace DLSDestinations {
|
|
3
|
+
let none: number;
|
|
4
|
+
let gain: number;
|
|
5
|
+
let reserved: number;
|
|
6
|
+
let pitch: number;
|
|
7
|
+
let pan: number;
|
|
8
|
+
let keyNum: number;
|
|
9
|
+
let chorusSend: number;
|
|
10
|
+
let reverbSend: number;
|
|
11
|
+
let modLfoFreq: number;
|
|
12
|
+
let modLfoDelay: number;
|
|
13
|
+
let vibLfoFreq: number;
|
|
14
|
+
let vibLfoDelay: number;
|
|
15
|
+
let volEnvAttack: number;
|
|
16
|
+
let volEnvDecay: number;
|
|
17
|
+
let volEnvRelease: number;
|
|
18
|
+
let volEnvSustain: number;
|
|
19
|
+
let volEnvDelay: number;
|
|
20
|
+
let volEnvHold: number;
|
|
21
|
+
let modEnvAttack: number;
|
|
22
|
+
let modEnvDecay: number;
|
|
23
|
+
let modEnvRelease: number;
|
|
24
|
+
let modEnvSustain: number;
|
|
25
|
+
let modEnvDelay: number;
|
|
26
|
+
let modEnvHold: number;
|
|
27
|
+
let filterCutoff: number;
|
|
28
|
+
let filterQ: number;
|
|
29
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export class DLSPreset extends BasicPreset {
|
|
2
2
|
/**
|
|
3
3
|
* Creates a new DLS preset
|
|
4
|
-
* @param ulBank {number}
|
|
5
|
-
* @param ulInstrument {number}
|
|
6
|
-
* @param regionsAmount {number}
|
|
4
|
+
* @param ulBank {number}
|
|
5
|
+
* @param ulInstrument {number}
|
|
7
6
|
*/
|
|
8
|
-
constructor(ulBank: number, ulInstrument: number
|
|
9
|
-
|
|
7
|
+
constructor(ulBank: number, ulInstrument: number);
|
|
8
|
+
DLSInstrument: BasicInstrument;
|
|
9
|
+
presetZones: BasicPresetZone[];
|
|
10
10
|
}
|
|
11
11
|
import { BasicPreset } from '../basic_soundfont/basic_preset.js';
|
|
12
|
+
import { BasicInstrument } from '../basic_soundfont/basic_instrument.js';
|
|
13
|
+
import { BasicPresetZone } from '../basic_soundfont/basic_zones.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class DLSSample extends BasicSample {
|
|
2
|
+
/**
|
|
3
|
+
* @param name {string}
|
|
4
|
+
* @param rate {number}
|
|
5
|
+
* @param pitch {number}
|
|
6
|
+
* @param pitchCorrection {number}
|
|
7
|
+
* @param loopStart {number} sample data points
|
|
8
|
+
* @param loopEnd {number} sample data points
|
|
9
|
+
* @param data {Float32Array}
|
|
10
|
+
*/
|
|
11
|
+
constructor(name: string, rate: number, pitch: number, pitchCorrection: number, loopStart: number, loopEnd: number, data: Float32Array);
|
|
12
|
+
/**
|
|
13
|
+
* @type {Float32Array}
|
|
14
|
+
*/
|
|
15
|
+
sampleData: Float32Array;
|
|
16
|
+
getRawData(): Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
import { BasicSample } from '../basic_soundfont/basic_sample.js';
|
|
@@ -4,8 +4,8 @@ export class DLSSoundFont extends BasicSoundFont {
|
|
|
4
4
|
* @param buffer {ArrayBuffer}
|
|
5
5
|
*/
|
|
6
6
|
constructor(buffer: ArrayBuffer);
|
|
7
|
-
dataArray:
|
|
8
|
-
instrumentAmount:
|
|
7
|
+
dataArray: IndexedByteArray;
|
|
8
|
+
instrumentAmount: number;
|
|
9
9
|
/**
|
|
10
10
|
* @param chunk {RiffChunk}
|
|
11
11
|
* @param expected {string}
|
|
@@ -18,7 +18,14 @@ export class DLSSoundFont extends BasicSoundFont {
|
|
|
18
18
|
verifyText(text: string, expected: string): void;
|
|
19
19
|
readDLSInstrumentList: typeof readDLSInstrumentList;
|
|
20
20
|
readDLSInstrument: typeof readDLSInstrument;
|
|
21
|
+
readRegion: typeof readRegion;
|
|
22
|
+
readLart: typeof readLart;
|
|
23
|
+
readDLSSamples: typeof readDLSSamples;
|
|
21
24
|
}
|
|
22
25
|
import { BasicSoundFont } from '../basic_soundfont/basic_soundfont.js';
|
|
26
|
+
import { IndexedByteArray } from '../../utils/indexed_array.js';
|
|
23
27
|
import { readDLSInstrumentList } from './read_instrument_list.js';
|
|
24
28
|
import { readDLSInstrument } from './read_instrument.js';
|
|
29
|
+
import { readRegion } from './read_region.js';
|
|
30
|
+
import { readLart } from './read_lart.js';
|
|
31
|
+
import { readDLSSamples } from './read_samples.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type DLSSources = number;
|
|
2
|
+
export namespace DLSSources {
|
|
3
|
+
let none: number;
|
|
4
|
+
let modLfo: number;
|
|
5
|
+
let velocity: number;
|
|
6
|
+
let keyNum: number;
|
|
7
|
+
let volEnv: number;
|
|
8
|
+
let modEnv: number;
|
|
9
|
+
let pitchWheel: number;
|
|
10
|
+
let polyPressure: number;
|
|
11
|
+
let channelPressure: number;
|
|
12
|
+
let vibratoLfo: number;
|
|
13
|
+
let modulationWheel: number;
|
|
14
|
+
let volume: number;
|
|
15
|
+
let pan: number;
|
|
16
|
+
let expression: number;
|
|
17
|
+
let chorus: number;
|
|
18
|
+
let reverb: number;
|
|
19
|
+
let pitchWheelRange: number;
|
|
20
|
+
let fineTune: number;
|
|
21
|
+
let coarseTune: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class DLSZone extends BasicInstrumentZone {
|
|
2
|
+
/**
|
|
3
|
+
* @param keyRange {SoundFontRange}
|
|
4
|
+
* @param velRange {SoundFontRange}
|
|
5
|
+
*/
|
|
6
|
+
constructor(keyRange: SoundFontRange, velRange: SoundFontRange);
|
|
7
|
+
keyRange: SoundFontRange;
|
|
8
|
+
velRange: SoundFontRange;
|
|
9
|
+
/**
|
|
10
|
+
* @param attenuationCb {number} with EMU correction
|
|
11
|
+
* @param loopingMode {number} the sfont one
|
|
12
|
+
* @param loop {{start: number, end: number}}
|
|
13
|
+
* @param sampleKey {number}
|
|
14
|
+
* @param sample {BasicSample}
|
|
15
|
+
* @param sampleID {number}
|
|
16
|
+
*/
|
|
17
|
+
setWavesample(attenuationCb: number, loopingMode: number, loop: {
|
|
18
|
+
start: number;
|
|
19
|
+
end: number;
|
|
20
|
+
}, sampleKey: number, sample: BasicSample, sampleID: number): void;
|
|
21
|
+
}
|
|
22
|
+
import { BasicInstrumentZone } from '../basic_soundfont/basic_zones.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the articulator chunk
|
|
3
|
+
* @param chunk {RiffChunk}
|
|
4
|
+
* @param disableVibrato {boolean} it seems that dls 1 does not have vibrato lfo, so we shall disable it
|
|
5
|
+
* @returns {{modulators: Modulator[], generators: Generator[]}}
|
|
6
|
+
*/
|
|
7
|
+
export function readArticulation(chunk: RiffChunk, disableVibrato: boolean): {
|
|
8
|
+
modulators: Modulator[];
|
|
9
|
+
generators: Generator[];
|
|
10
|
+
};
|
|
11
|
+
import { Modulator } from '../read_sf2/modulators.js';
|
|
12
|
+
import { Generator } from '../read_sf2/generators.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @this {DLSSoundFont}
|
|
3
|
-
* @param
|
|
3
|
+
* @param instrumentListChunk {RiffChunk}
|
|
4
4
|
*/
|
|
5
|
-
export function readDLSInstrumentList(this: DLSSoundFont,
|
|
5
|
+
export function readDLSInstrumentList(this: DLSSoundFont, instrumentListChunk: RiffChunk): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param lartChunk {RiffChunk|undefined}
|
|
3
|
+
* @param lar2Chunk {RiffChunk|undefined}
|
|
4
|
+
* @param zone {BasicInstrumentZone}
|
|
5
|
+
* @this {DLSSoundFont}
|
|
6
|
+
*/
|
|
7
|
+
export function readLart(this: DLSSoundFont, lartChunk: RiffChunk | undefined, lar2Chunk: RiffChunk | undefined, zone: BasicInstrumentZone): void;
|
|
@@ -84,16 +84,29 @@ export const generatorLimits: {
|
|
|
84
84
|
def: number;
|
|
85
85
|
}[];
|
|
86
86
|
export class Generator {
|
|
87
|
+
/**
|
|
88
|
+
* Constructs a new generator
|
|
89
|
+
* @param type {generatorTypes|number}
|
|
90
|
+
* @param value {number}
|
|
91
|
+
*/
|
|
92
|
+
constructor(type?: generatorTypes | number, value?: number);
|
|
93
|
+
/**
|
|
94
|
+
* The generator's enum number
|
|
95
|
+
* @type {generatorTypes|number}
|
|
96
|
+
*/
|
|
97
|
+
generatorType: generatorTypes | number;
|
|
98
|
+
/**
|
|
99
|
+
* The generator's 16-bit value
|
|
100
|
+
* @type {number}
|
|
101
|
+
*/
|
|
102
|
+
generatorValue: number;
|
|
103
|
+
}
|
|
104
|
+
export class ReadGenerator extends Generator {
|
|
87
105
|
/**
|
|
88
106
|
* Creates a generator
|
|
89
107
|
* @param dataArray {IndexedByteArray}
|
|
90
108
|
*/
|
|
91
109
|
constructor(dataArray: IndexedByteArray);
|
|
92
|
-
/**
|
|
93
|
-
* @type {generatorTypes}
|
|
94
|
-
**/
|
|
95
|
-
generatorType: generatorTypes;
|
|
96
|
-
generatorValue: number;
|
|
97
110
|
}
|
|
98
111
|
import { RiffChunk } from '../basic_soundfont/riff_chunk.js';
|
|
99
112
|
import { IndexedByteArray } from '../../utils/indexed_array.js';
|
package/README.md
CHANGED
|
@@ -76,12 +76,13 @@ document.getElementById("button").onclick = async () => {
|
|
|
76
76
|
- **Easy MIDI editing:** Use [helper functions](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#modifymidi) to modify the song to your needs!
|
|
77
77
|
- **Loop detection:** Automatically detects loops in MIDIs (e.g., from _Touhou Project_)
|
|
78
78
|
- **First note detection:** Skip unnecessary silence at the start by jumping to the first note!
|
|
79
|
-
- **[Write MIDI files from scratch](https://github.com/spessasus/SpessaSynth/wiki/Creating-MIDI-Files
|
|
79
|
+
- **[Write MIDI files from scratch](https://github.com/spessasus/SpessaSynth/wiki/Creating-MIDI-Files)**
|
|
80
80
|
- **Easy saving:** Save with just [one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writemidifile)
|
|
81
81
|
|
|
82
82
|
#### Read and write [RMID files with embedded SF2 soundfonts](https://github.com/spessasus/sf2-rmidi-specification#readme)
|
|
83
83
|
- **[Level 4](https://github.com/spessasus/sf2-rmidi-specification#level-4) compliance:** Reads and writes *everything!*
|
|
84
84
|
- **Compression and trimming support:** Reduce a MIDI file with a 1GB soundfont to **as small as 5MB**!
|
|
85
|
+
- **DLS Version support:** The original legacy format with bank offset detection!
|
|
85
86
|
- **Automatic bank shifting and validation:** Every soundfont *just works!*
|
|
86
87
|
- **Metadata support:** Add title, artist, album name and cover and more! And of course read them too! *(In any encoding!)*
|
|
87
88
|
- **Compatible with [Falcosoft Midi Player 6!](https://falcosoft.hu/softwares.html#midiplayer)**
|
|
@@ -98,5 +99,14 @@ document.getElementById("button").onclick = async () => {
|
|
|
98
99
|
- **Variable compression quality:** You choose between file size and quality!
|
|
99
100
|
- **Compression preserving:** Avoid decompressing and recompressing uncompressed samples for minimal quality loss!
|
|
100
101
|
|
|
102
|
+
#### Read and play DLS Level 1 or 2 files
|
|
103
|
+
- Read DLS (DownLoadable Sounds) files as SF2 files!
|
|
104
|
+
- **Works like a normal soundfont:** *Saving is still [just one function!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#write)*
|
|
105
|
+
- Converts articulators to both **modulators** and **generators**!
|
|
106
|
+
- Works with both unsigned 8-bit samples and signed 16-bit samples!
|
|
107
|
+
- **Covers special generator cases:** *such as modLfoToPitch*!
|
|
108
|
+
- **Correct volume:** *looking at you, Viena and gm.sf2!*
|
|
109
|
+
- Support built right into the synthesizer!
|
|
110
|
+
|
|
101
111
|
## License
|
|
102
112
|
MIT License, except for the stbvorbis_sync.js in the `externals` folder which is licensed under the Apache-2.0 license.
|
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Import modules
|
|
2
2
|
import { loadSoundFont } from "./soundfont/load_soundfont.js";
|
|
3
|
+
import { BasicSoundFont } from "./soundfont/basic_soundfont/basic_soundfont.js";
|
|
3
4
|
import { MIDI } from './midi_parser/midi_loader.js';
|
|
4
5
|
import { MIDIBuilder } from "./midi_parser/midi_builder.js";
|
|
5
6
|
import { Synthetizer, VOICE_CAP, DEFAULT_PERCUSSION } from './synthetizer/synthetizer.js';
|
|
@@ -39,6 +40,7 @@ export {
|
|
|
39
40
|
VOICE_CAP,
|
|
40
41
|
|
|
41
42
|
// SoundFont
|
|
43
|
+
BasicSoundFont,
|
|
42
44
|
loadSoundFont,
|
|
43
45
|
trimSoundfont,
|
|
44
46
|
modulatorSources,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dataBytesAmount, getChannel, messageTypes, MidiMessage } from './midi_message.js'
|
|
2
2
|
import { IndexedByteArray } from '../utils/indexed_array.js'
|
|
3
3
|
import { arrayToHexString, consoleColors, formatTitle } from '../utils/other.js'
|
|
4
|
-
import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo } from '../utils/loggin.js'
|
|
4
|
+
import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn } from '../utils/loggin.js'
|
|
5
5
|
import { readRIFFChunk } from '../soundfont/basic_soundfont/riff_chunk.js'
|
|
6
6
|
import { readVariableLengthQuantity } from '../utils/byte_functions/variable_length_quantity.js'
|
|
7
7
|
import { readBytesAsUintBigEndian } from '../utils/byte_functions/big_endian.js'
|
|
@@ -33,6 +33,8 @@ class MIDI extends BasicMIDI
|
|
|
33
33
|
|
|
34
34
|
let nameDetected = false;
|
|
35
35
|
|
|
36
|
+
let DLSRMID = false;
|
|
37
|
+
|
|
36
38
|
const initialString = readBytesAsString(binaryData, 4);
|
|
37
39
|
binaryData.currentIndex -= 4;
|
|
38
40
|
if(initialString === "RIFF")
|
|
@@ -62,12 +64,21 @@ class MIDI extends BasicMIDI
|
|
|
62
64
|
const currentChunk = readRIFFChunk(binaryData, true);
|
|
63
65
|
if(currentChunk.header === "RIFF")
|
|
64
66
|
{
|
|
65
|
-
const type = readBytesAsString(currentChunk.chunkData, 4);
|
|
66
|
-
if(type === "sfbk" || type === "sfpk")
|
|
67
|
+
const type = readBytesAsString(currentChunk.chunkData, 4).toLowerCase();
|
|
68
|
+
if(type === "sfbk" || type === "sfpk" || type === "dls ")
|
|
67
69
|
{
|
|
68
70
|
SpessaSynthInfo("%cFound embedded soundfont!", consoleColors.recognized);
|
|
69
71
|
this.embeddedSoundFont = binaryData.slice(startIndex, startIndex + currentChunk.size).buffer;
|
|
70
72
|
}
|
|
73
|
+
else
|
|
74
|
+
{
|
|
75
|
+
SpessaSynthWarn(`Unknown RIFF chunk: "${type}"`);
|
|
76
|
+
}
|
|
77
|
+
if(type === "dls ")
|
|
78
|
+
{
|
|
79
|
+
// assume bank offset of 0 by default. If we find any bank selects, then the offset is 1.
|
|
80
|
+
DLSRMID = true;
|
|
81
|
+
}
|
|
71
82
|
}
|
|
72
83
|
else if(currentChunk.header === "LIST")
|
|
73
84
|
{
|
|
@@ -109,6 +120,13 @@ class MIDI extends BasicMIDI
|
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
}
|
|
123
|
+
|
|
124
|
+
if(DLSRMID)
|
|
125
|
+
{
|
|
126
|
+
console.log(DLSRMID)
|
|
127
|
+
// assume bank offset of 0 by default. If we find any bank selects, then the offset is 1.
|
|
128
|
+
this.bankOffset = 0;
|
|
129
|
+
}
|
|
112
130
|
}
|
|
113
131
|
else
|
|
114
132
|
{
|
|
@@ -388,6 +406,15 @@ class MIDI extends BasicMIDI
|
|
|
388
406
|
loopEnd = 0;
|
|
389
407
|
}
|
|
390
408
|
break;
|
|
409
|
+
|
|
410
|
+
case 0:
|
|
411
|
+
// check RMID
|
|
412
|
+
if(DLSRMID && eventData[1] !== 0 && eventData[1] !== 127)
|
|
413
|
+
{
|
|
414
|
+
SpessaSynthInfo("%cDLS RMIDI with offset 1 detected!",
|
|
415
|
+
consoleColors.recognized);
|
|
416
|
+
this.bankOffset = 1;
|
|
417
|
+
}
|
|
391
418
|
}
|
|
392
419
|
}
|
|
393
420
|
}
|
package/package.json
CHANGED
package/soundfont/README.md
CHANGED
|
@@ -3,6 +3,10 @@ The code here is responsible for parsing the SoundFont2 file and
|
|
|
3
3
|
providing an easy way to get the data out.
|
|
4
4
|
Default modulators are also stored here (in `modulators.js`)
|
|
5
5
|
|
|
6
|
-
`
|
|
6
|
+
`basic_soundfont` folder contains the classes that represent the soundfont file.
|
|
7
7
|
|
|
8
|
-
`
|
|
8
|
+
`read_sf2` folder contains the code for reading an `.sf2` file.
|
|
9
|
+
|
|
10
|
+
`write` folder contains the code for writing out an `.sf2` file.
|
|
11
|
+
|
|
12
|
+
`dls` folder contains the code for reading a `.dls` file (and converting in into a soundfont representation).
|
|
@@ -58,15 +58,15 @@ export class BasicSample {
|
|
|
58
58
|
*/
|
|
59
59
|
this.sampleType = sampleType
|
|
60
60
|
/**
|
|
61
|
-
* Relative to start of the sample, bytes
|
|
61
|
+
* Relative to start of the sample, bytes assuming 16 bit
|
|
62
62
|
* @type {number}
|
|
63
63
|
*/
|
|
64
64
|
this.sampleLoopStartIndex = loopStart
|
|
65
65
|
/**
|
|
66
|
-
* Relative to start of the sample, in bytes
|
|
66
|
+
* Relative to start of the sample, in bytes assuming 16 bit
|
|
67
67
|
* @type {number}
|
|
68
68
|
*/
|
|
69
|
-
this.sampleLoopEndIndex = loopEnd
|
|
69
|
+
this.sampleLoopEndIndex = loopEnd;
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Indicates if the sample is compressed
|
|
@@ -6,34 +6,34 @@
|
|
|
6
6
|
|
|
7
7
|
export class BasicZone
|
|
8
8
|
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
15
|
-
this.generators = [];
|
|
16
|
-
/**
|
|
17
|
-
* The zone's modulators
|
|
18
|
-
* @type {Modulator[]}
|
|
19
|
-
*/
|
|
20
|
-
this.modulators = [];
|
|
21
|
-
/**
|
|
22
|
-
* Indicates if the zone is global
|
|
23
|
-
* @type {boolean}
|
|
24
|
-
*/
|
|
25
|
-
this.isGlobal = false;
|
|
26
|
-
/**
|
|
27
|
-
* The zone's key range
|
|
28
|
-
* @type {SoundFontRange}
|
|
29
|
-
*/
|
|
30
|
-
this.keyRange = { min: 0, max: 127 };
|
|
9
|
+
/**
|
|
10
|
+
* The zone's velocity range
|
|
11
|
+
* @type {SoundFontRange}
|
|
12
|
+
*/
|
|
13
|
+
velRange = { min: 0, max: 127 };
|
|
31
14
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The zone's key range
|
|
17
|
+
* @type {SoundFontRange}
|
|
18
|
+
*/
|
|
19
|
+
keyRange = { min: 0, max: 127 };
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Indicates if the zone is global
|
|
23
|
+
* @type {boolean}
|
|
24
|
+
*/
|
|
25
|
+
isGlobal = false;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The zone's generators
|
|
29
|
+
* @type {Generator[]}
|
|
30
|
+
*/
|
|
31
|
+
generators = [];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The zone's modulators
|
|
35
|
+
* @type {Modulator[]}
|
|
36
|
+
*/
|
|
37
|
+
modulators = [];
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -2,16 +2,16 @@ import { BasicZone } from './basic_zone.js'
|
|
|
2
2
|
|
|
3
3
|
export class BasicInstrumentZone extends BasicZone
|
|
4
4
|
{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Zone's sample. Undefined if global
|
|
7
|
+
* @type {BasicSample|undefined}
|
|
8
|
+
*/
|
|
9
|
+
sample = undefined;
|
|
10
|
+
/**
|
|
11
|
+
* The zone's use count
|
|
12
|
+
* @type {number}
|
|
13
|
+
*/
|
|
14
|
+
useCount = 0;
|
|
15
15
|
|
|
16
16
|
deleteZone()
|
|
17
17
|
{
|
|
@@ -26,15 +26,11 @@ export class BasicInstrumentZone extends BasicZone
|
|
|
26
26
|
|
|
27
27
|
export class BasicPresetZone extends BasicZone
|
|
28
28
|
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* @type {BasicInstrument|undefined}
|
|
35
|
-
*/
|
|
36
|
-
this.instrument = undefined
|
|
37
|
-
}
|
|
29
|
+
/**
|
|
30
|
+
* Zone's instrument. Undefined if global
|
|
31
|
+
* @type {BasicInstrument|undefined}
|
|
32
|
+
*/
|
|
33
|
+
instrument = undefined
|
|
38
34
|
|
|
39
35
|
deleteZone()
|
|
40
36
|
{
|