spessasynth_lib 3.25.1 → 3.25.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/midi_parser/midi_editor.js +45 -28
- package/midi_parser/rmidi_writer.js +49 -35
- package/midi_parser/used_keys_loaded.js +27 -22
- package/package.json +1 -1
- package/soundfont/basic_soundfont/basic_preset.js +12 -0
- package/soundfont/basic_soundfont/basic_soundfont.js +25 -15
- package/soundfont/dls/dls_preset.js +11 -1
- package/synthetizer/worklet_processor.min.js +12 -12
- package/synthetizer/worklet_system/main_processor.js +29 -2
- package/synthetizer/worklet_system/message_protocol/handle_message.js +1 -1
- package/synthetizer/worklet_system/snapshot/channel_snapshot.js +18 -3
- package/synthetizer/worklet_system/worklet_methods/controller_control/controller_change.js +2 -9
- package/synthetizer/worklet_system/worklet_methods/controller_control/reset_controllers.js +8 -4
- package/synthetizer/worklet_system/worklet_methods/program_change.js +10 -5
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/clear_sound_font.js +2 -3
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/get_preset.js +2 -2
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js +1 -2
- package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js +20 -5
- package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +43 -20
- package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +2 -3
- package/utils/xg_hacks.js +56 -8
|
@@ -6,6 +6,7 @@ import { consoleColors } from "../utils/other.js";
|
|
|
6
6
|
import { customControllers } from "../synthetizer/worklet_system/worklet_utilities/controller_tables.js";
|
|
7
7
|
import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";
|
|
8
8
|
import { isGMOn, isGSOn, isXGOn } from "../utils/sysex_detector.js";
|
|
9
|
+
import { isXGDrums, XG_SFX_VOICE } from "../utils/xg_hacks.js";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @param ticks {number}
|
|
@@ -127,6 +128,11 @@ export function modifyMIDI(
|
|
|
127
128
|
const midi = this;
|
|
128
129
|
SpessaSynthGroupCollapsed("%cApplying changes to the MIDI file...", consoleColors.info);
|
|
129
130
|
|
|
131
|
+
SpessaSynthInfo("Desired program changes:", desiredProgramChanges);
|
|
132
|
+
SpessaSynthInfo("Desired CC changes:", desiredControllerChanges);
|
|
133
|
+
SpessaSynthInfo("Desired channels to clear:", desiredChannelsToClear);
|
|
134
|
+
SpessaSynthInfo("Desired channels to transpose:", desiredChannelsToTranspose);
|
|
135
|
+
|
|
130
136
|
/**
|
|
131
137
|
* @type {Set<number>}
|
|
132
138
|
*/
|
|
@@ -337,7 +343,7 @@ export function modifyMIDI(
|
|
|
337
343
|
if (channelsToChangeProgram.has(channel))
|
|
338
344
|
{
|
|
339
345
|
const change = desiredProgramChanges.find(c => c.channel === channel);
|
|
340
|
-
let desiredBank = change.bank;
|
|
346
|
+
let desiredBank = Math.max(0, Math.min(change.bank, 127));
|
|
341
347
|
const desiredProgram = change.program;
|
|
342
348
|
SpessaSynthInfo(
|
|
343
349
|
`%cSetting %c${change.channel}%c to %c${desiredBank}:${desiredProgram}%c. Track num: %c${trackNum}`,
|
|
@@ -362,50 +368,61 @@ export function modifyMIDI(
|
|
|
362
368
|
);
|
|
363
369
|
addEventBefore(programChange);
|
|
364
370
|
|
|
365
|
-
|
|
366
|
-
if (!change.isDrum && system === "xg")
|
|
371
|
+
const addBank = (isLSB, v) =>
|
|
367
372
|
{
|
|
368
|
-
const
|
|
373
|
+
const bankChange = getControllerChange(
|
|
369
374
|
midiChannel,
|
|
370
|
-
midiControllers.lsbForControl0BankSelect,
|
|
371
|
-
|
|
375
|
+
isLSB ? midiControllers.lsbForControl0BankSelect : midiControllers.bankSelect,
|
|
376
|
+
v,
|
|
372
377
|
e.ticks
|
|
373
378
|
);
|
|
374
|
-
addEventBefore(
|
|
375
|
-
}
|
|
379
|
+
addEventBefore(bankChange);
|
|
380
|
+
};
|
|
376
381
|
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
midiChannel,
|
|
380
|
-
midiControllers.bankSelect,
|
|
381
|
-
desiredBank,
|
|
382
|
-
e.ticks
|
|
383
|
-
);
|
|
384
|
-
addEventBefore(bankChange);
|
|
385
|
-
|
|
386
|
-
// is drums?
|
|
387
|
-
// if so, adjust
|
|
388
|
-
// do not add gs drum change on the drum channel
|
|
389
|
-
if (change.isDrum)
|
|
382
|
+
// on xg, add lsb
|
|
383
|
+
if (system === "xg")
|
|
390
384
|
{
|
|
391
|
-
|
|
385
|
+
// xg drums: msb can be 120, 126 or 127
|
|
386
|
+
if (change.isDrum)
|
|
392
387
|
{
|
|
393
388
|
SpessaSynthInfo(
|
|
394
|
-
`%cAdding
|
|
389
|
+
`%cAdding XG Drum change on track %c${trackNum}`,
|
|
395
390
|
consoleColors.recognized,
|
|
396
391
|
consoleColors.value
|
|
397
392
|
);
|
|
398
|
-
|
|
393
|
+
addBank(false, isXGDrums(desiredBank) ? desiredBank : 127);
|
|
394
|
+
addBank(true, 0);
|
|
399
395
|
}
|
|
400
|
-
else
|
|
396
|
+
else
|
|
401
397
|
{
|
|
398
|
+
// sfx voice is set via MSB
|
|
399
|
+
if (desiredBank === XG_SFX_VOICE)
|
|
400
|
+
{
|
|
401
|
+
addBank(false, XG_SFX_VOICE);
|
|
402
|
+
addBank(true, 0);
|
|
403
|
+
}
|
|
404
|
+
else
|
|
405
|
+
{
|
|
406
|
+
// add variation as LSB
|
|
407
|
+
addBank(false, 0);
|
|
408
|
+
addBank(true, desiredBank);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else
|
|
413
|
+
{
|
|
414
|
+
// add just msb
|
|
415
|
+
addBank(false, desiredBank);
|
|
416
|
+
|
|
417
|
+
if (change.isDrum && midiChannel !== DEFAULT_PERCUSSION)
|
|
418
|
+
{
|
|
419
|
+
// add gs drum change
|
|
402
420
|
SpessaSynthInfo(
|
|
403
|
-
`%cAdding
|
|
421
|
+
`%cAdding GS Drum change on track %c${trackNum}`,
|
|
404
422
|
consoleColors.recognized,
|
|
405
423
|
consoleColors.value
|
|
406
424
|
);
|
|
407
|
-
|
|
408
|
-
desiredBank = 127;
|
|
425
|
+
addEventBefore(getDrumChange(midiChannel, e.ticks));
|
|
409
426
|
}
|
|
410
427
|
}
|
|
411
428
|
}
|
|
@@ -204,46 +204,54 @@ export function writeRMIDI(
|
|
|
204
204
|
const channel = channelsInfo[chNum];
|
|
205
205
|
if (status === messageTypes.programChange)
|
|
206
206
|
{
|
|
207
|
+
const isXG = system === "xg";
|
|
207
208
|
// check if the preset for this program exists
|
|
209
|
+
const initialProgram = e.messageData[0];
|
|
208
210
|
if (channel.drums)
|
|
209
211
|
{
|
|
210
|
-
if (soundfont.presets.findIndex(p => p.program ===
|
|
212
|
+
if (soundfont.presets.findIndex(p => p.program === initialProgram && p.isDrumPreset(
|
|
213
|
+
isXG,
|
|
214
|
+
true
|
|
215
|
+
)) === -1)
|
|
211
216
|
{
|
|
212
217
|
// doesn't exist. pick any preset that has bank 128.
|
|
213
|
-
e.messageData[0] = soundfont.presets.find(p => p.
|
|
218
|
+
e.messageData[0] = soundfont.presets.find(p => p.isDrumPreset(isXG))?.program || 0;
|
|
219
|
+
SpessaSynthInfo(
|
|
220
|
+
`%cNo drum preset %c${initialProgram}%c. Channel %c${chNum}%c. Changing program to ${e.messageData[0]}.`,
|
|
221
|
+
consoleColors.info,
|
|
222
|
+
consoleColors.unrecognized,
|
|
223
|
+
consoleColors.info,
|
|
224
|
+
consoleColors.recognized,
|
|
225
|
+
consoleColors.info
|
|
226
|
+
);
|
|
214
227
|
}
|
|
215
228
|
}
|
|
216
229
|
else
|
|
217
230
|
{
|
|
218
|
-
if (soundfont.presets.findIndex(p => p.program ===
|
|
231
|
+
if (soundfont.presets.findIndex(p => p.program === initialProgram && !p.isDrumPreset(isXG)) === -1)
|
|
219
232
|
{
|
|
220
233
|
// doesn't exist. pick any preset that does not have bank 128.
|
|
221
|
-
e.messageData[0] = soundfont.presets.find(p => p.
|
|
234
|
+
e.messageData[0] = soundfont.presets.find(p => !p.isDrumPreset(isXG))?.program || 0;
|
|
235
|
+
SpessaSynthInfo(
|
|
236
|
+
`%cNo preset %c${initialProgram}%c. Channel %c${chNum}%c. Changing program to ${e.messageData[0]}.`,
|
|
237
|
+
consoleColors.info,
|
|
238
|
+
consoleColors.unrecognized,
|
|
239
|
+
consoleColors.info,
|
|
240
|
+
consoleColors.recognized,
|
|
241
|
+
consoleColors.info
|
|
242
|
+
);
|
|
222
243
|
}
|
|
223
244
|
}
|
|
224
245
|
channel.program = e.messageData[0];
|
|
225
246
|
// check if this preset exists for program and bank
|
|
226
247
|
const realBank = Math.max(0, channel.lastBank?.messageData[1] - mid.bankOffset); // make sure to take the previous bank offset into account
|
|
227
|
-
|
|
248
|
+
const bankLSB = (channel?.lastBankLSB?.messageData[1] - mid.bankOffset) || 0;
|
|
228
249
|
if (channel.lastBank === undefined)
|
|
229
250
|
{
|
|
230
251
|
continue;
|
|
231
252
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (channel.drums)
|
|
235
|
-
{
|
|
236
|
-
// drums override: set the bank to 127
|
|
237
|
-
channelsInfo[chNum].lastBank.messageData[1] = 127;
|
|
238
|
-
}
|
|
239
|
-
else
|
|
240
|
-
{
|
|
241
|
-
// potential bank lsb override
|
|
242
|
-
const bankLSB = (channel?.lastBankLSB?.messageData[1] - mid.bankOffset) || 0;
|
|
243
|
-
bank = chooseBank(bank, bankLSB);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
253
|
+
// adjust bank for XG
|
|
254
|
+
let bank = chooseBank(realBank, bankLSB, channel.drums, isXG);
|
|
247
255
|
if (soundfont.presets.findIndex(p => p.bank === bank && p.program === e.messageData[0]) === -1)
|
|
248
256
|
{
|
|
249
257
|
// no preset with this bank. find this program with any bank
|
|
@@ -254,7 +262,9 @@ export function writeRMIDI(
|
|
|
254
262
|
channel.lastBankLSB.messageData[1] = targetBank;
|
|
255
263
|
}
|
|
256
264
|
SpessaSynthInfo(
|
|
257
|
-
`%cNo preset %c${bank}:${e.messageData[0]}%c. Changing bank to ${targetBank}.`,
|
|
265
|
+
`%cNo preset %c${bank}:${e.messageData[0]}%c. Channel %c${chNum}%c. Changing bank to ${targetBank}.`,
|
|
266
|
+
consoleColors.info,
|
|
267
|
+
consoleColors.unrecognized,
|
|
258
268
|
consoleColors.info,
|
|
259
269
|
consoleColors.recognized,
|
|
260
270
|
consoleColors.info
|
|
@@ -263,15 +273,21 @@ export function writeRMIDI(
|
|
|
263
273
|
else
|
|
264
274
|
{
|
|
265
275
|
// There is a preset with this bank. Add offset. For drums add the normal offset.
|
|
266
|
-
let drumBank =
|
|
267
|
-
|
|
276
|
+
let drumBank = bank;
|
|
277
|
+
if (system === "xg" && bank === 128)
|
|
278
|
+
{
|
|
279
|
+
bank = 127;
|
|
280
|
+
}
|
|
281
|
+
const newBank = (bank === 128 ? 128 : drumBank) + bankOffset;
|
|
268
282
|
channel.lastBank.messageData[1] = newBank;
|
|
269
|
-
if (channel?.lastBankLSB?.messageData)
|
|
283
|
+
if (channel?.lastBankLSB?.messageData && !channel.drums)
|
|
270
284
|
{
|
|
271
285
|
channel.lastBankLSB.messageData[1] = channel.lastBankLSB.messageData[1] - mid.bankOffset + bankOffset;
|
|
272
286
|
}
|
|
273
287
|
SpessaSynthInfo(
|
|
274
|
-
`%cPreset %c${bank}:${e.messageData[0]}%c exists. Changing bank to ${newBank}.`,
|
|
288
|
+
`%cPreset %c${bank}:${e.messageData[0]}%c exists. Channel %c${chNum}%c. Changing bank to ${newBank}.`,
|
|
289
|
+
consoleColors.info,
|
|
290
|
+
consoleColors.recognized,
|
|
275
291
|
consoleColors.info,
|
|
276
292
|
consoleColors.recognized,
|
|
277
293
|
consoleColors.info
|
|
@@ -307,16 +323,13 @@ export function writeRMIDI(
|
|
|
307
323
|
{
|
|
308
324
|
channel.drums = false;
|
|
309
325
|
}
|
|
310
|
-
if (
|
|
326
|
+
if (isLSB)
|
|
311
327
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
{
|
|
318
|
-
channel.lastBank = e;
|
|
319
|
-
}
|
|
328
|
+
channel.lastBankLSB = e;
|
|
329
|
+
}
|
|
330
|
+
else
|
|
331
|
+
{
|
|
332
|
+
channel.lastBank = e;
|
|
320
333
|
}
|
|
321
334
|
}
|
|
322
335
|
|
|
@@ -370,7 +383,8 @@ export function writeRMIDI(
|
|
|
370
383
|
const ticks = track[indexToAdd].ticks;
|
|
371
384
|
const targetBank = (soundfont.getPreset(
|
|
372
385
|
0,
|
|
373
|
-
has.program
|
|
386
|
+
has.program,
|
|
387
|
+
system === "xg"
|
|
374
388
|
)?.bank + bankOffset) || bankOffset;
|
|
375
389
|
track.splice(indexToAdd, 0, new MIDIMessage(
|
|
376
390
|
ticks,
|
|
@@ -8,7 +8,7 @@ import { isGSDrumsOn, isXGOn } from "../utils/sysex_detector.js";
|
|
|
8
8
|
/**
|
|
9
9
|
* Gets the used programs and keys for this MIDI file with a given sound bank
|
|
10
10
|
* @this {BasicMIDI}
|
|
11
|
-
* @param soundfont {
|
|
11
|
+
* @param soundfont {BasicSoundBank|WorkletSoundfontManager} - the sound bank
|
|
12
12
|
* @returns {Object<string, Set<string>>}
|
|
13
13
|
*/
|
|
14
14
|
export function getUsedProgramsAndKeys(soundfont)
|
|
@@ -21,7 +21,7 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
21
21
|
// Find every bank:program combo and every key:velocity for each. Make sure to care about ports and drums
|
|
22
22
|
const channelsAmount = 16 + mid.midiPortChannelOffsets.reduce((max, cur) => cur > max ? cur : max);
|
|
23
23
|
/**
|
|
24
|
-
* @type {{program: number, bank: number, bankLSB: number, drums: boolean, string: string}[]}
|
|
24
|
+
* @type {{program: number, bank: number, bankLSB: number, drums: boolean, string: string, actualBank: number}[]}
|
|
25
25
|
*/
|
|
26
26
|
const channelPresets = [];
|
|
27
27
|
for (let i = 0; i < channelsAmount; i++)
|
|
@@ -31,20 +31,23 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
31
31
|
program: 0,
|
|
32
32
|
bank: bank,
|
|
33
33
|
bankLSB: 0,
|
|
34
|
+
actualBank: bank,
|
|
34
35
|
drums: i % 16 === DEFAULT_PERCUSSION, // drums appear on 9 every 16 channels,
|
|
35
36
|
string: `${bank}:0`
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
// check for xg
|
|
41
|
+
let system = "gs";
|
|
42
|
+
|
|
39
43
|
function updateString(ch)
|
|
40
44
|
{
|
|
41
|
-
const bank = chooseBank(ch.bank, ch.bankLSB);
|
|
45
|
+
const bank = chooseBank(ch.bank, ch.bankLSB, ch.drums, system === "xg");
|
|
42
46
|
// check if this exists in the soundfont
|
|
43
|
-
let exists = soundfont.getPreset(bank, ch.program);
|
|
44
|
-
ch.
|
|
45
|
-
ch.bankLSB = 0;
|
|
47
|
+
let exists = soundfont.getPreset(bank, ch.program, system === "xg");
|
|
48
|
+
ch.actualBank = exists.bank;
|
|
46
49
|
ch.program = exists.program;
|
|
47
|
-
ch.string = ch.
|
|
50
|
+
ch.string = ch.actualBank + ":" + ch.program;
|
|
48
51
|
if (!usedProgramsAndKeys[ch.string])
|
|
49
52
|
{
|
|
50
53
|
SpessaSynthInfo(
|
|
@@ -90,8 +93,11 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
const ports = mid.midiPorts.slice();
|
|
93
|
-
//
|
|
94
|
-
|
|
96
|
+
// initialize
|
|
97
|
+
channelPresets.forEach(c =>
|
|
98
|
+
{
|
|
99
|
+
updateString(c);
|
|
100
|
+
});
|
|
95
101
|
while (remainingTracks > 0)
|
|
96
102
|
{
|
|
97
103
|
let trackNum = findFirstEventIndex();
|
|
@@ -142,6 +148,14 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
142
148
|
}
|
|
143
149
|
const bank = event.messageData[1];
|
|
144
150
|
const realBank = Math.max(0, bank - mid.bankOffset);
|
|
151
|
+
if (isLSB)
|
|
152
|
+
{
|
|
153
|
+
ch.bankLSB = realBank;
|
|
154
|
+
}
|
|
155
|
+
else
|
|
156
|
+
{
|
|
157
|
+
ch.bank = realBank;
|
|
158
|
+
}
|
|
145
159
|
// interpret the bank
|
|
146
160
|
const intepretation = parseBankSelect(
|
|
147
161
|
ch.bank,
|
|
@@ -151,7 +165,6 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
151
165
|
ch.drums,
|
|
152
166
|
channel
|
|
153
167
|
);
|
|
154
|
-
|
|
155
168
|
switch (intepretation.drumsStatus)
|
|
156
169
|
{
|
|
157
170
|
case 0:
|
|
@@ -162,7 +175,6 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
162
175
|
// drums changed to off
|
|
163
176
|
// drum change is a program change
|
|
164
177
|
ch.drums = false;
|
|
165
|
-
ch.bank = realBank;
|
|
166
178
|
updateString(ch);
|
|
167
179
|
break;
|
|
168
180
|
|
|
@@ -170,18 +182,9 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
170
182
|
// drums changed to on
|
|
171
183
|
// drum change is a program change
|
|
172
184
|
ch.drums = true;
|
|
173
|
-
ch.bank = 128;
|
|
174
185
|
updateString(ch);
|
|
175
186
|
break;
|
|
176
187
|
}
|
|
177
|
-
if (isLSB)
|
|
178
|
-
{
|
|
179
|
-
ch.bankLSB = intepretation.newBank;
|
|
180
|
-
}
|
|
181
|
-
else
|
|
182
|
-
{
|
|
183
|
-
ch.bank = ch.drums ? 128 : intepretation.newBank;
|
|
184
|
-
}
|
|
185
188
|
// do not update the data, bank change doesn't change the preset
|
|
186
189
|
break;
|
|
187
190
|
|
|
@@ -191,7 +194,6 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
191
194
|
// that's a note off
|
|
192
195
|
continue;
|
|
193
196
|
}
|
|
194
|
-
updateString(ch);
|
|
195
197
|
usedProgramsAndKeys[ch.string].add(`${event.messageData[0]}-${event.messageData[1]}`);
|
|
196
198
|
break;
|
|
197
199
|
|
|
@@ -203,6 +205,10 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
203
205
|
if (isXGOn(event))
|
|
204
206
|
{
|
|
205
207
|
system = "xg";
|
|
208
|
+
SpessaSynthInfo(
|
|
209
|
+
"%cXG on detected!",
|
|
210
|
+
consoleColors.recognized
|
|
211
|
+
);
|
|
206
212
|
}
|
|
207
213
|
continue;
|
|
208
214
|
}
|
|
@@ -210,7 +216,6 @@ export function getUsedProgramsAndKeys(soundfont)
|
|
|
210
216
|
const isDrum = !!(event.messageData[7] > 0 && event.messageData[5] >> 4);
|
|
211
217
|
ch = channelPresets[sysexChannel];
|
|
212
218
|
ch.drums = isDrum;
|
|
213
|
-
ch.bank = isDrum ? 128 : 0;
|
|
214
219
|
updateString(ch);
|
|
215
220
|
break;
|
|
216
221
|
|
package/package.json
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { generatorTypes } from "./generator.js";
|
|
11
11
|
import { Modulator } from "./modulator.js";
|
|
12
|
+
import { isXGDrums } from "../../utils/xg_hacks.js";
|
|
12
13
|
|
|
13
14
|
export class BasicPreset
|
|
14
15
|
{
|
|
@@ -78,6 +79,17 @@ export class BasicPreset
|
|
|
78
79
|
this.defaultModulators = modulators;
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
/**
|
|
83
|
+
* @param allowXG {boolean}
|
|
84
|
+
* @param allowSFX {boolean}
|
|
85
|
+
* @returns {boolean}
|
|
86
|
+
*/
|
|
87
|
+
isDrumPreset(allowXG, allowSFX = false)
|
|
88
|
+
{
|
|
89
|
+
// sfx is not cool
|
|
90
|
+
return this.bank === 128 || (allowXG && isXGDrums(this.bank) && (this.bank !== 126 || allowSFX));
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
deletePreset()
|
|
82
94
|
{
|
|
83
95
|
this.presetZones.forEach(z => z.deleteZone());
|
|
@@ -14,6 +14,7 @@ import { BasicInstrumentZone, BasicPresetZone } from "./basic_zones.js";
|
|
|
14
14
|
import { Generator, generatorTypes } from "./generator.js";
|
|
15
15
|
import { BasicInstrument } from "./basic_instrument.js";
|
|
16
16
|
import { BasicPreset } from "./basic_preset.js";
|
|
17
|
+
import { isXGDrums } from "../../utils/xg_hacks.js";
|
|
17
18
|
|
|
18
19
|
class BasicSoundBank
|
|
19
20
|
{
|
|
@@ -392,54 +393,63 @@ class BasicSoundBank
|
|
|
392
393
|
* Get the appropriate preset, undefined if not foun d
|
|
393
394
|
* @param bankNr {number}
|
|
394
395
|
* @param programNr {number}
|
|
395
|
-
* @param
|
|
396
|
+
* @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
|
|
396
397
|
* @return {BasicPreset}
|
|
397
398
|
*/
|
|
398
|
-
getPresetNoFallback(bankNr, programNr,
|
|
399
|
+
getPresetNoFallback(bankNr, programNr, allowXGDrums = false)
|
|
399
400
|
{
|
|
401
|
+
// check for exact match
|
|
400
402
|
const p = this.presets.find(p => p.bank === bankNr && p.program === programNr);
|
|
401
403
|
if (p)
|
|
402
404
|
{
|
|
403
405
|
return p;
|
|
404
406
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
if (bankNr === 128)
|
|
407
|
+
// no match...
|
|
408
|
+
const isDrum = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
|
|
409
|
+
if (isDrum)
|
|
410
410
|
{
|
|
411
|
-
|
|
412
|
-
|
|
411
|
+
if (allowXGDrums)
|
|
412
|
+
{
|
|
413
|
+
// try any drum preset with matching program?
|
|
414
|
+
const p = this.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNr);
|
|
415
|
+
if (p)
|
|
416
|
+
{
|
|
417
|
+
return p;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
413
420
|
}
|
|
414
|
-
return
|
|
421
|
+
return undefined;
|
|
415
422
|
}
|
|
416
423
|
|
|
417
424
|
/**
|
|
418
425
|
* Get the appropriate preset
|
|
419
426
|
* @param bankNr {number}
|
|
420
427
|
* @param programNr {number}
|
|
428
|
+
* @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
|
|
421
429
|
* @returns {BasicPreset}
|
|
422
430
|
*/
|
|
423
|
-
getPreset(bankNr, programNr)
|
|
431
|
+
getPreset(bankNr, programNr, allowXGDrums = false)
|
|
424
432
|
{
|
|
425
433
|
// check for exact match
|
|
426
434
|
let preset = this.presets.find(p => p.bank === bankNr && p.program === programNr);
|
|
435
|
+
const isDrums = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
|
|
427
436
|
if (!preset)
|
|
428
437
|
{
|
|
429
438
|
// no match...
|
|
430
|
-
if (
|
|
439
|
+
if (isDrums)
|
|
431
440
|
{
|
|
432
441
|
// drum preset: find any preset with bank 128
|
|
433
|
-
preset = this.presets.find(p => p.
|
|
442
|
+
preset = this.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNr);
|
|
434
443
|
if (!preset)
|
|
435
444
|
{
|
|
436
|
-
|
|
445
|
+
// only allow 128, otherwise it would default to XG SFX
|
|
446
|
+
preset = this.presets.find(p => p.isDrumPreset(allowXGDrums));
|
|
437
447
|
}
|
|
438
448
|
}
|
|
439
449
|
else
|
|
440
450
|
{
|
|
441
451
|
// non-drum preset: find any preset with the given program that is not a drum preset
|
|
442
|
-
preset = this.presets.find(p => p.program === programNr && p.
|
|
452
|
+
preset = this.presets.find(p => p.program === programNr && !p.isDrumPreset(allowXGDrums));
|
|
443
453
|
}
|
|
444
454
|
if (preset)
|
|
445
455
|
{
|
|
@@ -15,7 +15,17 @@ export class DLSPreset extends BasicPreset
|
|
|
15
15
|
// use stock default modulators, dls won't ever have DMOD chunk
|
|
16
16
|
super(defaultModulators);
|
|
17
17
|
this.program = ulInstrument & 127;
|
|
18
|
-
|
|
18
|
+
const bankMSB = (ulBank >> 8) & 127;
|
|
19
|
+
const bankLSB = ulBank & 127;
|
|
20
|
+
// switch accordingly
|
|
21
|
+
if (bankMSB > 0)
|
|
22
|
+
{
|
|
23
|
+
this.bank = bankMSB;
|
|
24
|
+
}
|
|
25
|
+
else
|
|
26
|
+
{
|
|
27
|
+
this.bank = bankLSB;
|
|
28
|
+
}
|
|
19
29
|
const isDrums = ulBank >> 31;
|
|
20
30
|
if (isDrums)
|
|
21
31
|
{
|