spessasynth_lib 3.22.10 → 3.22.12
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/@types/soundfont/basic_soundfont/basic_soundfont.d.ts +1 -0
- package/@types/synthetizer/synthetizer.d.ts +13 -1
- package/@types/synthetizer/worklet_system/message_protocol/worklet_message.d.ts +2 -0
- package/midi_parser/midi_editor.js +13 -0
- package/package.json +1 -1
- package/sequencer/worklet_sequencer/play.js +6 -8
- package/sequencer/worklet_sequencer/song_control.js +6 -0
- package/soundfont/basic_soundfont/basic_soundfont.js +7 -0
- package/soundfont/dls/articulator_converter.js +5 -4
- package/soundfont/dls/dls_soundfont.js +6 -0
- package/soundfont/read_sf2/soundfont.js +6 -0
- package/synthetizer/synthetizer.js +39 -2
- package/synthetizer/worklet_processor.min.js +10 -10
- package/synthetizer/worklet_system/main_processor.js +33 -0
- package/synthetizer/worklet_system/message_protocol/handle_message.js +9 -0
- package/synthetizer/worklet_system/message_protocol/worklet_message.js +5 -1
- package/synthetizer/worklet_system/worklet_methods/reset_controllers.js +14 -1
- package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js +9 -0
- package/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +4 -4
- package/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +2 -2
|
@@ -86,6 +86,12 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
86
86
|
|
|
87
87
|
this.enableEventSystem = options.processorOptions.enableEventSystem;
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* If the worklet is alive
|
|
91
|
+
* @type {boolean}
|
|
92
|
+
*/
|
|
93
|
+
this.alive = true;
|
|
94
|
+
|
|
89
95
|
/**
|
|
90
96
|
* Synth's device id: -1 means all
|
|
91
97
|
* @type {number}
|
|
@@ -131,6 +137,9 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
131
137
|
|
|
132
138
|
this.midiVolume = 1;
|
|
133
139
|
|
|
140
|
+
this.reverbGain = 1;
|
|
141
|
+
this.chorusGain = 1;
|
|
142
|
+
|
|
134
143
|
/**
|
|
135
144
|
* Maximum number of voices allowed at once
|
|
136
145
|
* @type {number}
|
|
@@ -310,6 +319,10 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
310
319
|
*/
|
|
311
320
|
process(inputs, outputs)
|
|
312
321
|
{
|
|
322
|
+
if (!this.alive)
|
|
323
|
+
{
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
313
326
|
if (this.processTickCallback)
|
|
314
327
|
{
|
|
315
328
|
this.processTickCallback();
|
|
@@ -382,6 +395,26 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
382
395
|
}
|
|
383
396
|
return true;
|
|
384
397
|
}
|
|
398
|
+
|
|
399
|
+
destroyWorkletProcessor()
|
|
400
|
+
{
|
|
401
|
+
this.alive = false;
|
|
402
|
+
this.workletProcessorChannels.forEach(c =>
|
|
403
|
+
{
|
|
404
|
+
delete c.midiControllers;
|
|
405
|
+
delete c.voices;
|
|
406
|
+
delete c.sustainedVoices;
|
|
407
|
+
delete c.cachedVoices;
|
|
408
|
+
delete c.lockedControllers;
|
|
409
|
+
delete c.preset;
|
|
410
|
+
delete c.customControllers;
|
|
411
|
+
});
|
|
412
|
+
delete this.workletProcessorChannels;
|
|
413
|
+
delete this.sequencer.midiData;
|
|
414
|
+
delete this.sequencer;
|
|
415
|
+
this.soundfontManager.destroyManager();
|
|
416
|
+
delete this.soundfontManager;
|
|
417
|
+
}
|
|
385
418
|
}
|
|
386
419
|
|
|
387
420
|
// include other methods
|
|
@@ -215,6 +215,15 @@ export function handleMessage(message)
|
|
|
215
215
|
SpessaSynthLogging(data[0], data[1], data[2], data[3]);
|
|
216
216
|
break;
|
|
217
217
|
|
|
218
|
+
case workletMessageType.setEffectsGain:
|
|
219
|
+
this.reverbGain = data[0];
|
|
220
|
+
this.chorusGain = data[1];
|
|
221
|
+
break;
|
|
222
|
+
|
|
223
|
+
case workletMessageType.destroyWorklet:
|
|
224
|
+
this.alive = false;
|
|
225
|
+
break;
|
|
226
|
+
|
|
218
227
|
default:
|
|
219
228
|
SpessaSynthWarn("Unrecognized event:", data);
|
|
220
229
|
break;
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
* @property {number} requestSynthesizerSnapshot - 24 -> (no data)
|
|
29
29
|
* @property {number} setLogLevel - 25 -> [enableInfo<boolean>, enableWarning<boolean>, enableGroup<boolean>, enableTable<boolean>]
|
|
30
30
|
* @property {number} keyModifier - 26 -> [messageType<workletKeyModifierMessageType> messageData<any>]
|
|
31
|
+
* @property {number} setEffectsGain - 27 -> [reverbGain<number>, chorusGain<number>]
|
|
32
|
+
* @property {number} destroyWorklet - 28 -> (no data)
|
|
31
33
|
*/
|
|
32
34
|
export const workletMessageType = {
|
|
33
35
|
noteOff: 0,
|
|
@@ -56,7 +58,9 @@ export const workletMessageType = {
|
|
|
56
58
|
sequencerSpecific: 23,
|
|
57
59
|
requestSynthesizerSnapshot: 24,
|
|
58
60
|
setLogLevel: 25,
|
|
59
|
-
keyModifierManager: 26
|
|
61
|
+
keyModifierManager: 26,
|
|
62
|
+
setEffectsGain: 27,
|
|
63
|
+
destroyWorklet: 28
|
|
60
64
|
};
|
|
61
65
|
|
|
62
66
|
/**
|
|
@@ -143,7 +143,20 @@ export function resetControllers(channel)
|
|
|
143
143
|
channelObject.keyCentTuning.fill(0);
|
|
144
144
|
|
|
145
145
|
// reset the array
|
|
146
|
-
|
|
146
|
+
for (let i = 0; i < resetArray.length; i++)
|
|
147
|
+
{
|
|
148
|
+
const resetValue = resetArray[i];
|
|
149
|
+
if (channelObject.midiControllers[i] !== resetValue && i < 127)
|
|
150
|
+
{
|
|
151
|
+
// call cc change if reset
|
|
152
|
+
this.callEvent("controllerchange", {
|
|
153
|
+
channel: channel,
|
|
154
|
+
controllerNumber: i,
|
|
155
|
+
controllerValue: resetValue >> 7
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
channelObject.midiControllers[i] = resetValue;
|
|
159
|
+
}
|
|
147
160
|
channelObject.channelVibrato = { rate: 0, depth: 0, delay: 0 };
|
|
148
161
|
channelObject.holdPedal = false;
|
|
149
162
|
|
|
@@ -240,4 +240,13 @@ export class WorkletSoundfontManager
|
|
|
240
240
|
return this.soundfontList[0].soundfont.presets[0];
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
|
+
|
|
244
|
+
destroyManager()
|
|
245
|
+
{
|
|
246
|
+
this.soundfontList.forEach(s =>
|
|
247
|
+
{
|
|
248
|
+
s.soundfont.destroySoundfont();
|
|
249
|
+
});
|
|
250
|
+
delete this.soundfontList;
|
|
251
|
+
}
|
|
243
252
|
}
|
|
@@ -144,12 +144,12 @@ export class WorkletLowpassFilter
|
|
|
144
144
|
// fix cutoff on low frequencies (fluid_iir_filter.c line 392)
|
|
145
145
|
filter.cutoffHz = Math.min(filter.cutoffHz, 0.45 * sampleRate);
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
filter.reasonanceGain = decibelAttenuationToGain(-1 * qDb); // -1 because it's attenuation and we don't want attenuation
|
|
147
|
+
const qDb = filter.reasonanceCb / 10;
|
|
148
|
+
// correct the filter gain, like fluid does
|
|
149
|
+
filter.reasonanceGain = decibelAttenuationToGain(-1 * (qDb - 3.01)); // -1 because it's attenuation and we don't want attenuation
|
|
150
150
|
|
|
151
151
|
// reduce the gain by the Q factor (fluid_iir_filter.c line 250)
|
|
152
|
-
const qGain = 1 / Math.sqrt(
|
|
152
|
+
const qGain = 1 / Math.sqrt(decibelAttenuationToGain(-qDb));
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
// code is ported from https://github.com/sinshu/meltysynth/ to work with js.
|
|
@@ -38,8 +38,8 @@ export function panVoice(voice,
|
|
|
38
38
|
const gainRight = Math.sin(HALF_PI * voice.currentPan) * gain * this.panRight;
|
|
39
39
|
// disable reverb and chorus in one output mode
|
|
40
40
|
|
|
41
|
-
const reverbLevel = voice.modulatedGenerators[generatorTypes.reverbEffectsSend] / WORKLET_SYSTEM_REVERB_DIVIDER * gain;
|
|
42
|
-
const chorusLevel = voice.modulatedGenerators[generatorTypes.chorusEffectsSend] / WORKLET_SYSTEM_CHORUS_DIVIDER;
|
|
41
|
+
const reverbLevel = this.reverbGain * voice.modulatedGenerators[generatorTypes.reverbEffectsSend] / WORKLET_SYSTEM_REVERB_DIVIDER * gain;
|
|
42
|
+
const chorusLevel = this.chorusGain * voice.modulatedGenerators[generatorTypes.chorusEffectsSend] / WORKLET_SYSTEM_CHORUS_DIVIDER;
|
|
43
43
|
|
|
44
44
|
if (reverbLevel > 0 && !this.oneOutputMode)
|
|
45
45
|
{
|