MCPcopy Index your code
hub / github.com/Fredemus/va-filter

github.com/Fredemus/va-filter @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
129 symbols 280 edges 16 files 29 documented · 22%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

va-filter

Virtual analogue filters. implemented as a VST3 and Clap plugin in Rust, using Vizia for the GUI and nih-plug for all the plugin boilerplate stuff.

circuits

This plugin currently has 3 circuit models:

Transistor ladder filter

This is a 4-pole lowpass ladder filter loosely based on the ones found in Moog synthesizers. It distorts nicely and is capable of stable self-oscillation when k_ladder==4, and can output other slopes too.

Resonance is limited by the differential BJT buffers.

It converges very well, usually only taking 2 iterations, and almost never more than 4. Could just always do 2, especially when oversampled.

Circuit solved by applying KCL, finding the jacobian of the entire system and then applying newton's method.

State-variable filter

This is a 2-pole multimode filter loosely based on the one found in the edp wasp synthesizer. It's a good all-around filter that distorts nicely and keeps resonance well at high levels.

It's capable of outputting all basic filter modes (lowpass, highpass, bandpass, notch, etc.) and self-oscillation.

OTA core, nonlinear op-amp buffers. The EDP wasp uses inverters as a weird extremely nonlinear op-amp buffer, but I haven't looked into how to model that (in a way that converges well) yet. Resonance is limited by a diode clipper on the damping feedback, boosting it when gain is high, since it'd otherwise disappear because of the opamp nonlinearities, which would lead to the resonance completely dominating the signal.

Its convergence is generally good. The convergence gets a lot better when oversampled 2x or more, which I recommend anyway since it distorts.

Circuit solved by Holters & Zölzer's generalization of the DK-method. This method has a lot of advantages compared to the other approach, namely it's much better equipped for handling nonlinear voltage-controlled voltage sources such as op-amps and jacobian matrices are only necessary on a per-component basis, meaning it's not necessary to solve the whole system each iteration, speeding up iterations significantly. Special thanks to Martin Holters and his amazing circuit emulation tool ACME for the great work on circuit emulation and answering my questions when I got stuck.

The fast version is optimized by removing unnecessary operations and replacing the general solver with an analytic solution of the specific model. At some point I'll look into how a simd-optimized version would compare, since most of the operations are dot products anyway, but the current fast version is definitely fast enough for real-time use in DAW projects. Sadly convergence varies too much for using simd-lanes for processing left and right at the same time to bring a big performance benefit.

Sallen-key filter

This is a 2-pole lowpass filter loosely based on the one found in the second revision of the Korg MS20 synthesizer. It distorts really nicely and gets especially gnarly when resonance is high. My personal favorite.

It's able to self-oscillate and starts doing so when its resonance is above 0.8.

OTA core, nonlinear op-amp buffers. Resonance is limited by a diode clipper, but it disappears quite quickly at high drives.

Its convergence is generally good, but it does get a bit slower at high drives. The parameter vector for the nonlinear contributions is just 2 entries long, meaning that it might be reasonable to create a lookup table to guarantee stable, fast runtime. <- not as reasonable as I thought, also needs entries for g and res

Circuit solved by Holters & Zölzer's generalization of the DK-method.

The fast version is optimized by removing unnecessary operations and replacing the general solver with an analytic solution of the specific model. At some point I'll look into how a simd-optimized version would compare, since most of the operations are dot products anyway, but the current fast version is definitely fast enough for real-time use in DAW projects.

Build Instructions

The plugin uses simd operations which requires you to build it with nightly rust.

To build the plugin:

cargo +nightly xtask bundle -p va-filter --release

The plugin is then saved in the target/bundled folder

A standalone version can be run in jack:

cargo +nightly run --release

Extension points exported contracts — how you extend this code

AtomicOps (Interface)
use std::ops::{Sub, Add, Mul, Div}; [2 implementers]
src/utils.rs

Core symbols most depended-on inside this repo

get
called by 36
src/utils.rs
set_extrapolation_origin
called by 14
src/filter/solver.rs
eval_opamp
called by 14
src/filter/solver.rs
tanh_levien
called by 11
src/filter.rs
set
called by 11
src/utils.rs
set_lin_solver
called by 9
src/filter/solver.rs
set_p
called by 8
src/filter/solver.rs
set_jp
called by 8
src/filter/solver.rs

Shape

Method 78
Class 25
Function 20
Enum 5
Interface 1

Languages

Rust100%

Modules by API surface

src/filter/svf.rs16 symbols
src/filter/svf_old.rs14 symbols
src/filter/solver.rs14 symbols
src/filter/sallen_key.rs13 symbols
src/filter.rs13 symbols
src/ui.rs9 symbols
src/utils.rs8 symbols
src/lib.rs8 symbols
src/editor.rs8 symbols
src/ui/plot.rs7 symbols
src/filter_params.rs7 symbols
src/resampling.rs6 symbols

For agents

$ claude mcp add va-filter \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact