spessasynth_core 3.27.3 → 3.27.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.
- package/package.json +1 -1
- package/src/soundfont/basic_soundfont/modulator.js +31 -17
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +7 -0
- package/src/synthetizer/audio_engine/engine_components/voice.js +6 -3
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +3 -0
package/package.json
CHANGED
|
@@ -73,6 +73,13 @@ export class Modulator
|
|
|
73
73
|
*/
|
|
74
74
|
isEffectModulator = false;
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The default resonant modulator does not affect the filter gain.
|
|
78
|
+
* Neither XG nor GS responded to cc #74 in that way.
|
|
79
|
+
* @type {boolean}
|
|
80
|
+
*/
|
|
81
|
+
isDefaultResonanceModulator = false;
|
|
82
|
+
|
|
76
83
|
/**
|
|
77
84
|
* 1 if the source is bipolar (min is -1, max is 1)
|
|
78
85
|
* otherwise min is 0 and max is 1
|
|
@@ -198,7 +205,7 @@ export class Modulator
|
|
|
198
205
|
*/
|
|
199
206
|
static copy(modulator)
|
|
200
207
|
{
|
|
201
|
-
|
|
208
|
+
const m = new Modulator(
|
|
202
209
|
modulator.sourceIndex,
|
|
203
210
|
modulator.sourceCurveType,
|
|
204
211
|
modulator.sourceUsesCC,
|
|
@@ -214,6 +221,8 @@ export class Modulator
|
|
|
214
221
|
modulator.transformType,
|
|
215
222
|
modulator.isEffectModulator
|
|
216
223
|
);
|
|
224
|
+
m.isDefaultResonanceModulator = modulator.isDefaultResonanceModulator;
|
|
225
|
+
return m;
|
|
217
226
|
}
|
|
218
227
|
|
|
219
228
|
/**
|
|
@@ -313,7 +322,7 @@ export class Modulator
|
|
|
313
322
|
*/
|
|
314
323
|
sumTransform(modulator)
|
|
315
324
|
{
|
|
316
|
-
|
|
325
|
+
const m = new Modulator(
|
|
317
326
|
this.sourceIndex,
|
|
318
327
|
this.sourceCurveType,
|
|
319
328
|
this.sourceUsesCC,
|
|
@@ -329,6 +338,8 @@ export class Modulator
|
|
|
329
338
|
this.transformType,
|
|
330
339
|
this.isEffectModulator
|
|
331
340
|
);
|
|
341
|
+
m.isDefaultResonanceModulator = modulator.isDefaultResonanceModulator;
|
|
342
|
+
return m;
|
|
332
343
|
}
|
|
333
344
|
}
|
|
334
345
|
|
|
@@ -531,23 +542,26 @@ const customModulators = [
|
|
|
531
542
|
generatorTypes.initialFilterFc,
|
|
532
543
|
6000,
|
|
533
544
|
0
|
|
534
|
-
),
|
|
535
|
-
|
|
536
|
-
// cc 71 (filter Q) to filter Q
|
|
537
|
-
new DecodedModulator(
|
|
538
|
-
getModSourceEnum(
|
|
539
|
-
modulatorCurveTypes.linear,
|
|
540
|
-
1,
|
|
541
|
-
0,
|
|
542
|
-
1,
|
|
543
|
-
midiControllers.filterResonance
|
|
544
|
-
), // linear forwards bipolar cc 74
|
|
545
|
-
0x0, // no controller
|
|
546
|
-
generatorTypes.initialFilterQ,
|
|
547
|
-
250,
|
|
548
|
-
0
|
|
549
545
|
)
|
|
546
|
+
|
|
550
547
|
];
|
|
548
|
+
// cc 71 (filter Q) to filter Q
|
|
549
|
+
const resonanceModulator = new DecodedModulator(
|
|
550
|
+
getModSourceEnum(
|
|
551
|
+
modulatorCurveTypes.linear,
|
|
552
|
+
1,
|
|
553
|
+
0,
|
|
554
|
+
1,
|
|
555
|
+
midiControllers.filterResonance
|
|
556
|
+
), // linear forwards bipolar cc 74
|
|
557
|
+
0x0, // no controller
|
|
558
|
+
generatorTypes.initialFilterQ,
|
|
559
|
+
250,
|
|
560
|
+
0
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
resonanceModulator.isDefaultResonanceModulator = true;
|
|
564
|
+
customModulators.push(resonanceModulator);
|
|
551
565
|
|
|
552
566
|
/**
|
|
553
567
|
* @type {Modulator[]}
|
|
@@ -113,6 +113,13 @@ export function computeModulator(controllerTable, modulator, voice)
|
|
|
113
113
|
computedValue = Math.abs(computedValue);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
// resonant modulator: take its value and ensure that it won't change the final gain
|
|
117
|
+
if (modulator.isDefaultResonanceModulator)
|
|
118
|
+
{
|
|
119
|
+
// half the gain, negates the filter
|
|
120
|
+
voice.resonanceOffset = Math.max(0, computedValue / 2);
|
|
121
|
+
}
|
|
122
|
+
|
|
116
123
|
modulator.currentValue = computedValue;
|
|
117
124
|
return computedValue;
|
|
118
125
|
}
|
|
@@ -143,6 +143,12 @@ class Voice
|
|
|
143
143
|
*/
|
|
144
144
|
modulators = [];
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Resonance offset, it is affected by the default resonant modulator
|
|
148
|
+
* @type {number}
|
|
149
|
+
*/
|
|
150
|
+
resonanceOffset = 0;
|
|
151
|
+
|
|
146
152
|
/**
|
|
147
153
|
* The generators in real-time, affected by modulators.
|
|
148
154
|
* This is used during rendering.
|
|
@@ -290,7 +296,6 @@ class Voice
|
|
|
290
296
|
this.modulatedGenerators = new Int16Array(generators);
|
|
291
297
|
this.modulators = modulators;
|
|
292
298
|
this.filter = new LowpassFilter(sampleRate);
|
|
293
|
-
|
|
294
299
|
this.velocity = velocity;
|
|
295
300
|
this.midiNote = midiNote;
|
|
296
301
|
this.startTime = currentTime;
|
|
@@ -452,8 +457,6 @@ export function getVoicesForPreset(preset, bank, program, midiNote, velocity, re
|
|
|
452
457
|
// MidiNote: midiNote,
|
|
453
458
|
// AudioSample: audioSample
|
|
454
459
|
// }]);
|
|
455
|
-
|
|
456
|
-
|
|
457
460
|
voices.push(
|
|
458
461
|
new Voice(
|
|
459
462
|
this.sampleRate,
|
|
@@ -160,6 +160,9 @@ export function renderVoice(
|
|
|
160
160
|
cents += modEnv * modEnvPitchDepth;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
// default resonant modulator: it does not affect the filter gain (neither XG nor GS did that)
|
|
164
|
+
volumeExcursionCentibels -= voice.resonanceOffset;
|
|
165
|
+
|
|
163
166
|
// finally, calculate the playback rate
|
|
164
167
|
const centsTotal = ~~(cents + semitones * 100);
|
|
165
168
|
if (centsTotal !== voice.currentTuningCents)
|