Edit a Compressor in a tab of its own, with knobs and levels (#378)

A Compressor had only its number rows in the node. Its numbers are
easier to set by feel on a dial, and what it does is easier to judge
when the level going in and the level going out are seen side by side.

- Knob is a new widget in the toolkit: a slider bent into a circle,
  its name above and a number field below. A drag up or down turns
  it, Shift a tenth as far, a notch of the wheel a fiftieth of the
  turn, a double-click sets the default, the number takes a typed
  value. A taper gives the low end more of the turn.
- The Compressor's tab opens on a double-click, one per node, like
  the Parametric EQ's. It has a knob for each of the seven numbers,
  greyed while its input is linked.
- Its curve shows level in to level out from -60 to 0 dB. The point
  where it bends sets the threshold, the end of the curve sets the
  ratio that ends there.
- Its levels show the last 4 s on both sides of the node. Where it
  takes more than 0.5 dB away, the stretch below the level coming in
  is tinted. The makeup is left out of that.
- The Compressor is tapped like the EQ. SpectrumTaps listens to more
  than one node at once and reads the loudest sample of the last
  25 ms on each side.
- The node tabs share one map in the editor (nodeTabs), so a third
  kind needs no new plumbing.

Findings:

- CI task 614 for 23922ee was red on the memory check of the stream:
  the tab's renderer grew by 94 MB with nothing decoded. Play mode
  made garbage of its own and was read before a collection. Both
  readings in play now come after one, and the check compares the
  growth streamed with the growth decoded (3.7 MB against 59.8 MB).
- The ratio handle sat on the right edge of the picture, where a
  widget's hit area ends. The curve is inset by the grab radius.

Tests:

- Gate (melektaus-atx): 282 files, 4338 tests (17 new)
- e2e 34 (melektaus-atx): ALL PASSED, 116 checks (6 new)
- Counter-checks: an inverted ratio search, stop() letting go of
  every node and a drag without its least step each fail exactly
  their test.
- Looked at the tab in a screenshot: a blip at -4.4 dB came out at
  -16.7 dB, the gap tinted, the threshold line at -24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-09 22:40:12 +02:00
1 parent 23922ee4a2
commit 1df38bd430
20 files changed
+1471 -103

No files matched your search

+4 -2
View File
@@ -1005,7 +1005,8 @@ const COMPRESS_ATTACK = { ...numberRow('attack', 'Attack (s)', 0, 1, 0.001), def
const COMPRESS_RELEASE = { ...numberRow('release', 'Release (s)', 0, 1, 0.001), default: 0.25 };
const MAKEUP = numberRow('makeup', 'Makeup (dB)', -24, 24, 0.5);
const AUTO_GAIN = numberRow('autoGain', 'Auto-gain', 0, 1, 0.01);
const COMPRESS_ROWS = {
/** The numbers of a Compressor, in the order its tab shows them as knobs (#378). */
export const COMPRESS_ROWS = {
threshold: COMPRESS_THRESHOLD,
ratio: COMPRESS_RATIO,
knee: COMPRESS_KNEE,
@@ -1020,8 +1021,9 @@ export const SoundFxCompressor: SoundFxNodeDef = effect(
type: 'SoundFxCompressor',
label: 'Compressor',
category: 'sound',
tapped: true,
description:
'Squeezes the loudness of the sound together: what goes above "threshold" (dB) comes out only 1/"ratio" as much louder, so 4 makes 8 dB over it 2 dB. "knee" (dB) eases into that from the threshold on instead of at once. "attack" is how fast it turns down once the sound is over the threshold, "release" how fast it lets go, both in seconds. "makeup" (dB) raises it again afterwards. "auto-gain" from 0 to 1 blends that with the gain that brings a sound at full scale back to full scale: 0 is the makeup alone, 1 the auto-gain alone. It is 6 ms late, which a voice, a Mix and a bus make up for. All of it can change while the sound plays.' +
'Squeezes the loudness of the sound together: what goes above "threshold" (dB) comes out only 1/"ratio" as much louder, so 4 makes 8 dB over it 2 dB. "knee" (dB) eases into that from the threshold on instead of at once. "attack" is how fast it turns down once the sound is over the threshold, "release" how fast it lets go, both in seconds. "makeup" (dB) raises it again afterwards. "auto-gain" from 0 to 1 blends that with the gain that brings a sound at full scale back to full scale: 0 is the makeup alone, 1 the auto-gain alone. It is 6 ms late, which a voice, a Mix and a bus make up for. All of it can change while the sound plays. Double-click the node to open its editor: a knob for each number, its curve with threshold and ratio to drag, and the level coming in and going out over the last seconds.' +
BLENDS,
inputs: [audioIn, ...Object.values(COMPRESS_ROWS).map(numberIn)],
outputs: [audioOut],