feat(forge): add Forge tracked channel strip
One note tracker reads the input and Lathe, Temper and Knurl follow it as modules, in any of six orders, each on or off. Every module gets the tracker's events delayed by the latency of the modules in front of it. - One module alone matches its standalone plugin sample for sample in every order. - With Knurl's sub-octave pattern in front, Lathe in Forge follows the played note; a standalone Lathe after Knurl reads it an octave low. - About 72 ms latency against about 206 ms for the three in a row. The module pages reuse the standalone editors. Register Forge in the catalog, CI, README, docs and website, and drop the built Ballast from the site's idea list.
This commit is contained in:
1 parent
340376eee2
commit
7b989f7685
28 files changed
+4678
-23
No files matched your search
+10
-3
@@ -1,19 +1,24 @@
|
||||
# Signal chain
|
||||
|
||||
The order of the Bass Foundry plugins in a chain matters. Anvil, Lathe, Temper,
|
||||
Knurl, Planish, Braze and Ballast each detect the pitch from the audio they receive. If a plugin earlier
|
||||
Knurl, Planish, Braze, Ballast and Forge each detect the pitch from the audio they receive. If a plugin earlier
|
||||
in the chain changes the audio, the pitch detection after it can go wrong.
|
||||
|
||||
## Recommended order
|
||||
|
||||
```text
|
||||
bass track: synth → Lathe → Temper → Planish → Braze → Knurl → Patina → Ballast → Weld
|
||||
or: synth → Forge (Lathe, Temper, Knurl) → Planish → Braze → Patina → Ballast → Weld
|
||||
bass bus: Anvil → (bus compression) → Quench → Crucible
|
||||
master: … → Quench (last, or before a true-peak limiter)
|
||||
```
|
||||
|
||||
- **Lathe and Temper before Knurl.** They hear the plain synth, where the pitch
|
||||
is clear.
|
||||
- **Or Forge in their place.** Forge runs Lathe, Temper and Knurl behind one
|
||||
tracker that reads its input, so the order inside it does not upset the pitch
|
||||
detection, and the three cost one lookahead (about 72 ms) instead of three.
|
||||
Planish and Braze then come after Knurl: run them from MIDI.
|
||||
- **Planish after the distortion, before Knurl.** OTT usually comes after
|
||||
distortion. Planish's band edges follow the tracked note, so it also needs a
|
||||
clear pitch: after Knurl, use MIDI.
|
||||
@@ -58,13 +63,15 @@ tracker on a saw bass:
|
||||
its phase on each, Lathe, Temper and Planish retune on each.
|
||||
|
||||
When a tracked plugin must come after Knurl, select **MIDI** as its pitch source
|
||||
and route the bass's MIDI notes to it.
|
||||
and route the bass's MIDI notes to it. Inside Forge this does not apply: its one
|
||||
tracker reads the input before Knurl.
|
||||
|
||||
## Latency
|
||||
|
||||
Each tracked plugin adds its own lookahead: Anvil 80 ms, Lathe, Temper,
|
||||
Planish and Braze about 67 ms, Knurl about 71 ms, Patina about 45 ms, Ballast
|
||||
about 172 ms, Quench under 1 ms. A full chain is
|
||||
about 172 ms, Quench under 1 ms. Forge holds Lathe, Temper and Knurl in about
|
||||
72 ms, against about 206 ms for the three plugins in a row. A full chain is
|
||||
about 400 ms. FL
|
||||
Studio compensates this for playback and rendering, but playing a MIDI keyboard
|
||||
through the full chain is not practical. Write with a shorter chain and add the
|
||||
|
||||
+6
-3
@@ -25,8 +25,10 @@ Patina has `render` for offline WAV evaluation. The shared crates are:
|
||||
|
||||
- `common-ui`: palette, embedded fonts, header, panels, knobs, meters.
|
||||
- `common-dsp`: filters, YIN pitch tracking, the note tracker used by Anvil,
|
||||
Lathe, Temper, Knurl, Planish, Braze and Ballast, 4× oversampling (also Quench's),
|
||||
BS.1770 K-weighting (Ballast), meters and WAV files.
|
||||
Lathe, Temper, Knurl, Planish, Braze, Ballast and Forge (with the `Tracked`
|
||||
module trait that lets Lathe, Temper and Knurl run behind one shared tracker),
|
||||
4× oversampling (also Quench's), BS.1770 K-weighting (Ballast), meters and WAV
|
||||
files.
|
||||
|
||||
The wrappers stay separate workspaces, each with its own lockfile, so the
|
||||
NIH-plug Git dependency stays out of the root workspace. Host identities and
|
||||
@@ -46,7 +48,7 @@ python3 -m unittest discover -s scripts/tests -v
|
||||
```
|
||||
|
||||
Products: `rivet`, `patina`, `anvil`, `crucible`, `lathe`, `temper`, `weld`,
|
||||
`knurl`, `planish`, `braze`, `quench`, `ballast`.
|
||||
`knurl`, `planish`, `braze`, `quench`, `ballast`, `forge`.
|
||||
|
||||
`check-plugin.py` runs formatting, tests and clippy for one product's packages
|
||||
and its wrapper, without compiling the other products. Run it for every product
|
||||
@@ -149,6 +151,7 @@ identify plugins by CLAP ID, so the vendor name does not affect saved projects.
|
||||
| Braze | (new) | `io.narl.bass-foundry.braze` |
|
||||
| Quench | (new) | `io.narl.bass-foundry.quench` |
|
||||
| Ballast | (new) | `io.narl.bass-foundry.ballast` |
|
||||
| Forge | (new) | `io.narl.bass-foundry.forge` |
|
||||
|
||||
CLAP IDs use the form `io.narl.bass-foundry.<product>`. Builds tagged before
|
||||
this scheme used `io.storyboard.*` IDs; hosts treat the new IDs as different
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Forge changelog
|
||||
|
||||
## Unreleased (0.1.0)
|
||||
|
||||
- Introduce Forge, one tracked channel strip: Lathe, Temper and Knurl behind a
|
||||
single note tracker, in any of the six orders, each module on or off.
|
||||
- Every module follows the note read from the strip's input, so a module after
|
||||
Knurl no longer hears Knurl's sub-octave.
|
||||
- One latency of about 72 ms, the same in every order, instead of more than
|
||||
200 ms for the three plugins in a row.
|
||||
- A single module on its own gives the same output, sample for sample, as its
|
||||
standalone plugin.
|
||||
- Editor: the chain, and each module's standalone editor as its page.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Forge
|
||||
|
||||
Forge is one tracked channel strip: Lathe, Temper and Knurl run behind a single
|
||||
note tracker, in the order you choose. Current version **0.1.0** (unreleased).
|
||||
|
||||
Each of the three plugins detects the played note itself. In a row, their
|
||||
lookaheads add up (Lathe 67 ms, Temper 68 ms, Knurl 71 ms: more than 200 ms),
|
||||
and a tracker after Knurl hears Knurl's sub-octave and follows a note an octave
|
||||
low. Forge reads the note once, from its input, and every module follows that
|
||||
one tracker. In a test with Knurl's sub-octave pattern in front of Lathe, a
|
||||
standalone Lathe after Knurl followed the note an octave low in every frame;
|
||||
Lathe inside Forge followed the played note in every frame.
|
||||
|
||||

|
||||
|
||||
## Install on Windows
|
||||
|
||||
Copy `Forge.clap` into `C:\Program Files\Common Files\CLAP\`. In FL Studio
|
||||
2024.1 or newer, open Options → Manage plugins, enable Verify plugins, and Find
|
||||
installed plugins. Load Forge in the mixer slot of the bass, right after the
|
||||
synth. Keep the font license with redistributed packages.
|
||||
|
||||
## Work with it
|
||||
|
||||
1. Choose **Pitch from** in the header: **AUDIO** detects the note from the
|
||||
input; **MIDI** follows MIDI notes sent to the effect. All modules use it.
|
||||
2. The **Chain** row shows the modules in processing order. Click a module's
|
||||
name to edit it below; **ON** switches it on or off. The button between two
|
||||
modules swaps them. The default order is Lathe, Temper, Knurl, as in the
|
||||
standalone chain.
|
||||
3. Each module's page is its standalone editor: [Lathe](../lathe/README.md),
|
||||
[Temper](../temper/README.md) and [Knurl](../knurl/README.md) explain the
|
||||
controls. Temper's **AUTO GAIN** sits in the Chain row while its page is
|
||||
open.
|
||||
4. The **Gate** knob on every page is the one shared tracker gate: turning it on
|
||||
one page turns it on all.
|
||||
|
||||
**Bypass** in the header crossfades the whole strip to the delayed input.
|
||||
|
||||
## How it works
|
||||
|
||||
The tracker reads the strip's input, and the audio is delayed by its lookahead
|
||||
once. Every module gets the note events delayed by the latency of the modules
|
||||
in front of it, so each module sees a note start exactly on the attack of the
|
||||
audio it receives. A single module on its own in Forge gives the same output,
|
||||
sample for sample, as its standalone plugin, in every position of the chain.
|
||||
|
||||
Temper's **Normalize** measures each note's level one lookahead ahead. In Forge
|
||||
it measures the strip's input, not the output of the modules in front of it.
|
||||
Lathe and Knurl change the level about equally on every note, so the notes
|
||||
still reach the shaper at one level.
|
||||
|
||||
## Timing and limits
|
||||
|
||||
Latency is the tracker's lookahead (about 67 ms), Temper's oversampling filters
|
||||
(under 1 ms) and Knurl's room for timing jitter (about 4 ms): about 72 ms in
|
||||
all, reported to the host. A module that is off still delays its audio by its
|
||||
own latency, so the latency stays the same in every order and with any module
|
||||
off.
|
||||
|
||||
Changing the order while audio plays switches the routing at once and can
|
||||
click. The standalone plugins stay: use them when you need only one module, or
|
||||
when another plugin must sit between two of them.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 314 KiB |
+26
-1
@@ -270,7 +270,7 @@ one period of the note, so heavy settings do not ripple at f0. See [Planish](pla
|
||||
(prototype `scripts/fatness.py`); Anvil Ghost harmonics and Phone listen
|
||||
(done, Anvil 0.3.0); Braze (done, 0.1.0); Anvil Kick lock with offset
|
||||
audition (done, Anvil 0.3.0).
|
||||
4. Forge, when enough modules exist.
|
||||
4. Forge (done, unreleased 0.1.0): Lathe, Temper and Knurl behind one tracker.
|
||||
5. Assay, one plugin for the display-only ideas.
|
||||
6. Texture plugins (Anneal, Swarf, Etch, Bellows) and the note-keyed sequencer.
|
||||
|
||||
@@ -291,6 +291,31 @@ before Knurl) and the repeated MIDI routing. The standalone plugins stay.
|
||||
Sharing one tracker between separate `.clap` files would need named shared
|
||||
memory across DLLs, which is fragile; one strip is simpler.
|
||||
|
||||
Built (unreleased 0.1.0, see [Forge](forge/README.md)). Lathe, Temper and Knurl
|
||||
became modules (a `Tracked` trait in common-dsp: `ahead`, `event`, `process`);
|
||||
each standalone plugin is now its tracker plus its module, Lathe and Temper
|
||||
bit-exact against the old engines, Knurl one sample later (its interpolation
|
||||
needs one newer sample) and equal within float rounding. In the strip one
|
||||
tracker reads the input; a per-sample record of the tracker's events, note state
|
||||
and input is replayed to each module, delayed by the latency of the modules in
|
||||
front of it. Findings:
|
||||
|
||||
- One module alone in Forge matches its standalone plugin sample for sample, in
|
||||
all six orders (tested).
|
||||
- Knurl's Double-style pattern (0, −12 dB) in front of Lathe: standalone Lathe
|
||||
after Knurl read the note an octave low in 149 of 149 frames on an A2 saw;
|
||||
Lathe inside Forge read A2 in 149 of 149.
|
||||
- Latency 72 ms against 206 ms for the three in a row (48 kHz).
|
||||
- Temper's Normalize looks one lookahead ahead; in the strip it reads the strip
|
||||
input, not the modules in front of it. Fine while those change every note's
|
||||
level alike.
|
||||
|
||||
Next for Forge: the *Tension* macro over Knurl (and later Anneal) at matched
|
||||
loudness; Planish and Braze as modules (both are tracked, and Braze after
|
||||
Knurl is the next tracker that hears the sub-octave); a short crossfade when
|
||||
the order changes; one shared modulation source (per-note envelope or LFO in
|
||||
cycles) that every module can read.
|
||||
|
||||
### Braze — tempo-locked beating (problem 20)
|
||||
|
||||
Brazing joins two metals with a filler. Braze adds a detuned copy of the bass
|
||||
|
||||
Reference in new issue
Block a user