From f2a3834212bbad687294b097382c8dbd87677ea0 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Tue, 6 Oct 2026 13:13:08 +0200 Subject: [PATCH] Describe one sound at the Output and the curve of a Mix #331 - Instruments: the Output takes one sound, a drum kit goes through Mixes, an old instrument with several edges says why it does not compile, and two layers at once depend on the Mix's curve. - Sounds: the Mix's setting Curve with a table of both curves, the +6 dB at the middle, and how a glide follows the curve. - Architecture: one line on the Output. Co-Authored-By: Claude Opus 5.5 --- Architecture.md | 2 +- Instruments.md | 17 +++++++++++++---- Sounds.md | 26 +++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/Architecture.md b/Architecture.md index b8af203..5d077cd 100644 --- a/Architecture.md +++ b/Architecture.md @@ -204,7 +204,7 @@ src/viewport/ WorldViewport (the drawing of a world or a holder, the ba CPU and laid side by side onto one canvas, so a frame is cut out like a texture frame), SoundLibrary + pitchWorklet (the AudioWorklet that plays a way with a Pitch through core/soundfx/pitchPlayer, a phase vocoder, #317; a note of an instrument is one voice - of several layers, each way with its own file, #331; a voice can start and be released + of what reaches its Output, each way with its own file, #331; a voice can start and be released at a second of the audio clock, #332), music (the scheduler on the library's clock, its notes played by the project's instruments, driven by `__gm.music` until #333) + musicTimer (the Web Worker whose interval is the scheduler's beat, #332), ShaderLibrary, ParticleLibrary, diff --git a/Instruments.md b/Instruments.md index 92458b3..2bdfa4a 100644 --- a/Instruments.md +++ b/Instruments.md @@ -22,7 +22,7 @@ A at 440 Hz, 127 the highest. A note is named with its octave after it and no da | **Sample** | Plays a sound asset when its `trigger` is on. With **Follow note** (on by default) it plays higher or lower by the distance from **Root**, the note it sounds as it is (C4 by default), and **keeps its length** — it is played by the same worklet as a Pitch (#317). Off, every note plays it as it is, as for a drum. **Play** says how it is played while the note is held and once it is let go (table below). **Loop start** and **Loop end** are in seconds, 0 at the end being the end of the sound. The volume of the sound asset counts. | | **Parameters** | The instrument's own parameters, each a number output with a default — like the parameters of a sound FX's Input. One per instrument. | | **Sound FX** | Sends the sound through a sound FX asset, as if it were the sound at the FX's Input. Every parameter of that FX is an input here; one left open is the FX's default. The node is titled after the FX, and a double click opens it. | -| **Output** | What is heard. Unlike every other sound input it takes **any number** of sounds and plays them together: the layers of the instrument. One per instrument. | +| **Output** | What is heard. It takes **one** sound, like every other sound input; a second edge replaces the first. To play several together, put a **Mix** in front of it (several Mixes in a row for more than two). One per instrument. | | Gain, Pitch, 5-Band-EQ, Mix, Delay | The effects of a [sound FX](Sounds#sound-fx), the same nodes. | **Play** of a Sample: @@ -48,8 +48,16 @@ the source plays when one of them is on: C1 and D1 can both play the same Sample **Zones and layers.** Several Notes nodes split the keyboard into zones: a bass sample for C1-B2, another one from C3. Where two ranges overlap, both are heard. A drum kit is one Notes node over -C1-B1 with Single notes on, a Sample on each output (C1 Kick, D1 Snare, F#1 Hi-Hat …) and all of -them into the Output: one instrument plays the whole kit. +C1-B1 with Single notes on, a Sample on each output (C1 Kick, D1 Snare, F#1 Hi-Hat …) and Mixes +gathering them into the Output: one instrument plays the whole kit. Only one drum sounds for a +note, so each Mix is its other side and the drum keeps its own volume. Two layers that sound at +once (a piano with a string pad under it) are mixed by the Mix's `mix`: with the curve +*Crossfade* 0.5 is both at half, with *Both at center* both in full (see +[the curve of a Mix](Sounds#the-curve-of-a-mix)). + +An instrument saved while the Output still took any number of sounds and played them together +keeps its edges, but does not compile until there is one: the Output says *Takes one sound: put a +Mix in front of it to play several*. ## How a note is made @@ -65,7 +73,8 @@ voice 0. them on a playing note. - **Velocity is always loudness**: the voice is played at `volume * velocity`. The output `velocity` is there for anything else as well, a filter that opens with a harder stroke. -- A note is **one voice**, its layers side by side, each way reading its own file. It ends when all +- A note is **one voice**, whatever the graph mixes into it, each way reading its own file, so + `Play note` gives out one `voice` and `Stop sound` ends all of it. It ends when all its ways have ended, or rings on first where it has an echo (see [Sounds](Sounds#delay-and-the-tail-of-a-voice)). - **The end of a note** (the key let go, the duration of `Play note` over): every *Gate* and *Loop* Sample fades out in 10 ms, *One-shot* ones play on, and *Loop, then release* ones leave their diff --git a/Sounds.md b/Sounds.md index 9c5bf65..abb13d5 100644 --- a/Sounds.md +++ b/Sounds.md @@ -104,7 +104,7 @@ Input and the Output once each; their pins carry sound and fit nothing but each | **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. | | **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. | -| **Mix** | Blends the sounds at `a` and `b`: at 0 only `a` is heard, at 1 only `b`, at 0.5 half of each (0.5 is the default). | +| **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, `mix` is how loud the echoes are next to the sound, which stays as it is. **Ping-pong** sends the echoes left and right in turn. See [below](#delay-and-the-tail-of-a-voice). | Every number of these nodes is an **input**: typed in while nothing is connected, or fed from a @@ -153,6 +153,30 @@ goes to both of its sounds. A Mix typed in at exactly 0 or 1 leaves the silent w one is not even played. A Mix fed by a parameter keeps both ways, because the value may still change while the voice plays. +### The curve of a Mix + +| `mix` | *Crossfade* `a` / `b` | *Both at center* `a` / `b` | +| --- | --- | --- | +| 0 | 1 / 0 | 1 / 0 | +| 0.25 | 0.75 / 0.25 | 1 / 0.5 | +| 0.5 | 0.5 / 0.5 | 1 / 1 | +| 0.75 | 0.25 / 0.75 | 0.5 / 1 | +| 1 | 0 / 1 | 0 / 1 | + +Between the rows it runs in a straight line. *Both at center* is what a DJ mixer calls a sharp +crossfader curve: one side only starts to fade once the other is full. + +- **At 0.5 both sounds are added in full**, as two sounds on top of each other. Where both are + loud at the same moment that is up to twice as loud (+6 dB) and can clip; a Gain after the Mix + takes it down. For a drum kit, where only one side sounds per note, it changes nothing. +- **Curve is a setting, not an input**: it holds for the whole voice. `mix` itself can still be + fed by a parameter and moved with *Set sound FX parameters*. +- **A glide follows the curve.** With *Both at center* the voice carries `mix` itself on the + audio thread (a `ConstantSourceNode`), and two `WaveShaperNode`s make the shares of `a` and `b` + from it. A glide from 0 to 1 keeps `a` full for its first half, rather than ramping both shares + straight and dipping to half each at the middle. +- Mixes saved before the curve existed are *Crossfade* and sound as they did. + ### Delay and the tail of a voice A **Delay** (#327) is a delay line whose output goes through a low-pass (the damping), back into