Zoom the Parametric EQ's dB with the wheel, saved on its node (#376)
game-maker / gate (push) Successful in 3m48s
game-maker / suite (push) Successful in 14m59s

Close moves of a few dB were hard to set and to see on a curve that
always spans -24 to +24 dB. The wheel on free space now zooms the dB
the curve shows, and the node's small curve shows the same range.

- The range is one of ±3, ±6, ±12, ±24 and ±48 dB, always the same
  either side of 0. Up zooms in.
- It is saved on the node as `range`, so it is back after loading.
  Like the game scale (#226) it is no undo step. EditorState gets
  `setNodeView` for such a setting of a node.
- The lines across the curve follow the range: every 1, 2, 3, 6 or
  12 dB. A handle whose gain lies beyond the range stays on the edge,
  in sight and in reach.
- The wheel over a handle still turns the band's Q. It no longer does
  so anywhere while a band is picked: after opening, a band nearly
  always is, and the zoom would be out of reach.
- `EqArea` carries the range, so the tab and the node map dB alike.
  The spectrum keeps its own scale.

Tests:
- Unit parametric-eq: 16 green, 5 new (range in compile and save,
  node picture, wheel steps, grid lines, handle on the edge)
- Counter-check: the node's picture without the saved range turns
  the new picture test red
- e2e 34 (melektaus-atx): ALL PASSED, 99 checks, 1 new
- Gate (melektaus-atx): CHECK EXIT 0, 275 files, 4252 tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-09 16:36:33 +02:00
1 parent 41af1a6e51
commit 3377524958
9 files changed
+181 -34

No files matched your search

+1 -1
View File
@@ -630,7 +630,7 @@ export const SoundFxParametricEq: SoundFxNodeDef = effect(
type: 'SoundFxParametricEq',
label: 'Parametric EQ',
category: 'sound',
description: `Up to ${MAX_EQ_BANDS} filters working together, drawn as one curve, here in small. Double-click the node to open its editor: double-click the curve to add a band, drag a band for its frequency and gain, turn the mouse wheel over it for its Q. Each band is a peak, a low or high shelf, a low or high cut, a band-pass or a notch, and a cut, a band-pass or a notch can be steeper with its slope. While the editor is seen, the spectrum of what passes the node is drawn behind the curve: faint as it comes in, strong as it goes on.${BLENDS}`,
description: `Up to ${MAX_EQ_BANDS} filters working together, drawn as one curve, here in small. Double-click the node to open its editor: double-click the curve to add a band, drag a band for its frequency and gain, turn the mouse wheel over it for its Q, and anywhere else to zoom the dB the curve shows, here as well. Each band is a peak, a low or high shelf, a low or high cut, a band-pass or a notch, and a cut, a band-pass or a notch can be steeper with its slope. While the editor is seen, the spectrum of what passes the node is drawn behind the curve: faint as it comes in, strong as it goes on.${BLENDS}`,
inputs: [audioIn],
outputs: [audioOut],
params: [],
+20 -7
View File
@@ -223,15 +223,24 @@ export function eqCurves(
/**
* A picture of the curve, in the EQ's tab and in its node: frequency to the right in octaves, from
* 20 Hz to 20 kHz, and dB up, the same distance either side of 0.
* 20 Hz to 20 kHz, and dB up, `range` either side of 0.
*/
export interface EqArea {
w: number;
h: number;
range: number;
}
/** The dB a picture of the curve shows above and below 0. */
const EQ_VIEW_DB = EQ_GAIN.max;
/**
* The zoom of the curve (#376): the dB it shows above and below 0, one of `EQ_RANGES`. It is saved
* on the node, so the tab and the node show the same.
*/
export const EQ_RANGE_PARAM = 'range';
export const EQ_RANGES: readonly number[] = [3, 6, 12, 24, 48];
const DEFAULT_RANGE = EQ_GAIN.max;
export const eqRangeOf = (params: PropertyBag): number =>
EQ_RANGES.find((range) => range === params[EQ_RANGE_PARAM]) ?? DEFAULT_RANGE;
const SPAN = Math.log(EQ_FREQUENCY.max / EQ_FREQUENCY.min);
@@ -241,9 +250,9 @@ export const frequencyToX = (frequency: number, area: EqArea): number =>
export const xToFrequency = (x: number, area: EqArea): number =>
EQ_FREQUENCY.min * Math.exp((Math.max(0, Math.min(area.w, x)) / area.w) * SPAN);
export const dbToY = (db: number, area: EqArea): number => area.h / 2 - (db / EQ_VIEW_DB) * (area.h / 2);
export const dbToY = (db: number, area: EqArea): number => area.h / 2 - (db / area.range) * (area.h / 2);
export const yToDb = (y: number, area: EqArea): number => ((area.h / 2 - y) / (area.h / 2)) * EQ_VIEW_DB;
export const yToDb = (y: number, area: EqArea): number => ((area.h / 2 - y) / (area.h / 2)) * area.range;
/**
* The curves of `eqCurves` laid onto an area through `steps` + 1 points, evenly in octaves. A point
@@ -301,8 +310,12 @@ function eqPictureShapes(bands: readonly EqBand[], area: EqArea): PictureShape[]
];
}
/** Without a band the box stays, with its 0 dB line: the node does not jump at the first one. */
/**
* Without a band the box stays, with its 0 dB line: the node does not jump at the first one. It shows
* the dB the tab is zoomed to.
*/
export const EQ_PICTURE: NodePicture = {
height: PICTURE_HEIGHT,
shapes: (params, w) => eqPictureShapes(eqBandsOf(params), { w, h: PICTURE_HEIGHT }),
shapes: (params, w) =>
eqPictureShapes(eqBandsOf(params), { w, h: PICTURE_HEIGHT, range: eqRangeOf(params) }),
};