This is a listing of notable features of cl-patterns. For a listing of new features relative to SuperCollider’s patterns system, see sc-differences.org.
- multiple sound server backends are supported:
- SuperCollider (via the cl-collider library)
- Incudine
- ALSA MIDI (via the cl-alsaseq library)
- event keys that are different representations of the same concept are automatically converted between each other. For example, if you set the
amp
of an event and then try to get itsdb
, cl-patterns converts the amplitude to decibels for you:
(db (event :amp 0.5))
;=> -6.0205994
(amp (event :db -3))
;=> 0.70794576
See special-keys.org for a full listing of such keys.
- pbind has “special” keys which alter the functionality of the pattern or pstream.
For consistency, they’re typically named after other patterns, i.e. pfin
, pfindur
, psync
, etc.
See special-keys.org for a full listing.
- it’s possible to embed an event’s values into another from inside a pattern. For example:
(next-n (pbind :foo (pseq '(1 2 3 4))
:embed (pseq (list (event) (event :bar 1 :baz 2) (event :qux 3))))
3)
((EVENT :FOO 1)
(EVENT :FOO 2 :BAR 1 :BAZ 2)
(EVENT :FOO 3 :QUX 3))
- all pstreams keep a history of previous values that can be referred back to at any time using
pstream-elt
. - patterns that have
repeat
orlength
arguments accept any pattern as “gate” patterns:
(let* ((foo 1)
(bar (as-pstream (pseq '(1 2 3) (pfunc (lambda () foo))))))
(print (next-n bar 10)) ;=> (1 2 3 1 2 3 1 2 3 1)
(setf foo 0)
(print (next-n bar 3)) ;=> (2 3 NIL)
)
- patterns keep track of their “parents”:
(defparameter *pat* (pbind :foo (pseq '(1 2 3))))
(defparameter *pseq* (getf (slot-value *pat* 'cl-patterns::pairs) :foo))
(parent-pattern *pseq*) ;=> #<PBIND {1003480F53}>
(eq *pat* (parent-pattern *pseq*)) ;=> T
- errors in pattern execution give you the option to remove the task from the clock, or just skip one event.
- alternatively, “performance mode” gives you the option to automatically remove erroring patterns from the clock, with their error and stack trace recorded to a variable:
(setf *performance-mode* t)
(play (pbind :x (p/ 1 (pseq '(440 220 0)))))
;; ...and then the error occurs:
;; WARNING: Task #<CL-PATTERNS::TASK {100438A803}> had error #<DIVISION-BY-ZERO {10043ABA93}>; removed from clock, with state recorded as index 0 in CL-PATTERNS::*PERFORMANCE-ERRORS*.
(car (last *performance-errors*))
;;=> (:TASK #<CL-PATTERNS::TASK {100438A803}>
;; :ERROR #<DIVISION-BY-ZERO {10043ABA93}>
;; :STACK (#<DISSECT::SBCL-CALL [1] ...> ...))
- SuperCollider backend: if a node is supplied as a value for a
pbind
, the synth metadata for that node is used to set itsinput-bus
oroutput-bus
as the value instead:
(sc::set-synthdef-metadata :fx :input-bus (bus-audio :chanls 2))
(defparameter *fx* (proxy :fx
(let* ((sig (in.ar (sc::get-synthdef-metadata :fx :input-bus) 2))
(sig (comb-c.ar sig 0.2 (range (lf-noise1.kr 1) 0.04 0.2))))
sig)))
(pb :fx-test
:instrument :kik
:dur (p/ 1 (pwhite 1 16))
:midinote (pwhite 0 127)
:pan (pwhite -1.0 1.0)
:out *fx*
:pfindur 4)
(play :fx-test)
…in the future, this will be even simpler. :)
metadata
slot for patterns
Hash table associated with each pattern for storing additional data. Access with the pattern-metadata
function. Used by the midifile functionality to include track names/information/etc.