spessasynth_lib 3.25.5 → 3.25.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/midi_parser/basic_midi.js +0 -28
- package/package.json +1 -1
- package/soundfont/basic_soundfont/basic_instrument.js +18 -14
- package/soundfont/basic_soundfont/basic_preset.js +63 -59
- package/soundfont/basic_soundfont/basic_sample.js +75 -55
- package/soundfont/basic_soundfont/basic_soundfont.js +120 -68
- package/soundfont/dls/dls_preset.js +3 -3
- package/soundfont/dls/dls_soundfont.js +1 -1
- package/soundfont/dls/read_instrument.js +1 -1
- package/soundfont/read_sf2/presets.js +6 -6
- package/soundfont/read_sf2/samples.js +19 -18
- package/soundfont/read_sf2/soundfont.js +2 -2
- package/soundfont/read_sf2/zones.js +2 -3
- package/synthetizer/worklet_processor.min.js +11 -11
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js +0 -2
- package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js +0 -13
- package/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +16 -10
|
@@ -533,35 +533,7 @@ class BasicMIDI extends MIDISequenceData
|
|
|
533
533
|
);
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
-
// lyrics fix:
|
|
537
|
-
// sometimes, all lyrics events lack spaces at the start or end of the lyric
|
|
538
|
-
// then, and only then, add space at the end of each lyric
|
|
539
|
-
// space ASCII is 32
|
|
540
|
-
let lacksSpaces = true;
|
|
541
|
-
for (const lyric of this.lyrics)
|
|
542
|
-
{
|
|
543
|
-
if (lyric[0] === 32 || lyric[lyric.length - 1] === 32)
|
|
544
|
-
{
|
|
545
|
-
lacksSpaces = false;
|
|
546
|
-
break;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
536
|
|
|
550
|
-
if (lacksSpaces)
|
|
551
|
-
{
|
|
552
|
-
this.lyrics = this.lyrics.map(lyric =>
|
|
553
|
-
{
|
|
554
|
-
// One exception: hyphens at the end. Don't add a space to them
|
|
555
|
-
if (lyric[lyric.length - 1] === 45)
|
|
556
|
-
{
|
|
557
|
-
return lyric;
|
|
558
|
-
}
|
|
559
|
-
const withSpaces = new Uint8Array(lyric.length + 1);
|
|
560
|
-
withSpaces.set(lyric, 0);
|
|
561
|
-
withSpaces[lyric.length] = 32;
|
|
562
|
-
return withSpaces;
|
|
563
|
-
});
|
|
564
|
-
}
|
|
565
537
|
/**
|
|
566
538
|
* The total playback time, in seconds
|
|
567
539
|
* @type {number}
|
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
export class BasicInstrument
|
|
2
2
|
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The instrument's name
|
|
5
|
+
* @type {string}
|
|
6
|
+
*/
|
|
7
|
+
instrumentName = "";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The instrument's zones
|
|
11
|
+
* @type {BasicInstrumentZone[]}
|
|
12
|
+
*/
|
|
13
|
+
instrumentZones = [];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Instrument's use count, used for trimming
|
|
17
|
+
* @type {number}
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
_useCount = 0;
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* @returns {number}
|
|
@@ -14,69 +14,69 @@ import { isXGDrums } from "../../utils/xg_hacks.js";
|
|
|
14
14
|
export class BasicPreset
|
|
15
15
|
{
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* The parent soundbank instance
|
|
18
|
+
* Currently used for determining default modulators and XG status
|
|
19
|
+
* @type {BasicSoundBank}
|
|
18
20
|
*/
|
|
19
|
-
|
|
21
|
+
parentSoundBank;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The preset's name
|
|
25
|
+
* @type {string}
|
|
26
|
+
*/
|
|
27
|
+
presetName = "";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The preset's MIDI program number
|
|
31
|
+
* @type {number}
|
|
32
|
+
*/
|
|
33
|
+
program = 0;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The preset's MIDI bank number
|
|
37
|
+
* @type {number}
|
|
38
|
+
*/
|
|
39
|
+
bank = 0;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The preset's zones
|
|
43
|
+
* @type {BasicPresetZone[]}
|
|
44
|
+
*/
|
|
45
|
+
presetZones = [];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Stores already found getSamplesAndGenerators for reuse
|
|
49
|
+
* @type {SampleAndGenerators[][][]}
|
|
50
|
+
*/
|
|
51
|
+
foundSamplesAndGenerators = [];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* unused metadata
|
|
55
|
+
* @type {number}
|
|
56
|
+
*/
|
|
57
|
+
library = 0;
|
|
58
|
+
/**
|
|
59
|
+
* unused metadata
|
|
60
|
+
* @type {number}
|
|
61
|
+
*/
|
|
62
|
+
genre = 0;
|
|
63
|
+
/**
|
|
64
|
+
* unused metadata
|
|
65
|
+
* @type {number}
|
|
66
|
+
*/
|
|
67
|
+
morphology = 0;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Creates a new preset representation
|
|
71
|
+
* @param parentSoundBank {BasicSoundBank}
|
|
72
|
+
*/
|
|
73
|
+
constructor(parentSoundBank)
|
|
20
74
|
{
|
|
21
|
-
|
|
22
|
-
* The preset's name
|
|
23
|
-
* @type {string}
|
|
24
|
-
*/
|
|
25
|
-
this.presetName = "";
|
|
26
|
-
/**
|
|
27
|
-
* The preset's MIDI program number
|
|
28
|
-
* @type {number}
|
|
29
|
-
*/
|
|
30
|
-
this.program = 0;
|
|
31
|
-
/**
|
|
32
|
-
* The preset's MIDI bank number
|
|
33
|
-
* @type {number}
|
|
34
|
-
*/
|
|
35
|
-
this.bank = 0;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* The preset's zones
|
|
39
|
-
* @type {BasicPresetZone[]}
|
|
40
|
-
*/
|
|
41
|
-
this.presetZones = [];
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* SampleID offset for this preset
|
|
45
|
-
* @type {number}
|
|
46
|
-
*/
|
|
47
|
-
this.sampleIDOffset = 0;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Stores already found getSamplesAndGenerators for reuse
|
|
51
|
-
* @type {SampleAndGenerators[][][]}
|
|
52
|
-
*/
|
|
53
|
-
this.foundSamplesAndGenerators = [];
|
|
75
|
+
this.parentSoundBank = parentSoundBank;
|
|
54
76
|
for (let i = 0; i < 128; i++)
|
|
55
77
|
{
|
|
56
78
|
this.foundSamplesAndGenerators[i] = [];
|
|
57
79
|
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* unused metadata
|
|
61
|
-
* @type {number}
|
|
62
|
-
*/
|
|
63
|
-
this.library = 0;
|
|
64
|
-
/**
|
|
65
|
-
* unused metadata
|
|
66
|
-
* @type {number}
|
|
67
|
-
*/
|
|
68
|
-
this.genre = 0;
|
|
69
|
-
/**
|
|
70
|
-
* unused metadata
|
|
71
|
-
* @type {number}
|
|
72
|
-
*/
|
|
73
|
-
this.morphology = 0;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Default modulators
|
|
77
|
-
* @type {Modulator[]}
|
|
78
|
-
*/
|
|
79
|
-
this.defaultModulators = modulators;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -86,8 +86,12 @@ export class BasicPreset
|
|
|
86
86
|
*/
|
|
87
87
|
isDrumPreset(allowXG, allowSFX = false)
|
|
88
88
|
{
|
|
89
|
+
const xg = allowXG && this.parentSoundBank.isXGBank;
|
|
89
90
|
// sfx is not cool
|
|
90
|
-
return this.bank === 128 || (
|
|
91
|
+
return this.bank === 128 || (
|
|
92
|
+
xg &&
|
|
93
|
+
(isXGDrums(this.bank) && (this.bank !== 126 || allowSFX))
|
|
94
|
+
);
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
deletePreset()
|
|
@@ -286,7 +290,7 @@ export class BasicPreset
|
|
|
286
290
|
// default mods
|
|
287
291
|
addUniqueMods(
|
|
288
292
|
instrumentModulators,
|
|
289
|
-
this.defaultModulators
|
|
293
|
+
this.parentSoundBank.defaultModulators
|
|
290
294
|
);
|
|
291
295
|
|
|
292
296
|
/**
|
|
@@ -10,6 +10,79 @@ const RESAMPLE_RATE = 48000;
|
|
|
10
10
|
|
|
11
11
|
export class BasicSample
|
|
12
12
|
{
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The sample's name
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
sampleName;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Sample rate in Hz
|
|
22
|
+
* @type {number}
|
|
23
|
+
*/
|
|
24
|
+
sampleRate;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Original pitch of the sample as a MIDI note number
|
|
28
|
+
* @type {number}
|
|
29
|
+
*/
|
|
30
|
+
samplePitch;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Pitch correction, in cents. Can be negative
|
|
34
|
+
* @type {number}
|
|
35
|
+
*/
|
|
36
|
+
samplePitchCorrection;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Sample link, currently unused here
|
|
40
|
+
* @type {number}
|
|
41
|
+
*/
|
|
42
|
+
sampleLink;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Type of the sample, currently only used for SF3
|
|
46
|
+
* @type {number}
|
|
47
|
+
*/
|
|
48
|
+
sampleType;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Relative to the start of the sample in sample points
|
|
52
|
+
* @type {number}
|
|
53
|
+
*/
|
|
54
|
+
sampleLoopStartIndex;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Relative to the start of the sample in sample points
|
|
58
|
+
* @type {number}
|
|
59
|
+
*/
|
|
60
|
+
sampleLoopEndIndex;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Indicates if the sample is compressed
|
|
64
|
+
* @type {boolean}
|
|
65
|
+
*/
|
|
66
|
+
isCompressed;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The compressed sample data if it was compressed by spessasynth
|
|
70
|
+
* @type {Uint8Array}
|
|
71
|
+
*/
|
|
72
|
+
compressedData = undefined;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The sample's use count
|
|
76
|
+
* @type {number}
|
|
77
|
+
*/
|
|
78
|
+
useCount = 0;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The sample's audio data
|
|
82
|
+
* @type {Float32Array}
|
|
83
|
+
*/
|
|
84
|
+
sampleData = undefined;
|
|
85
|
+
|
|
13
86
|
/**
|
|
14
87
|
* The basic representation of a soundfont sample
|
|
15
88
|
* @param sampleName {string} The sample's name
|
|
@@ -32,72 +105,19 @@ export class BasicSample
|
|
|
32
105
|
loopEnd
|
|
33
106
|
)
|
|
34
107
|
{
|
|
35
|
-
/**
|
|
36
|
-
* Sample's name
|
|
37
|
-
* @type {string}
|
|
38
|
-
*/
|
|
39
108
|
this.sampleName = sampleName;
|
|
40
|
-
/**
|
|
41
|
-
* Sample rate in Hz
|
|
42
|
-
* @type {number}
|
|
43
|
-
*/
|
|
44
109
|
this.sampleRate = sampleRate;
|
|
45
|
-
/**
|
|
46
|
-
* Original pitch of the sample as a MIDI note number
|
|
47
|
-
* @type {number}
|
|
48
|
-
*/
|
|
49
110
|
this.samplePitch = samplePitch;
|
|
50
|
-
/**
|
|
51
|
-
* Pitch correction, in cents. Can be negative
|
|
52
|
-
* @type {number}
|
|
53
|
-
*/
|
|
54
111
|
this.samplePitchCorrection = samplePitchCorrection;
|
|
55
|
-
/**
|
|
56
|
-
* Sample link, currently unused.
|
|
57
|
-
* @type {number}
|
|
58
|
-
*/
|
|
59
112
|
this.sampleLink = sampleLink;
|
|
60
|
-
/**
|
|
61
|
-
* Type of the sample, an enum
|
|
62
|
-
* @type {number}
|
|
63
|
-
*/
|
|
64
113
|
this.sampleType = sampleType;
|
|
65
|
-
/**
|
|
66
|
-
* Relative to the start of the sample in sample points
|
|
67
|
-
* @type {number}
|
|
68
|
-
*/
|
|
69
114
|
this.sampleLoopStartIndex = loopStart;
|
|
70
|
-
/**
|
|
71
|
-
* Relative to the start of the sample in sample points
|
|
72
|
-
* @type {number}
|
|
73
|
-
*/
|
|
74
115
|
this.sampleLoopEndIndex = loopEnd;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Indicates if the sample is compressed
|
|
78
|
-
* @type {boolean}
|
|
79
|
-
*/
|
|
116
|
+
// https://github.com/FluidSynth/fluidsynth/wiki/SoundFont3Format
|
|
80
117
|
this.isCompressed = (sampleType & 0x10) > 0;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* The compressed sample data if it was compressed by spessasynth
|
|
84
|
-
* @type {Uint8Array}
|
|
85
|
-
*/
|
|
86
|
-
this.compressedData = undefined;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* The sample's use count
|
|
90
|
-
* @type {number}
|
|
91
|
-
*/
|
|
92
|
-
this.useCount = 0;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* The sample's audio data
|
|
96
|
-
* @type {Float32Array}
|
|
97
|
-
*/
|
|
98
|
-
this.sampleData = undefined;
|
|
99
118
|
}
|
|
100
119
|
|
|
120
|
+
|
|
101
121
|
/**
|
|
102
122
|
* @returns {Uint8Array|IndexedByteArray}
|
|
103
123
|
*/
|
|
@@ -18,42 +18,49 @@ import { isXGDrums } from "../../utils/xg_hacks.js";
|
|
|
18
18
|
|
|
19
19
|
class BasicSoundBank
|
|
20
20
|
{
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Soundfont's info stored as name: value. ifil and iver are stored as string representation of float (e.g., 2.1)
|
|
24
|
+
* @type {Object<string, string|IndexedByteArray>}
|
|
25
|
+
*/
|
|
26
|
+
soundFontInfo = {};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The soundfont's presets
|
|
30
|
+
* @type {BasicPreset[]}
|
|
31
|
+
*/
|
|
32
|
+
presets = [];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The soundfont's samples
|
|
36
|
+
* @type {BasicSample[]}
|
|
37
|
+
*/
|
|
38
|
+
samples = [];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The soundfont's instruments
|
|
42
|
+
* @type {BasicInstrument[]}
|
|
43
|
+
*/
|
|
44
|
+
instruments = [];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Soundfont's default modulatorss
|
|
48
|
+
* @type {Modulator[]}
|
|
49
|
+
*/
|
|
50
|
+
defaultModulators = defaultModulators.map(m => Modulator.copy(m));
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Checks for XG drumsets and considers if this soundfont is XG.
|
|
54
|
+
* @type {boolean}
|
|
55
|
+
*/
|
|
56
|
+
isXGBank = false;
|
|
57
|
+
|
|
21
58
|
/**
|
|
22
59
|
* Creates a new basic soundfont template
|
|
23
60
|
* @param data {undefined|{presets: BasicPreset[], info: Object<string, string>}}
|
|
24
61
|
*/
|
|
25
62
|
constructor(data = undefined)
|
|
26
63
|
{
|
|
27
|
-
/**
|
|
28
|
-
* Soundfont's info stored as name: value. ifil and iver are stored as string representation of float (e.g., 2.1)
|
|
29
|
-
* @type {Object<string, string|IndexedByteArray>}
|
|
30
|
-
*/
|
|
31
|
-
this.soundFontInfo = {};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* The soundfont's presets
|
|
35
|
-
* @type {BasicPreset[]}
|
|
36
|
-
*/
|
|
37
|
-
this.presets = [];
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The soundfont's samples
|
|
41
|
-
* @type {BasicSample[]}
|
|
42
|
-
*/
|
|
43
|
-
this.samples = [];
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The soundfont's instruments
|
|
47
|
-
* @type {BasicInstrument[]}
|
|
48
|
-
*/
|
|
49
|
-
this.instruments = [];
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Soundfont's default modulatorss
|
|
53
|
-
* @type {Modulator[]}
|
|
54
|
-
*/
|
|
55
|
-
this.defaultModulators = defaultModulators.map(m => Modulator.copy(m));
|
|
56
|
-
|
|
57
64
|
if (data?.presets)
|
|
58
65
|
{
|
|
59
66
|
this.presets.push(...data.presets);
|
|
@@ -135,7 +142,7 @@ class BasicSoundBank
|
|
|
135
142
|
const pZone = new BasicPresetZone();
|
|
136
143
|
pZone.instrument = inst;
|
|
137
144
|
|
|
138
|
-
const preset = new BasicPreset(font
|
|
145
|
+
const preset = new BasicPreset(font);
|
|
139
146
|
preset.presetName = "Saw Wave";
|
|
140
147
|
preset.presetZones.push(pZone);
|
|
141
148
|
font.presets.push(preset);
|
|
@@ -143,9 +150,44 @@ class BasicSoundBank
|
|
|
143
150
|
font.soundFontInfo["ifil"] = "2.1";
|
|
144
151
|
font.soundFontInfo["isng"] = "EMU8000";
|
|
145
152
|
font.soundFontInfo["INAM"] = "Dummy";
|
|
153
|
+
font._parseInternal();
|
|
146
154
|
return font.write().buffer;
|
|
147
155
|
}
|
|
148
156
|
|
|
157
|
+
/**
|
|
158
|
+
* parses the bank after loading is done
|
|
159
|
+
* @protected
|
|
160
|
+
*/
|
|
161
|
+
_parseInternal()
|
|
162
|
+
{
|
|
163
|
+
this.isXGBank = false;
|
|
164
|
+
// definitions for XG:
|
|
165
|
+
// at least one preset with bank 127, 126 or 120
|
|
166
|
+
// MUST be a valid XG bank.
|
|
167
|
+
// allowed banks: (see XG specification)
|
|
168
|
+
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 24,
|
|
169
|
+
// 25, 27, 28, 29, 30, 31, 32, 33, 40, 41, 48,
|
|
170
|
+
// 64, 65, 66, 126, 127
|
|
171
|
+
const allowedPrograms = new Set([
|
|
172
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 24,
|
|
173
|
+
25, 27, 28, 29, 30, 31, 32, 33, 40, 41, 48,
|
|
174
|
+
64, 65, 66, 126, 127
|
|
175
|
+
]);
|
|
176
|
+
for (const preset of this.presets)
|
|
177
|
+
{
|
|
178
|
+
if (isXGDrums(preset.bank))
|
|
179
|
+
{
|
|
180
|
+
this.isXGBank = true;
|
|
181
|
+
if (!allowedPrograms.has(preset.program))
|
|
182
|
+
{
|
|
183
|
+
// not valid!
|
|
184
|
+
this.isXGBank = false;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
149
191
|
/**
|
|
150
192
|
* Trims a sound bank to only contain samples in a given MIDI file
|
|
151
193
|
* @param mid {BasicMIDI} - the MIDI file
|
|
@@ -381,16 +423,7 @@ class BasicSoundBank
|
|
|
381
423
|
}
|
|
382
424
|
|
|
383
425
|
/**
|
|
384
|
-
*
|
|
385
|
-
* @param offset {number}
|
|
386
|
-
*/
|
|
387
|
-
setSampleIDOffset(offset)
|
|
388
|
-
{
|
|
389
|
-
this.presets.forEach(p => p.sampleIDOffset = offset);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Get the appropriate preset, undefined if not foun d
|
|
426
|
+
* Get the appropriate preset, undefined if not found
|
|
394
427
|
* @param bankNr {number}
|
|
395
428
|
* @param programNr {number}
|
|
396
429
|
* @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
|
|
@@ -398,14 +431,22 @@ class BasicSoundBank
|
|
|
398
431
|
*/
|
|
399
432
|
getPresetNoFallback(bankNr, programNr, allowXGDrums = false)
|
|
400
433
|
{
|
|
434
|
+
const isDrum = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
|
|
401
435
|
// check for exact match
|
|
402
|
-
|
|
436
|
+
let p;
|
|
437
|
+
if (isDrum)
|
|
438
|
+
{
|
|
439
|
+
p = this.presets.find(p => p.bank === bankNr && p.isDrumPreset(allowXGDrums) && p.program === programNr);
|
|
440
|
+
}
|
|
441
|
+
else
|
|
442
|
+
{
|
|
443
|
+
p = this.presets.find(p => p.bank === bankNr && p.program === programNr);
|
|
444
|
+
}
|
|
403
445
|
if (p)
|
|
404
446
|
{
|
|
405
447
|
return p;
|
|
406
448
|
}
|
|
407
449
|
// no match...
|
|
408
|
-
const isDrum = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
|
|
409
450
|
if (isDrum)
|
|
410
451
|
{
|
|
411
452
|
if (allowXGDrums)
|
|
@@ -430,36 +471,47 @@ class BasicSoundBank
|
|
|
430
471
|
*/
|
|
431
472
|
getPreset(bankNr, programNr, allowXGDrums = false)
|
|
432
473
|
{
|
|
433
|
-
// check for exact match
|
|
434
|
-
let preset = this.presets.find(p => p.bank === bankNr && p.program === programNr);
|
|
435
474
|
const isDrums = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
|
|
436
|
-
|
|
475
|
+
// check for exact match
|
|
476
|
+
let preset;
|
|
477
|
+
// only allow drums if the preset is considered to be a drum preset
|
|
478
|
+
if (isDrums)
|
|
437
479
|
{
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if (preset)
|
|
480
|
+
preset = this.presets.find(p => p.bank === bankNr && p.isDrumPreset(allowXGDrums) && p.program === programNr);
|
|
481
|
+
}
|
|
482
|
+
else
|
|
483
|
+
{
|
|
484
|
+
preset = this.presets.find(p => p.bank === bankNr && p.program === programNr);
|
|
485
|
+
}
|
|
486
|
+
if (preset)
|
|
487
|
+
{
|
|
488
|
+
return preset;
|
|
489
|
+
}
|
|
490
|
+
// no match...
|
|
491
|
+
if (isDrums)
|
|
492
|
+
{
|
|
493
|
+
// drum preset: find any preset with bank 128
|
|
494
|
+
preset = this.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNr);
|
|
495
|
+
if (!preset)
|
|
455
496
|
{
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
consoleColors.warn,
|
|
459
|
-
consoleColors.recognized
|
|
460
|
-
);
|
|
497
|
+
// only allow 128, otherwise it would default to XG SFX
|
|
498
|
+
preset = this.presets.find(p => p.isDrumPreset(allowXGDrums));
|
|
461
499
|
}
|
|
462
500
|
}
|
|
501
|
+
else
|
|
502
|
+
{
|
|
503
|
+
// non-drum preset: find any preset with the given program that is not a drum preset
|
|
504
|
+
preset = this.presets.find(p => p.program === programNr && !p.isDrumPreset(allowXGDrums));
|
|
505
|
+
}
|
|
506
|
+
if (preset)
|
|
507
|
+
{
|
|
508
|
+
SpessaSynthWarn(
|
|
509
|
+
`%cPreset ${bankNr}.${programNr} not found. Replaced with %c${preset.presetName} (${preset.bank}.${preset.program})`,
|
|
510
|
+
consoleColors.warn,
|
|
511
|
+
consoleColors.recognized
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
463
515
|
// no preset, use the first one available
|
|
464
516
|
if (!preset)
|
|
465
517
|
{
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { BasicPreset } from "../basic_soundfont/basic_preset.js";
|
|
2
2
|
import { BasicPresetZone } from "../basic_soundfont/basic_zones.js";
|
|
3
3
|
import { BasicInstrument } from "../basic_soundfont/basic_instrument.js";
|
|
4
|
-
import { defaultModulators } from "../basic_soundfont/modulator.js";
|
|
5
4
|
|
|
6
5
|
export class DLSPreset extends BasicPreset
|
|
7
6
|
{
|
|
8
7
|
/**
|
|
9
8
|
* Creates a new DLS preset
|
|
9
|
+
* @param dls {BasicSoundBank}
|
|
10
10
|
* @param ulBank {number}
|
|
11
11
|
* @param ulInstrument {number}
|
|
12
12
|
*/
|
|
13
|
-
constructor(ulBank, ulInstrument)
|
|
13
|
+
constructor(dls, ulBank, ulInstrument)
|
|
14
14
|
{
|
|
15
15
|
// use stock default modulators, dls won't ever have DMOD chunk
|
|
16
|
-
super(
|
|
16
|
+
super(dls);
|
|
17
17
|
this.program = ulInstrument & 127;
|
|
18
18
|
const bankMSB = (ulBank >> 8) & 127;
|
|
19
19
|
const bankLSB = ulBank & 127;
|
|
@@ -115,7 +115,7 @@ class DLSSoundFont extends BasicSoundBank
|
|
|
115
115
|
|
|
116
116
|
// sort presets
|
|
117
117
|
this.presets.sort((a, b) => (a.program - b.program) + (a.bank - b.bank));
|
|
118
|
-
|
|
118
|
+
this._parseInternal();
|
|
119
119
|
SpessaSynthInfo(
|
|
120
120
|
`%cParsing finished! %c"${this.soundFontInfo["INAM"] || "UNNAMED"}"%c has %c${this.presets.length} %cpresets,
|
|
121
121
|
%c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
|
|
@@ -38,7 +38,7 @@ export function readDLSInstrument(chunk)
|
|
|
38
38
|
const regions = readLittleEndian(instrumentHeader.chunkData, 4);
|
|
39
39
|
const ulBank = readLittleEndian(instrumentHeader.chunkData, 4);
|
|
40
40
|
const ulInstrument = readLittleEndian(instrumentHeader.chunkData, 4);
|
|
41
|
-
const preset = new DLSPreset(ulBank, ulInstrument);
|
|
41
|
+
const preset = new DLSPreset(this, ulBank, ulInstrument);
|
|
42
42
|
|
|
43
43
|
// read preset name in INFO
|
|
44
44
|
let presetName = "unnamedPreset";
|