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
|
@@ -191,6 +191,22 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
191
191
|
*/
|
|
192
192
|
totalVoicesAmount = 0;
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Synth's default (reset) preset
|
|
196
|
+
* @type {BasicPreset}
|
|
197
|
+
*/
|
|
198
|
+
defaultPreset;
|
|
199
|
+
|
|
200
|
+
defaultPresetUsesOverride = false;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Synth's default (reset) drum preset
|
|
204
|
+
* @type {BasicPreset}
|
|
205
|
+
*/
|
|
206
|
+
drumPreset;
|
|
207
|
+
|
|
208
|
+
defaultDrumsUsesOverride = false;
|
|
209
|
+
|
|
194
210
|
/**
|
|
195
211
|
* Creates a new worklet synthesis system. contains all channels
|
|
196
212
|
* @param options {{
|
|
@@ -235,8 +251,7 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
235
251
|
}
|
|
236
252
|
this.sendPresetList();
|
|
237
253
|
|
|
238
|
-
this.
|
|
239
|
-
this.drumPreset = this.getPreset(128, 0);
|
|
254
|
+
this.getDefaultPresets();
|
|
240
255
|
|
|
241
256
|
|
|
242
257
|
for (let i = 0; i < options.processorOptions.midiChannels; i++)
|
|
@@ -303,6 +318,18 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
303
318
|
return this.masterGain * this.midiVolume;
|
|
304
319
|
}
|
|
305
320
|
|
|
321
|
+
getDefaultPresets()
|
|
322
|
+
{
|
|
323
|
+
// override this to XG, to set the default preset to NOT be XG drums!
|
|
324
|
+
const sys = this.system;
|
|
325
|
+
this.system = "xg";
|
|
326
|
+
this.defaultPreset = this.getPreset(0, 0);
|
|
327
|
+
this.defaultPresetUsesOverride = this.overrideSoundfont?.presets?.indexOf(this.defaultPreset) >= 0;
|
|
328
|
+
this.system = sys;
|
|
329
|
+
this.drumPreset = this.getPreset(128, 0);
|
|
330
|
+
this.defaultDrumsUsesOverride = this.overrideSoundfont?.presets?.indexOf(this.drumPreset) >= 0;
|
|
331
|
+
}
|
|
332
|
+
|
|
306
333
|
/**
|
|
307
334
|
* @param value {SynthSystem}
|
|
308
335
|
*/
|
|
@@ -15,6 +15,12 @@ export class ChannelSnapshot
|
|
|
15
15
|
*/
|
|
16
16
|
bank;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* If the bank is LSB. For restoring.
|
|
20
|
+
* @type {boolean}
|
|
21
|
+
*/
|
|
22
|
+
isBankLSB;
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* The name of the patch currently loaded in the channel.
|
|
20
26
|
* @type {string}
|
|
@@ -27,6 +33,12 @@ export class ChannelSnapshot
|
|
|
27
33
|
*/
|
|
28
34
|
lockPreset;
|
|
29
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Indicates the MIDI system when the preset was locked
|
|
38
|
+
* @type {SynthSystem}
|
|
39
|
+
*/
|
|
40
|
+
lockedSystem;
|
|
41
|
+
|
|
30
42
|
/**
|
|
31
43
|
* The array of all MIDI controllers (in 14-bit values) with the modulator sources at the end.
|
|
32
44
|
* @type {Int16Array}
|
|
@@ -103,7 +115,9 @@ export class ChannelSnapshot
|
|
|
103
115
|
// program data
|
|
104
116
|
channelSnapshot.program = channelObject.preset.program;
|
|
105
117
|
channelSnapshot.bank = channelObject.getBankSelect();
|
|
118
|
+
channelSnapshot.isBankLSB = channelSnapshot.bank !== channelObject.bank;
|
|
106
119
|
channelSnapshot.lockPreset = channelObject.lockPreset;
|
|
120
|
+
channelSnapshot.lockedSystem = channelObject.lockedSystem;
|
|
107
121
|
channelSnapshot.patchName = channelObject.preset.presetName;
|
|
108
122
|
|
|
109
123
|
// controller data
|
|
@@ -152,9 +166,10 @@ export class ChannelSnapshot
|
|
|
152
166
|
channelObject.velocityOverride = channelSnapshot.velocityOverride;
|
|
153
167
|
|
|
154
168
|
// restore preset and lock
|
|
155
|
-
channelObject.
|
|
156
|
-
channelObject.setBankSelect(channelSnapshot.bank,
|
|
169
|
+
channelObject.setPresetLock(false);
|
|
170
|
+
channelObject.setBankSelect(channelSnapshot.bank, channelSnapshot.isBankLSB);
|
|
157
171
|
channelObject.programChange(channelSnapshot.program);
|
|
158
|
-
channelObject.
|
|
172
|
+
channelObject.setPresetLock(channelSnapshot.lockPreset);
|
|
173
|
+
channelObject.lockedSystem = channelSnapshot.lockedSystem;
|
|
159
174
|
}
|
|
160
175
|
}
|
|
@@ -66,18 +66,11 @@ export function controllerChange(controllerNumber, controllerValue, force = fals
|
|
|
66
66
|
|
|
67
67
|
// special case: bank select
|
|
68
68
|
case midiControllers.bankSelect:
|
|
69
|
-
|
|
70
|
-
{
|
|
71
|
-
this.setBankSelect(controllerValue);
|
|
72
|
-
}
|
|
73
|
-
else
|
|
74
|
-
{
|
|
75
|
-
this.bank = controllerValue;
|
|
76
|
-
}
|
|
69
|
+
this.setBankSelect(controllerValue);
|
|
77
70
|
break;
|
|
78
71
|
|
|
79
72
|
case midiControllers.lsbForControl0BankSelect:
|
|
80
|
-
this.setBankSelect(controllerValue,
|
|
73
|
+
this.setBankSelect(controllerValue, true);
|
|
81
74
|
break;
|
|
82
75
|
|
|
83
76
|
// check for RPN and NPRN and data entry
|
|
@@ -38,11 +38,11 @@ export function resetAllControllers(log = true)
|
|
|
38
38
|
// if preset is unlocked, switch to non-drums and call event
|
|
39
39
|
if (!ch.lockPreset)
|
|
40
40
|
{
|
|
41
|
-
ch.
|
|
42
|
-
ch.setBankSelect(0, true);
|
|
41
|
+
ch.setBankSelect(0);
|
|
43
42
|
if (channelNumber % 16 === DEFAULT_PERCUSSION)
|
|
44
43
|
{
|
|
45
|
-
|
|
44
|
+
ch.setPreset(this.drumPreset);
|
|
45
|
+
ch.presetUsesOverride = this.defaultDrumsUsesOverride;
|
|
46
46
|
ch.drumChannel = true;
|
|
47
47
|
this.callEvent("drumchange", {
|
|
48
48
|
channel: channelNumber,
|
|
@@ -52,6 +52,7 @@ export function resetAllControllers(log = true)
|
|
|
52
52
|
else
|
|
53
53
|
{
|
|
54
54
|
ch.drumChannel = false;
|
|
55
|
+
ch.presetUsesOverride = this.defaultDrumsUsesOverride;
|
|
55
56
|
ch.setPreset(this.defaultPreset);
|
|
56
57
|
this.callEvent("drumchange", {
|
|
57
58
|
channel: channelNumber,
|
|
@@ -67,11 +68,14 @@ export function resetAllControllers(log = true)
|
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
const presetBank = ch.preset.bank;
|
|
72
|
+
const sentBank = presetBank === 128 ? 128 : (ch.presetUsesOverride ? presetBank + this.soundfontBankOffset : presetBank);
|
|
73
|
+
|
|
70
74
|
// call program change
|
|
71
75
|
this.callEvent("programchange", {
|
|
72
76
|
channel: channelNumber,
|
|
73
77
|
program: ch.preset.program,
|
|
74
|
-
bank:
|
|
78
|
+
bank: sentBank,
|
|
75
79
|
userCalled: false
|
|
76
80
|
});
|
|
77
81
|
|
|
@@ -11,31 +11,36 @@ export function programChange(programNumber, userChange = false)
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
// always 128 for percussion
|
|
14
|
-
|
|
14
|
+
let bank = this.getBankSelect();
|
|
15
15
|
let sentBank;
|
|
16
16
|
let preset;
|
|
17
17
|
|
|
18
|
+
const isXG = this.isXGChannel;
|
|
18
19
|
// check if override
|
|
19
20
|
if (this.synth.overrideSoundfont)
|
|
20
21
|
{
|
|
21
22
|
const bankWithOffset = bank === 128 ? 128 : bank - this.synth.soundfontBankOffset;
|
|
22
|
-
const p = this.synth.overrideSoundfont.getPresetNoFallback(
|
|
23
|
+
const p = this.synth.overrideSoundfont.getPresetNoFallback(
|
|
24
|
+
bankWithOffset,
|
|
25
|
+
programNumber,
|
|
26
|
+
isXG
|
|
27
|
+
);
|
|
23
28
|
if (p)
|
|
24
29
|
{
|
|
25
|
-
sentBank = bank;
|
|
30
|
+
sentBank = p.bank === 128 ? 128 : p.bank + this.synth.soundfontBankOffset;
|
|
26
31
|
preset = p;
|
|
27
32
|
this.presetUsesOverride = true;
|
|
28
33
|
}
|
|
29
34
|
else
|
|
30
35
|
{
|
|
31
|
-
preset = this.synth.soundfontManager.getPreset(bank, programNumber);
|
|
36
|
+
preset = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
32
37
|
sentBank = preset.bank;
|
|
33
38
|
this.presetUsesOverride = false;
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
else
|
|
37
42
|
{
|
|
38
|
-
preset = this.synth.soundfontManager.getPreset(bank, programNumber);
|
|
43
|
+
preset = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
39
44
|
sentBank = preset.bank;
|
|
40
45
|
this.presetUsesOverride = false;
|
|
41
46
|
}
|
|
@@ -11,8 +11,7 @@ export function clearSoundFont(sendPresets = true, clearOverride = true)
|
|
|
11
11
|
delete this.overrideSoundfont;
|
|
12
12
|
this.overrideSoundfont = undefined;
|
|
13
13
|
}
|
|
14
|
-
this.
|
|
15
|
-
this.drumPreset = this.getPreset(128, 0);
|
|
14
|
+
this.getDefaultPresets();
|
|
16
15
|
this.cachedVoices = [];
|
|
17
16
|
|
|
18
17
|
for (let i = 0; i < this.workletProcessorChannels.length; i++)
|
|
@@ -20,7 +19,7 @@ export function clearSoundFont(sendPresets = true, clearOverride = true)
|
|
|
20
19
|
const channelObject = this.workletProcessorChannels[i];
|
|
21
20
|
if (!clearOverride || (clearOverride && channelObject.presetUsesOverride))
|
|
22
21
|
{
|
|
23
|
-
channelObject.
|
|
22
|
+
channelObject.setPresetLock(false);
|
|
24
23
|
}
|
|
25
24
|
channelObject.programChange(channelObject.preset.program);
|
|
26
25
|
}
|
|
@@ -10,11 +10,11 @@ export function getPreset(bank, program)
|
|
|
10
10
|
{
|
|
11
11
|
// if override soundfont
|
|
12
12
|
const bankWithOffset = bank === 128 ? 128 : bank - this.soundfontBankOffset;
|
|
13
|
-
const preset = this.overrideSoundfont.getPresetNoFallback(bankWithOffset, program);
|
|
13
|
+
const preset = this.overrideSoundfont.getPresetNoFallback(bankWithOffset, program, this.system === "xg");
|
|
14
14
|
if (preset)
|
|
15
15
|
{
|
|
16
16
|
return preset;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
return this.soundfontManager.getPreset(bank, program);
|
|
19
|
+
return this.soundfontManager.getPreset(bank, program, this.system === "xg");
|
|
20
20
|
}
|
package/synthetizer/worklet_system/worklet_methods/soundfont_management/reload_sound_font.js
CHANGED
|
@@ -32,8 +32,7 @@ export function reloadSoundFont(buffer, isOverride = false)
|
|
|
32
32
|
});
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
-
this.
|
|
36
|
-
this.drumPreset = this.getPreset(128, 0);
|
|
35
|
+
this.getDefaultPresets();
|
|
37
36
|
this.workletProcessorChannels.forEach(c =>
|
|
38
37
|
c.programChange(c.preset.program)
|
|
39
38
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SpessaSynthWarn } from "../../../../utils/loggin.js";
|
|
2
2
|
import { WorkletSoundfontManagerMessageType } from "./sfman_message.js";
|
|
3
3
|
import { loadSoundFont } from "../../../../soundfont/load_soundfont.js";
|
|
4
|
+
import { isXGDrums } from "../../../../utils/xg_hacks.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {Object} SoundFontType
|
|
@@ -194,9 +195,10 @@ export class WorkletSoundfontManager
|
|
|
194
195
|
* Gets a given preset from the soundfont stack
|
|
195
196
|
* @param bankNumber {number}
|
|
196
197
|
* @param programNumber {number}
|
|
198
|
+
* @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
|
|
197
199
|
* @returns {BasicPreset} the preset
|
|
198
200
|
*/
|
|
199
|
-
getPreset(bankNumber, programNumber)
|
|
201
|
+
getPreset(bankNumber, programNumber, allowXGDrums = false)
|
|
200
202
|
{
|
|
201
203
|
if (this.soundfontList.length < 1)
|
|
202
204
|
{
|
|
@@ -205,19 +207,25 @@ export class WorkletSoundfontManager
|
|
|
205
207
|
for (const sf of this.soundfontList)
|
|
206
208
|
{
|
|
207
209
|
// check for the preset (with given offset)
|
|
208
|
-
const preset = sf.soundfont.getPresetNoFallback(
|
|
210
|
+
const preset = sf.soundfont.getPresetNoFallback(
|
|
211
|
+
bankNumber - sf.bankOffset,
|
|
212
|
+
programNumber,
|
|
213
|
+
allowXGDrums
|
|
214
|
+
);
|
|
209
215
|
if (preset !== undefined)
|
|
210
216
|
{
|
|
211
217
|
return preset;
|
|
212
218
|
}
|
|
213
219
|
// if not found, advance to the next soundfont
|
|
214
220
|
}
|
|
221
|
+
const isDrum = bankNumber === 128 || (allowXGDrums && isXGDrums(bankNumber));
|
|
215
222
|
// if none found, return the first correct preset found
|
|
216
|
-
if (
|
|
223
|
+
if (!isDrum)
|
|
217
224
|
{
|
|
218
225
|
for (const sf of this.soundfontList)
|
|
219
226
|
{
|
|
220
|
-
const preset = sf.soundfont.presets.find(p => p.program === programNumber
|
|
227
|
+
const preset = sf.soundfont.presets.find(p => p.program === programNumber && !p.isDrumPreset(
|
|
228
|
+
allowXGDrums));
|
|
221
229
|
if (preset)
|
|
222
230
|
{
|
|
223
231
|
return preset;
|
|
@@ -230,7 +238,14 @@ export class WorkletSoundfontManager
|
|
|
230
238
|
{
|
|
231
239
|
for (const sf of this.soundfontList)
|
|
232
240
|
{
|
|
233
|
-
|
|
241
|
+
// check for any drum type (127/128) and matching program
|
|
242
|
+
const p = sf.soundfont.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNumber);
|
|
243
|
+
if (p)
|
|
244
|
+
{
|
|
245
|
+
return p;
|
|
246
|
+
}
|
|
247
|
+
// check for any drum preset
|
|
248
|
+
const preset = sf.soundfont.presets.find(p => p.isDrumPreset(allowXGDrums));
|
|
234
249
|
if (preset)
|
|
235
250
|
{
|
|
236
251
|
return preset;
|
|
@@ -27,7 +27,8 @@ 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 { parseBankSelect } from "../../../utils/xg_hacks.js";
|
|
30
|
+
import { chooseBank, parseBankSelect } from "../../../utils/xg_hacks.js";
|
|
31
|
+
import { DEFAULT_PERCUSSION } from "../../synth_constants.js";
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* This class represents a single MIDI Channel within the synthesizer.
|
|
@@ -114,6 +115,12 @@ class WorkletProcessorChannel
|
|
|
114
115
|
*/
|
|
115
116
|
bank = 0;
|
|
116
117
|
|
|
118
|
+
/**
|
|
119
|
+
* The bank LSB number of the channel (used for patch changes in XG mode).
|
|
120
|
+
* @type {number}
|
|
121
|
+
*/
|
|
122
|
+
bankLSB = 0;
|
|
123
|
+
|
|
117
124
|
/**
|
|
118
125
|
* The preset currently assigned to the channel.
|
|
119
126
|
* @type {BasicPreset}
|
|
@@ -126,6 +133,12 @@ class WorkletProcessorChannel
|
|
|
126
133
|
*/
|
|
127
134
|
lockPreset = false;
|
|
128
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Indicates the MIDI system when the preset was locked.
|
|
138
|
+
* @type {SynthSystem}
|
|
139
|
+
*/
|
|
140
|
+
lockedSystem = "gs";
|
|
141
|
+
|
|
129
142
|
/**
|
|
130
143
|
* Indicates whether the channel uses a preset from the override soundfont.
|
|
131
144
|
* @type {boolean}
|
|
@@ -190,6 +203,11 @@ class WorkletProcessorChannel
|
|
|
190
203
|
this.channelNumber = channelNumber;
|
|
191
204
|
}
|
|
192
205
|
|
|
206
|
+
get isXGChannel()
|
|
207
|
+
{
|
|
208
|
+
return this.synth.system === "xg" || (this.lockPreset && this.lockedSystem === "xg");
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
/**
|
|
194
212
|
* @param type {customControllers|number}
|
|
195
213
|
* @param value {number}
|
|
@@ -231,32 +249,43 @@ class WorkletProcessorChannel
|
|
|
231
249
|
));
|
|
232
250
|
}
|
|
233
251
|
|
|
252
|
+
/**
|
|
253
|
+
* @param locked {boolean}
|
|
254
|
+
*/
|
|
255
|
+
setPresetLock(locked)
|
|
256
|
+
{
|
|
257
|
+
this.lockPreset = locked;
|
|
258
|
+
if (locked)
|
|
259
|
+
{
|
|
260
|
+
this.lockedSystem = this.synth.system;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
234
264
|
/**
|
|
235
265
|
* @param bank {number}
|
|
236
|
-
* @param force {boolean}
|
|
237
266
|
* @param isLSB {boolean}
|
|
238
267
|
*/
|
|
239
|
-
setBankSelect(bank,
|
|
268
|
+
setBankSelect(bank, isLSB = false)
|
|
240
269
|
{
|
|
241
270
|
if (this.lockPreset)
|
|
242
271
|
{
|
|
243
272
|
return;
|
|
244
273
|
}
|
|
245
|
-
if (
|
|
274
|
+
if (isLSB)
|
|
246
275
|
{
|
|
247
|
-
this.
|
|
276
|
+
this.bankLSB = bank;
|
|
248
277
|
}
|
|
249
278
|
else
|
|
250
279
|
{
|
|
280
|
+
this.bank = bank;
|
|
251
281
|
const bankLogic = parseBankSelect(
|
|
252
282
|
this.getBankSelect(),
|
|
253
283
|
bank,
|
|
254
284
|
this.synth.system,
|
|
255
|
-
|
|
285
|
+
false,
|
|
256
286
|
this.drumChannel,
|
|
257
287
|
this.channelNumber
|
|
258
288
|
);
|
|
259
|
-
this.bank = bankLogic.newBank;
|
|
260
289
|
switch (bankLogic.drumsStatus)
|
|
261
290
|
{
|
|
262
291
|
default:
|
|
@@ -264,7 +293,11 @@ class WorkletProcessorChannel
|
|
|
264
293
|
break;
|
|
265
294
|
|
|
266
295
|
case 1:
|
|
267
|
-
this.
|
|
296
|
+
if (this.channelNumber % 16 === DEFAULT_PERCUSSION)
|
|
297
|
+
{
|
|
298
|
+
// cannot disable drums on channel 9
|
|
299
|
+
this.bank = 127;
|
|
300
|
+
}
|
|
268
301
|
break;
|
|
269
302
|
|
|
270
303
|
case 2:
|
|
@@ -279,11 +312,7 @@ class WorkletProcessorChannel
|
|
|
279
312
|
*/
|
|
280
313
|
getBankSelect()
|
|
281
314
|
{
|
|
282
|
-
|
|
283
|
-
{
|
|
284
|
-
return 128;
|
|
285
|
-
}
|
|
286
|
-
return this.bank;
|
|
315
|
+
return chooseBank(this.bank, this.bankLSB, this.drumChannel, this.isXGChannel);
|
|
287
316
|
}
|
|
288
317
|
|
|
289
318
|
/**
|
|
@@ -319,23 +348,17 @@ class WorkletProcessorChannel
|
|
|
319
348
|
// clear transpose
|
|
320
349
|
this.channelTransposeKeyShift = 0;
|
|
321
350
|
this.drumChannel = true;
|
|
322
|
-
this.setPreset(this.synth.getPreset(this.getBankSelect(), this.preset.program));
|
|
323
351
|
}
|
|
324
352
|
else
|
|
325
353
|
{
|
|
326
354
|
this.drumChannel = false;
|
|
327
|
-
this.setPreset(
|
|
328
|
-
this.synth.getPreset(
|
|
329
|
-
this.getBankSelect(),
|
|
330
|
-
this.preset.program
|
|
331
|
-
)
|
|
332
|
-
);
|
|
333
355
|
}
|
|
334
356
|
this.presetUsesOverride = false;
|
|
335
357
|
this.synth.callEvent("drumchange", {
|
|
336
358
|
channel: this.channelNumber,
|
|
337
359
|
isDrumChannel: this.drumChannel
|
|
338
360
|
});
|
|
361
|
+
this.programChange(this.preset.program);
|
|
339
362
|
this.synth.sendChannelProperties();
|
|
340
363
|
}
|
|
341
364
|
|
|
@@ -408,7 +408,7 @@ export function getWorkletVoices(channel,
|
|
|
408
408
|
let preset = channelObject.preset;
|
|
409
409
|
if (overridePatch)
|
|
410
410
|
{
|
|
411
|
-
preset = this.soundfontManager.getPreset(bank, program);
|
|
411
|
+
preset = this.soundfontManager.getPreset(bank, program, this.system === "xg");
|
|
412
412
|
}
|
|
413
413
|
/**
|
|
414
414
|
* @returns {WorkletVoice[]}
|
|
@@ -503,8 +503,7 @@ export function getWorkletVoices(channel,
|
|
|
503
503
|
targetKey,
|
|
504
504
|
realKey,
|
|
505
505
|
generators,
|
|
506
|
-
sampleAndGenerators.modulators.map(m => Modulator.copy(m))
|
|
507
|
-
this.filterSmoothingFactor
|
|
506
|
+
sampleAndGenerators.modulators.map(m => Modulator.copy(m))
|
|
508
507
|
)
|
|
509
508
|
);
|
|
510
509
|
return voices;
|
package/utils/xg_hacks.js
CHANGED
|
@@ -2,6 +2,8 @@ import { SpessaSynthInfo } from "./loggin.js";
|
|
|
2
2
|
import { consoleColors } from "./other.js";
|
|
3
3
|
import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";
|
|
4
4
|
|
|
5
|
+
export const XG_SFX_VOICE = 64;
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* @param bankNr {number}
|
|
7
9
|
* @returns {boolean}
|
|
@@ -11,6 +13,15 @@ export function isXGDrums(bankNr)
|
|
|
11
13
|
return bankNr === 120 || bankNr === 126 || bankNr === 127;
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @param bank {number}
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
export function isValidXGMSB(bank)
|
|
21
|
+
{
|
|
22
|
+
return isXGDrums(bank) || bank === XG_SFX_VOICE;
|
|
23
|
+
}
|
|
24
|
+
|
|
14
25
|
/**
|
|
15
26
|
* Bank select hacks abstracted here
|
|
16
27
|
* @param bankBefore {number} the current bank number
|
|
@@ -29,12 +40,11 @@ export function parseBankSelect(bankBefore, bank, system, isLSB, isDrums, channe
|
|
|
29
40
|
// 64 means SFX in MSB, so it is allowed
|
|
30
41
|
let out = bankBefore;
|
|
31
42
|
let drumsStatus = 0;
|
|
32
|
-
const isValidMSB = b => isXGDrums(b) || b === 64;
|
|
33
43
|
if (isLSB)
|
|
34
44
|
{
|
|
35
45
|
if (system === "xg")
|
|
36
46
|
{
|
|
37
|
-
if (!
|
|
47
|
+
if (!isValidXGMSB(bank))
|
|
38
48
|
{
|
|
39
49
|
out = bank;
|
|
40
50
|
}
|
|
@@ -59,7 +69,7 @@ export function parseBankSelect(bankBefore, bank, system, isLSB, isDrums, channe
|
|
|
59
69
|
break;
|
|
60
70
|
|
|
61
71
|
case "xg":
|
|
62
|
-
canSetBankSelect =
|
|
72
|
+
canSetBankSelect = isValidXGMSB(bank);
|
|
63
73
|
// for xg, if msb is 120, 126 or 127, then it's drums
|
|
64
74
|
if (isXGDrums(bank))
|
|
65
75
|
{
|
|
@@ -112,17 +122,55 @@ export function parseBankSelect(bankBefore, bank, system, isLSB, isDrums, channe
|
|
|
112
122
|
|
|
113
123
|
|
|
114
124
|
/**
|
|
125
|
+
* Chooses a bank number according to spessasynth logic
|
|
126
|
+
* That is:
|
|
127
|
+
* for GS, bank MSB if not drum, otherwise 128
|
|
128
|
+
* for XG: bank MSB if drum and MSB is valid, 128 othewise, bank MSB if it is SFX voice, LSB otherwise
|
|
115
129
|
* @param msb {number}
|
|
116
130
|
* @param lsb {number}
|
|
131
|
+
* @param isDrums {boolean}
|
|
132
|
+
* @param isXG {boolean}
|
|
133
|
+
* @returns {number}
|
|
117
134
|
*/
|
|
118
|
-
export function chooseBank(msb, lsb)
|
|
135
|
+
export function chooseBank(msb, lsb, isDrums, isXG)
|
|
119
136
|
{
|
|
120
|
-
if (
|
|
137
|
+
if (isXG)
|
|
121
138
|
{
|
|
122
|
-
if (
|
|
139
|
+
if (isDrums)
|
|
123
140
|
{
|
|
124
|
-
|
|
141
|
+
if (isXGDrums(msb))
|
|
142
|
+
{
|
|
143
|
+
return msb;
|
|
144
|
+
}
|
|
145
|
+
else
|
|
146
|
+
{
|
|
147
|
+
return 128;
|
|
148
|
+
}
|
|
125
149
|
}
|
|
150
|
+
else
|
|
151
|
+
{
|
|
152
|
+
// check for SFX
|
|
153
|
+
if (msb !== XG_SFX_VOICE)
|
|
154
|
+
{
|
|
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;
|
|
165
|
+
}
|
|
166
|
+
else
|
|
167
|
+
{
|
|
168
|
+
return XG_SFX_VOICE;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else
|
|
173
|
+
{
|
|
174
|
+
return isDrums ? 128 : msb;
|
|
126
175
|
}
|
|
127
|
-
return msb;
|
|
128
176
|
}
|