mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-12 22:15:27 -04:00
Merge branch 'main' into glossing/midin-channels
This commit is contained in:
@@ -2786,3 +2786,17 @@ export const scrub = register(
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
/**
|
||||
* Transient shaper. Gives independent control over the emphasis on transients
|
||||
* and sustains
|
||||
*
|
||||
* @name transient
|
||||
* @param {number | Pattern} attack Emphasis on transients; between -1 (deaccentuate) and 1 (accentuate)
|
||||
* @param {number | Pattern} sustain Emphasis on the sustains; between -1 (deaccentuate) and 1 (accentuate)
|
||||
* @example
|
||||
* s("bd").transient("<-1 -0.5 0 0.5 1>")
|
||||
* @example
|
||||
* s("hh*16").bank("tr909").transient("<-1:1 1:-1>")
|
||||
*/
|
||||
export const { transient } = registerControl(['transient', 'transsustain']);
|
||||
|
||||
@@ -448,6 +448,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||
compressorKnee,
|
||||
compressorAttack,
|
||||
compressorRelease,
|
||||
transient,
|
||||
transsustain,
|
||||
} = value;
|
||||
|
||||
delaytime = delaytime ?? cycleToSeconds(delaysync, cps);
|
||||
@@ -529,6 +531,23 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
||||
chain.push(sourceNode);
|
||||
stretch !== undefined && chain.push(getWorklet(ac, 'phase-vocoder-processor', { pitchFactor: stretch }));
|
||||
|
||||
transient !== undefined &&
|
||||
chain.push(
|
||||
getWorklet(
|
||||
ac,
|
||||
'transient-processor',
|
||||
{},
|
||||
{
|
||||
processorOptions: {
|
||||
attack: transient,
|
||||
sustain: transsustain,
|
||||
begin: t,
|
||||
end: endWithRelease,
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// gain stage
|
||||
chain.push(gainNode(gain));
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ const PI = Math.PI;
|
||||
const TWO_PI = 2 * PI;
|
||||
const INVSR = 1 / sampleRate;
|
||||
|
||||
const timeToCoeff = (t) => 1 - Math.exp(-INVSR / t);
|
||||
const dbToLin = (db) => Math.pow(10, db / 20);
|
||||
|
||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||
const mod = (n, m) => ((n % m) + m) % m;
|
||||
const lerp = (a, b, n) => n * (b - a) + a;
|
||||
@@ -1384,3 +1387,82 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
|
||||
}
|
||||
|
||||
registerProcessor('wavetable-oscillator-processor', WavetableOscillatorProcessor);
|
||||
|
||||
class TransientProcessor extends AudioWorkletProcessor {
|
||||
static get parameterDescriptors() {
|
||||
return [];
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
super();
|
||||
this.gainCoeff = timeToCoeff(0.2);
|
||||
this.avgGain = 1;
|
||||
let {
|
||||
attackTime = 0.003,
|
||||
sustainTime = 0.08,
|
||||
attack = 0,
|
||||
sustain = 0,
|
||||
sensitivity = 0.1,
|
||||
mix = 1,
|
||||
begin = 0,
|
||||
end = 0,
|
||||
} = options.processorOptions;
|
||||
attackTime = clamp(attackTime, 0.0005, 0.05);
|
||||
sustainTime = clamp(sustainTime, 0.01, 0.5);
|
||||
this.attackCoeff = timeToCoeff(attackTime);
|
||||
this.sustainCoeff = timeToCoeff(sustainTime);
|
||||
this.attackAmt = clamp(attack, -1, 1);
|
||||
this.sustainAmt = clamp(sustain, -1, 1);
|
||||
this.scaling = 0.5 + 5 * clamp(sensitivity, 0, 1);
|
||||
this.mix = clamp(mix, 0, 1);
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.attackEnv = new Float32Array(2); // assume stereo
|
||||
this.sustainEnv = new Float32Array(2);
|
||||
}
|
||||
|
||||
process(inputs, outputs, _params) {
|
||||
const input = inputs[0];
|
||||
const output = outputs[0];
|
||||
if (currentTime >= this.end) {
|
||||
return false;
|
||||
}
|
||||
if (currentTime <= this.begin) {
|
||||
return true;
|
||||
}
|
||||
const channels = input.length;
|
||||
if (channels > this.attackEnv.length) {
|
||||
this.attackEnv = new Float32Array(channels);
|
||||
this.sustainEnv = new Float32Array(channels);
|
||||
}
|
||||
let avgGain = this.avgGain;
|
||||
for (let ch = 0; ch < channels; ch++) {
|
||||
let attEnv = this.attackEnv[ch];
|
||||
let susEnv = this.sustainEnv[ch];
|
||||
for (let n = 0; n < blockSize; n++) {
|
||||
const sample = input[ch][n];
|
||||
const x = Math.abs(sample);
|
||||
attEnv = lerp(attEnv, x, this.attackCoeff);
|
||||
susEnv = lerp(susEnv, x, this.sustainCoeff);
|
||||
const peakiness = clamp((this.scaling * (attEnv - susEnv)) / (susEnv + 1e-6), -1.5, 1.5);
|
||||
const attScale = peakiness > 0 ? peakiness : 0;
|
||||
const susScale = peakiness < 0 ? -peakiness : 0;
|
||||
const attackGain = dbToLin(this.attackAmt * attScale * 18);
|
||||
const sustainGain = dbToLin(this.sustainAmt * susScale * 36);
|
||||
const gain = clamp(attackGain * sustainGain, 0, 8);
|
||||
avgGain = lerp(avgGain, gain, this.gainCoeff);
|
||||
const makeup = avgGain > 1e-3 ? 1 / avgGain : 1;
|
||||
const wet = sample * gain * makeup;
|
||||
let y = lerp(sample, wet, this.mix);
|
||||
y /= 1 + Math.abs(y); // soft clip
|
||||
output[ch][n] = y;
|
||||
}
|
||||
this.attackEnv[ch] = attEnv;
|
||||
this.sustainEnv[ch] = susEnv;
|
||||
}
|
||||
this.avgGain = avgGain;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('transient-processor', TransientProcessor);
|
||||
|
||||
@@ -12029,6 +12029,84 @@ exports[`runs examples > example "tour" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "transient" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | s:bd transient:-1 ]",
|
||||
"[ 1/1 → 2/1 | s:bd transient:-0.5 ]",
|
||||
"[ 2/1 → 3/1 | s:bd transient:0 ]",
|
||||
"[ 3/1 → 4/1 | s:bd transient:0.5 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "transient" example index 1 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 1/16 → 1/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 1/8 → 3/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 3/16 → 1/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 1/4 → 5/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 5/16 → 3/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 3/8 → 7/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 7/16 → 1/2 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 1/2 → 9/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 9/16 → 5/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 5/8 → 11/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 11/16 → 3/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 3/4 → 13/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 13/16 → 7/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 7/8 → 15/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 15/16 → 1/1 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 1/1 → 17/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 17/16 → 9/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 9/8 → 19/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 19/16 → 5/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 5/4 → 21/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 21/16 → 11/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 11/8 → 23/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 23/16 → 3/2 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 3/2 → 25/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 25/16 → 13/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 13/8 → 27/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 27/16 → 7/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 7/4 → 29/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 29/16 → 15/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 15/8 → 31/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 31/16 → 2/1 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 2/1 → 33/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 33/16 → 17/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 17/8 → 35/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 35/16 → 9/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 9/4 → 37/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 37/16 → 19/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 19/8 → 39/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 39/16 → 5/2 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 5/2 → 41/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 41/16 → 21/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 21/8 → 43/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 43/16 → 11/4 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 11/4 → 45/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 45/16 → 23/8 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 23/8 → 47/16 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 47/16 → 3/1 | s:hh bank:tr909 transient:-1 transsustain:1 ]",
|
||||
"[ 3/1 → 49/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 49/16 → 25/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 25/8 → 51/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 51/16 → 13/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 13/4 → 53/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 53/16 → 27/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 27/8 → 55/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 55/16 → 7/2 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 7/2 → 57/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 57/16 → 29/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 29/8 → 59/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 59/16 → 15/4 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 15/4 → 61/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 61/16 → 31/8 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 31/8 → 63/16 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
"[ 63/16 → 4/1 | s:hh bank:tr909 transient:1 transsustain:-1 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "transpose" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:C2 ]",
|
||||
|
||||
Reference in New Issue
Block a user