Building serious audio software requires making a set of architectural choices that will remain with a project for years. Digital signal processing code tends to outlive user interfaces, frameworks, and even the products in which it was originally written. A good oscillator, filter, dynamics processor, resampler, or modulation system may eventually appear in a synthesizer, an audio effect, a web application, a native plugin, a testing environment, or a completely different product.
That is the premise behind KahuStack DSP.
Rather than building DSP separately for every product, KahuStack DSP is being developed as a reusable audio-processing foundation for MANA Synth, Voxaliber, future KahuStack audio products, experimental processors, web applications, and potentially native plugin environments.
Three technologies are particularly important to that architecture:
Rust, WebAssembly, and Faust.
They each solve a different problem.
Rust provides the systems architecture.
Faust provides a specialized language for expressing DSP algorithms.
WebAssembly provides a portable execution target capable of bringing high-performance DSP into browsers and other sandboxed environments.
The interesting part is not any one of these technologies individually. The real advantage comes from using them together while keeping clear boundaries between their responsibilities.
The Basic KahuStack DSP Architecture
The emerging KahuStack DSP model can be summarized roughly as:
DSP mathematics → Faust and/or Rust implementation → Rust library architecture → WebAssembly/native compilation → applications and test environments
Faust is used where its declarative DSP model provides a meaningful advantage.
Rust is the primary integration and systems language.
WebAssembly is the primary portable deployment target, particularly for the web.
The same underlying library should remain usable by native hosts rather than becoming fundamentally dependent on browser technology.
This distinction is important.
KahuStack DSP is not intended to become a collection of unrelated Faust programs wrapped in JavaScript.
It is also not intended to become a massive Rust codebase in which every DSP primitive must be manually implemented even when a specialized DSP language would express it better.
Instead, we are creating a layered library where each technology is used where it is strongest.
Why Rust?
Rust is becoming the architectural center of KahuStack DSP.
That does not mean Rust necessarily needs to implement every sample-by-sample DSP algorithm. It means Rust provides the framework in which those algorithms live.
This distinction is one of the most important architectural decisions in the project.
Memory Safety Without a Garbage Collector
Audio processing is unusually sensitive to runtime behavior.
Real-time DSP cannot tolerate unpredictable pauses caused by garbage collection. An audio callback that stalls for even a few milliseconds can result in clicks, dropouts, or complete buffer underruns.
Traditionally, this has made C and C++ the dominant languages for professional audio development.
Rust offers something unusual: memory safety without requiring a garbage-collected runtime.
That provides many of the advantages associated with systems languages while eliminating entire categories of defects associated with unmanaged memory.
Rust’s ownership and borrowing system can prevent problems such as:
- use-after-free errors,
- dangling pointers,
- many race conditions,
- accidental shared mutation,
- double frees,
- unsafe lifetime relationships.
For a growing DSP library, this matters considerably.
A synthesizer with hundreds of voices, modulation connections, effect processors, buffers, worker systems, and state transitions can become extremely difficult to reason about in conventional C++.
Rust pushes many of those correctness constraints into the compiler.
Rust Makes Architectural Contracts Explicit
KahuStack DSP is increasingly interested in strongly typed representations of DSP concepts.
Audio software frequently represents very different quantities using the same primitive type:
440.0
0.5
48000.0
-12.0
120.0
Those values might mean:
440 Hz
0.5 linear gain
48,000 samples per second
-12 dB
120 BPM
To a floating-point number, they are all identical.
To an audio system, they are completely different concepts.
Rust is particularly well suited to building strongly typed domain APIs around quantities such as:
Frequency
SampleRate
Gain
Decibels
Pan
StereoWidth
Mix
Samples
Frames
Seconds
Milliseconds
Phase
Radians
Beats
Bars
Tempo
PPQ
This makes invalid operations harder to express.
Instead of relying on developer discipline to remember whether a parameter is normalized, logarithmic, measured in samples, or measured in seconds, the type system can represent that information directly.
This is already becoming an important design principle in KahuStack DSP.
Rust as the Library Layer
The larger advantage of Rust is not merely safer code.
It gives KahuStack DSP a coherent library architecture.
A professional DSP system needs considerably more than the processor itself.
It needs:
- parameter systems,
- state management,
- strongly typed units,
- modulation infrastructure,
- buffer abstractions,
- SIMD implementations,
- scheduling,
- processor graphs,
- presets,
- serialization,
- testing,
- benchmarking,
- host adapters,
- WebAssembly bindings,
- native bindings,
- metadata,
- documentation,
- processor manifests.
Rust can provide that infrastructure while individual DSP implementations remain replaceable.
A compressor implemented today can eventually be optimized without changing every application that consumes it.
A filter may begin as a conventional scalar implementation and later gain SIMD processing.
A Faust-generated processor may sit behind the same higher-level Rust API as a hand-written Rust implementation.
That separation is central to the long-term usefulness of the library.
The Drawbacks of Rust
Rust is not free of costs.
Rust Has a Significant Learning Curve
Ownership, borrowing, lifetimes, traits, generics, and concurrency rules introduce complexity.
Developers experienced in C++, JavaScript, or Python can initially find Rust slower to work with.
DSP development already requires understanding difficult topics such as numerical stability, real-time constraints, aliasing, and filter topology.
Adding a sophisticated type system increases the conceptual load.
Rust Can Encourage Over-Abstraction
Rust makes expressive type systems possible.
That does not mean every scalar needs to become a deeply generic abstraction.
Audio code must remain understandable.
It is possible to create architectures where the type system becomes more complicated than the DSP itself.
KahuStack therefore needs to use strong typing strategically.
Types such as Frequency, SampleRate, Pan, StereoWidth, and Mix provide real semantic protection.
Creating elaborate abstraction hierarchies around every internal multiplication probably does not.
Compile Times and Generic Complexity Can Grow
Large Rust projects can suffer from substantial compile times, particularly when extensive generics, procedural macros, code generation, and large dependency graphs are involved.
KahuStack DSP needs to keep crate boundaries intentional and avoid allowing the library to become monolithic.
The Native Audio Ecosystem Still Leans Heavily Toward C++
JUCE, decades of plugin examples, proprietary DSP SDKs, and many vendor libraries are still centered around C++.
Rust integration with native plugin ecosystems is improving, but using Rust may occasionally require interoperability layers that would not be necessary in an entirely C++ project.
That is a real engineering tradeoff.
Why WebAssembly?
WebAssembly addresses a different problem.
Rust helps us build the engine.
WebAssembly helps us deploy it.
The browser is increasingly important to KahuStack’s audio work.
MANA has already demonstrated why.
If a serious synthesizer can run directly in the browser, users can test it instantly without installing software. DSP research can include interactive demonstrations. QA environments can exercise processors visually and audibly. Educational material can contain real implementations rather than screenshots.
WebAssembly makes that possible without maintaining a completely separate JavaScript DSP implementation.
One DSP Engine, Multiple Environments
The ideal architecture is not:
Rust DSP
C++ DSP
JavaScript DSP
Browser DSP
Plugin DSP
with five implementations of the same algorithm.
The goal is closer to:
KahuStack DSP
|
Rust Library
/ \
WASM Native
| |
Browser Plugin / Host
This substantially reduces algorithm drift.
A filter validated in the web QA environment should be fundamentally the same filter used elsewhere.
A compressor should not behave differently simply because one implementation lives in JavaScript and another lives in a plugin.
WebAssembly provides the bridge that makes this architecture practical.
Why the Browser Matters for DSP Development
The browser is more than a deployment platform.
For KahuStack DSP, it can become a development instrument.
The current direction includes a lightweight Vite/React QA environment capable of exposing processors vertically.
A DSP module can eventually have:
- parameter controls,
- realtime audio input,
- file input,
- waveform views,
- spectrum analysis,
- transfer-function visualization,
- metering,
- automation testing,
- preset cases,
- impulse tests,
- sweeps,
- listening comparisons.
That gives each processor an interactive laboratory.
A developer implementing an allpass filter should be able to compile the library, open the test bench, route audio through it, automate its parameters, examine phase behavior, and listen to it immediately.
WebAssembly makes that experience possible while exercising production DSP rather than a JavaScript approximation.
WASM Performance
WebAssembly is particularly attractive for numerical workloads.
It supports:
- predictable linear memory,
- efficient numeric operations,
- SIMD,
- compact binaries,
- interoperability with Rust and C/C++,
- sandboxed execution,
- browser portability.
For many DSP workloads, carefully structured WASM can achieve performance sufficiently close to native code that the architecture becomes practical for sophisticated synthesis and effects.
That includes workloads involving:
- oscillators,
- filters,
- waveshaping,
- dynamics,
- modulation,
- FFT processing,
- convolution,
- voice processing,
- wavetable synthesis.
Performance still needs to be measured rather than assumed, but WASM is no longer limited to trivial web-audio demonstrations.
The Drawbacks of WebAssembly
WebAssembly also has important limitations.
The Browser Is Still a Constrained Environment
Native applications have more direct control over:
- audio devices,
- threads,
- memory,
- scheduling,
- SIMD capabilities,
- filesystem access,
- MIDI devices,
- plugin hosting,
- operating-system services.
The browser intentionally restricts many of those capabilities.
That is good for security but can complicate professional audio software.
Crossing the JavaScript/WASM Boundary Has Costs
Calling into WASM for every sample or tiny DSP operation would be a poor architecture.
Data should cross the boundary in relatively large, intentional units.
For example:
process audio block
is sensible.
Calling JavaScript → WASM for each individual sample is not.
This strongly influences API design.
AudioWorklet and Threading Require Careful Architecture
Web audio processing generally involves separate execution contexts.
Communication between the UI, workers, AudioWorklet, and WASM engine needs carefully designed messaging and shared-memory strategies.
Poor architecture can erase many of WASM’s performance advantages.
WASM Is Not the Product Architecture
This is another important distinction.
KahuStack DSP should not become architecturally dependent on WebAssembly.
WASM is a target.
The DSP library is the product.
Maintaining that distinction protects native portability.
Why Faust?
Faust addresses another layer entirely.
Faust is a domain-specific programming language designed specifically for real-time signal processing.
That matters because DSP contains recurring structures that general-purpose languages do not represent especially elegantly.
Consider a DSP algorithm such as:
input
→ filter
→ nonlinear stage
→ feedback path
→ output
In a conventional language, much of the implementation concerns state storage, buffer traversal, sample loops, and plumbing.
Faust allows the developer to describe the signal-processing relationship much more directly.
The compiler handles much of the lower-level implementation.
That makes Faust particularly attractive for a DSP research library.
Faust as Executable DSP Research
Academic DSP literature often describes algorithms mathematically.
Turning those equations into production C++, Rust, or WASM requires an additional translation step.
Faust reduces the distance between:
paper
and:
working audio processor
That makes it valuable for experimentation.
A paper describing a nonlinear filter, oscillator, compressor, physical model, or waveshaper can often be prototyped more quickly in Faust than by constructing all of the surrounding infrastructure manually.
That implementation can then become:
- an audible prototype,
- a reference implementation,
- a regression oracle,
- a generated production component,
- or the basis for a later hand-optimized implementation.
Faust’s Compiler Is Part of Its Value
Faust is not merely a scripting language.
The Faust compiler can transform DSP definitions into other implementation forms.
For KahuStack DSP, this creates an interesting possibility:
Faust DSP
↓
Generated implementation
↓
Rust integration
↓
WASM / native
This allows Faust to function as a specialized DSP authoring layer while Rust remains responsible for the larger system architecture.
That distinction prevents Faust from taking over responsibilities it was not designed to solve.
Where Faust Makes the Most Sense
Faust appears especially attractive for processor families such as:
- filters,
- equalizers,
- oscillators,
- saturation,
- distortion,
- dynamics,
- modulation effects,
- delay structures,
- reverberation,
- physical modeling,
- resonators,
- utility DSP.
It is also valuable when comparing multiple algorithms.
A research project examining five compressor topologies can implement them in a common DSP language and test them using the same surrounding infrastructure.
Where Faust Makes Less Sense
Not everything belongs in Faust.
Complex systems involving:
- preset management,
- voice allocation,
- dynamic graph construction,
- file management,
- sample streaming,
- large caches,
- worker coordination,
- UI state,
- MIDI routing,
- project serialization,
- asynchronous operations,
are generally better expressed in a systems language.
That is where Rust takes over.
The boundary might roughly look like:
Faust
---------------------
signal processing
sample state
filters
oscillators
nonlinearities
delays
DSP graphs
Rust
---------------------
processor lifecycle
strongly typed parameters
resource ownership
voice management
routing
host integration
serialization
threading
testing
WASM bindings
native bindings
The exact boundary can vary from processor to processor.
The Drawbacks of Faust
Faust introduces its own risks.
Generated Code Can Become a Black Box
Code generation is useful only when developers understand the resulting system.
A DSP library should not blindly trust generated artifacts.
Generated processors still need:
- validation,
- benchmarks,
- numerical tests,
- listening tests,
- documentation,
- version tracking.
Debugging Can Be Less Direct
Debugging handwritten Rust or C++ often means stepping directly through the implementation.
Generated code introduces another layer.
The bug may exist in:
- the Faust definition,
- generated code,
- bindings,
- build scripts,
- parameter conversion,
- host integration.
That makes tooling and documentation important.
Faust Is Another Language to Maintain
Every additional language increases project complexity.
Developers now need to understand:
Rust
Faust
JavaScript/TypeScript
WebAssembly behavior
and potentially C/C++ interoperability.
That cost needs to produce substantial value.
For simple processors, handwritten Rust may occasionally be clearer.
Generated Artifacts Can Drift
Code generation introduces a repository-management problem.
If generated source is committed, it can become stale.
If generated source is not committed, builds depend on having the correct generator available.
KahuStack DSP needs explicit policies around:
- generated artifacts,
- deterministic generation,
- generator versions,
- CI validation,
- source-of-truth files.
A generate:check style workflow is therefore valuable.
Why the Combination Is More Powerful Than Any One Technology
The architectural argument is ultimately not:
Rust vs. Faust vs. WebAssembly.
It is:
Rust + Faust + WebAssembly.
Each technology addresses a different layer.
| Layer | Primary technology |
|---|---|
| DSP research expression | Faust / Rust |
| Production library architecture | Rust |
| Strongly typed domain model | Rust |
| Generated DSP | Faust |
| Web deployment | WebAssembly |
| Browser UI | TypeScript / React |
| Native deployment | Rust/native interfaces |
| Testing and validation | Rust + browser QA |
| Research documentation | Markdown / web knowledge base |
This separation is intentional.
A Practical Example: Building a Filter
Consider a new analog-modeling filter.
Research may begin with an academic paper.
A Faust implementation can quickly reproduce the proposed signal structure.
The processor can then be compiled into the KahuStack DSP environment.
Rust provides typed controls:
Frequency
Resonance
Drive
Mix
SampleRate
rather than passing arbitrary floating-point values throughout the system.
The processor is exposed through a standardized Rust interface.
Tests measure:
- frequency response,
- resonance behavior,
- stability,
- modulation behavior,
- aliasing,
- nonlinear distortion.
The same implementation is compiled to WebAssembly.
The browser QA application provides:
- cutoff controls,
- resonance controls,
- drive,
- automation,
- spectrum display,
- transfer response,
- realtime audio input.
Once validated, that same DSP module can eventually be consumed by MANA or another application.
The research has moved through an intentional pipeline:
Research
↓
Algorithm
↓
Reference implementation
↓
Production DSP
↓
Validation
↓
Reusable library
↓
Product
That is considerably more valuable than implementing the same filter directly inside a synthesizer and leaving its knowledge buried there.
KahuStack DSP Is Becoming Infrastructure
This is perhaps the larger architectural point.
KahuStack DSP should not be thought of as a collection of effects.
It is infrastructure.
MANA needs:
- oscillators,
- filters,
- distortion,
- modulation,
- delays,
- reverbs,
- dynamics.
Vocal processing tools need:
- metering,
- filtering,
- dynamics,
- spectral analysis,
- restoration,
- leveling.
Future audio applications may need completely different combinations of the same primitives.
If every application reimplements these capabilities independently, development effort grows while consistency declines.
A shared library reverses that equation.
Every new processor potentially strengthens every future product.
Strongly Typed DSP Is Part of the Strategy
One of the more important recent directions in KahuStack DSP is the adoption of semantic DSP units.
Traditional DSP APIs commonly accept values like:
float cutoff
float gain
float pan
float time
The meaning of these values exists largely in documentation.
KahuStack is moving toward APIs where meaning exists in the type system:
Frequency
Decibels
LinearGain
Pan
StereoWidth
Mix
Seconds
Samples
SampleRate
Tempo
Beats
This becomes increasingly important as the library grows.
Time is particularly interesting because audio software operates in several simultaneous coordinate systems:
samples
frames
seconds
milliseconds
beats
bars
PPQ
host timeline positions
Confusing two of those can produce bugs that are difficult to diagnose.
A strongly typed architecture makes those mistakes harder to express in the first place.
Rust is particularly effective at supporting this design.
Real-Time Safety Remains the Final Authority
No language or framework automatically produces good DSP.
A Rust program can still allocate memory in the audio thread.
A Faust processor can still contain an unstable algorithm.
A WebAssembly processor can still miss its audio deadline.
Therefore KahuStack DSP needs to evaluate every implementation against real-time requirements.
That includes questions such as:
- Does processing allocate?
- Does it acquire locks?
- Is execution bounded?
- Can parameters change without clicking?
- Does the algorithm remain stable?
- Is the memory requirement predictable?
- Is SIMD actually improving performance?
- What happens under high polyphony?
- How does the processor behave at different sample rates?
- Does oversampling provide enough audible benefit to justify its cost?
Architecture assists these decisions.
It does not replace them.
The Importance of Vertical Testing
The accompanying QA test bench is an important part of this development model.
DSP should not be considered complete simply because it compiles.
Every processor should ultimately be testable vertically:
DSP source
↓
Rust interface
↓
WASM
↓
browser audio
↓
controls
↓
visualization
↓
measurement
↓
listening
This dramatically reduces the distance between implementation and evaluation.
It also makes research reproducible.
A future article explaining a compressor topology could eventually embed the actual KahuStack implementation and allow the reader to hear it.
That is an unusually powerful combination of documentation and software.
The Main Risks
There are legitimate reasons not to adopt this architecture.
The most important are complexity and fragmentation.
Using Rust, Faust, WebAssembly, TypeScript, generated code, native targets, and browser targets creates more moving parts than building a straightforward C++ plugin.
That means KahuStack must aggressively maintain boundaries.
The project needs:
- one canonical DSP library,
- clear source-of-truth rules,
- deterministic generation,
- small and understandable interfaces,
- processor manifests,
- permanent validation tests,
- coherent documentation,
- reproducible builds.
Without that discipline, the architecture could become more complicated than the products it is intended to support.
Why We Are Still Choosing This Direction
The reason to accept that complexity is leverage.
A conventional product architecture optimizes for shipping one application.
KahuStack DSP is optimizing for building an audio technology platform.
Rust gives us a robust systems foundation.
Faust gives us a concise and research-friendly DSP language.
WebAssembly lets that DSP run directly on the web without creating an entirely separate engine.
Together they allow us to pursue an architecture in which:
research becomes reusable code, reusable code becomes validated DSP infrastructure, and that infrastructure becomes available to multiple products and platforms.
That is the larger argument for the technology stack.
The goal is not to prove that Rust is better than C++, that Faust is better than handwritten DSP, or that WebAssembly is equivalent to every native environment.
Each technology has real drawbacks.
The argument is instead that their strengths align unusually well with what KahuStack DSP is trying to become: a portable, testable, strongly typed, research-driven DSP platform whose algorithms can move from academic literature to interactive browser experiments to serious production audio software without repeatedly starting over.
If we maintain disciplined boundaries between those layers, that is a substantial architectural advantage.
Leave a Reply