GlicolVerb - The Hard Part Was The UI
December 30, 2025I read a piece by Joan Westenberg a couple weeks ago — Thin Desires are Eating Your Life — that resonated with me. In particular, this quote lodged in my brain and I couldnt get it out:
“Build something that will never scale, never be monetized, never attract users.”
With that in mind, I built GlicolVerb this week. It’s a VST3/CLAP plugin that lets you write Glicol code in a text editor, click “Update”, and hear your guitar (or voice, keyboard, whatever) processed through whatever DSP chain you just described. Live-coding for guitar pedals, basically. The whole thing was a learning exercise: first time writing Rust for audio, first time building a VST plugin, first time poking around the Rust audio ecosystem to see what’s actually out there.
I went in expecting the hard part to be the audio processing. Real-time constraints! Buffer management! Sample rates! DSP math! Surely getting audio to flow through a plugin without crackling, dropping, or exploding would be the thing that ate all my time.
Turns out I was completely wrong about where the pain would be.
NIH-plug is excellent. Like, genuinely impressive. Here’s the entire Glicol engine wrapper - the thing that does the actual audio processing:
pub struct GlicolWrapper {
engine: Engine<128>, // 128-sample blocks
left_buffer: [f32; 128],
right_buffer: [f32; 128],
}
impl GlicolWrapper {
pub fn new(sample_rate: f32) -> Self {
let mut engine = Engine::<128>::new();
engine.set_sr(sample_rate as usize);
engine.update_with_code("out: ~input >> plate 0.5");
Self { engine, left_buffer: [0.0; 128], right_buffer: [0.0; 128] }
}
pub fn update_code(&mut self, code: &str) -> Result<(), String> {
self.engine.update_with_code(code);
Ok(())
}
} That’s it. Fifty lines for the whole file. Glicol’s update_with_code() hot-swaps your DSP graph
without audio glitches. NIH-plug handles parameter smoothing, buffer management, DAW integration.
Even writing a 3-band parametric EQ from scratch using biquad filters was less painful than
expected.
So where did the time go? Looking back at the commit history, about a third of commits (9 out of 28)
are UI-related. And not just small tweaks. Here’s the editor.rs changelog:
c801c13: src/editor.rs | 764 ++++++--- (509 insertions, 255 deletions)
"Add dark hardware theme and two-column layout"
1fac077: src/editor.rs | 649 ++++++--- (369 insertions, 293 deletions)
"Redesign UI with compact Effects Lab and fix state persistence"
dfb43b7: src/editor.rs | 324 +++++--- (281 insertions, 55 deletions)
"Improve UI layout and add new effect recipes" That’s over 1,700 lines of changes across just three commits. The UI file is 970 lines. The main plugin logic is 350. The entire DSP equalizer is 359 lines. The “simple” text editor became the central challenge. I made small tweaks myself to figure out what wasn’t working, and then had Claude Code rewrite entire sets of UI definition at once like when switching all the slider controls at once from one egui type to another. Huge time saver!
The culprit: getting text input and panel layout to work reliably inside a plugin window. The stack is egui (immediate-mode GUI) running on top of baseview (cross-platform windowing for plugin UIs). This combo is popular in the Rust audio world and mostly works. Except when it doesn’t. baseview has a known issue with keyboard handling in plugin hosts - the host intercepts key events in ways that mess with text input. Some DAWs work fine, others eat your keystrokes or send them twice. I ended up adding preset buttons as a workaround because you can’t always reliably type code. I spent an embarrising amount of time debugging before spotting the upstream issue..
Then there was a macOS crash. baseview had a bug that would crash the plugin on certain setups. There’s a fix in a PR that wasn’t merged yet, so I vendored a patched version. Had to figure out how to do that with Rust modules. Claude Code helped me with that. Had to fix submodule pointers when CI broke. Several commits just to keep the UI from crashing.
The irony isn’t lost on me. I wanted to learn about audio processing, and I did. But the lesson I didn’t expect was: the Rust audio ecosystem is surprisingly mature for the hard stuff, and surprisingly rough for the “easy” stuff. NIH-plug makes real-time audio accessible. Glicol makes DSP fun. But putting a text box on screen that works reliably in every DAW? That’s still an adventure. I suppose I shouldn’t be surprised, but I was. :)
Anyway, v0.1.2 is out. VST3 and CLAP
builds for macOS, Windows, and Linux. It works. I think? You can write out: ~input >> lpf 1000.0 1.0 >> plate 0.5 and hear your guitar through a low-pass filter into a plate reverb. The text input
is janky in some hosts but the presets get you most of the way there. It’s still hobby project
class software, but it works and makes me smile, which I wasn’t sure I should expect when I started!

Final thoughts. The journey was the point. Building is fun, and I’m having a blast using LLM tech to get from 0—>1 on a project and then deal with some of the tedious chores so I can spend my time reading about the Robert Bristow-Johnson cookbook formulas for EQ filters. Now I’m curious what else is hiding in the Rust audio world. I’m also now curious to try building something similar in JUCE, which I gather is by far the most popular choice for audio plugin development. C++. Good times!