spessasynth_core 3.26.4 → 3.26.5
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/package.json +1 -1
- package/src/midi/midi_tools/used_keys_loaded.js +26 -8
- package/src/sequencer/song_control.js +20 -25
- package/src/soundfont/basic_soundfont/basic_preset.js +1 -40
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -1
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +45 -17
- package/src/synthetizer/audio_engine/engine_components/voice.js +45 -49
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +1 -5
- package/src/synthetizer/audio_engine/engine_methods/program_change.js +4 -39
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js +43 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js +5 -20
- package/src/synthetizer/audio_engine/main_processor.js +16 -20
- package/src/synthetizer/synth_constants.js +3 -1
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -32
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -33
package/package.json
CHANGED
|
@@ -4,11 +4,12 @@ import { messageTypes, midiControllers } from "../midi_message.js";
|
|
|
4
4
|
import { DEFAULT_PERCUSSION } from "../../synthetizer/synth_constants.js";
|
|
5
5
|
import { chooseBank, isSystemXG, parseBankSelect } from "../../utils/xg_hacks.js";
|
|
6
6
|
import { isGSDrumsOn, isXGOn } from "../../utils/sysex_detector.js";
|
|
7
|
+
import { SoundFontManager } from "../../synthetizer/audio_engine/engine_components/soundfont_manager.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Gets the used programs and keys for this MIDI file with a given sound bank
|
|
10
11
|
* @this {BasicMIDI}
|
|
11
|
-
* @param soundfont {BasicSoundBank
|
|
12
|
+
* @param soundfont {SoundFontManager|BasicSoundBank} - the sound bank
|
|
12
13
|
* @returns {Object<string, Set<string>>} Object<bank:program, Set<key-velocity>>
|
|
13
14
|
*/
|
|
14
15
|
export function getUsedProgramsAndKeys(soundfont)
|
|
@@ -44,9 +45,27 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
44
45
|
{
|
|
45
46
|
const bank = chooseBank(ch.bank, ch.bankLSB, ch.drums, isSystemXG(system));
|
|
46
47
|
// check if this exists in the soundfont
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
let existsBank, existsProgram;
|
|
49
|
+
if (soundfont instanceof SoundFontManager)
|
|
50
|
+
{
|
|
51
|
+
/**
|
|
52
|
+
* @type {{preset: BasicPreset, bankOffset: number}}
|
|
53
|
+
*/
|
|
54
|
+
let exists = soundfont.getPreset(bank, ch.program, isSystemXG(system));
|
|
55
|
+
existsBank = exists.preset.bank + exists.bankOffset;
|
|
56
|
+
existsProgram = exists.preset.program;
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
{
|
|
60
|
+
/**
|
|
61
|
+
* @type {BasicPreset}
|
|
62
|
+
*/
|
|
63
|
+
let exists = soundfont.getPreset(bank, ch.program, isSystemXG(system));
|
|
64
|
+
existsBank = exists.bank;
|
|
65
|
+
existsProgram = exists.program;
|
|
66
|
+
}
|
|
67
|
+
ch.actualBank = existsBank;
|
|
68
|
+
ch.program = existsProgram;
|
|
50
69
|
ch.string = ch.actualBank + ":" + ch.program;
|
|
51
70
|
if (!usedProgramsAndKeys[ch.string])
|
|
52
71
|
{
|
|
@@ -147,19 +166,18 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
147
166
|
continue;
|
|
148
167
|
}
|
|
149
168
|
const bank = event.messageData[1];
|
|
150
|
-
const realBank = Math.max(0, bank - mid.bankOffset);
|
|
151
169
|
if (isLSB)
|
|
152
170
|
{
|
|
153
|
-
ch.bankLSB =
|
|
171
|
+
ch.bankLSB = bank;
|
|
154
172
|
}
|
|
155
173
|
else
|
|
156
174
|
{
|
|
157
|
-
ch.bank =
|
|
175
|
+
ch.bank = bank;
|
|
158
176
|
}
|
|
159
177
|
// interpret the bank
|
|
160
178
|
const intepretation = parseBankSelect(
|
|
161
179
|
ch.bank,
|
|
162
|
-
|
|
180
|
+
bank,
|
|
163
181
|
system,
|
|
164
182
|
isLSB,
|
|
165
183
|
ch.drums,
|
|
@@ -57,41 +57,36 @@ export function loadNewSequence(parsedMidi, autoPlay = true)
|
|
|
57
57
|
*/
|
|
58
58
|
this.midiData = parsedMidi;
|
|
59
59
|
|
|
60
|
+
// clear old embedded bank if exists
|
|
61
|
+
this.synth.clearEmbeddedBank();
|
|
62
|
+
|
|
60
63
|
// check for embedded soundfont
|
|
61
64
|
if (this.midiData.embeddedSoundFont !== undefined)
|
|
62
65
|
{
|
|
63
66
|
SpessaSynthInfo("%cEmbedded soundfont detected! Using it.", consoleColors.recognized);
|
|
64
67
|
this.synth.setEmbeddedSoundFont(this.midiData.embeddedSoundFont, this.midiData.bankOffset);
|
|
65
68
|
}
|
|
66
|
-
|
|
69
|
+
|
|
70
|
+
SpessaSynthGroupCollapsed("%cPreloading samples...", consoleColors.info);
|
|
71
|
+
// smart preloading: load only samples used in the midi!
|
|
72
|
+
const used = this.midiData.getUsedProgramsAndKeys(this.synth.soundfontManager);
|
|
73
|
+
for (const [programBank, combos] of Object.entries(used))
|
|
67
74
|
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for (const
|
|
75
|
+
const [bank, program] = programBank.split(":").map(Number);
|
|
76
|
+
const preset = this.synth.getPreset(bank, program);
|
|
77
|
+
SpessaSynthInfo(
|
|
78
|
+
`%cPreloading used samples on %c${preset.presetName}%c...`,
|
|
79
|
+
consoleColors.info,
|
|
80
|
+
consoleColors.recognized,
|
|
81
|
+
consoleColors.info
|
|
82
|
+
);
|
|
83
|
+
for (const combo of combos)
|
|
77
84
|
{
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const preset = this.synth.getPreset(bank, program);
|
|
81
|
-
SpessaSynthInfo(
|
|
82
|
-
`%cPreloading used samples on %c${preset.presetName}%c...`,
|
|
83
|
-
consoleColors.info,
|
|
84
|
-
consoleColors.recognized,
|
|
85
|
-
consoleColors.info
|
|
86
|
-
);
|
|
87
|
-
for (const combo of combos)
|
|
88
|
-
{
|
|
89
|
-
const split = combo.split("-");
|
|
90
|
-
preset.preloadSpecific(parseInt(split[0]), parseInt(split[1]));
|
|
91
|
-
}
|
|
85
|
+
const [midiNote, velocity] = combo.split("-").map(Number);
|
|
86
|
+
this.synth.getVoicesForPreset(preset, bank, program, midiNote, velocity, midiNote);
|
|
92
87
|
}
|
|
93
|
-
SpessaSynthGroupEnd();
|
|
94
88
|
}
|
|
89
|
+
SpessaSynthGroupEnd();
|
|
95
90
|
|
|
96
91
|
/**
|
|
97
92
|
* the midi track data
|
|
@@ -44,12 +44,6 @@ export class BasicPreset
|
|
|
44
44
|
*/
|
|
45
45
|
presetZones = [];
|
|
46
46
|
|
|
47
|
-
/**
|
|
48
|
-
* Stores already found getSamplesAndGenerators for reuse
|
|
49
|
-
* @type {SampleAndGenerators[][][]}
|
|
50
|
-
*/
|
|
51
|
-
foundSamplesAndGenerators = [];
|
|
52
|
-
|
|
53
47
|
/**
|
|
54
48
|
* unused metadata
|
|
55
49
|
* @type {number}
|
|
@@ -73,15 +67,6 @@ export class BasicPreset
|
|
|
73
67
|
constructor(parentSoundBank)
|
|
74
68
|
{
|
|
75
69
|
this.parentSoundBank = parentSoundBank;
|
|
76
|
-
for (let i = 0; i < 128; i++)
|
|
77
|
-
{
|
|
78
|
-
this.foundSamplesAndGenerators[i] = [];
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
clearCache()
|
|
83
|
-
{
|
|
84
|
-
this.foundSamplesAndGenerators = [];
|
|
85
70
|
}
|
|
86
71
|
|
|
87
72
|
/**
|
|
@@ -136,34 +121,13 @@ export class BasicPreset
|
|
|
136
121
|
}
|
|
137
122
|
|
|
138
123
|
/**
|
|
139
|
-
*
|
|
140
|
-
* @param key {number}
|
|
141
|
-
* @param velocity {number}
|
|
142
|
-
*/
|
|
143
|
-
preloadSpecific(key, velocity)
|
|
144
|
-
{
|
|
145
|
-
this.getSamplesAndGenerators(key, velocity).forEach(samandgen =>
|
|
146
|
-
{
|
|
147
|
-
if (!samandgen.sample.isSampleLoaded)
|
|
148
|
-
{
|
|
149
|
-
samandgen.sample.getAudioData();
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Returns generatorTranslator and generators for given note
|
|
124
|
+
* Returns samples and generators for given note
|
|
156
125
|
* @param midiNote {number}
|
|
157
126
|
* @param velocity {number}
|
|
158
127
|
* @returns {SampleAndGenerators[]}
|
|
159
128
|
*/
|
|
160
129
|
getSamplesAndGenerators(midiNote, velocity)
|
|
161
130
|
{
|
|
162
|
-
const memorized = this.foundSamplesAndGenerators[midiNote][velocity];
|
|
163
|
-
if (memorized)
|
|
164
|
-
{
|
|
165
|
-
return memorized;
|
|
166
|
-
}
|
|
167
131
|
|
|
168
132
|
if (this.presetZones.length < 1)
|
|
169
133
|
{
|
|
@@ -333,9 +297,6 @@ export class BasicPreset
|
|
|
333
297
|
});
|
|
334
298
|
});
|
|
335
299
|
});
|
|
336
|
-
|
|
337
|
-
// save and return
|
|
338
|
-
this.foundSamplesAndGenerators[midiNote][velocity] = parsedGeneratorsAndSamples;
|
|
339
300
|
return parsedGeneratorsAndSamples;
|
|
340
301
|
}
|
|
341
302
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SpessaSynthWarn } from "../../../utils/loggin.js";
|
|
1
|
+
import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
|
|
2
2
|
import { isXGDrums } from "../../../utils/xg_hacks.js";
|
|
3
|
+
import { EMBEDDED_SOUND_BANK_ID } from "../../synth_constants.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {Object} SoundFontType
|
|
@@ -47,7 +48,8 @@ export class SoundFontManager
|
|
|
47
48
|
const presets = new Set();
|
|
48
49
|
for (const p of font.soundfont.presets)
|
|
49
50
|
{
|
|
50
|
-
const
|
|
51
|
+
const bank = Math.min(128, p.bank + font.bankOffset);
|
|
52
|
+
const presetString = `${bank}-${p.program}`;
|
|
51
53
|
if (presets.has(presetString))
|
|
52
54
|
{
|
|
53
55
|
continue;
|
|
@@ -86,11 +88,8 @@ export class SoundFontManager
|
|
|
86
88
|
*/
|
|
87
89
|
reloadManager(soundFont)
|
|
88
90
|
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
* @type {SoundFontType[]}
|
|
92
|
-
*/
|
|
93
|
-
this.soundfontList = [];
|
|
91
|
+
// do not clear the embedded bank
|
|
92
|
+
this.soundfontList = this.soundfontList.filter(sf => sf.id === EMBEDDED_SOUND_BANK_ID);
|
|
94
93
|
this.soundfontList.push({
|
|
95
94
|
id: "main",
|
|
96
95
|
bankOffset: 0,
|
|
@@ -114,7 +113,7 @@ export class SoundFontManager
|
|
|
114
113
|
const index = this.soundfontList.findIndex(s => s.id === id);
|
|
115
114
|
if (index === -1)
|
|
116
115
|
{
|
|
117
|
-
|
|
116
|
+
SpessaSynthInfo(`No soundfont with id of "${id}" found. Aborting!`);
|
|
118
117
|
return;
|
|
119
118
|
}
|
|
120
119
|
delete this.soundfontList[index].soundfont.presets;
|
|
@@ -145,6 +144,15 @@ export class SoundFontManager
|
|
|
145
144
|
this.generatePresetList();
|
|
146
145
|
}
|
|
147
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Gets the current soundfont order
|
|
149
|
+
* @returns {string[]}
|
|
150
|
+
*/
|
|
151
|
+
getCurrentSoundFontOrder()
|
|
152
|
+
{
|
|
153
|
+
return this.soundfontList.map(s => s.id);
|
|
154
|
+
}
|
|
155
|
+
|
|
148
156
|
// noinspection JSUnusedGlobalSymbols
|
|
149
157
|
/**
|
|
150
158
|
* Rearranges the soundfonts
|
|
@@ -163,7 +171,7 @@ export class SoundFontManager
|
|
|
163
171
|
* @param bankNumber {number}
|
|
164
172
|
* @param programNumber {number}
|
|
165
173
|
* @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
|
|
166
|
-
* @returns {BasicPreset} the preset
|
|
174
|
+
* @returns {{preset: BasicPreset, bankOffset: number}} the preset and its bank offset
|
|
167
175
|
*/
|
|
168
176
|
getPreset(bankNumber, programNumber, allowXGDrums = false)
|
|
169
177
|
{
|
|
@@ -171,21 +179,24 @@ export class SoundFontManager
|
|
|
171
179
|
{
|
|
172
180
|
throw new Error("No soundfonts! Did you forget to add one?");
|
|
173
181
|
}
|
|
182
|
+
const isDrum = bankNumber === 128 || (allowXGDrums && isXGDrums(bankNumber));
|
|
174
183
|
for (const sf of this.soundfontList)
|
|
175
184
|
{
|
|
176
185
|
// check for the preset (with given offset)
|
|
177
186
|
const preset = sf.soundfont.getPresetNoFallback(
|
|
178
|
-
bankNumber - sf.bankOffset,
|
|
187
|
+
bankNumber === 128 ? 128 : bankNumber - sf.bankOffset,
|
|
179
188
|
programNumber,
|
|
180
189
|
allowXGDrums
|
|
181
190
|
);
|
|
182
191
|
if (preset !== undefined)
|
|
183
192
|
{
|
|
184
|
-
return
|
|
193
|
+
return {
|
|
194
|
+
preset: preset,
|
|
195
|
+
bankOffset: sf.bankOffset
|
|
196
|
+
};
|
|
185
197
|
}
|
|
186
198
|
// if not found, advance to the next soundfont
|
|
187
199
|
}
|
|
188
|
-
const isDrum = bankNumber === 128 || (allowXGDrums && isXGDrums(bankNumber));
|
|
189
200
|
// if none found, return the first correct preset found
|
|
190
201
|
if (!isDrum)
|
|
191
202
|
{
|
|
@@ -195,11 +206,18 @@ export class SoundFontManager
|
|
|
195
206
|
allowXGDrums));
|
|
196
207
|
if (preset)
|
|
197
208
|
{
|
|
198
|
-
return
|
|
209
|
+
return {
|
|
210
|
+
preset: preset,
|
|
211
|
+
bankOffset: sf.bankOffset
|
|
212
|
+
};
|
|
199
213
|
}
|
|
200
214
|
}
|
|
201
215
|
// if nothing at all, use the first preset
|
|
202
|
-
|
|
216
|
+
const sf = this.soundfontList[0];
|
|
217
|
+
return {
|
|
218
|
+
preset: sf.soundfont.presets[0],
|
|
219
|
+
bankOffset: sf.bankOffset
|
|
220
|
+
};
|
|
203
221
|
}
|
|
204
222
|
else
|
|
205
223
|
{
|
|
@@ -209,17 +227,27 @@ export class SoundFontManager
|
|
|
209
227
|
const p = sf.soundfont.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNumber);
|
|
210
228
|
if (p)
|
|
211
229
|
{
|
|
212
|
-
return
|
|
230
|
+
return {
|
|
231
|
+
preset: p,
|
|
232
|
+
bankOffset: sf.bankOffset
|
|
233
|
+
};
|
|
213
234
|
}
|
|
214
235
|
// check for any drum preset
|
|
215
236
|
const preset = sf.soundfont.presets.find(p => p.isDrumPreset(allowXGDrums));
|
|
216
237
|
if (preset)
|
|
217
238
|
{
|
|
218
|
-
return
|
|
239
|
+
return {
|
|
240
|
+
preset: preset,
|
|
241
|
+
bankOffset: sf.bankOffset
|
|
242
|
+
};
|
|
219
243
|
}
|
|
220
244
|
}
|
|
221
245
|
// if nothing at all, use the first preset
|
|
222
|
-
|
|
246
|
+
const sf = this.soundfontList[0];
|
|
247
|
+
return {
|
|
248
|
+
preset: sf.soundfont.presets[0],
|
|
249
|
+
bankOffset: sf.bankOffset
|
|
250
|
+
};
|
|
223
251
|
}
|
|
224
252
|
}
|
|
225
253
|
|
|
@@ -9,7 +9,6 @@ import { VolumeEnvelope } from "./volume_envelope.js";
|
|
|
9
9
|
import { ModulationEnvelope } from "./modulation_envelope.js";
|
|
10
10
|
import { addAndClampGenerator, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
|
|
11
11
|
import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
12
|
-
import { isSystemXG } from "../../../utils/xg_hacks.js";
|
|
13
12
|
|
|
14
13
|
const EXCLUSIVE_CUTOFF_TIME = -2320;
|
|
15
14
|
const EXCLUSIVE_MOD_CUTOFF_TIME = -1130; // less because filter shenanigans
|
|
@@ -162,12 +161,6 @@ class Voice
|
|
|
162
161
|
*/
|
|
163
162
|
isInRelease = false;
|
|
164
163
|
|
|
165
|
-
/**
|
|
166
|
-
* MIDI channel number.
|
|
167
|
-
* @type {number}
|
|
168
|
-
*/
|
|
169
|
-
channelNumber = 0;
|
|
170
|
-
|
|
171
164
|
/**
|
|
172
165
|
* Velocity of the note.
|
|
173
166
|
* @type {number}
|
|
@@ -272,7 +265,6 @@ class Voice
|
|
|
272
265
|
* @param audioSample {AudioSample}
|
|
273
266
|
* @param midiNote {number}
|
|
274
267
|
* @param velocity {number}
|
|
275
|
-
* @param channel {number}
|
|
276
268
|
* @param currentTime {number}
|
|
277
269
|
* @param targetKey {number}
|
|
278
270
|
* @param realKey {number}
|
|
@@ -284,7 +276,6 @@ class Voice
|
|
|
284
276
|
audioSample,
|
|
285
277
|
midiNote,
|
|
286
278
|
velocity,
|
|
287
|
-
channel,
|
|
288
279
|
currentTime,
|
|
289
280
|
targetKey,
|
|
290
281
|
realKey,
|
|
@@ -301,7 +292,6 @@ class Voice
|
|
|
301
292
|
|
|
302
293
|
this.velocity = velocity;
|
|
303
294
|
this.midiNote = midiNote;
|
|
304
|
-
this.channelNumber = channel;
|
|
305
295
|
this.startTime = currentTime;
|
|
306
296
|
this.targetKey = targetKey;
|
|
307
297
|
this.realKey = realKey;
|
|
@@ -333,7 +323,6 @@ class Voice
|
|
|
333
323
|
sample,
|
|
334
324
|
voice.midiNote,
|
|
335
325
|
voice.velocity,
|
|
336
|
-
voice.channelNumber,
|
|
337
326
|
currentTime,
|
|
338
327
|
voice.targetKey,
|
|
339
328
|
realKey,
|
|
@@ -372,53 +361,21 @@ class Voice
|
|
|
372
361
|
}
|
|
373
362
|
|
|
374
363
|
/**
|
|
375
|
-
* @param
|
|
364
|
+
* @param preset {BasicPreset} the preset to get voices for
|
|
365
|
+
* @param bank {number} the bank to cache the voices in
|
|
366
|
+
* @param program {number} program to cache the voices in
|
|
376
367
|
* @param midiNote {number} the MIDI note to use
|
|
377
368
|
* @param velocity {number} the velocity to use
|
|
378
369
|
* @param realKey {number} the real MIDI note if the "midiNote" was changed by MIDI Tuning Standard
|
|
379
370
|
* @this {SpessaSynthProcessor}
|
|
380
371
|
* @returns {Voice[]} output is an array of Voices
|
|
381
372
|
*/
|
|
382
|
-
export function
|
|
383
|
-
midiNote,
|
|
384
|
-
velocity,
|
|
385
|
-
realKey)
|
|
373
|
+
export function getVoicesForPreset(preset, bank, program, midiNote, velocity, realKey)
|
|
386
374
|
{
|
|
387
375
|
/**
|
|
388
376
|
* @type {Voice[]}
|
|
389
377
|
*/
|
|
390
|
-
|
|
391
|
-
const channelObject = this.midiAudioChannels[channel];
|
|
392
|
-
|
|
393
|
-
// override patch
|
|
394
|
-
const overridePatch = this.keyModifierManager.hasOverridePatch(channel, midiNote);
|
|
395
|
-
|
|
396
|
-
let bank = channelObject.getBankSelect();
|
|
397
|
-
let program = channelObject.preset.program;
|
|
398
|
-
if (overridePatch)
|
|
399
|
-
{
|
|
400
|
-
const override = this.keyModifierManager.getPatch(channel, midiNote);
|
|
401
|
-
bank = override.bank;
|
|
402
|
-
program = override.program;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const cached = this.getCachedVoice(bank, program, midiNote, velocity);
|
|
406
|
-
// if cached, return it!
|
|
407
|
-
if (cached !== undefined)
|
|
408
|
-
{
|
|
409
|
-
return cached.map(v => Voice.copy(v, this.currentSynthTime, realKey));
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// not cached...
|
|
413
|
-
let preset = channelObject.preset;
|
|
414
|
-
if (overridePatch)
|
|
415
|
-
{
|
|
416
|
-
preset = this.soundfontManager.getPreset(bank, program, isSystemXG(this.system));
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* @returns {Voice[]}
|
|
420
|
-
*/
|
|
421
|
-
voices = preset.getSamplesAndGenerators(midiNote, velocity)
|
|
378
|
+
const voices = preset.getSamplesAndGenerators(midiNote, velocity)
|
|
422
379
|
.reduce((voices, sampleAndGenerators) =>
|
|
423
380
|
{
|
|
424
381
|
if (sampleAndGenerators.sample.getAudioData() === undefined)
|
|
@@ -501,7 +458,6 @@ export function getVoices(channel,
|
|
|
501
458
|
audioSample,
|
|
502
459
|
midiNote,
|
|
503
460
|
velocity,
|
|
504
|
-
channel,
|
|
505
461
|
this.currentSynthTime,
|
|
506
462
|
targetKey,
|
|
507
463
|
realKey,
|
|
@@ -515,4 +471,44 @@ export function getVoices(channel,
|
|
|
515
471
|
this.setCachedVoice(bank, program, midiNote, velocity, voices.map(v =>
|
|
516
472
|
Voice.copy(v, this.currentSynthTime, realKey)));
|
|
517
473
|
return voices;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* @param channel {number} a hint for the processor to recalculate sample cursors when sample dumping
|
|
478
|
+
* @param midiNote {number} the MIDI note to use
|
|
479
|
+
* @param velocity {number} the velocity to use
|
|
480
|
+
* @param realKey {number} the real MIDI note if the "midiNote" was changed by MIDI Tuning Standard
|
|
481
|
+
* @this {SpessaSynthProcessor}
|
|
482
|
+
* @returns {Voice[]} output is an array of Voices
|
|
483
|
+
*/
|
|
484
|
+
export function getVoices(channel, midiNote, velocity, realKey)
|
|
485
|
+
{
|
|
486
|
+
const channelObject = this.midiAudioChannels[channel];
|
|
487
|
+
|
|
488
|
+
// override patch
|
|
489
|
+
const overridePatch = this.keyModifierManager.hasOverridePatch(channel, midiNote);
|
|
490
|
+
|
|
491
|
+
let bank = channelObject.getBankSelect();
|
|
492
|
+
let program = channelObject.preset.program;
|
|
493
|
+
if (overridePatch)
|
|
494
|
+
{
|
|
495
|
+
const override = this.keyModifierManager.getPatch(channel, midiNote);
|
|
496
|
+
bank = override.bank;
|
|
497
|
+
program = override.program;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const cached = this.getCachedVoice(bank, program, midiNote, velocity);
|
|
501
|
+
// if cached, return it!
|
|
502
|
+
if (cached !== undefined)
|
|
503
|
+
{
|
|
504
|
+
return cached.map(v => Voice.copy(v, this.currentSynthTime, realKey));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// not cached...
|
|
508
|
+
let preset = channelObject.preset;
|
|
509
|
+
if (overridePatch)
|
|
510
|
+
{
|
|
511
|
+
preset = this.getPreset(bank, program);
|
|
512
|
+
}
|
|
513
|
+
return this.getVoicesForPreset(preset, bank, program, midiNote, velocity, realKey);
|
|
518
514
|
}
|
|
@@ -43,7 +43,6 @@ export function resetAllControllers(log = true)
|
|
|
43
43
|
if (channelNumber % 16 === DEFAULT_PERCUSSION)
|
|
44
44
|
{
|
|
45
45
|
ch.setPreset(this.drumPreset);
|
|
46
|
-
ch.presetUsesOverride = this.defaultDrumsUsesOverride;
|
|
47
46
|
ch.drumChannel = true;
|
|
48
47
|
this.callEvent("drumchange", {
|
|
49
48
|
channel: channelNumber,
|
|
@@ -53,7 +52,6 @@ export function resetAllControllers(log = true)
|
|
|
53
52
|
else
|
|
54
53
|
{
|
|
55
54
|
ch.drumChannel = false;
|
|
56
|
-
ch.presetUsesOverride = this.defaultDrumsUsesOverride;
|
|
57
55
|
ch.setPreset(this.defaultPreset);
|
|
58
56
|
this.callEvent("drumchange", {
|
|
59
57
|
channel: channelNumber,
|
|
@@ -70,13 +68,11 @@ export function resetAllControllers(log = true)
|
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
const presetBank = ch.preset.bank;
|
|
73
|
-
const sentBank = presetBank === 128 ? 128 : (ch.presetUsesOverride ? presetBank + this.soundfontBankOffset : presetBank);
|
|
74
|
-
|
|
75
71
|
// call program change
|
|
76
72
|
this.callEvent("programchange", {
|
|
77
73
|
channel: channelNumber,
|
|
78
74
|
program: ch.preset.program,
|
|
79
|
-
bank:
|
|
75
|
+
bank: presetBank
|
|
80
76
|
});
|
|
81
77
|
|
|
82
78
|
for (let ccNum = 0; ccNum < 128; ccNum++)
|
|
@@ -11,51 +11,16 @@ export function programChange(programNumber)
|
|
|
11
11
|
}
|
|
12
12
|
// always 128 for percussion
|
|
13
13
|
let bank = this.getBankSelect();
|
|
14
|
-
let sentBank;
|
|
15
|
-
/**
|
|
16
|
-
* @type {BasicPreset}
|
|
17
|
-
*/
|
|
18
|
-
let preset;
|
|
19
14
|
|
|
20
15
|
const isXG = this.isXGChannel;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
const bankWithOffset = bank === 128 ? 128 : bank - this.synth.soundfontBankOffset;
|
|
25
|
-
const p = this.synth.overrideSoundfont.getPresetNoFallback(
|
|
26
|
-
bankWithOffset,
|
|
27
|
-
programNumber,
|
|
28
|
-
isXG
|
|
29
|
-
);
|
|
30
|
-
if (p)
|
|
31
|
-
{
|
|
32
|
-
sentBank = p.bank === 128 ? 128 : p.bank + this.synth.soundfontBankOffset;
|
|
33
|
-
preset = p;
|
|
34
|
-
this.presetUsesOverride = true;
|
|
35
|
-
}
|
|
36
|
-
else
|
|
37
|
-
{
|
|
38
|
-
preset = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
39
|
-
const offset = this.synth.soundfontManager.soundfontList
|
|
40
|
-
.find(s => s.soundfont === preset.parentSoundBank).bankOffset;
|
|
41
|
-
sentBank = preset.bank - offset;
|
|
42
|
-
this.presetUsesOverride = false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
else
|
|
46
|
-
{
|
|
47
|
-
preset = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
48
|
-
const offset = this.synth.soundfontManager.soundfontList
|
|
49
|
-
.find(s => s.soundfont === preset.parentSoundBank).bankOffset;
|
|
50
|
-
sentBank = preset.bank - offset;
|
|
51
|
-
this.presetUsesOverride = false;
|
|
52
|
-
}
|
|
16
|
+
const p = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
17
|
+
const preset = p.preset;
|
|
53
18
|
this.setPreset(preset);
|
|
54
|
-
this.sentBank =
|
|
19
|
+
this.sentBank = Math.min(128, preset.bank + p.bankOffset);
|
|
55
20
|
this.synth.callEvent("programchange", {
|
|
56
21
|
channel: this.channelNumber,
|
|
57
22
|
program: preset.program,
|
|
58
|
-
bank: sentBank
|
|
23
|
+
bank: this.sentBank
|
|
59
24
|
});
|
|
60
25
|
this.sendChannelProperty();
|
|
61
26
|
}
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { loadSoundFont } from "../../../../soundfont/load_soundfont.js";
|
|
2
|
+
import { SpessaSynthInfo } from "../../../../utils/loggin.js";
|
|
3
|
+
import { consoleColors } from "../../../../utils/other.js";
|
|
4
|
+
import { EMBEDDED_SOUND_BANK_ID } from "../../../synth_constants.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @this {SpessaSynthProcessor}
|
|
8
|
+
*/
|
|
9
|
+
export function clearEmbeddedBank()
|
|
10
|
+
{
|
|
11
|
+
if (this.soundfontManager.soundfontList.some(s => s.id === EMBEDDED_SOUND_BANK_ID))
|
|
12
|
+
{
|
|
13
|
+
this.soundfontManager.deleteSoundFont(EMBEDDED_SOUND_BANK_ID);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Sets the embedded (RMI soundfont)
|
|
19
|
+
* @param font {ArrayBuffer}
|
|
20
|
+
* @param offset {number}
|
|
21
|
+
* @this {SpessaSynthProcessor}
|
|
22
|
+
*/
|
|
23
|
+
export function setEmbeddedSoundFont(font, offset)
|
|
24
|
+
{
|
|
25
|
+
// the embedded bank is set as the first bank in the manager,
|
|
26
|
+
// with a special ID that does not clear when reloadManager is performed.
|
|
27
|
+
this.soundfontBankOffset = offset;
|
|
28
|
+
const loadedFont = loadSoundFont(font);
|
|
29
|
+
this.soundfontManager.addNewSoundFont(loadedFont, EMBEDDED_SOUND_BANK_ID, offset);
|
|
30
|
+
// rearrange so the embedded is first (most important as it overrides all others)
|
|
31
|
+
const order = this.soundfontManager.getCurrentSoundFontOrder();
|
|
32
|
+
order.pop();
|
|
33
|
+
order.unshift(EMBEDDED_SOUND_BANK_ID);
|
|
34
|
+
this.soundfontManager.rearrangeSoundFonts(order);
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
// apply snapshot again if applicable
|
|
38
|
+
if (this._snapshot !== undefined)
|
|
39
|
+
{
|
|
40
|
+
this.applySynthesizerSnapshot(this._snapshot);
|
|
41
|
+
}
|
|
42
|
+
SpessaSynthInfo(`%cEmbedded sound bank set at offset %c${offset}`, consoleColors.recognized, consoleColors.value);
|
|
43
|
+
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { isSystemXG } from "../../../../utils/xg_hacks.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @this {SpessaSynthProcessor}
|
|
5
|
-
* @param program {number}
|
|
6
|
-
* @param bank {number}
|
|
7
|
-
* @returns {BasicPreset}
|
|
8
|
-
*/
|
|
9
|
-
export function getPreset(bank, program)
|
|
10
|
-
{
|
|
11
|
-
if (this.overrideSoundfont)
|
|
12
|
-
{
|
|
13
|
-
// if override soundfont
|
|
14
|
-
const bankWithOffset = bank === 128 ? 128 : bank - this.soundfontBankOffset;
|
|
15
|
-
const preset = this.overrideSoundfont.getPresetNoFallback(bankWithOffset, program, isSystemXG(this.system));
|
|
16
|
-
if (preset)
|
|
17
|
-
{
|
|
18
|
-
return preset;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return this.soundfontManager.getPreset(bank, program, isSystemXG(this.system));
|
|
22
|
-
}
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js
CHANGED
|
@@ -7,28 +7,13 @@ export function updatePresetList()
|
|
|
7
7
|
* @type {{bank: number, presetName: string, program: number}[]}
|
|
8
8
|
*/
|
|
9
9
|
const mainFont = this.soundfontManager.getPresetList();
|
|
10
|
-
if (this.overrideSoundfont !== undefined)
|
|
11
|
-
{
|
|
12
|
-
this.overrideSoundfont.presets.forEach(p =>
|
|
13
|
-
{
|
|
14
|
-
const bankCheck = p.bank === 128 ? 128 : p.bank + this.soundfontBankOffset;
|
|
15
|
-
const exists = mainFont.find(pr => pr.bank === bankCheck && pr.program === p.program);
|
|
16
|
-
if (exists !== undefined)
|
|
17
|
-
{
|
|
18
|
-
exists.presetName = p.presetName;
|
|
19
|
-
}
|
|
20
|
-
else
|
|
21
|
-
{
|
|
22
|
-
mainFont.push({
|
|
23
|
-
presetName: p.presetName,
|
|
24
|
-
bank: bankCheck,
|
|
25
|
-
program: p.program
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
10
|
this.clearCache();
|
|
31
11
|
this.callEvent("presetlistchange", mainFont);
|
|
32
12
|
this.getDefaultPresets();
|
|
13
|
+
// unlock presets
|
|
14
|
+
this.midiAudioChannels.forEach(c =>
|
|
15
|
+
{
|
|
16
|
+
c.setPresetLock(false);
|
|
17
|
+
});
|
|
33
18
|
this.resetAllControllers(false);
|
|
34
19
|
}
|
|
@@ -9,13 +9,11 @@ import { masterParameterType, setMasterParameter } from "./engine_methods/contro
|
|
|
9
9
|
import { resetAllControllers } from "./engine_methods/controller_control/reset_controllers.js";
|
|
10
10
|
import { SoundFontManager } from "./engine_components/soundfont_manager.js";
|
|
11
11
|
import { KeyModifierManager } from "./engine_components/key_modifier_manager.js";
|
|
12
|
-
import { getVoices } from "./engine_components/voice.js";
|
|
12
|
+
import { getVoices, getVoicesForPreset } from "./engine_components/voice.js";
|
|
13
13
|
import { PAN_SMOOTHING_FACTOR } from "./engine_components/stereo_panner.js";
|
|
14
14
|
import { stopAllChannels } from "./engine_methods/stopping_notes/stop_all_channels.js";
|
|
15
|
-
import { setEmbeddedSoundFont } from "./engine_methods/soundfont_management/
|
|
16
|
-
import { clearSoundFont } from "./engine_methods/soundfont_management/clear_sound_font.js";
|
|
15
|
+
import { clearEmbeddedBank, setEmbeddedSoundFont } from "./engine_methods/soundfont_management/embedded_sound_bank.js";
|
|
17
16
|
import { updatePresetList } from "./engine_methods/soundfont_management/update_preset_list.js";
|
|
18
|
-
import { getPreset } from "./engine_methods/soundfont_management/get_preset.js";
|
|
19
17
|
import { transposeAllChannels } from "./engine_methods/tuning_control/transpose_all_channels.js";
|
|
20
18
|
import { setMasterTuning } from "./engine_methods/tuning_control/set_master_tuning.js";
|
|
21
19
|
import { applySynthesizerSnapshot } from "./snapshot/apply_synthesizer_snapshot.js";
|
|
@@ -26,6 +24,7 @@ import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
|
26
24
|
import { interpolationTypes } from "./engine_components/enums.js";
|
|
27
25
|
import { DEFAULT_SYNTH_OPTIONS } from "./synth_processor_options.js";
|
|
28
26
|
import { fillWithDefaults } from "../../utils/fill_with_defaults.js";
|
|
27
|
+
import { isSystemXG } from "../../utils/xg_hacks.js";
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
/**
|
|
@@ -169,7 +168,7 @@ class SpessaSynthProcessor
|
|
|
169
168
|
/**
|
|
170
169
|
* Cached voices for all presets for this synthesizer.
|
|
171
170
|
* Nesting goes like this:
|
|
172
|
-
* this.cachedVoices[bankNumber][programNumber][midiNote][velocity] = a list of
|
|
171
|
+
* this.cachedVoices[bankNumber][programNumber][midiNote][velocity] = a list of voices for that.
|
|
173
172
|
* @type {Voice[][][][][]}
|
|
174
173
|
*/
|
|
175
174
|
cachedVoices = [];
|
|
@@ -211,7 +210,6 @@ class SpessaSynthProcessor
|
|
|
211
210
|
*/
|
|
212
211
|
soundfontBankOffset = 0;
|
|
213
212
|
|
|
214
|
-
|
|
215
213
|
/**
|
|
216
214
|
* The volume gain, set by user
|
|
217
215
|
* @type {number}
|
|
@@ -270,12 +268,6 @@ class SpessaSynthProcessor
|
|
|
270
268
|
*/
|
|
271
269
|
keyModifierManager = new KeyModifierManager();
|
|
272
270
|
|
|
273
|
-
/**
|
|
274
|
-
* Overrides the main soundfont (embedded, for example)
|
|
275
|
-
* @type {BasicSoundBank}
|
|
276
|
-
*/
|
|
277
|
-
overrideSoundfont = undefined;
|
|
278
|
-
|
|
279
271
|
/**
|
|
280
272
|
* contains all the channels with their voices on the processor size
|
|
281
273
|
* @type {MidiAudioChannel[]}
|
|
@@ -299,16 +291,12 @@ class SpessaSynthProcessor
|
|
|
299
291
|
*/
|
|
300
292
|
defaultPreset;
|
|
301
293
|
|
|
302
|
-
defaultPresetUsesOverride = false;
|
|
303
|
-
|
|
304
294
|
/**
|
|
305
295
|
* Synth's default (reset) drum preset
|
|
306
296
|
* @type {BasicPreset}
|
|
307
297
|
*/
|
|
308
298
|
drumPreset;
|
|
309
299
|
|
|
310
|
-
defaultDrumsUsesOverride = false;
|
|
311
|
-
|
|
312
300
|
/**
|
|
313
301
|
* Controls if the processor is fully initialized
|
|
314
302
|
* @type {Promise<boolean>}
|
|
@@ -431,10 +419,8 @@ class SpessaSynthProcessor
|
|
|
431
419
|
const sys = this.system;
|
|
432
420
|
this.system = "xg";
|
|
433
421
|
this.defaultPreset = this.getPreset(0, 0);
|
|
434
|
-
this.defaultPresetUsesOverride = this.overrideSoundfont?.presets?.indexOf(this.defaultPreset) >= 0;
|
|
435
422
|
this.system = sys;
|
|
436
423
|
this.drumPreset = this.getPreset(128, 0);
|
|
437
|
-
this.defaultDrumsUsesOverride = this.overrideSoundfont?.presets?.indexOf(this.drumPreset) >= 0;
|
|
438
424
|
}
|
|
439
425
|
|
|
440
426
|
/**
|
|
@@ -750,11 +736,22 @@ class SpessaSynthProcessor
|
|
|
750
736
|
{
|
|
751
737
|
this.cachedVoices = [];
|
|
752
738
|
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* @param program {number}
|
|
742
|
+
* @param bank {number}
|
|
743
|
+
* @returns {BasicPreset}
|
|
744
|
+
*/
|
|
745
|
+
getPreset(bank, program)
|
|
746
|
+
{
|
|
747
|
+
return this.soundfontManager.getPreset(bank, program, isSystemXG(this.system)).preset;
|
|
748
|
+
}
|
|
753
749
|
}
|
|
754
750
|
|
|
755
751
|
// include other methods
|
|
756
752
|
// voice related
|
|
757
753
|
SpessaSynthProcessor.prototype.voiceKilling = voiceKilling;
|
|
754
|
+
SpessaSynthProcessor.prototype.getVoicesForPreset = getVoicesForPreset;
|
|
758
755
|
SpessaSynthProcessor.prototype.getVoices = getVoices;
|
|
759
756
|
|
|
760
757
|
// system-exclusive related
|
|
@@ -773,8 +770,7 @@ SpessaSynthProcessor.prototype.transposeAllChannels = transposeAllChannels;
|
|
|
773
770
|
SpessaSynthProcessor.prototype.setMasterTuning = setMasterTuning;
|
|
774
771
|
|
|
775
772
|
// program related
|
|
776
|
-
SpessaSynthProcessor.prototype.
|
|
777
|
-
SpessaSynthProcessor.prototype.clearSoundFont = clearSoundFont;
|
|
773
|
+
SpessaSynthProcessor.prototype.clearEmbeddedBank = clearEmbeddedBank;
|
|
778
774
|
SpessaSynthProcessor.prototype.setEmbeddedSoundFont = setEmbeddedSoundFont;
|
|
779
775
|
SpessaSynthProcessor.prototype.updatePresetList = updatePresetList;
|
|
780
776
|
|
|
@@ -19,4 +19,6 @@ export const MIDI_CHANNEL_COUNT = 16;
|
|
|
19
19
|
*/
|
|
20
20
|
export const DEFAULT_SYNTH_MODE = "gs";
|
|
21
21
|
|
|
22
|
-
export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
22
|
+
export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
23
|
+
|
|
24
|
+
export const EMBEDDED_SOUND_BANK_ID = `SPESSASYNTH_EMBEDDED_BANK_${Math.random()}`;
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @this {SpessaSynthProcessor}
|
|
3
|
-
* @param sendPresets {boolean}
|
|
4
|
-
* @param clearOverride {boolean}
|
|
5
|
-
*/
|
|
6
|
-
export function clearSoundFont(sendPresets = true, clearOverride = true)
|
|
7
|
-
{
|
|
8
|
-
this.stopAllChannels(true);
|
|
9
|
-
if (clearOverride)
|
|
10
|
-
{
|
|
11
|
-
delete this.overrideSoundfont;
|
|
12
|
-
this.overrideSoundfont = undefined;
|
|
13
|
-
}
|
|
14
|
-
this.getDefaultPresets();
|
|
15
|
-
this.clearCache();
|
|
16
|
-
|
|
17
|
-
if (sendPresets)
|
|
18
|
-
{
|
|
19
|
-
this.updatePresetList();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
for (let i = 0; i < this.midiAudioChannels.length; i++)
|
|
23
|
-
{
|
|
24
|
-
const channelObject = this.midiAudioChannels[i];
|
|
25
|
-
if (!clearOverride || (clearOverride && channelObject.presetUsesOverride))
|
|
26
|
-
{
|
|
27
|
-
channelObject.setPresetLock(false);
|
|
28
|
-
}
|
|
29
|
-
channelObject.programChange(channelObject.preset.program);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
}
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { loadSoundFont } from "../../../../soundfont/load_soundfont.js";
|
|
2
|
-
import { SpessaSynthInfo } from "../../../../utils/loggin.js";
|
|
3
|
-
import { consoleColors } from "../../../../utils/other.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Sets the embedded (RMI soundfont)
|
|
7
|
-
* @param font {ArrayBuffer}
|
|
8
|
-
* @param offset {number}
|
|
9
|
-
* @this {SpessaSynthProcessor}
|
|
10
|
-
*/
|
|
11
|
-
export function setEmbeddedSoundFont(font, offset)
|
|
12
|
-
{
|
|
13
|
-
// set offset
|
|
14
|
-
this.soundfontBankOffset = offset;
|
|
15
|
-
this.clearSoundFont(false, true);
|
|
16
|
-
this.overrideSoundfont = loadSoundFont(font);
|
|
17
|
-
this.updatePresetList();
|
|
18
|
-
this.getDefaultPresets();
|
|
19
|
-
this.midiAudioChannels.forEach(c =>
|
|
20
|
-
c.programChange(c.preset.program)
|
|
21
|
-
);
|
|
22
|
-
// preload all samples
|
|
23
|
-
this.overrideSoundfont.samples.forEach(s => s.getAudioData());
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// apply snapshot again if applicable
|
|
27
|
-
if (this._snapshot !== undefined)
|
|
28
|
-
{
|
|
29
|
-
this.applySynthesizerSnapshot(this._snapshot);
|
|
30
|
-
this.resetAllControllers();
|
|
31
|
-
}
|
|
32
|
-
SpessaSynthInfo("%cSpessaSynth is ready!", consoleColors.recognized);
|
|
33
|
-
}
|