spessasynth_lib 3.25.2 → 3.25.4

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.
@@ -11,6 +11,7 @@ import {
11
11
  } from "../../worklet_utilities/controller_tables.js";
12
12
  import { midiControllers } from "../../../../midi_parser/midi_message.js";
13
13
  import { DEFAULT_PERCUSSION, DEFAULT_SYNTH_MODE } from "../../../synth_constants.js";
14
+ import { getDefaultBank } from "../../../../utils/xg_hacks.js";
14
15
 
15
16
 
16
17
  /**
@@ -38,7 +39,7 @@ export function resetAllControllers(log = true)
38
39
  // if preset is unlocked, switch to non-drums and call event
39
40
  if (!ch.lockPreset)
40
41
  {
41
- ch.setBankSelect(0);
42
+ ch.setBankSelect(getDefaultBank(this.system));
42
43
  if (channelNumber % 16 === DEFAULT_PERCUSSION)
43
44
  {
44
45
  ch.setPreset(this.drumPreset);
@@ -1,3 +1,5 @@
1
+ import { isSystemXG } from "../../../../utils/xg_hacks.js";
2
+
1
3
  /**
2
4
  * @this {SpessaSynthProcessor}
3
5
  * @param program {number}
@@ -10,11 +12,11 @@ export function getPreset(bank, program)
10
12
  {
11
13
  // if override soundfont
12
14
  const bankWithOffset = bank === 128 ? 128 : bank - this.soundfontBankOffset;
13
- const preset = this.overrideSoundfont.getPresetNoFallback(bankWithOffset, program, this.system === "xg");
15
+ const preset = this.overrideSoundfont.getPresetNoFallback(bankWithOffset, program, isSystemXG(this.system));
14
16
  if (preset)
15
17
  {
16
18
  return preset;
17
19
  }
18
20
  }
19
- return this.soundfontManager.getPreset(bank, program, this.system === "xg");
21
+ return this.soundfontManager.getPreset(bank, program, isSystemXG(this.system));
20
22
  }
@@ -2,6 +2,7 @@ import { arrayToHexString, consoleColors } from "../../../utils/other.js";
2
2
  import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
3
3
  import { midiControllers } from "../../../midi_parser/midi_message.js";
4
4
  import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from "../message_protocol/worklet_message.js";
5
+ import { isSystemXG } from "../../../utils/xg_hacks.js";
5
6
 
6
7
  /**
7
8
  * KeyNum: tuning
@@ -147,7 +148,7 @@ export function systemExclusive(messageData, channelOffset = 0)
147
148
  // gm system related
148
149
  if (messageData[3] === 0x01)
149
150
  {
150
- SpessaSynthInfo("%cGM system on", consoleColors.info);
151
+ SpessaSynthInfo("%cGM1 system on", consoleColors.info);
151
152
  this.setSystem("gm");
152
153
  }
153
154
  else if (messageData[3] === 0x03)
@@ -614,7 +615,7 @@ export function systemExclusive(messageData, channelOffset = 0)
614
615
  // XG part parameter
615
616
  if (messageData[3] === 0x08)
616
617
  {
617
- if (this.system !== "xg")
618
+ if (!isSystemXG(this.system))
618
619
  {
619
620
  return;
620
621
  }
@@ -714,7 +715,7 @@ export function systemExclusive(messageData, channelOffset = 0)
714
715
  }
715
716
  );
716
717
  }
717
- else if (this.system === "xg")
718
+ else if (isSystemXG(this.system))
718
719
  {
719
720
  SpessaSynthWarn(
720
721
  `%cUnrecognized Yamaha XG SysEx: %c${arrayToHexString(messageData)}`,
@@ -726,7 +727,7 @@ export function systemExclusive(messageData, channelOffset = 0)
726
727
  }
727
728
  else
728
729
  {
729
- if (this.system === "xg")
730
+ if (isSystemXG(this.system))
730
731
  {
731
732
  SpessaSynthWarn(
732
733
  `%cUnrecognized Yamaha SysEx: %c${arrayToHexString(messageData)}`,
@@ -139,20 +139,19 @@ export class WorkletLowpassFilter
139
139
 
140
140
  // the final cutoff for this calculation
141
141
  const targetCutoff = filter.currentInitialFc + fcExcursion;
142
-
142
+ const modulatedResonance = voice.modulatedGenerators[generatorTypes.initialFilterQ];
143
143
  /* note:
144
144
  * the check for initialFC is because of the filter optimization
145
145
  * (if cents are the maximum then the filter is open)
146
146
  * filter cannot use this optimization if it's dynamic (see #53), and
147
147
  * the filter can only be dynamic if the initial filter is not open
148
148
  */
149
- if (filter.currentInitialFc > 13499 && targetCutoff > 13499 && filter.resonanceCb === 0)
149
+ if (filter.currentInitialFc > 13499 && targetCutoff > 13499 && modulatedResonance === 0)
150
150
  {
151
151
  filter.currentInitialFc = 13500;
152
152
  return; // filter is open
153
153
  }
154
154
 
155
- const modulatedResonance = voice.modulatedGenerators[generatorTypes.initialFilterQ];
156
155
  // check if the frequency has changed. if so, calculate new coefficients
157
156
  if (Math.abs(filter.lastTargetCutoff - targetCutoff) > 1 || filter.resonanceCb !== modulatedResonance)
158
157
  {
@@ -27,7 +27,7 @@ import { channelPressure } from "../worklet_methods/tuning_control/channel_press
27
27
  import { pitchWheel } from "../worklet_methods/tuning_control/pitch_wheel.js";
28
28
  import { setOctaveTuning } from "../worklet_methods/tuning_control/set_octave_tuning.js";
29
29
  import { programChange } from "../worklet_methods/program_change.js";
30
- import { chooseBank, parseBankSelect } from "../../../utils/xg_hacks.js";
30
+ import { chooseBank, isSystemXG, parseBankSelect } from "../../../utils/xg_hacks.js";
31
31
  import { DEFAULT_PERCUSSION } from "../../synth_constants.js";
32
32
 
33
33
  /**
@@ -205,7 +205,7 @@ class WorkletProcessorChannel
205
205
 
206
206
  get isXGChannel()
207
207
  {
208
- return this.synth.system === "xg" || (this.lockPreset && this.lockedSystem === "xg");
208
+ return isSystemXG(this.synth.system) || (this.lockPreset && isSystemXG(this.lockedSystem));
209
209
  }
210
210
 
211
211
  /**
@@ -10,6 +10,7 @@ import { WorkletVolumeEnvelope } from "./volume_envelope.js";
10
10
  import { WorkletModulationEnvelope } from "./modulation_envelope.js";
11
11
  import { addAndClampGenerator, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
12
12
  import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
13
+ import { isSystemXG } from "../../../utils/xg_hacks.js";
13
14
 
14
15
  const EXCLUSIVE_CUTOFF_TIME = -2320;
15
16
  const EXCLUSIVE_MOD_CUTOFF_TIME = -1130; // less because filter shenanigans
@@ -408,7 +409,7 @@ export function getWorkletVoices(channel,
408
409
  let preset = channelObject.preset;
409
410
  if (overridePatch)
410
411
  {
411
- preset = this.soundfontManager.getPreset(bank, program, this.system === "xg");
412
+ preset = this.soundfontManager.getPreset(bank, program, isSystemXG(this.system));
412
413
  }
413
414
  /**
414
415
  * @returns {WorkletVoice[]}
@@ -42,5 +42,17 @@ export function isGSOn(e)
42
42
  export function isGMOn(e)
43
43
  {
44
44
  return e.messageData[0] === 0x7E // non realtime
45
- && e.messageData[2] === 0x09; // gm system
45
+ && e.messageData[2] === 0x09 // gm system
46
+ && e.messageData[3] === 0x01; // gm1
47
+ }
48
+
49
+ /**
50
+ * @param e {MIDIMessage}
51
+ * @returns boolean
52
+ */
53
+ export function isGM2On(e)
54
+ {
55
+ return e.messageData[0] === 0x7E // non realtime
56
+ && e.messageData[2] === 0x09 // gm system
57
+ && e.messageData[3] === 0x03; // gm2
46
58
  }
package/utils/xg_hacks.js CHANGED
@@ -4,6 +4,17 @@ import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";
4
4
 
5
5
  export const XG_SFX_VOICE = 64;
6
6
 
7
+ const GM2_DEFAULT_BANK = 121;
8
+
9
+ /**
10
+ * @param sys {SynthSystem}
11
+ * @returns {number}
12
+ */
13
+ export function getDefaultBank(sys)
14
+ {
15
+ return sys === "gm2" ? GM2_DEFAULT_BANK : 0;
16
+ }
17
+
7
18
  /**
8
19
  * @param bankNr {number}
9
20
  * @returns {boolean}
@@ -19,7 +30,7 @@ export function isXGDrums(bankNr)
19
30
  */
20
31
  export function isValidXGMSB(bank)
21
32
  {
22
- return isXGDrums(bank) || bank === XG_SFX_VOICE;
33
+ return isXGDrums(bank) || bank === XG_SFX_VOICE || bank === GM2_DEFAULT_BANK;
23
34
  }
24
35
 
25
36
  /**
@@ -42,7 +53,7 @@ export function parseBankSelect(bankBefore, bank, system, isLSB, isDrums, channe
42
53
  let drumsStatus = 0;
43
54
  if (isLSB)
44
55
  {
45
- if (system === "xg")
56
+ if (isSystemXG(system))
46
57
  {
47
58
  if (!isValidXGMSB(bank))
48
59
  {
@@ -150,27 +161,33 @@ export function chooseBank(msb, lsb, isDrums, isXG)
150
161
  else
151
162
  {
152
163
  // check for SFX
153
- if (msb !== XG_SFX_VOICE)
164
+ if (isValidXGMSB(msb))
154
165
  {
155
- // if lsb is 0 and msb is not, use that
156
- if (lsb === 0 && msb !== 0)
157
- {
158
- return msb;
159
- }
160
- if (!isValidXGMSB(lsb))
161
- {
162
- return lsb;
163
- }
164
- return 0;
166
+ return msb;
165
167
  }
166
- else
168
+ // if lsb is 0 and msb is not, use that
169
+ if (lsb === 0 && msb !== 0)
170
+ {
171
+ return msb;
172
+ }
173
+ if (!isValidXGMSB(lsb))
167
174
  {
168
- return XG_SFX_VOICE;
175
+ return lsb;
169
176
  }
177
+ return 0;
170
178
  }
171
179
  }
172
180
  else
173
181
  {
174
182
  return isDrums ? 128 : msb;
175
183
  }
184
+ }
185
+
186
+ /**
187
+ * @param system {SynthSystem}
188
+ * @returns boolean
189
+ */
190
+ export function isSystemXG(system)
191
+ {
192
+ return system === "gm2" || system === "xg";
176
193
  }