chore: rename the suite to Bass Foundry
Check and Windows preview / check (anvil) (push) Successful in 2m5s
Check and Windows preview / check (crucible) (push) Successful in 2m11s
Check and Windows preview / check (lathe) (push) Successful in 2m22s
Check and Windows preview / check (patina) (push) Successful in 2m50s
Check and Windows preview / check (rivet) (push) Successful in 46s
Check and Windows preview / check (temper) (push) Successful in 41s
Check and Windows preview / check (weld) (push) Successful in 39s
Check and Windows preview / previews (push) Failing after 24s
Check and Windows preview / windows (push) Skipped
Check and Windows preview / check (anvil) (push) Successful in 2m5s
Check and Windows preview / check (crucible) (push) Successful in 2m11s
Check and Windows preview / check (lathe) (push) Successful in 2m22s
Check and Windows preview / check (patina) (push) Successful in 2m50s
Check and Windows preview / check (rivet) (push) Successful in 46s
Check and Windows preview / check (temper) (push) Successful in 41s
Check and Windows preview / check (weld) (push) Successful in 39s
Check and Windows preview / previews (push) Failing after 24s
Check and Windows preview / windows (push) Skipped
Set the CLAP vendor of all seven plugins to "Bass Foundry" and name the combined preview ZIP bass-foundry-windows-x86_64.zip. CLAP IDs and saved state stay unchanged. Bring development.md and releases.md up to date with all seven products, the shared crates, the test types, the steps to add a product and the published releases. Add texture problems and seven texture plugin ideas to ideas.md.
This commit is contained in:
1 parent
6a4ec3d372
commit
0a0917ac56
14 files changed
+282
-123
No files matched your search
@@ -94,8 +94,8 @@ jobs:
|
||||
python3 scripts/package-windows.py
|
||||
- uses: https://github.com/actions/upload-artifact@v3-node20
|
||||
with:
|
||||
name: rivet-patina-windows-x86_64
|
||||
name: bass-foundry-windows-x86_64
|
||||
path: |
|
||||
dist/rivet-patina-windows-x86_64.zip
|
||||
dist/rivet-patina-windows-x86_64.zip.sha256
|
||||
dist/bass-foundry-windows-x86_64.zip
|
||||
dist/bass-foundry-windows-x86_64.zip.sha256
|
||||
retention-days: 30
|
||||
@@ -1,4 +1,4 @@
|
||||
# FL Studio Suite
|
||||
# Bass Foundry
|
||||
|
||||
**Rust CLAP plugins for writing, designing and mixing bass music in FL Studio.**
|
||||
|
||||
@@ -36,6 +36,8 @@ surface and keeps its character; an **anvil** is the solid base that everything
|
||||
is struck on; a **crucible** melts material down to be cast again; a **lathe**
|
||||
turns a piece so each cut lands the same all the way round; **tempering** sets
|
||||
how hard and how tough a metal ends up; a **weld** fuses two pieces into one.
|
||||
The suite is the **foundry**: the workshop where the bass gets cast, shaped and
|
||||
finished. Hosts list the plugins under the vendor name *Bass Foundry*.
|
||||
|
||||
## Editors
|
||||
|
||||
@@ -76,11 +78,13 @@ The previews are rendered headless from the real editor code by
|
||||
Keep the font license (`licenses/`) with redistributed packages.
|
||||
|
||||
Every branch and pull-request pipeline also builds a combined Windows preview
|
||||
ZIP in its **windows** job. Use it to test unreleased changes.
|
||||
ZIP, `bass-foundry-windows-x86_64.zip`, in its **windows** job. Use it to test unreleased changes.
|
||||
|
||||
> **Upgrading from Motif Storyboard or Resonance Compressor?** These are now
|
||||
> Rivet and Patina. The CLAP IDs and saved state are unchanged, so projects
|
||||
> still load. Delete the old `.clap` files and rescan.
|
||||
> still load. Delete the old `.clap` files and rescan. The vendor name changed
|
||||
> from "Rivet & Patina" to "Bass Foundry", so FL Studio may list the plugins
|
||||
> in a new vendor folder after the rescan.
|
||||
|
||||
## Build from source
|
||||
|
||||
|
||||
+112
-68
@@ -1,109 +1,153 @@
|
||||
# Development
|
||||
|
||||
Run commands from the repository root. Rust stable and Python **3.11 or newer**
|
||||
are required. Lockfiles are committed for the core workspace, both CLAP wrappers,
|
||||
and the headless editor tool.
|
||||
Run commands from the repository root. You need Rust stable and Python **3.11 or
|
||||
newer**. Lockfiles are committed for the root workspace, every CLAP wrapper and
|
||||
the headless editor tool. Use `--locked` so a build never changes them silently.
|
||||
|
||||
## Product boundaries
|
||||
|
||||
The catalog in [plugins/catalog.json](../plugins/catalog.json) defines product
|
||||
names, wrapper manifests, documentation, internal packages, and distribution
|
||||
licenses. Shared build/check/release tools consume it. Each wrapper's Cargo
|
||||
package version is the authoritative release version.
|
||||
[plugins/catalog.json](../plugins/catalog.json) is the single list of products.
|
||||
For each product it defines the display name, the wrapper manifest, the library
|
||||
name, the documentation folder, the CLAP ID, the internal packages and the
|
||||
licenses to ship. The build, check, package and release scripts and the script
|
||||
tests read it. The version in each wrapper's `Cargo.toml` is the release version.
|
||||
|
||||
The root workspace contains Rivet's core, MIDI, application, and offline preview
|
||||
crates; Patina's core, editor, and renderer; Anvil's and Crucible's core and
|
||||
editor crates; and the shared `common-ui` (palette, fonts, knobs, panels) and
|
||||
`common-dsp` (filters, YIN pitch detection, WAV files) crates. Wrappers under
|
||||
`plugins/<product>/plugin/` remain independent workspaces because they depend on
|
||||
a pinned NIH-plug Git revision. Their host identities and persistence stay separate.
|
||||
Every product has the same split:
|
||||
|
||||
| Folder | Content | Workspace |
|
||||
| --- | --- | --- |
|
||||
| `plugins/<product>/core/` | Engine. Plain Rust, no plugin SDK, tested on its own | root |
|
||||
| `plugins/<product>/ui/` | egui editor, built on `common-ui` | root |
|
||||
| `plugins/<product>/plugin/` | CLAP wrapper on a pinned NIH-plug revision | own |
|
||||
|
||||
Rivet has more crates in the root workspace (`midi`, `app`, `preview`), and
|
||||
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 and Temper, 4× oversampling, 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
|
||||
saved state are separate for every product.
|
||||
|
||||
The engines run allocation-free on the audio thread. Analysis that is too heavy
|
||||
for the audio thread (Rivet's generation jobs, and Weld's planned phase fit) runs on a worker
|
||||
thread. Data goes to the editor through lock-free queues.
|
||||
|
||||
## Checks
|
||||
|
||||
```sh
|
||||
cargo test --workspace --locked
|
||||
cargo clippy --workspace --all-targets --locked -- -D warnings
|
||||
python scripts/check-plugin.py --plugin rivet
|
||||
python scripts/check-plugin.py --plugin patina
|
||||
python scripts/check-plugin.py --plugin anvil
|
||||
python scripts/check-plugin.py --plugin crucible
|
||||
python scripts/check-plugin.py --plugin lathe
|
||||
python scripts/check-plugin.py --plugin temper
|
||||
python -m unittest discover -s scripts/tests -v
|
||||
python3 scripts/check-plugin.py --plugin <product>
|
||||
python3 -m unittest discover -s scripts/tests -v
|
||||
```
|
||||
|
||||
The product check script checks formatting, tests, and lints that product's
|
||||
packages and wrapper without compiling the other plugin. Offline builds work
|
||||
once dependencies are cached; append `--offline` to manual Cargo commands.
|
||||
Products: `rivet`, `patina`, `anvil`, `crucible`, `lathe`, `temper`, `weld`.
|
||||
|
||||
Native wrapper tests on Linux require pkg-config, X11/XCB, and OpenGL development
|
||||
headers. Rivet's optional standalone also needs ALSA/JACK headers. Gitea installs
|
||||
the headers needed by its check jobs.
|
||||
`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
|
||||
when you change a shared crate or the root workspace. Offline builds work once
|
||||
the dependencies are cached; add `--offline` to manual Cargo commands.
|
||||
|
||||
The test types are:
|
||||
|
||||
- **Engine tests** (`core/tests/dsp.rs` and similar) measure signal behaviour
|
||||
and latency against fixed targets.
|
||||
- **Realtime tests** (`core/tests/realtime.rs`) install a counting allocator
|
||||
and fail if the audio-thread path allocates.
|
||||
- **Host tests** (`plugin/tests/host.rs`) load the wrapper through the exported
|
||||
CLAP ABI without a DAW. They check the ports, latency, state save and load,
|
||||
and processing at 44.1, 48 and 96 kHz with odd block sizes.
|
||||
- **Script tests** (`scripts/tests/`) cover the catalog, release planning,
|
||||
packaging and the publish client with fake transports. They also fail when a
|
||||
catalog product is missing from a CI workflow.
|
||||
|
||||
The native wrapper tests on Linux need pkg-config and the X11/XCB and OpenGL
|
||||
development headers. Rivet's optional standalone also needs ALSA/JACK headers.
|
||||
The Gitea check jobs install these headers.
|
||||
|
||||
## Windows builds
|
||||
|
||||
On Windows, install Rust and the MSVC build tools. For Linux cross-compilation,
|
||||
install the Rust `x86_64-pc-windows-gnu` target and MinGW's
|
||||
`x86_64-w64-mingw32-gcc`.
|
||||
On Windows, install Rust and the MSVC build tools. To cross-compile on Linux,
|
||||
install the Rust `x86_64-pc-windows-gnu` target and MinGW
|
||||
(`x86_64-w64-mingw32-gcc`).
|
||||
|
||||
```sh
|
||||
python scripts/build-plugin.py --plugin rivet --target x86_64-pc-windows-gnu
|
||||
python scripts/build-plugin.py --plugin patina --target x86_64-pc-windows-gnu
|
||||
python scripts/build-plugin.py --plugin anvil --target x86_64-pc-windows-gnu
|
||||
python scripts/build-plugin.py --plugin crucible --target x86_64-pc-windows-gnu
|
||||
python scripts/build-plugin.py --plugin lathe --target x86_64-pc-windows-gnu
|
||||
python scripts/build-plugin.py --plugin temper --target x86_64-pc-windows-gnu
|
||||
python scripts/package-windows.py
|
||||
python scripts/package-windows.py --plugin rivet
|
||||
python scripts/package-windows.py --plugin patina
|
||||
python3 scripts/build-plugin.py --plugin <product> --target x86_64-pc-windows-gnu
|
||||
python3 scripts/package-windows.py # combined preview ZIP
|
||||
python3 scripts/package-windows.py --plugin <product> # one product's release ZIP
|
||||
```
|
||||
|
||||
Build outputs use `dist/<target>/<Name>.clap`, with docs and
|
||||
licenses retaining their directory structure. `CARGO_TARGET_DIR` is supported
|
||||
for sharing compilation between wrappers. MSVC packaging accepts
|
||||
Builds go to `dist/<target>/<Name>.clap`, with the docs and licenses in the same
|
||||
folder structure. `CARGO_TARGET_DIR` is supported for sharing one build
|
||||
directory between wrappers. MSVC packaging accepts
|
||||
`--target x86_64-pc-windows-msvc`.
|
||||
|
||||
The combined ZIP is `dist/rivet-patina-windows-x86_64.zip`. Individual ZIPs use
|
||||
`<product>-windows-x86_64-<version>.zip`. Each ZIP has internal file checksums and
|
||||
an external `.zip.sha256`. ZIP metadata is deterministic; binaries still depend
|
||||
on the toolchain and build environment. Packaging includes only selected catalog
|
||||
entries, never old binaries left in `dist`.
|
||||
- The combined ZIP is `dist/bass-foundry-windows-x86_64.zip`. It holds every
|
||||
product that has been built.
|
||||
- A product ZIP is `<product>-windows-x86_64-<version>.zip` and holds only that
|
||||
product.
|
||||
|
||||
Linux builds remain available for local development; CI produces Windows release
|
||||
binaries only. Neither build nor packaging installs plugins into a DAW.
|
||||
Every ZIP has a `SHA256SUMS` file inside and a `.zip.sha256` file next to it.
|
||||
ZIP metadata is deterministic; the binaries still depend on the toolchain and
|
||||
the build environment. Packaging takes only the selected catalog entries, never
|
||||
old binaries left in `dist`.
|
||||
|
||||
Linux builds are for local development; CI produces only Windows binaries. No
|
||||
script installs a plugin into a DAW.
|
||||
|
||||
## Editor previews
|
||||
|
||||
```sh
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/rivet.png --plugin rivet
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/rivet-creative.png --plugin rivet --creative
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/patina.png --plugin patina
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/patina-compact.png --plugin patina --compact
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/anvil.png --plugin anvil
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/crucible.png --plugin crucible
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/lathe.png --plugin lathe
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- /tmp/temper.png --plugin temper
|
||||
mkdir -p target/editor
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- target/editor/<product>.png --plugin <product>
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- target/editor/rivet-creative.png --plugin rivet --creative
|
||||
cargo run --manifest-path tools/editor-check/Cargo.toml -- target/editor/patina-compact.png --plugin patina --compact
|
||||
```
|
||||
|
||||
Patina also accepts `--silent`, `--delta`, and `--bypass` as render fixtures.
|
||||
The tool compiles actual editor code and software-renders without a display.
|
||||
These checks do not establish native host embedding, keyboard routing, or audible
|
||||
artistic quality. Use the product guides for FL Studio acceptance checks.
|
||||
Patina also accepts `--silent`, `--delta` and `--bypass`. The tool compiles the
|
||||
real editor code, feeds it synthetic analysis data and renders it in software
|
||||
without a display. Copy a checked render to `docs/<product>/assets/editor.png`
|
||||
to update the guide. These renders do not prove native host embedding, keyboard
|
||||
routing or how the plugin sounds; use the FL Studio checks in each product guide.
|
||||
|
||||
## Add a product
|
||||
|
||||
1. Create `plugins/<product>/{core,ui,plugin}`. Copy the wrapper `Cargo.toml`
|
||||
and `Cargo.lock` of a similar product so the NIH-plug revision matches.
|
||||
2. Add `core` and `ui` to the root `members`, the wrapper to `exclude`, and a
|
||||
`[profile.dev.package.<product>-core] opt-level = 2` entry if the tests run
|
||||
heavy DSP.
|
||||
3. Add the product to `plugins/catalog.json` with a new, unique CLAP ID.
|
||||
4. Add it to `.gitea/workflows/check.yml` (check matrix, editor preview,
|
||||
Windows build) and to the tag list in `release.yml`. The script tests fail
|
||||
until you do.
|
||||
5. Add a `--plugin <product>` fixture to `tools/editor-check`.
|
||||
6. Write `docs/<product>/README.md`, `CHANGELOG.md` and `assets/editor.png`, and
|
||||
add the product to the root README.
|
||||
|
||||
## Compatibility and naming
|
||||
|
||||
| Product | Former display name | Preserved CLAP ID |
|
||||
The suite is called **Bass Foundry**; this is the vendor name hosts show. Hosts
|
||||
identify plugins by CLAP ID, so the vendor name does not affect saved projects.
|
||||
|
||||
| Product | Former display name | CLAP ID |
|
||||
| --- | --- | --- |
|
||||
| Rivet | Motif Storyboard | `io.storyboard.motif` |
|
||||
| Patina | Resonance Compressor | `io.storyboard.resonance-compressor` |
|
||||
| Anvil | (new) | `io.storyboard.sub-anchor` |
|
||||
| Crucible | (new) | `io.storyboard.resampler` |
|
||||
| Lathe | (new) | `io.storyboard.harmonic-eq` |
|
||||
| Temper | (new) | `io.storyboard.tracked-distortion` |
|
||||
| Weld | (new) | `io.storyboard.layer-align` |
|
||||
|
||||
Rivet retains `story-session-v1` and its session migration support; Patina retains
|
||||
all parameter IDs. No JSON/state migration is introduced by the rename. These
|
||||
historical identifiers and copyright notices intentionally remain in source.
|
||||
Replace old scanned plugin files before rescanning, rather than keeping duplicate
|
||||
CLAP IDs installed. Verify existing-project recall in FL Studio.
|
||||
The `io.storyboard.` prefix is historical and stays, because changing a CLAP ID
|
||||
breaks existing projects. Rivet keeps `story-session-v1` and its session
|
||||
migration. Patina keeps all parameter IDs. The copyright notice keeps its
|
||||
original holder name. Replace old plugin files before rescanning, so no CLAP ID
|
||||
is installed twice, and check that existing projects still load in FL Studio.
|
||||
|
||||
See [release workflow](releases.md) for tagged publishing. Actual Gitea runner
|
||||
execution and FL Studio validation remain separate from local checks.
|
||||
See [releases](releases.md) for tagged publishing. Runs on the real Gitea runner
|
||||
and checks in FL Studio are separate from the local checks.
|
||||
+117
-7
@@ -1,7 +1,7 @@
|
||||
# Plugin ideas
|
||||
|
||||
A running list of plugin ideas for riddim, dubstep and bass-music sound design.
|
||||
Each entry names the problem first. Entries are grouped as released or idea. Names follow the metalwork theme of Rivet, Patina, Anvil and Crucible.
|
||||
Each entry names the problem first. Entries are grouped as released or idea. Names follow the metalwork theme of the Bass Foundry suite.
|
||||
|
||||
## Problems seen in bass-music production
|
||||
|
||||
@@ -24,6 +24,17 @@ Each entry names the problem first. Entries are grouped as released or idea. Nam
|
||||
lifts the 4th harmonic of one note and the 7th of another; a distortion with
|
||||
a fixed tone filter sounds brighter on low notes than on high notes.
|
||||
10. Layered bass patches partly cancel in the mids, not only in the sub.
|
||||
11. Texture makes a riddim patch: grit, rattle, metal, vowel, noise. It takes long
|
||||
chains (distortion, comb, formant, OTT, resample, repeat), and the result
|
||||
changes from note to note.
|
||||
12. Grit and tone cannot be shaped separately. More distortion for more grit
|
||||
also changes the body, the level and the low end.
|
||||
13. Resampled textures sound printed: a loop of one moment, with no movement
|
||||
inside the note.
|
||||
14. Texture changes inside a note (the switch-up within one held note) need
|
||||
automation lanes or chopping.
|
||||
15. There is no meter for texture. Two switch-ups can sound "the same" without
|
||||
a clear reason, and generic analysers show only level and spectrum.
|
||||
|
||||
## Released
|
||||
|
||||
@@ -58,13 +69,14 @@ loud the patch is, and the output is gain-matched. Oversampled to keep aliasing
|
||||
|
||||
## Ideas
|
||||
|
||||
### Weld — layer phase alignment (problem 10)
|
||||
### Weld — layer phase alignment (problem 10) — in development
|
||||
|
||||
Takes a second bass layer through the sidechain. Per band, it rotates phase
|
||||
with allpass filters (no added delay) and flips polarity so the layers sum
|
||||
instead of cancel. A display shows how much level the cancellation cost. Anvil
|
||||
solves the sub band; Weld solves the mids. Hardest of the list: phase matching
|
||||
against a moving sidechain.
|
||||
Takes a second bass layer through the sidechain. It fits polarity and a chain
|
||||
of up to four allpass sections to the measured cross-spectrum (no added
|
||||
delay), so the layers sum instead of cancel. A display shows how much level the
|
||||
cancellation cost and how much Weld recovered. Anvil solves the sub band; Weld
|
||||
solves the mids. A sidechain test build exists; the fit comes after the FL
|
||||
Studio routing test. See [Weld](weld/README.md).
|
||||
|
||||
### Ballast — switch-up loudness leveller (problem 2)
|
||||
|
||||
@@ -99,3 +111,101 @@ patterns. No name yet.
|
||||
Loudness-matched A/B of a drop against a reference, with sub, low-mid, mid and
|
||||
high energy over time: for example "your sub is 3 dB under the reference in
|
||||
bars 2–4". No name yet.
|
||||
|
||||
## Texture ideas
|
||||
|
||||
These ideas target problems 11–15. Most of them reuse the note tracker in
|
||||
`common-dsp`, so a texture setting means the same thing on every note, the same
|
||||
way Lathe and Temper work.
|
||||
|
||||
### Knurl — pitch-synchronous grit (problems 11, 13)
|
||||
|
||||
Knurling presses a ridged pattern into metal. Knurl cuts the signal into single
|
||||
pitch periods with the note tracker and changes each period on its own:
|
||||
|
||||
- level and timing jitter per cycle;
|
||||
- short noise bursts locked to the cycle;
|
||||
- period doubling and tripling (a cycle pattern such as "loud, quiet, quiet"),
|
||||
which gives the subharmonic rattle and growl of riddim basses;
|
||||
- slow random drift of each harmonic's level and phase, which brings movement
|
||||
into a printed resample without widening it.
|
||||
|
||||
Rates are in cycles, not in Hz or tempo, so the grit has the same grain on F1
|
||||
and on C2. A pattern editor sets 1–16 cycles. Everything is mono-safe. Latency
|
||||
is the tracker lookahead, about 67 ms. Recommended first texture build: it is
|
||||
new, small, and reuses Lathe's tracking.
|
||||
|
||||
### Anneal — tone and grit split (problem 12)
|
||||
|
||||
Annealing changes how a metal behaves without changing its shape. Anneal
|
||||
splits the signal into three parts: the harmonic part (energy on the harmonics
|
||||
of the tracked note), the residual noise and grit between the harmonics, and
|
||||
the transients. Each part has a level fader, a drive and a tilt.
|
||||
|
||||
- Turn the grit up 6 dB and keep the body and the sub unchanged.
|
||||
- Take all the grit out of a layer and leave a clean tone for further design.
|
||||
- Listen to each part solo, or send the grit to a second output for its own
|
||||
chain.
|
||||
|
||||
DSP: an STFT with the note tracker; harmonic masks at k·f0, with a width that
|
||||
follows the pitch; a transient mask from spectral flux. Latency is one FFT
|
||||
frame. The display shows the three parts in different colours on Lathe's
|
||||
harmonic strip.
|
||||
|
||||
### Swarf — in-key granular shavings (problems 11, 13)
|
||||
|
||||
Swarf is the shavings that machining leaves. Swarf records the bass itself and
|
||||
sprays short grains of it back as a layer. Grain lengths are whole pitch
|
||||
periods, and every grain is retuned to the note playing now, so the shredded
|
||||
layer stays in key across a riddim line. Controls are density, spray (position
|
||||
spread back in time), grain size in cycles, reverse probability, and a
|
||||
harmonic-only filter for the layer. It is useful for the "shredded metal" top
|
||||
layer, and works on a resample from Crucible as well.
|
||||
|
||||
### Etch — texture imprint (problem 11)
|
||||
|
||||
Etching transfers a pattern onto metal with acid. Etch takes a texture source
|
||||
through the sidechain or from a loaded sample (a metal scrape, a vocal, a field
|
||||
recording) and imprints its fine structure on the bass. The bass keeps its
|
||||
pitch and its harmonic levels; between and on the harmonics, the source's
|
||||
noise, roughness and movement come through. A "harmonic lock" mode samples the
|
||||
source's spectral envelope only at the bass harmonics, so the imprint is always
|
||||
in key. It differs from a vocoder: a vocoder transfers the envelope, and Etch
|
||||
transfers the surface.
|
||||
|
||||
### Chase — talking formants that hit harmonics (problems 11, 14)
|
||||
|
||||
Chasing shapes metal by hammering it from the front. Chase is a formant filter
|
||||
with a 2D vowel pad (a, e, i, o, u, plus "yoi" and "wub" shapes). You draw a
|
||||
path over the pad and sync it to the tempo, or let each MIDI note select a path.
|
||||
The formants stay in Hz, so a vowel stays a vowel on every note. A **snap**
|
||||
control moves each resonant peak onto the nearest harmonic of the tracked
|
||||
note, so a narrow formant never falls into the gap between two harmonics and
|
||||
vanishes on some notes. Gain-matched, so a vowel change does not change the
|
||||
level.
|
||||
|
||||
### Damascus — texture step sequencer (problem 14)
|
||||
|
||||
Damascus steel is folded from layers into a visible pattern. Damascus holds up
|
||||
to four texture slots (for example a formant, a comb, a sample-rate reducer and
|
||||
a Knurl-type rattle) and a tempo-synced step grid that chooses a slot, or a mix
|
||||
of two, per step. Steps have their own crossfade time, so changes can be hard
|
||||
cuts or smears. Each slot is gain-matched, so the steps change texture and not
|
||||
level. Each MIDI note can select its own pattern, which is a texture switch-up
|
||||
inside one held note. This overlaps with the wobble sequencer above; both could
|
||||
become one plugin.
|
||||
|
||||
### Loupe — texture meter (problem 15)
|
||||
|
||||
A loupe is the lens used to inspect engraving. Loupe measures texture per note
|
||||
over time:
|
||||
|
||||
- roughness and fluctuation strength (psychoacoustic models);
|
||||
- harmonic-to-noise ratio, which shows how gritty a sound is;
|
||||
- inharmonicity, which shows how metallic a sound is;
|
||||
- brightness relative to the note (harmonic centroid, not centroid in Hz).
|
||||
|
||||
It places every switch-up of a drop as a point on a texture map. Two patches
|
||||
that sit on the same point are why a drop sounds repetitive. A reference track
|
||||
can be loaded for comparison. Display only, so it is a small build, and it fits
|
||||
with Gauge and Drop compare.
|
||||
+34
-33
@@ -1,49 +1,50 @@
|
||||
# Independent plugin releases on Gitea
|
||||
|
||||
Rivet and Patina have independent versions and releases. Workflows live under
|
||||
`.gitea/workflows/`.
|
||||
Every Bass Foundry plugin has its own version and its own release. The
|
||||
workflows are in `.gitea/workflows/`. A plugin's version is the `version` in
|
||||
`plugins/<plugin>/plugin/Cargo.toml`, and its release tag is
|
||||
`<plugin>-v<version>`.
|
||||
|
||||
| Tag | Gitea release | Windows download |
|
||||
| Plugin | Latest tag | Windows download |
|
||||
| --- | --- | --- |
|
||||
| `rivet-v0.3.0` | Rivet 0.3.0 | `rivet-windows-x86_64-0.3.0.zip` |
|
||||
| `patina-v0.1.0` | Patina 0.1.0 | `patina-windows-x86_64-0.1.0.zip` |
|
||||
| Rivet | `rivet-v0.4.0` | `rivet-windows-x86_64-0.4.0.zip` |
|
||||
| Patina | `patina-v0.2.0` | `patina-windows-x86_64-0.2.0.zip` |
|
||||
| Anvil | `anvil-v0.1.0` | `anvil-windows-x86_64-0.1.0.zip` |
|
||||
| Crucible | `crucible-v0.1.0` | `crucible-windows-x86_64-0.1.0.zip` |
|
||||
| Lathe | `lathe-v0.1.0` | `lathe-windows-x86_64-0.1.0.zip` |
|
||||
| Temper | `temper-v0.1.0` | `temper-windows-x86_64-0.1.0.zip` |
|
||||
| Weld | not released yet | |
|
||||
|
||||
## Make a release
|
||||
|
||||
1. Update the selected wrapper's `Cargo.toml` version and its
|
||||
`docs/<product>/CHANGELOG.md`. The wrapper version determines the release
|
||||
version; internal crate versions can evolve separately.
|
||||
2. Refresh affected lockfiles, run the product check, and commit/push the change.
|
||||
3. Tag the intended commit and push that product's tag.
|
||||
1. Set the new version in the plugin's wrapper `Cargo.toml` and add a section
|
||||
with that version to `docs/<plugin>/CHANGELOG.md`. Internal crate versions
|
||||
can change independently.
|
||||
2. Refresh the affected lockfiles, run the plugin's check, then commit and push.
|
||||
3. Tag the commit and push only that plugin's tag.
|
||||
|
||||
For Rivet:
|
||||
For example, Temper 0.2.0:
|
||||
|
||||
```sh
|
||||
python scripts/check-plugin.py --plugin rivet
|
||||
git tag -a rivet-v0.3.0 -m "Rivet 0.3.0"
|
||||
git push origin rivet-v0.3.0
|
||||
python3 scripts/check-plugin.py --plugin temper
|
||||
git tag -a temper-v0.2.0 -m "Temper 0.2.0"
|
||||
git push origin temper-v0.2.0
|
||||
```
|
||||
|
||||
For Patina:
|
||||
|
||||
```sh
|
||||
python scripts/check-plugin.py --plugin patina
|
||||
git tag -a patina-v0.1.0 -m "Patina 0.1.0"
|
||||
git push origin patina-v0.1.0
|
||||
```
|
||||
|
||||
These are instructions; this change does not create tags or publish a release.
|
||||
Tags must exactly match the selected wrapper version and a changelog section.
|
||||
Wrong product/version tags fail before building or publishing. Cargo prerelease
|
||||
versions such as `patina-v0.2.0-rc.1` are supported and marked as prereleases.
|
||||
The tag must match the wrapper version and a changelog section exactly. A wrong
|
||||
plugin name or version fails in the `plan` job, before anything is built or
|
||||
published. Cargo prerelease versions such as `temper-v0.2.0-rc.1` are supported
|
||||
and published as prereleases.
|
||||
|
||||
## Workflows
|
||||
|
||||
**Check and Windows preview** runs on branch pushes, pull requests, and manual
|
||||
dispatch. It checks both products, renders editor previews, and provides a combined
|
||||
Windows ZIP as an Actions artifact. It never publishes a release.
|
||||
dispatch. It checks every product in a matrix, renders all editor previews, and
|
||||
provides the combined `bass-foundry-windows-x86_64.zip` as an Actions artifact.
|
||||
It never publishes a release.
|
||||
|
||||
**Independent plugin release** runs on `rivet-v*` or `patina-v*` tag pushes:
|
||||
**Independent plugin release** runs when a `<plugin>-v*` tag is pushed, for any
|
||||
plugin in the catalog:
|
||||
|
||||
1. `plan` validates the product/version/changelog and exposes the selected plugin.
|
||||
2. `build` checks and cross-compiles only that plugin, then packages its Windows
|
||||
@@ -106,7 +107,7 @@ The release tag must already exist in Gitea; the publisher does not create tags.
|
||||
The ZIP must contain exactly the selected plugin. Its sidecar and internal file
|
||||
checksums are verified before any release write.
|
||||
|
||||
Choose a plugin's named release/tag rather than assuming the repository's global
|
||||
latest release refers to both products. Package and API behavior are tested with
|
||||
fake transports; an actual runner/tag release on this Gitea instance remains to
|
||||
be verified.
|
||||
Link to a plugin's own release or tag. The repository's "latest release" is
|
||||
only the most recent release of any plugin. Packaging and API behaviour are tested with
|
||||
fake transports. Every tag in the table above was published by this workflow on
|
||||
the project's Gitea instance.
|
||||
@@ -41,7 +41,7 @@ impl Default for Anvil {
|
||||
}
|
||||
impl Plugin for Anvil {
|
||||
const NAME: &'static str = "Anvil";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -51,7 +51,7 @@ impl Default for Crucible {
|
||||
}
|
||||
impl Plugin for Crucible {
|
||||
const NAME: &'static str = "Crucible";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -33,7 +33,7 @@ impl Default for Lathe {
|
||||
}
|
||||
impl Plugin for Lathe {
|
||||
const NAME: &'static str = "Lathe";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -39,7 +39,7 @@ impl Default for Patina {
|
||||
}
|
||||
impl Plugin for Patina {
|
||||
const NAME: &'static str = "Patina";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -66,7 +66,7 @@ impl Default for Rivet {
|
||||
}
|
||||
impl Plugin for Rivet {
|
||||
const NAME: &'static str = "Rivet";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -31,7 +31,7 @@ impl Default for Temper {
|
||||
}
|
||||
impl Plugin for Temper {
|
||||
const NAME: &'static str = "Temper";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -31,7 +31,7 @@ impl Default for Weld {
|
||||
}
|
||||
impl Plugin for Weld {
|
||||
const NAME: &'static str = "Weld";
|
||||
const VENDOR: &'static str = "Rivet & Patina";
|
||||
const VENDOR: &'static str = "Bass Foundry";
|
||||
const URL: &'static str = "";
|
||||
const EMAIL: &'static str = "";
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -39,7 +39,7 @@ def package(target="x86_64-pc-windows-gnu", plugin=None, root=ROOT):
|
||||
f"See [{product['name']} guide]({product['documentation']}/README.md).\n"
|
||||
).encode()
|
||||
else:
|
||||
filename = "rivet-patina-windows-x86_64.zip"
|
||||
filename = "bass-foundry-windows-x86_64.zip"
|
||||
payload["README.md"] = (folder / "README.md").read_bytes()
|
||||
checksums = "".join(f"{hashlib.sha256(data).hexdigest()} {name}\n" for name, data in sorted(payload.items()))
|
||||
payload["SHA256SUMS"] = checksums.encode()
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ class Gitea:
|
||||
return self.fetch("GET", url)
|
||||
|
||||
def upload(self, release_id, path):
|
||||
boundary = "rivet-patina-" + uuid.uuid4().hex
|
||||
boundary = "bass-foundry-" + uuid.uuid4().hex
|
||||
body = (
|
||||
f"--{boundary}\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"{path.name}\"\r\n"
|
||||
"Content-Type: application/octet-stream\r\n\r\n"
|
||||
|
||||
Reference in new issue
Block a user