feat: improve compressor graph
This commit is contained in:
@@ -263,19 +263,44 @@ function CompressorPanel({
|
||||
);
|
||||
}
|
||||
|
||||
// Soft-knee compressor transfer curve, in dB.
|
||||
// Compressor transfer curve, in dB.
|
||||
//
|
||||
// The knee is NOT a smooth/quadratic blend. It is three straight
|
||||
// (piecewise-linear) segments:
|
||||
// 1) input <= kneeStart -> 1:1 line (output = input)
|
||||
// 2) kneeStart < input < kneeEnd -> a straight line connecting the
|
||||
// point on segment (1) at kneeStart
|
||||
// to the point on segment (3) at kneeEnd
|
||||
// 3) input >= kneeEnd -> ratio line (output = threshold + (input-threshold)/ratio)
|
||||
//
|
||||
// kneeStart/kneeEnd are simply the threshold shifted down/up by half the
|
||||
// knee width, so increasing "knee" widens the middle straight segment
|
||||
// symmetrically around the threshold.
|
||||
function compressorOutputDb(input: number, threshold: number, ratio: number, knee: number): number {
|
||||
const kneeStart = threshold - knee / 2;
|
||||
const kneeEnd = threshold + knee / 2;
|
||||
|
||||
if (knee <= 0 || input <= kneeStart) {
|
||||
// No knee: simple two-segment (hard-knee) curve.
|
||||
if (knee <= 0) {
|
||||
return input <= threshold ? input : threshold + (input - threshold) / ratio;
|
||||
}
|
||||
|
||||
// Segment 1: below the knee, straight 1:1 line.
|
||||
if (input <= kneeStart) {
|
||||
return input;
|
||||
}
|
||||
|
||||
// Segment 3: above the knee, straight ratio line.
|
||||
if (input >= kneeEnd) {
|
||||
return threshold + (input - threshold) / ratio;
|
||||
}
|
||||
const x = input - kneeStart;
|
||||
return input + ((1 / ratio - 1) * x * x) / (2 * knee);
|
||||
|
||||
// Segment 2: straight line between the two boundary points
|
||||
// (kneeStart, kneeStart) and (kneeEnd, threshold + (kneeEnd - threshold) / ratio).
|
||||
const y1 = kneeStart;
|
||||
const y2 = threshold + (kneeEnd - threshold) / ratio;
|
||||
const t = (input - kneeStart) / (kneeEnd - kneeStart);
|
||||
return y1 + t * (y2 - y1);
|
||||
}
|
||||
|
||||
function CompressorSection({ dsp, set_compressor }: { dsp: DSP; set_compressor: SetCompressorFn }) {
|
||||
@@ -339,7 +364,7 @@ function CompressorSection({ dsp, set_compressor }: { dsp: DSP; set_compressor:
|
||||
const steps = 120;
|
||||
const points: [number, number][] = [];
|
||||
for (let i = 0; i <= steps; i++) {
|
||||
const x = -60 + (60 * i) / steps;
|
||||
const x = -100 + (100 * i) / steps;
|
||||
points.push([x, compressorOutputDb(x, threshold, ratioNumeric, knee)]);
|
||||
}
|
||||
return points;
|
||||
@@ -352,9 +377,9 @@ function CompressorSection({ dsp, set_compressor }: { dsp: DSP; set_compressor:
|
||||
<div className="compressor-graph__title">{activeOutputState.name} - RMS Compressor</div>
|
||||
|
||||
<LinearGraph
|
||||
xMin={-60}
|
||||
xMin={-100}
|
||||
xMax={0}
|
||||
yMin={-60}
|
||||
yMin={-100}
|
||||
yMax={0}
|
||||
xLabel="in dB"
|
||||
yLabel="out dB"
|
||||
@@ -365,7 +390,7 @@ function CompressorSection({ dsp, set_compressor }: { dsp: DSP; set_compressor:
|
||||
ctx.strokeStyle = '#6b7280';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([4, 4]);
|
||||
const [ux0, uy0] = toPx(-60, -60);
|
||||
const [ux0, uy0] = toPx(-100, -100);
|
||||
const [ux1, uy1] = toPx(0, 0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(ux0, uy0);
|
||||
@@ -377,7 +402,7 @@ function CompressorSection({ dsp, set_compressor }: { dsp: DSP; set_compressor:
|
||||
ctx.strokeStyle = '#fbbf24';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([2, 3]);
|
||||
const [tx0, ty0] = toPx(activeComp.threshold, -60);
|
||||
const [tx0, ty0] = toPx(activeComp.threshold, -100);
|
||||
const [tx1, ty1] = toPx(activeComp.threshold, 0);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(tx0, ty0);
|
||||
|
||||
Reference in New Issue
Block a user