Skip to content

Latest commit

 

History

History
250 lines (232 loc) · 19.7 KB

TODO.org

File metadata and controls

250 lines (232 loc) · 19.7 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.

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

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.

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 parp 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 number slot but for the number of times the pattern is played, not the number of events in the pstream.

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

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

i.e., could be something like this:

(pmetropolis
 (pbind :instrument :acid
  :midinote (pseq '(60 59 58 57 56 55 54 53) :inf))
 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.

maybe don’t make it a macro so the step pattern could be a pseq, prand, etc?

pgatestorm - erogenous tones gatestorm-inspired pattern class with a mini-language for writing trigger-based patterns.

define a cl-patterns/basic system as a more minimal system that does not include clock or event special keys.

define cl-patterns/clock for the clock.

define cl-patterns/music-events for the event special keys.

pprocess - dsl for altering patterns. (maybe call it 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.

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

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.

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

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

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 two 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: http://www.sbcl.org/manual/#Extensible-Sequences

Renoise import/export

see cl-renoise

make sure communicating with pure data via OSC works

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 (i.e. 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 ? something like parp ?)

consider alternatives to nil for end of pattern

(mainly because patterns like pif otherwise have no way to differentiate between “end of pattern” and “false”…)
  • perhaps use 'cl-patterns:end as the end-of-pattern symbol instead? the symbol is already exported anyway, however it does refer to the end method
  • perhaps make a 'cl-patterns:eop (“end of pattern”) symbol?

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

mutateful-inspired pattern mini-language

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

curve parameter for pdurstutter~/~pr

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

option to make changes to patterns affect their pstreams immediately

it should be pretty easy to do this for eseq.

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

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

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

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

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

ipstream

pswing pattern to 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)

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

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

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

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

pattern for doing feedback in patterns