From a907ee1fec4933b3e02b0bdaadbcbd6e9bcfe137 Mon Sep 17 00:00:00 2001 From: meleki Date: Fri, 9 Oct 2026 15:58:57 +0200 Subject: [PATCH] Describe the EQ's curve in its node and its spectrum (#375, #374) - Sounds: the node row says the curve is drawn in small and the tab shows a spectrum. The Parametric EQ section has a point for each: the curve in the node and its box without a band, the spectrum with its sides, its scale of 0 to -96 dBFS, what counts as played and when no analyser is fed. "What is heard" names the taps. - Architecture: the `picture` of a node in NodeRegistry and NodeView, the taps in the sound FX compiler, the axes in parametricEq, viewport/spectrum, and the spectrum in EqEditor and eqView. - Development: 1921 checks. Co-Authored-By: Claude Opus 5.5 --- Architecture.md | 14 +++++++++----- Development.md | 2 +- Sounds.md | 18 ++++++++++++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Architecture.md b/Architecture.md index 1e6da7f..fbef841 100644 --- a/Architecture.md +++ b/Architecture.md @@ -132,7 +132,7 @@ src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject src/core/properties/ PropertySchema, kinds (one row per value kind), listItems (an item's kind, read off its value), resolve (the only override merge), deviation (what is gold), collider/camera/bounds geometry, clip (the region clip areas cut each object to, a convex polygon, #260) (with the side a one-way collider blocks from, and the rectangle around a shape a broad phase looks at first, #184), convex (capsules and polygons: rounded convex pieces against each other), ray (where a ray meets a shape, in double precision), rigidbody (what the engine reads off a rigidbody, a collider's material and the scene), joint (what it reads off a joint: its settings, where its far end is, its length and a hinge's limits, #154), aspect, enabled, editorRun, assetRef/textureRef (how a reference reads), declaredRows (the row a Property node declares in a shader or particle graph, and the params that node has in both) src/core/util/ list (take out, put back and move an item — what a command's undo is made of), vec (dot, the closest point on a segment — shared by the collider maths, the outline hit area and the polygon grips; a cubic Bezier at `t` and cut in two at `t` — shared by vector art, its Boolean operations and the curve grips), color (`mixColor`, channel by channel — keys of an animation, stops of a gradient, the particles' Mix colour), recorder (#253: assignments taken back last first — the undo of an edit whose reach is not known in advance) src/core/commands/ undoable commands (pixelArtCommands: one command runs any pixel art edit and keeps the state before it, #130), CommandStack, SetBagValueCommand base, RenameCommand base (undone by renaming back: variable, struct field, port), MoveCommand base (undone by moving back: tile picture, tilemap layer, vector shape), vectorArtCommands (#129: the shapes of a drawing, one gesture one command), one import command shape for texture/font/sound, require.ts (validated lookups, and what an instance may not change), naming.ts -src/core/graph/ graph model, NodeRegistry/NodeContext/values (a travelling list may hold live objects, #157; +src/core/graph/ graph model, NodeRegistry (with a node's `picture` below its rows, as plain shapes, #375)/NodeContext/values (a travelling list may hold live objects, #157; liveObjects' `withoutObjects` empties them on every way out of the run, #238), interpreter, dropTarget, nested (behaviors as nodes), emitGraph (the walk both graph compilers share: each node once, in dependency order; cycles and property names reported), sharedState (what a run shares: a bag per Variables asset, the state of a global machine; what a scene change carries forward and what it starts afresh, #164), @@ -173,7 +173,9 @@ src/core/music/ time (ticks, 480 to the quarter, tempo and meter, a posit pattern item), take (#342: a recorded take as 16-bit WAV, cut to where the song started) src/core/soundfx/ the sound FX graph (#311): nodes (every effect and what it adds to a plan), compile (the graph walked back from the Output to a plan; a parameter stays open until a voice - starts), parametricEq (#367: the bands, and the curve Web Audio plays of them); the + starts; a tapped node gets a `tap` in front and behind, #374), parametricEq (#367: + the bands, the curve Web Audio plays of them, its axes, and the curve in the node, + #375); the effects the FX worklet runs, plain classes tested in Node: pitchPlayer (#317/#346, a phase vocoder), chip (#329), crusher (#322), phaser (#341: Phaser and Flanger), dynamics (#326), lfo (#320: Tremolo and Vibrato); reverb (#328) and saturation (#323) @@ -236,7 +238,8 @@ src/viewport/ WorldViewport (the drawing of a world or a holder, the ba server lacks are uploaded before a save, #130) + pixelArtPicture (every frame composed on the CPU and laid side by side onto one canvas, so a frame is cut out like a texture frame), SoundLibrary + fxNodes (what each stage of a sound FX becomes as Web Audio nodes, and - how the knobs of a playing voice move) + fxWorklet (the AudioWorklet of the effects Web Audio has no node for: a + how the knobs of a playing voice move) + spectrum (#374: the taps of the voices and + buses playing, and the analysers they feed while a node is listened to) + fxWorklet (the AudioWorklet of the effects Web Audio has no node for: a `Source` plays a sound of its own, a way with a Pitch, #317, or a Chip, #329; an `Effect` sits between two stages, the pitch of a bus, #346, a Bitcrusher, a Phaser, a Flanger, a Limiter, a Tremolo or a Vibrato; `Start` keeps either silent until its voice starts, @@ -354,7 +357,7 @@ src/editor/graph/ GraphEditor (header, breadcrumb), GraphCanvas and what it empty space opens, a transition armed from a state's menu), graphDrags (nodes, groups and comments moved or resized, each gesture one undo step), annotationLayer (the boxes behind the edges); graphView (zoom limits, grid, panAndZoom — shared with NodeBoard and the Tile tab's TileCanvas — and `inView`, which nodes are in the picture, #292), EdgeLayer (curves and fold marks), graphMenus, - NodeView + portRow (how an input and an output share one row, #306), NodePalette + paletteEntries (which also ranks a search), folding (hidden links, collapsed nodes), Breadcrumb + trail (the path into nested behaviors), beads (the run's pulses and the clock that launches them), + NodeView (and the picture below the rows, drawn again only when the settings change, #375) + portRow (how an input and an output share one row, #306), NodePalette + paletteEntries (which also ranks a search), folding (hidden links, collapsed nodes), Breadcrumb + trail (the path into nested behaviors), beads (the run's pulses and the clock that launches them), AnnotationView + annotationDrag (groups and comments: what a drag carries, each thing moved once), SnapToggle (the magnet every tab that snaps carries, the vector art tab included, #194) src/editor/container/ ContainerEditor (header), ContainerCanvas (a SceneViewport on a template) @@ -398,7 +401,8 @@ src/editor/sound/ SoundEditor (#343: header with Play, the clip's direction and length in the inspector), SoundPicker (the "+ → Sound" rows with their play mark) src/editor/soundfx/ SoundFxEditor (#311: the graph, a sound to try it on, Play and Stop), PreviewParams (the header's fields for the parameters a tab plays with, shared with the Instrument tab), - EqEditor + eqView (#367/#370: the Parametric EQ in a tab of its own, its curve on a picture) + EqEditor + eqView (#367/#370: the Parametric EQ in a tab of its own, its handles on + the picture, and the spectrum behind the curve, #374) src/editor/instrument/ InstrumentEditor (#331: the graph over the keys, Preset, Randomize, Mutate, Audition), PianoKeyboard + keys (the keys drawn, played by the pointer and the computer keyboard) src/editor/routing/ RoutingEditor (#351: the Master routing tab, one per project) diff --git a/Development.md b/Development.md index 7137ac4..dd69c45 100644 --- a/Development.md +++ b/Development.md @@ -19,7 +19,7 @@ php tests/php/accounts.test.php # the API's accoun php tests/php/snapshots.test.php # the snapshot store (#231), the same way php tests/php/releases.test.php # the release store (#266), the same way php tests/php/files.test.php # uploaded files in a folder per account (#344), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1919 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1921 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/Sounds.md b/Sounds.md index 72a4b0f..503bcbf 100644 --- a/Sounds.md +++ b/Sounds.md @@ -364,7 +364,7 @@ response of a Reverb, and as what the Sound FX tab tries out. Its row means noth | **Gain** | Louder or quieter, in dB (`Gain (dB)`): 0 leaves it alone, -6 is about half as loud, +6 twice. Above 0 the sound can clip. | | **Pitch** | Higher or lower, in semitones (12 is an octave, 0.5 a quarter tone). The sound **keeps its length**, also when the pitch changes while it plays. The pitch is made where the sound is read, so an effect before the Pitch acts as if it came after it. On a [Chip](Instruments#chips) of an instrument it moves the frequency of the Chip itself. Its `wet` takes the semitones from 0 up to all of them, see [below](#bypass-and-wet). | | **5-Band-EQ** | Five bands in dB: 80 Hz and 12 kHz as shelves, 250 Hz, 1 kHz and 4 kHz as peaks. A band at 0 does nothing. | -| **Parametric EQ** | Up to 10 bands, each a filter of its own type, frequency, gain, Q and slope, drawn together as one curve. A **double-click on the node** opens its editor. A new node has no band and does nothing. See [below](#parametric-eq). | +| **Parametric EQ** | Up to 10 bands, each a filter of its own type, frequency, gain, Q and slope, drawn together as one curve, in small in the node too. A **double-click on the node** opens its editor, which also shows the spectrum of what passes the node. A new node has no band and does nothing. See [below](#parametric-eq). | | **Filter** | **Type** *Low-pass* (the default) takes away what is above `frequency` (Hz, 1000 by default), *High-pass* what is below it, *Band-pass* all but a band around it and *Notch* just that band. *Low shelf* and *High shelf* raise or lower everything below or above it by `gain` (dB), *Peaking* a band around it; only these three have the `gain` row. *All-pass* leaves every frequency as loud as it was and only turns its phase. `Q` (0.707 by default) says how sharp it is: at 0.707 a low- or high-pass has no bump, higher it rings at the frequency, and a band, a notch or a peak gets narrower. **Slope** makes a low-pass, high-pass, band-pass or notch steeper: *12 dB/oct* is one filter, *24* two and *48* four in a row, and only the last of them has the Q. In an [instrument](Instruments#envelopes) an Envelope can move all three numbers while a note plays. See [below](#filter). | | **Mix** | Blends the sounds at `a` and `b`: at 0 only `a` is heard, at 1 only `b` (0.5 is the default). **Curve** says what lies between: *Crossfade* (the default) gives half of each at 0.5, *Both at center* keeps each full up to the middle. See [below](#the-curve-of-a-mix). | | **Delay** | An echo: the sound comes back after `time`, again and again, each time `feedback` times as loud. **Sync** says what `time` counts: *Seconds*, or *Beats* in quarter notes at the tempo of the voice. `damping` makes every echo duller than the last. `wet` (0.5) is the sound alone at 0, the sound and its echoes in full at 0.5, the echoes alone at 1. **Ping-pong** sends the echoes left and right in turn. See [below](#delay-and-the-tail-of-a-voice). | @@ -598,6 +598,18 @@ opens its editor, in a sound FX and in an instrument alike. - **The curve** takes the room of the tab and shows 20 Hz to 20 kHz in octaves and -24 to +24 dB. The thick line is all bands together, each band has a thin line in its own colour and a numbered handle. +- **In the node** (#375) the curve of all bands is drawn in small below its rows, on the same + axes: the 0 dB line, the area up or down to the curve, and the curve. Without a band the box + stays, flat, so the node does not grow at the first one. It follows every change, a drag in the + tab as well. A double-click on it opens the tab like anywhere on the node. +- **The spectrum** (#374): while the EQ's tab is seen, in the tab row or in a window, it draws + behind the curve what passes the node right now. Faint and grey is the sound as it comes in, + in the colour of a sound port as it goes on, so you see what the EQ takes away. It has its own + scale: 0 dBFS at the top of the picture, -96 dBFS at its foot. Every sound passing the node + counts: the sound FX's *Play*, an instrument's keys, a song, a run in the editor and the game. + Each side is one analysis of 8192 points, about 6 Hz apart at 48 kHz, smoothed by the browser's + analyser, so it falls away softly once the sound has gone. While the tab is not seen, no + analyser is fed. - **With the mouse:** a double-click on free space adds a peak there. Dragging a handle moves the band's frequency and, for a peak or a shelf, its gain. The mouse wheel over a handle, or anywhere while a band is picked, makes it a sixth of an octave narrower or wider. A right-click on a @@ -612,7 +624,9 @@ opens its editor, in a sound FX and in an instrument alike. band. - **What is heard:** each band is one `BiquadFilterNode` per voice, or 2 or 4 for a steeper slope. A peak or a shelf at 0 dB is left out. The curve is worked out with the formulas Web Audio - uses, at 48 kHz. + uses, at 48 kHz. In front of the bands and behind them every voice and every bus has a tap, a + gain of 1 that does nothing to the sound. Only while the tab is seen do the taps of that node + feed its analysers. A bypassed EQ keeps its taps. - The bands are saved on the node as a list (`bands`). They have no input, so a parameter of the Input or an Envelope cannot move them. Bypass and `wet` work as on every effect.