spessasynth_lib 3.25.1 → 3.25.3
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 +48 -31
- package/midi_parser/rmidi_writer.js +57 -38
- package/midi_parser/used_keys_loaded.js +28 -23
- 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 +9 -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 +4 -2
- package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js +1 -2
- package/synthetizer/worklet_system/worklet_methods/system_exclusive.js +5 -4
- 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 +3 -3
- package/utils/sysex_detector.js +13 -1
- package/utils/xg_hacks.js +74 -9
|
@@ -5,7 +5,8 @@ import { consoleColors } from "../utils/other.js";
|
|
|
5
5
|
|
|
6
6
|
import { customControllers } from "../synthetizer/worklet_system/worklet_utilities/controller_tables.js";
|
|
7
7
|
import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";
|
|
8
|
-
import { isGMOn, isGSOn, isXGOn } from "../utils/sysex_detector.js";
|
|
8
|
+
import { isGM2On, isGMOn, isGSOn, isXGOn } from "../utils/sysex_detector.js";
|
|
9
|
+
import { isSystemXG, 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 (isSystemXG(system))
|
|
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
|
}
|
|
@@ -487,9 +504,9 @@ export function modifyMIDI(
|
|
|
487
504
|
}
|
|
488
505
|
else
|
|
489
506
|
// check for GM/2 on
|
|
490
|
-
if (isGMOn(e))
|
|
507
|
+
if (isGMOn(e) || isGM2On(e))
|
|
491
508
|
{
|
|
492
|
-
// that's a
|
|
509
|
+
// that's a GM1 system change, remove it!
|
|
493
510
|
SpessaSynthInfo(
|
|
494
511
|
"%cGM/2 on detected, removing!",
|
|
495
512
|
consoleColors.info
|
|
@@ -7,8 +7,8 @@ import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from "../utils
|
|
|
7
7
|
import { consoleColors } from "../utils/other.js";
|
|
8
8
|
import { writeLittleEndian } from "../utils/byte_functions/little_endian.js";
|
|
9
9
|
import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";
|
|
10
|
-
import { chooseBank, parseBankSelect } from "../utils/xg_hacks.js";
|
|
11
|
-
import { isGMOn, isGSDrumsOn, isGSOn, isXGOn } from "../utils/sysex_detector.js";
|
|
10
|
+
import { chooseBank, isSystemXG, parseBankSelect } from "../utils/xg_hacks.js";
|
|
11
|
+
import { isGM2On, isGMOn, isGSDrumsOn, isGSOn, isXGOn } from "../utils/sysex_detector.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @enum {string}
|
|
@@ -183,12 +183,17 @@ export function writeRMIDI(
|
|
|
183
183
|
}
|
|
184
184
|
else if (isGMOn(e))
|
|
185
185
|
{
|
|
186
|
+
// we do not want gm1
|
|
186
187
|
system = "gm";
|
|
187
188
|
unwantedSystems.push({
|
|
188
189
|
tNum: trackNum,
|
|
189
190
|
e: e
|
|
190
191
|
});
|
|
191
192
|
}
|
|
193
|
+
else if (isGM2On(e))
|
|
194
|
+
{
|
|
195
|
+
system = "gm2";
|
|
196
|
+
}
|
|
192
197
|
continue;
|
|
193
198
|
}
|
|
194
199
|
const sysexChannel = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15][e.messageData[5] & 0x0F] + portOffset;
|
|
@@ -204,46 +209,54 @@ export function writeRMIDI(
|
|
|
204
209
|
const channel = channelsInfo[chNum];
|
|
205
210
|
if (status === messageTypes.programChange)
|
|
206
211
|
{
|
|
212
|
+
const isXG = isSystemXG(system);
|
|
207
213
|
// check if the preset for this program exists
|
|
214
|
+
const initialProgram = e.messageData[0];
|
|
208
215
|
if (channel.drums)
|
|
209
216
|
{
|
|
210
|
-
if (soundfont.presets.findIndex(p => p.program ===
|
|
217
|
+
if (soundfont.presets.findIndex(p => p.program === initialProgram && p.isDrumPreset(
|
|
218
|
+
isXG,
|
|
219
|
+
true
|
|
220
|
+
)) === -1)
|
|
211
221
|
{
|
|
212
222
|
// doesn't exist. pick any preset that has bank 128.
|
|
213
|
-
e.messageData[0] = soundfont.presets.find(p => p.
|
|
223
|
+
e.messageData[0] = soundfont.presets.find(p => p.isDrumPreset(isXG))?.program || 0;
|
|
224
|
+
SpessaSynthInfo(
|
|
225
|
+
`%cNo drum preset %c${initialProgram}%c. Channel %c${chNum}%c. Changing program to ${e.messageData[0]}.`,
|
|
226
|
+
consoleColors.info,
|
|
227
|
+
consoleColors.unrecognized,
|
|
228
|
+
consoleColors.info,
|
|
229
|
+
consoleColors.recognized,
|
|
230
|
+
consoleColors.info
|
|
231
|
+
);
|
|
214
232
|
}
|
|
215
233
|
}
|
|
216
234
|
else
|
|
217
235
|
{
|
|
218
|
-
if (soundfont.presets.findIndex(p => p.program ===
|
|
236
|
+
if (soundfont.presets.findIndex(p => p.program === initialProgram && !p.isDrumPreset(isXG)) === -1)
|
|
219
237
|
{
|
|
220
238
|
// doesn't exist. pick any preset that does not have bank 128.
|
|
221
|
-
e.messageData[0] = soundfont.presets.find(p => p.
|
|
239
|
+
e.messageData[0] = soundfont.presets.find(p => !p.isDrumPreset(isXG))?.program || 0;
|
|
240
|
+
SpessaSynthInfo(
|
|
241
|
+
`%cNo preset %c${initialProgram}%c. Channel %c${chNum}%c. Changing program to ${e.messageData[0]}.`,
|
|
242
|
+
consoleColors.info,
|
|
243
|
+
consoleColors.unrecognized,
|
|
244
|
+
consoleColors.info,
|
|
245
|
+
consoleColors.recognized,
|
|
246
|
+
consoleColors.info
|
|
247
|
+
);
|
|
222
248
|
}
|
|
223
249
|
}
|
|
224
250
|
channel.program = e.messageData[0];
|
|
225
251
|
// check if this preset exists for program and bank
|
|
226
252
|
const realBank = Math.max(0, channel.lastBank?.messageData[1] - mid.bankOffset); // make sure to take the previous bank offset into account
|
|
227
|
-
|
|
253
|
+
const bankLSB = (channel?.lastBankLSB?.messageData[1] - mid.bankOffset) || 0;
|
|
228
254
|
if (channel.lastBank === undefined)
|
|
229
255
|
{
|
|
230
256
|
continue;
|
|
231
257
|
}
|
|
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
|
-
|
|
258
|
+
// adjust bank for XG
|
|
259
|
+
let bank = chooseBank(realBank, bankLSB, channel.drums, isXG);
|
|
247
260
|
if (soundfont.presets.findIndex(p => p.bank === bank && p.program === e.messageData[0]) === -1)
|
|
248
261
|
{
|
|
249
262
|
// no preset with this bank. find this program with any bank
|
|
@@ -254,7 +267,9 @@ export function writeRMIDI(
|
|
|
254
267
|
channel.lastBankLSB.messageData[1] = targetBank;
|
|
255
268
|
}
|
|
256
269
|
SpessaSynthInfo(
|
|
257
|
-
`%cNo preset %c${bank}:${e.messageData[0]}%c. Changing bank to ${targetBank}.`,
|
|
270
|
+
`%cNo preset %c${bank}:${e.messageData[0]}%c. Channel %c${chNum}%c. Changing bank to ${targetBank}.`,
|
|
271
|
+
consoleColors.info,
|
|
272
|
+
consoleColors.unrecognized,
|
|
258
273
|
consoleColors.info,
|
|
259
274
|
consoleColors.recognized,
|
|
260
275
|
consoleColors.info
|
|
@@ -263,15 +278,21 @@ export function writeRMIDI(
|
|
|
263
278
|
else
|
|
264
279
|
{
|
|
265
280
|
// There is a preset with this bank. Add offset. For drums add the normal offset.
|
|
266
|
-
let drumBank =
|
|
267
|
-
|
|
281
|
+
let drumBank = bank;
|
|
282
|
+
if (isSystemXG(system) && bank === 128)
|
|
283
|
+
{
|
|
284
|
+
bank = 127;
|
|
285
|
+
}
|
|
286
|
+
const newBank = (bank === 128 ? 128 : drumBank) + bankOffset;
|
|
268
287
|
channel.lastBank.messageData[1] = newBank;
|
|
269
|
-
if (channel?.lastBankLSB?.messageData)
|
|
288
|
+
if (channel?.lastBankLSB?.messageData && !channel.drums)
|
|
270
289
|
{
|
|
271
290
|
channel.lastBankLSB.messageData[1] = channel.lastBankLSB.messageData[1] - mid.bankOffset + bankOffset;
|
|
272
291
|
}
|
|
273
292
|
SpessaSynthInfo(
|
|
274
|
-
`%cPreset %c${bank}:${e.messageData[0]}%c exists. Changing bank to ${newBank}.`,
|
|
293
|
+
`%cPreset %c${bank}:${e.messageData[0]}%c exists. Channel %c${chNum}%c. Changing bank to ${newBank}.`,
|
|
294
|
+
consoleColors.info,
|
|
295
|
+
consoleColors.recognized,
|
|
275
296
|
consoleColors.info,
|
|
276
297
|
consoleColors.recognized,
|
|
277
298
|
consoleColors.info
|
|
@@ -307,16 +328,13 @@ export function writeRMIDI(
|
|
|
307
328
|
{
|
|
308
329
|
channel.drums = false;
|
|
309
330
|
}
|
|
310
|
-
if (
|
|
331
|
+
if (isLSB)
|
|
311
332
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
{
|
|
318
|
-
channel.lastBank = e;
|
|
319
|
-
}
|
|
333
|
+
channel.lastBankLSB = e;
|
|
334
|
+
}
|
|
335
|
+
else
|
|
336
|
+
{
|
|
337
|
+
channel.lastBank = e;
|
|
320
338
|
}
|
|
321
339
|
}
|
|
322
340
|
|
|
@@ -370,7 +388,8 @@ export function writeRMIDI(
|
|
|
370
388
|
const ticks = track[indexToAdd].ticks;
|
|
371
389
|
const targetBank = (soundfont.getPreset(
|
|
372
390
|
0,
|
|
373
|
-
has.program
|
|
391
|
+
has.program,
|
|
392
|
+
isSystemXG(system)
|
|
374
393
|
)?.bank + bankOffset) || bankOffset;
|
|
375
394
|
track.splice(indexToAdd, 0, new MIDIMessage(
|
|
376
395
|
ticks,
|
|
@@ -380,7 +399,7 @@ export function writeRMIDI(
|
|
|
380
399
|
});
|
|
381
400
|
|
|
382
401
|
// make sure to put xg if gm
|
|
383
|
-
if (system !== "gs" && system
|
|
402
|
+
if (system !== "gs" && !isSystemXG(system))
|
|
384
403
|
{
|
|
385
404
|
for (const m of unwantedSystems)
|
|
386
405
|
{
|
|
@@ -2,13 +2,13 @@ import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo } from
|
|
|
2
2
|
import { consoleColors } from "../utils/other.js";
|
|
3
3
|
import { messageTypes, midiControllers } from "./midi_message.js";
|
|
4
4
|
import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";
|
|
5
|
-
import { chooseBank, parseBankSelect } from "../utils/xg_hacks.js";
|
|
5
|
+
import { chooseBank, isSystemXG, parseBankSelect } from "../utils/xg_hacks.js";
|
|
6
6
|
import { isGSDrumsOn, isXGOn } from "../utils/sysex_detector.js";
|
|
7
7
|
|
|
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, isSystemXG(system));
|
|
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, isSystemXG(system));
|
|
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
|
{
|