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.
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.
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?)
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
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.
pcycles
add more tests to tests.lisp
(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…?
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
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.
cl-patterns/basic
- minimal system that only includes patterns and not the clock or event special keys.
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.
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.
see make it possible to easily create lfos for the synth’s parameters as well
make other libraries that expand upon cl-patterns’ feature sets (i.e. libraries for live coding conveience macros, etc.)
make sure the functionality in scales.lisp, etc, is correct.
look into ChordSymbol
support the super-ultra-hyper-mega-meta-lydian scale
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.
- 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
render
is complete.
make pstreams compatible with sequence functions
subsystem for generic-cl methods to make working with patterns even easier!
see cl-renoise
same with sc-extensions
functions to get output range of patterns, so something like range
could be used on them to easily set numeric output ranges.
https://depts.washington.edu/dxscdoc/Help/Overviews/Event_types.html
type | description |
---|---|
on | create a synth without release |
set | set values of controls |
off | release a node (or free it if it has no gate ) |
group | create a group |
kill | free a node |
bus | send array to consecutive control buses, starting at id |
alloc | allocate a buffer |
free | free a buffer |
gen | generate values in buffer |
load | allocate and load a file to a buffer (integrate with bdef too) |
read | read a file into an already-allocated buffer (+ bdef ) |
key | description |
---|---|
detune | frequency detuning in Hz |
steps-per-octave | number of steps per octave (i.e. override scale or tuning value) |
harmonic | harmonic ratio |
octave-ratio | size of the octave (i.e. default 2 means 1 octave up = 2x the frequency) |
midinote-to-freq | function to convert MIDI note number to a freq (defaults to midinote-freq ) |
mtranspose | modal transposition of degree within a scale |
gtranspose | gamut transposition of note within a steps-per-octave e.t. scale |
ctranspose | chromatic transposition of midinote within 12 tone e.t. scale |
maybe make it a pattern instead? pstrum
?
pfor
can already do something similar
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?
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)
take into account these variables (and maybe others?):
*print-readably*
*print-escape*
*print-pretty*
*print-length*
- also look into
make-load-form
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? theend
function could just set the after action tostop
or similar. - if the after action is
next
, to find the “next pattern”, do the following:
- if the pattern name has a dash in it, select up to the first (or last?) dash (i.e.
NAME-
if the name isNAME-1
) and find all that also start withNAME-
- if the pattern has no dash, look for any patterns that start with a number (i.e. if
NAME
, look forNAME1
, thenNAME2
, etc) - 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”
- 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)
- 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)
- Bitwig’s next actions
sort patterns from patterns.lisp into separate files based on category (same categories as patterns.org)
(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
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
*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
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.
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?
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?
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)))
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.
include Pd abstractions/examples in res/
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
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)
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).
(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.
- 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”