Sorbis is an experimental signal-flow language for composing sound with text. A Sorbis program connects oscillators, filters, envelopes, sequencers, spatial processors, and effects from left to right, then renders the result as audio or plays it directly in the browser.
The current engine parses Sorbis in C++, generates a compiled Cmajor signal graph, and runs that graph through the Cmajor performer. The native command-line renderer and browser editor share the same parser, syntax tree, and code generator.
Try Sorbis in your browser
Edit the program, then choose Compile + play. The parser and audio engine run locally in your browser.
How it works
Every chain begins with a node. Nodes are joined with >>, and the special
chain o sends the final mix to the output. Names beginning with ~ define
reusable signal or control chains.
// A four-note line with an event-driven envelope
bpm 120
~p: pitch 60 64 67 69
~r: rhythm 1 1 1 1
~mel: combine ~p ~r
~amp: adsr ~mel.note 0.01 0.1 0.7 0.2
~voice: sine ~mel.freq >> mul ~amp >> mul 0.4
o: mix ~voice
Sorbis references can address typed fields. A combine chain exposes
~name.freq for oscillator pitch and ~name.note for NoteOn/NoteOff
events. This keeps musical timing separate from the audio-rate signal path.
Signal flow and mixing
~dry: sawtoothUp 110 >> lowpass 1200 >> mul 0.25
~wet: mix ~dry >> delay 0.3 >> feedback 0.45 >> mul 0.3
o: mix ~dry ~wet >> limiter
Use mix to combine chains. A glob reference such as ~voice.. expands every
chain whose name begins with voice, in definition order. Commas and | are
treated as whitespace and // begins a comment.
Sound building blocks
The current Cmajor engine includes:
- anti-aliased
sine,triangle,square,sawtoothUp, andsawtoothDownoscillators, plusphasor,random, andlfo; - white, pink, and brown noise, FM and ring modulation, granular synthesis, and a triggered physical-model resonator;
- Cmajor low-pass and high-pass filters, delay, feedback, comb filtering, Zita reverb, and a stereo safety limiter;
asr, event-drivenadsr, and one-shot multi-pointenvenvelopes;- pitch, rhythm, tuplets, probability, MIDI CC input, named sections, arrangements, and crossfades; and
- stereo panning and binaural positioning.
One-shot breakpoint envelope
env alternates values and times in milliseconds, followed by a curve value.
It currently runs once from the start of the program. Use asr or adsr with
a .note event source for rhythm-triggered envelopes.
// Attack to 1 in 500 ms, decay to 0 over 4000 ms
~e: env 1 500 0 4000 0.75
~tone: sine 220 >> mul ~e
o: mix ~tone
Listen
Square-wave frequency sweep
~sweep: lfo triangle 0.1 5000 5000
~tone: square ~sweep >> mul 0.1
o: mix ~tone
Amplitude-modulated telephone tone
bpm 60
~p: pitch 72
~r: rhythm 1 -1
~telephone: combine ~p ~r
~amp: adsr ~telephone.note 0.1 0.1 1.0 0.05
~carrier: sine ~telephone.freq >> mul ~amp
~modulator: sine 30 >> mul 10
~am: mix ~carrier >> mul ~modulator
o: mix ~am >> mul 0.1
Native build
Install or mount a Cmajor release, then build Sorbis from its repository:
make
./sorbis examples/hello.sorbis hello.wav --duration 5
Sorbis renders 48 kHz, 32-bit floating-point WAV files. It can also emit the generated Cmajor source for inspection or further development:
./sorbis examples/hello.sorbis --emit-cmajor hello.cmajor
Project
| Feature | Current implementation |
|---|---|
| Language front end | C++ parser and code generator |
| DSP graph | Compiled Cmajor |
| Native runtime | cmaj::Performer |
| Browser runtime | WebAssembly, Web Audio, and AudioWorklet |
| File output | 48 kHz, 32-bit float WAV |
| Licensing | AGPLv3-or-later software / CC BY-NC-ND 4.0 documentation |
Source, full language reference, and build instructions on Codeberg.
The earlier Rust implementation remains available on the
legacy-v1 branch.