Skip to content

Latest commit

 

History

History
343 lines (328 loc) · 25.8 KB

TODO.org

File metadata and controls

343 lines (328 loc) · 25.8 KB

TODO

This is just a list of various ideas, or tasks that need to be done for this library. For a list of overall project goals, see roadmap.org.

write more documentation

docstrings for all patterns

“how to write pattern classes” document

event/pbind special keys

readtable/syntax shortcuts

bsubseq - “beat subseq” function for getting a subsequence based on start times of events.

bsubseq* function. same as bsubseq but it also includes synths that would’ve already been playing at the start time specified.

  • i.e. (bsubseq* (pbind :dur 2 :foo (pseq '(1 2 3))) 1 4) returns (list (event :dur 1 :foo 1) (event :dur 2 :foo 2))

do “static” things to “dynamic” patterns - i.e. (protate (pseq '(1 2 3)) 1) results in (3 1 2 3 1 2 3 ...) or the like. would work with event patterns too obviously and should “fail” gracefully by still giving output even if the source pattern is infinite-length (maybe just only operate on the first 16 beats, events, or output values by default for infinite patterns).

more metadata in patterns and streams so that it’s easier to write functions that process streams/patterns/etc

automatically record output from pstreams so it can be referenced later - store *max-pattern-yield-length* values from each pattern.

make a current function that will get the last value that was output from a pstream.

<<lfos>>make it possible to easily create lfos for the synth’s parameters

maybe this all should be implemented as a pattern that yields the mapping, rather than as part of pattern itself. that way its behavior can be configured more easily (i.e. whether the synth should retrigger per event or just once at the start of the pattern)

can embed a synth definition (sc:defsynth) as the value, in which case the synth is triggered at the start of each pattern (or maybe for each event?)

can embed a sc:proxy, in which case the pattern just takes values from the output of the proxy.

can embed an Env, in which case a env-playing synth is mapped to the triggered synth’s parameter.

maybe make it possible to change whether to retrigger for each event or just have the synth/env play for the duration of the pattern. perhaps retrigger if the synth/env is the result of an embedded pbind, but play for the duration if it’s just a lone env/synthdef.

create a pattern that takes a dur pattern and a value pattern and converts it to an LFO which can then be assigned to a key in a pbind

make it possible to send out values of a key at a different rate

i.e.: (pbind :dur 1 :foo (pseq '(1 2 3)) :bar (pbind :dur 1/2 :val (pseq '(9 8 7)))) results in :foo being set to 1, then 2, then 3 on every beat, while :bar is set to 9, then 8, then 7 on every half beat. effectively, the :bar sub-pattern is independent from the main pbind, it’s just launched at the same time and ends at the same time.

make macros to quickly write out patterns with symbols, i.e. k---s---k---s--- for a kick/snare/kick/snare pattern or the like.

see pcycles

add more tests to tests.lisp

add tests for clock behavior

make patterns able to trigger other patterns

maybe something like this?

(progn
  (play (pbind :name :bar :pefollow :foo :timing-offset 0.25))
  (play (pbind :name :foo :dur (pseq '(0.5 0.5 0.5 0.5 1 1)))))

…then the :bar pattern’s events will play 0.25 beats after each of :foo’s events play, because it’s set to :pefollow that pattern.

similarly, a :pfollow key could be used to automatically start the pattern for each event of the source pattern. the default event would be the event from the source pattern that triggered the subpattern to play.

or maybe have an :action key for patterns that can be used to fork the pattern, launch another pattern, etc…?

allow a pattern play another by using it for its :instrument key.

see pfor and pmeta

:cleanup key for patterns. this can either contain a function or a list of functions. when the pattern ends or is stopped, the function or functions will be called.

not sure if it should be called if the pattern is swapped out while playing, i.e. through pdef redefintion or the like.

patterns from SuperCollider - see sc.org

pclockdm - clock divider/multiplier pattern.

could be used, for example, for a pattern that’s set to :pfollow another pattern, to make it trigger twice as often, half as often, etc. for half as often, patterns would have to have their own gensym s or IDs so that it could be kept track of whether or not to trigger the sub-pattern for each event. this ID would probably have to be associated with the pattern itself, not the pstream. could maybe be like the pstream-count slot?

events with lists as values should be automatically multichannel-expanded as the last step before being played, and those lists/events should be handled properly by the pattern system prior to that.

basic pre-backend multichannel expansion

patterns automatically and correctly handle/coerce lists as values

split out cl-patterns functionality into independent sub-systems

cl-patterns/basic - minimal system that only includes patterns and not the clock or event special keys.

cl-patterns/clock - the clock.

cl-patterns/special-keys - the event special keys.

pprocess - dsl for altering patterns. (maybe call it peach or pfor instead?)

accepts statements like these:

  • for last 2 notes in (pbind :midinote (pseq '(60 58 56 55) 1)) set :dur 2
  • for only (= (mod (slot-value e 'number) 2) 0) in (pbind :midinote (pseq '(60 58 56 55) 1)) set :midinote (p+ 12 (pk :midinote))

pattern that automatically calculates sample :start and :end from onsets data (in the form of an event stream, which can then be :embed-ed) for synths that play sections of a sound.

done; see psplits from the bdef library.

special key for patterns that lets you specify the beat that an event starts on directly, rather than it being determined by inter-onset times with :dur or the like.

  • would probably be relative to the start of the pattern.
  • probably couldn’t be an event special key since context is needed to derive the duration/start time, etc.

done; see :beat

improve clock.lisp and various backends support by abstracting away time and converting it to each backend’s representation when necessary, etc.

abstract away stuff so they work consistently regardless of backend:

envelopes

buffers

see the bdef library

buses

synths/synthdefs/proxies

see make it possible to easily create lfos for the synth’s parameters as well

make sure multiple backends can be used simultaneously

generalize the library

make other libraries that expand upon cl-patterns’ feature sets (i.e. libraries for live coding conveience macros, etc.)

music theory

make sure the functionality in scales.lisp, etc, is correct.

support chord notation

look into ChordSymbol

support I, II, III, IV, i, ii, iii, iv, etc. notation

clock condition handler (formerly known as “performance mode”)

…where any pattern that signals a condition is automatically handled with the specified restart, so the music doesn’t come to a screeching halt. still trying to think of ideas for how to make a good “performance mode” without just dumbly removing any patterns with errors… (is it possible to continue the rest of the clock’s tasks while the user/coder is responding to the error condition?)

add a restart to re-add the broken pattern

pattern plotting

via vgplot

interactively, via (Mc)CLIM/Thundersnow

pseries/pgeom fromEndPoints

done as pseries* and pgeom*

“triggered mode” that causes patterns that proceed to the next event only when they receive an external trigger

see also: :pfollow

keys like dur and delta would no longer have effect. perhaps enable triggered mode by setting a pattern’s dur to :trigger instead of a number?

legato and sustain would have limited effect. perhaps if legato is < 1, received triggers start a note and end a note, whereas if legato is >= 1, triggers start a note, or if a note is already playing, both stop it and start the next one.

l-systems

tempo change curves

  • can tempo be represented as a key in patterns instead of a slot in the clock? or maybe as a pattern that is always playing, and can be referred to with (ptempo) or the like? that way we get curves, etc for free

pblend to blend between multiple patterns

export patterns as SuperCollider Score files so they can be rendered in non-realtime

then make render or record functions

render is complete.

make pstreams compatible with sequence functions

subsystem for generic-cl methods to make working with patterns even easier!

Renoise import/export

see cl-renoise

add an OSC backend

make sure communicating with pure data via OSC works

make a Pure Data backend too - see Pure Data backend below

make sure our clock works with the cl-collider TempoClock so they can be used together/synced etc.

same with sc-extensions

provide a quickproject template to quickly generate a cl-patterns project

test on ccl and other implementations

cl-patterns “patterns-as-audio” backend

allow the clock to be stopped and resumed and for it to be slave to an external clock

might need to get rid of local-time stuff for this to work

functions to get output range of patterns, so something like range could be used on them to easily set numeric output ranges.

probably would also be nice to have this metadata for supercollider/cl-collider ugens as well.

additional event types:

https://depts.washington.edu/dxscdoc/Help/Overviews/Event_types.html

typedescription
oncreate a synth without release
setset values of controls
offrelease a node (or free it if it has no gate)
groupcreate a group
killfree a node
bussend array to consecutive control buses, starting at id
allocallocate a buffer
freefree a buffer
gengenerate values in buffer
loadallocate and load a file to a buffer (integrate with bdef too)
readread a file into an already-allocated buffer (+ bdef)

additional event keys:

keydescription
detunefrequency detuning in Hz
steps-per-octavenumber of steps per octave (i.e. override scale or tuning value)
harmonicharmonic ratio
octave-ratiosize of the octave (i.e. default 2 means 1 octave up = 2x the frequency)
midinote-to-freqfunction to convert MIDI note number to a freq (defaults to midinote-freq)
mtransposemodal transposition of degree within a scale
gtransposegamut transposition of note within a steps-per-octave e.t. scale
ctransposechromatic transposition of midinote within 12 tone e.t. scale

equivalent for SuperCollider’s strum event key

maybe make it a pattern instead? pstrum ? pfor can already do something similar

consider alternatives to nil for end of pattern

done - we now use cl-patterns:eop instead.

pattern that “curves” the time of another pattern (basically like the curve parameter for SuperCollider’s envelopes does)

could this be generalized so that it can curve any parameter?

curve parameter for pdurstutter~/~pr

maybe also a way to apply dur curves in general, i.e. so it can be used in pfor as well?

option to make changes to patterns affect their pstreams immediately

it should be pretty easy to do this for timeline.

perhaps just make a pstream that is just a proxy to the pattern, auto-updated when the pattern changes?

more “hotswappable pstream” stuff; i.e. stuff to swap pstreams in the middle of the pattern as they’re playing, with all changes applied immediately and continuing from the same beat

see timeline (integrate the functionality of ipstream into it)

improve print-object methods

take into account these variables (and maybe others?):

  • *print-readably*
  • *print-escape*
  • *print-pretty*
  • *print-length*
  • also look into make-load-form

Include Emacs skeletons and other functionality for writing patterns faster

done - see the res/emacs directory

pswing pattern to easily apply swing to an input pattern

“after actions”

determine what pattern should be played or action should be taken at the end of this pattern, by providing a list to the :after slot/key of a pattern.

  • could theoretically be a replacement/generalization of loop-p, i.e. loop-p would be the same as a “loop current” after action.
  • calculated when the pattern ends, by calling next on the pattern’s :after key (so it can be provided either as a list or as a function/pattern).
  • next on a pattern should return the after action as a second value when the pattern is ending.
  • maybe the default action should be next, which defaults to the current pattern if there are not other patterns with the same name prefix? i.e. that way it automatically loops the pattern until the next one is defined? the end function could just set the after action to stop or similar.
  • if the after action is next, to find the “next pattern”, do the following:
  1. if the pattern name has a dash in it, select up to the first (or last?) dash (i.e. NAME- if the name is NAME-1) and find all that also start with NAME-
  2. if the pattern has no dash, look for any patterns that start with a number (i.e. if NAME, look for NAME1, then NAME2, etc)
  3. if none are found for steps 1 or 2, just repeat the same pattern.
  • when finding the next pattern, you can also specify the prefix to search patterns for, a list of patterns to select from, or other after action parameter(s)
  • should be possible to specify a number of times for the after action to apply, to i.e. be able to say “loop this pattern 4 times, then proceed to the next pattern”

the after action can be any of the following:

  • just a after action by name (coerced to a list of the form (AFTER-ACTION-NAME))
  • a list in the form (AFTER-ACTION-NAME &optional LIST-OF-PATTERNS) to provide a list of potential patterns for the after action to choose from (or maybe just after action parameter, possibly keys as well?)
  • just a pattern by name (if the pattern has the same name as a after action, the after action is selected)

list of possible after actions:

  • stop or end (remove this task/pattern from the clock)
  • back (play the one that was played before this) (maybe? then we’d have to store that information in the pattern too…)
  • next (sort all pdefs by name, then play the next one alphabetically? can also specify a pattern by name)
  • previous or prev (alphabetically?)
  • first (by finding all that start with the same prefix, i.e. if the pattern is named :FOO-2 and patterns :FOO-1 and :FOO-3 also exist, first will select all patterns whose names start with :FOO-, sort by name, and pick the first one)
  • last (like first but pick the last one instead)
  • random or rand (find all with same prefix, then pick a random one. can also specify the list of patterns to select from, in which case it basically expands to a prand of all applicable patterns)
  • other, xrandom, or xrand (same as random/rand except don’t play the same pattern twice in a row)
  • round-robin or rr (select all patterns with the same name prefix, then either play the next one or the first one is this is the last one… does this differ from the “next” after action in any way?)
  • reverse-round-robin, rev-round-robin, rev-rr, or rrr (same as round-robin but pick previous or last instead of next/first)
  • this, same, or loop (repeat the same pattern)

prior art:

estimate-length and estimate-dur methods

sort patterns from patterns.lisp into separate files based on category (same categories as patterns.org)

more “effect” patterns that process incoming patterns. i.e. “probability” could be a pattern like:

(pprobability PATTERN PROBABILITY &key (ON :event) (OFF :rest))

where PATTERN is the input pattern, PROBABILITY is the probability (can be static like 1/2 or dynamic like (pk :probability) for example), ON is what to do when the probability is true, OFF is what to do when it’s false. ON and OFF can be static events, or they can be “preset actions”, i.e.:

  • :event means pass the input event through unchanged
  • :rest means set the input event’s note type to :rest

“event transformations”, list of standard event transforms like :event and :rest above

use mutility:ringbuffer for pstream history

consider parachute instead of fiveam

patterns like pfindur and psync should allow you to configure whether they cut the notes at the end of their maxdur

allow the user to set default values for the repeats and length parameters instead of always being :inf

done - *default-pattern-length* and *default-pattern-repeats*

make the default value of repeats and length arguments customizable on a per-pattern basis? perhaps using class variables?

Ableton Link support

LinkUGen - possibly useful as a reference?

make some kind of function or pattern to get the mouse position, a la the mouse-x and mouse-y UGens, except from the Lisp side so we don’t have to proxy them from the SC server.

as per issue #28

as-ugen function that can convert a pattern object into a ugen graph for supported backends

pattern for doing feedback in patterns

some kind of bytebeat pattern

add a webhook for circle-ci to send a notification to the matrix room on test failures.

the old one used for travis-ci was:

# matrix notifications on failures
notifications:
  email: false
  webhooks:
    urls:
      - "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MGRlZmF1bHR4ciUzQXN0cnVjdC53cy8lMjFNT1JMTkN0YWdLUW1jdXBvZ28lM0FzdHJ1Y3Qud3M"
    on_success: change # always|never|change
    on_failure: always
    on_start: never

maybe look at this for an example?

use something like ASDF-System-Connections to automatically load relevant subsystems (such as cl-patterns/supercollider) when the relevant other system (such as cl-collider) is loaded.

something like Nodal or Midinous perhaps? see this video for a demo.

make and export functions to add, remove, and list special keys

Since more and more special keys are being defined, there should be a programmatic way to query what a key can do. Such a function should take into account all of the following:

  • event builtins/conversions
  • information on event types
  • pbind special keys (init, wrap, process)
  • pmeta special keys
  • backend-specific keys (i.e. the ones for MIDI backends like alsa-midi)
  • others?

allow MIDI/OSC input to the pattern system

should be possible to use the held notes as list inputs to patterns (i.e. then pseq or other patterns could be used as a way to make simple arpeggiators)

allow note pressure to control parameters of said “arpeggiators”; i.e. pressure could be mapped to ratcheting or similar, so each note’s ratcheting could be “played” with the keyboard

Repetition.sc-style DSL?

replace error and warn strings with actual condition classes

formats

ensure that functions provided as event pattern values are passed the current value of their key, so stuff like this can be done:

(pbind :dur (pwhite 1 4)
       :dur (fn (* _ 1/4)))

update playing synths to point at the new node when when redefining a proxy or dn used as an effect

synths that are currently playing are not updated to point at the new instance of the effect. fix that. it’s particularly bad for :type :mono :legato 1 patterns.

<<pd-backend>>Pure Data backend

perhaps take influence from the Scheme for Max/Scheme for Pure Data project

include Pd abstractions/examples in res/

function to convert chord progressions into patterns

example: C-C/Bb-F/A-Fm6/Ab-C/G-D/F-F-Fm6 as per this part of this video and explanation in this video

use generators instead of manual pattern class implementation?

series

snakes

factor out “transformations” into regular common lisp functions

for example the “curve the time of another pattern” stuff could maybe be factored out into a function

hexBeat, as described at 15:48 in this talk

(hexbeat #x88) ;=> (1 0 0 0 1 0 0 0)

function to get the name of a chord from a list of notes.

rename cl-patterns/supercollider to cl-patterns/cl-collider for consistency with bdef

inspirations

pgatestorm (working name)

Erogenous Tones GateStorm-inspired pattern class with a mini-language for writing trigger-based patterns. playlist of instructional videos

Harmony Scaler-inspired pattern (WIP as pspiral) to generate melodies based on pitches spiraling in a circle with offsets

Mutable Instruments Grids-inspired pattern

perhaps make something that can auto-extract sequences from drumloop sound files?

mutateful-inspired pattern mini-language

https://cdm.link/2019/10/mutateful-free-live-coding-ableton/

betablocker-inspired pattern (perhaps related to pfsm or pdfsm or the like?)

pmetropolis - intellijel metropolis-inspired pattern class (maybe a mini-language for compactly representing durstutters, etc).

maybe something like this:

(pbind :instrument :acid
       :midinote (pseq '(60 59 58 57 56 55 54 53))
       :embed (pmetropolis '(5s 2h+ 2r 2o 0 3 2h- 1)))

this pattern would stutter 60 for 5 pulses, hold 59 for 2 pulses with a slide into 58 (+ meaning slide), rest for 2 pulses (instead of playing 58), play 57 for 1 pulse and then rest for a pulse, skip 56 entirely (0 pulses), play 55 once and then rest 2 pulses (default step mode is “once”), skip 54 entirely (- means skip), play 53 for one pulse, and then loop.

“preset” patterns, i.e. amen break (and other common loops), optionally loadable via a function

  • amen break
  • 4 on the floor
  • drum patterns for various genres
    • drum’n’bass
    • house
    • etc
  • 18 rhythms you should know - also explains swing/shuffle
  • “see also: pbjorklund”

rename pbjorklund to peuclid or similar?

give a better error message if *clock* is nil - for example, for issues like byulparan/cl-collider#144