spessasynth_lib 3.20.0 → 3.20.2
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/{soundfont.d.ts → read_sf2/soundfont.d.ts} +4 -4
- package/README.md +1 -1
- package/external_midi/web_midi_link.js +2 -1
- package/index.js +2 -0
- package/package.json +5 -2
- package/soundfont/dls/dls_sample.js +8 -0
- package/soundfont/dls/dls_zone.js +4 -2
- package/soundfont/dls/read_articulation.js +43 -6
- package/soundfont/load_soundfont.js +1 -1
- package/soundfont/{soundfont.js → read_sf2/soundfont.js} +14 -14
- package/synthetizer/worklet_processor.min.js +7 -7
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 };
|
|
@@ -11,7 +11,7 @@ export class SoundFont2 extends BasicSoundFont {
|
|
|
11
11
|
constructor(arrayBuffer: ArrayBuffer, warnDeprecated?: boolean);
|
|
12
12
|
dataArray: IndexedByteArray;
|
|
13
13
|
sampleDataStartIndex: number;
|
|
14
|
-
instruments: import("./
|
|
14
|
+
instruments: import("./instruments.js").Instrument[];
|
|
15
15
|
/**
|
|
16
16
|
* @param chunk {RiffChunk}
|
|
17
17
|
* @param expected {string}
|
|
@@ -23,6 +23,6 @@ export class SoundFont2 extends BasicSoundFont {
|
|
|
23
23
|
*/
|
|
24
24
|
verifyText(text: string, expected: string): void;
|
|
25
25
|
}
|
|
26
|
-
import { BasicSoundFont } from '
|
|
27
|
-
import { IndexedByteArray } from '
|
|
28
|
-
import { RiffChunk } from '
|
|
26
|
+
import { BasicSoundFont } from '../basic_soundfont/basic_soundfont.js';
|
|
27
|
+
import { IndexedByteArray } from '../../utils/indexed_array.js';
|
|
28
|
+
import { RiffChunk } from '../basic_soundfont/riff_chunk.js';
|
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ 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)
|
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,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spessasynth_lib",
|
|
3
|
-
"version": "3.20.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.20.2",
|
|
4
|
+
"description": "MIDI and SoundFont2 or DLS Synthesizer library with no compromises",
|
|
5
5
|
"browser": "index.js",
|
|
6
6
|
"types": "@types/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"synth",
|
|
19
19
|
"sf2",
|
|
20
20
|
"sf3",
|
|
21
|
+
"dls",
|
|
22
|
+
"dls-to-sf2",
|
|
21
23
|
"midi",
|
|
24
|
+
"rmi",
|
|
22
25
|
"midi-player",
|
|
23
26
|
"web-audio-api",
|
|
24
27
|
"web-midi-api",
|
|
@@ -46,6 +46,14 @@ export class DLSSample extends BasicSample
|
|
|
46
46
|
|
|
47
47
|
getRawData()
|
|
48
48
|
{
|
|
49
|
+
if(this.isCompressed)
|
|
50
|
+
{
|
|
51
|
+
if (!this.compressedData)
|
|
52
|
+
{
|
|
53
|
+
throw new Error("Compressed but no data??")
|
|
54
|
+
}
|
|
55
|
+
return this.compressedData;
|
|
56
|
+
}
|
|
49
57
|
const uint8 = new Uint8Array(this.sampleData.length * 2);
|
|
50
58
|
for (let i = 0; i < this.sampleData.length; i++)
|
|
51
59
|
{
|
|
@@ -46,7 +46,8 @@ export class DLSZone extends BasicInstrumentZone
|
|
|
46
46
|
{
|
|
47
47
|
const fine = diffStart % 32768;
|
|
48
48
|
this.generators.push(new Generator(generatorTypes.startloopAddrsOffset, fine));
|
|
49
|
-
|
|
49
|
+
// coarse generator uses 32768 samples per step
|
|
50
|
+
const coarse = (diffStart - fine) / 32768;
|
|
50
51
|
if(coarse !== 0)
|
|
51
52
|
{
|
|
52
53
|
this.generators.push(new Generator(generatorTypes.startloopAddrsCoarseOffset, fine));
|
|
@@ -56,7 +57,8 @@ export class DLSZone extends BasicInstrumentZone
|
|
|
56
57
|
{
|
|
57
58
|
const fine = diffEnd % 32768;
|
|
58
59
|
this.generators.push(new Generator(generatorTypes.endloopAddrsOffset, fine));
|
|
59
|
-
|
|
60
|
+
// coarse generator uses 32768 samples per step
|
|
61
|
+
const coarse = (diffEnd - fine) / 32768;
|
|
60
62
|
if(coarse !== 0)
|
|
61
63
|
{
|
|
62
64
|
this.generators.push(new Generator(generatorTypes.endloopAddrsCoarseOffset, fine));
|
|
@@ -76,8 +76,14 @@ export function readArticulation(chunk, disableVibrato)
|
|
|
76
76
|
const control = readLittleEndian(artData, 2);
|
|
77
77
|
const destination = readLittleEndian(artData, 2);
|
|
78
78
|
const transform = readLittleEndian(artData, 2);
|
|
79
|
-
const
|
|
79
|
+
const scale = readLittleEndian(artData, 4) | 0;
|
|
80
|
+
const value = scale >> 16; // convert it to 16 bit as soundfont uses that
|
|
80
81
|
|
|
82
|
+
// if(destination === DLSDestinations.volEnvDecay)
|
|
83
|
+
// {
|
|
84
|
+
// console.log(scale, value)
|
|
85
|
+
// }
|
|
86
|
+
//modulatorConverterDebug(source, control, destination, value, transform);
|
|
81
87
|
// interpret this somehow...
|
|
82
88
|
// if source and control are both zero, it's a generator
|
|
83
89
|
if(source === 0 && control === 0 && transform === 0)
|
|
@@ -224,26 +230,57 @@ export function readArticulation(chunk, disableVibrato)
|
|
|
224
230
|
// key to vol env hold
|
|
225
231
|
if(source === DLSSources.keyNum && destination === DLSDestinations.volEnvHold)
|
|
226
232
|
{
|
|
227
|
-
// according to viena and another strange (with modulators) rendition of gm.dls in sf2,
|
|
228
|
-
|
|
233
|
+
// according to viena and another strange (with modulators) rendition of gm.dls in sf2,
|
|
234
|
+
// it shall be divided by -128
|
|
235
|
+
// and a strange correction needs to be applied to the real value:
|
|
236
|
+
// real + (60 / 128) * scale
|
|
237
|
+
generators.push(new Generator(generatorTypes.keyNumToVolEnvHold, value / -128));
|
|
238
|
+
const correction = Math.round((60 / 128) * value);
|
|
239
|
+
generators.forEach(g => {
|
|
240
|
+
if(g.generatorType === generatorTypes.holdVolEnv) g.generatorValue += correction;
|
|
241
|
+
});
|
|
229
242
|
}
|
|
230
243
|
else
|
|
231
244
|
// key to vol env decay
|
|
232
245
|
if(source === DLSSources.keyNum && destination === DLSDestinations.volEnvDecay)
|
|
233
246
|
{
|
|
234
|
-
|
|
247
|
+
// according to viena and another strange (with modulators) rendition of gm.dls in sf2,
|
|
248
|
+
// it shall be divided by -128
|
|
249
|
+
// and a strange correction needs to be applied to the real value:
|
|
250
|
+
// real + (60 / 128) * scale
|
|
251
|
+
generators.push(new Generator(generatorTypes.keyNumToVolEnvDecay, value / -128));
|
|
252
|
+
const correction = Math.round((60 / 128) * value);
|
|
253
|
+
generators.forEach(g => {
|
|
254
|
+
if(g.generatorType === generatorTypes.decayVolEnv) g.generatorValue += correction;
|
|
255
|
+
});
|
|
235
256
|
}
|
|
236
257
|
else
|
|
237
258
|
// key to mod env hold
|
|
238
259
|
if(source === DLSSources.keyNum && destination === DLSDestinations.modEnvHold)
|
|
239
260
|
{
|
|
240
|
-
|
|
261
|
+
// according to viena and another strange (with modulators) rendition of gm.dls in sf2,
|
|
262
|
+
// it shall be divided by -128
|
|
263
|
+
// and a strange correction needs to be applied to the real value:
|
|
264
|
+
// real + (60 / 128) * scale
|
|
265
|
+
generators.push(new Generator(generatorTypes.keyNumToModEnvHold, value / -128));
|
|
266
|
+
const correction = Math.round((60 / 128) * value);
|
|
267
|
+
generators.forEach(g => {
|
|
268
|
+
if(g.generatorType === generatorTypes.holdModEnv) g.generatorValue += correction;
|
|
269
|
+
});
|
|
241
270
|
}
|
|
242
271
|
else
|
|
243
272
|
// key to mod env decay
|
|
244
273
|
if(source === DLSSources.keyNum && destination === DLSDestinations.modEnvDecay)
|
|
245
274
|
{
|
|
246
|
-
|
|
275
|
+
// according to viena and another strange (with modulators) rendition of gm.dls in sf2,
|
|
276
|
+
// it shall be divided by -128
|
|
277
|
+
// and a strange correction needs to be applied to the real value:
|
|
278
|
+
// real + (60 / 128) * scale
|
|
279
|
+
generators.push(new Generator(generatorTypes.keyNumToModEnvDecay, value / -128));
|
|
280
|
+
const correction = Math.round((60 / 128) * value);
|
|
281
|
+
generators.forEach(g => {
|
|
282
|
+
if(g.generatorType === generatorTypes.decayModEnv) g.generatorValue += correction;
|
|
283
|
+
});
|
|
247
284
|
}
|
|
248
285
|
else
|
|
249
286
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IndexedByteArray } from '../utils/indexed_array.js'
|
|
2
2
|
import { readBytesAsString } from '../utils/byte_functions/string.js'
|
|
3
3
|
import { DLSSoundFont } from './dls/dls_soundfont.js'
|
|
4
|
-
import { SoundFont2 } from './soundfont.js'
|
|
4
|
+
import { SoundFont2 } from './read_sf2/soundfont.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Loads a soundfont file
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import {readSamples} from "./
|
|
3
|
-
import { readLittleEndian } from '
|
|
4
|
-
import { readGenerators, Generator } from './
|
|
5
|
-
import {readInstrumentZones, InstrumentZone, readPresetZones} from "./
|
|
6
|
-
import { readPresets } from "./
|
|
7
|
-
import {readInstruments} from "./
|
|
8
|
-
import {readModulators, Modulator} from "./
|
|
9
|
-
import { readRIFFChunk, RiffChunk } from '
|
|
10
|
-
import { consoleColors } from '
|
|
11
|
-
import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from '
|
|
12
|
-
import { readBytesAsString } from '
|
|
13
|
-
import { stbvorbis } from "
|
|
14
|
-
import { BasicSoundFont } from '
|
|
1
|
+
import { IndexedByteArray } from '../../utils/indexed_array.js'
|
|
2
|
+
import { readSamples } from "./samples.js";
|
|
3
|
+
import { readLittleEndian } from '../../utils/byte_functions/little_endian.js'
|
|
4
|
+
import { readGenerators, Generator } from './generators.js'
|
|
5
|
+
import { readInstrumentZones, InstrumentZone, readPresetZones } from "./zones.js";
|
|
6
|
+
import { readPresets } from "./presets.js";
|
|
7
|
+
import { readInstruments } from "./instruments.js";
|
|
8
|
+
import { readModulators, Modulator } from "./modulators.js";
|
|
9
|
+
import { readRIFFChunk, RiffChunk } from '../basic_soundfont/riff_chunk.js'
|
|
10
|
+
import { consoleColors } from '../../utils/other.js'
|
|
11
|
+
import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from '../../utils/loggin.js'
|
|
12
|
+
import { readBytesAsString } from '../../utils/byte_functions/string.js'
|
|
13
|
+
import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
|
|
14
|
+
import { BasicSoundFont } from '../basic_soundfont/basic_soundfont.js'
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* soundfont.js
|