2018-04-21

time mapping musical sequencer

for programming the time occurrence of sounds using functions

a pure function and algorithm that maps time offsets to sample values or sample arrays

sample generating functions are called at the right time, passed the right input arguments and results are mixed to a single sample or sample array

there can be several stages of cross modulation between sound functions. sounds can modulate and be modulated by other sounds freely

sequencer calls can be nested to compose complex sounds and for example to model riffs and groups

existing tools typically require the manual pre-programming of the playback start of sounds on separate tracks or portions of the composition (riffs). this tends to be not fully controllable by programs. the proposed sequencer is supposed to allow for less restrained automatic generation and modification of sound sequencing

the functionality is currently considered comprehensive and should allow for a maximum of reasonable freedom

reference implementation, under 400 lines, contains additional documentation, part of sph-sp

usage example in scheme using the reference implementation

pair is cons, pairs is cons*

(import (sph sp) (sph sp generate) (sph sp generate sequencer))


;-- sound functions return samples or sample arrays

(define (sound-a time state event duration custom)
  (and (< duration 1) (seq-output (sp-sine time 100) state)))

(define (sound-b time state event duration custom)
  (seq-output (* 0.5 (sp-sine time 200)) state (alist-q freq time)))

(define (sound-c time state event duration custom) (seq-output (* 0.5 (sp-sine time 400)) state))


;-- the events function generates event lists. either the next few relevant relative to time or possibly even all at once

(define (events-f time end seq-state)
  ; this returns a list of next event objects. events-f is called again after (seq-state-duration seq-state) seconds
  (list
    (seq-event a sound-a 0)
    (seq-event b sound-b 1)
    (seq-event c sound-c 1.5)
    (seq-event c sound-b (+ time 1))
    (seq-event d sound-b (+ time 20))))


;-- sample and segment functions are used by sp-generate to map time. "seq" is the main sequencer function

(define (sample-f env time gen-result seq-state . custom)
  ; used by sp-generate to map time to single sample values
  (seq time seq-state (lambda (data seq-state) (pairs data gen-result seq-state custom))))

(define (segment-f env time segment gen-result . custom)
  ; this maps time and the array initialised by sample-f to a new list of one sample array per channel
  (pair (pair (list segment) gen-result) custom))


;-- map time to sample arrays with sp-generate and pass it to a digital to analog converter

(define (run)
  (let*
    ( (seq-state (seq-state-new events-f))
      (result-states
        (sp-generate sample-rate 0 duration segment-f sample-f
          ; custom state values
            null seq-state))
        (result-segments (reverse (first result-states))))
      (sp-segments->alsa result-segments sample-rate "plughw:0" 4096)))

knowledge applied

i previously wrote sph-upcoming which can generate and filter arbitrary calendar event sequences (for example give the date of time of the next occurrence of an event that starts at date x, repeats every 20 minutes but not on mondays). i spent years using the fruity loops sequencer and trying to automate effects with available frontend tools, i also have experience with sequencer programming using puredata (similar to max/msp)


tags: programming start music q1 specification computer design sound signal sph-sp algorithm sequencer sequencing