cl-patterns-study/2022-08-19-patterns-guide.lisp

314 lines
7.8 KiB
Common Lisp

;; https://github.com/defaultxr/cl-patterns/blob/master/doc/tutorial.org
;; https://github.com/defaultxr/cl-patterns/blob/master/doc/cookbook.org - other examples
(ql:quickload :cl-patterns/supercollider)
(cl-patterns:backend-start 'supercollider)
;; also launch QjackCTL and connect SuperCollider outputs 1 & 2 to headphones
;; to force restart, use killall scsynth
(in-package #:cl-patterns)
(start-clock-loop :tempo 136/60)
(pb :automatic-jazz
:note (pshuf (scale-notes :minor) 4)
:octave (pr (pwhite 2 7))
:root (pr (pwhite 0 12))
:dur (pshuf (list 1/3 1/4)))
(play :automatic-jazz)
(end :automatic-jazz)
;; (tempo 136/60) ; this raises error
(pb :hat
:instrument :hat
:dur 1/2 ;; play the hihat every 1/2 beat
:pfindur 4 ;; limit the pattern to 4 beats in length (it loops automatically)
:quant 4 ;; ensure that the pattern starts on a beat that is divisible by 4
)
(pb :snare
:embed (pcycles "----o--o-o--o--o") ;; using the snare tab from the page linked above
:instrument :snare
:dur 1/4
:quant 4)
(play :snare)
(end :snare)
(pb :kick
:embed (pcycles "o-o-------oo----")
:instrument :kick
:dur 1/4
:quant 4)
;; play the patterns we've defined:
(play :hat) ; for some reason just NIL
(end :hat)
(play (list :hat :snare :kick)) ; hm
(pb :12-bar-blues
:scale :chromatic
:root 4 ;; E for all guitar lovers out there
:octave 4
:dur (pseq (list 2/3 1/3))
:amp (pseq (list 0.5 0.4))
:legato (pseq (list 0.7 0.2))
:degree (pr (pseq (list (pseq '((0 7) (0 9)) 8)
(pseq '((5 12) (5 14)) 4)
(pseq '((0 7) (0 9)) 4)
(pseq '((7 14) (7 16)) 2)
(pseq '((5 12) (5 14)) 2)
(pseq '((0 7) (0 9)) 2)
(pseq '((7 14) (7 16)) 2))
1)
2))
(play :12-bar-blues)
(end :12-bar-blues)
;; what do I want to learn though?
(pb :foo ;; define a new pattern named :foo
:instrument :kik ;; use the :kik synth we defined above
:play-quant 4 ;; make sure the pattern will only start on a beat that is divisible by 4, to stay in sync
:dur 1 ;; give each event a duration of 1 beat
:pfin 4 ;; limit the length of the pattern to 4 events (the default is infinite events)
)
(pb :bar
:instrument :default
:play-quant 4
:dur 1/2
:scale :major ;; select the major scale
:degree (pwhite 0 7) ;; pick a random note from the first 7 notes in the selected scale
:pfindur 4 ;; limit the length of the pattern to 4 beats. pfindur causes the pattern to be limited based on its duration in beats, rather than the number of events.
)
(play :foo)
(end :foo)
;; let's try to modify most basic ones? copy them again
(in-package #:cl-collider)
(defsynth kik ((freq 440) (out 0))
(let* ((env (env-gen.kr (env (list 0 1 0) (list 0.001 1)) :act :free))
(fenv (env-gen.kr (env (list 1 0) (list 0.25)) :level-scale freq))
(sig (sin-osc.ar fenv 0 0.2)))
(out.ar out (pan2.ar sig 0 env))))
(in-package #:cl-patterns)
(pb :foo ;; define a new pattern named :foo
:instrument :kik ;; use the :kik synth we defined above
:play-quant 4 ;; make sure the pattern will only start on a beat that is divisible by 4, to stay in sync
:dur 1 ;; give each event a duration of 1 beat
:pfin 4 ;; limit the length of the pattern to 4 events (the default is infinite events)
)
(play :foo)
(end :foo)
;; ok, I'm starting to try something of my own
(pb :my-foo
:note (pseq '(1 (1 2) (1 3) (1 4) 2 4))
:play-quant 3
:dur 1
)
(play :my-foo)
(stop :my-foo)
;; what's this :note? are they steps of an ocave?
(pb :my-notes
:note (pseq '(0 1 2 3 4 5 6 7 8 9))
:play-quant 3
:dur 1
)
(play :my-notes)
(stop :my-notes)
;; maybe! let's do octave
(pb :my-octave
:note (pseq '(0 1 2 3 4 5 6 7 (0 7)))
:dur (pseq (concatenate 'list (make-list 7 :initial-element 0.5) '(4 8)))
:play-quant 4
:dur 1
)
(play :my-octave)
(stop :my-octave)
;; why :dur doesn't influence things?
(pb :my-lengths
:note (pseq '(0 1))
:dur (pseq '(1 1 2 2 4 4 8 8 16 16))
:play-quant 4
)
(play :my-lengths)
(stop :my-lengths)
;; well that's because there was another :dur with single value, cool
;; maybe! let's do octave fixed
(pb :my-octave2
:note (pseq '(0 1 2 3 4 5 6 7 (0 7)) 1)
:dur (pseq (concatenate 'list (make-list 7 :initial-element 1) '(2 4)))
:play-quant 4
)
(play :my-octave2)
(end :my-octave2)
;; by adding 1 as pseq REPEATS thing, I can stop the pattern by END, which ends after the pattern completion
;; and pattern completes after single repetition,
;; but without END pattern repeats, that's cool
;;; now, what about other ways to set up pitch? apart from note there were other?
(pb :what-note
:note (pseq '(0 1 2 3 4 5 6 7 (0 7)) 1)
:octave 5
:dur (pseq (concatenate 'list (make-list 7 :initial-element 1) '(2 4)))
:play-quant 4
)
;; looks like octave 5 is default, and quite high.
;; 1 - 2 are barely audible
;; 3 is bass
(play :what-note)
(end :what-note)
(pb :what-degree
:octave 3
:note (pseq '(0 1 2 3 4 5 6 7 (0 7)) 1)
:dur (pseq (concatenate 'list (make-list 7 :initial-element 1) '(2 4)))
:play-quant 4
)
(play :what-degree)
(end :what-degree)
;; so, is that same thing?
;;; now. let's look at :root
(pb :what-root
:note (pseq '(0 7 (0 7)) 1)
:octave 4
:root 2
:dur (pseq '(1 1 3))
:play-quant 4
)
(play :what-root)
(end :what-root)
;; yup, root changes root of the key
;;; now let's try to write some chords?
(setq *M1* '(0 2 4))
(setq *Min1* '(0 1.5 4))
(setq *M3* '(2 4 6))
(setq *chord* *Min1*)
(pb :what-chord
:note (pseq `(,*m1* ,*min1*))
:octave 4
:root 2
:dur (pseq '(2 2) 1)
;; :play-quant 4
)
(play :what-chord)
(end :what-chord)
;; those are major and minor chord, but very ugly cheap sound.
;; is there are way to make it clear?
;; is that about "instrument"?
;; https://github.com/defaultxr/cl-patterns/blob/master/doc/supercollider-example.lisp
(in-package #:cl-collider)
(defsynth default ((gate 1) (freq 440) (out 0))
(let* ((env (env-gen.kr (asr 0.01 1 0.1) :gate gate :act :free))
(sig (sin-osc.ar freq 0 0.2)))
(out.ar out (pan2.ar sig 0 env))))
(defsynth kik ((freq 440) (out 0))
(let* ((env (env-gen.kr (env (list 0 1 0) (list 0.001 1)) :act :free))
(fenv (env-gen.kr (env (list 1 0) (list 0.25)) :level-scale freq))
(sig (sin-osc.ar fenv 0 0.2)))
(out.ar out (pan2.ar sig 0 env))))
(defsynth sine-wave ((note 60) (freq 400))
(let* ((freq (midicps note))
(sig (sin-osc.ar freq 0 .2)))
(out.ar 0 sig)))
(in-package #:cl-patterns)
(pb :what-instrument
:note (pseq `(0 1))
:instrument :default
:octave 5
:root 2
:dur (pseq '(2 2) 1)
;; :play-quant 4
)
(play :what-instrument)
(end :what-instrument)
;; changing instrument on the fly leaves something running
;; how do I disable it all?
(cl-patterns:stop t)
;;; and some aux functions discovered:
(all-chords)
(all-scales)
(all-tunings)
(defparameter *some-chord* (chord "Major Triad"))
(chord-notes *some-chord*)
;;; can I just use chord as :note ?
(mapcar #'chord-notes (list (chord "Major Triad") (chord "Minor Triad")))
(pb :what-predef-chord
:note (pseq (mapcar #'chord-notes (list (chord "Major Triad") (chord "Minor Triad") (chord "Minor 7th") (chord "Major 7th") (chord "Diminished Triad") (chord "Major Triad"))) 1)
:octave 4
:root 2
:dur (pseq '(2 2 4))
;; :play-quant 4
)
(play :what-predef-chord)
(end :what-predef-chord)
(in-package #:cl-collider)
(proxy :foo (sin-osc.ar 440 0 0.2))
;; so, attempt to call #'PLAY for those predef chords, leads to nothing playing
;; and previous things not starting.
;; more or less stable setup is
;; - restart emacs
;; - whole "setting-up-cl-collider"
;; - whole "supercollider-examples"
;; let's put that into single file maybe? as cargo cult