spessasynth_core 3.26.35 → 3.26.36

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_core",
3
- "version": "3.26.35",
3
+ "version": "3.26.36",
4
4
  "description": "MIDI and SoundFont2/DLS library with no compromises",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,5 +1,6 @@
1
1
  import { BasicGlobalZone } from "./basic_global_zone.js";
2
2
  import { BasicInstrumentZone } from "./basic_instrument_zone.js";
3
+ import { SpessaSynthWarn } from "../../utils/loggin.js";
3
4
 
4
5
  export class BasicInstrument
5
6
  {
@@ -64,7 +65,8 @@ export class BasicInstrument
64
65
  const index = this.linkedPresets.indexOf(preset);
65
66
  if (index < 0)
66
67
  {
67
- throw new Error(`Cannot unlink ${preset.presetName} from ${this.instrumentName}: not linked.`);
68
+ SpessaSynthWarn(`Cannot unlink ${preset.presetName} from ${this.instrumentName}: not linked.`);
69
+ return;
68
70
  }
69
71
  this.linkedPresets.splice(index, 1);
70
72
  this.instrumentZones.forEach(z => z.useCount--);
@@ -87,7 +89,7 @@ export class BasicInstrument
87
89
  {
88
90
  if (this.useCount > 0)
89
91
  {
90
- throw new Error(`Cannot delete an instrument that has ${this.useCount} usages.`);
92
+ throw new Error(`Cannot delete an instrument that is used by: ${this.linkedPresets.map(p => p.presetName)}.`);
91
93
  }
92
94
  this.instrumentZones.forEach(z => z.deleteZone());
93
95
  this.instrumentZones.length = 0;
@@ -249,7 +249,7 @@ export class BasicSample
249
249
  {
250
250
  if (this.useCount > 0)
251
251
  {
252
- throw new Error(`Cannot delete sample that has ${this.useCount} usages.`);
252
+ throw new Error(`Cannot delete sample used by: ${this.linkedInstruments.map(i => i.instrumentName)}.`);
253
253
  }
254
254
  this.unlinkSample();
255
255
  }
@@ -310,7 +310,8 @@ export class BasicSample
310
310
  const index = this.linkedInstruments.indexOf(instrument);
311
311
  if (index < 0)
312
312
  {
313
- throw new Error(`Cannot unlink ${instrument.instrumentName} from ${this.sampleName}: not linked.`);
313
+ SpessaSynthWarn(`Cannot unlink ${instrument.instrumentName} from ${this.sampleName}: not linked.`);
314
+ return;
314
315
  }
315
316
  this.linkedInstruments.splice(index, 1);
316
317
  }
@@ -166,7 +166,7 @@ class MidiAudioChannel
166
166
 
167
167
  /**
168
168
  * The preset currently assigned to the channel.
169
- * @type {BasicPreset}
169
+ * @type {?BasicPreset}
170
170
  */
171
171
  preset = undefined;
172
172
 
@@ -364,7 +364,6 @@ class MidiAudioChannel
364
364
  {
365
365
  return;
366
366
  }
367
- delete this.preset;
368
367
  this.preset = preset;
369
368
  }
370
369
 
@@ -464,7 +463,7 @@ class MidiAudioChannel
464
463
  isDrum: this.drumChannel,
465
464
  transposition: this.channelTransposeKeyShift + this.customControllers[customControllers.channelTransposeFine] / 100,
466
465
  bank: this.sentBank,
467
- program: this.preset.program
466
+ program: this.preset?.program
468
467
  };
469
468
  this.synth?.onChannelPropertyChange?.(data, this.channelNumber);
470
469
  }
@@ -491,7 +491,14 @@ export function getVoices(channel, midiNote, velocity, realKey)
491
491
  const overridePatch = this.keyModifierManager.hasOverridePatch(channel, midiNote);
492
492
 
493
493
  let bank = channelObject.getBankSelect();
494
- let program = channelObject.preset.program;
494
+
495
+ let preset = channelObject.preset;
496
+ if (!preset)
497
+ {
498
+ SpessaSynthWarn(`No preset for channel ${channel}!`);
499
+ return [];
500
+ }
501
+ let program = preset.program;
495
502
  if (overridePatch)
496
503
  {
497
504
  const override = this.keyModifierManager.getPatch(channel, midiNote);
@@ -507,7 +514,6 @@ export function getVoices(channel, midiNote, velocity, realKey)
507
514
  }
508
515
 
509
516
  // not cached...
510
- let preset = channelObject.preset;
511
517
  if (overridePatch)
512
518
  {
513
519
  preset = this.getPreset(bank, program);
@@ -29,13 +29,17 @@ export function resetAllControllers(log = true)
29
29
  this.setSystem(DEFAULT_SYNTH_MODE);
30
30
  for (let channelNumber = 0; channelNumber < this.midiAudioChannels.length; channelNumber++)
31
31
  {
32
- this.midiAudioChannels[channelNumber].resetControllers();
33
-
34
32
  /**
35
33
  * @type {MidiAudioChannel}
36
34
  **/
37
35
  const ch = this.midiAudioChannels[channelNumber];
38
36
 
37
+ ch.resetControllers();
38
+ // safety net
39
+ if (!ch.preset)
40
+ {
41
+ continue;
42
+ }
39
43
  // if preset is unlocked, switch to non-drums and call event
40
44
  if (!ch.lockPreset)
41
45
  {
@@ -67,11 +71,11 @@ export function resetAllControllers(log = true)
67
71
  });
68
72
  }
69
73
 
70
- const presetBank = ch.preset.bank;
74
+ const presetBank = ch.preset?.bank;
71
75
  // call program change
72
76
  this.callEvent("programchange", {
73
77
  channel: channelNumber,
74
- program: ch.preset.program,
78
+ program: ch.preset?.program,
75
79
  bank: presetBank
76
80
  });
77
81
 
@@ -4,6 +4,7 @@ import { customControllers } from "../engine_components/controller_tables.js";
4
4
  import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
5
5
  import { GENERATOR_OVERRIDE_NO_CHANGE_VALUE } from "../../synth_constants.js";
6
6
  import { generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
7
+ import { SpessaSynthWarn } from "../../../utils/loggin.js";
7
8
 
8
9
  /**
9
10
  * sends a "MIDI Note on message"
@@ -29,6 +30,12 @@ export function noteOn(midiNote, velocity)
29
30
  return;
30
31
  }
31
32
 
33
+ if (!this.preset)
34
+ {
35
+ SpessaSynthWarn(`No preset for channel ${this.channelNumber}!`);
36
+ return;
37
+ }
38
+
32
39
  const realKey = midiNote + this.channelTransposeKeyShift + this.customControllers[customControllers.channelKeyShift];
33
40
  let internalMidiNote = realKey;
34
41
 
@@ -36,7 +43,7 @@ export function noteOn(midiNote, velocity)
36
43
  {
37
44
  return;
38
45
  }
39
- const program = this.preset.program;
46
+ const program = this.preset?.program;
40
47
  const tune = this.synth.tunings[program]?.[realKey]?.midiNote;
41
48
  if (tune >= 0)
42
49
  {
@@ -1,3 +1,6 @@
1
+ import { SpessaSynthWarn } from "../../../utils/loggin.js";
2
+ import { BasicPreset } from "../../../soundfont/basic_soundfont/basic_preset.js";
3
+
1
4
  /**
2
5
  * executes a program change
3
6
  * @param programNumber {number}
@@ -14,7 +17,13 @@ export function programChange(programNumber)
14
17
 
15
18
  const isXG = this.isXGChannel;
16
19
  const p = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
17
- const preset = p.preset;
20
+ let preset = p.preset;
21
+ if (!preset)
22
+ {
23
+ SpessaSynthWarn("No presets! Using empty fallback.");
24
+ preset = new BasicPreset(this.synth.soundfontManager.soundfontList[0].soundfont);
25
+ preset.presetName = "SPESSA EMPTY FALLBACK PRESET";
26
+ }
18
27
  this.setPreset(preset);
19
28
  this.sentBank = Math.min(128, preset.bank + p.bankOffset);
20
29
  this.synth.callEvent("programchange", {
@@ -66,7 +66,7 @@ export function renderVoice(
66
66
  let semitones = voice.modulatedGenerators[generatorTypes.coarseTune]; // soundfont coarse tuning
67
67
 
68
68
  // midi tuning standard
69
- const tuning = this.synth.tunings[this.preset.program]?.[voice.realKey];
69
+ const tuning = this.synth.tunings[this.preset?.program]?.[voice.realKey];
70
70
  if (tuning !== undefined && tuning?.midiNote >= 0)
71
71
  {
72
72
  // override key