spessasynth_core 4.2.9 → 4.2.10
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/dist/index.d.ts +17 -17
- package/dist/index.js +104 -166
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -362,6 +362,10 @@ declare class VolumeEnvelope {
|
|
|
362
362
|
* The sample rate in Hz.
|
|
363
363
|
*/
|
|
364
364
|
readonly sampleRate: number;
|
|
365
|
+
/**
|
|
366
|
+
* The target gain for the current rendering block.
|
|
367
|
+
*/
|
|
368
|
+
outputGain: number;
|
|
365
369
|
/**
|
|
366
370
|
* The current attenuation of the envelope in cB.
|
|
367
371
|
*/
|
|
@@ -425,21 +429,15 @@ declare class VolumeEnvelope {
|
|
|
425
429
|
* We can't do that with modulated as it can silence the volume and then raise it again, and the voice must keep playing.
|
|
426
430
|
*/
|
|
427
431
|
private canEndOnSilentSustain;
|
|
428
|
-
private readonly gainSmoothing;
|
|
429
|
-
private currentGain;
|
|
430
432
|
/**
|
|
431
|
-
*
|
|
433
|
+
* The current peak gain, used for smoothing.
|
|
434
|
+
* @private
|
|
432
435
|
*/
|
|
433
|
-
|
|
436
|
+
private peakGain;
|
|
434
437
|
/**
|
|
435
|
-
*
|
|
436
|
-
* Essentially we use approach of 100dB is silence, 0dB is peak.
|
|
437
|
-
* @param sampleCount the amount of samples to write
|
|
438
|
-
* @param buffer the audio buffer to modify
|
|
439
|
-
* @param gainTarget the gain target to smooth.
|
|
440
|
-
* @returns if the voice is still active
|
|
438
|
+
* @param sampleRate Hz
|
|
441
439
|
*/
|
|
442
|
-
|
|
440
|
+
constructor(sampleRate: number);
|
|
443
441
|
/**
|
|
444
442
|
* Starts the release phase in the envelope.
|
|
445
443
|
* @param voice the voice this envelope belongs to.
|
|
@@ -450,13 +448,15 @@ declare class VolumeEnvelope {
|
|
|
450
448
|
* @param voice The voice this envelope belongs to
|
|
451
449
|
*/
|
|
452
450
|
init(voice: Voice): void;
|
|
451
|
+
/**
|
|
452
|
+
* Calculates the gain value for the last sample in the block and writes it to `outputGain`.
|
|
453
|
+
* Essentially we use approach of 100dB is silence, 0dB is peak.
|
|
454
|
+
* @param sampleCount the amount of samples to write
|
|
455
|
+
* @param gainTarget the gain to apply.
|
|
456
|
+
* @returns if the voice has finished.
|
|
457
|
+
*/
|
|
458
|
+
process(sampleCount: number, gainTarget: number): boolean;
|
|
453
459
|
private timecentsToSamples;
|
|
454
|
-
private releasePhase;
|
|
455
|
-
private delayPhase;
|
|
456
|
-
private attackPhase;
|
|
457
|
-
private holdPhase;
|
|
458
|
-
private decayPhase;
|
|
459
|
-
private sustainPhase;
|
|
460
460
|
}
|
|
461
461
|
//#endregion
|
|
462
462
|
//#region src/synthesizer/audio_engine/engine_components/dsp_chain/modulation_envelope.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1650,8 +1650,13 @@ function getUsedProgramsAndKeys(mid, soundBank) {
|
|
|
1650
1650
|
const usedProgramsAndKeys = /* @__PURE__ */ new Map();
|
|
1651
1651
|
const ports = mid.tracks.map((t) => t.port);
|
|
1652
1652
|
mid.iterate((event, trackNum) => {
|
|
1653
|
-
if (event.statusByte === midiMessageTypes.midiPort) {
|
|
1654
|
-
|
|
1653
|
+
if (event.statusByte === midiMessageTypes.midiPort && mid.tracks[trackNum].channels.size > 0) {
|
|
1654
|
+
let port = event.data[0];
|
|
1655
|
+
if (mid.portChannelOffsetMap[port] === void 0) {
|
|
1656
|
+
SpessaSynthWarn(`Invalid port ${port} on track ${trackNum}. (No offset found in the MIDI map.`);
|
|
1657
|
+
port = 0;
|
|
1658
|
+
}
|
|
1659
|
+
ports[trackNum] = port;
|
|
1655
1660
|
return;
|
|
1656
1661
|
}
|
|
1657
1662
|
const status = event.statusByte & 240;
|
|
@@ -6043,13 +6048,16 @@ var LowpassFilter = class LowpassFilter {
|
|
|
6043
6048
|
*/
|
|
6044
6049
|
const CB_SILENCE = 960;
|
|
6045
6050
|
const PERCEIVED_CB_SILENCE = 900;
|
|
6046
|
-
const GAIN_SMOOTHING_FACTOR$1 = .01;
|
|
6047
6051
|
var VolumeEnvelope = class {
|
|
6048
6052
|
/**
|
|
6049
6053
|
* The sample rate in Hz.
|
|
6050
6054
|
*/
|
|
6051
6055
|
sampleRate;
|
|
6052
6056
|
/**
|
|
6057
|
+
* The target gain for the current rendering block.
|
|
6058
|
+
*/
|
|
6059
|
+
outputGain = 0;
|
|
6060
|
+
/**
|
|
6053
6061
|
* The current attenuation of the envelope in cB.
|
|
6054
6062
|
*/
|
|
6055
6063
|
attenuationCb = CB_SILENCE;
|
|
@@ -6112,32 +6120,16 @@ var VolumeEnvelope = class {
|
|
|
6112
6120
|
* We can't do that with modulated as it can silence the volume and then raise it again, and the voice must keep playing.
|
|
6113
6121
|
*/
|
|
6114
6122
|
canEndOnSilentSustain = false;
|
|
6115
|
-
|
|
6116
|
-
|
|
6123
|
+
/**
|
|
6124
|
+
* The current peak gain, used for smoothing.
|
|
6125
|
+
* @private
|
|
6126
|
+
*/
|
|
6127
|
+
peakGain = 0;
|
|
6117
6128
|
/**
|
|
6118
6129
|
* @param sampleRate Hz
|
|
6119
6130
|
*/
|
|
6120
6131
|
constructor(sampleRate) {
|
|
6121
6132
|
this.sampleRate = sampleRate;
|
|
6122
|
-
this.gainSmoothing = GAIN_SMOOTHING_FACTOR$1 * (44100 / sampleRate);
|
|
6123
|
-
}
|
|
6124
|
-
/**
|
|
6125
|
-
* Applies volume envelope gain to the given output buffer.
|
|
6126
|
-
* Essentially we use approach of 100dB is silence, 0dB is peak.
|
|
6127
|
-
* @param sampleCount the amount of samples to write
|
|
6128
|
-
* @param buffer the audio buffer to modify
|
|
6129
|
-
* @param gainTarget the gain target to smooth.
|
|
6130
|
-
* @returns if the voice is still active
|
|
6131
|
-
*/
|
|
6132
|
-
process(sampleCount, buffer, gainTarget) {
|
|
6133
|
-
if (this.enteredRelease) return this.releasePhase(sampleCount, buffer, gainTarget);
|
|
6134
|
-
switch (this.state) {
|
|
6135
|
-
case 0: return this.delayPhase(sampleCount, buffer, gainTarget, 0);
|
|
6136
|
-
case 1: return this.attackPhase(sampleCount, buffer, gainTarget, 0);
|
|
6137
|
-
case 2: return this.holdPhase(sampleCount, buffer, gainTarget, 0);
|
|
6138
|
-
case 3: return this.decayPhase(sampleCount, buffer, gainTarget, 0);
|
|
6139
|
-
case 4: return this.sustainPhase(sampleCount, buffer, gainTarget, 0);
|
|
6140
|
-
}
|
|
6141
6133
|
}
|
|
6142
6134
|
/**
|
|
6143
6135
|
* Starts the release phase in the envelope.
|
|
@@ -6189,7 +6181,8 @@ var VolumeEnvelope = class {
|
|
|
6189
6181
|
this.state = 0;
|
|
6190
6182
|
this.sampleTime = 0;
|
|
6191
6183
|
this.canEndOnSilentSustain = voice.modulatedGenerators[generatorTypes.sustainVolEnv] >= PERCEIVED_CB_SILENCE;
|
|
6192
|
-
this.
|
|
6184
|
+
this.peakGain = CENTIBEL_LOOKUP_TABLE[voice.modulatedGenerators[generatorTypes.initialAttenuation] - MIN_CENTIBELS | 0];
|
|
6185
|
+
this.outputGain = this.peakGain;
|
|
6193
6186
|
this.sustainCb = Math.min(CB_SILENCE, voice.modulatedGenerators[generatorTypes.sustainVolEnv]);
|
|
6194
6187
|
this.attackDuration = this.timecentsToSamples(voice.modulatedGenerators[generatorTypes.attackVolEnv]);
|
|
6195
6188
|
const keyNumAddition = (60 - voice.targetKey) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvDecay];
|
|
@@ -6202,132 +6195,65 @@ var VolumeEnvelope = class {
|
|
|
6202
6195
|
this.decayEnd = this.decayDuration + this.holdEnd;
|
|
6203
6196
|
if (this.attackEnd === 0) this.state = 2;
|
|
6204
6197
|
}
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
const
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
this.sampleTime = sampleTime;
|
|
6222
|
-
this.currentGain = currentGain;
|
|
6223
|
-
this.attenuationCb = attenuationCb;
|
|
6224
|
-
return attenuationCb < PERCEIVED_CB_SILENCE;
|
|
6225
|
-
}
|
|
6226
|
-
delayPhase(sampleCount, buffer, gainTarget, filledBuffer) {
|
|
6227
|
-
const { delayEnd } = this;
|
|
6228
|
-
let { sampleTime } = this;
|
|
6229
|
-
if (sampleTime < delayEnd) {
|
|
6230
|
-
this.attenuationCb = CB_SILENCE;
|
|
6231
|
-
const delaySamples = Math.min(delayEnd - sampleTime, sampleCount);
|
|
6232
|
-
buffer.fill(0, filledBuffer, filledBuffer + delaySamples);
|
|
6233
|
-
filledBuffer += delaySamples;
|
|
6234
|
-
sampleTime += delaySamples;
|
|
6235
|
-
if (filledBuffer >= sampleCount) {
|
|
6236
|
-
this.sampleTime = sampleTime;
|
|
6237
|
-
return true;
|
|
6238
|
-
}
|
|
6198
|
+
/**
|
|
6199
|
+
* Calculates the gain value for the last sample in the block and writes it to `outputGain`.
|
|
6200
|
+
* Essentially we use approach of 100dB is silence, 0dB is peak.
|
|
6201
|
+
* @param sampleCount the amount of samples to write
|
|
6202
|
+
* @param gainTarget the gain to apply.
|
|
6203
|
+
* @returns if the voice has finished.
|
|
6204
|
+
*/
|
|
6205
|
+
process(sampleCount, gainTarget) {
|
|
6206
|
+
const { releaseStartTimeSamples, releaseStartCb, releaseDuration, delayEnd, attackEnd, attackDuration, holdEnd, decayEnd, decayDuration, sustainCb } = this;
|
|
6207
|
+
const sampleTime = this.sampleTime += sampleCount;
|
|
6208
|
+
if (this.enteredRelease) {
|
|
6209
|
+
const elapsedRelease = sampleTime - releaseStartTimeSamples;
|
|
6210
|
+
const cbDifference = CB_SILENCE - releaseStartCb;
|
|
6211
|
+
this.attenuationCb = elapsedRelease / releaseDuration * cbDifference + releaseStartCb;
|
|
6212
|
+
this.outputGain = CENTIBEL_LOOKUP_TABLE[this.attenuationCb - MIN_CENTIBELS | 0] * gainTarget;
|
|
6213
|
+
return this.attenuationCb < PERCEIVED_CB_SILENCE;
|
|
6239
6214
|
}
|
|
6240
|
-
this.
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
const { attackEnd, attackDuration, gainSmoothing } = this;
|
|
6246
|
-
let { sampleTime, currentGain } = this;
|
|
6247
|
-
const smooth = currentGain !== gainTarget;
|
|
6248
|
-
if (sampleTime < attackEnd) {
|
|
6249
|
-
this.attenuationCb = 0;
|
|
6250
|
-
while (sampleTime < attackEnd) {
|
|
6251
|
-
if (smooth) currentGain += (gainTarget - currentGain) * gainSmoothing;
|
|
6252
|
-
const linearGain = 1 - (attackEnd - sampleTime) / attackDuration;
|
|
6253
|
-
buffer[filledBuffer] *= linearGain * currentGain;
|
|
6254
|
-
sampleTime++;
|
|
6255
|
-
if (++filledBuffer >= sampleCount) {
|
|
6256
|
-
this.sampleTime = sampleTime;
|
|
6257
|
-
this.currentGain = currentGain;
|
|
6215
|
+
switch (this.state) {
|
|
6216
|
+
case 0:
|
|
6217
|
+
if (sampleTime < delayEnd) {
|
|
6218
|
+
this.attenuationCb = CB_SILENCE;
|
|
6219
|
+
this.outputGain = 0;
|
|
6258
6220
|
return true;
|
|
6259
6221
|
}
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
return this.holdPhase(sampleCount, buffer, gainTarget, filledBuffer);
|
|
6266
|
-
}
|
|
6267
|
-
holdPhase(sampleCount, buffer, gainTarget, filledBuffer) {
|
|
6268
|
-
const { holdEnd, gainSmoothing } = this;
|
|
6269
|
-
let { sampleTime, currentGain } = this;
|
|
6270
|
-
const smooth = currentGain !== gainTarget;
|
|
6271
|
-
if (sampleTime < holdEnd) {
|
|
6272
|
-
this.attenuationCb = 0;
|
|
6273
|
-
while (sampleTime < holdEnd) {
|
|
6274
|
-
if (smooth) currentGain += (gainTarget - currentGain) * gainSmoothing;
|
|
6275
|
-
buffer[filledBuffer] *= currentGain;
|
|
6276
|
-
sampleTime++;
|
|
6277
|
-
if (++filledBuffer >= sampleCount) {
|
|
6278
|
-
this.sampleTime = sampleTime;
|
|
6279
|
-
this.currentGain = currentGain;
|
|
6222
|
+
this.state++;
|
|
6223
|
+
case 1:
|
|
6224
|
+
if (sampleTime < attackEnd) {
|
|
6225
|
+
this.attenuationCb = 0;
|
|
6226
|
+
this.outputGain = (1 - (attackEnd - sampleTime) / attackDuration) * gainTarget;
|
|
6280
6227
|
return true;
|
|
6281
6228
|
}
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6229
|
+
this.state++;
|
|
6230
|
+
case 2:
|
|
6231
|
+
if (sampleTime < holdEnd) {
|
|
6232
|
+
this.attenuationCb = 0;
|
|
6233
|
+
this.outputGain = gainTarget;
|
|
6234
|
+
return true;
|
|
6235
|
+
}
|
|
6236
|
+
this.state++;
|
|
6237
|
+
case 3:
|
|
6238
|
+
if (sampleTime < decayEnd) {
|
|
6239
|
+
this.attenuationCb = (1 - (decayEnd - sampleTime) / decayDuration) * sustainCb;
|
|
6240
|
+
this.outputGain = gainTarget * CENTIBEL_LOOKUP_TABLE[this.attenuationCb - MIN_CENTIBELS | 0];
|
|
6241
|
+
return true;
|
|
6242
|
+
}
|
|
6243
|
+
this.state++;
|
|
6244
|
+
case 4:
|
|
6245
|
+
if (this.canEndOnSilentSustain && sustainCb >= PERCEIVED_CB_SILENCE) {
|
|
6246
|
+
this.attenuationCb = CB_SILENCE;
|
|
6247
|
+
this.outputGain = 0;
|
|
6248
|
+
return false;
|
|
6249
|
+
}
|
|
6250
|
+
this.attenuationCb = sustainCb;
|
|
6251
|
+
this.outputGain = gainTarget * CENTIBEL_LOOKUP_TABLE[sustainCb - MIN_CENTIBELS | 0];
|
|
6302
6252
|
return true;
|
|
6303
|
-
}
|
|
6304
6253
|
}
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
this.state++;
|
|
6309
|
-
return this.sustainPhase(sampleCount, buffer, gainTarget, filledBuffer);
|
|
6310
|
-
}
|
|
6311
|
-
sustainPhase(sampleCount, buffer, gainTarget, filledBuffer) {
|
|
6312
|
-
const { sustainCb, gainSmoothing } = this;
|
|
6313
|
-
if (this.canEndOnSilentSustain && sustainCb >= PERCEIVED_CB_SILENCE) {
|
|
6314
|
-
buffer.fill(0, filledBuffer, sampleCount);
|
|
6315
|
-
return false;
|
|
6316
|
-
}
|
|
6317
|
-
let { sampleTime, currentGain } = this;
|
|
6318
|
-
const smooth = currentGain !== gainTarget;
|
|
6319
|
-
if (filledBuffer < sampleCount) {
|
|
6320
|
-
this.attenuationCb = sustainCb;
|
|
6321
|
-
while (filledBuffer < sampleCount) {
|
|
6322
|
-
if (smooth) currentGain += (gainTarget - currentGain) * gainSmoothing;
|
|
6323
|
-
buffer[filledBuffer] *= currentGain * CENTIBEL_LOOKUP_TABLE[sustainCb - MIN_CENTIBELS | 0];
|
|
6324
|
-
sampleTime++;
|
|
6325
|
-
filledBuffer++;
|
|
6326
|
-
}
|
|
6327
|
-
}
|
|
6328
|
-
this.sampleTime = sampleTime;
|
|
6329
|
-
this.currentGain = currentGain;
|
|
6330
|
-
return true;
|
|
6254
|
+
}
|
|
6255
|
+
timecentsToSamples(tc) {
|
|
6256
|
+
return Math.max(0, Math.floor(timecentsToSeconds(tc) * this.sampleRate));
|
|
6331
6257
|
}
|
|
6332
6258
|
};
|
|
6333
6259
|
//#endregion
|
|
@@ -11386,12 +11312,15 @@ function renderVoice(voice, timeNow, outputL, outputR, startIndex, sampleCount)
|
|
|
11386
11312
|
voice.tuningRatio = Math.pow(2, centsTotal / 1200);
|
|
11387
11313
|
}
|
|
11388
11314
|
const gainTarget = cbAttenuationToGain(modulated[generatorTypes.initialAttenuation]) * cbAttenuationToGain(volumeExcursionCentibels);
|
|
11389
|
-
const buffer = core.voiceBuffer;
|
|
11390
11315
|
if (voice.loopingMode === 2 && !voice.isInRelease) {
|
|
11391
|
-
voice.isActive = voice.volEnv.process(sampleCount,
|
|
11316
|
+
voice.isActive = voice.volEnv.process(sampleCount, gainTarget);
|
|
11392
11317
|
return;
|
|
11393
11318
|
}
|
|
11319
|
+
const buffer = core.voiceBuffer;
|
|
11394
11320
|
voice.isActive = voice.wavetable.process(sampleCount, voice.tuningRatio, buffer);
|
|
11321
|
+
let gain = voice.volEnv.outputGain;
|
|
11322
|
+
const envActive = voice.volEnv.process(sampleCount, gainTarget);
|
|
11323
|
+
const gainInc = (voice.volEnv.outputGain - gain) / sampleCount;
|
|
11395
11324
|
{
|
|
11396
11325
|
const f = voice.filter;
|
|
11397
11326
|
const initialFc = modulated[generatorTypes.initialFilterFc];
|
|
@@ -11402,8 +11331,13 @@ function renderVoice(voice, timeNow, outputL, outputR, startIndex, sampleCount)
|
|
|
11402
11331
|
}
|
|
11403
11332
|
const targetCutoff = f.currentInitialFc + lowpassExcursion;
|
|
11404
11333
|
const modulatedResonance = modulated[generatorTypes.initialFilterQ];
|
|
11405
|
-
if (f.currentInitialFc > 13499 && targetCutoff > 13499 && modulatedResonance === 0)
|
|
11406
|
-
|
|
11334
|
+
if (f.currentInitialFc > 13499 && targetCutoff > 13499 && modulatedResonance === 0) {
|
|
11335
|
+
f.currentInitialFc = 13500;
|
|
11336
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
11337
|
+
buffer[i] *= gain;
|
|
11338
|
+
gain += gainInc;
|
|
11339
|
+
}
|
|
11340
|
+
} else {
|
|
11407
11341
|
if (Math.abs(f.lastTargetCutoff - targetCutoff) > 1 || f.resonanceCb !== modulatedResonance) {
|
|
11408
11342
|
f.lastTargetCutoff = targetCutoff;
|
|
11409
11343
|
f.resonanceCb = modulatedResonance;
|
|
@@ -11418,7 +11352,8 @@ function renderVoice(voice, timeNow, outputL, outputR, startIndex, sampleCount)
|
|
|
11418
11352
|
x1 = input;
|
|
11419
11353
|
y2 = y1;
|
|
11420
11354
|
y1 = filtered;
|
|
11421
|
-
buffer[i] = filtered;
|
|
11355
|
+
buffer[i] = filtered * gain;
|
|
11356
|
+
gain += gainInc;
|
|
11422
11357
|
}
|
|
11423
11358
|
f.x1 = x1;
|
|
11424
11359
|
f.x2 = x2;
|
|
@@ -11426,7 +11361,6 @@ function renderVoice(voice, timeNow, outputL, outputR, startIndex, sampleCount)
|
|
|
11426
11361
|
f.y2 = y2;
|
|
11427
11362
|
}
|
|
11428
11363
|
}
|
|
11429
|
-
const envActive = voice.volEnv.process(sampleCount, buffer, gainTarget);
|
|
11430
11364
|
voice.isActive = voice.isActive && envActive;
|
|
11431
11365
|
let pan;
|
|
11432
11366
|
if (voice.overridePan) pan = voice.overridePan;
|
|
@@ -11434,10 +11368,10 @@ function renderVoice(voice, timeNow, outputL, outputR, startIndex, sampleCount)
|
|
|
11434
11368
|
voice.currentPan += (modulated[generatorTypes.pan] - voice.currentPan) * core.panSmoothingFactor;
|
|
11435
11369
|
pan = voice.currentPan;
|
|
11436
11370
|
}
|
|
11437
|
-
const
|
|
11371
|
+
const outputGain = core.masterParameters.masterGain * core.midiVolume * voiceGain;
|
|
11438
11372
|
const index = pan + 500 | 0;
|
|
11439
|
-
const gainLeft = panTableLeft$1[index] *
|
|
11440
|
-
const gainRight = panTableRight$1[index] *
|
|
11373
|
+
const gainLeft = panTableLeft$1[index] * outputGain * core.panLeft;
|
|
11374
|
+
const gainRight = panTableRight$1[index] * outputGain * core.panRight;
|
|
11441
11375
|
if (this.insertionEnabled) {
|
|
11442
11376
|
const insertionL = core.insertionInputL;
|
|
11443
11377
|
const insertionR = core.insertionInputR;
|
|
@@ -11457,20 +11391,20 @@ function renderVoice(voice, timeNow, outputL, outputR, startIndex, sampleCount)
|
|
|
11457
11391
|
if (!core.enableEffects) return;
|
|
11458
11392
|
const reverbSend = modulated[generatorTypes.reverbEffectsSend] * voice.reverbSend;
|
|
11459
11393
|
if (reverbSend > 0) {
|
|
11460
|
-
const reverbGain = core.masterParameters.reverbGain *
|
|
11394
|
+
const reverbGain = core.masterParameters.reverbGain * outputGain * (reverbSend / 1e3);
|
|
11461
11395
|
const reverb = core.reverbInput;
|
|
11462
11396
|
for (let i = 0; i < sampleCount; i++) reverb[i] += reverbGain * buffer[i];
|
|
11463
11397
|
}
|
|
11464
11398
|
const chorusSend = modulated[generatorTypes.chorusEffectsSend] * voice.chorusSend;
|
|
11465
11399
|
if (chorusSend > 0) {
|
|
11466
|
-
const chorusGain = core.masterParameters.chorusGain * (chorusSend / 1e3) *
|
|
11400
|
+
const chorusGain = core.masterParameters.chorusGain * (chorusSend / 1e3) * outputGain;
|
|
11467
11401
|
const chorus = core.chorusInput;
|
|
11468
11402
|
for (let i = 0; i < sampleCount; i++) chorus[i] += chorusGain * buffer[i];
|
|
11469
11403
|
}
|
|
11470
11404
|
if (core.delayActive) {
|
|
11471
11405
|
const delaySend = this.midiControllers[midiControllers.variationDepth] * voice.delaySend;
|
|
11472
11406
|
if (delaySend > 0) {
|
|
11473
|
-
const delayGain =
|
|
11407
|
+
const delayGain = outputGain * core.masterParameters.delayGain * ((delaySend >> 7) / 127);
|
|
11474
11408
|
const delay = core.delayInput;
|
|
11475
11409
|
for (let i = 0; i < sampleCount; i++) delay[i] += delayGain * buffer[i];
|
|
11476
11410
|
}
|
|
@@ -11542,7 +11476,7 @@ function dataEntryCoarse(dataCoarse) {
|
|
|
11542
11476
|
switch (paramCoarse) {
|
|
11543
11477
|
default:
|
|
11544
11478
|
if (dataCoarse === 64) return;
|
|
11545
|
-
SpessaSynthInfo(`%cUnrecognized NRPN for %c${this.channel}%c: %c(0x${
|
|
11479
|
+
SpessaSynthInfo(`%cUnrecognized NRPN for %c${this.channel}%c: %c(0x${paramCoarse.toString(16).toUpperCase()} 0x${paramFine.toString(16).toUpperCase()})%c data value: %c${dataCoarse}`, consoleColors.warn, consoleColors.recognized, consoleColors.warn, consoleColors.unrecognized, consoleColors.warn, consoleColors.value);
|
|
11546
11480
|
break;
|
|
11547
11481
|
case nonRegisteredMSB.partParameter: {
|
|
11548
11482
|
const paramLock = this.synthCore.masterParameters.nprnParamLock;
|
|
@@ -11821,9 +11755,12 @@ function dataEntryFine(dataValue) {
|
|
|
11821
11755
|
switch (this.dataEntryState) {
|
|
11822
11756
|
default: break;
|
|
11823
11757
|
case dataEntryStates.RPCoarse:
|
|
11824
|
-
case dataEntryStates.RPFine:
|
|
11825
|
-
|
|
11826
|
-
|
|
11758
|
+
case dataEntryStates.RPFine: {
|
|
11759
|
+
const rpnValue = this.midiControllers[midiControllers.registeredParameterMSB] | this.midiControllers[midiControllers.registeredParameterLSB] >> 7;
|
|
11760
|
+
switch (rpnValue) {
|
|
11761
|
+
default:
|
|
11762
|
+
SpessaSynthInfo(`%cUnrecognized RPN LSB for %c${this.channel}%c: %c(0x${rpnValue.toString(16)})%c data value: %c${dataValue}`, consoleColors.warn, consoleColors.recognized, consoleColors.warn, consoleColors.unrecognized, consoleColors.warn, consoleColors.value);
|
|
11763
|
+
break;
|
|
11827
11764
|
case registeredParameterTypes.pitchWheelRange: {
|
|
11828
11765
|
if (dataValue === 0) break;
|
|
11829
11766
|
this.midiControllers[128 + modulatorSources.pitchWheelRange] |= dataValue;
|
|
@@ -11846,16 +11783,17 @@ function dataEntryFine(dataValue) {
|
|
|
11846
11783
|
break;
|
|
11847
11784
|
}
|
|
11848
11785
|
break;
|
|
11786
|
+
}
|
|
11849
11787
|
case dataEntryStates.NRPFine: {
|
|
11850
|
-
const
|
|
11851
|
-
const
|
|
11852
|
-
if (
|
|
11853
|
-
switch (
|
|
11788
|
+
const paramCoarse = this.midiControllers[midiControllers.nonRegisteredParameterMSB] >> 7;
|
|
11789
|
+
const paramFine = this.midiControllers[midiControllers.nonRegisteredParameterLSB] >> 7;
|
|
11790
|
+
if (paramCoarse === nonRegisteredMSB.SF2 || paramCoarse >= nonRegisteredMSB.drumPitch && paramFine <= nonRegisteredMSB.drumDelay || paramCoarse === nonRegisteredMSB.partParameter) return;
|
|
11791
|
+
switch (paramCoarse) {
|
|
11854
11792
|
default:
|
|
11855
|
-
SpessaSynthInfo(`%cUnrecognized NRPN LSB for %c${this.channel}%c: %c(0x${
|
|
11793
|
+
SpessaSynthInfo(`%cUnrecognized NRPN LSB for %c${this.channel}%c: %c(0x${paramCoarse.toString(16).toUpperCase()} 0x${paramFine.toString(16).toUpperCase()})%c data value: %c${dataValue}`, consoleColors.warn, consoleColors.recognized, consoleColors.warn, consoleColors.unrecognized, consoleColors.warn, consoleColors.value);
|
|
11856
11794
|
break;
|
|
11857
11795
|
case nonRegisteredMSB.awe32:
|
|
11858
|
-
handleAWE32NRPN.call(this,
|
|
11796
|
+
handleAWE32NRPN.call(this, paramFine, dataValue, this.midiControllers[midiControllers.dataEntryMSB] >> 7);
|
|
11859
11797
|
break;
|
|
11860
11798
|
}
|
|
11861
11799
|
}
|