Signal-Flow Scripting Language for Music

Sorbis

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.

Interactive

Try Sorbis in your browser

Edit the program, then choose Compile + play. The parser and audio engine run locally in your browser.

Open full editor ↗

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, and sawtoothDown oscillators, plus phasor, random, and lfo;
  • 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-driven adsr, and one-shot multi-point env envelopes;
  • 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
00:00
0–10,000 Hz square-wave sweep

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
00:00
Amplitude-modulated telephone tone

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

FeatureCurrent implementation
Language front endC++ parser and code generator
DSP graphCompiled Cmajor
Native runtimecmaj::Performer
Browser runtimeWebAssembly, Web Audio, and AudioWorklet
File output48 kHz, 32-bit float WAV
LicensingAGPLv3-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.

If Sorbis is useful to you, you can support Wandersound's open-source work.

Donate using Liberapay