Skip to content

Commit

Permalink
Fix volenv attack clicks
Browse files Browse the repository at this point in the history
  • Loading branch information
spessasus committed Sep 29, 2024
1 parent 2413cd3 commit b56b2fa
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 37 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SpessaSynth",
"version": "3.20.31",
"version": "3.20.32",
"type": "module",
"scripts": {
"start": "node src/website/server/server.js"
Expand Down
16 changes: 8 additions & 8 deletions src/spessasynth_lib/synthetizer/worklet_processor.min.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,8 @@ export function releaseVoice(voice)
{
voice.releaseStartTime = voice.startTime + MIN_NOTE_LENGTH;
}
if(voice.sample.loopingMode === 3)
{
voice.sample.isLooping = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export class WorkletVolumeEnvelope
{
voice.finished = true;
}
env.currentReleaseGain = decibelAttenuationToGain(env.releaseStartDb);
}
}

Expand Down Expand Up @@ -329,6 +330,7 @@ export class WorkletVolumeEnvelope
// fallthrough

case 1:
let gain;
// attack phase: ramp from 0 to attenuation
while(env.currentSampleTime < env.attackEnd)
{
Expand All @@ -337,11 +339,11 @@ export class WorkletVolumeEnvelope

// Special case: linear gain ramp instead of linear db ramp
let linearAttenuation = 1 - (env.attackEnd - env.currentSampleTime) / env.attackDuration; // 0 to 1
audioBuffer[filledBuffer] *= linearAttenuation * decibelAttenuationToGain(env.attenuation + decibelOffset)

gain = linearAttenuation * decibelAttenuationToGain(env.attenuation + decibelOffset)
audioBuffer[filledBuffer] *= gain;
// set current attenuation to peak as its invalid during this phase
env.currentAttenuationDb = env.attenuation;

env.currentSampleTime++;
if(++filledBuffer >= audioBuffer.length)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ export const interpolationTypes = {
*/
export function getSampleLinear(voice, outputBuffer)
{
let cur = voice.sample.cursor;
const loop = (voice.sample.loopingMode === 1) || (voice.sample.loopingMode === 3 && !voice.isInRelease);
const sampleData = voice.sample.sampleData;
const sample = voice.sample;
let cur = sample.cursor;
const sampleData = sample.sampleData;

if(loop)
if(sample.isLooping)
{
const loopLength = voice.sample.loopEnd - voice.sample.loopStart;
const loopLength = sample.loopEnd - sample.loopStart;
for (let i = 0; i < outputBuffer.length; i++)
{
// check for loop
while(cur >= voice.sample.loopEnd)
while(cur >= sample.loopEnd)
{
cur -= loopLength;
}
Expand All @@ -40,7 +40,7 @@ export function getSampleLinear(voice, outputBuffer)
const floor = ~~cur;
let ceil = floor + 1;

while(ceil >= voice.sample.loopEnd)
while(ceil >= sample.loopEnd)
{
ceil -= loopLength;
}
Expand All @@ -52,15 +52,15 @@ export function getSampleLinear(voice, outputBuffer)
const lower = sampleData[floor];
outputBuffer[i] = (lower + (upper - lower) * fraction);

cur += voice.sample.playbackStep * voice.currentTuningCalculated;
cur += sample.playbackStep * voice.currentTuningCalculated;
}
}
else
{
// check and correct end errors
if(voice.sample.end >= sampleData.length)
if(sample.end >= sampleData.length)
{
voice.sample.end = sampleData.length - 1;
sample.end = sampleData.length - 1;
}
for (let i = 0; i < outputBuffer.length; i++)
{
Expand All @@ -70,7 +70,7 @@ export function getSampleLinear(voice, outputBuffer)
const ceil = floor + 1;

// flag the voice as finished if needed
if(ceil >= voice.sample.end)
if(ceil >= sample.end)
{
voice.finished = true;
return;
Expand All @@ -83,7 +83,7 @@ export function getSampleLinear(voice, outputBuffer)
const lower = sampleData[floor];
outputBuffer[i] = (lower + (upper - lower) * fraction);

cur += voice.sample.playbackStep * voice.currentTuningCalculated;
cur += sample.playbackStep * voice.currentTuningCalculated;
}
}
voice.sample.cursor = cur;
Expand All @@ -96,38 +96,38 @@ export function getSampleLinear(voice, outputBuffer)
*/
export function getSampleNearest(voice, outputBuffer)
{
let cur = voice.sample.cursor;
const loop = (voice.sample.loopingMode === 1) || (voice.sample.loopingMode === 3 && !voice.isInRelease);
const loopLength = voice.sample.loopEnd - voice.sample.loopStart;
const sampleData = voice.sample.sampleData;
if(loop)
const sample = voice.sample;
let cur = sample.cursor;
const loopLength = sample.loopEnd - sample.loopStart;
const sampleData = sample.sampleData;
if(voice.sample.isLooping)
{
for (let i = 0; i < outputBuffer.length; i++)
{
// check for loop
while(cur >= voice.sample.loopEnd)
while(cur >= sample.loopEnd)
{
cur -= loopLength;
}

// grab the nearest neighbor
let ceil = ~~cur + 1;

while(ceil >= voice.sample.loopEnd)
while(ceil >= sample.loopEnd)
{
ceil -= loopLength;
}

outputBuffer[i] = sampleData[ceil];
cur += voice.sample.playbackStep * voice.currentTuningCalculated;
cur += sample.playbackStep * voice.currentTuningCalculated;
}
}
else
{
// check and correct end errors
if(voice.sample.end >= sampleData.length)
if(sample.end >= sampleData.length)
{
voice.sample.end = sampleData.length - 1;
sample.end = sampleData.length - 1;
}
for (let i = 0; i < outputBuffer.length; i++)
{
Expand All @@ -136,16 +136,16 @@ export function getSampleNearest(voice, outputBuffer)
const ceil = ~~cur + 1;

// flag the voice as finished if needed
if(ceil >= voice.sample.end)
if(ceil >= sample.end)
{
voice.finished = true;
return;
}

//nearest neighbor (uncomment to use)
outputBuffer[i] = sampleData[ceil];
cur += voice.sample.playbackStep * voice.currentTuningCalculated;
cur += sample.playbackStep * voice.currentTuningCalculated;
}
}
voice.sample.cursor = cur;
sample.cursor = cur;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ class WorkletSample
this.loopEnd = loopEnd;
this.end = endIndex;
this.loopingMode = loopingMode;
this.isLooping = this.loopingMode === 1 || this.loopingMode === 3
}



/**
* the sample's audio data
* @type {Float32Array}
Expand Down Expand Up @@ -86,6 +90,13 @@ class WorkletSample
* @type {0|1|2}
*/
loopingMode = 0;


/**
* Indicates if the sample is currently looping
* @type {boolean}
*/
isLooping = false;
}

import { addAndClampGenerator, generatorTypes } from '../../../soundfont/read_sf2/generators.js'
Expand Down

0 comments on commit b56b2fa

Please sign in to comment.