Zoom the Parametric EQ's dB with the wheel, saved on its node (#376)
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:
1 parent
41af1a6e51
commit
3377524958
9 files changed
+181
-34
No files matched your search
@@ -18,7 +18,14 @@ import {
|
||||
MAX_EQ_BANDS,
|
||||
withBandSet,
|
||||
} from '../../src/core/soundfx/parametricEq';
|
||||
import { SPECTRUM_FLOOR_DB, spectrumPeak, spectrumYs } from '../../src/editor/soundfx/eqView';
|
||||
import {
|
||||
eqGridDb,
|
||||
handleOf,
|
||||
SPECTRUM_FLOOR_DB,
|
||||
spectrumPeak,
|
||||
spectrumYs,
|
||||
wheeledRange,
|
||||
} from '../../src/editor/soundfx/eqView';
|
||||
import { graphEditor, makeProject, roundTrip } from '../helpers';
|
||||
|
||||
const band = (change: Partial<EqBand>): EqBand => ({
|
||||
@@ -96,6 +103,15 @@ describe('the bands of a Parametric EQ', () => {
|
||||
expect(kinds()).toEqual([`in:${id}`, `out:${id}`]);
|
||||
});
|
||||
|
||||
it('keep the zoom of their curve on the node, saved, and it changes nothing heard (#376)', () => {
|
||||
const f = eqLine([band({ gain: 6 })]);
|
||||
const stages = () => compileSoundFx(f.fx.graph, undefined, f.fx.id).compiled!.stages;
|
||||
const before = stages();
|
||||
f.eq.params.range = 12;
|
||||
expect(stages()).toEqual(before);
|
||||
expect(roundTrip(f.project)).toEqual(f.project);
|
||||
});
|
||||
|
||||
it('draw the curve Web Audio plays', () => {
|
||||
const peak = band({ gain: 6 });
|
||||
expect(bandDb(peak, 1000)).toBeCloseTo(6, 3);
|
||||
@@ -138,8 +154,10 @@ describe('the bands of a Parametric EQ', () => {
|
||||
describe('the curve in the node (#375)', () => {
|
||||
const picture = SoundFxParametricEq.picture!;
|
||||
const W = 164;
|
||||
const area = { w: W, h: picture.height };
|
||||
const lineOf = (bands: unknown) => picture.shapes({ bands } as never, W).find((s) => s.kind === 'line')!;
|
||||
const area = { w: W, h: picture.height, range: 24 };
|
||||
const lineOf = (bands: unknown, range?: number) =>
|
||||
picture.shapes({ bands, range } as never, W).find((s) => s.kind === 'line')!;
|
||||
const topOf = (line: { points: number[] }) => Math.min(...line.points.filter((_, i) => i % 2 === 1));
|
||||
|
||||
it('has its highest point where the peak is, as high as its gain', () => {
|
||||
const line = lineOf([band({ gain: 6 })]);
|
||||
@@ -165,11 +183,43 @@ describe('the curve in the node (#375)', () => {
|
||||
expect(Math.max(...ys)).toBe(picture.height);
|
||||
expect(Math.min(...ys)).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it('shows the dB its tab is zoomed to, and ±24 dB for a range the tab does not offer (#376)', () => {
|
||||
const peak = [band({ gain: 6 })];
|
||||
expect(topOf(lineOf(peak))).toBeCloseTo(dbToY(6, area), 1);
|
||||
expect(topOf(lineOf(peak, 12))).toBeCloseTo(dbToY(6, { ...area, range: 12 }), 1);
|
||||
expect(topOf(lineOf(peak, 12))).toBeCloseTo(picture.height / 4, 1);
|
||||
expect(lineOf(peak, 7)).toEqual(lineOf(peak));
|
||||
});
|
||||
});
|
||||
|
||||
describe('the zoom of the curve in the tab (#376)', () => {
|
||||
it('goes a range smaller with the wheel up and larger with it down, and stops at either end', () => {
|
||||
expect(wheeledRange(24, -100)).toBe(12);
|
||||
expect(wheeledRange(24, 100)).toBe(48);
|
||||
expect(wheeledRange(3, -100)).toBe(3);
|
||||
expect(wheeledRange(48, 100)).toBe(48);
|
||||
});
|
||||
|
||||
it('rules the curve with whole dB, as many lines either side of 0', () => {
|
||||
expect(eqGridDb(3)).toEqual([-2, -1, 0, 1, 2]);
|
||||
expect(eqGridDb(6)).toEqual([-4, -2, 0, 2, 4]);
|
||||
expect(eqGridDb(12)).toEqual([-9, -6, -3, 0, 3, 6, 9]);
|
||||
expect(eqGridDb(24)).toEqual([-18, -12, -6, 0, 6, 12, 18]);
|
||||
expect(eqGridDb(48)).toEqual([-36, -24, -12, 0, 12, 24, 36]);
|
||||
});
|
||||
|
||||
it('keeps the handle of a gain beyond the range on the edge', () => {
|
||||
const area = { w: 600, h: 300, range: 3 };
|
||||
expect(handleOf(band({ gain: 12 }), area).y).toBe(0);
|
||||
expect(handleOf(band({ gain: -12 }), area).y).toBe(300);
|
||||
expect(handleOf(band({ gain: 1.5 }), area).y).toBeCloseTo(75, 6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the spectrum behind the curve (#374)', () => {
|
||||
const BIN = 48000 / 8192;
|
||||
const area = { w: 600, h: 300 };
|
||||
const area = { w: 600, h: 300, range: 24 };
|
||||
const xs = Array.from({ length: 301 }, (_, i) => i * 2);
|
||||
/** All silence but one loud bin at about 1 kHz. */
|
||||
const sine = () => {
|
||||
|
||||
Reference in new issue
Block a user