1
0
Fork
You've already forked motif
0
Programmable music composition engine — DSL, CLI renderer, and MCP server for AI-driven music generation
  • C 99.6%
  • Scheme 0.4%
Find a file
David Wilson ac06ab7166 Bump to 0.5.1; track sigil-audio ^0.12 and sigil-args ^0.16
The pins lagged current published sigil-audio (0.12) and sigil-args (0.16);
motif compiles and runs against both (verified via the Cinder desktop build).
Aligning them so a downstream consumer building against shipped deps gets a
consistent version graph.
2026年07月12日 15:33:53 +03:00
examples Sync examples/ directory with updated demo scripts 2026年04月02日 17:47:33 +03:00
src motif render: render-track-to-ogg as a normal define with cond-expand body 2026年07月12日 11:03:53 +03:00
test Add (motif presets) — curated cinder-cantata voice lookup 2026年04月18日 11:59:40 +03:00
.gitignore Add demo tracks, drum synthesis, step sequencer, and native C render loop 2026年04月02日 15:54:14 +03:00
dev-redirects.sgl Bump Motif for Sigil 0.15 2026年05月03日 10:29:38 +03:00
manifest.scm Add section transition system and new fill patterns 2026年04月03日 12:17:14 +03:00
package.sgl Bump to 0.5.1; track sigil-audio ^0.12 and sigil-args ^0.16 2026年07月12日 15:33:53 +03:00
README.md Parameterized synth construction + Karplus-Strong arp (v0.4.0) 2026年04月18日 17:01:12 +03:00
sigil.lock Regenerate lock against published 0.17 deps 2026年06月25日 15:47:06 +03:00

motif

A programmable music composition engine built in Sigil. Describe tracks using a DSL, render them to WAV files with a native C render loop.

Building

Requires a local checkout of sigil-dsp at ../sigil-dsp.

sigil deps install --redirects dev-redirects.sgl
sigil build --redirects dev-redirects.sgl

Rendering tracks

# List available tracks
./build/dev/bin/motif render
# Render a track to WAV
./build/dev/bin/motif render light-ambient -o light-ambient.wav
# Render with a shorter duration for testing
./build/dev/bin/motif render techno -d 30 -o test.wav

Example tracks

Five demo tracks in examples/ showcase different genres and motif features:

Track Duration Tempo Key Style
light-ambient 3 min 70 BPM C major Warm pad, bell melody, gentle kick+hihat pulse
dark-ambient 4 min 60 BPM C minor Sub-bass drone, dark pad, sparse bells
dnb 3 min 174 BPM F minor Syncopated breakbeat, reese bass, pad stabs
deep-house 4 min 122 BPM A minor Four-on-floor, sub-bass, warm pad, pluck melody
techno 3 min 135 BPM D minor Driving kick, 16th hihats, acid bass filter sweep

Each track demonstrates:

  • Song structure with sections (intro, build, drop, breakdown, outro)
  • Filter cutoff and volume automation across sections
  • Layer muting per section for arrangement
  • Multiple synth presets and drum synthesis

Architecture

DSP layer

Built on sigil-dsp (SoundPipe bindings): oscillators, filters, envelopes, reverb, delay, noise generators, dynamics.

Composition DSL

  • Tracks contain layers, each with a synth preset and pattern
  • Chord progressions drive melodic layers
  • Step sequencer drives drum layers with grid patterns
  • Sections define which layers are active and automate parameters
  • Synth presets: warm-pad, dark-pad, bright-pad, bell, sub-bass, reese-bass, acid-bass, pluck

Native C render loop

The per-sample DSP loop runs entirely in C for performance. Sigil builds a "render plan" (DSP objects + parameters), the C code processes it and writes WAV directly. A 3-minute track renders in under 90 seconds.

Synth Presets

Curated, named voice presets for the seven cinder-cantata design-doc §7 voice families. Each preset bundles a target voice, the underlying synth (or drum) graph, and a short description.

(import (motif presets))
(synth-presets) ;; => (kick snare hi-hat bass lead pad arp)
(let ((p (synth-preset 'kick)))
 (preset-name p) ;; => kick
 (preset-kind p) ;; => drum
 (preset-synth p) ;; => "kick" (drum-track name)
 (preset-description p)) ;; => "Deep sub sine with fast ..."
(let* ((p (synth-preset 'pad))
 (pad-pattern (make-sustained-chord 'c3 'minor 32)))
 (layer name: "pad"
 synth: (preset-synth p) ;; 'warm-pad
 pattern: pad-pattern
 volume: (preset-suggested-volume p)))
Preset Kind Underlying voice Sonic target
kick drum "kick" Deep sub + fast pitch-sweep click
snare drum "snare" 200Hz sine body + highpassed noise
hi-hat drum "hat" Highpassed noise, 40ms decay
bass melodic 'reese-bass Detuned saws through a Moog low-pass
lead melodic 'bell FM bell, 1.5s decay
pad melodic 'warm-pad Detuned saws, Moog LP, long attack
arp melodic 'karplus-strong Plucked string (feedback-delay physical model)

Audition all seven presets back-to-back (one 4-beat window each):

motif render presets-demo -o /tmp/motif-presets.ogg

Tuning a preset

v0.4 makes each melodic preset a parameter bundle rather than a hard-coded graph. preset-params returns the defaults the preset was tuned against; you can override individual knobs and thread the result back into layer synth: via preset-voice-spec:

(import (motif presets) (motif synth))
(let* ((p (synth-preset 'pad))
 (tuned (alist-set (preset-params p) 'cutoff 1200.0))
 (voice (preset-voice-spec p tuned)))
 (layer name: "pad"
 synth: voice ;; carries kind + params
 pattern: my-pad-prog
 volume: (preset-suggested-volume p)))

The layer API still accepts a bare kind symbol (synth: 'warm-pad) — that continues to work unchanged and uses the preset's defaults.

The full parameter surface per kind is whatever (synth-default-params kind) returns; (synth-kinds) lists every registered kind. Under the hood every kind is a thin wrapper over (make-synth-graph kind params), so (motif synth) graph builders are now composable data rather than fixed code.

See folio topics/motif-cantata-synth-presets for the voice-family rationale and folio topics/motif-synth-parameterized-construction for the parameter-bundle design.

Karplus-Strong arp

The arp preset routes through a real Karplus-Strong plucked string (feedback delay line with 2-tap averaging lowpass, excited by a noise burst on the gate's rising edge). The KS node ships in sigil-dsp (sigil dsp osc) as make-ks freq decay excite-gain and is wired into the motif graph DSL as g:ks. See folio topics/sigil-dsp-karplus-strong for the primitive's parameters and decay math.

motif render arp-ks-demo -o /tmp/arp-demo.ogg

Streaming render

Alongside the one-shot render-track-to-ogg, motif exposes a chunked streaming API that pulls N samples at a time, preserving all render state between calls. Every chunk also emits a deterministic event stream — one entry per drum onset or melodic chord change, tagged with a sample-offset within the chunk, a voice name, a note frequency, and a duration in samples. Downstream consumers (e.g. a game loop that wants visuals coupled to sample-accurate audio) can feed the PCM bytevectors to an audio device at their own cadence while reading the events synchronously.

(import (motif render))
(let* ((stream (open-render-stream trk))
 (result (render-stream-chunk! stream 4096)))
 (car result) ;; => bytevector, 4096 stereo float32 frames
 ;; (length = 4096 * 2 * 4 bytes, host endian)
 (cadr result)) ;; => ((offset voice-name note duration-samples) ...)
 ;; offset in [0, 4096)
;; Full-track convenience:
(render-track-streaming trk 4096) ;; => pcm bytevector
(render-track-streaming-with-events trk 4096) ;; => (pcm absolute-events)

At any chunk size the resulting PCM is byte-for-byte identical to a one-shot render of the same track — verified at chunk sizes {total, 4096, 1024, 1}. The one-shot render-track-to-ogg has been reimplemented on top of render-track-streaming; existing callers see no change.

Streams are not thread-safe: each <render-stream> is single-owner. Call close-render-stream! when done (the finalizer also releases the C-side state if close is skipped).

See folio topics/motif-streaming-render-architecture for the state machine design, event generation, and chunk-size tradeoffs.

Modules

Module Purpose
(motif main) CLI dispatch
(motif track) Track and layer data structures
(motif theory) Note/MIDI/frequency conversion, scales, chords
(motif pattern) Chord progressions and note patterns
(motif synth) Synth preset definitions
(motif presets) Curated named voices for cinder-cantata and friends
(motif drums) Drum synthesis (kick, snare, hihat, clap)
(motif sequencer) Step sequencer with grid patterns
(motif song) Song sections and automation
(motif render) Render pipeline orchestration
(motif render plan) Build native render plans from track data
(motif render native) C render loop and WAV writer bindings
(motif render stream) Streaming / chunked render API
(motif wav) Sigil-side WAV writer (legacy)