spessasynth_core 3.27.3 → 3.27.5
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 +41 -15
- 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
|
@@ -34,6 +34,20 @@ export const modulatorCurveTypes = {
|
|
|
34
34
|
switch: 3
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
+
|
|
38
|
+
export function getModSourceEnum(curveType, polarity, direction, isCC, index)
|
|
39
|
+
{
|
|
40
|
+
return (curveType << 10) | (polarity << 9) | (direction << 8) | (isCC << 7) | index;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const defaultResonantModSource = getModSourceEnum(
|
|
44
|
+
modulatorCurveTypes.linear,
|
|
45
|
+
1,
|
|
46
|
+
0,
|
|
47
|
+
1,
|
|
48
|
+
midiControllers.filterResonance
|
|
49
|
+
); // linear forwards bipolar cc 74
|
|
50
|
+
|
|
37
51
|
export class Modulator
|
|
38
52
|
{
|
|
39
53
|
/**
|
|
@@ -70,9 +84,18 @@ export class Modulator
|
|
|
70
84
|
* - still can be disabled if the soundfont has its own modulator curve
|
|
71
85
|
* - this fixes the very low amount of reverb by default and doesn't break soundfonts
|
|
72
86
|
* @type {boolean}
|
|
87
|
+
* @readonly
|
|
73
88
|
*/
|
|
74
89
|
isEffectModulator = false;
|
|
75
90
|
|
|
91
|
+
/**
|
|
92
|
+
* The default resonant modulator does not affect the filter gain.
|
|
93
|
+
* Neither XG nor GS responded to cc #74 in that way.
|
|
94
|
+
* @type {boolean}
|
|
95
|
+
* @readonly
|
|
96
|
+
*/
|
|
97
|
+
isDefaultResonantModulator = false;
|
|
98
|
+
|
|
76
99
|
/**
|
|
77
100
|
* 1 if the source is bipolar (min is -1, max is 1)
|
|
78
101
|
* otherwise min is 0 and max is 1
|
|
@@ -151,6 +174,7 @@ export class Modulator
|
|
|
151
174
|
* @param amount {number}
|
|
152
175
|
* @param transformType {0|2}
|
|
153
176
|
* @param isEffectModulator {boolean}
|
|
177
|
+
* @param isDefaultResonantModulator {boolean}
|
|
154
178
|
*/
|
|
155
179
|
constructor(sourceIndex,
|
|
156
180
|
sourceCurveType,
|
|
@@ -165,7 +189,8 @@ export class Modulator
|
|
|
165
189
|
destination,
|
|
166
190
|
amount,
|
|
167
191
|
transformType,
|
|
168
|
-
isEffectModulator = false
|
|
192
|
+
isEffectModulator = false,
|
|
193
|
+
isDefaultResonantModulator = false)
|
|
169
194
|
{
|
|
170
195
|
this.sourcePolarity = sourcePolarity;
|
|
171
196
|
this.sourceDirection = sourceDirection;
|
|
@@ -183,6 +208,7 @@ export class Modulator
|
|
|
183
208
|
this.transformAmount = amount;
|
|
184
209
|
this.transformType = transformType;
|
|
185
210
|
this.isEffectModulator = isEffectModulator;
|
|
211
|
+
this.isDefaultResonantModulator = isDefaultResonantModulator;
|
|
186
212
|
|
|
187
213
|
|
|
188
214
|
if (this.modulatorDestination > MAX_GENERATOR)
|
|
@@ -212,7 +238,8 @@ export class Modulator
|
|
|
212
238
|
modulator.modulatorDestination,
|
|
213
239
|
modulator.transformAmount,
|
|
214
240
|
modulator.transformType,
|
|
215
|
-
modulator.isEffectModulator
|
|
241
|
+
modulator.isEffectModulator,
|
|
242
|
+
modulator.isDefaultResonantModulator
|
|
216
243
|
);
|
|
217
244
|
}
|
|
218
245
|
|
|
@@ -327,7 +354,8 @@ export class Modulator
|
|
|
327
354
|
this.modulatorDestination,
|
|
328
355
|
this.transformAmount + modulator.transformAmount,
|
|
329
356
|
this.transformType,
|
|
330
|
-
this.isEffectModulator
|
|
357
|
+
this.isEffectModulator,
|
|
358
|
+
this.isDefaultResonantModulator
|
|
331
359
|
);
|
|
332
360
|
}
|
|
333
361
|
}
|
|
@@ -385,16 +413,19 @@ export class DecodedModulator extends Modulator
|
|
|
385
413
|
this.modulatorDestination === generatorTypes.reverbEffectsSend
|
|
386
414
|
|| this.modulatorDestination === generatorTypes.chorusEffectsSend
|
|
387
415
|
);
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
this.isDefaultResonantModulator = (
|
|
419
|
+
sourceEnum === defaultResonantModSource
|
|
420
|
+
&& secondarySourceEnum === 0x0
|
|
421
|
+
&& this.modulatorDestination === generatorTypes.initialFilterQ
|
|
422
|
+
);
|
|
388
423
|
}
|
|
389
424
|
}
|
|
390
425
|
|
|
391
426
|
export const DEFAULT_ATTENUATION_MOD_AMOUNT = 960;
|
|
392
427
|
export const DEFAULT_ATTENUATION_MOD_CURVE_TYPE = modulatorCurveTypes.concave;
|
|
393
428
|
|
|
394
|
-
export function getModSourceEnum(curveType, polarity, direction, isCC, index)
|
|
395
|
-
{
|
|
396
|
-
return (curveType << 10) | (polarity << 9) | (direction << 8) | (isCC << 7) | index;
|
|
397
|
-
}
|
|
398
429
|
|
|
399
430
|
const soundFontModulators = [
|
|
400
431
|
// vel to attenuation
|
|
@@ -533,20 +564,15 @@ const customModulators = [
|
|
|
533
564
|
0
|
|
534
565
|
),
|
|
535
566
|
|
|
536
|
-
// cc 71 (filter Q) to filter Q
|
|
567
|
+
// cc 71 (filter Q) to filter Q (default resonant modulator)
|
|
537
568
|
new DecodedModulator(
|
|
538
|
-
|
|
539
|
-
modulatorCurveTypes.linear,
|
|
540
|
-
1,
|
|
541
|
-
0,
|
|
542
|
-
1,
|
|
543
|
-
midiControllers.filterResonance
|
|
544
|
-
), // linear forwards bipolar cc 74
|
|
569
|
+
defaultResonantModSource,
|
|
545
570
|
0x0, // no controller
|
|
546
571
|
generatorTypes.initialFilterQ,
|
|
547
572
|
250,
|
|
548
573
|
0
|
|
549
574
|
)
|
|
575
|
+
|
|
550
576
|
];
|
|
551
577
|
|
|
552
578
|
/**
|
|
@@ -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.isDefaultResonantModulator)
|
|
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)
|