28909f0adfb81b99d65618957db9dff1bd9fe334
35
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
28909f0adf |
Show a Limiter node as a device that holds what it took away (#397)
A Limiter only said what it does in rows of numbers. How much it took away, and when, could not be seen at all, and a short sound is over before any needle could show it. Now the node is a device of its own size, and its screen catches the reduction from the moment a sound starts and holds it once the sound ends. - LimiterPanel draws a 720x280 plate of brushed brick. The threshold knob is large, ceiling and release are small beside it, auto-gain is a lever. A LIMIT lamp lights while it takes something away. - The screen hangs the reduction down from the top, 0 to 24 dB by the square root like the Compressor's meter. The level coming in runs along the bottom, orange above the limit. Time runs from the start of the sound over 1, 2, 4 or 8 s, and a longer sound rolls. - ReductionCapture in limiterView holds the capture after 0.4 s of silence, without the silence, until the next sound. It writes the most taken away and when, and NOW or LASTED on the right. - The Limiter is tapped now, like the Compressor. The face reads the loudest sample since the last frame on both sides. - SpectrumTaps.levels takes a lateBy. The side in front is read 5 ms earlier, so a peak going in is met by what it became. - limiterReduction leaves the auto-gain out and solves Wet's blend for the limited part. Less than 0.2 dB counts as none. - A capture is also held when the node leaves the picture. Changing a knob or the lever leaves it as it is. - Hook __gm.limiter.panel(id) for the sound FX and instrument graphs. Decided myself: - The capture stays held until the next sound, not for a fixed time. - The screen has no wet knob, as the Compressor's has none. - The Limiter's two taps cost two gains of 1 per voice. The analysers only exist while the node is in the picture. Measured on stein2: the seeded blip at -4.4 dBFS against -12 dB showed 7.56 dB. Three hits at 0, -8 and -2 dBFS showed 11.9 dB at the first. In e2e 34 on melektaus-atx, -10.44 dBFS in against -20 dB showed 9.56 dB, the difference to the hundredth. Tests: - Unit: limiter-view 13 tests (new), spectrum 6 (1 new), soundfx 67 with the Limiter's taps. - Counter-test: without Wet's share in the formula the blend test fails. - e2e 34: ALL PASSED, 138 checks (1 new). - Gate: CHECK EXIT 0, 290 files, 4445 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
80b25488ce |
Show a Saturation node as a device that glows with its drive (#396)
A Saturation in the graph was a stack of rows. The user wanted a device of its own style and size, like the Delay and the Reverb, that shows warmth and heat the harder the sound is driven. - The node is a copper plate of 720x280 with a button per type, the auto-gain lever, a big drive knob and small knobs for tone, output and wet. Each change is one undo step, wired numbers lock their knob. - The screen draws a sine at -12 dBFS, the level auto-gain is reckoned at, as a grey ghost. Over it is the wave that comes out: bent by the type, its DC taken out, auto-gain and output after it, blended by wet. Under it stand the auto-gain and the peak. - The heat is the drive over 48 dB, as far as wet lets it be heard. The wave goes from cold steel through ember red to white, a glow rises from below and flickers, and embers fly up from about 8 dB on. A lamp beside the name glows with it. - The node keeps the editor drawing only while there is heat. Without drive it draws nothing, unlike the Delay, which always animates. - The Reverb's private type button is now PickButton with its own colours, and the Saturation's type buttons use it as well. - No instrument preset uses a Saturation, so no preset needs more columns. Tests: - Unit saturation-view: 14 new tests. - Counter-check: without taking out the DC, exactly the DC test fails. - e2e 34 (atx): ALL PASSED, 137 checks, one new for type, lever and drive with undo. - Gate (atx): CHECK EXIT 0, 289 files, 4431 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d4a45c127b |
Show a Delay node as a device with its echoes over time (#393)
After the Chip, the Envelope, the Reverb and the one-knob devices, the Delay is drawn as a device of its own size too. Its screen shows what time, feedback, damping, wet and ping-pong make of a sound, and a light runs over the echoes at the beat they come at. - DelayPanel: a 680x280 plate in the Compressor's brushed aluminium, now exported as ALUMINIUM. A screen, levers for Sync and Ping-pong, knobs for Time, Feedback, Damping and Wet, and an Echo lamp. - The screen draws the sound as a white bar and each echo as a bar one step later. A bar is as tall as the echo is loud, evenly in dB to -60. It turns from warm white to rust as the damping takes the highs. With ping-pong the bars alternate above and below, the first left. - At most 24 bars are drawn, and the screen says how many more are heard. Under it stand the step and the end of the tail, above it where the highs of the first echo end. - The running light: DelayFace.tick returns true while the node is in the picture, so the editor keeps drawing, as for the Particles tab. The light goes round the span in real time, a bar glows as it is passed, and the lamp blinks with every echo but not with the sound. - On beats the screen counts at 120 BPM, as the tempo of the voice is not known in the graph. The time knob then names the note, dotted and triplet ones included. In seconds, 2 s and up reads "2 s max". - delayView holds the rules apart from the drawing: layout, tapers, echoTrain, echoCutoff for k rounds of the Butterworth low-pass, sweepAt and the texts. At wet 0 the rest is drawn faint. - delayEchoes in the core counts the echoes heard. The tail of a voice and the screen use it both. DELAY_ROWS, DELAY_SYNC and PING_PONG are exported. - Knob.reformat writes the number anew when its format changes, here when Sync switches between seconds and beats. - The test hook __gm.delay.panel returns knobs, levers, idle settings, the echoes drawn, the texts and where the light is. - Instrument presets give the Delay 4 columns. Echo Lead and Bell use one. In the picture of Echo Lead nothing overlaps. Found on the way: a node with a face draws no setting rows. The e2e check of a bypassed Delay (#354) read "Bypass: true" from them. It now checks the faded node and the stages heard, as before. Tests: - Unit delay-view: 17 tests, new. Counter-check: the first ping-pong echo on the right turns the side test red. - e2e 34 (melektaus-atx): 136 checks, 1 new. - Gate (melektaus-atx): 288 files, 4416 tests. - Pictures looked at: default, ping-pong, beats with damping, 83 echoes at 50 ms, wet 0, and the preset Echo Lead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
389d9555fa |
Show a Pan node as a one-knob device in cyan (#392)
After the Gain, the Pitch and the Mix, the Pan is the next node that is just one number. It now gets the same device in the graph instead of a row for its pan. - PAN_DEVICE: the Gain's 160x160 plate in cyan with one bipolar knob for Pan. The middle stands straight up, and the turn goes evenly to L and R, which are engraved at its ends like A and B on the Mix. - PAN_TAPER in hardwareView is 1, so left and right are heard alike. Device and unit test read the same constant. - PAN_ROW is exported from the core, so the knob has the node's range. - A linked Pan greys the knob, as for the Gain. - The test hook __gm.pan.panel returns the same shape as the Gain's. - No instrument preset uses a Pan, so no preset columns change. Tests: - Unit hardware-view: 17 tests, 2 new (the turn, and L and R inside the plate and clear of the screws). Counter-check: PAN_TAPER 2 turns the turn test red. - e2e 34 (melektaus-atx): 135 checks, 1 new. - Gate (melektaus-atx): 287 files, 4399 tests. - Pictures looked at: Gain, Pitch, Mix and Pan in a row, Pan at -0.35. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fe4e0d9f1a |
Snap to the grid from the start in every graph tab (#391)
Laying out a graph by hand mostly means lining nodes up, so the magnet was switched on in nearly every session. Every graph tab now starts with it lit: Behavior, State machine, Shader, Particles, Sound FX, Instrument, the song's Routing and the Routing tab. - SnapToggle takes the state it starts in and lights its button to match. GRAPH_SNAPS_AT_FIRST sets it for the toggles and for GraphCanvas alike, so button and canvas cannot disagree. - Curve and Vector Art are no graphs and still start without it. - New hook __gm.graphSnapping(on?) reads every graph tab's magnet, or "mixed" where button and canvas differ, and switches them all. - The e2e harness reads the magnets after each navigate() and then switches them off, as it already sets the zoom transition to 0. Most checks drag a node to an exact spot. e2e 45 does the same itself, because the editor comes up there through the sign-in. - e2e 06 checks that all eight graph tabs started with the magnet on. The checks in 06, 26 and 65 that read it off now say they read what the harness left. Tests: - Unit snap-toggle: 4 tests, 1 new (lit at first, nothing asked of the target before a click). - e2e 06 (melektaus-atx): 150 checks, 1 new. e2e 34: 134 checks. - Gate (melektaus-atx, together with #390): 287 files, 4397 tests. - Pictures looked at: none, the state comes from the hook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e70954115c |
Show Pitch and Mix nodes as one-knob devices in green and blue (#390)
The Gain has been a small device with one big knob since #384. The Pitch and the Mix are just as much a single number, so they now look and work the same way. The Mix also gets a lever for its curve, which until now was only a row in the inspector. - GainPanel and GainFace become KnobPanel and KnobFace. Each node is described by a KnobDevice: its plate, its row, how the knob turns, and an optional lever. The Gain looks as before. - Pitch: a green 160x160 plate with a bipolar knob for Semitones. 0 stands straight up and taper 2 puts an octave at 43 % of each half, so small steps near 0 are easy and the full +-64 is still there. - Mix: a blue 180x200 plate, the lever on top and the knob below. The knob has A and B engraved at the ends of its turn. The lever reads "crossfade" down and "both at center" up with its lamp lit. A flip is one undo step. - A wired Semitones or Mix greys the knob, as for the Gain. - The instrument presets give Pitch and Mix two columns. In the graph they are 281 and 261 units wide, more than one column of 240. - The test hooks __gm.pitch.panel and __gm.mix.panel return the same shape as __gm.gain.panel, plus the lever. Tests: - Unit hardware-view: 15 tests, 3 new (Pitch turn, lever above the knob and ends on the Mix plate). Counter-check: taper 1 turns the Pitch test red. - e2e 34 (melektaus-atx): 134 checks, 1 new. - Gate (melektaus-atx, together with #391): 287 files, 4397 tests. - Pictures looked at: Gain, Pitch and Mix in a row, Pitch at -24.5, Mix with both curves, the Bell preset without overlaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e8021b1fd3 |
Show a Reverb node as a device with a round screen of its tail (#389)
The Compressor, the Gain, the Chip and the Envelope are devices in the graph. The Reverb was still a list of rows, and how long and how dark its tail rings was left to the numbers. - The node is a plate of 640x280 in pale lavender. Its inputs are on the left, its output on the right. - A round screen draws the tail as rings out from the sound. A ring's radius is its time, as the root of its seconds, on one scale up to 10.5 s for every Reverb. So a Room is a small disc and a Cave fills two thirds. - A ring is as bright as the tail is loud there, evenly in dB. Its colour is how much of the highs is left, from ice to violet, with the cut-off of the impulse response (reverbCutoff, now shared). - The pre-delay is a dark gap round the dot, a dashed ring marks -60 dB. Seeded dots stand for the reflections. Wet fades the tail against the dot. - A type of Sound draws the peaks of its sound from the library, each against its loudest. It says LOADING until they are there. - A button for each type, a list of the sounds and four chrome knobs: Decay, Damping, Pre-delay and Wet. - A knob the type does not take is greyed but turns. It goes over to Custom with the type's numbers, as one undo step. Picking a sound makes the type Sound, also one step. - NodeParamDrag can write several settings as one drag for that. - Test hook __gm.reverb.panel(nodeId), for the sound FX and the instrument graph. Tests: - Unit reverb-view: 10 new tests for the plate, the knob turn, the numbers per type, the scale, the tail and the texts. A screen that ignores damping turns the highs test red. - e2e 34 (atx): 1 new check (device between its ports, decay knob of a Hall goes to Custom as one undo step, Cave button, a sound from the list makes it Sound and draws that sound). - Probe pictures on stein2: Room, Hall, Cave, Plate, Custom with damping 1 and pre-delay 0.3 s, Sound. - Gate (atx): CHECK EXIT 0, 287 files, 4393 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c75e72d4ee |
Show an Envelope node as a device with its ADSR curve (#388)
The Compressor, the Gain and the Chip are devices in the graph. The Envelope was still a list of rows, and its shape was left to the imagination of whoever read the numbers. - The node is a plate of 520x280 in pale sea green. Its inputs are on the left, out and value on the right. - A dark screen draws the curve over a note in amber. A letter sits above each stage, its time below it, and the sustain in percent above its line. - The time on the screen is squeezed. Each stage is as wide as the root of its seconds, at least 3 %, and the hold has a fixed fifth. So 5 ms of attack still shows beside a release of 3 s. - The falls use SETTLE, as the player does. With sustain 0 there is no hold and no release, and the screen says NOTE ENDS. - Attack, Decay, Sustain and Release are chrome knobs. The times use taper 4, so 5 ms sits an eighth of the way and 1 s not quite half. - From and To have no range a knob could turn through. They are NumberFields on the plate, typed in or scrubbed. - The decay at sustain 1 and From/To while nothing takes value are faded. While a link takes value, the bezel says what it moves between, as VALUE 400 TO 3500. The UI font has no arrow. - Instrument presets give an Envelope 3 columns of 240. - Test hook __gm.envelope.panel(nodeId). Tests: - Unit envelope-view: 6 new tests for the plate, the knob turn, the idle settings and the curve. A linear decay turns two of them red. - e2e 34 (atx): 1 new check on the Laser preset (device between its ports, curve ends with the decay, decay knob and scrubbed To field each one undo step). - Probe pictures on stein2: Synth Brass preset, pad, pluck, organ and an Envelope whose value moves a Chip. - Gate (atx): CHECK EXIT 0, 286 files, 4383 tests. The first run was red on the font test (#214) for an arrow in the bezel text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb78f3cbf3 |
Show a Chip node as a device with its wave and its pitch (#386)
The Chip had eleven numbers in rows and nothing that showed what they do to a note. Its node is now a device of one size like the Compressor's, and two screens draw the wave and the pitch from the settings, worked right in the instrument graph. - ChipPanel is 840x280 in the warm grey of a handheld console. A button per wave, the "follow note" lever and a chrome knob per number, grouped Oscillator, Slide, Vibrato, Arpeggio and Repeat. - The wave screen draws two periods as loud as the Chip plays them, a square at its duty. toneValue and periodicSteps come out of chip.ts, so the screen and the worklet share one formula. - The pitch screen draws what slide, delta slide, vibrato, arpeggio and repeat make of the pitch over a note. It ends where the note falls below "min frequency" and starts from A4 while the Chip follows the note. - Idle settings are faded, wired ones greyed and locked, as the rows were. Every change is one undo step. - Knobs take a bipolar range: 0 straight up, the taper bends each half. Slide, delta slide, duty sweep and arpeggio use it. - The Compressor's auto-gain lever is now a Lever with a name of its own, which the Chip uses for "follow note". - Presets give a Chip five columns, as a Filter has four since #385. Found on the way: - With the Chip this wide the Laser preset is about 3060 units. In a 1280 px window Fit stops at the least zoom of 0.25 and cuts the Notes node off. The zoom limit is left as it is. Tests: - Unit: chip-view (9 new), knob (1 new), chip, chip-presets and hardware-view, 53 green - e2e 34 on melektaus-atx: ALL PASSED, 131 checks (1 new). The first run was red on the check itself: a Laser's "min frequency" can lie above A4, and the screen then rightly says the note ends at once. - Gate on melektaus-atx: CHECK EXIT 0, 285 files, 4377 tests - Counter-check: a square drawn with its duty mirrored turns the wave test red Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c087993000 |
Edit a Filter in its node and resize EQ and Filter nodes (#385)
A Filter sounds like one band of the Parametric EQ, but it keeps what the EQ cannot: linked numbers, the all-pass and +-40 dB. So it stays a node of its own and gets the EQ's editor with itself as the one band. The editors also stop running out of their room: what does not fit is left out instead of being cut. - The curve of the EQ is now BandCurve with a host the EQ and the Filter both fill. CurvePanel holds what their panels share. - FilterPanel shows the Filter as one band. A drag of its handle sets frequency and gain as one undo step. A number fed by a link is greyed out and the drag leaves it alone. - A double-click on the Filter's title opens the same in a tab of its own. Delete there does nothing, the node stays. - The Filter is tapped like the EQ, so its node and its tab draw the spectrum of what passes it. A tap is two gain nodes per voice, the analysers are made only while someone listens. - EqFace and FilterFace are one CurveFace now, given the panel. - EQ and Filter nodes have a corner to resize them, drawn like the floating window's. The size is saved on the node as `size`, each drag is one undo step, the least is 240 x 120. - In the node the help line is gone. The row of numbers comes in only once the curve keeps 120 px of height. A group of the row that does not fit is not drawn, the one on the right first. - A frequency or dB label that would run into the one before it is left out. - The all-pass is drawn flat. The curve's maths takes every shape a Filter has. Found on the way: - The instrument presets set nodes 240 apart. A Filter with its editor is about 700 wide and covered the Bitcrusher, so a Filter now takes four columns. Tests: - Unit: 8 new (filter band, resize command and save, fitting rules), stage lists with a Filter now hold its taps - e2e 34 (atx): ALL PASSED, 130 checks (4 new) - Gate (atx): CHECK EXIT 0, 284 files, 4367 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
17f47f6956 |
Drop the Gain's engraved name and centre its knob (#384)
The plate was taller than its one knob needs, and the engraved "GAIN" only repeated the node's title. Without it the plate is square, and the knob sits in its middle. - The plate is 160x160 instead of 160x220, without the "GAIN" engraving. - The knob is centred on what it shows: the "DB" caption and the dial. Since #382 its number hangs inside the dial's open bottom, so it adds no height. - CAPTION_AIR (4) takes out the empty space above the caption's capitals. Without it the knob sat a little too low. Measured on a picture at zoom 0.8: 19 px of air above "DB" and 19 px below the number. The user's screenshot showed about 14 above and 35 below. Tests: - Unit hardware-view: 12 tests green. The layout test now asks for the same air above and below. - e2e 34 (melektaus-atx): ALL PASSED, 126 checks. - Gate (melektaus-atx): CHECK EXIT 0, 283 files, 4359 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
01ee61868b |
Show a Gain node as an orange device with one knob (#384)
A Gain node now draws a small device in the graph, as the Compressor does since #380: the brushed plate in orange, 160x220 graph units, with one chrome knob between its inputs and its output. - GainPanel and GainFace join the node faces. The knob drags, resets on a double-click and keeps the wheel for the graph (#383). Each turn is one undo step, a linked Gain (dB) greys it. - The knob turns with a taper of 0.26, so 0 dB stands straight up and the range below -24 dB takes a fifth of the turn. - drawPlate, engrave and the brushed look move out of CompressorPanel so both devices share them. The Knob takes an arc colour, because the orange arc vanished on the orange plate. - No meter and no tap. Gain sits in every voice of an instrument, and a tap would add two audio nodes to each note for a display nobody asked for. Found on the way: - Knob.dialGlobal added half the dial unscaled. In a zoomed graph it pointed beside the dial. The Compressor's e2e only hit by luck. Tests: - Unit: 2 new for the Gain plate and its taper. - e2e 34 on atx: ALL PASSED, 126 checks (1 new). - Gate on atx: CHECK EXIT 0, 283 files, 4359 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
79a04e6764 |
Edit a Parametric EQ in its node, let the wheel only zoom graphs (#381)
The small curve below the EQ node's rows (#375) only showed the bands. Like the Compressor since #380, the node now shows the editor of its tab between its inputs and its output, and is worked right there. A double-click on the node still opens the same editor in a tab. Two wishes for the nodes with a panel came on top and share the same files, so they are in this commit as well: the numbers below the Compressor's knobs read as plain labels (#382), and the wheel over a node zooms the graph instead of turning a value (#383). #381, the EQ in its node: - EqPanel holds the curve, the band's numbers and the help line, taken out of EqEditor. The tab puts its one panel under a header, each EQ node has a panel of its own at 720 x 360 (EqFace). - A press on the curve neither picks nor moves the node. A double-click on the curve adds a band, one on the title or the edge opens the tab. - In the node a press on the Type or Slope button stays with the button, so the node is not picked or moved. - The spectrum runs in the node while it is in the picture. The tab lets go of the tap once, like the Compressor's, and Editor.tick lets every unseen tab and graph go before any seen one listens. - The count of bands moved from the tab's header into the band row, so the node shows it as well. - The node picture of #375 is gone with its only user: NodePicture, EQ_PICTURE and NodeView's drawing of it. #382, the numbers below the Compressor's knobs in its node: - A Knob with typed: false shows its number as a centred Label without a box, in the panel's ink. The ratio reads 4:1 (ratioText). - The label is as high as its text and sits up in the dial's open bottom, right under the ends of the scale. - Label takes a colour of its own. #383, the wheel in a graph: - GraphCanvas takes the wheel on the way down and stops it there. It zooms over a node too, and no knob or curve in a node sees it. - The tabs keep their wheel: a knob's step, a band's Q and the zoom of the EQ's dB. Found on the way: - A Menu opened below a button in the zoomed graph would have been placed by the button's own height. openBelow now takes the bottom edge as drawn. - The band row did not lay out its labels after a text change when its own size stayed. In the tab a later resize hid it, in the node "Band 1" and the count were missing. The row now lays out itself. - Handle and point positions for the checks were unscaled. They now go through toGlobal and hold at the graph's zoom. Tests: - Unit parametric-eq: 16 tests. The #375 tests now check eqCurvePoints and eqRangeOf directly. compressor-view: ratioText. - e2e 34 (atx): ALL PASSED, 125 checks (3 new: the EQ panel and its ports, editing in the node, the spectrum in the node with the tab open). The Compressor node's check reads its numbers as labels and 8:1. Both node checks now expect the wheel to zoom the graph and leave the ratio, the Q and the dB zoom alone. - The unseen-tab check now leaves for the Scene tab, since the node in the graph listens to the same tap. - Counter-check: the tab letting go of the tap every unseen frame stalls the node's spectrum with the tab open (1 frame against 22, probe on stein2). - Gate (atx): CHECK EXIT 0, 283 files, 4357 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1f2b64fb4c |
Show a Compressor's panel in its node, its tab on a double-click (#380)
The panel of #379 opened in a window of its own and replaced the tab. The user wanted the device in the graph instead, and the tab of #378 back on a double-click. The switch Hardware look goes again. - A node can show a face instead of its rows (`NodeFace`). Its inputs sit on the left of it and its outputs on the right, in the middle of the height. Each side is as wide as its longest port name. - A Compressor node shows the panel at full size, 820x280 graph units. Its settings and numbers are not listed as rows, the panel has them. - The knobs and the lever work in the node. A drag, a notch of the wheel and a double-click are one undo step each. A press on them neither picks nor moves the node, and the wheel does not zoom the graph. The number below a knob is only shown, typing stays in the tab and the inspector. - The meter and the LEDs run while the node is in the picture of a sound FX or instrument graph that is seen. Out of the picture, folded or hidden, the node lets go of its taps. - The window of one size, `fixedSize`, `refit`, `keptSize` and the rule that kept a Compressor out of the tab row are gone again. - A knob's drag as one undo step lives in `nodeParamDrag.ts` now, for the tab and the node. The numbers of a node and what auto-gain says moved to `compressorView.ts`. Found and fixed on the way: - The tab and the node listen to the same taps. The tab let go of them on every frame it was not seen, so the node's meter stood still while the tab was open. Now the tab lets go once, and in a frame everything unseen lets go before anything seen listens. Tests: - Unit: compressor-view (2 new), documents (the test of `keptSize` is gone with it) - e2e 34 (stein2, melektaus-atx was off): ALL PASSED, 122 checks. The four checks of #379 are now four of the node: ports beside the panel, knobs and lever in the node, the needle when played (21.7 dB with the tab open), and the double-click opening the tab. - Gate (stein2): CHECK EXIT 0, 283 files, 4356 tests - Counter-checks: an old auto-gain number read as off turns exactly its unit test red. A tab that lets go on every frame leaves the node's needle at 0 dB and no LED lit (probe on stein2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9917253751 |
Open a Compressor as a device in a window of one size (#379)
The tab from #378 shows a Compressor as an editor. The user wanted it to look like a device as well, after a brushed aluminium plug-in, with a meter of the gain reduction instead of the pictures. The tab stays and is switched to per node. - Hardware look is a switch under Settings, on by default for new and existing Compressors. Only the editor reads it. - The panel is 820x280 px and opens straight in a window of that size. The window has no sizing corner and no Dock. A pane says so through `fixedSize`, and `keptSize` keeps the window's middle when it changes to that size. - A Compressor in this look never sits in the tab row. Opening one floats it, and switching the look on moves its tab into the window. - The panel has chrome knobs (threshold and makeup large), a meter with a needle that moves like a VU's, an LCD with the name and the reading, a lever with a lamp for auto-gain, and LEDs for the level going out. Everything is drawn in code. - The Knob takes a size and a chrome look, and leaves out its caption when it has no name, so the panel engraves its own. - `autoGainOn` is now `switchOn`, because the new switch reads the same way. - Where parts sit, the meter's scale, the needle's speed, the LEDs and the plate's grain are in `hardwareView.ts`, apart from the drawing. Decided myself: - The meter's scale runs by the square root, so the first dB is about as wide as the last nine. It is red from 10 dB on. - The LEDs light one every 3 dB from -39 to 0 dB and fall by 20 dB a second. - Switching the look changes the graph's fingerprint, like any other setting of a node. The sound FX is built again once. Findings, fixed on the way: - Pixi's `arc` goes on from the last point of the path. The meter's scale had a line from the corner of the face until each arc got a `moveTo` to its own start. - A text put into a Graphics makes Pixi warn that only Containers take children. The LCD is a Container now. - The first browser check read the needle at one moment and missed the short sound. The panel keeps the most its needle and LEDs showed. Tests: - Unit: hardware-view (10 new), documents (1 new) - e2e 34 (melektaus-atx): ALL PASSED, 122 checks (4 new). Played, the needle reached 20.9 dB and 5 LEDs lit. - Gate (melektaus-atx): CHECK EXIT 0, 283 files, 4355 tests (11 new) - Counter-checks: a window that keeps its corner instead of its middle, and a linear meter scale, each turn exactly their test red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2d4909d248 |
Fit the Compressor's tab to any size, make auto-gain a switch (#378)
Two things came up on the new tab. Floated and sized down, it spilled its knobs out of its window, and sized up it left the window empty. Auto-gain lifted far too much: it brought 0 dB back to 0 dB, which at -40 dB, 4:1 and knee 6 is +28.1 dB, so a sound at -24 dB came out at -6 dB. And as a knob from 0 to 1 it blended between makeup and auto-gain, so at 1 the makeup knob did nothing. Layout: - The knobs stay on the bottom line, centred, with the help line above them. - The levels fill the height left above. The curve is a square at their right, centred up and down. It grows with the tab from 180 to 360 px and takes no more than 40 % of its width (picturesLayout). - A floated window cannot be sized below what its pane needs. A pane says so in its minWidth and minHeight, and the Compressor's is every knob and the smallest pictures. Other panes keep 320 x 200. - A pane put into an open window that is too small grows the window. Auto-gain, as decided in #378: - A Compressor's auto-gain gives back what it takes from a sound at -18 dB, so that one comes out as loud as it went in. At the numbers above that is +14.6 dB. - Auto-gain is a switch on the Compressor, the Limiter and the Saturation alike, a setting and no longer an input. The makeup or output is added on top of it instead of being blended with it. - A project from before reads a number as on above 0. Nodes never set keep their defaults: off on the Compressor, on on the other two. - The tab shows the switch at the right of the knobs, with the dB it gives below it. With it on, the curve has a line at -18 dB from the curve up to the diagonal. - Every level reading keeps the gain of its time. Before, the whole picture was read by the current makeup, so after a change the tinting of the last seconds was wrong or missing. Findings: - My first e2e run of the layout clicked Dock where it was before the window was sized up, so the window stayed open and the next check went red. The check reads the button again. Tests: - Gate (melektaus-atx): 282 files, 4344 tests (6 new) - e2e 34 (melektaus-atx): ALL PASSED, 118 checks (2 new) - Offline in Chrome: a sine at -18 dB through -24 dB and 4:1 came out at -17.92 dB with auto-gain on and -22.42 dB with it off. - Counter-checks: the curve set at the top instead of the middle, and every reading read at a gain of 0, each fail exactly their test. - Looked at the window in screenshots: at its least every knob and the switch show. At 1280 x 797 the levels fill the height, the curve is centred at the right and the knobs are at the bottom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1df38bd430 |
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
|
||
|
|
23922ee4a2 |
Show the zoom of the music tabs and the EQ as a transition (#377)
The zoom transition of #309 left out the Pattern, Song and Sound tabs
and the Parametric EQ's curve. There a wheel step or Fit still jumped,
whatever "Zoom (ms)" in the general settings said.
- axisTween wraps ViewTween for a single axis. The music tabs zoom
their time across and their rows, tracks or height down apart, so
each keeps one tween per axis and either goes its own way.
- Fit by its button is shown as a transition too, as in the other
tabs. The fit on opening a document still jumps.
- A middle-button pan first lands a transition under way, and saving
a document's view lands it on the step it was heading for.
- The EQ's range is saved on the node at once. While the zoom is on
its way the curve draws a range of its own and writes nothing.
Its dB lines are those of the new range, sliding to their place,
so no line shows a crooked number.
Found on the way, not part of #377:
- CI task 611 for
|
||
|
|
3377524958 |
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> |
||
|
|
687377682c |
Draw the EQ's curve in its node and a spectrum behind it (#375, #374)
Both were asked for in #367 "for later". The node of a Parametric EQ now shows its curve in small, and its tab shows what passes the node while it is seen. #375, the curve in the node: - NodeDef has an optional `picture`: a height, and shapes made from the settings as plain point lists (guide, area, line). It is general, the Parametric EQ is its first user. - NodeView draws it in a box below the rows, again only when the box or the settings change. A drag in the EQ tab changes them, so the node follows it live. - Without a band the box stays, flat on its 0 dB line, so the node does not grow at the first band. - The axes of the curve, `eqCurvePoints` and `fillShapes` move from editor/soundfx/eqView to core/soundfx/parametricEq. Tab and node draw the sum from the same function. #374, the spectrum: - A node marked `tapped` gets a `tap` stage in front of its own stages and one behind them when compiled, in a sound FX and in an instrument alike. Its id is asset and node, since a copied asset keeps its node ids. - A tap is a gain of 1. SpectrumTaps (new, viewport/spectrum.ts) holds the tap of every voice and bus while it plays. - While the EQ tab is seen, in the tab row or in a window, the taps of that node feed one analyser per side (8192 points). Nothing is made before a tap of the node plays, so no AudioContext is opened early. - The tab draws both behind the curve, on a scale of 0 to -96 dBFS: the sound coming in faint and grey, the sound going on in the colour of a sound port. The analyser smooths it, and once the sound has gone the sum still hands it silence, so it falls away. - Once the tab is not seen, Editor.tick lets the analysers go, like the meters of the Song tab. - A tap does nothing to the sound, so `stats().last.stages` leaves it out, and a bypassed EQ keeps its taps. Decided on my own: - Every sound passing the node counts: Play of the sound FX tab, an instrument's keys, a song, a run. The issue proposed that. - The spectrum has no labels of its own. Its scale is in the wiki. Tests: Gate (melektaus-atx) 275 files, 4247 tests (11 new), EXIT 0 e2e 34 (melektaus-atx) ALL PASSED, 98 checks (2 new), twice Counter-checks, each put back by copy and compared with cmp: - The node's curve drawn without its bands: 2 unit tests fail. - The spectrum without the loudest bin between two points: 1 fails. - SpectrumTaps.stop leaving the taps linked: 1 fails. - Taps that never feed the analyser: e2e 34 fails in exactly the spectrum check (frames 0). Run in the container only. The screenshots of the second run were looked at: the blip as one peak behind the curve, and the dip at 4 kHz in the node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
25084f8576 |
Refactoring round 10: split SoundLibrary, fold sound duplicates (#85)
Refactoring round 10 covers everything since round 9 ( |
||
|
|
9166d4a56f |
Drop the Remove button below the EQ's curve (#370)
A right-click on a band's handle removes it, and so does Delete in the EQ's tab. The button said the same a third time and took room in the row of numbers. - The row below the curve holds Type, Hz, dB, Q and Slope only. - `removePicked` stays, the right-click and Delete use it. Tests: - Typecheck, ESLint, Prettier: clean. - e2e 34 never pressed the button, nothing to change there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9ab1bbc507 |
Edit a Parametric EQ in a tab of its own (#370)
The EQ's editor floated over the editor as a window since #367. The user wants it as a tab for now. Whether any tab can float and dock again is weighed apart from this. - A double-click on the node asks for the tab through `EditorState.openEq`, as `openValues` does for a Variables tab. - The tab is a document `eq:<asset>:<node>`, one per EQ node. A second double-click brings the open one up. - Its name is the asset's, with `EQ 2`, `EQ 3` when the asset has more than one. The icon is the sound FX's. - The tab closes with its node, its asset, or a new project, through the same `syncDocuments` as every document. - `EqWindow` becomes `EqEditor`, a `VStack` with a `TabHeader`. The curve takes the room of the tab, 320 x 160 at least. - The window's title bar, dragging and Close button are gone. - Delete in the EQ's tab removes the picked band. It never falls through to the selection, which is still the EQ's node. - The hint below the curve is shorter, it was cut off at 1280 px. Tests: - e2e 34 (melektaus-atx): ALL PASSED, 96 checks, 2 rewritten. The tab opens on a double-click and goes with its node. - Gate (melektaus-atx): CHECK EXIT 0, 274 files, 4231 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
af2312a5e7 |
Play every tab's preview straight into the master (#368)
Since #351 the tabs played their asset along its links in the Master routing, as the game does. A song linked into a reverb bus was heard through that bus while it was edited. A preview should sound like the asset itself, so the tabs leave the Master routing out again. - The Sound, Sound FX, Instrument, Pattern and Song tab play into the master. The sound FX of the asset still applies, and so does the master's own volume and FX. - Inside a song its own routing of tracks and sends still counts. - The game is unchanged: Play nodes go along the routing as before. Tests: - e2e 34 (melektaus-atx): ALL PASSED, 96 checks. The routing check now holds the mix of the two buses as before, and the Sound tab on the master with the bus silent. - Counter-probe e2e: the Sound tab along the routing again, the routing check red. - Gate (melektaus-atx): CHECK EXIT 0, 274 files, 4230 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1f13794b0c |
Shape a sound with a Parametric EQ and its own curve editor (#367)
A sound FX or an instrument had a 5-Band-EQ with fixed bands and a Filter with one band. The Parametric EQ holds up to ten bands of any type, and a double-click on the node opens an editor that draws the curve they make together. - The bands are a list on the node (`bands`): type, frequency, gain, Q and slope. A hand-edited project is held to the editor's ranges and to ten bands. - Each band compiles to the existing `pass` stage, so the audio core is unchanged. A peak or a shelf at 0 dB is left out. - The curve is worked out in `parametricEq.ts` with the biquad formulas of the Web Audio spec, so the editor draws what is heard. - The editor is a window that floats over the editor without a backdrop, so the tab's Play stays usable. A double-click adds a peak, a drag moves a band, the wheel turns its Q, a right-click removes it. Fields below the curve set the picked band. It opens in the middle of the screen and moves by its title bar. - A drag or a scrub writes the node as a preview and makes one undo step on release. The panels hear of the preview once a frame, and the window lays itself out only when one of its texts changes. - The area under the curve is filled as one shape for each side of 0 dB. As a single shape it crossed itself and came apart. - The curve works out each band's coefficients once and adds the sum up from the bands. A drag took 295 ms of script time in a profile before and 64 ms after. Decided on my own: - Bands are added by a double-click, so a single click can let go of the picked band without adding one. - The cuts are labelled "Low cut" and "High cut" as in an EQ, not "High-pass" and "Low-pass" as on the Filter. - The bands have no input, so no parameter or Envelope moves them. Tests: - Unit parametric-eq (new) and soundfx: 69 green. Counter-probe with no stages emitted: the compile test red. Counter-probe with one fill shape: the fill test red. - e2e 34 (melektaus-atx): ALL PASSED, 96 checks (3 new). - Counter-probe e2e: no stages emitted, the playing check red. - Gate (melektaus-atx): CHECK EXIT 0, 274 files, 4230 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
0e73fd85b9 |
Route sounds, songs and buses in one Master routing graph (#351)
A project bus could only go into one other bus, and a sound, an
instrument, a pattern or a song into exactly one bus. A shared reverb
needs a sound to go there in part and on dry at the same time. Instead
of a list of sends on every asset, the project gets one routing graph
like the routing of a song (#350), one level up.
- Menu -> Master routing opens a tab with one graph per project. It has
a node per sound, instrument, pattern, song and bus, named after its
asset, and one Master. Embedded assets have none, their song routes
them.
- The nodes follow the assets. Every edit settles the routing in the
same undo step (KeepRoutingCommand), so an undone delete brings the
links of its asset back. A new asset gets a node and a link to the
master. What went only into a deleted bus goes to the master.
- New nodes start in three columns: what plays, the buses, and the
master a row above, so no link into it runs behind a bus.
- Links are sends: -60 to +12 dB, and a Mode on links out of a bus or a
song. Out of a sound, an instrument or a pattern a link always takes
the sound after its volume and FX. Loops are refused.
- A node without a link is silent and says "Goes nowhere".
- The rows Bus and Into are gone. Play nodes with a picked bus still
overrule the routing.
- A click on a node shows its asset in the inspector, the Master shows
the master volume and sound FX. A double click opens the asset's tab.
- The graph lives in project.routing and is held to the assets when a
project is read, but nothing is added there. The editor adds the
nodes when it opens a project. An asset without a node plays on the
master, so old projects sound as before without a migration.
- In the mix an asset with one link at 0 dB goes straight into that bus.
A sound or instrument with more gets a bus of its own with the sends.
A pattern or song sends from the master of its playing, which is
where its Mode taps. Buses of the mix can have sends now too.
Found:
- The check "the scheduler plans a looped bar" in e2e 34 wobbles. It
failed in 2 of 5 runs here and in CI task 580 at
|
||
|
|
42a3759d9d |
Cut a sound into named clips, as a texture into frames (#357)
A sound could only be cut to one stretch, set on the asset itself. To
play two parts of one file, the file had to be imported twice. Now a
sound is always the whole file, and its clips are the stretches of it,
each with a name and a cut of its own.
- A clip is { id, name, props } on SoundAsset.clips. Its id shares the
generator with asset ids, so a sound field holds a sound or a clip,
as a texture field holds a texture or a frame.
- props are the cut: start, end, the fades and their curves, reverse.
Volume, loop, sound FX and bus stay on the sound for all its clips.
The cut rows left the sound's schema for CLIP_ROWS.
- findSound resolves either id. Play sound, the Sample of an
instrument, a Reverb impulse, song items, the scheduler and the test
sound of the Sound FX tab all go through it.
- Every sound field offers each sound followed by its clips, "Kick",
"Kick / Clip 1". A clip that is gone reads as "<id>?".
- The Sound tab has a strip under the ruler with the clips as bands.
A drag there makes a clip, a click picks one, beside the bands the
sound. Only the picked clip has handles. Reverse, fades and curves
in the header work on it and are greyed out without one.
- Whole file is gone from the header, as the user asked.
- Picking a clip is a selection of its own, like a frame. The
inspector shows its name, its cut rows and Delete clip. Delete
takes it away without asking, as with a frame. Ctrl+Z brings it
back.
- Copies get fresh clip ids: Duplicate, Embed a copy, a song
duplicated with its takes, and the copy a split or paste makes of
an embedded take. An item on a clip plays the same clip of its copy.
- A double-click on a song item playing a clip opens its sound with
the clip picked. The Sound row of an item on an embedded take
offers the take and its clips, which no list shows.
- A new take stays the whole sound. Clips are made by hand, as the
user decided.
- No migration in the code, as the user decided. The one project
with cut sounds was changed over by hand.
Deviation from the issue: deleting a used clip does not warn. A frame
does not warn either, and the issue had promised "like a frame".
Tests:
- Unit sound-clips (new): 11 green, 7 counter-checks each red
- Unit sounds, embedded: adjusted to clips, green
- e2e 34 (melektaus-atx): ALL PASSED, 90 checks (3 new, 12 rewritten)
- Counter-check in the browser: clips left out of the sound fields,
the picker check fails
- Gate (melektaus-atx): CHECK EXIT 0, 271 files, 4194 tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
25c1d02b06 |
Keep the audio thread free of ended voices and too many vocoders (#356)
A song that had been played a few times in a long session stuttered at regular intervals until the page was reloaded. A quick run up the keys of a sampled instrument made every sound drop out for a second or two. Both came from work the audio thread should not have had. - Every worklet node of a voice listened on its port. Chrome never collects a port that is listened to, and through its listener not the voice either. Every node of the voice stayed on its bus and was worked on in every block. A way or stage on the worklet now closes its port once it ends or is stopped, and the processor closes its own side when it is told to stop. - A voice without echoes now leaves its bus as soon as its sound and what its stages hold back are through. Before, only a voice with echoes did. - At most 12 ways play through the pitch worklet at once. One more cuts the oldest in 10 ms, a note already let go before one still held. Each runs a phase vocoder, whose first block alone took 2.7 ms of the 2.67 ms a block has on stein2. - Play for the game ends everything the tabs play: the piece holding the transport and every key or preview (`stopPreviews`). - Closing a Sound, Sound FX, Instrument, Pattern or Song tab stops what it plays of that asset (`AssetTabEditor.closed`). - A preset in the Instrument tab plays nothing any more. With Audition on it is heard like any other change. - Test hooks: `__gm.instrument.play`, `__gm.sound.playing`, and `vocoders` in the stats of the sound library. Measured: - A copy of the project, its Song 2 played for 12 s and stopped, six times (Chrome on stein2, CDP WebAudio): before, 746 nodes were left after the first time and 4469 after the sixth, the load at rest grew from 0.01 to 0.06. After, 7 nodes are left every time (the master and one bus) and the load at rest stays at 0.01 to 0.02. - Pitch-player voices live in Chrome on melektaus-atx: 12 take 0.50 of the audio thread, 16 take 0.71, 24 take 0.99. 30 struck 40 ms apart held it at 0.99 from the first second on. Tests: - Unit sound-library: 110 green (3 new), 4 counter-probes each red - e2e 34 (melektaus-atx): ALL PASSED, 86 checks (3 new, 2 changed) - e2e counter-probe with game start and preset undone: their 3 checks red, and the old check of Play note in the game as well, which now counts on the preview being gone - e2e counter-probe with tab close undone: exactly its check red. A first form of it held a key and stayed green, since the keys let go of a held key by themselves once the tab shows no asset - Gate (melektaus-atx): 270 files, 4181 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
23cb34f781 |
Keep a recorded take inside its song (#355)
A take used to land in the Assets panel as "Song – Take N", next to every other sound of the project. Now a song can keep a sound, a pattern or a sound FX to itself: an ordinary asset whose new field `owner` names the song. Everything that finds an asset by its id finds it, so playing, the tabs and the game need no change. Only the places that list assets leave it out. - `core/music/embedded.ts` holds the rules: which types can be embedded, `listedAssets`, the title "Song › Take 1", and the rows an embedded sound hides (Loop, Bus). - One user per embedded asset. `SetSongCommand` settles the song after every edit: a place naming an asset an earlier place claimed, or one of another song, gets a copy, and what nothing names any more goes in the same undo step. The outcome is worked out once, so a redo brings back the same copies. - A split, Ctrl+D and a paste get that for free. The clipboard keeps the embedded assets of the copied items, so a paste after a delete brings the take back. - Deleting a song deletes what it keeps. Duplicating it copies that and points the copy at the copies. A duplicate of an embedded asset is a project asset. - The item menu has Open, Make project asset and Embed a copy. - An embedded item carries a bullet in front of its name. The first pick was a diamond, which the gate's font test refused: the UI font has no glyph for it. - A take is "Take 1", 2, … numbered per song. With the song gone while it uploads, it becomes a project sound under a free name. - Left out of: the Assets panel, every asset picker, the sound FX menu of a track, the test sound of the Sound FX tab and the naming of new assets. Delete on an embedded asset only says where it lives. A ping lights up its song. - Loading drops an `owner` whose song is gone, the asset stays as a project asset. No migration: older projects have no owner. Tests: - Unit embedded (new): 13 green, 6 counter-checks each red - Unit take, song, song-edit, asset-fx, asset-ref, serialize and neighbours: 116 green - e2e 65 (melektaus-atx): ALL PASSED, 47 checks (1 new) - Counter-check e2e 65 (asset panel unfiltered): exactly that check red - Gate (melektaus-atx): CHECK EXIT 0, 269 files, 4167 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d349251a01 |
Put a sound in a room, a hall or a cave with a Reverb node (#328)
A sound FX had no space around it. The Reverb node folds the sound with an impulse response: one it makes itself, or a sound asset as the answer of a real space. It works on a voice and on a bus. - Type: Room, Hall, Cave and Plate have fixed numbers. Custom shows Decay (up to 10 s), Damping and Pre-delay. Sound shows the pick of a sound asset and Pre-delay. The rows are derived ports, the sound pick an idle param, so they only appear for their type. - The made impulse response is seeded noise per side, 60 dB down at Decay, through a low-pass closing from 20 kHz toward 500 Hz as far as Damping says. It is made once per rate, decay and damping, the last 16 are kept. - A sound as impulse response: the sound FX compilers now get the project, so a node can turn a sound asset into its file. The build key holds that file, so a cut or swapped sound builds again. The instrument compiler does the same for a Reverb inside an instrument. - The library loads that file with the voice, a sequence or before a bus builds its chain. A missing file leaves the reverb silent. - Mix blends dry and reverb and is the only number that moves while the sound plays, as the issue said. The voice rings for pre-delay plus decay, or as long as its sound. - The open point from #325 about sends on project buses is #351, not part of this. Tests: - Unit reverb (new) 4, soundfx 57 (4 new), sound-library 104 (2 new), green. - Counter-checks, each turns one test red: the impulse file not loaded with the voice, the tail without the length of the sound. - e2e 34 (melektaus-atx): ALL PASSED, 81 checks (1 new). Chrome offline: silent during the pre-delay, 35.9 dB fall over 0.6 s of a 1 s decay (36 expected), the dry half at 0.25 for mix 0.5. A sound with one sample at 0.2 s gives the impulse back 0.25 s later and nowhere else. - Gate (melektaus-atx) over the end of this series #318 to #328: CHECK EXIT 0, 267 files, 4134 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3a52f2290f |
Mix sounds through buses and a master (#325)
Until now every sound went straight to the speakers. There was no point where all of them came together, so nothing could turn the music down against the effects, and a compressor or a shared echo over everything had nowhere to sit. The bus technique of #346 was there already, only the end of the chain was missing. - Bus asset (Audio): Volume, Sound FX and Into. Into is empty for the master and never offers the bus itself nor a bus that already goes into it. The list is worked out when the menu opens, so a change made meanwhile counts. A loop that is in a project anyway sends the buses on it into the master. - The master is no asset. Its volume and sound FX are two new rows under Master in Project settings, one undo step each. A project written before has 1 and none, which is how it sounded. - Sound, instrument, pattern and song have a row Bus, empty for the master. Play sound, Play note, Play pattern and Play song have an input bus: From the asset, Master or a bus. Inside a song or a pattern only the bus of the song or pattern counts. - Set bus volume (bus, volume, time, easing) and Bus volume. An empty bus is the master. The volume set holds for the whole run, across scenes, over that of the asset. GameRun resets it at start and end. Set sound FX parameters without a voice now reaches the sound FX of the bus picked in its new bus input. - SoundLibrary: the master is the bus "mix", each bus "mix:<id>". Every bus, the playing masters of #346 included, ends there, and only the master is heard. setMix sets them up once a context exists, so an editor nobody listened to opens no audio device. The same mix again changes nothing, which lets the editor hand it over on every change of the project. - The tabs play as the game does: Sound, Sound FX, Instrument, Pattern and Song tab through the bus of their asset and the master. - Pause game does nothing to the buses (the user's answer 4b). A game that wants quiet in its pause menu sets a bus volume itself. - Streaming long music files is #349, split off as asked. Finding on the way: the Into menu first worked from a list made when the inspector row was built. After another bus was sent into the open one, e2e 34 saw it still offered. It is now asked on open. The SoundLibrary tests expected voices to end at the destination. They now end in the master, which adds its input, level and pan to every wiring and two gains to every list. Those expectations are updated, nothing else in them changed. Tests: - Unit buses (new): 15 green. Ten counter-checks, each red on its own: loop check, bus picked, reset at run start, bus of Set sound FX parameters, master volume in the settings, and in SoundLibrary default into the master, voices into the master, run volume over the mix, no context before a play, a playing on its bus. - Unit sound-library: 90 green (5 new). Node catalog: 416 green (9 new cases). - e2e 34 (melektaus-atx): ALL PASSED, 75 checks (3 new). The voice of the Sound tab was heard on mix:<bus>, that bus into the other, that one at 0.5 into the master. Master volume 0.6 via the dialog, undo back to 1. - Gate (melektaus-atx): CHECK EXIT 0, 262 files, 4072 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f1f4a57589 |
Cut a sound to a stretch of its file in its own Sound tab (#343)
A sound asset now opens in a tab that shows its file as a waveform. Two handles set where the sound starts and ends in the file, and that stretch is the sample: Play sound, a song item and an instrument's Sample all play it and nothing else. The file itself is never changed. - The asset has three new rows: Start (s), End (s) and Edge fade (ms). End 0 is the end of the file, the fade is 10 ms by default. Older assets have no values and play the whole file as before. - Every way of playing asks playedSoundOf() for a name instead of the file: the file, or <file>#<start>~<end>~<fade> for a cut. - SoundLibrary makes the cut from the decoded file the first time that name plays and ramps each edge inside the file over the fade. Length and peaks of a cut are read from the file without a copy. - Cut buffers can be made again at any time, so the library lets the oldest go past 64 Mi samples. A voice holds its buffers itself. - The tab draws min/max per pixel from 256-sample block peaks, and the samples as a line when zoomed in far. Wheel zooms, the middle button pans, as in the music tabs. Wave, cut and ruler sit under a mask, so a handle panned out of view does not draw over the panels beside. - Dragging a handle moves that edge, dragging elsewhere spans a new stretch. One drag is one undo step for both edges. Whole file puts the handles back, Play or Space plays the stretch with a playhead. - The inspector preview and the Sound FX preview play the cut too, and the song lanes draw and repeat it. Tests: - Unit: sounds 20, wave-view 8 (new), sound-library 68, plus 258 in the touched areas (instrument, song, pattern, inspector, tabs) - e2e 34 on melektaus-atx: ALL PASSED, 57 checks (7 new) - Gate on melektaus-atx: CHECK EXIT 0, 253 files, 3936 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c7e9769f90 |
Change the sound FX parameters of a sound while it plays #315
Until now a value handed to a sound FX counted from the start of the voice only. An engine whose pitch follows the speed, or a loop that gets quieter, could not be built. Every play of Play sound now gives out the number of its voice, and a new node lets the knobs of that one voice glide to new values while it plays. - Play sound has a new output voice: the number of this one play, or 0 where nothing was played. Kept in a Number variable it reaches the voice from another event. Two plays of one sound are two voices. - New action node Set sound FX parameters (exec, voice, fx params). It reaches exactly the voice it is given, a detached one too. A voice that has ended, or voice 0, is not reached. - AudioSink.play returns the voice number and takes the plan and the values (FxVoice) instead of a finished chain. AudioSink.tune takes a voice number and new values. A name the voice's FX does not have is left out, one not given keeps its value. - SoundLibrary hands out the number at once, before the bytes are there, and never twice. A voice still waiting for its bytes starts with the values handed in meanwhile. - Every knob of a voice moves with setTargetAtTime (30 ms time constant). A knob whose value did not change is not sent again, so a tune every frame costs next to nothing. - A pitch on a playing voice glides by playbackRate. A new WSOLA copy in the middle of a sound is not worked out, so the voice gets shorter or longer while it is moved. On a loop that is not heard. - fxChainOf now gives a chain whose shape depends on the plan alone. A stage fed by a parameter stays at 0 dB, and a Mix fed by a parameter keeps both ways. A typed-in 0 or Mix at 0/1 is still left out by the compiler. - Every way of a voice has a source of its own, also at the same pitch, so each can glide on its own. The pitched copy is shared. - The tab keeps the numbers of what it plays, so moving a parameter field is heard at once. - Test hook __gm.sound.levels(file) reads the knobs of every voice of a file, oldest first, and stats() counts the voices tuned. Tests: - soundfx.test.ts: 29 tests (+2 for the node in a running world: the voice of the first of two plays of one sound, and a play that played nothing) - sound-library.test.ts: 15 tests (+3: glide, reach by number, pending voice) - node-catalog.test.ts: 370 tests (+2, Play sound checks its voice) - sounds + keep-on-scene-load: 31 tests, unchanged - Counter-test: a tune that reaches every voice of the same file makes the reach test fail. - e2e 34 (melektaus-atx): ALL PASSED - 30 checks (+1). In Chrome two looping voices of one sound start at depth 7. The one whose number sits in a variable glides to 0.7938 (2^(-4/12) = 0.7937), the other stays at 1. Both gains stay at 0.5012. - The gate ran before voices got a number (CHECK EXIT 0, 241 files, 3658 tests), not after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
183f356c99 |
Let a game hand values to the parameters of a sound FX #311
A sound FX played the same every time: its numbers were settings of the nodes. Now the Input declares parameters with a default, every number of Gain, Pitch and EQ is an input they can feed, and a Play sound hands in values for them. - Input declares number parameters in the inspector, each with a Default (DeclaredPort.default, SetPortDefaultCommand). They are outputs of the Input. Input and Output count as terminals now, one of each per graph. - Gain, Pitch and EQ take their numbers at inputs under the keys the settings had, so saved graphs sound as before without a migration. Each value is held to its range however it arrives. - The compiler gives an FxPlan with the parameters still open. fxChainOf fills them in when a voice starts. The player still only sees an FxChain. - New behavior node Sound FX parameters: names an FX and picks its parameters like a Variables node picks variables. Each picked one is a number input that starts at the FX's default. Its output has the new port type fxparams, which only fits Play sound's fx params. - Play sound warns when the parameters name another FX than the one it plays. Names the FX does not know are left out. - Renaming a parameter at the Input renames it in every Sound FX parameters node naming that FX, edges and values included. - The Sound FX tab has a number field per parameter in its header. Play uses those values, they are never written into the asset. - A value counts from the start of a voice. Changing a playing voice is #315, a Mix node is #316. Tests: - soundfx.test.ts 22 (+11): parameters in the plan, held values, a 0-by-default stage, EQ band, save with defaults, wrong port types, default command with undo, Sound FX parameters into Play sound, defaults of picked ones, node problems, mismatch, rename with undo - node-catalog 368 (+3): Play sound fx params, Sound FX parameters - e2e 34: ALL PASSED - 28 checks (+2: header field plays depth 5, a Sound FX parameters node gives the game's voice depth 7) - Gate on melektaus-atx: typecheck, lint, prettier clean, 240 test files, 3636 tests green - Counter-check: with fxChainOf ignoring the values and the rename not followed, 5 of the new tests fail. - Browser probe: header fields, inspector Default and the picked parameter looked at in two screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
de14f0f9e2 |
Play a sound through a graph of gain, pitch and EQ effects #311
A sound could only be played as it was uploaded. A Sound FX asset is
a node graph like a shader: Input, effects, Output. Play sound has a
new input fx that sends the voice through it.
- New asset type soundfx ("Sound FX"), not placeable, with a graph
and its own tab. The heading in the asset panel is "Sound effects",
so it does not take the click meant for the + menu entry.
- Nodes in core/soundfx/nodes.ts, category sound, port type audio
that only fits audio: Input, Output, Gain (dB), Pitch (semitones),
EQ (80 Hz and 12 kHz shelves, peaks at 250 Hz, 1 kHz and 4 kHz).
- compileSoundFx walks back from the Output with the shared graph
emitter. An input takes one edge, so the result is one line: a
pitch and a list of gain and filter stages. A node without input
or a graph without Output reports a problem on the node.
- Pitch is the playback rate of the source. It applies to the whole
sound and also changes its length, the node description says so.
- The BehaviorSystem resolves fx and hands the line to the AudioSink.
An fx that is missing or does not compile plays the sound dry.
- SoundLibrary wires source, stages, volume, destination in that
order. stats().last now also names pitch and stage count.
- The tab header picks one of the project's sounds and plays it
through the graph as it stands. Stop there ends only its own voice.
Tests:
- soundfx.test.ts (new, 11), sound-library (9, +2 for the wiring),
node-catalog (+1 for fx), graph and asset-groups adjusted
- e2e 34: ALL PASSED - 26 checks (+5: + menu opens the tab, palette,
2 effects, tab Play and game Play through the FX at -12 st)
- Gate on melektaus-atx: typecheck, lint, prettier clean, 239 of 240
test files green. The red one was sound-library (its fake
AudioContext had no playbackRate), fixed afterwards, gate not
re-run in full.
- Counter-check: without the audio rule in portsCompatible the port
test fails.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|