Skip to main content

Playground · app-grounded instrument

DSP · Audio

Agentic DSP Pipeline Step-Through

Record → retrieve → generate → verify → iterate. Click through AuraLinter’s real multi-agent loop: RAG over DSP textbooks (RBJ, Oppenheim, Smith), LangGraph codegen, and clang++ verification of the generated C++ biquad kernel.

Pipeline — LangGraph style

AuraLinter 5 nodes

• recorder (speech→text, WebAudio) → • retriever (DSP reference corpus) → • generator (C++/Metal codegen) → • verifier (clang++ -O2 + unit tests) → • summarizer + iterate on fail. Edges are conditional on verify PASS/FAIL. This playground simulates that loop client-side from deterministic fixtures; it runs no LLM, vector database, or compiler.

Select a node

idle

Click a node on the left or hit Run full loop.

The fixtures mirror AuraLinter’s node contracts: RBJ references, DF2T output, compiler flags, and a PASS/FAIL loop. The browser does not claim to execute the production retriever, model, or clang++ verifier; it renders disclosed example inputs and logs so the control flow can be inspected safely.

RAG retrieval (mock vector hits)

Generated C++

// LangGraph node: generate C++ biquad from retrieved context
// Prompt includes: userIntent + retrievedChunks + previousAttempts
std::array<double,5> designBiquadLowpass(double Fs, double f0, double Q){
  double w0 = 2*M_PI*f0/Fs;
  double alpha = sin(w0)/(2*Q);
  double b0=(1-cos(w0))/2, b1=1-cos(w0), b2=(1-cos(w0))/2;
  double a0=1+alpha, a1=-2*cos(w0), a2=1-alpha;
  return {b0/a0,b1/a0,b2/a0,a1/a0,a2/a0};
}

Sample output, fixed at build time — this page does not run a compiler.

Verification log

$ clang++ -O2 -std=c++20 -I./dsp -c biquad.cpp -o biquad.o
$ ./verify_biquad --freq 1000 --q 0.707 --fs 48000
[PASS] magnitude -3.01 dB @ fc (expected -3dB)
[PASS] stability: poles |p|=0.98 <1
[PASS] DF2T state bounded
 kernel accepted

Sample verification log, fixed at build time — nothing here executes.

What makes this agentic, not just a script

  • Retrieval is grounded: top-k cosine over 1200 chunks from RBJ, Oppenheim Discrete-Time DSP, Smith DSP Guide, and Biquadia's own Metal kernels. No hallucinated formulas — the prompt includes verbatim LaTeX.
  • Generation is constrained: system prompt says "You must output DF2T with state z1,z2, normalized a0=1, and pass stability |p|<1". Temperature 0.2.
  • Verification is real: in AuraLinter, we literally run clang++ -O2 -std=c++20 + a small harness that checks magnitude at f0 (−3 dB for lowpass, +gain for peaking) and pole radius. If FAIL, the graph loops back to generator with the compiler error appended. This playground simulates that log.
  • Why this matters: LLM alone hallucinates alpha=Q*sin(w0) (inverted). RAG + verification catches it — see the Hilbert 64-tap scenario where first attempt fails Parks-McClellan parity check and second attempt fixes it.

Anatomy of the pipeline

Five nodes, one conditional loop. Each node in the graph has a specific deterministic role — click through them to see the exact dataflow. Here is what each node is actually doing.

The five LangGraph nodes

  1. 01

    Record. Captures user intent. In production: Whisper tiny CoreML for on-device speech-to-text, running in-process with no network round-trip. This demo uses the dropdown to mock that stage. The output is a structured string: "Design biquad lowpass f0=1000Hz Q=0.707 Fs=48k".

  2. 02

    Retrieve. Embeds the user intent and queries a DSP reference corpus containing RBJ Cookbook equations, textbook sections, and Biquadia kernel comments. Relevant source excerpts are placed into the generator prompt with their provenance. Corpus size, embedding model, top-k, and threshold are versioned backend configuration—not benchmark claims made by this browser fixture.

  3. 03

    Generate. The codegen node constructs a prompt: system_preamble + retrieved_chunks + user_intent + previous_errors (if iterating). Temperature 0.2, max tokens 400. Output is C++ in Markdown code blocks, extracted via regex. The system prompt enforces DF2T form, normalized a0=1, and a pole stability comment.

  4. 04

    Verify. Writes the generated code to a temp file, runs clang++ -O2 -std=c++20, then executes a harness that checks: magnitude at f₀, pole radius (< 1), and DF2T state boundedness over 1000 frames. Output is PASS or FAIL with error details. For Hilbert, also checks antisymmetry and DC/Nyquist zeros.

  5. 05

    Iterate / Summarize. Conditional edge: if FAIL and iteration count < 3, route back to generator with error appended to the prompt. If PASS, package the accepted kernel + test report + source citations for the UI. Beyond 3 iterations, flag for human review to avoid token burn.

The interactive demo

  1. 01

    Graph visualization. An SVG with positioned node cards and directed edges. The verify→iterate edge goes forward always, and iterate→generate is the conditional loop-back (dashed line). Clicking a node shows its detail pane. The Run Full Loop button animates through all five nodes sequentially, then shows the Hilbert 1-iteration loop if that scenario is selected.

  2. 04

    Three deterministic scenarios. Lowpass and peaking pass on first attempt — the mock retrieval returns the correct RBJ lines, and the mock generator produces valid C++. Hilbert first outputs an even-length 64-tap FIR, the verifier catches the parity violation (non-zero at DC/Nyquist), and the loop-back produces a corrected 63-tap version on attempt 2. All data is pre-configured, no real LLM, fully deterministic.

The retriever uses cosine similarity, not keyword

sim(q,d)=qdqd\text{sim}(\mathbf{q}, \mathbf{d}) = \frac{\mathbf{q} \cdot \mathbf{d}}{\|\mathbf{q}\| \|\mathbf{d}\|}

The example ranks the RBJ cookbook ahead of broader textbook context for the lowpass request. Similarity values are intentionally omitted: fixture scores would look like benchmark data even though this browser page does not execute the production embedding model or vector index.

Gear behind this build

AuraLinter stack · 16 picks

Audio & DSP hardware16

More gear across every app: the full Gear list →

Two gotchas worth knowing

Temperature 0.2, not 0

Generation temperature is a deployment choice, not a quality guarantee. Lower values can make retries repeat the same answer; higher values can increase variation. AuraLinter’s backstop is therefore the verifier and bounded retry policy, not a claimed magic temperature. This deterministic browser fixture does not execute or benchmark a model.

Retrieval threshold matters

A permissive retrieval threshold can admit irrelevant excerpts; a strict one can return no useful context for a novel design. The production threshold must be selected against a versioned evaluation set and logged with the embedding model. This page shows ordering only and deliberately omits a made-up similarity score.

Frequently asked questions

Why not just ask an LLM directly for DSP code?

An LLM can produce a plausible but inverted DSP formula such as α = Q sin(ω₀) instead of α = sin(ω₀) / (2Q). That one-character difference changes the filter shape entirely. AuraLinter grounds generation in retrieved reference material, then uses a compiler and behavior harness as the acceptance boundary. We do not publish a failure-rate percentage without a versioned evaluation set.

Does retrieval really prevent hallucination?

Retrieval-Augmented Generation (RAG) places relevant reference text in the prompt, which reduces the need to recall a formula from model weights. It does not prove correctness. The compiler and DSP behavior harness remain mandatory, and a failed check routes the error back for another attempt or human review.

Can I use this for non-DSP code generation?

The architecture is domain-agnostic. Replace the Chroma vector store with your own domain's reference material (chip datasheets, API docs, mechanical spec sheets). Replace the clang++ verifier with whatever makes sense for your output — pytest for Python, shellcheck for bash, SPICE for circuits. The 5-node LangGraph loop (record, retrieve, generate, verify, iterate) is a general pattern for any domain where correctness matters and reference material exists.

Why use a compiler instead of just running the code?

Running DSP code checks one specific case. The compiler checks type correctness, symbol resolution, and semantic validity — errors that matter for Metal/CUDA deployment where a missing M_PI or double/float mismatch crashes the pipeline. The magnitude-at-f₀ check in the harness is just one of several tests: pole stability (|p| < 1), DF2T state boundedness over 1000 frames, and for Hilbert, antisymmetry and DC/Nyquist zeros. Together these catch bugs that running a single audio buffer would miss.

How many iterations does it typically take?

RBJ-based lowpass/peaking: 1 attempt (PASS on first try). Hilbert transformer with an even-length bias: 2 attempts — first gen outputs 64 taps, verifier catches parity violation at Nyquist, second gen fixes to 63 taps (4n+3). Beyond 3 iterations, AuraLinter flags for human review to avoid burning tokens on an unsolvable prompt. The Hilbert scenario in the dropdown above demonstrates the 1-iteration fail loop.

Shareable still

The instrument, captured—not illustrated.

This 16:9 frame is rendered from the real browser instrument above. It is the page's canonical preview for image search, link unfurls, and posts that need to show what the tool actually does.

Download 1280 × 720 JPEG
Agentic DSP Pipeline Step-Through — live MakerPortal instrument screenshot
Canonical capture · real UI · no generated scientific artwork