spessasynth_core 3.26.17 → 3.26.19
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/index.js +5 -3
- package/package.json +1 -1
- package/src/externals/README.md +6 -0
- package/src/sequencer/README.md +5 -1
- package/src/soundfont/README.md +6 -8
- package/src/soundfont/basic_soundfont/basic_global_zone.js +16 -0
- package/src/soundfont/basic_soundfont/basic_instrument.js +26 -22
- package/src/soundfont/basic_soundfont/basic_instrument_zone.js +35 -0
- package/src/soundfont/basic_soundfont/basic_preset.js +53 -42
- package/src/soundfont/basic_soundfont/basic_preset_zone.js +30 -0
- package/src/soundfont/basic_soundfont/{basic_soundfont.js → basic_soundbank.js} +96 -55
- package/src/soundfont/basic_soundfont/basic_zone.js +73 -5
- package/src/soundfont/basic_soundfont/generator.js +4 -163
- package/src/soundfont/basic_soundfont/generator_types.js +151 -0
- package/src/soundfont/basic_soundfont/modulator.js +217 -65
- package/src/soundfont/basic_soundfont/write_dls/art2.js +3 -2
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +28 -45
- package/src/soundfont/basic_soundfont/write_dls/ins.js +11 -27
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +2 -2
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +2 -2
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +22 -19
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +33 -29
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +26 -16
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +4 -5
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +21 -18
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +32 -29
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +4 -2
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +26 -16
- package/src/soundfont/basic_soundfont/write_sf2/write.js +14 -8
- package/src/soundfont/dls/articulator_converter.js +9 -3
- package/src/soundfont/dls/dls_preset.js +2 -3
- package/src/soundfont/dls/dls_soundfont.js +2 -3
- package/src/soundfont/dls/dls_sources.js +7 -6
- package/src/soundfont/dls/dls_zone.js +13 -16
- package/src/soundfont/dls/read_articulation.js +2 -1
- package/src/soundfont/dls/read_instrument.js +7 -10
- package/src/soundfont/dls/read_lart.js +5 -5
- package/src/soundfont/dls/read_region.js +3 -3
- package/src/soundfont/read_sf2/instruments.js +10 -1
- package/src/soundfont/read_sf2/modulators.js +10 -23
- package/src/soundfont/read_sf2/presets.js +10 -1
- package/src/soundfont/read_sf2/soundfont.js +3 -5
- package/src/soundfont/read_sf2/zones.js +30 -70
- package/src/synthetizer/README.md +3 -3
- package/src/synthetizer/audio_engine/README.md +1 -1
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +20 -19
- package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +11 -3
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/voice.js +7 -10
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +2 -1
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -4
- package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +7 -0
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +2 -1
- package/src/utils/README.md +5 -2
- package/src/soundfont/basic_soundfont/basic_zones.js +0 -43
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BasicSoundBank } from "../basic_soundfont/
|
|
1
|
+
import { BasicSoundBank } from "../basic_soundfont/basic_soundbank.js";
|
|
2
2
|
import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
3
3
|
import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../utils/loggin.js";
|
|
4
4
|
import { consoleColors } from "../../utils/other.js";
|
|
@@ -114,8 +114,7 @@ class DLSSoundFont extends BasicSoundBank
|
|
|
114
114
|
this.readDLSInstrumentList(instrumentListChunk);
|
|
115
115
|
|
|
116
116
|
// sort presets
|
|
117
|
-
this.
|
|
118
|
-
this._parseInternal();
|
|
117
|
+
this.flush();
|
|
119
118
|
SpessaSynthInfo(
|
|
120
119
|
`%cParsing finished! %c"${this.soundFontInfo["INAM"] || "UNNAMED"}"%c has %c${this.presets.length} %cpresets,
|
|
121
120
|
%c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { DecodedModulator } from "../basic_soundfont/modulator.js";
|
|
2
|
+
|
|
3
|
+
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @enum {number}
|
|
@@ -29,7 +30,7 @@ export const DLSSources = {
|
|
|
29
30
|
coarseTune: 0x102
|
|
30
31
|
};
|
|
31
32
|
|
|
32
|
-
export const DEFAULT_DLS_REVERB = new
|
|
33
|
+
export const DEFAULT_DLS_REVERB = new DecodedModulator(
|
|
33
34
|
0x00DB,
|
|
34
35
|
0x0,
|
|
35
36
|
generatorTypes.reverbEffectsSend,
|
|
@@ -37,7 +38,7 @@ export const DEFAULT_DLS_REVERB = new Modulator(
|
|
|
37
38
|
0
|
|
38
39
|
);
|
|
39
40
|
|
|
40
|
-
export const DEFAULT_DLS_CHORUS = new
|
|
41
|
+
export const DEFAULT_DLS_CHORUS = new DecodedModulator(
|
|
41
42
|
0x00DD,
|
|
42
43
|
0x0,
|
|
43
44
|
generatorTypes.chorusEffectsSend,
|
|
@@ -45,7 +46,7 @@ export const DEFAULT_DLS_CHORUS = new Modulator(
|
|
|
45
46
|
0
|
|
46
47
|
);
|
|
47
48
|
|
|
48
|
-
export const DLS_1_NO_VIBRATO_MOD = new
|
|
49
|
+
export const DLS_1_NO_VIBRATO_MOD = new DecodedModulator(
|
|
49
50
|
0x0081,
|
|
50
51
|
0x0,
|
|
51
52
|
generatorTypes.vibLfoToPitch,
|
|
@@ -53,7 +54,7 @@ export const DLS_1_NO_VIBRATO_MOD = new Modulator(
|
|
|
53
54
|
0
|
|
54
55
|
);
|
|
55
56
|
|
|
56
|
-
export const DLS_1_NO_VIBRATO_PRESSURE = new
|
|
57
|
+
export const DLS_1_NO_VIBRATO_PRESSURE = new DecodedModulator(
|
|
57
58
|
0x000D,
|
|
58
59
|
0x0,
|
|
59
60
|
generatorTypes.vibLfoToPitch,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Generator } from "../basic_soundfont/generator.js";
|
|
2
|
+
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
3
|
+
import { BasicInstrumentZone } from "../basic_soundfont/basic_instrument_zone.js";
|
|
3
4
|
|
|
4
5
|
export class DLSZone extends BasicInstrumentZone
|
|
5
6
|
{
|
|
@@ -12,7 +13,6 @@ export class DLSZone extends BasicInstrumentZone
|
|
|
12
13
|
super();
|
|
13
14
|
this.keyRange = keyRange;
|
|
14
15
|
this.velRange = velRange;
|
|
15
|
-
this.isGlobal = true;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -36,22 +36,21 @@ export class DLSZone extends BasicInstrumentZone
|
|
|
36
36
|
{
|
|
37
37
|
if (loopingMode !== 0)
|
|
38
38
|
{
|
|
39
|
-
this.
|
|
39
|
+
this.addGenerators(new Generator(generatorTypes.sampleModes, loopingMode));
|
|
40
40
|
}
|
|
41
|
-
this.
|
|
42
|
-
this.isGlobal = false;
|
|
41
|
+
this.addGenerators(new Generator(generatorTypes.initialAttenuation, attenuationCb));
|
|
43
42
|
|
|
44
43
|
// correct tuning if needed
|
|
45
44
|
samplePitchCorrection -= sample.samplePitchCorrection;
|
|
46
45
|
const coarseTune = Math.trunc(samplePitchCorrection / 100);
|
|
47
46
|
if (coarseTune !== 0)
|
|
48
47
|
{
|
|
49
|
-
this.
|
|
48
|
+
this.addGenerators(new Generator(generatorTypes.coarseTune, coarseTune));
|
|
50
49
|
}
|
|
51
50
|
const fineTune = samplePitchCorrection - (coarseTune * 100);
|
|
52
51
|
if (fineTune !== 0)
|
|
53
52
|
{
|
|
54
|
-
this.
|
|
53
|
+
this.addGenerators(new Generator(generatorTypes.fineTune, fineTune));
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
// correct loop if needed
|
|
@@ -62,34 +61,32 @@ export class DLSZone extends BasicInstrumentZone
|
|
|
62
61
|
if (diffStart !== 0)
|
|
63
62
|
{
|
|
64
63
|
const fine = diffStart % 32768;
|
|
65
|
-
this.
|
|
64
|
+
this.addGenerators(new Generator(generatorTypes.startloopAddrsOffset, fine));
|
|
66
65
|
// coarse generator uses 32768 samples per step
|
|
67
66
|
const coarse = Math.trunc(diffStart / 32768);
|
|
68
67
|
if (coarse !== 0)
|
|
69
68
|
{
|
|
70
|
-
this.
|
|
69
|
+
this.addGenerators(new Generator(generatorTypes.startloopAddrsCoarseOffset, coarse));
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
if (diffEnd !== 0)
|
|
74
73
|
{
|
|
75
74
|
const fine = diffEnd % 32768;
|
|
76
|
-
this.
|
|
75
|
+
this.addGenerators(new Generator(generatorTypes.endloopAddrsOffset, fine));
|
|
77
76
|
// coarse generator uses 32768 samples per step
|
|
78
77
|
const coarse = Math.trunc(diffEnd / 32768);
|
|
79
78
|
if (coarse !== 0)
|
|
80
79
|
{
|
|
81
|
-
this.
|
|
80
|
+
this.addGenerators(new Generator(generatorTypes.endloopAddrsCoarseOffset, coarse));
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
// correct the key if needed
|
|
86
85
|
if (sampleKey !== sample.samplePitch)
|
|
87
86
|
{
|
|
88
|
-
this.
|
|
87
|
+
this.addGenerators(new Generator(generatorTypes.overridingRootKey, sampleKey));
|
|
89
88
|
}
|
|
90
89
|
// add sample ID
|
|
91
|
-
this.
|
|
92
|
-
this.sample = sample;
|
|
93
|
-
sample.useCount++;
|
|
90
|
+
this.setSample(sample);
|
|
94
91
|
}
|
|
95
92
|
}
|
|
@@ -4,8 +4,9 @@ import { DLS_1_NO_VIBRATO_MOD, DLS_1_NO_VIBRATO_PRESSURE, DLSSources } from "./d
|
|
|
4
4
|
import { getSF2ModulatorFromArticulator } from "./articulator_converter.js";
|
|
5
5
|
import { SpessaSynthInfo, SpessaSynthWarn } from "../../utils/loggin.js";
|
|
6
6
|
import { consoleColors } from "../../utils/other.js";
|
|
7
|
-
import { Generator
|
|
7
|
+
import { Generator } from "../basic_soundfont/generator.js";
|
|
8
8
|
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
9
|
+
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -3,11 +3,10 @@ import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
|
3
3
|
import { DLSPreset } from "./dls_preset.js";
|
|
4
4
|
import { findRIFFListType, readRIFFChunk } from "../basic_soundfont/riff_chunk.js";
|
|
5
5
|
import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd } from "../../utils/loggin.js";
|
|
6
|
-
import { BasicInstrumentZone } from "../basic_soundfont/basic_zones.js";
|
|
7
6
|
import { consoleColors } from "../../utils/other.js";
|
|
8
|
-
import { generatorLimits, generatorTypes } from "../basic_soundfont/generator.js";
|
|
9
7
|
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
10
8
|
import { DEFAULT_DLS_CHORUS, DEFAULT_DLS_REVERB } from "./dls_sources.js";
|
|
9
|
+
import { generatorLimits, generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* @this {DLSSoundFont}
|
|
@@ -70,8 +69,7 @@ export function readDLSInstrument(chunk)
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
// global articulation: essentially global zone
|
|
73
|
-
const globalZone =
|
|
74
|
-
globalZone.isGlobal = true;
|
|
72
|
+
const globalZone = preset.DLSInstrument.globalZone;
|
|
75
73
|
|
|
76
74
|
// read articulators
|
|
77
75
|
const globalLart = findRIFFListType(chunks, "lart");
|
|
@@ -86,14 +84,13 @@ export function readDLSInstrument(chunk)
|
|
|
86
84
|
// reverb
|
|
87
85
|
if (globalZone.modulators.find(m => m.modulatorDestination === generatorTypes.reverbEffectsSend) === undefined)
|
|
88
86
|
{
|
|
89
|
-
globalZone.
|
|
87
|
+
globalZone.addModulators(Modulator.copy(DEFAULT_DLS_REVERB));
|
|
90
88
|
}
|
|
91
89
|
// chorus
|
|
92
90
|
if (globalZone.modulators.find(m => m.modulatorDestination === generatorTypes.chorusEffectsSend) === undefined)
|
|
93
91
|
{
|
|
94
|
-
globalZone.
|
|
92
|
+
globalZone.addModulators(Modulator.copy(DEFAULT_DLS_CHORUS));
|
|
95
93
|
}
|
|
96
|
-
preset.DLSInstrument.instrumentZones.push(globalZone);
|
|
97
94
|
|
|
98
95
|
// read regions
|
|
99
96
|
for (let i = 0; i < regions; i++)
|
|
@@ -111,11 +108,11 @@ export function readDLSInstrument(chunk)
|
|
|
111
108
|
const zone = this.readRegion(chunk);
|
|
112
109
|
if (zone)
|
|
113
110
|
{
|
|
114
|
-
preset.DLSInstrument.
|
|
111
|
+
preset.DLSInstrument.addZones(zone);
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
114
|
|
|
118
|
-
this.
|
|
119
|
-
this.
|
|
115
|
+
this.addPresets(preset);
|
|
116
|
+
this.addInstruments(preset.DLSInstrument);
|
|
120
117
|
SpessaSynthGroupEnd();
|
|
121
118
|
}
|
|
@@ -4,7 +4,7 @@ import { readArticulation } from "./read_articulation.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* @param lartChunk {RiffChunk|undefined}
|
|
6
6
|
* @param lar2Chunk {RiffChunk|undefined}
|
|
7
|
-
* @param zone {
|
|
7
|
+
* @param zone {BasicZone}
|
|
8
8
|
* @this {DLSSoundFont}
|
|
9
9
|
*/
|
|
10
10
|
export function readLart(lartChunk, lar2Chunk, zone)
|
|
@@ -16,8 +16,8 @@ export function readLart(lartChunk, lar2Chunk, zone)
|
|
|
16
16
|
const art1 = readRIFFChunk(lartChunk.chunkData);
|
|
17
17
|
this.verifyHeader(art1, "art1", "art2");
|
|
18
18
|
const modsAndGens = readArticulation(art1, true);
|
|
19
|
-
zone.
|
|
20
|
-
zone.
|
|
19
|
+
zone.addGenerators(...modsAndGens.generators);
|
|
20
|
+
zone.addModulators(...modsAndGens.modulators);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -28,8 +28,8 @@ export function readLart(lartChunk, lar2Chunk, zone)
|
|
|
28
28
|
const art2 = readRIFFChunk(lar2Chunk.chunkData);
|
|
29
29
|
this.verifyHeader(art2, "art2", "art1");
|
|
30
30
|
const modsAndGens = readArticulation(art2, false);
|
|
31
|
-
zone.
|
|
32
|
-
zone.
|
|
31
|
+
zone.addGenerators(...modsAndGens.generators);
|
|
32
|
+
zone.addModulators(...modsAndGens.modulators);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
|
|
2
2
|
import { findRIFFListType, readRIFFChunk } from "../basic_soundfont/riff_chunk.js";
|
|
3
3
|
import { DLSZone } from "./dls_zone.js";
|
|
4
|
-
import { Generator
|
|
4
|
+
import { Generator } from "../basic_soundfont/generator.js";
|
|
5
|
+
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @this {DLSSoundFont}
|
|
@@ -51,7 +52,7 @@ export function readRegion(chunk)
|
|
|
51
52
|
const exclusive = readLittleEndian(regionHeader.chunkData, 2);
|
|
52
53
|
if (exclusive !== 0)
|
|
53
54
|
{
|
|
54
|
-
zone.
|
|
55
|
+
zone.addGenerators(new Generator(generatorTypes.exclusiveClass, exclusive));
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
// lart
|
|
@@ -60,7 +61,6 @@ export function readRegion(chunk)
|
|
|
60
61
|
this.readLart(lart, lar2, zone);
|
|
61
62
|
|
|
62
63
|
// wsmp: wave sample chunk
|
|
63
|
-
zone.isGlobal = false;
|
|
64
64
|
const waveSampleChunk = regionChunks.find(c => c.header === "wsmp");
|
|
65
65
|
// cbSize
|
|
66
66
|
readLittleEndian(waveSampleChunk.chunkData, 4);
|
|
@@ -33,7 +33,16 @@ export class Instrument extends BasicInstrument
|
|
|
33
33
|
this.instrumentZonesAmount = amount;
|
|
34
34
|
for (let i = this.instrumentZoneIndex; i < this.instrumentZonesAmount + this.instrumentZoneIndex; i++)
|
|
35
35
|
{
|
|
36
|
-
|
|
36
|
+
const zone = zones[i];
|
|
37
|
+
if (zone.hasSample())
|
|
38
|
+
{
|
|
39
|
+
this.addZones(zone);
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
{
|
|
43
|
+
// global!
|
|
44
|
+
this.globalZone.copyFrom(zone);
|
|
45
|
+
}
|
|
37
46
|
}
|
|
38
47
|
}
|
|
39
48
|
}
|
|
@@ -1,24 +1,5 @@
|
|
|
1
1
|
import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
|
|
2
|
-
import {
|
|
3
|
-
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export class ReadModulator extends Modulator
|
|
7
|
-
{
|
|
8
|
-
/**
|
|
9
|
-
* Creates a modulator
|
|
10
|
-
* @param dataArray {IndexedByteArray}
|
|
11
|
-
*/
|
|
12
|
-
constructor(dataArray)
|
|
13
|
-
{
|
|
14
|
-
const srcEnum = readLittleEndian(dataArray, 2);
|
|
15
|
-
const destination = readLittleEndian(dataArray, 2);
|
|
16
|
-
const amount = signedInt16(dataArray[dataArray.currentIndex++], dataArray[dataArray.currentIndex++]);
|
|
17
|
-
const secSrcEnum = readLittleEndian(dataArray, 2);
|
|
18
|
-
const transformType = readLittleEndian(dataArray, 2);
|
|
19
|
-
super(srcEnum, secSrcEnum, destination, amount, transformType);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
2
|
+
import { DecodedModulator, Modulator } from "../basic_soundfont/modulator.js";
|
|
22
3
|
|
|
23
4
|
/**
|
|
24
5
|
* Reads the modulator read
|
|
@@ -27,10 +8,16 @@ export class ReadModulator extends Modulator
|
|
|
27
8
|
*/
|
|
28
9
|
export function readModulators(modulatorChunk)
|
|
29
10
|
{
|
|
30
|
-
let
|
|
11
|
+
let mods = [];
|
|
31
12
|
while (modulatorChunk.chunkData.length > modulatorChunk.chunkData.currentIndex)
|
|
32
13
|
{
|
|
33
|
-
|
|
14
|
+
const dataArray = modulatorChunk.chunkData;
|
|
15
|
+
const sourceEnum = readLittleEndian(dataArray, 2);
|
|
16
|
+
const destination = readLittleEndian(dataArray, 2);
|
|
17
|
+
const amount = signedInt16(dataArray[dataArray.currentIndex++], dataArray[dataArray.currentIndex++]);
|
|
18
|
+
const secondarySourceEnum = readLittleEndian(dataArray, 2);
|
|
19
|
+
const transformType = readLittleEndian(dataArray, 2);
|
|
20
|
+
mods.push(new DecodedModulator(sourceEnum, secondarySourceEnum, destination, amount, transformType));
|
|
34
21
|
}
|
|
35
|
-
return
|
|
22
|
+
return mods;
|
|
36
23
|
}
|
|
@@ -43,7 +43,16 @@ export class Preset extends BasicPreset
|
|
|
43
43
|
this.presetZonesAmount = amount;
|
|
44
44
|
for (let i = this.presetZoneStartIndex; i < this.presetZonesAmount + this.presetZoneStartIndex; i++)
|
|
45
45
|
{
|
|
46
|
-
|
|
46
|
+
const zone = zones[i];
|
|
47
|
+
if (zone.hasInstrument())
|
|
48
|
+
{
|
|
49
|
+
this.presetZones.push(zone);
|
|
50
|
+
}
|
|
51
|
+
else
|
|
52
|
+
{
|
|
53
|
+
// global!
|
|
54
|
+
this.globalZone.copyFrom(zone);
|
|
55
|
+
}
|
|
47
56
|
}
|
|
48
57
|
}
|
|
49
58
|
}
|
|
@@ -11,7 +11,7 @@ import { consoleColors } from "../../utils/other.js";
|
|
|
11
11
|
import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../utils/loggin.js";
|
|
12
12
|
import { readBytesAsString } from "../../utils/byte_functions/string.js";
|
|
13
13
|
import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
|
|
14
|
-
import { BasicSoundBank } from "../basic_soundfont/
|
|
14
|
+
import { BasicSoundBank } from "../basic_soundfont/basic_soundbank.js";
|
|
15
15
|
import { Generator } from "../basic_soundfont/generator.js";
|
|
16
16
|
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
17
17
|
|
|
@@ -215,7 +215,6 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
215
215
|
* @type {Modulator[]}
|
|
216
216
|
*/
|
|
217
217
|
let instrumentModulators = readModulators(presetInstrumentModulatorsChunk);
|
|
218
|
-
|
|
219
218
|
/**
|
|
220
219
|
* read all the instrument zones
|
|
221
220
|
* @type {InstrumentZone[]}
|
|
@@ -243,9 +242,8 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
243
242
|
|
|
244
243
|
let presetZones = readPresetZones(presetZonesChunk, presetGenerators, presetModulators, this.instruments);
|
|
245
244
|
|
|
246
|
-
this.
|
|
247
|
-
this.
|
|
248
|
-
this._parseInternal();
|
|
245
|
+
this.addPresets(...readPresets(presetHeadersChunk, presetZones, this));
|
|
246
|
+
this.flush();
|
|
249
247
|
SpessaSynthInfo(
|
|
250
248
|
`%cParsing finished! %c"${this.soundFontInfo["INAM"]}"%c has %c${this.presets.length} %cpresets,
|
|
251
249
|
%c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
2
2
|
import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
3
3
|
import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
|
|
4
|
-
import {
|
|
5
|
-
import { Generator
|
|
4
|
+
import { BasicPresetZone } from "../basic_soundfont/basic_preset_zone.js";
|
|
5
|
+
import { Generator } from "../basic_soundfont/generator.js";
|
|
6
6
|
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
7
|
+
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
8
|
+
import { BasicInstrumentZone } from "../basic_soundfont/basic_instrument_zone.js";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* zones.js
|
|
@@ -23,7 +25,6 @@ export class InstrumentZone extends BasicInstrumentZone
|
|
|
23
25
|
this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
|
|
24
26
|
this.modulatorZoneSize = 0;
|
|
25
27
|
this.generatorZoneSize = 0;
|
|
26
|
-
this.isGlobal = true;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
setZoneSize(modulatorZoneSize, generatorZoneSize)
|
|
@@ -40,7 +41,12 @@ export class InstrumentZone extends BasicInstrumentZone
|
|
|
40
41
|
{
|
|
41
42
|
for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
|
|
42
43
|
{
|
|
43
|
-
|
|
44
|
+
const g = generators[i];
|
|
45
|
+
if (!g)
|
|
46
|
+
{
|
|
47
|
+
throw new Error("Missing generator in instrument zone! The file may corrupted.");
|
|
48
|
+
}
|
|
49
|
+
this.addGenerators(g);
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -52,7 +58,12 @@ export class InstrumentZone extends BasicInstrumentZone
|
|
|
52
58
|
{
|
|
53
59
|
for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
|
|
54
60
|
{
|
|
55
|
-
|
|
61
|
+
const m = modulators[i];
|
|
62
|
+
if (!m)
|
|
63
|
+
{
|
|
64
|
+
throw new Error("Missing modulator in instrument zone! The file may corrupted.");
|
|
65
|
+
}
|
|
66
|
+
this.addModulators(m);
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
|
|
@@ -65,35 +76,7 @@ export class InstrumentZone extends BasicInstrumentZone
|
|
|
65
76
|
let sampleID = this.generators.find(g => g.generatorType === generatorTypes.sampleID);
|
|
66
77
|
if (sampleID)
|
|
67
78
|
{
|
|
68
|
-
this.
|
|
69
|
-
this.isGlobal = false;
|
|
70
|
-
this.sample.useCount++;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Reads the keyRange of the zone
|
|
76
|
-
*/
|
|
77
|
-
getKeyRange()
|
|
78
|
-
{
|
|
79
|
-
let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
|
|
80
|
-
if (range)
|
|
81
|
-
{
|
|
82
|
-
this.keyRange.min = range.generatorValue & 0x7F;
|
|
83
|
-
this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* reads the velolicty range of the zone
|
|
89
|
-
*/
|
|
90
|
-
getVelRange()
|
|
91
|
-
{
|
|
92
|
-
let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
|
|
93
|
-
if (range)
|
|
94
|
-
{
|
|
95
|
-
this.velRange.min = range.generatorValue & 0x7F;
|
|
96
|
-
this.velRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
79
|
+
this.setSample(samples[sampleID.generatorValue]);
|
|
97
80
|
}
|
|
98
81
|
}
|
|
99
82
|
}
|
|
@@ -123,8 +106,6 @@ export function readInstrumentZones(zonesChunk, instrumentGenerators, instrument
|
|
|
123
106
|
zones[zones.length - 1].getGenerators(instrumentGenerators);
|
|
124
107
|
zones[zones.length - 1].getModulators(instrumentModulators);
|
|
125
108
|
zones[zones.length - 1].getSample(instrumentSamples);
|
|
126
|
-
zones[zones.length - 1].getKeyRange();
|
|
127
|
-
zones[zones.length - 1].getVelRange();
|
|
128
109
|
}
|
|
129
110
|
zones.push(zone);
|
|
130
111
|
}
|
|
@@ -149,7 +130,6 @@ export class PresetZone extends BasicPresetZone
|
|
|
149
130
|
this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
|
|
150
131
|
this.modulatorZoneSize = 0;
|
|
151
132
|
this.generatorZoneSize = 0;
|
|
152
|
-
this.isGlobal = true;
|
|
153
133
|
}
|
|
154
134
|
|
|
155
135
|
setZoneSize(modulatorZoneSize, generatorZoneSize)
|
|
@@ -166,7 +146,12 @@ export class PresetZone extends BasicPresetZone
|
|
|
166
146
|
{
|
|
167
147
|
for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
|
|
168
148
|
{
|
|
169
|
-
|
|
149
|
+
const g = generators[i];
|
|
150
|
+
if (!g)
|
|
151
|
+
{
|
|
152
|
+
throw new Error("Missing generator in preset zone! The file may corrupted.");
|
|
153
|
+
}
|
|
154
|
+
this.addGenerators(g);
|
|
170
155
|
}
|
|
171
156
|
}
|
|
172
157
|
|
|
@@ -178,7 +163,12 @@ export class PresetZone extends BasicPresetZone
|
|
|
178
163
|
{
|
|
179
164
|
for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
|
|
180
165
|
{
|
|
181
|
-
|
|
166
|
+
const m = modulators[i];
|
|
167
|
+
if (!m)
|
|
168
|
+
{
|
|
169
|
+
throw new Error("Missing modulator in preset zone! The file may corrupted.");
|
|
170
|
+
}
|
|
171
|
+
this.addModulators(m);
|
|
182
172
|
}
|
|
183
173
|
}
|
|
184
174
|
|
|
@@ -191,35 +181,7 @@ export class PresetZone extends BasicPresetZone
|
|
|
191
181
|
let instrumentID = this.generators.find(g => g.generatorType === generatorTypes.instrument);
|
|
192
182
|
if (instrumentID)
|
|
193
183
|
{
|
|
194
|
-
this.
|
|
195
|
-
this.instrument.addUseCount();
|
|
196
|
-
this.isGlobal = false;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Reads the keyRange of the zone
|
|
202
|
-
*/
|
|
203
|
-
getKeyRange()
|
|
204
|
-
{
|
|
205
|
-
let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
|
|
206
|
-
if (range)
|
|
207
|
-
{
|
|
208
|
-
this.keyRange.min = range.generatorValue & 0x7F;
|
|
209
|
-
this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* reads the velolicty range of the zone
|
|
215
|
-
*/
|
|
216
|
-
getVelRange()
|
|
217
|
-
{
|
|
218
|
-
let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
|
|
219
|
-
if (range)
|
|
220
|
-
{
|
|
221
|
-
this.velRange.min = range.generatorValue & 0x7F;
|
|
222
|
-
this.velRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
184
|
+
this.setInstrument(instruments[instrumentID.generatorValue]);
|
|
223
185
|
}
|
|
224
186
|
}
|
|
225
187
|
}
|
|
@@ -249,8 +211,6 @@ export function readPresetZones(zonesChunk, presetGenerators, presetModulators,
|
|
|
249
211
|
zones[zones.length - 1].getGenerators(presetGenerators);
|
|
250
212
|
zones[zones.length - 1].getModulators(presetModulators);
|
|
251
213
|
zones[zones.length - 1].getInstrument(instruments);
|
|
252
|
-
zones[zones.length - 1].getKeyRange();
|
|
253
|
-
zones[zones.length - 1].getVelRange();
|
|
254
214
|
}
|
|
255
215
|
zones.push(zone);
|
|
256
216
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
## This is the
|
|
1
|
+
## This is the synthesizer folder.
|
|
2
2
|
|
|
3
3
|
The code here is responsible for making the actual sound.
|
|
4
4
|
This is the heart of the SpessaSynth library.
|
|
5
5
|
|
|
6
|
-
- `audio_engine` - the core synthesis engine, it theoretically can run on non-browser environments
|
|
7
|
-
- `
|
|
6
|
+
- `audio_engine` - the core synthesis engine, it theoretically can run on non-browser environments
|
|
7
|
+
- `synth_constants.js` - contains the synthesizer's configuration constants
|
|
@@ -6,4 +6,4 @@ The code here is responsible for a single midi channel, synthesizing the sound t
|
|
|
6
6
|
- `engine_components` contains the various digital signal processing functions such as the wavetable oscillator, low
|
|
7
7
|
pass filter, etc.
|
|
8
8
|
|
|
9
|
-
For those interested, `render_voice.js` file contains the actual DSP synthesis code.
|
|
9
|
+
For those interested, `engine_methods/render_voice.js` file contains the actual DSP synthesis code.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { getModulatorCurveValue, MOD_PRECOMPUTED_LENGTH } from "./modulator_curves.js";
|
|
2
2
|
import { VolumeEnvelope } from "./volume_envelope.js";
|
|
3
3
|
import { ModulationEnvelope } from "./modulation_envelope.js";
|
|
4
|
-
import { generatorLimits, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
|
|
5
4
|
import { Modulator, modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
6
5
|
import { NON_CC_INDEX_OFFSET } from "./controller_tables.js";
|
|
7
|
-
import {
|
|
6
|
+
import { generatorLimits, generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* compute_modulator.js
|
|
@@ -146,22 +145,23 @@ export function computeModulators(voice, sourceUsesCC = -1, sourceIndex = 0)
|
|
|
146
145
|
modulatedGenerators.set(generators);
|
|
147
146
|
modulators.forEach(mod =>
|
|
148
147
|
{
|
|
149
|
-
|
|
150
|
-
if (!limits)
|
|
151
|
-
{
|
|
152
|
-
SpessaSynthWarn(`Invalid modulator: ${mod.modulatorDestination}`);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const newValue = modulatedGenerators[mod.modulatorDestination] + computeModulator(
|
|
148
|
+
modulatedGenerators[mod.modulatorDestination] += computeModulator(
|
|
156
149
|
this.midiControllers,
|
|
157
150
|
mod,
|
|
158
151
|
voice
|
|
159
152
|
);
|
|
160
|
-
modulatedGenerators[mod.modulatorDestination] = Math.max(
|
|
161
|
-
limits.min,
|
|
162
|
-
Math.min(newValue, limits.max)
|
|
163
|
-
);
|
|
164
153
|
});
|
|
154
|
+
// apply limits
|
|
155
|
+
for (let gen = 0; gen < modulatedGenerators.length; gen++)
|
|
156
|
+
{
|
|
157
|
+
const limit = generatorLimits[gen];
|
|
158
|
+
if (!limit)
|
|
159
|
+
{
|
|
160
|
+
// skip unused
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
modulatedGenerators[gen] = Math.min(limit.max, Math.max(limit.min, modulatedGenerators[gen]));
|
|
164
|
+
}
|
|
165
165
|
VolumeEnvelope.recalculate(voice);
|
|
166
166
|
ModulationEnvelope.recalculate(voice);
|
|
167
167
|
return;
|
|
@@ -201,14 +201,15 @@ export function computeModulators(voice, sourceUsesCC = -1, sourceIndex = 0)
|
|
|
201
201
|
{
|
|
202
202
|
if (m.modulatorDestination === destination)
|
|
203
203
|
{
|
|
204
|
-
|
|
205
|
-
const newValue = modulatedGenerators[mod.modulatorDestination] + m.currentValue;
|
|
206
|
-
modulatedGenerators[mod.modulatorDestination] = Math.max(
|
|
207
|
-
limits.min,
|
|
208
|
-
Math.min(newValue, limits.max)
|
|
209
|
-
);
|
|
204
|
+
modulatedGenerators[destination] += m.currentValue;
|
|
210
205
|
}
|
|
211
206
|
});
|
|
207
|
+
// apply limits
|
|
208
|
+
const limits = generatorLimits[destination];
|
|
209
|
+
modulatedGenerators[destination] = Math.max(
|
|
210
|
+
limits.min,
|
|
211
|
+
Math.min(modulatedGenerators[destination], limits.max)
|
|
212
|
+
);
|
|
212
213
|
computedDestinations.add(destination);
|
|
213
214
|
}
|
|
214
215
|
}
|