From d93dd942a88e36c3fbcbae9a0be04b527d7574cc Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Fri, 6 Nov 2026 16:05:19 +0100 Subject: [PATCH] feat(ballast): add Ballast switch-up leveller Ballast gives every part of a bassline one gain that brings it to the target loudness, with no compression inside a part. Parts start at note starts, detected from the audio or taken from MIDI, or on the host's beat grid, so a patch change on the same note counts too. - Loudness is K-weighted over each part's first 100 ms, in 10 ms blocks with a relative gate, and every part is weighted from rest so the last part does not ring into it. - The audio path is delayed by the tracker's lookahead, the window and a 5 ms glide, so each gain is in place on its part's first sample. - Learn takes the next part's loudness as the target. Amount, Range, Measure from (leave the sub out), Gate, Output, Bypass. - Editor shows the last 32 parts in and out, the target, and the spread of the last 16 parts. - Registered in the catalog, workflows, editor-check, README, chain and development docs, and the website copy. --- .gitea/workflows/check.yml | 4 +- .gitea/workflows/release.yml | 2 +- Cargo.lock | 19 + Cargo.toml | 4 +- README.md | 10 +- docs/ballast/CHANGELOG.md | 17 + docs/ballast/README.md | 80 + docs/ballast/assets/editor.png | Bin 0 -> 261735 bytes docs/chain.md | 15 +- docs/development.md | 6 +- docs/ideas.md | 19 +- plugins/ballast/core/Cargo.toml | 12 + plugins/ballast/core/src/lib.rs | 474 +++++ plugins/ballast/core/src/settings.rs | 133 ++ plugins/ballast/core/tests/dsp.rs | 332 ++++ plugins/ballast/core/tests/realtime.rs | 86 + plugins/ballast/plugin/Cargo.lock | 2381 ++++++++++++++++++++++++ plugins/ballast/plugin/Cargo.toml | 25 + plugins/ballast/plugin/src/lib.rs | 210 +++ plugins/ballast/plugin/src/params.rs | 203 ++ plugins/ballast/plugin/tests/host.rs | 216 +++ plugins/ballast/ui/Cargo.toml | 11 + plugins/ballast/ui/src/lib.rs | 376 ++++ plugins/catalog.json | 17 + tools/editor-check/Cargo.lock | 20 + tools/editor-check/Cargo.toml | 2 + tools/editor-check/src/main.rs | 48 +- website/src/data/plugins.ts | 15 + 28 files changed, 4716 insertions(+), 21 deletions(-) create mode 100644 docs/ballast/CHANGELOG.md create mode 100644 docs/ballast/README.md create mode 100644 docs/ballast/assets/editor.png create mode 100644 plugins/ballast/core/Cargo.toml create mode 100644 plugins/ballast/core/src/lib.rs create mode 100644 plugins/ballast/core/src/settings.rs create mode 100644 plugins/ballast/core/tests/dsp.rs create mode 100644 plugins/ballast/core/tests/realtime.rs create mode 100644 plugins/ballast/plugin/Cargo.lock create mode 100644 plugins/ballast/plugin/Cargo.toml create mode 100644 plugins/ballast/plugin/src/lib.rs create mode 100644 plugins/ballast/plugin/src/params.rs create mode 100644 plugins/ballast/plugin/tests/host.rs create mode 100644 plugins/ballast/ui/Cargo.toml create mode 100644 plugins/ballast/ui/src/lib.rs diff --git a/.gitea/workflows/check.yml b/.gitea/workflows/check.yml index 67956bd..37b0381 100644 --- a/.gitea/workflows/check.yml +++ b/.gitea/workflows/check.yml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - plugin: [rivet, patina, anvil, crucible, lathe, temper, weld, knurl, planish, braze, quench] + plugin: [rivet, patina, anvil, crucible, lathe, temper, weld, knurl, planish, braze, quench, ballast] steps: - uses: https://github.com/actions/checkout@v4 with: @@ -65,6 +65,7 @@ jobs: cargo run --manifest-path tools/editor-check/Cargo.toml --locked -- target/editor/planish.png --plugin planish cargo run --manifest-path tools/editor-check/Cargo.toml --locked -- target/editor/braze.png --plugin braze cargo run --manifest-path tools/editor-check/Cargo.toml --locked -- target/editor/quench.png --plugin quench + cargo run --manifest-path tools/editor-check/Cargo.toml --locked -- target/editor/ballast.png --plugin ballast - uses: https://github.com/actions/upload-artifact@v3-node20 with: name: editor-previews @@ -99,6 +100,7 @@ jobs: python3 scripts/build-plugin.py --plugin planish --target x86_64-pc-windows-gnu python3 scripts/build-plugin.py --plugin braze --target x86_64-pc-windows-gnu python3 scripts/build-plugin.py --plugin quench --target x86_64-pc-windows-gnu + python3 scripts/build-plugin.py --plugin ballast --target x86_64-pc-windows-gnu python3 scripts/package-windows.py - uses: https://github.com/actions/upload-artifact@v3-node20 with: diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index e2285ad..8c142f3 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,7 +1,7 @@ name: Independent plugin release on: push: - tags: ["rivet-v*", "patina-v*", "anvil-v*", "crucible-v*", "lathe-v*", "temper-v*", "weld-v*", "knurl-v*", "planish-v*", "braze-v*", "quench-v*"] + tags: ["rivet-v*", "patina-v*", "anvil-v*", "crucible-v*", "lathe-v*", "temper-v*", "weld-v*", "knurl-v*", "planish-v*", "braze-v*", "quench-v*", "ballast-v*"] permissions: contents: read diff --git a/Cargo.lock b/Cargo.lock index c229024..069d7e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,25 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "ballast-core" +version = "0.1.0" +dependencies = [ + "common-dsp", + "serde", + "serde_json", +] + +[[package]] +name = "ballast-ui" +version = "0.1.0" +dependencies = [ + "ballast-core", + "common-dsp", + "common-ui", + "egui", +] + [[package]] name = "bitflags" version = "2.13.2" diff --git a/Cargo.toml b/Cargo.toml index d23524d..9e666a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["plugins/common/ui", "plugins/common/dsp", "plugins/anvil/core", "plugins/anvil/ui", "plugins/lathe/core", "plugins/lathe/ui", "plugins/temper/core", "plugins/temper/ui", "plugins/weld/core", "plugins/weld/ui", "plugins/knurl/core", "plugins/knurl/ui", "plugins/planish/core", "plugins/planish/ui", "plugins/braze/core", "plugins/braze/ui", "plugins/quench/core", "plugins/quench/ui", "plugins/crucible/core", "plugins/crucible/ui", "plugins/rivet/core", "plugins/rivet/midi", "plugins/rivet/preview", "plugins/rivet/app", "plugins/patina/core", "plugins/patina/render", "plugins/patina/ui"] +members = ["plugins/common/ui", "plugins/common/dsp", "plugins/anvil/core", "plugins/anvil/ui", "plugins/lathe/core", "plugins/lathe/ui", "plugins/temper/core", "plugins/temper/ui", "plugins/weld/core", "plugins/weld/ui", "plugins/knurl/core", "plugins/knurl/ui", "plugins/planish/core", "plugins/planish/ui", "plugins/braze/core", "plugins/braze/ui", "plugins/quench/core", "plugins/quench/ui", "plugins/ballast/core", "plugins/ballast/ui", "plugins/crucible/core", "plugins/crucible/ui", "plugins/rivet/core", "plugins/rivet/midi", "plugins/rivet/preview", "plugins/rivet/app", "plugins/patina/core", "plugins/patina/render", "plugins/patina/ui"] exclude = ["plugins/rivet/plugin", "tools/editor-check", "plugins/patina/plugin", "plugins/anvil/plugin", "plugins/crucible/plugin", "plugins/lathe/plugin", "plugins/temper/plugin", "plugins/weld/plugin", "plugins/knurl/plugin", "plugins/planish/plugin"] [workspace.package] @@ -33,3 +33,5 @@ opt-level = 2 opt-level = 2 [profile.dev.package.quench-core] opt-level = 2 +[profile.dev.package.ballast-core] +opt-level = 2 diff --git a/README.md b/README.md index 10ec66d..94071b4 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,10 @@ note. Each plugin is a separate product with its own version, guide and release. | **[Planish](docs/planish/README.md)** | Upward and downward compression (OTT) in bands set by harmonic number: band 2 holds harmonics 2–4 on every note | Bass | ≈ 67 ms | [Guide](docs/planish/README.md) · [Changes](docs/planish/CHANGELOG.md) | | **[Braze](docs/braze/README.md)** | Adds a detuned copy whose beating stays on the tempo grid on every note: reese movement in time | Bass | ≈ 67 ms | [Guide](docs/braze/README.md) · [Changes](docs/braze/CHANGELOG.md) | | **[Quench](docs/quench/README.md)** | Clips the top as hard as you like while the sub passes clean: the low end keeps its level under a loud master | Master or bass bus, last | < 1 ms (oversampling) | [Guide](docs/quench/README.md) · [Changes](docs/quench/CHANGELOG.md) | +| **[Ballast](docs/ballast/README.md)** | Levels every note or switch-up to one loudness with a single gain each: no compression inside a part | Bass, after the sound design | ≈ 172 ms | [Guide](docs/ballast/README.md) · [Changes](docs/ballast/CHANGELOG.md) | Plugins with latency report it to the host, so FL Studio compensates the delay. -Anvil, Lathe, Temper, Knurl, Planish and Braze detect pitch from the audio. They can also take the +Anvil, Lathe, Temper, Knurl, Planish, Braze and Ballast detect notes from the audio. They can also take the pitch from MIDI. The order of the plugins matters: see [Signal chain](docs/chain.md). The names come from metalwork: a **rivet** joins pieces; **patina** changes a @@ -43,7 +44,7 @@ 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; **knurling** presses a ridged grip pattern into a surface; **planishing** hammers a surface smooth and even; **brazing** joins two metals with a filler; **quenching** hardens hot metal in one -fast step. +fast step; **ballast** is the weight that keeps a ship level. 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*. @@ -72,7 +73,7 @@ finished. Hosts list the plugins under the vendor name *Bass Foundry*. Quench editor
Quench: sub-safe clipper - + Ballast editor
Ballast: switch-up leveller @@ -132,7 +133,7 @@ cargo run --manifest-path tools/editor-check/Cargo.toml -- target/editor/lathe.p ``` Plugin names for the scripts are `rivet`, `patina`, `anvil`, `crucible`, -`lathe`, `temper`, `weld`, `knurl`, `planish`, `braze` and `quench`. Builds go to `dist//.clap`. No +`lathe`, `temper`, `weld`, `knurl`, `planish`, `braze`, `quench` and `ballast`. Builds go to `dist//.clap`. No script installs anything into a DAW. [Development and testing](docs/development.md) has the full command list. @@ -173,6 +174,7 @@ plugins/ planish/ core · ui · plugin braze/ core · ui · plugin quench/ core · ui · plugin + ballast/ core · ui · plugin common/ ui/ Shared look: palette, embedded fonts, knobs, panels, meters dsp/ Shared filters, pitch tracking, oversampling, meters, WAV files diff --git a/docs/ballast/CHANGELOG.md b/docs/ballast/CHANGELOG.md new file mode 100644 index 0000000..a046787 --- /dev/null +++ b/docs/ballast/CHANGELOG.md @@ -0,0 +1,17 @@ +# Ballast changelog + +## Unreleased (0.1.0) + +- Introduce Ballast, a switch-up leveller: every part of a bassline gets one + gain that brings it to the Target loudness. No compression inside a part. +- Parts start at note starts (detected from the audio, or from MIDI) or on the + host's beat grid, from 1 bar to 1/16. +- Loudness is K-weighted (ITU-R BS.1770) over each part's first 100 ms, in + 10 ms blocks with a relative gate, and each part is weighted from rest. +- The gain glides over 5 ms and is in place on the part's first sample. +- **Learn** takes the next part's loudness as the target. **Amount**, + **Range**, **Measure from** (leave the sub out of the measurement), **Gate**, + **Output**, **Bypass**. +- Editor: the last 32 parts, their loudness in and out, the target, and the + spread of the last 16 parts. +- About 172 ms of latency: the tracker's lookahead, the window and the glide. diff --git a/docs/ballast/README.md b/docs/ballast/README.md new file mode 100644 index 0000000..243e3c9 --- /dev/null +++ b/docs/ballast/README.md @@ -0,0 +1,80 @@ +# Ballast + +Ballast levels every note or switch-up of a bassline to one loudness, with a +single gain for each. Current version **0.1.0** (unreleased). + +Riddim and dubstep basslines change patch every few beats. Patches at the same +peak level still differ in how loud they sound, so each switch-up lands at a +different loudness and gets hand-set gain or clipping. A compressor would even +them out but also change their envelope and punch. Ballast measures each part's +loudness and gives the whole part one gain: inside a part nothing moves. + +![Ballast](assets/editor.png) + +## Install on Windows + +Copy `Ballast.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 Ballast in the mixer slot of the bass, after its sound +design. Keep the font license with redistributed packages. + +## Work with it + +1. Choose where a part starts with **Parts from**: + - **Notes**: every note start, detected from the audio, or from MIDI notes + sent to the effect (**Notes from**: AUDIO or MIDI). + - **Grid**: every line of the host's beat grid, from 1 bar to 1/16. Use it + when a switch-up changes the patch on the same note: the note tracker does + not see a new note there. +2. Play the bassline and press **LEARN** just before the switch-up that sits + right in the mix. Its loudness becomes the **Target**. You can also set + Target by hand. +3. Watch the display: one bar per part with its loudness as it came in, and a + mark where Ballast puts it. The marks line up on the target line. +4. Lower **Amount** to keep some of the differences: 50 % halves them. + +The panel shows the spread of the last 16 parts, in and out: the standard +deviation of their loudness in dB. In the editor preview four patches spread +by 7 dB come out within 0.4 dB; the rest is what Range left. + +Other controls: + +- **Range** is the most boost or cut a part gets. +- **Measure from**: the measurement hears only what is above this frequency; + the gain still applies to the whole signal. When Anvil makes the sub on the + bus, set it to Anvil's Split: Anvil replaces the sub anyway, so only the part + above it should decide the gain. +- **Gate** is the note-start threshold (Audio). A part quieter than the gate + keeps the last part's gain instead of being lifted, so rests and tails are + not pulled up. +- **Output** trims the level; **Bypass** crossfades to the delayed input. + +### How it measures + +A part's loudness is its K-weighted level (ITU-R BS.1770, the weighting behind +LUFS) over its first 100 ms, or over all of it when it is shorter. The level is +counted in 10 ms blocks, and blocks 20 dB under the part's loudest block are +left out. Each part is weighted from rest, as if it played alone, so the last +part's level does not ring into it. + +The gain glides to the new value over 5 ms and is in place on the part's first +sample, so the attack already has the new level. Later parts of a long note keep +that gain: Ballast does not follow the note's envelope. + +## Timing and limits + +Latency is the note tracker's lookahead (about 67 ms), the 100 ms measuring +window and the 5 ms glide, about 172 ms in all, reported to the host for delay +compensation. That is too much for playing live through Ballast: add it for the +mix. + +In Grid mode the grid follows the host's beat position while it plays and runs +on at the last tempo when it stops. A note start found by a change of pitch can +come about 20 ms early, inside the gap before the note; +the block gate keeps that gap out of the measurement. Two parts closer than +10 ms are merged. + +Ballast decides from the first 100 ms of a part. A patch that swells after +that, or a note whose loudness depends on what plays with it, is levelled by +its start only. It levels loudness, not brightness: two patches at the same +loudness can still differ in tone. diff --git a/docs/ballast/assets/editor.png b/docs/ballast/assets/editor.png new file mode 100644 index 0000000000000000000000000000000000000000..5f572db3b2b6361083a496549aa7017966d15769 GIT binary patch literal 261735 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
  • Q04o#`QB=IJ$UT@3G&tXUFeb{MTvQLdjw`O9Th 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

    cSc9>b;MMBFkki4 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 m1{X>3^i&qd7$WLjc*ZMRtw-is{GG#pix`. Builds tagged before this scheme used `io.storyboard.*` IDs; hosts treat the new IDs as different diff --git a/docs/ideas.md b/docs/ideas.md index 9f1e8fe..fa4caf8 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -263,8 +263,8 @@ one period of the note, so heavy settings do not ripple at f0. See [Planish](pla Patina already cut fixed formants on every note, but it also cut a boosted harmonic as hard (5.7 dB), at a position that moved with the note. Open: MIDI as the pitch source. -3. Planish (done, released 0.1.0), then Quench (done, unreleased) and Ballast: - they fill the mix and master gap. +3. Planish (done, released 0.1.0), then Quench and Ballast (both done, + unreleased): they fill the mix and master gap. - In parallel, from the research findings, in this order: Weld delay spread (done, Weld 0.3.0); the fatness lane, as the first Assay piece (prototype `scripts/fatness.py`); Anvil Ghost harmonics and Phone listen @@ -376,6 +376,21 @@ the same loudness without compression changing its character. Earlier working name: Hit Leveler. Pairs with Anvil: Anvil levels the sub, Ballast the whole patch. +Built (unreleased 0.1.0, see [Ballast](ballast/README.md)): one gain per part, +parts from note starts or the host grid (a patch change on the same note is not +a new note to the tracker), K-weighted loudness of the first 100 ms, Learn for +the reference. Found while building it: + +- A note start from a pitch change comes about 20 ms early, in the gap before + the note; a plain mean over the window then reads the part ~0.9 dB quiet. + Fixed with 10 ms blocks and a relative gate (−20 dB under the loudest block). +- The K-weighting filters ring the last part into the next one: a near-silent + part after a loud one read −18 LUFS instead of under −60. Fixed by weighting + every part from rest. +- Next ideas: a brightness match next to loudness (problem 2 names both; with + Lathe or Patina doing the EQ), a "follow" option for long notes that swell, + and switch-up detection from timbre change instead of the grid. + ### Bellows — pitch-tracked resonator A comb or Karplus-style resonator tuned to the detected note. It turns noise, diff --git a/plugins/ballast/core/Cargo.toml b/plugins/ballast/core/Cargo.toml new file mode 100644 index 0000000..9109f48 --- /dev/null +++ b/plugins/ballast/core/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ballast-core" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +[dependencies] +common-dsp = { path = "../../common/dsp" } +serde = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true } diff --git a/plugins/ballast/core/src/lib.rs b/plugins/ballast/core/src/lib.rs new file mode 100644 index 0000000..3066863 --- /dev/null +++ b/plugins/ballast/core/src/lib.rs @@ -0,0 +1,474 @@ +//! Levels each part of a bassline, a note or a step of the beat grid, to one loudness with a +//! single gain per part. No compression: the gain does not move inside a part, so a patch +//! keeps its own envelope and punch. +//! +//! A part's loudness is the K-weighted (ITU-R BS.1770) mean square of its first 100 ms, or +//! of all of it when it is shorter, counted in 10 ms blocks; blocks 20 dB under the loudest +//! one are left out, so a gap at the start does not pull the reading down. Each part is +//! weighted from rest, as if it played alone. The audio path is delayed by the note tracker's lookahead +//! plus that window plus a 5 ms ramp, so every part's gain is known before its attack leaves +//! the plugin, and the ramp to it ends exactly on the attack. +mod settings; +use common_dsp::loudness::{lufs, KWeighting}; +use common_dsp::svf::{Svf, SvfCoef}; +use common_dsp::tracker::{NoteEvent, Tracker, TrackerConfig}; +use common_dsp::{coefficient, db_to_gain, gain_to_db}; +pub use settings::{ + Grid, Segment, Settings, Source, FROM_MAX, FROM_MIN, RANGE_MAX, TARGET_MAX, TARGET_MIN, +}; + +/// Each part is measured over this much of its start. +pub const WINDOW_MS: f32 = 100.; +/// The gain glides to a new part's value over this long, ending on its first sample. +pub const RAMP_MS: f32 = 5.; +/// A boundary closer than this to the last one is ignored: the parts are merged. +const MIN_PART_MS: f32 = 10.; +/// The window is measured in blocks of this length. +const BLOCK_MS: f32 = 10.; +const BLOCKS: usize = (WINDOW_MS / BLOCK_MS) as usize; +/// Blocks this far under the part's loudest block do not count: a note start found by a +/// pitch change can come early, inside the gap before the note. +const RELATIVE_GATE_DB: f64 = 20.; +/// Parts shown in the editor. +pub const HISTORY: usize = 32; +/// Parts used for the spread readout. +const SPREAD: usize = 16; +const PENDING: usize = 32; +const Q: f32 = std::f32::consts::FRAC_1_SQRT_2; +/// Tempo the grid runs at before the host reports one. +const FALLBACK_BPM: f64 = 120.; + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Part { + /// Loudness of the part's measured start, in LUFS. + pub loudness: f32, + /// Gain given to the part, in dB. + pub gain: f32, + /// Under the gate: the part kept the previous gain. + pub gated: bool, +} + +#[derive(Clone, Copy, Debug)] +pub struct AnalyzerFrame { + /// Latest parts, oldest first; the first `count` entries are valid. + pub history: [Part; HISTORY], + pub count: usize, + /// Gain applied at the output right now, in dB. + pub gain: f32, + /// Standard deviation of the loudness of the last 16 parts over the gate, before and after + /// Ballast. NaN with fewer than two. + pub spread_in: f32, + pub spread_out: f32, + /// Waiting for the next part to take as the target. + pub learning: bool, + /// The loudness last taken by Learn, and a number that changes each time one is taken. + pub learned: f32, + pub learn_id: u32, + pub tempo: f64, + pub synced: bool, + pub latency: u32, + pub sample_rate: f32, +} +impl Default for AnalyzerFrame { + fn default() -> Self { + Self { + history: [Part::default(); HISTORY], + count: 0, + gain: 0., + spread_in: f32::NAN, + spread_out: f32::NAN, + learning: false, + learned: f32::NAN, + learn_id: 0, + tempo: FALLBACK_BPM, + synced: false, + latency: 0, + sample_rate: 48000., + } + } +} + +/// Gain in dB that brings `loudness` to the target, at `amount` (0–1), within ±`range`. +pub fn part_gain(loudness: f32, target: f32, amount: f32, range: f32) -> f32 { + ((target - loudness) * amount).clamp(-range, range) +} + +#[derive(Clone, Copy, Default)] +struct Pending { + start: u64, + gain: f32, +} + +pub struct Engine { + rate: f32, + channels: usize, + settings: Settings, + tracker: Tracker, + lookahead: usize, + window: usize, + ramp: usize, + min_part: usize, + delay: Vec<[f32; 2]>, + delay_at: usize, + weighting: [KWeighting; 2], + from: [[Svf; 2]; 2], + from_coef: SvfCoef, + /// Samples of the aligned stream: the input delayed by the tracker's lookahead. + clock: u64, + open: bool, + part_start: u64, + block: usize, + blocks: [(f64, usize); BLOCKS], + measured: usize, + last_gain: f32, + queue: [Pending; PENDING], + queue_head: usize, + queue_len: usize, + gain: f32, + ramp_from: f32, + ramp_to: f32, + ramp_left: usize, + history: [Part; HISTORY], + history_at: usize, + history_len: usize, + learn: bool, + learned: f32, + learn_id: u32, + tempo: f64, + /// Beat position of the aligned stream. + beats: f64, + synced: bool, + cell: i64, + output: f32, + bypass: f32, + smooth: f32, + fresh: bool, +} + +impl Engine { + pub fn new(rate: f32, channels: usize) -> Result { + if !(8000.0..=384000.).contains(&rate) { + return Err("unsupported sample rate"); + } + if !(1..=2).contains(&channels) { + return Err("unsupported channel count"); + } + let tracker = Tracker::new(rate, TrackerConfig::BASS); + let lookahead = tracker.latency(); + let samples = |ms: f32| ((rate * ms * 0.001).round() as usize).max(1); + let (window, ramp) = (samples(WINDOW_MS), samples(RAMP_MS)); + let mut e = Self { + rate, + channels, + settings: Settings::default(), + tracker, + lookahead, + window, + ramp, + min_part: samples(MIN_PART_MS), + delay: vec![[0.; 2]; lookahead + window + ramp + 1], + delay_at: 0, + weighting: [KWeighting::new(rate); 2], + from: [[Svf::default(); 2]; 2], + from_coef: SvfCoef::IDENTITY, + clock: 0, + open: false, + part_start: 0, + block: samples(BLOCK_MS), + blocks: [(0., 0); BLOCKS], + measured: 0, + last_gain: 0., + queue: [Pending::default(); PENDING], + queue_head: 0, + queue_len: 0, + gain: 1., + ramp_from: 1., + ramp_to: 1., + ramp_left: 0, + history: [Part::default(); HISTORY], + history_at: 0, + history_len: 0, + learn: false, + learned: f32::NAN, + learn_id: 0, + tempo: FALLBACK_BPM, + beats: 0., + synced: false, + cell: 0, + output: 1., + bypass: 0., + smooth: coefficient(rate, 10.), + fresh: true, + }; + e.set_settings(Settings::default())?; + e.fresh = true; + Ok(e) + } + /// Lookahead of the tracker, the measuring window and the ramp. + pub fn latency_samples(&self) -> u32 { + (self.lookahead + self.window + self.ramp) as u32 + } + pub fn channels(&self) -> usize { + self.channels + } + pub fn settings(&self) -> Settings { + self.settings + } + pub fn set_settings(&mut self, s: Settings) -> Result<(), &'static str> { + s.validate()?; + self.tracker.set(s.source == Source::Midi, s.gate, false); + if s.from != self.settings.from || self.fresh { + self.from_coef = if s.from > FROM_MIN { + SvfCoef::highpass(self.rate, s.from, Q) + } else { + SvfCoef::IDENTITY + }; + } + self.settings = s; + if std::mem::take(&mut self.fresh) { + self.output = db_to_gain(s.output); + self.bypass = f32::from(s.bypass); + } + Ok(()) + } + /// Host tempo in BPM and, while playing, the beat position at the block's first sample. + pub fn set_transport(&mut self, tempo: Option, position: Option) { + if let Some(t) = tempo.filter(|t| t.is_finite() && *t > 0.) { + self.tempo = t; + } + match position.filter(|p| p.is_finite()) { + Some(p) => { + // The parts are cut on the aligned stream, `lookahead` samples behind the input. + self.beats = p - self.lookahead as f64 / self.rate as f64 * self.tempo / 60.; + self.synced = true; + } + None => self.synced = false, + } + } + pub fn note_on(&mut self, note: u8) { + self.tracker.note_on(note); + } + pub fn note_off(&mut self, note: u8) { + self.tracker.note_off(note); + } + /// Takes the loudness of the next part over the gate as the new target. + pub fn learn(&mut self) { + self.learn = true; + } + pub fn reset(&mut self) { + self.tracker.reset(); + self.delay.fill([0.; 2]); + self.delay_at = 0; + for k in &mut self.weighting { + k.reset(); + } + self.from = [[Svf::default(); 2]; 2]; + self.clock = 0; + self.open = false; + self.blocks = [(0., 0); BLOCKS]; + self.measured = 0; + self.last_gain = 0.; + self.queue_len = 0; + self.gain = 1.; + self.ramp_left = 0; + self.history_len = 0; + self.learn = false; + self.fresh = true; + let s = self.settings; + let _ = self.set_settings(s); + } + + /// Mean square of the measured blocks, without those far under the loudest. + fn gated_mean(&self) -> f64 { + let used = self.measured.div_ceil(self.block).min(BLOCKS); + let blocks = &self.blocks[..used]; + let loudest = blocks + .iter() + .map(|(s, n)| s / (*n).max(1) as f64) + .fold(0., f64::max); + let floor = loudest * 10f64.powf(-RELATIVE_GATE_DB / 10.); + let (sum, n) = blocks + .iter() + .filter(|(s, n)| s / (*n).max(1) as f64 >= floor) + .fold((0., 0), |(a, b), (s, n)| (a + s, b + n)); + sum / n.max(1) as f64 + } + fn close(&mut self) { + self.open = false; + let s = self.settings; + let loudness = lufs(self.gated_mean()); + let gated = loudness < s.gate; + let gain = if gated { + self.last_gain + } else { + part_gain(loudness, s.target, s.amount * 0.01, s.range) + }; + if !gated { + self.last_gain = gain; + if std::mem::take(&mut self.learn) { + self.learned = loudness; + self.learn_id = self.learn_id.wrapping_add(1); + } + } + if self.queue_len < PENDING { + let at = (self.queue_head + self.queue_len) % PENDING; + self.queue[at] = Pending { + start: self.part_start, + gain, + }; + self.queue_len += 1; + } + self.history[self.history_at] = Part { + loudness, + gain, + gated, + }; + self.history_at = (self.history_at + 1) % HISTORY; + self.history_len = (self.history_len + 1).min(HISTORY); + } + + // Channels index the delayed frame, the filters and the output at once. + #[allow(clippy::needless_range_loop)] + pub fn process_sample(&mut self, x: [f32; 2]) -> [f32; 2] { + let mono = if self.channels == 2 { + 0.5 * (x[0] + x[1]) + } else { + x[0] + }; + let mut started = false; + self.tracker.process(mono, |e| { + if matches!(e, NoteEvent::Start { .. }) { + started = true; + } + }); + let len = self.delay.len(); + self.delay[self.delay_at] = x; + let aligned = self.delay[(self.delay_at + len - self.lookahead) % len]; + self.delay_at = (self.delay_at + 1) % len; + let delayed = self.delay[self.delay_at]; + + // Grid lines are counted on the aligned stream even in Notes mode, so switching modes + // does not cut a part. + let cell = (self.beats / self.settings.grid.quarters()).floor() as i64; + self.beats += self.tempo / 60. / self.rate as f64; + let crossed = cell != self.cell; + self.cell = cell; + let boundary = match self.settings.segment { + Segment::Notes => started, + Segment::Grid => crossed, + }; + + if boundary && !(self.open && self.measured < self.min_part) { + if self.open { + self.close(); + } + self.open = true; + self.part_start = self.clock; + self.blocks = [(0., 0); BLOCKS]; + self.measured = 0; + // Each part is weighted from rest, as if it played alone: the filters' memory of + // the last part would otherwise ring into this one. + for k in &mut self.weighting { + k.reset(); + } + self.from = [[Svf::default(); 2]; 2]; + } + let mut power = 0f64; + for c in 0..self.channels { + let f = &mut self.from[c]; + let v = f[0].process(&self.from_coef, aligned[c]); + let v = f[1].process(&self.from_coef, v); + let w = self.weighting[c].process(v) as f64; + power += w * w; + } + if self.open { + let b = &mut self.blocks[(self.measured / self.block).min(BLOCKS - 1)]; + b.0 += power; + b.1 += 1; + self.measured += 1; + if self.measured >= self.window { + self.close(); + } + } + // A part's ramp starts `ramp` samples before its first sample reaches the output. + if self.queue_len > 0 { + let next = self.queue[self.queue_head]; + if self.clock >= next.start + self.window as u64 { + self.queue_head = (self.queue_head + 1) % PENDING; + self.queue_len -= 1; + self.ramp_from = self.gain; + self.ramp_to = db_to_gain(next.gain); + self.ramp_left = self.ramp; + } + } + if self.ramp_left > 0 { + self.ramp_left -= 1; + let t = 1. - self.ramp_left as f32 / self.ramp as f32; + let t = t * t * (3. - 2. * t); + self.gain = self.ramp_from + (self.ramp_to - self.ramp_from) * t; + } + self.clock += 1; + + let s = self.settings; + self.output += (db_to_gain(s.output) - self.output) * self.smooth; + self.bypass += (f32::from(s.bypass) - self.bypass) * self.smooth; + if (f32::from(s.bypass) - self.bypass).abs() < 1e-6 { + self.bypass = f32::from(s.bypass); + } + let mut out = [0.; 2]; + for c in 0..self.channels { + let wet = delayed[c] * self.gain * self.output; + out[c] = if self.bypass >= 1. { + delayed[c] + } else { + wet + (delayed[c] - wet) * self.bypass + }; + } + out + } + + fn spread(&self, after: bool) -> f32 { + let (mut n, mut sum, mut sq) = (0usize, 0f64, 0f64); + for i in 0..self.history_len { + if n == SPREAD { + break; + } + let p = self.history[(self.history_at + HISTORY - 1 - i) % HISTORY]; + if p.gated { + continue; + } + let v = (p.loudness + if after { p.gain } else { 0. }) as f64; + n += 1; + sum += v; + sq += v * v; + } + if n < 2 { + return f32::NAN; + } + let mean = sum / n as f64; + ((sq / n as f64 - mean * mean).max(0.)).sqrt() as f32 + } + + /// Readings for the editor. Never allocates. + pub fn take_analyzer(&self) -> AnalyzerFrame { + let mut f = AnalyzerFrame { + count: self.history_len, + gain: gain_to_db(self.gain), + spread_in: self.spread(false), + spread_out: self.spread(true), + learning: self.learn, + learned: self.learned, + learn_id: self.learn_id, + tempo: self.tempo, + synced: self.synced, + latency: self.latency_samples(), + sample_rate: self.rate, + ..AnalyzerFrame::default() + }; + let first = (self.history_at + HISTORY - self.history_len) % HISTORY; + for i in 0..self.history_len { + f.history[i] = self.history[(first + i) % HISTORY]; + } + f + } +} diff --git a/plugins/ballast/core/src/settings.rs b/plugins/ballast/core/src/settings.rs new file mode 100644 index 0000000..89c74d2 --- /dev/null +++ b/plugins/ballast/core/src/settings.rs @@ -0,0 +1,133 @@ +//! Host-independent controls. Loudness in LUFS, gains in dB, amounts in percent. +use serde::{Deserialize, Serialize}; + +pub const TARGET_MIN: f32 = -40.; +pub const TARGET_MAX: f32 = 0.; +pub const RANGE_MAX: f32 = 24.; +/// Lowest frequency the measurement can start from. At or under this the measurement hears +/// the full band. +pub const FROM_MIN: f32 = 20.; +pub const FROM_MAX: f32 = 300.; + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] +pub enum Source { + /// Note starts are detected from the incoming bass. + #[default] + Audio, + /// Note starts come from MIDI note input. + Midi, +} + +/// Where one leveled part ends and the next begins. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] +pub enum Segment { + /// Every note start. + #[default] + Notes, + /// Every line of the host's beat grid, so a patch change on the same note counts too. + Grid, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] +pub enum Grid { + Bar, + Half, + #[default] + Quarter, + Eighth, + Sixteenth, +} +impl Grid { + pub const ALL: [Grid; 5] = [ + Grid::Bar, + Grid::Half, + Grid::Quarter, + Grid::Eighth, + Grid::Sixteenth, + ]; + /// Length in quarter notes. + pub fn quarters(self) -> f64 { + match self { + Grid::Bar => 4., + Grid::Half => 2., + Grid::Quarter => 1., + Grid::Eighth => 0.5, + Grid::Sixteenth => 0.25, + } + } + pub fn label(self) -> &'static str { + match self { + Grid::Bar => "1 BAR", + Grid::Half => "1/2", + Grid::Quarter => "1/4", + Grid::Eighth => "1/8", + Grid::Sixteenth => "1/16", + } + } +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct Settings { + pub source: Source, + pub segment: Segment, + pub grid: Grid, + /// Loudness every part should land at, measured over its first 100 ms. + pub target: f32, + /// Share of the correction that is applied. + pub amount: f32, + /// Most boost or cut, in dB. + pub range: f32, + /// The measurement hears only what is above this frequency; the gain still applies to + /// the full band. Set it to Anvil's Split when Anvil makes the sub. + pub from: f32, + /// Note-start threshold (Audio source), and the loudness under which a part keeps the + /// last gain instead of being lifted. + pub gate: f32, + pub output: f32, + pub bypass: bool, +} +impl Default for Settings { + fn default() -> Self { + Self { + source: Source::Audio, + segment: Segment::Notes, + grid: Grid::Quarter, + target: -14., + amount: 100., + range: 12., + from: FROM_MIN, + gate: -48., + output: 0., + bypass: false, + } + } +} +impl Settings { + pub fn validate(&self) -> Result<(), &'static str> { + let finite = [ + self.target, + self.amount, + self.range, + self.from, + self.gate, + self.output, + ] + .iter() + .all(|v| v.is_finite()); + if !finite { + return Err("non-finite setting"); + } + let ok = (TARGET_MIN..=TARGET_MAX).contains(&self.target) + && (0.0..=100.).contains(&self.amount) + && (0.0..=RANGE_MAX).contains(&self.range) + && (FROM_MIN..=FROM_MAX).contains(&self.from) + && (-60.0..=-20.).contains(&self.gate) + && (-12.0..=12.).contains(&self.output); + if ok { + Ok(()) + } else { + Err("setting out of range") + } + } +} diff --git a/plugins/ballast/core/tests/dsp.rs b/plugins/ballast/core/tests/dsp.rs new file mode 100644 index 0000000..19a59bb --- /dev/null +++ b/plugins/ballast/core/tests/dsp.rs @@ -0,0 +1,332 @@ +use ballast_core::{part_gain, Engine, Grid, Segment, Settings, Source, RAMP_MS, WINDOW_MS}; +use common_dsp::loudness::{lufs, KWeighting}; +use std::f64::consts::TAU; + +const RATE: f32 = 48000.; +const BPM: f64 = 120.; +/// One quarter at 120 BPM. +const QUARTER: usize = 24000; + +/// Two patches a switch-up might alternate: a loud saw and a quiet sine, an octave apart. +fn patch(i: usize, which: usize) -> f32 { + let t = i as f64 / RATE as f64; + if which.is_multiple_of(2) { + let phase = (55. * t).fract(); + (0.5 * (2. * phase - 1.)) as f32 + } else { + (0.1 * (TAU * 110. * t).sin()) as f32 + } +} +fn grid_engine(s: Settings) -> Engine { + let mut e = Engine::new(RATE, 2).unwrap(); + e.set_settings(Settings { + segment: Segment::Grid, + grid: Grid::Quarter, + ..s + }) + .unwrap(); + e +} +/// Runs `input` through the engine in 512-sample blocks with the transport playing from 0. +fn run(e: &mut Engine, input: &[f32]) -> Vec { + let mut out = Vec::with_capacity(input.len()); + for (i, &v) in input.iter().enumerate() { + if i % 512 == 0 { + e.set_transport(Some(BPM), Some(i as f64 / RATE as f64 * BPM / 60.)); + } + out.push(e.process_sample([v, v])[0]); + } + out +} +/// K-weighted loudness of both channels (the same signal) over `window` samples from `start`. +fn loudness(x: &[f32], start: usize, window: usize) -> f32 { + let mut k = KWeighting::new(RATE); + // Settle the filter on what came before, as the engine's own measurement does. + for &v in &x[start.saturating_sub(4800)..start] { + k.process(v); + } + let sum: f64 = x[start..start + window] + .iter() + .map(|&v| (k.process(v) as f64).powi(2)) + .sum(); + lufs(2. * sum / window as f64) +} +fn window() -> usize { + (RATE * WINDOW_MS * 0.001) as usize +} + +#[test] +fn every_part_lands_at_the_target() { + let target = -18.; + let mut e = grid_engine(Settings { + target, + ..Settings::default() + }); + let latency = e.latency_samples() as usize; + let parts = 10; + let input: Vec = (0..parts * QUARTER + latency) + .map(|i| patch(i, i / QUARTER)) + .collect(); + let out = run(&mut e, &input); + for p in 2..parts { + let start = p * QUARTER; + let before = loudness(&input, start, window()); + let after = loudness(&out, start + latency, window()); + assert!( + (after - target).abs() < 0.3, + "part {p}: {before:.1} → {after:.1}" + ); + } + let f = e.take_analyzer(); + assert!(f.spread_in > 5., "{}", f.spread_in); + assert!(f.spread_out < 0.1, "{}", f.spread_out); +} + +#[test] +fn the_gain_holds_still_inside_a_part_and_is_in_place_on_its_attack() { + let mut e = grid_engine(Settings { + target: -18., + ..Settings::default() + }); + let latency = e.latency_samples() as usize; + let ramp = (RATE * RAMP_MS * 0.001) as usize; + let input: Vec = (0..6 * QUARTER + latency) + .map(|i| patch(i, i / QUARTER) + 0.2) + .collect(); + let out = run(&mut e, &input); + for p in 2..5 { + let start = p * QUARTER; + assert!(input[start].abs() > 0.05); + let gain = out[start + latency] / input[start]; + for n in start..start + QUARTER - ramp { + if input[n].abs() < 0.05 { + continue; + } + let g = out[n + latency] / input[n]; + assert!( + (g / gain - 1.).abs() < 1e-4, + "part {p}, sample {n}: {g} vs {gain}" + ); + } + } +} + +#[test] +fn note_starts_from_the_audio_cut_the_parts() { + let target = -18.; + let mut e = Engine::new(RATE, 2).unwrap(); + e.set_settings(Settings { + target, + ..Settings::default() + }) + .unwrap(); + let latency = e.latency_samples() as usize; + // 300 ms notes with 100 ms gaps, alternating the two patches. + let note = 19200; + let input: Vec = (0..8 * note + latency) + .map(|i| { + if i % note < 14400 && i < 8 * note { + patch(i, i / note) + } else { + 0. + } + }) + .collect(); + let out = run(&mut e, &input); + let f = e.take_analyzer(); + let parts = f.history[..f.count].iter().filter(|p| !p.gated).count(); + assert_eq!(parts, 8, "{:?}", &f.history[..f.count]); + for n in 2..8 { + // The tracker finds the start a few milliseconds in; measure past that. + let start = n * note + 960; + let after = loudness(&out, start + latency, window()); + assert!((after - target).abs() < 0.5, "note {n}: {after:.1}"); + } +} + +#[test] +fn midi_note_starts_cut_legato_parts() { + let target = -18.; + let mut e = Engine::new(RATE, 2).unwrap(); + e.set_settings(Settings { + target, + source: Source::Midi, + ..Settings::default() + }) + .unwrap(); + let latency = e.latency_samples() as usize; + let note = QUARTER; + let mut out = Vec::new(); + let input: Vec = (0..6 * note + latency) + .map(|i| patch(i, i / note)) + .collect(); + for (i, &v) in input.iter().enumerate() { + if i % note == 0 { + // Legato: the new note starts before the old one ends, on the same pitch. + e.note_on(33); + if i > 0 { + e.note_off(33); + e.note_on(33); + } + } + out.push(e.process_sample([v, v])[0]); + } + for n in 2..6 { + let after = loudness(&out, n * note + latency, window()); + assert!((after - target).abs() < 0.3, "note {n}: {after:.1}"); + } +} + +#[test] +fn quiet_parts_keep_the_last_gain() { + let mut e = grid_engine(Settings { + target: -18., + gate: -40., + ..Settings::default() + }); + // A loud part, then a part far under the gate, then the loud patch again. The parts change + // on zero crossings of a 110 Hz sine, so no step rings into the quiet part. + let input: Vec = (0..4 * QUARTER) + .map(|i| { + let v = 0.5 * (TAU * 110. * i as f64 / RATE as f64).sin() as f32; + if i / QUARTER == 2 { + v * 0.001 + } else { + v + } + }) + .collect(); + run(&mut e, &input); + let f = e.take_analyzer(); + let parts = &f.history[..f.count]; + // The first part is the silence before the input reaches the measurement. + let quiet = 1 + parts[1..] + .iter() + .position(|p| p.gated) + .expect("a gated part"); + assert_eq!(parts[quiet].gain, parts[quiet - 1].gain); +} + +#[test] +fn amount_and_range_scale_the_correction() { + assert_eq!(part_gain(-10., -14., 1., 12.), -4.); + assert_eq!(part_gain(-10., -14., 0.5, 12.), -2.); + assert_eq!(part_gain(-40., -14., 1., 12.), 12.); + assert_eq!(part_gain(0., -14., 1., 6.), -6.); + let mut e = grid_engine(Settings { + target: -18., + amount: 50., + ..Settings::default() + }); + let input: Vec = (0..4 * QUARTER).map(|i| patch(i, i / QUARTER)).collect(); + run(&mut e, &input); + let f = e.take_analyzer(); + for p in &f.history[1..f.count] { + let full = -18. - p.loudness; + assert!((p.gain - 0.5 * full).abs() < 1e-3, "{p:?}"); + } +} + +#[test] +fn learn_takes_the_next_part_as_the_target() { + let mut e = grid_engine(Settings::default()); + let input: Vec = (0..3 * QUARTER).map(|i| patch(i, i / QUARTER)).collect(); + run(&mut e, &input[..QUARTER + 100]); + e.learn(); + assert!(e.take_analyzer().learning); + let before = e.take_analyzer().learn_id; + run(&mut e, &input[QUARTER + 100..]); + let f = e.take_analyzer(); + assert!(!f.learning); + assert_ne!(f.learn_id, before); + let taken = f.history[..f.count] + .iter() + .find(|p| p.loudness == f.learned) + .expect("learned a part's loudness"); + assert!(!taken.gated); +} + +#[test] +fn the_measurement_can_leave_out_the_sub() { + // The same top, once with a loud sub under it. + let top = |i: usize| (0.05 * (TAU * 1000. * i as f64 / RATE as f64).sin()) as f32; + let sub = |i: usize| (0.5 * (TAU * 50. * i as f64 / RATE as f64).sin()) as f32; + let gains = |from: f32| { + let mut e = grid_engine(Settings { + target: -24., + range: 24., + from, + ..Settings::default() + }); + let input: Vec = (0..4 * QUARTER) + .map(|i| { + top(i) + + if (i / QUARTER).is_multiple_of(2) { + sub(i) + } else { + 0. + } + }) + .collect(); + run(&mut e, &input); + let f = e.take_analyzer(); + let p = &f.history[..f.count]; + (p[p.len() - 2].gain - p[p.len() - 1].gain).abs() + }; + assert!(gains(20.) > 10.); + assert!(gains(200.) < 1., "{}", gains(200.)); +} + +#[test] +fn bypass_is_the_input_delayed_by_the_latency() { + let mut e = grid_engine(Settings { + bypass: true, + target: -30., + ..Settings::default() + }); + let latency = e.latency_samples() as usize; + let lookahead = latency - window() - (RATE * RAMP_MS * 0.001) as usize; + // The tracker's lookahead: two periods of 30 Hz and a margin, about 67 ms. + assert!((lookahead as f32 / RATE - 0.067).abs() < 0.005); + let input: Vec = (0..2 * QUARTER).map(|i| patch(i, i / QUARTER)).collect(); + let out = run(&mut e, &input); + for i in latency..input.len() { + assert_eq!(out[i], input[i - latency]); + } +} + +#[test] +fn settings_are_validated_and_serialise() { + assert!(Settings::default().validate().is_ok()); + for bad in [ + Settings { + target: 3., + ..Settings::default() + }, + Settings { + range: 30., + ..Settings::default() + }, + Settings { + from: 10., + ..Settings::default() + }, + Settings { + amount: f32::NAN, + ..Settings::default() + }, + ] { + assert!(bad.validate().is_err()); + assert!(Engine::new(RATE, 2).unwrap().set_settings(bad).is_err()); + } + let s = Settings { + segment: Segment::Grid, + grid: Grid::Eighth, + source: Source::Midi, + target: -9., + ..Settings::default() + }; + let json = serde_json::to_string(&s).unwrap(); + assert_eq!(serde_json::from_str::(&json).unwrap(), s); + assert!(serde_json::from_str::(r#"{"target":0,"oops":1}"#).is_err()); +} diff --git a/plugins/ballast/core/tests/realtime.rs b/plugins/ballast/core/tests/realtime.rs new file mode 100644 index 0000000..6e3bd81 --- /dev/null +++ b/plugins/ballast/core/tests/realtime.rs @@ -0,0 +1,86 @@ +use ballast_core::{Engine, Grid, Segment, Settings, Source}; +use std::{ + alloc::{GlobalAlloc, Layout, System}, + cell::Cell, +}; + +struct CheckedAllocator; +thread_local! { + static CHECK:Cell=const {Cell::new(false)}; + static OPERATIONS:Cell=const {Cell::new(0)}; +} +fn record() { + if CHECK.try_with(Cell::get).unwrap_or(false) { + let _ = OPERATIONS.try_with(|n| n.set(n.get() + 1)); + } +} +unsafe impl GlobalAlloc for CheckedAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + record(); + unsafe { System.alloc(layout) } + } + unsafe fn dealloc(&self, pointer: *mut u8, layout: Layout) { + record(); + unsafe { System.dealloc(pointer, layout) } + } + unsafe fn realloc(&self, pointer: *mut u8, layout: Layout, size: usize) -> *mut u8 { + record(); + unsafe { System.realloc(pointer, layout, size) } + } +} +#[global_allocator] +static ALLOCATOR: CheckedAllocator = CheckedAllocator; + +#[test] +fn processing_notes_settings_transport_and_analysis_do_not_allocate_or_free() { + let mut engine = Engine::new(48000., 2).unwrap(); + let mut settings = Settings::default(); + engine.set_settings(settings).unwrap(); + CHECK.with(|v| v.set(true)); + for i in 0..96000 { + if i % 512 == 0 { + let playing = (i / 24000) % 2 == 0; + engine.set_transport( + Some(140.), + playing.then_some(i as f64 / 48000. * 140. / 60.), + ); + } + if i % 4800 == 0 { + let step = i / 4800; + settings.segment = if step % 2 == 0 { + Segment::Grid + } else { + Segment::Notes + }; + settings.grid = Grid::ALL[step % Grid::ALL.len()]; + settings.source = if step % 4 < 2 { + Source::Audio + } else { + Source::Midi + }; + settings.from = 20. + 30. * (step % 5) as f32; + settings.bypass = step % 7 == 6; + engine.set_settings(settings).unwrap(); + engine.note_on(33 + (step % 12) as u8); + if step % 3 == 0 { + engine.learn(); + } + } + if i % 4800 == 2400 { + engine.note_off(33 + (i / 4800 % 12) as u8); + } + let t = i as f32 / 48000.; + let x = if (i / 2400) % 2 == 0 { + (std::f32::consts::TAU * 55. * t).sin() * 0.5 + } else { + 0. + }; + std::hint::black_box(engine.process_sample([x, -x])); + if i % 1600 == 0 { + std::hint::black_box(engine.take_analyzer()); + } + } + engine.reset(); + CHECK.with(|v| v.set(false)); + assert_eq!(OPERATIONS.with(Cell::get), 0); +} diff --git a/plugins/ballast/plugin/Cargo.lock b/plugins/ballast/plugin/Cargo.lock new file mode 100644 index 0000000..1100ec2 --- /dev/null +++ b/plugins/ballast/plugin/Cargo.lock @@ -0,0 +1,2381 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "addr2line" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e567177890eb1617b1f774005b66b26b2377afd138a2ca37aae7d8f0c81429d4" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "android-activity" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" +dependencies = [ + "android-properties", + "bitflags 2.13.2", + "cc", + "jni", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror 2.0.21", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "anymap3" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5dfbc6d8d2675589ccbe4d0fd61df2419075625f8c1a62325e718e2b0049f9" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atomic_float" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62af46d040ba9df09edc6528dae9d8e49f5f3e82f55b7d2ec31a733c38dbc49d" + +[[package]] +name = "atomic_refcell" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e4227379beff4205943696e6c3e0cd809bacdf3f0edd6e3dd153e2269571a4" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "backtrace" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f4220217f3288537b83684130f42fad43320b1c3b805f1910d683d52ded24f" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "ballast" +version = "0.1.0" +dependencies = [ + "ballast-core", + "ballast-ui", + "clap-sys", + "crossbeam-queue", + "nih_plug", + "nih_plug_egui", + "serde_json", +] + +[[package]] +name = "ballast-core" +version = "0.1.0" +dependencies = [ + "common-dsp", + "serde", +] + +[[package]] +name = "ballast-ui" +version = "0.1.0" +dependencies = [ + "ballast-core", + "common-dsp", + "common-ui", + "egui", +] + +[[package]] +name = "baseview" +version = "0.1.0" +source = "git+https://github.com/RustAudio/baseview.git?rev=9a0b42c09d712777b2edb4c5e0cb6baf21e988f0#9a0b42c09d712777b2edb4c5e0cb6baf21e988f0" +dependencies = [ + "cocoa", + "core-foundation", + "keyboard-types", + "nix", + "objc", + "raw-window-handle 0.5.2", + "uuid", + "winapi", + "x11", + "x11rb", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.13.2", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "cc" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff2a8126fff0f8c839080d619675a585e61720bb12d2baceae45769fd66f155" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "clap-sys" +version = "0.5.0" +source = "git+https://github.com/micahrj/clap-sys.git?rev=25d7f53fdb6363ad63fbd80049cb7a42a97ac156#25d7f53fdb6363ad63fbd80049cb7a42a97ac156" + +[[package]] +name = "clipboard-win" +version = "5.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052af7878466feccda12ba7a6a67d019d712f296809559b47c12c8cc196d3a9a" +dependencies = [ + "error-code", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics 0.22.3", + "foreign-types 0.3.2", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "combine" +version = "4.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "common-dsp" +version = "0.1.0" + +[[package]] +name = "common-ui" +version = "0.1.0" +dependencies = [ + "egui", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "copypasta" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6811e17f81fe246ef2bc553f76b6ee6ab41a694845df1d37e52a92b7bbd38a" +dependencies = [ + "clipboard-win", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "x11-clipboard", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "crossbeam" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71406cd8807725f7ac2f999a4cdd32e98f829fdf65f528343cebf945e41df1e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "deranged" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "ecolor" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "egui" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" +dependencies = [ + "ahash", + "bitflags 2.13.2", + "emath", + "epaint", + "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui-baseview" +version = "0.5.0" +source = "git+https://github.com/BillyDM/egui-baseview.git?rev=ec70c3fe6b2f070dcacbc22924431edbe24bd1c0#ec70c3fe6b2f070dcacbc22924431edbe24bd1c0" +dependencies = [ + "baseview", + "copypasta", + "egui", + "egui_glow", + "keyboard-types", + "log", + "open", + "raw-window-handle 0.5.2", + "thiserror 2.0.21", +] + +[[package]] +name = "egui_glow" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "910906e3f042ea6d2378ec12a6fd07698e14ddae68aed2d819ffe944a73aab9e" +dependencies = [ + "ahash", + "bytemuck", + "egui", + "glow", + "log", + "memoffset 0.9.1", + "profiling", + "wasm-bindgen", + "web-sys", + "winit", +] + +[[package]] +name = "emath" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "epaint" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "epaint_default_fonts", + "nohash-hasher", + "parking_lot", + "profiling", +] + +[[package]] +name = "epaint_default_fonts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7" + +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.6", + "windows-link", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "gimli" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1033caf0b349c518623b5396bfb2cf0bddf44f0306d543a250e5743297aafd10" + +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.21", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc09d2154098bbf4ef54eab6b117a3c24cbbffe94046b16ee6d6d4510584d3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "keyboard-types" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libredox" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" +dependencies = [ + "bitflags 2.13.2", + "libc", + "plain", + "redox_syscall 0.9.5", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "midi-consts" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2dd5c7f8aaf48a76e389068ab25ed80bdbc226b887f9013844c415698c9952" + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.2", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle 0.6.2", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "nih_log" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0cdb52ef79af48ae110401c883bdb9c15e0306a99ab6ecf18bc52068b668e54" +dependencies = [ + "atty", + "log", + "once_cell", + "termcolor", + "time", + "windows", +] + +[[package]] +name = "nih_plug" +version = "0.0.0" +source = "git+https://github.com/robbert-vdh/nih-plug.git?rev=de421011f41a6d10fc8c7a6084e4f4dee0143683#de421011f41a6d10fc8c7a6084e4f4dee0143683" +dependencies = [ + "anyhow", + "anymap3", + "atomic_float", + "atomic_refcell", + "backtrace", + "bitflags 1.3.2", + "cfg-if", + "clap-sys", + "core-foundation", + "crossbeam", + "libc", + "log", + "midi-consts", + "nih_log", + "nih_plug_derive", + "objc", + "parking_lot", + "raw-window-handle 0.5.2", + "serde", + "serde_json", + "widestring", + "windows", +] + +[[package]] +name = "nih_plug_derive" +version = "0.1.0" +source = "git+https://github.com/robbert-vdh/nih-plug.git?rev=de421011f41a6d10fc8c7a6084e4f4dee0143683#de421011f41a6d10fc8c7a6084e4f4dee0143683" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "nih_plug_egui" +version = "0.0.0" +source = "git+https://github.com/robbert-vdh/nih-plug.git?rev=de421011f41a6d10fc8c7a6084e4f4dee0143683#de421011f41a6d10fc8c7a6084e4f4dee0143683" +dependencies = [ + "baseview", + "crossbeam", + "egui-baseview", + "nih_plug", + "parking_lot", + "raw-window-handle 0.5.2", + "serde", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "num_threads" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabcc654086861f9e1bc5115258de62ef92c79b20f4615a1b0cc57c4e82027d4" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d5490aaf8f1d7cf7688dfa9b0ce07900e168852c45cd2c03f534dfd27cfd0b" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.2", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.13.2", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.13.2", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.2", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.13.2", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.13.2", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.13.2", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.13.2", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "object" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "open" +version = "5.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d8c8b8e725ad26404d6896eb2f064294a0a7b4f1d9120210d85544684c4ca95" +dependencies = [ + "is-wsl", + "libc", +] + +[[package]] +name = "orbclient" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.5.3", + "pin-project-lite", + "rustix 1.1.6", + "windows-sys 0.61.2", +] + +[[package]] +name = "powerfmt" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "redox_syscall" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "580c875845b41ecb1564ad1ae4703044cef774145e3d7a94dc2b3fa7c97868fd" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl 2.0.21", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tokio" +version = "1.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "toml_datetime" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.18+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec6e78bd70db9420d8d212fa9dc97f116448a1ceff5d00eabb991d407e21396" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0181c14ddd6c7b8b0b0132a5f1ea2f32be0d893cd3ea97b6e3b28886b8a3d1c" +dependencies = [ + "cfg-if", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e14e0327cb5368ad60ccb22d04a9827a693c95a926d8d125e9fa39e0baec501" +dependencies = [ + "js-sys", + "tokio", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e931a02a39abdbf66966fc35902b5ed58344750a70885bed4ebb3d8eaf28ed9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca4b54280e455bd831e33a6b8e734baf432fe63fbc35c42ac14ce67a043a53a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.9", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b1f9c3798725016c6ee5f2f57869ec0831e8bbc0ab0310a86e787e97f41389e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d179596ff5ec0f6de4db64d54011bde6289cc49603d3a6e4ce3f329207ab88" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winit" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" +dependencies = [ + "android-activity", + "atomic-waker", + "bitflags 2.13.2", + "block2", + "bytemuck", + "calloop", + "cfg_aliases", + "concurrent-queue", + "core-foundation", + "core-graphics 0.23.2", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle 0.6.2", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3b93199df0ab874cdf0c6a94f0a0dc3423fe41f1cafb62b8bd7b1deb277aef" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-clipboard" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3" +dependencies = [ + "libc", + "x11rb", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 1.1.6", + "x11rb-protocol", + "xcursor", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xcursor" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.13.2", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "zerocopy" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/plugins/ballast/plugin/Cargo.toml b/plugins/ballast/plugin/Cargo.toml new file mode 100644 index 0000000..fd108a5 --- /dev/null +++ b/plugins/ballast/plugin/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "ballast" +version = "0.1.0" +edition = "2021" +license = "ISC" + +[workspace] + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +nih_plug = { git = "https://github.com/robbert-vdh/nih-plug.git", rev = "de421011f41a6d10fc8c7a6084e4f4dee0143683", default-features = false } +nih_plug_egui = { git = "https://github.com/robbert-vdh/nih-plug.git", rev = "de421011f41a6d10fc8c7a6084e4f4dee0143683" } +ballast-core = { path = "../core" } +ballast-ui = { path = "../ui" } +crossbeam-queue = "0.3" + +[dev-dependencies] +clap-sys = { git = "https://github.com/micahrj/clap-sys.git", rev = "25d7f53fdb6363ad63fbd80049cb7a42a97ac156" } +serde_json = "1" + +[profile.release] +lto = "thin" +strip = "symbols" diff --git a/plugins/ballast/plugin/src/lib.rs b/plugins/ballast/plugin/src/lib.rs new file mode 100644 index 0000000..1a5018f --- /dev/null +++ b/plugins/ballast/plugin/src/lib.rs @@ -0,0 +1,210 @@ +//! CLAP audio effect. All DSP state is owned by the processing thread. +mod params; +use ballast_core::{AnalyzerFrame, Engine}; +use crossbeam_queue::ArrayQueue; +use nih_plug::prelude::*; +use nih_plug_egui::{create_egui_editor, egui}; +use params::{BallastParams, FLOATS}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + +struct Shared { + analyzer: ArrayQueue, + /// Set by the editor's Learn button, taken by the audio thread. + learn: AtomicBool, +} + +struct EditorData { + ui: ballast_ui::State, + gestures: [bool; FLOATS], +} +pub struct Ballast { + params: Arc, + shared: Arc, + engine: Option, + publish_count: usize, + publish_interval: usize, +} +impl Default for Ballast { + fn default() -> Self { + Self { + params: Arc::new(BallastParams::default()), + shared: Arc::new(Shared { + analyzer: ArrayQueue::new(2), + learn: AtomicBool::new(false), + }), + engine: None, + publish_count: 0, + publish_interval: 1600, + } + } +} +impl Plugin for Ballast { + const NAME: &'static str = "Ballast"; + const VENDOR: &'static str = "Bass Foundry"; + const URL: &'static str = ""; + const EMAIL: &'static str = ""; + const VERSION: &'static str = env!("CARGO_PKG_VERSION"); + const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[ + AudioIOLayout { + main_input_channels: NonZeroU32::new(2), + main_output_channels: NonZeroU32::new(2), + ..AudioIOLayout::const_default() + }, + AudioIOLayout { + main_input_channels: NonZeroU32::new(1), + main_output_channels: NonZeroU32::new(1), + ..AudioIOLayout::const_default() + }, + ]; + const MIDI_INPUT: MidiConfig = MidiConfig::Basic; + const SAMPLE_ACCURATE_AUTOMATION: bool = false; + type SysExMessage = (); + type BackgroundTask = (); + fn params(&self) -> Arc { + self.params.clone() + } + fn editor(&mut self, _: AsyncExecutor) -> Option> { + let params = self.params.clone(); + let shared = self.shared.clone(); + create_egui_editor( + params.editor.clone(), + EditorData { + ui: ballast_ui::State::default(), + gestures: [false; FLOATS], + }, + |ctx, _| ballast_ui::style(ctx), + move |ctx, setter, data| { + while let Some(frame) = shared.analyzer.pop() { + data.ui.accept_frame(frame); + } + let before = params.settings(); + let mut edited = before; + nih_plug_egui::resizable_window::ResizableWindow::new("ballast-editor") + .min_size(egui::vec2( + ballast_ui::WIDTH as f32 - 80., + ballast_ui::HEIGHT as f32 - 40., + )) + .show(ctx, ¶ms.editor, |ui| { + ballast_ui::show(ui, &mut edited, &mut data.ui) + }); + params.apply( + setter, + &before, + &edited, + data.ui.gesture_active, + &mut data.gestures, + ); + if std::mem::take(&mut data.ui.learn_request) { + shared.learn.store(true, Ordering::Release); + } + ctx.request_repaint_after(std::time::Duration::from_millis(40)); + }, + ) + } + fn initialize( + &mut self, + layout: &AudioIOLayout, + config: &BufferConfig, + context: &mut impl InitContext, + ) -> bool { + let Ok(mut engine) = Engine::new( + config.sample_rate, + layout.main_input_channels.map_or(0, |v| v.get() as usize), + ) else { + return false; + }; + let settings = self.params.settings(); + if engine.set_settings(settings).is_err() { + return false; + } + context.set_latency_samples(engine.latency_samples()); + self.publish_interval = (config.sample_rate / 30.) as usize; + self.engine = Some(engine); + true + } + fn reset(&mut self) { + if let Some(e) = self.engine.as_mut() { + e.reset(); + } + self.publish_count = 0; + } + fn process( + &mut self, + buffer: &mut Buffer, + _: &mut AuxiliaryBuffers, + context: &mut impl ProcessContext, + ) -> ProcessStatus { + let Some(engine) = self.engine.as_mut() else { + return ProcessStatus::Normal; + }; + let settings = self.params.settings(); + let _ = engine.set_settings(settings); + if self.shared.learn.swap(false, Ordering::AcqRel) { + engine.learn(); + } + let transport = context.transport(); + engine.set_transport( + transport.tempo, + if transport.playing { + transport.pos_beats() + } else { + None + }, + ); + let mut next = context.next_event(); + for (index, mut sample) in buffer.iter_samples().enumerate() { + while let Some(event) = next { + if event.timing() as usize > index { + break; + } + match event { + NoteEvent::NoteOn { note, velocity, .. } if velocity > 0. => { + engine.note_on(note) + } + NoteEvent::NoteOn { note, .. } | NoteEvent::NoteOff { note, .. } => { + engine.note_off(note) + } + NoteEvent::Choke { note, .. } => engine.note_off(note), + _ => {} + } + next = context.next_event(); + } + let x = [ + *sample.get_mut(0).unwrap(), + if engine.channels() == 2 { + *sample.get_mut(1).unwrap() + } else { + 0. + }, + ]; + let out = engine.process_sample(x); + for (c, value) in sample.into_iter().enumerate() { + *value = out[c]; + } + self.publish_count += 1; + if self.publish_count >= self.publish_interval { + let _ = self.shared.analyzer.force_push(engine.take_analyzer()); + self.publish_count = 0; + } + } + // The lookahead delay must drain after input stops. + ProcessStatus::KeepAlive + } +} +impl ClapPlugin for Ballast { + const CLAP_ID: &'static str = "io.narl.bass-foundry.ballast"; + const CLAP_DESCRIPTION: Option<&'static str> = + Some("Levels every note or switch-up to one loudness with a single gain each"); + const CLAP_MANUAL_URL: Option<&'static str> = None; + const CLAP_SUPPORT_URL: Option<&'static str> = None; + const CLAP_FEATURES: &'static [ClapFeature] = &[ + ClapFeature::AudioEffect, + ClapFeature::Utility, + ClapFeature::Stereo, + ClapFeature::Mono, + ]; +} +nih_export_clap!(Ballast); diff --git a/plugins/ballast/plugin/src/params.rs b/plugins/ballast/plugin/src/params.rs new file mode 100644 index 0000000..e999979 --- /dev/null +++ b/plugins/ballast/plugin/src/params.rs @@ -0,0 +1,203 @@ +use ballast_core::{ + Grid, Segment, Settings, Source, FROM_MAX, FROM_MIN, RANGE_MAX, TARGET_MAX, TARGET_MIN, +}; +use nih_plug::prelude::*; +use nih_plug_egui::EguiState; +use std::sync::Arc; + +#[derive(Enum, Debug, PartialEq, Eq, Clone, Copy)] +pub enum SourceParam { + #[id = "audio"] + Audio, + #[id = "midi"] + #[name = "MIDI"] + Midi, +} +#[derive(Enum, Debug, PartialEq, Eq, Clone, Copy)] +pub enum SegmentParam { + #[id = "notes"] + Notes, + #[id = "grid"] + Grid, +} +#[derive(Enum, Debug, PartialEq, Eq, Clone, Copy)] +pub enum GridParam { + #[id = "bar"] + #[name = "1 bar"] + Bar, + #[id = "1-2"] + #[name = "1/2"] + Half, + #[id = "1-4"] + #[name = "1/4"] + Quarter, + #[id = "1-8"] + #[name = "1/8"] + Eighth, + #[id = "1-16"] + #[name = "1/16"] + Sixteenth, +} +const GRIDS: [(GridParam, Grid); 5] = [ + (GridParam::Bar, Grid::Bar), + (GridParam::Half, Grid::Half), + (GridParam::Quarter, Grid::Quarter), + (GridParam::Eighth, Grid::Eighth), + (GridParam::Sixteenth, Grid::Sixteenth), +]; +fn grid_param(g: Grid) -> GridParam { + GRIDS + .iter() + .find(|(_, v)| *v == g) + .map_or(GridParam::Quarter, |(p, _)| *p) +} +fn linear(name: &str, v: f32, min: f32, max: f32, unit: &'static str) -> FloatParam { + FloatParam::new(name, v, FloatRange::Linear { min, max }).with_unit(unit) +} +/// Continuous controls, in the order of the gesture slots. +pub const FLOATS: usize = 6; + +#[derive(Params)] +pub struct BallastParams { + #[persist = "editor"] + pub editor: Arc, + #[id = "source"] + pub source: EnumParam, + #[id = "segment"] + pub segment: EnumParam, + #[id = "grid"] + pub grid: EnumParam, + #[id = "target"] + pub target: FloatParam, + #[id = "amount"] + pub amount: FloatParam, + #[id = "range"] + pub range: FloatParam, + #[id = "from"] + pub from: FloatParam, + #[id = "gate"] + pub gate: FloatParam, + #[id = "output"] + pub output: FloatParam, + #[id = "bypass"] + pub bypass: BoolParam, +} +impl Default for BallastParams { + fn default() -> Self { + let d = Settings::default(); + Self { + editor: EguiState::from_size(ballast_ui::WIDTH, ballast_ui::HEIGHT), + source: EnumParam::new("Note source", SourceParam::Audio), + segment: EnumParam::new("Parts from", SegmentParam::Notes), + grid: EnumParam::new("Grid", grid_param(d.grid)), + target: linear("Target", d.target, TARGET_MIN, TARGET_MAX, " LUFS"), + amount: linear("Amount", d.amount, 0., 100., " %"), + range: linear("Range", d.range, 0., RANGE_MAX, " dB"), + from: FloatParam::new( + "Measure from", + d.from, + FloatRange::Skewed { + min: FROM_MIN, + max: FROM_MAX, + factor: FloatRange::skew_factor(-1.), + }, + ) + .with_unit(" Hz"), + gate: linear("Gate", d.gate, -60., -20., " dB"), + output: linear("Output", d.output, -12., 12., " dB"), + bypass: BoolParam::new("Bypass", false).make_bypass(), + } + } +} +impl BallastParams { + pub fn settings(&self) -> Settings { + let grid = self.grid.value(); + Settings { + source: match self.source.value() { + SourceParam::Audio => Source::Audio, + SourceParam::Midi => Source::Midi, + }, + segment: match self.segment.value() { + SegmentParam::Notes => Segment::Notes, + SegmentParam::Grid => Segment::Grid, + }, + grid: GRIDS + .iter() + .find(|(p, _)| *p == grid) + .map_or(Grid::Quarter, |(_, g)| *g), + target: self.target.value(), + amount: self.amount.value(), + range: self.range.value(), + from: self.from.value(), + gate: self.gate.value(), + output: self.output.value(), + bypass: self.bypass.value(), + } + } + fn floats(&self) -> [&FloatParam; FLOATS] { + [ + &self.target, + &self.amount, + &self.range, + &self.from, + &self.gate, + &self.output, + ] + } + fn values(s: &Settings) -> [f32; FLOATS] { + [s.target, s.amount, s.range, s.from, s.gate, s.output] + } + /// Pushes every changed editor value to the host. Continuous controls hold one gesture + /// while the pointer is down; switches are set in a single gesture. + pub fn apply( + &self, + setter: &ParamSetter, + old: &Settings, + new: &Settings, + dragging: bool, + open: &mut [bool; FLOATS], + ) { + let pairs = Self::values(old).into_iter().zip(Self::values(new)); + for (i, (p, (a, b))) in self.floats().into_iter().zip(pairs).enumerate() { + if a != b { + if !open[i] { + open[i] = true; + setter.begin_set_parameter(p); + } + setter.set_parameter(p, b); + } + if !dragging && open[i] { + setter.end_set_parameter(p); + open[i] = false; + } + } + if new.bypass != old.bypass { + setter.begin_set_parameter(&self.bypass); + setter.set_parameter(&self.bypass, new.bypass); + setter.end_set_parameter(&self.bypass); + } + if new.source != old.source { + let v = match new.source { + Source::Audio => SourceParam::Audio, + Source::Midi => SourceParam::Midi, + }; + setter.begin_set_parameter(&self.source); + setter.set_parameter(&self.source, v); + setter.end_set_parameter(&self.source); + } + if new.segment != old.segment { + let v = match new.segment { + Segment::Notes => SegmentParam::Notes, + Segment::Grid => SegmentParam::Grid, + }; + setter.begin_set_parameter(&self.segment); + setter.set_parameter(&self.segment, v); + setter.end_set_parameter(&self.segment); + } + if new.grid != old.grid { + setter.begin_set_parameter(&self.grid); + setter.set_parameter(&self.grid, grid_param(new.grid)); + setter.end_set_parameter(&self.grid); + } + } +} diff --git a/plugins/ballast/plugin/tests/host.rs b/plugins/ballast/plugin/tests/host.rs new file mode 100644 index 0000000..036a98d --- /dev/null +++ b/plugins/ballast/plugin/tests/host.rs @@ -0,0 +1,216 @@ +//! Exercise the actual exported CLAP ABI without requiring a GUI or installed DAW. +use clap_sys::{ + audio_buffer::*, + events::*, + ext::{audio_ports::*, latency::*, state::*}, + factory::plugin_factory::*, + host::*, + process::*, + stream::*, + version::*, +}; +use std::{ + ffi::{c_char, c_void, CStr}, + io::{Cursor, Read}, + ptr, +}; + +unsafe extern "C" fn extension(_: *const clap_host, _: *const c_char) -> *const c_void { + ptr::null() +} +unsafe extern "C" fn request(_: *const clap_host) {} +unsafe extern "C" fn count(_: *const clap_input_events) -> u32 { + 0 +} +unsafe extern "C" fn event(_: *const clap_input_events, _: u32) -> *const clap_event_header { + ptr::null() +} +unsafe extern "C" fn push(_: *const clap_output_events, _: *const clap_event_header) -> bool { + true +} +unsafe extern "C" fn write(stream: *const clap_ostream, buffer: *const c_void, size: u64) -> i64 { + // SAFETY: The test owns the Vec for the entire synchronous save call. + let bytes = unsafe { &mut *((*stream).ctx as *mut Vec) }; + bytes.extend_from_slice(unsafe { + std::slice::from_raw_parts(buffer as *const u8, size as usize) + }); + size as i64 +} +unsafe extern "C" fn read(stream: *const clap_istream, buffer: *mut c_void, size: u64) -> i64 { + // SAFETY: The test owns the Cursor; the wrapper supplies writable stream storage. + let cursor = unsafe { &mut *((*stream).ctx as *mut Cursor>) }; + cursor + .read(unsafe { std::slice::from_raw_parts_mut(buffer as *mut u8, size as usize) }) + .unwrap() as i64 +} + +#[test] +fn effect_ports_state_latency_and_audio_lifecycle() { + // SAFETY: All callbacks, strings, streams, buffers, and the host outlive their + // synchronous ABI calls. Activation/processing/destruction follow CLAP order. + unsafe { + let entry = &ballast::clap_entry; + assert!(entry.init.unwrap()(c"ballast.clap".as_ptr())); + let factory = entry.get_factory.unwrap()(CLAP_PLUGIN_FACTORY_ID.as_ptr()) + as *const clap_plugin_factory; + assert!(!factory.is_null()); + let factory = &*factory; + assert_eq!(factory.get_plugin_count.unwrap()(factory), 1); + let descriptor = factory.get_plugin_descriptor.unwrap()(factory, 0); + assert!(!descriptor.is_null()); + assert_eq!(CStr::from_ptr((*descriptor).name), c"Ballast"); + assert_eq!( + CStr::from_ptr((*descriptor).id), + c"io.narl.bass-foundry.ballast" + ); + assert!(factory.get_plugin_descriptor.unwrap()(factory, 1).is_null()); + let host = clap_host { + clap_version: CLAP_VERSION, + host_data: ptr::null_mut(), + name: c"Storyboard test host".as_ptr(), + vendor: c"Tests".as_ptr(), + url: c"".as_ptr(), + version: c"1.0".as_ptr(), + get_extension: Some(extension), + request_restart: Some(request), + request_process: Some(request), + request_callback: Some(request), + }; + let plugin = factory.create_plugin.unwrap()(factory, &host, (*descriptor).id); + assert!(!plugin.is_null()); + let p = &*plugin; + assert!(p.init.unwrap()(plugin)); + let ports = p.get_extension.unwrap()(plugin, CLAP_EXT_AUDIO_PORTS.as_ptr()) + as *const clap_plugin_audio_ports; + assert!(!ports.is_null()); + assert_eq!((*ports).count.unwrap()(plugin, false), 1); + assert_eq!((*ports).count.unwrap()(plugin, true), 1); + let latency = p.get_extension.unwrap()(plugin, CLAP_EXT_LATENCY.as_ptr()) + as *const clap_plugin_latency; + assert!(!latency.is_null()); + let state = + p.get_extension.unwrap()(plugin, CLAP_EXT_STATE.as_ptr()) as *const clap_plugin_state; + assert!(!state.is_null()); + let state = &*state; + let save = || { + let mut bytes = Vec::new(); + let stream = clap_ostream { + ctx: &mut bytes as *mut Vec as *mut c_void, + write: Some(write), + }; + assert!(state.save.unwrap()(plugin, &stream)); + bytes + }; + let mut envelope: nih_plug::prelude::PluginState = + serde_json::from_slice(&save()[8..]).unwrap(); + use nih_plug::wrapper::state::ParamValue; + // Amount 0 passes the input through the lookahead delay unchanged. + envelope.params.insert("amount".into(), ParamValue::F32(0.)); + envelope + .params + .insert("target".into(), ParamValue::F32(-20.)); + envelope.params.insert("from".into(), ParamValue::F32(100.)); + envelope + .params + .insert("segment".into(), ParamValue::String("grid".into())); + envelope + .params + .insert("grid".into(), ParamValue::String("1-8".into())); + envelope + .params + .insert("source".into(), ParamValue::String("midi".into())); + let encoded = serde_json::to_vec(&envelope).unwrap(); + let mut framed = (encoded.len() as u64).to_le_bytes().to_vec(); + framed.extend_from_slice(&encoded); + let mut bytes = Cursor::new(framed); + let stream = clap_istream { + ctx: &mut bytes as *mut Cursor> as *mut c_void, + read: Some(read), + }; + assert!(state.load.unwrap()(plugin, &stream)); + let restored: nih_plug::prelude::PluginState = + serde_json::from_slice(&save()[8..]).unwrap(); + assert_eq!( + serde_json::to_value(&restored.params).unwrap(), + serde_json::to_value(&envelope.params).unwrap() + ); + for rate in [44100., 48000., 96000.] { + assert!(p.activate.unwrap()(plugin, rate, 1, 512)); + let delay = (*latency).get.unwrap()(plugin) as usize; + // The tracker's 67 ms, the 100 ms measuring window and the 5 ms ramp. + assert!((delay as f64 / rate - 0.172).abs() < 0.005, "{delay}"); + assert!(p.start_processing.unwrap()(plugin)); + let total = delay + 9600; + let mut position = 0; + let (mut energy_in, mut energy_out) = (0f64, 0f64); + while position < total { + let frames = [1, 127, 512, 31][position % 4].min(total - position); + // A 1 kHz tone at amount 0. + let tone = |n: usize| { + 0.25 * (std::f64::consts::TAU * 1000. * n as f64 / rate).sin() as f32 + }; + let mut input_left = [0f32; 512]; + let mut input_right = [0f32; 512]; + for i in 0..frames { + input_left[i] = tone(position + i); + input_right[i] = -tone(position + i); + } + let mut left = [0f32; 512]; + let mut right = [0f32; 512]; + let mut in_channels = [input_left.as_mut_ptr(), input_right.as_mut_ptr()]; + let mut out_channels = [left.as_mut_ptr(), right.as_mut_ptr()]; + let incoming = clap_audio_buffer { + data32: in_channels.as_mut_ptr(), + data64: ptr::null_mut(), + channel_count: 2, + latency: 0, + constant_mask: 0, + }; + let mut outgoing_audio = clap_audio_buffer { + data32: out_channels.as_mut_ptr(), + data64: ptr::null_mut(), + channel_count: 2, + latency: 0, + constant_mask: 0, + }; + let input = clap_input_events { + ctx: ptr::null_mut(), + size: Some(count), + get: Some(event), + }; + let outgoing = clap_output_events { + ctx: ptr::null_mut(), + try_push: Some(push), + }; + let process = clap_process { + steady_time: position as i64, + frames_count: frames as u32, + transport: ptr::null(), + audio_inputs: &incoming, + audio_outputs: &mut outgoing_audio, + audio_inputs_count: 1, + audio_outputs_count: 1, + in_events: &input, + out_events: &outgoing, + }; + assert_ne!(p.process.unwrap()(plugin, &process), CLAP_PROCESS_ERROR); + for i in 0..frames { + let n = position + i; + if n < delay { + assert!(left[i].abs() < 1e-6, "output before the lookahead"); + } else if n > delay + 4800 { + energy_in += (tone(n - delay) as f64).powi(2); + energy_out += (left[i] as f64).powi(2) + (right[i] as f64).powi(2); + } + } + position += frames; + } + let ratio_db = 10. * (energy_out / (2. * energy_in)).log10(); + assert!(ratio_db.abs() < 0.2, "{ratio_db}"); + p.stop_processing.unwrap()(plugin); + p.deactivate.unwrap()(plugin); + } + p.destroy.unwrap()(plugin); + entry.deinit.unwrap()(); + } +} diff --git a/plugins/ballast/ui/Cargo.toml b/plugins/ballast/ui/Cargo.toml new file mode 100644 index 0000000..3f7c519 --- /dev/null +++ b/plugins/ballast/ui/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ballast-ui" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +[dependencies] +egui = "0.31.1" +ballast-core = { path = "../core" } +common-ui = { path = "../../common/ui" } +common-dsp = { path = "../../common/dsp" } diff --git a/plugins/ballast/ui/src/lib.rs b/plugins/ballast/ui/src/lib.rs new file mode 100644 index 0000000..1862774 --- /dev/null +++ b/plugins/ballast/ui/src/lib.rs @@ -0,0 +1,376 @@ +//! Ballast editor, shared by the CLAP wrapper and the headless renderer. +use ballast_core::{ + AnalyzerFrame, Grid, Segment, Settings, Source, FROM_MAX, FROM_MIN, HISTORY, RANGE_MAX, + TARGET_MAX, TARGET_MIN, +}; +use common_ui::*; +use egui::{self, Color32, FontId, Pos2, Rect, RichText, Sense, Stroke, Vec2}; + +pub use common_ui::style; +pub const WIDTH: u32 = 980; +pub const HEIGHT: u32 = 660; + +pub struct State { + pub analyzer: AnalyzerFrame, + /// Set by the Learn button; the wrapper passes it to the engine and clears it. + pub learn_request: bool, + /// The last Learn result already applied. None until the first frame arrives, so an old + /// result is not applied again when the editor opens. + learn_seen: Option, + learned: Option, + /// True while a pointer button is held, so knob drags become one host gesture. + pub gesture_active: bool, + pub help: String, +} +impl Default for State { + fn default() -> Self { + Self { + analyzer: AnalyzerFrame::default(), + learn_request: false, + learn_seen: None, + learned: None, + gesture_active: false, + help: DEFAULT_HELP.into(), + } + } +} +const DEFAULT_HELP: &str = "Put Ballast on the bass after its sound design. Press LEARN on the \ + switch-up that sits right, or set Target."; +impl State { + pub fn accept_frame(&mut self, frame: AnalyzerFrame) { + match self.learn_seen { + Some(id) if id != frame.learn_id && frame.learned.is_finite() => { + self.learned = Some(frame.learned); + } + _ => {} + } + self.learn_seen = Some(frame.learn_id); + self.analyzer = frame; + } +} +fn hint(r: &egui::Response, state: &mut State, text: &str) { + if r.hovered() || r.has_focus() { + state.help = text.into(); + } +} +#[allow(clippy::too_many_arguments)] +fn knob( + ui: &mut egui::Ui, + state: &mut State, + name: &str, + value: &mut f32, + range: std::ops::RangeInclusive, + default: f32, + unit: &str, + help: &str, +) { + ui.vertical_centered(|ui| { + let r = rotary(ui, name, value, range, default, unit, 72., ACCENT); + hint(&r, state, help); + }); +} + +const LOW: f32 = -42.; +const HIGH: f32 = 0.; + +/// The last parts: their loudness in (bars), after Ballast (marks) and the target. +fn parts(ui: &mut egui::Ui, settings: &Settings, frame: &AnalyzerFrame, height: f32) { + let (rect, _) = ui.allocate_exact_size(Vec2::new(ui.available_width(), height), Sense::hover()); + let p = ui.painter_at(rect); + p.rect_filled(rect, 2., SCREEN); + p.text( + rect.left_top() + Vec2::new(10., 8.), + egui::Align2::LEFT_TOP, + format!("LAST {HISTORY} PARTS · LOUDNESS OF THE FIRST 100 MS"), + FontId::proportional(11.), + MUTED, + ); + p.text( + rect.right_top() + Vec2::new(-12., 8.), + egui::Align2::RIGHT_TOP, + "bar: in · mark: out", + FontId::proportional(11.), + MUTED, + ); + let area = Rect::from_min_max( + rect.left_top() + Vec2::new(44., 30.), + rect.right_bottom() - Vec2::new(12., 12.), + ); + let y = |lufs: f32| { + let t = ((lufs - LOW) / (HIGH - LOW)).clamp(0., 1.); + area.bottom() - t * area.height() + }; + for db in [-36., -24., -12., 0.] { + p.line_segment( + [ + Pos2::new(area.left(), y(db)), + Pos2::new(area.right(), y(db)), + ], + Stroke::new(1.0_f32, Color32::from_rgb(32, 35, 40)), + ); + p.text( + Pos2::new(area.left() - 6., y(db)), + egui::Align2::RIGHT_CENTER, + format!("{db:.0}"), + FontId::monospace(10.), + DIM, + ); + } + let column = area.width() / HISTORY as f32; + // Newest part on the right. + let offset = HISTORY - frame.count; + for i in 0..frame.count { + let part = frame.history[i]; + let x = area.left() + column * (offset + i) as f32; + let bar = Rect::from_min_max( + Pos2::new(x + column * 0.2, y(part.loudness)), + Pos2::new(x + column * 0.8, area.bottom()), + ); + let color = if part.gated { + DIM.gamma_multiply(0.6) + } else { + STEEL.gamma_multiply(0.45) + }; + p.rect_filled(bar, 1., color); + if !part.gated { + let out = y(part.loudness + part.gain); + p.line_segment( + [ + Pos2::new(x + column * 0.1, out), + Pos2::new(x + column * 0.9, out), + ], + Stroke::new(3.0_f32, ACCENT), + ); + } + } + let t = y(settings.target); + p.line_segment( + [Pos2::new(area.left(), t), Pos2::new(area.right(), t)], + Stroke::new(1.0_f32, ACCENT.gamma_multiply(0.5)), + ); + p.text( + Pos2::new(area.left() + 4., t - 3.), + egui::Align2::LEFT_BOTTOM, + format!("TARGET {:.1} LUFS", settings.target), + FontId::proportional(10.), + ACCENT, + ); + p.rect_stroke( + rect, + 2., + Stroke::new(1.0_f32, EDGE), + egui::StrokeKind::Inside, + ); +} + +pub fn show(ui: &mut egui::Ui, settings: &mut Settings, state: &mut State) { + backdrop(ui); + state.help = DEFAULT_HELP.into(); + state.gesture_active = ui.input(|i| i.pointer.any_down()); + if let Some(l) = state.learned.take() { + settings.target = l.clamp(TARGET_MIN, TARGET_MAX); + } + ui.add_space(2.); + header(ui, "BALLAST", "SWITCH-UP LEVELLER", |ui| { + let r = ui + .selectable_label(settings.bypass, RichText::new("BYPASS").size(13.)) + .on_hover_text("Crossfade to the delayed dry signal."); + if r.clicked() { + settings.bypass = !settings.bypass; + } + ui.separator(); + if settings.segment == Segment::Notes { + for (source, label) in [(Source::Midi, "MIDI"), (Source::Audio, "AUDIO")] { + let r = + ui.selectable_label(settings.source == source, RichText::new(label).size(13.)); + if r.clicked() { + settings.source = source; + } + } + caption(ui, "NOTES FROM"); + ui.separator(); + } + for (segment, label) in [(Segment::Grid, "GRID"), (Segment::Notes, "NOTES")] { + let r = + ui.selectable_label(settings.segment == segment, RichText::new(label).size(13.)); + if r.clicked() { + settings.segment = segment; + } + } + caption(ui, "PARTS FROM"); + }); + ui.add_space(6.); + let frame = state.analyzer; + ui.horizontal_top(|ui| { + panel(ui, |ui| { + ui.set_width(250.); + ui.set_min_height(TOP); + ui.vertical(|ui| readings(ui, settings, state, &frame)); + }); + ui.add_space(4.); + panel(ui, |ui| { + ui.set_width(ui.available_width()); + parts(ui, settings, &frame, TOP); + }); + }); + ui.add_space(6.); + panel(ui, |ui| { + ui.set_width(ui.available_width()); + ui.vertical(|ui| controls(ui, settings, state)); + }); + ui.separator(); + ui.label(RichText::new(&state.help).color(MUTED)); +} +const TOP: f32 = 300.; + +fn readings(ui: &mut egui::Ui, settings: &Settings, state: &mut State, frame: &AnalyzerFrame) { + caption(ui, "SPREAD OF THE LAST PARTS"); + let known = frame.spread_in.is_finite(); + ui.label( + RichText::new(if known { + format!("{:.1} · {:.1} dB", frame.spread_in, frame.spread_out) + } else { + "—".into() + }) + .font(FontId::new(34., egui::FontFamily::Name("medium".into()))) + .color(if known { TEXT } else { DIM }), + ); + ui.label( + RichText::new("in · out, standard deviation") + .size(12.) + .color(MUTED), + ); + ui.add_space(12.); + readout(ui, "GAIN NOW", format!("{:+.1} dB", frame.gain), ACCENT); + readout(ui, "TARGET", format!("{:.1} LUFS", settings.target), TEXT); + let label = if frame.learning || state.learn_request { + "LISTENING" + } else { + "LEARN" + }; + let r = ui.selectable_label( + frame.learning || state.learn_request, + RichText::new(label).size(13.), + ); + if r.clicked() { + state.learn_request = true; + } + hint( + &r, + state, + "Takes the loudness of the next part over the gate as the target. Press it just \ + before the switch-up that sits right in the mix.", + ); + ui.add_space(10.); + ui.label( + RichText::new(format!( + "{:.0} ms lookahead · {}", + frame.latency as f32 / frame.sample_rate.max(1.) * 1000., + match settings.segment { + Segment::Notes => match settings.source { + Source::Audio => "parts at detected notes".to_string(), + Source::Midi => "parts at MIDI notes".to_string(), + }, + Segment::Grid => format!( + "grid at {:.1} BPM, {}", + frame.tempo, + if frame.synced { + "host transport" + } else { + "free running" + } + ), + } + )) + .size(12.) + .color(MUTED), + ); +} + +fn controls(ui: &mut egui::Ui, settings: &mut Settings, state: &mut State) { + let d = Settings::default(); + if settings.segment == Segment::Grid { + ui.horizontal(|ui| { + caption(ui, "ONE PART EVERY"); + ui.add_space(6.); + for grid in Grid::ALL { + let r = ui + .selectable_label(settings.grid == grid, RichText::new(grid.label()).size(13.)); + if r.clicked() { + settings.grid = grid; + } + hint( + &r, + state, + "A new part starts on every line of this grid, also when the note does not \ + change.", + ); + } + }); + ui.add_space(8.); + ui.separator(); + } + ui.columns(6, |c| { + knob( + &mut c[0], + state, + "Target", + &mut settings.target, + TARGET_MIN..=TARGET_MAX, + d.target, + " LUFS", + "Loudness every part lands at, over its first 100 ms.", + ); + knob( + &mut c[1], + state, + "Amount", + &mut settings.amount, + 0. ..=100., + d.amount, + " %", + "Share of the correction. 50 % halves the differences between parts.", + ); + knob( + &mut c[2], + state, + "Range", + &mut settings.range, + 0. ..=RANGE_MAX, + d.range, + " dB", + "Most boost or cut a part gets.", + ); + knob( + &mut c[3], + state, + "Measure from", + &mut settings.from, + FROM_MIN..=FROM_MAX, + d.from, + " Hz", + "The measurement hears only what is above this. Set it to Anvil's Split when \ + Anvil makes the sub; the gain still applies to the whole signal.", + ); + knob( + &mut c[4], + state, + "Gate", + &mut settings.gate, + -60. ..=-20., + d.gate, + " dB", + "Note-start threshold, and the loudness under which a part keeps the last gain.", + ); + knob( + &mut c[5], + state, + "Output", + &mut settings.output, + -12. ..=12., + d.output, + " dB", + "Output trim.", + ); + }); +} diff --git a/plugins/catalog.json b/plugins/catalog.json index 9580817..e509775 100644 --- a/plugins/catalog.json +++ b/plugins/catalog.json @@ -182,5 +182,22 @@ "quench-core", "quench-ui" ] + }, + "ballast": { + "name": "Ballast", + "description": "Levels every note or switch-up to one loudness with a single gain each", + "manifest": "plugins/ballast/plugin/Cargo.toml", + "library": "ballast", + "documentation": "docs/ballast", + "clap_id": "io.narl.bass-foundry.ballast", + "licenses": { + "plugins/common/ui/assets/OFL.txt": "licenses/Roboto-OFL.txt" + }, + "packages": [ + "common-ui", + "common-dsp", + "ballast-core", + "ballast-ui" + ] } } diff --git a/tools/editor-check/Cargo.lock b/tools/editor-check/Cargo.lock index a97da10..d5f4398 100644 --- a/tools/editor-check/Cargo.lock +++ b/tools/editor-check/Cargo.lock @@ -60,6 +60,24 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "ballast-core" +version = "0.1.0" +dependencies = [ + "common-dsp", + "serde", +] + +[[package]] +name = "ballast-ui" +version = "0.1.0" +dependencies = [ + "ballast-core", + "common-dsp", + "common-ui", + "egui", +] + [[package]] name = "bitflags" version = "2.13.2" @@ -171,6 +189,8 @@ version = "0.1.0" dependencies = [ "anvil-core", "anvil-ui", + "ballast-core", + "ballast-ui", "braze-core", "braze-ui", "common-dsp", diff --git a/tools/editor-check/Cargo.toml b/tools/editor-check/Cargo.toml index 9986c3f..9b168ac 100644 --- a/tools/editor-check/Cargo.toml +++ b/tools/editor-check/Cargo.toml @@ -31,5 +31,7 @@ braze-core = { path = "../../plugins/braze/core" } braze-ui = { path = "../../plugins/braze/ui" } quench-core = { path = "../../plugins/quench/core" } quench-ui = { path = "../../plugins/quench/ui" } +ballast-core = { path = "../../plugins/ballast/core" } +ballast-ui = { path = "../../plugins/ballast/ui" } weld-core = { path = "../../plugins/weld/core" } weld-ui = { path = "../../plugins/weld/ui" } diff --git a/tools/editor-check/src/main.rs b/tools/editor-check/src/main.rs index 8fbff15..1e311b1 100644 --- a/tools/editor-check/src/main.rs +++ b/tools/editor-check/src/main.rs @@ -12,13 +12,13 @@ fn main() { .unwrap_or("rivet"); if ![ "rivet", "patina", "anvil", "crucible", "lathe", "temper", "weld", "knurl", "planish", - "braze", "quench", + "braze", "quench", "ballast", ] .contains(&plugin) { eprintln!( "Use --plugin rivet, patina, anvil, crucible, lathe, temper, weld, knurl, planish, \ - braze or quench" + braze, quench or ballast" ); std::process::exit(2); } @@ -33,7 +33,10 @@ fn main() { let planish = plugin == "planish"; let braze = plugin == "braze"; let quench = plugin == "quench"; - let (width, height) = if quench { + let ballast = plugin == "ballast"; + let (width, height) = if ballast { + (ballast_ui::WIDTH, ballast_ui::HEIGHT) + } else if quench { (quench_ui::WIDTH, quench_ui::HEIGHT) } else if braze { (braze_ui::WIDTH, braze_ui::HEIGHT) @@ -253,6 +256,37 @@ fn main() { } quench_state.accept_frame(engine.take_analyzer()); } + let mut ballast_settings = ballast_core::Settings { + segment: ballast_core::Segment::Grid, + target: -16., + ..Default::default() + }; + let mut ballast_state = ballast_ui::State::default(); + if ballast { + // A switch-up every quarter at 140 BPM, cycling four patches of different loudness. + let mut engine = ballast_core::Engine::new(48000., 2).unwrap(); + engine.set_settings(ballast_settings).unwrap(); + let mut saw = common_dsp::Saw::new(48000., 43.65); + let quarter = 48000. * 60. / 140.; + for i in 0..48000 * 9 { + if i % 512 == 0 { + engine.set_transport(Some(140.), Some(i as f64 / 48000. * 140. / 60.)); + } + let part = (i as f32 / quarter) as usize; + let s = saw.sample(); + let x = match part % 4 { + 0 => (s * 4.).tanh() * 0.6, + 1 => s * 0.15, + 2 => (s * 2.).tanh() * 0.35, + _ => (s * 8.).tanh() * 0.9, + }; + engine.process_sample([x, x]); + if i % 1600 == 0 { + ballast_state.accept_frame(engine.take_analyzer()); + } + } + ballast_state.accept_frame(engine.take_analyzer()); + } let mut weld_settings = weld_core::Settings::default(); let mut weld_state = weld_ui::State::default(); if weld { @@ -382,7 +416,9 @@ fn main() { let session_motif = session.motifs[0].id; shared.replace(session).unwrap(); let ctx = egui::Context::default(); - if quench { + if ballast { + ballast_ui::style(&ctx); + } else if quench { quench_ui::style(&ctx); } else if braze { braze_ui::style(&ctx); @@ -425,7 +461,9 @@ fn main() { }, |ui| { egui::CentralPanel::default().show(ui, |ui| { - if quench { + if ballast { + ballast_ui::show(ui, &mut ballast_settings, &mut ballast_state); + } else if quench { quench_ui::show(ui, &mut quench_settings, &mut quench_state); } else if braze { braze_ui::show(ui, &mut braze_settings, &mut braze_state); diff --git a/website/src/data/plugins.ts b/website/src/data/plugins.ts index 01dd806..e168e0c 100644 --- a/website/src/data/plugins.ts +++ b/website/src/data/plugins.ts @@ -214,6 +214,21 @@ const COPY: Record = { latency: '< 1 ms', tracksNotes: false, }, + ballast: { + role: 'Switch-up leveller', + metal: 'Ballast is the weight that keeps a ship level.', + problem: + 'Patches at the same peak level still sound louder or quieter, so every switch-up lands at a different loudness and gets hand-set gain or clipping. A compressor evens them out but changes their punch.', + points: [ + 'One gain per part: nothing moves inside a note or switch-up.', + 'Parts start at note starts, from the audio or MIDI, or on the host’s beat grid.', + 'Loudness is K-weighted (BS.1770) over each part’s first 100 ms; Learn takes a reference part.', + 'Measure from leaves the sub out of the measurement when Anvil makes it.', + ], + loadOn: 'Bass, after the sound design', + latency: '≈ 172 ms', + tracksNotes: true, + }, }; export interface Plugin extends Copy {