spessasynth_lib 3.25.0 → 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.
Files changed (27) hide show
  1. package/midi_parser/midi_editor.js +50 -44
  2. package/midi_parser/rmidi_writer.js +90 -45
  3. package/midi_parser/used_keys_loaded.js +59 -39
  4. package/package.json +1 -1
  5. package/sequencer/sequencer.js +0 -1
  6. package/soundfont/basic_soundfont/basic_preset.js +12 -0
  7. package/soundfont/basic_soundfont/basic_soundfont.js +25 -15
  8. package/soundfont/dls/dls_preset.js +11 -1
  9. package/synthetizer/synthetizer.js +48 -1
  10. package/synthetizer/worklet_processor.min.js +12 -12
  11. package/synthetizer/worklet_system/main_processor.js +46 -4
  12. package/synthetizer/worklet_system/message_protocol/handle_message.js +4 -1
  13. package/synthetizer/worklet_system/message_protocol/worklet_message.js +5 -6
  14. package/synthetizer/worklet_system/snapshot/channel_snapshot.js +18 -3
  15. package/synthetizer/worklet_system/snapshot/synthesizer_snapshot.js +1 -1
  16. package/synthetizer/worklet_system/worklet_methods/controller_control/controller_change.js +64 -135
  17. package/synthetizer/worklet_system/worklet_methods/controller_control/reset_controllers.js +8 -4
  18. package/synthetizer/worklet_system/worklet_methods/program_change.js +10 -5
  19. package/synthetizer/worklet_system/worklet_methods/soundfont_management/clear_sound_font.js +2 -3
  20. package/synthetizer/worklet_system/worklet_methods/soundfont_management/get_preset.js +2 -2
  21. package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js +1 -2
  22. package/synthetizer/worklet_system/worklet_methods/system_exclusive.js +6 -6
  23. package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js +20 -5
  24. package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +70 -14
  25. package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +2 -3
  26. package/utils/sysex_detector.js +46 -0
  27. package/utils/xg_hacks.js +176 -0
@@ -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 fallbackToProgram {boolean} if true, if no exact match is found, will use any bank with the given preset
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, fallbackToProgram = false)
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
- if (fallbackToProgram === false)
406
- {
407
- return undefined;
408
- }
409
- if (bankNr === 128)
407
+ // no match...
408
+ const isDrum = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
409
+ if (isDrum)
410
410
  {
411
- // any drum preset
412
- return this.presets.find(p => p.bank === 128);
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 this.presets.find(p => p.program === programNr);
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 (bankNr === 128)
439
+ if (isDrums)
431
440
  {
432
441
  // drum preset: find any preset with bank 128
433
- preset = this.presets.find(p => p.bank === 128 && p.program === programNr);
442
+ preset = this.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNr);
434
443
  if (!preset)
435
444
  {
436
- preset = this.presets.find(p => p.bank === 128);
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.bank !== 128);
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
- this.bank = (ulBank >> 8) & 127;
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
  {
@@ -15,7 +15,13 @@ import { DEFAULT_SYNTH_CONFIG } from "./audio_effects/effects_config.js";
15
15
  import { SoundfontManager } from "./synth_soundfont_manager.js";
16
16
  import { KeyModifierManager } from "./key_modifier_manager.js";
17
17
  import { channelConfiguration } from "./worklet_system/worklet_utilities/controller_tables.js";
18
- import { DEFAULT_PERCUSSION, MIDI_CHANNEL_COUNT, VOICE_CAP, WORKLET_PROCESSOR_NAME } from "./synth_constants.js";
18
+ import {
19
+ DEFAULT_PERCUSSION,
20
+ DEFAULT_SYNTH_MODE,
21
+ MIDI_CHANNEL_COUNT,
22
+ VOICE_CAP,
23
+ WORKLET_PROCESSOR_NAME
24
+ } from "./synth_constants.js";
19
25
 
20
26
 
21
27
  /**
@@ -239,6 +245,30 @@ export class Synthetizer
239
245
  });
240
246
  }
241
247
 
248
+ /**
249
+ * @type {"gm"|"gm2"|"gs"|"xg"}
250
+ * @private
251
+ */
252
+ _midiSystem = DEFAULT_SYNTH_MODE;
253
+
254
+ /**
255
+ * The current MIDI system used by the synthesizer
256
+ * @returns {"gm"|"gm2"|"gs"|"xg"}
257
+ */
258
+ get midiSystem()
259
+ {
260
+ return this._midiSystem;
261
+ }
262
+
263
+ /**
264
+ * The current MIDI system used by the synthesizer
265
+ * @param value {"gm"|"gm2"|"gs"|"xg"}
266
+ */
267
+ set midiSystem(value)
268
+ {
269
+ this._midiSystem = value;
270
+ }
271
+
242
272
  /**
243
273
  * current voice amount
244
274
  * @type {number}
@@ -383,6 +413,23 @@ export class Synthetizer
383
413
  }
384
414
  break;
385
415
 
416
+ case returnMessageType.masterParameterChange:
417
+ /**
418
+ * @type {masterParameterType}
419
+ */
420
+ const param = messageData[0];
421
+ const value = messageData[1];
422
+ switch (param)
423
+ {
424
+ default:
425
+ break;
426
+
427
+ case masterParameterType.midiSystem:
428
+ this._midiSystem = value;
429
+ break;
430
+ }
431
+ break;
432
+
386
433
  case returnMessageType.synthesizerSnapshot:
387
434
  if (this._snapshotCallback)
388
435
  {