The Little Modulator is a synthesizer instrument modeled on Yamaha’s famous X-series FM synthesizers. It is implemented as a set of Scheme libraries, with driver programs for performance.
This is a work in progress. The implementation is still quite rough. Bug reports and suggestions — especially on the finer points of synthesis implementation — are welcome.
At the moment I am working on TLM with Gauche. The implementation will need some adjustment to run under other R7RS Schemes.
Sound synthesis using arbitrary (but currently acyclic) graphs of frequency-modulated oscillators for tone production. (Implemented.)
Per-oscillator customizable envelope generators. (Implemented.)
Arbitrary pitch specification by frequency and frequency ratio. No artificial restriction to MIDI-note pitches (i.e. to twelve-tone equal temperament). (Implemented, at least internally.)
MUSIC V / Csound–style score input for ahead-of-time synthesis. (Implemented.)
Realtime performance under MIDI control. (TODO.)
TLM is currently written in R7RS Scheme with a few additional dependencies:
The R6RS bytevector library (AKA (scheme
bytevector)) or the equivalent.
The following uses an electric-organ-like instrument (described
by Chowning & Bristow in FM Theory &
Applications (1986), p. 101) to play a five-note scale
(Ptolemy’s
diatonic) to the file scale.s16. The format is currently
raw 16-bit PCM.
(import (scheme base)
(scheme file)
(tlm envelopes)
(tlm output)
(tlm score)
(tlm signal-graphs)
)
(define my-synth
(let* ((env0 (make-env 99 150.0 95 45.0 99 0.0))
(carrier-env (env-scale-levels 20 env0))
(osc0 (make-osc #f (make-env-generator carrier-env) 1.0))
(osc1 (make-osc 1.0 (make-env-generator env0) #f))
(osc2 (make-osc #f (make-env-generator carrier-env) 1.288))
(osc3 (make-osc 2.0 (make-env-generator env0) #f))
(osc4 (make-osc #f (make-env-generator carrier-env) 2.042))
(osc5 (make-osc 3.0 (make-env-generator env0) #f))
(ov (vector osc0 osc1 osc2 osc3 osc4 osc5)))
(make-instrument ov '((0) (1 0)
(2) (3 2)
(4) (5 4)))))
(define my-score
(list (make-note 0 3 400 64)
(make-note 4 3 450 64)
(make-note 8 3 500 64)
(make-note 12 3 533.333 64)
(make-note 16 6 600 64)))
(call-with-port
(open-binary-output-file "scale.s16")
(lambda (port)
(play-score port my-synth my-score)))
EUPL v1.2 or later.