2018-10-29

sequencer function

for programming the time occurrence of sounds using functions

  • a pure function and algorithm that can map time offsets to sample values or sample arrays
  • sample generating functions are called at desired times 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
  • sequencer calls can be nested to compose complex sounds and for example to model riffs and groups
  • existing sequencer programs 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 in under 400 lines

a small scheme usage example can be found in the readme of sph-sp-guile

data structures

event

fields

event-f groups: custom group names name: custom name start: seconds user-value: user controlled event specific data.

index

index is an array where elements are events for an evenly sized part of a timespan in order. the number of elements is defined by round(index-duration * index-size-factor). events are taken from index and added to state-input as they become relevant

fields

data: current known events for a timespan end: seconds events: current known events outside the timespan f: a function that returns an index for a timespan i-f: a function i-f :: time index-start -> integer:offset that returns a numeric index in data for a time value start: seconds

output

output for one event

fields

name: name of the event that generated it data: the data value created by the event event-state event

state

the main state value of seq

fields

events-f events-states: event specific user value event-states: ((event-name . user-value) ...), user-value index index-i: the currently active slot in seq-index input: all currently relevant events mixer: a function that receives all event results and creates a seq result. the default mixer expects events to return a list of sample values per channel and sums output values with rounding error compensation and clipping options: index-duration, index-size-factor output: output values to be finally passed to mixer and cleared before the next call to seq

functions

seq is the main function and others are helper functions

seq :: time state c:{result state -> seq-result} -> seq-result

seq calls sample generating functions at customisable times, shares state values between event-f and mixes output values to create a single result. the data type seq returns is user defined via event-f and seq-mixer. seq is called for each sample or segment with the time as argument. if no valid index is loaded, events-f is called to get relevant events. events that are active for the given time have their event-f called. slow-down and speed-up can be done by factor multiplying the time value

event-f :: time state event duration event-state -> false/(data state event-state-value ...)

input

  • time: seconds, time for which the event is called
  • state: seq-state
  • event: the event object this event-f belongs to
  • duration: seconds elapsed since the start of the event
  • event-state: event specific user values

output

  • false: the event is stopped. it will be removed from seq-input
  • list

    • data: an element that seq-state-mixer receives before it returns the result of seq. usually this would be the smallest element that a call to seq shall return, for example a sample value or an array of sample values

    • state: the current seq-state

    • event-state-value: the eventually updated input event-state

description

event-f creates one mixer input element and can update the seq-state and the event specific event-state. event-f are used until they return false, so that the duration is easier to modulate. by updating seq-state, it can add new events to the active event list. event-state and output value will be accessible to other event-f. for example for modulation

example: event could return samples for a sound and event-state would be a dictionary that contains the current frequency. other events can be modulated by the returned samples or values in the event-state

events-f :: time-range-start time-range-end state -> (event ...)

time-range-end: time-range-start plus index-duration returns events to be added to the index

generate :: sample-rate channel-count start duration segment-f sample-f user-values ... ->

generate is a different function related to seq. it calls a function for each time interval in a duration. for example, it can be used to call seq once per sample or an array of samples.

sample-f :: env time user-value ...

maps time to a single sample value

segment-f :: env time segment user-value ...

maps time to an array of sample values. the array is either set by sample-f, or if sample-f is false, set to zeros.

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)

faq

can seq be called with decreasing time

should be possible

can events be modulated by the output values of other events

yes, seq-state-output contains all output values associated with the name of the event that returned it

can the order of events be controlled for modulation

for example when an event depends on another event-state that has not been created or updated yet

a: only by the order they are returned from events-f