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:
1 parent
23922ee4a2
commit
1df38bd430
20 files changed
+1471
-103
No files matched your search
@@ -442,8 +442,20 @@ describe('a Pan in a sound FX graph (#319)', () => {
|
||||
});
|
||||
|
||||
describe('a Compressor and a Limiter in a sound FX graph (#326)', () => {
|
||||
// The taps a Compressor keeps for its tab do nothing to the sound (#378).
|
||||
const at = (type: string, params?: Record<string, number>) =>
|
||||
fxChainOf(compileSoundFx(line([{ type, params }]).fx.graph).compiled!).stages;
|
||||
fxChainOf(compileSoundFx(line([{ type, params }]).fx.graph).compiled!).stages.filter(
|
||||
(s) => s.kind !== 'tap',
|
||||
);
|
||||
|
||||
it('tap a Compressor on both sides for its tab, a Limiter not (#378)', () => {
|
||||
const kinds = (type: string) =>
|
||||
fxChainOf(compileSoundFx(line([{ type }]).fx.graph).compiled!).stages.map((s) =>
|
||||
s.kind === 'tap' ? `tap ${s.at}` : s.kind,
|
||||
);
|
||||
expect(kinds('SoundFxCompressor')).toEqual(['tap in', 'compress', 'tap out']);
|
||||
expect(kinds('SoundFxLimiter')).toEqual(['limit']);
|
||||
});
|
||||
|
||||
it('compress at their defaults, the gain after it worked out from makeup and auto-gain', () => {
|
||||
const [stage] = at('SoundFxCompressor', { threshold: -12, knee: 0, ratio: 4, autoGain: 1 });
|
||||
@@ -676,9 +688,11 @@ describe('Bypass and Wet (#354)', () => {
|
||||
f.input.ports = [{ key: 'blend', kind: 'number', default: 0.5 }];
|
||||
f.edit.connect(f.input, 'blend', compressor, 'wet');
|
||||
const plan = compileSoundFx(f.fx.graph).compiled!;
|
||||
expect(fxChainOf(plan).stages).toMatchObject([{ kind: 'wet', wet: 0.5, stages: [{ kind: 'compress' }] }]);
|
||||
expect(fxChainOf(plan, { blend: 0 }).stages).toMatchObject([{ kind: 'wet', wet: 0 }]);
|
||||
expect(fxChainOf(plan, { blend: 7 }).stages).toMatchObject([{ kind: 'wet', wet: 1 }]);
|
||||
const stages = (params?: Record<string, number>) =>
|
||||
fxChainOf(plan, params).stages.filter((s) => s.kind !== 'tap');
|
||||
expect(stages()).toMatchObject([{ kind: 'wet', wet: 0.5, stages: [{ kind: 'compress' }] }]);
|
||||
expect(stages({ blend: 0 })).toMatchObject([{ kind: 'wet', wet: 0 }]);
|
||||
expect(stages({ blend: 7 })).toMatchObject([{ kind: 'wet', wet: 1 }]);
|
||||
});
|
||||
|
||||
it('a blend is as late as what it blends and rings as long', () => {
|
||||
|
||||
Reference in new issue
Block a user