Compare commits

..

8 Commits

Author SHA1 Message Date
efim
b07c84a2f7 patterned-arpeggio as a function, yay! 2022-09-22 16:22:20 +00:00
efim
adb02840ba simpler arpeggios, and with steps now 2022-09-21 20:09:22 +00:00
efim
e6270ea435 first experiment written down 2022-09-11 15:32:15 +00:00
efim
00515cd9df small refactor of old notes and more arpeggios 2022-09-09 06:10:21 +00:00
efim
788c27c54b more arpeggio, per-phrase-attr 2022-09-08 15:28:08 +00:00
efim
12f0c80af7 attempting to get chord arpegios 2022-09-07 06:41:38 +00:00
efim
6a9b9a88c4 attempting repeating phrases with changing params 2022-09-05 19:19:34 +00:00
efim
0ae86a5f51 just cleanup 2022-09-05 17:54:18 +00:00
23 changed files with 1764 additions and 29 deletions

12
README.org Normal file
View File

@@ -0,0 +1,12 @@
#+title: Learning music with cl-patterns & cl-collider
* structure of files here
** dirty-journal
per-day lisp files and single org-journal as I'm figuring things out for the first time
** stabler-things
cleaned up definitions and functions, saved for possible reuse
1. setting-up.lisp
What I evaluate to start up and test setup
2. synthesizer.lisp
single collection of definitions for instruments
** and hopefully there will be cleaned up journal
that would separate significant things I've been figuring out in a form that would be helpful for other to figure them out

View File

@@ -1,10 +1,6 @@
(in-package #:cl-collider)
;; https://github.com/SCLOrkHub/SCLOrkSynths
;; https://github.com/SCLOrkHub/SCLOrkSynths/blob/master/SynthDefs/strings/violin.scd
(freq 440) (gate 1) (amp 1) (pan 0) (out 0) (att 0.1) (dec 0.1) (sus 0.5) (rel 0.1)
(vRate 4.6) (vDepth 0.02) (vAtt 0.15) (vRateVar 0.25) (vDepthVar 0.05)
(pwmVarRate 2) (pwmMin 0.7) (pwmMax 0.8) (pwmRate 5)
(bridgeFreq 2500) (scratchDepth 0.15)
(defsynth violin ((freq 440) (gate 1) (amp 1) (pan 0) (out 0) (att 0.1) (dec 0.1) (sus 0.5) (rel 0.1)
(vRate 4.6) (vDepth 0.02) (vAtt 0.15) (vRateVar 0.25) (vDepthVar 0.05)
@@ -20,8 +16,8 @@
(range (lf-pulse.ar (* freq 1.5)) (/ 1 scratch) scratch))))
(snd-step-2 (+ (* snd-step-1 0.7)
(bpf.ar snd-step-1 bridgeFreq 2 2)))
(snd-step-3 (* snd-step-2 envelope)))
(out.ar out (pan2.ar snd-step-3 pan)))))
(snd-step-3 (* snd-step-2 amp envelope)))
(out.ar out (pan2.ar snd-step-3 pan))))
;; (synth :violin :freq 400)
;; (stop)
(in-package #:cl-patterns)
@@ -31,9 +27,10 @@
:decay 2
:att 0.07
:sus 0.8
:amp 0.1
:legato 1
:degree (pseq (list 0 1 2 3 4 5 6 7) 1)
:dur 2)
:dur 1)
;; (play :foo-with-pluck-synth)
;; (end :foo-with-pluck-synth)
;; (stop :foo-with-pluck-synth)

View File

@@ -236,9 +236,9 @@
:instrument :fmrhodes1
:octave 3
:degree (pseq (list 0 1 4 8 (prest 0) 0 2 4 7 4 2) 1))
(play :hm-lallaa)
(end :hm-lallaa)
(stop :hm-lallaa)
;; (play :hm-lallaa)
;; (end :hm-lallaa)
;; (stop :hm-lallaa)
;; yup, that's a pause, cool
;; so, do I bring that stuff into a separate file?
@@ -252,7 +252,7 @@
(defun nchord (symbol &optional (base 0))
"Return list of notes for chord names by SYMBOL over the BASE."
(mapcar (lambda (note) (+ base note)) (chord-notes symbol)))
(mapcar (lambda (note) (+ base note)) (chord-notes (chord symbol))))
(nchord :major 3)
@@ -265,9 +265,9 @@
:base 2
:root 5
)
(play :hm-chords-progression)
(end :hm-chords-progression)
(stop :hm-chords-progression)
;; (play :hm-chords-progression)
;; (end :hm-chords-progression)
;; (stop :hm-chords-progression)
;; so, what's a good way to use them? just wrap separately into #'CHORD-NOTES
;; maybe at least for now
@@ -291,9 +291,9 @@
:base 2
:root 5
)
(play :hm-chords-progress-em-g-am-c)
(end :hm-chords-progress-em-g-am-c)
(stop :hm-chords-progress-em-g-am-c)
;; (play :hm-chords-progress-em-g-am-c)
;; (end :hm-chords-progress-em-g-am-c)
;; (stop :hm-chords-progress-em-g-am-c)
;; Am F C G (i VI III VII)
(pb :hm-chords-progress-am-f-c-g
@@ -306,24 +306,27 @@
:base 2
:root 5
)
(play :hm-chords-progress-am-f-c-g)
(end :hm-chords-progress-am-f-c-g)
(stop :hm-chords-progress-am-f-c-g)
;; (play :hm-chords-progress-am-f-c-g)
;; (end :hm-chords-progress-am-f-c-g)
;; (stop :hm-chords-progress-am-f-c-g)
;; IV V iii vi (from video on japan's favourite chord progression)
;; https://youtu.be/6aezSL_GvZA
(pb :hm-chords-progress-golden-road
:instrument :strings
;; :instrument :violin
:instrument :fmrhodes1
:octave 4
:amp 0.2
:legato 1
;; :degree (pseq (mapcar #'chord-notes (list :major :minor :maj7 :major)) 1) ; works, but can't insert (prest 0) among chords
;; :degree (pseq (list (chord :major) (chord :minor) (chord :maj7) (chord :major)) 1) ; doesn't seem to work
:degree (pseq (list (nchord :major 3) (nchord :major 4) (nchord :minor 2) (nchord :minor 5) ) 1) ; doesn't seem to work
;; :degree (pseq (list 1 2 3) 1) ; doesn't seem to work
:dur (pseq (list 4 4 4 4 ))
:root 0)
(play :hm-chords-progress-golden-road)
(end :hm-chords-progress-golden-road)
(stop :hm-chords-progress-golden-road)
;; (play :hm-chords-progress-golden-road)
;; (end :hm-chords-progress-golden-road)
;; (stop :hm-chords-progress-golden-road)
;; does it sound like in the video then?
@@ -332,3 +335,11 @@
;; - giving (note/chord) and rhythm to get form that single note
;; latter should be possible from defining a subpattern? with static note?
;;; now, I'd like to use (render (pdef :your-pattern) "/path/to/output.wav" :dur 4)
;; for that I'd need to use more recent version than I get from quicklisp, so clone repo
quicklisp:*local-project-directories*
(ql:register-local-projects)
(ql:where-is-system :cl-patterns) ;; #P"/home/efim/quicklisp/local-projects/cl-patterns/"
;; (render (pdef :hm-chords-progress-golden-road) "/tmp/chords-4.wav" :dur 16)

View File

@@ -0,0 +1,130 @@
(in-package #:cl-patterns)
(pb :notes
:degree (pseq (list 0 1 2 3) 1))
;; (play :notes)
;; (stop :notes)
(setq *notes* (pseq (list 0 1 2 3)))
(pb :just-*notes*
:degree *notes*)
;; (play :just-*notes*)
;; (stop :just-*notes*)
;;
;; but that would certainly not help with changing other params
;; "per phrase"
(pb :attempt-at-repeating-pattern
:degree (pseq (list 0 1 2 3) 2)
:octave (pr (pwhite 2 5))
)
;; (play :attempt-at-repeating-pattern)
;; (end :attempt-at-repeating-pattern)
;; (stop :attempt-at-repeating-pattern)
;; how does that work? why octave only changes after the degree pseq ends?
(in-package #:cl-patterns)
;; (next-upto-n (pr (pwhite 2 7) (pseq '(1 3 0 2) 1)))
;; this started some computations in sbcl, which are in backgournd and I don't know how to stop
;; (defpattern pr (pattern)
;; (pattern
;; (repeats :initform :inf)
;; (current-value :state t :initform nil)
;; (current-repeats-remaining :state t))
;; :documentation "Repeat each value from PATTERN REPEATS times. If REPEATS is 0, the value is skipped.
;; Example:
;; (next-upto-n (pr (pseries) (pseq '(1 3 0 2) 1)))
;; ;=> (0 1 1 1 3 3)
;; See also: `pdurstutter', `pn', `pdrop', `parp'")
(in-package #:cl-patterns)
(next-upto-n (pseq '(1 2 3) 6) 4)
(next-upto-n (pwhite 2 7) 4)
(next-upto-n (pr (pwhite 2 7) 3) 7)
(next-upto-n (pr (pwhite 2 7) (list 1 2 3)) 7)
(next-upto-n (pr (pwhite 2 7) (pseq '(1 3 0 2) 1)) 10) ; still not working?
(next-upto-n (pr (pwhite 2 7) (pseq '(1 3 0 2) 1)) 6) ; for some reason works up to 6
(next-upto-n (pr (pwhite 2 7) (pseq '(1 3 0 2) 1)) 7) ; for some reason works up to 6
;;; so, if I go into M-x sly-list-threads - I see worker threads,
;;; and I could kill them, but also could d for debug, and "return value from thread", then that value is appended as 7th iteam
;;; so the stream gets frozen, waiting for something to compute?
; well, I guess OBJECT is stream that always repeats itself
; so when I just put 3 or 4 - that's endless stream of 3s and 4s
;; and to have pseq work - I need to remove that "1" and pseq would repeat forever, and numbers from pseq would be "multipliers" for endless stream of random numbers
;; and random numbers would be new for second circle?
(next-upto-n (pr (pwhite 2 7) (pseq '(1 3 0 2) 2)) 7) ; yep
(next-upto-n (pr (pwhite 2 7) (pseq '(1 3 0 2))) 17) ; yep
;; so when "automatic jazz" https://github.com/defaultxr/cl-patterns/blob/master/doc/cookbook.org#random-notes-from-a-scale
;; does :octave (pr (pwhite 2 7))
;; that means repeat (randomly selected from 2 to 7) "forever/until end of pattern"
;; and end of pattern doesn't come from the :octave or :root
;; but comes from the fact that #'PSHUF for :note has "end after 4"
;; cool
;; so to have sequence of parameters that apply for whole melody
;; I'd need "pr forever" and then take items from the list, so from pseq
(pb :at-repeating-pattern
;; :degree (pseq (list 0 1 2 3) 2)
:note (pshuf (scale-notes :minor) 1)
:octave (pr (pseq (list 3 4 5)))
)
;; (play :at-repeating-pattern)
;; (end :at-repeating-pattern)
;; (stop :at-repeating-pattern)
(next-upto-n (pdef :at-repeating-pattern) 20)
;; well, no, I don't understand after all!
;; the pattern ends when :degree or :note part ends, and not restarts
;; let's just copy "automatic jazz" and view it with #'NEXT-UPTO-N
(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)
;; (stop :automatic-jazz)
(next-upto-n (pdef :automatic-jazz) 30)
;; well, maybe pr only doesn't work with pseq, since it always selects first from the stream?
(pb :at-with-random-repeating-pattern
:degree (pseq (list 0 1 2 3) 2)
:octave (pr (pwhite 3 5))
)
;; (play :at-with-random-repeating-pattern)
;; (end :at-with-random-repeating-pattern)
;; (stop :at-with-random-repeating-pattern)
;;; hm, not exactly what I imagined in a way of combining patterns
;; then I guess, I want the melody to repeat in pseq endlessly, and match pr repeat size to length of melody (in events, and not beats, alas!)
;; and use something like pxrand and end with end of pxrands
;; even though that is not yet satisfactory, let's try it
(pb :at-with-outside-pseq-repeating-pattern
;; :degree (pseq (list 0 1 2 3))
:degree (pseq (list 0 1 2 (list 0 7)))
:octave (pr (pseq (list 3 4 5 4 3)) 4)
:amp (pseq (list 0.7 0.5 0.5 0.5)))
;; (play :at-with-outside-pseq-repeating-pattern)
;; (end :at-with-outside-pseq-repeating-pattern)
;; (stop :at-with-outside-pseq-repeating-pattern)
(next-upto-n (pdef :at-with-outside-pseq-repeating-pattern) 12)
;; so I guess when the pattern "repeats" it will be "exactly same" with randoms recalculated
;; also - can I save the seeds? in case I'd like to record a random sequence that I liked on the walkthough?
;; also - how would I specify "a multiplier" for durations? if the notes are not of the same duration
;; (render (pdef :at-with-outside-pseq-repeating-pattern) "/tmp/repeating-4.wav" :dur 16)

View File

@@ -0,0 +1,101 @@
(in-package :cl-patterns)
(all-instruments)
(all-chords)
(nchord :major 3) ; so, i could then inject / what's the verb
; splice list as notes
(nchord "Dominant 7th" 2)
(chord :major)
(chord "Major Triad")
(chord-indexes :major) ; (0 2 4) this goes into :degree
(chord-notes :major) ; (0 4 7) and this goes into :notes?
(chord-midinotes :major)
;; (pb :first-try-sequencing
;; )
;; i want something like
;; (pb
;; :degree chorded-arpeggio '(0 1 3 2 3 0)
;; ok, let's settle situation with notes vs degrees
(pb :with-notes
:instrument :fmrhodes1
;; :note (pseq (list 0 1 2 3 4 5 6 7) 1))
;; :note (pseq (list 0 2 4 5 7 9 11 12) 1)
:note (pseq (list 0 2 4 5 7 9 11 12) 1))
;; (play :with-notes)
;; (end :with-notes)
;; (stop :with-notes)
;; not whole octave from 0 to 7, so every key one after anothe
;; and that would be just tuning steps, not taking into account the "lad"
;; 0 2 4 5 7 9 11 12 is the major. ok
(pb :with-degrees
:instrument :fmrhodes1
:degree (pseq (list 0 1 2 3 4 5 6 7) 1))
;; (play :with-degrees)
;; (end :with-degrees)
;; (stop :with-degrees)
;; so if I take 'chord-notes' in nchord, i need to use :note
;; in the pattern
;; yay, and the patterns from 09-04 sound much better now
;;; so, back to arpeggio things
;; i'd want something like
;; (pb :hopes-for-arpegio
;; :note (arpegio-thingy (list 0 2 3 1 3 0))
;; :dur (pseq (list 1 1 2 1 1 2))
;; :chords (pseq (list :maj :min :maj7 :maj6 :maj)))
;;; and then maybe have only :note and :dur as one names pattern
;; which somehow later combines with the :chords pseq
;; (defpattern pfunc (pattern)
;; ((func :type function-designator)
;; (length :initform :inf)
;; (current-repeats-remaining :state t))
;; :documentation "Yield the result of evaluating FUNC. Note that the current event of the parent pattern is still accessible via the `*event*' special variable.
;; Example:
(next-upto-n (pfunc (lambda () (random 10)) 4))
;=> ((5 2 8 9))
;; (next-upto-n (pbind :foo (pwhite 0 10 4)
;; :bar (pfunc (lambda ()
;; (if (> (event-value *event* :foo) 5) :greater :lesser)))))
;; ;=> ((EVENT :FOO 0 :BAR :LESSER) (EVENT :FOO 6 :BAR :GREATER)
;; (EVENT :FOO 7 :BAR :GREATER) (EVENT :FOO 8 :BAR :GREATER))
;; See also: `pf', `pnary', `plazy', `pif'")
;;; so, maybe that's the way?
;; I really could have :chord attribute, and could possibly have :arpeggio-steps attribute
;; and those would combine to create :note attribute
;; i was recommended PARP
;; but I don't understand how it could be used in conjunction with chords?
;; well, no, I see - I could change :octave, and in first pattern return :notes, right?
(chord-notes :major)
;;; full on gift of help:
(pdef :foo
(parp (pbind :note (pnary #'chord-notes (pseq (list :major :minor :maj7 :maj6 :major) 1))
:dur (pseq (list 1 1 2 1 1 2)))
(pbind :note (p+ (pk :note)
(pseq (list 0 2 3 1 3 0) 1)))))
(next-upto-n (pdef :foo) 4)
;; (play :foo)
;; (end :foo)
;; (stop :foo)
(next-upto-n (pbind :note (p+ 1 (pseq (list 0 2 3) 1))) 4)
;; let's try to get sequence of steps when we give as input notes of a chord
;; tomorrow

View File

@@ -0,0 +1,89 @@
;; let's try the pfunc to create arpegio from the chord
(in-package :cl-patterns)
(next-upto-n (pbind :chord (pseq (list :major :minor :minor-triad :major))
:note (pfunc (lambda ()
(let* ((chord (event-value *event* :chord))
(notes (nchord chord)))
;; let's keep it simple for a moment
notes))
)) 10)
;; ((EVENT :CHORD :MAJOR :NOTE (0 4 7)) (EVENT :CHORD :MINOR :NOTE (0 3 7))
;; (EVENT :CHORD :MINOR-TRIAD :NOTE (0 3 7)) (EVENT :CHORD :MAJOR :NOTE (0 4 7))
;; (EVENT :CHORD :MAJOR :NOTE (0 4 7)) (EVENT :CHORD :MINOR :NOTE (0 3 7))
;; (EVENT :CHORD :MINOR-TRIAD :NOTE (0 3 7)) (EVENT :CHORD :MAJOR :NOTE (0 4 7))
;; (EVENT :CHORD :MAJOR :NOTE (0 4 7)) (EVENT :CHORD :MINOR :NOTE (0 3 7)))
;; And I'd still in parp generator
(next-upto-n (parp (pbind :chord (pseq (list :minor-triad :major)))
(pbind :note (pfunc (lambda ()
(let* ((chord (event-value *event* :chord))
(notes (nchord chord)))
;; let's keep it simple for a moment
(pseq notes 1)))
))) 10)
;; for some reason this stays on first chord forever, but does arpegio
;; bit of something I don't understand
(next-upto-n (parp (pbind :ocatave (pseq (list 3 4 3 5)))
(pbind :note (pseq (list 0 1 2) 1))) 12) ; needed 1 repeat limit here
;; let's try with #'PK
(next-upto-n (parp (pbind :chord (pseq (list :minor-triad :major)))
(pbind :note (let* ((chord (pk :chord))
(notes (nchord chord)))
;; let's keep it simple for a moment
(pseq notes 1)))) 10)
;; error, no applicable method
;; how does that work then?
(pdef :foo
(parp (pbind :note (pnary #'chord-notes (pseq (list :major :minor :maj7 :maj6 :major) 1))
:dur (pseq (list 1 1 2 1 1 2)))
(pbind :note (p+ (pk :note)
(pseq (list 0 2 3 1 3 0) 1)))))
(next-upto-n (pdef :foo) 10)
;; and what if I change :note to :chord here?
(next-upto-n (pdef :foo
(parp (pbind :chord (pnary #'chord-notes (pseq (list :major :minor :maj7 :maj6 :major) 1))
:dur (pseq (list 1 1 2 1 1 2)))
(pbind :note (p+ (pk :chord)
(pseq (list 0 2 3 1 3 0) 1))))) 10)
;; maybe difference is that #'LET* can't be directly in the place that defined :note?
;; and I should use #'PSEQ and move #'LET* into list definiton?
(next-upto-n (parp (pbind :chord (pseq (list :minor-triad :major)))
(pbind :note (pseq (let* ((chord (pk :chord))
(notes (nchord chord)))
notes)
1)))
10)
;; or maybe (pk :chord) is a pattern and can't be used as "just function to get value"
;; seems true
(next-upto-n (parp (pbind :chord (pseq (list :minor-triad :major)))
(pbind :note (pk :chord)))
10)
;; here pk :chord is object so, endless pattern and we never switch to :major
;; but that's ok,
;; main lesson I guess that I need to use pattern transformation functions,
;; and lisp transformations mainly on arguments
(next-upto-n (parp (pbind :chord (pseq (list :minor-triad :major)))
(pbind :note (pfunc (lambda ()
(pseq (nchord (event-value *event* :chord)) 1)))))
10)
;; endless stream, inner :note doesn't end?
(next-upto-n (parp (pbind :chord (pseq (list :minor-triad :major)))
(pbind :note (pseq (pnary #'nchord (pk :chord)) 2)))
20)
;; not that seems to work?
(pdef :maybe-arpegio
(parp (pbind :chord (pseq (list :minor-triad :major) 2))
(pbind :note (pseq (pnary #'nchord (pk :chord)) 2))))
;; (play :maybe-arpegio)
;; (end :maybe-arpegio)
;; (stop :maybe-arpegio)
;; could I maybe now insert this into a pb
;; so that I could change speed and root for whole thing?

View File

@@ -0,0 +1,532 @@
(in-package :cl-patterns)
(pdef :maybe-arpegio
(parp (pbind :chord (pseq (list :minor-triad :major) 2))
(pbind :note (pseq (pnary #'nchord (pk :chord)) 2))))
;; (play :maybe-arpegio)
;; (end :maybe-arpegio)
;; (stop :maybe-arpegio)
(next-upto-n (pdef :maybe-arpegio) 10)
;; now about including patterns one into another, can I reference this pattern
;; in another which would specify an instrument?
;; judging by https://github.com/defaultxr/cl-patterns/blob/master/doc/patterns.org
;; maybe #'PSYM or #'PPAR would help?
(pb :legato-keys
:legato 1
:instrument :fmrhodes1)
(pdef :maybe-joined-patterns (psym (ppar (list :maybe-arpegio :legato-keys))))
;; (play :maybe-joined-patterns)
;; (end :maybe-joined-patterns)
;; (stop :maybe-joined-patterns)
;; nope, they just play in parallel, :legato-keys plays single note,
;; how would I merge them into a single pattern \ stream?
;;; maybe #'IPSTREAM ?
(pdef :attempt-2-at-joining (ipstream (list (pdef :maybe-arpegio) (pdef :legato-keys))))
;; (play :attempt-2-at-joining)
;; (stop :attempt-2-at-joining)
;; nope.
;; (and I actually can use #NEXT-UPTO-N to introspect
(next-upto-n (pdef :maybe-joined-patterns) 10)
(next-upto-n (pdef :attempt-2-at-joining) 10) ; also has EVENT :TYPE :REST inserted
;;; what about #'PMETA ?
;; nope
;;; let's check how #'PBIND works, it might just be able to extend existing patterns
;; looking at #'PBIND code I saw ":embed" key and went searching through the file
;; and found this:
;;
;;; pchain
;; :documentation Combine multiple patterns into one event stream.
;; (next-n (pchain (pbind :foo (pseq '(1 2 3))) (pbind :bar (pseq '(7 8 9) 1))) 4)
;;
;; ;=> ((EVENT :FOO 1 :BAR 7) (EVENT :FOO 2 :BAR 8) (EVENT :FOO 3 :BAR 9) NIL)
;; "see also pbind :embed key"
;;
;; So I don't know what :embed does, but pchain seems to be what I need, right?
;;
;; from the "patterns.org" : pchain - Chain patterns together by using the first source patterns output as the input to the second, etc.
;; didn't seem like the thing
;;; let's try it
(pdef :attempt-3
(pchain (pdef :legato-keys) (pdef :maybe-arpegio)))
(next-upto-n (pdef :attempt-3) 10)
;; (play :attempt-3)
;; (end :attempt-3)
;; (stop :attempt-3)
;; that's it!
;; now let's try :embed ?
(pb :attempt-4
:instrument :fmrhodes1
:legato 1
:embed :maybe-arpegio)
;; (play :attempt-4)
;; (end :attempt-4)
;; this also works, yay!
;; now, can I have several :embed arguments?
(pbind :dur 2) ; so #'PBIND "binds keys to patterns"
(pdef :with-lengths
(pbind :dur 2)) ; #'PDEF gives this name
; and takes in patterns, so can take in "pattern-constructors"
(pb :with-lengths-2
:dur 2) ; is a shorthand
; where we can use "pattern-combiners" for each key anyway
(pb :attempt-5
:instrument :fmrhodes1
:legato 1
:embed :with-lengths-2
:embed :maybe-arpegio)
;; (play :attempt-5)
;; (end :attempt-5)
;; (stop :attempt-5)
;; this also works, yay!
;; now, can I have several :embed arguments?
(next-upto-n (pdef :attempt-5) 10)
;; for some reason :dur shows up in a stream printed form, but same thing plays
;; maybe I need :embed in the beginning, so that I would overwrite it?
;; nope. I just had (play :attempt-4), so whops, more than a reason to get emacs support package
;;; It works!
;; yay.
;;; so, next? is trying to set attributes like :legato or :octave
;; per tact \ phrase regardless of how many events are there
;; maybe #'PMETA , maybe with :stepinject
;; nah?
;;
;; or maybe still arpeggio?
;; it would play first pattern until the end, but would also want the pattern of the repeating attribute to end
;; right?
;; I guess maybe as there are limits for "amount of events from stream"
;; there could be limits for "amount of clock ticks / beats"?
;; yup, pfindur
(pdef :with-with-beat-limiting (pfindur (pbind :eitght-beat-limiting t) 8))
(pb :test-limiting
:embed :with-with-beat-limiting
:dur 1/4
:degree (pwhite 0 7))
(next-upto-n (pdef :test-limiting) 30)
;; nah, what do I really want?
;; let's take the arpeggio as it is,
;; but then to 2 tacts of 1 beat per event,
;; and then 2 tacks of 1/4
(pb :try-arpeggio-with-durs
:embed :maybe-arpegio
)
;; (play :try-arpeggio-with-durs)
;; (end :try-arpeggio-with-durs)
;; (stop :try-arpeggio-with-durs)
(pbind
:dur (pseq (list 1 1/4)))
;; now that maybe done with arpeggio?
;; (next-upto-n (pdef :try-per-tact-with-parp) 20)
(next-upto-n (parp
(pbind :dur (pseq (list 1 1/2)))
(pfindur (pr (pk :dur)) 4)) 30)
;; oh, wow, yea
(pdef :durations-per-tact
(parp
(pbind :value (pseq (list 1 1/2)))
(pfindur (pr (pk :value)) 4)))
(next-upto-n (pdef :durations-per-tact) 30)
(pb :try-arpeggio-with-durations-per-tact
:instrument :fmrhodes1
:embed :maybe-arpegio
:dur (pdef :durations-per-tact)
;; :embed :durations-per-tact
)
(next-upto-n (pdef :try-arpeggio-with-durations-per-tact) 40)
;; (play :try-arpeggio-with-durations-per-tact)
;; (stop :try-arpeggio-with-durations-per-tact)
;; (end :try-arpeggio-with-durations-per-tact)
;; so, this is almost what I want?
;; with durations I'd likely want either something different, or make sure
;; that phrases can be sped up to the multiple
;;
;; but that's exactly what I want for legato?
(pb :try-arpeggio-with-legato-per-tact
:instrument :fmrhodes1
:embed :maybe-arpegio
:legato (pdef :durations-per-tact)
;; :embed :legato-per-tact
)
(next-upto-n (pdef :try-arpeggio-with-legato-per-tact) 40)
;; (play :try-arpeggio-with-legato-per-tact)
;; (stop :try-arpeggio-with-legato-per-tact)
;; (end :try-arpeggio-with-legato-per-tact)
;; oh no that's not it!
;; :durations-per-tact don't actually look at :dur of the final stream
;; but produce static
;; (1 1 1 1 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1 1 1 1 1/2 1/2 1/2 1/2 1/2 1/2 1/2
;; 1/2 1 1 1 1 1/2 1/2)
;; stream. whlp.
;; so, what if that would be for any other type of attribute, not for duration
;; then I could use pbind :dur (pk :dur) I guess,
;; and then pfindur would use duration of the embedding stream?
(pdef :try-keep-attribute-per-tact
(parp
(pbind :value (pseq (list 1 1/2)))
(pbind :dur (pfindur (pr (pk :dur)) 4))))
(next-upto-n (pdef :try-keep-attribute-per-tact) 30)
;; i think I just need to (pfindur (pr ...) 4)
;; but that's for single value
;; so if I'm keeping it too simple for stupid first step:
(pdef :abc-per-tact
(pseq (list
(pfindur (pbind :attr "a" :dur (pk :dur)) 4)
(pfindur (pbind :attr "b" :dur (pk :dur)) 4)
(pfindur (pbind :attr "c" :dur (pk :dur)) 4))
))
(next-upto-n (pdef :abc-per-tact) 30)
;; so right now this has default :dur of 1,
;; but if I :embed this into a stream with variable
(pb :trying-abc-with-different-durations
:dur 1/2
:embed :abc-per-tact)
(next-upto-n (pdef :trying-abc-with-different-durations) 30)
;; yep, that seems to work
;; now I want to not hardcode :attr, and possibly not hardcode 4
;; I don't know whether I can use actual :dur
(pb :trying-abc-with-different-durations-2
:dur (pseq (list (pfindur 1 4) (pfindur 1/2 4)))
:embed :abc-per-tact
)
(next-upto-n (pdef :trying-abc-with-different-durations-2) 30)
;; yep, that seems to work too
;; so I could probably define that :attr-per-duration with a marco
;; but is there a way to defite it with a fucntion?
;;; also, let's make our arpeggio aligned by 2 tacts in 4 measure, so 8 beats?
;; there was something that aligns with padding pauses in the end?
(pdef :maybe-arpegio-padded
(parp (pbind :chord (pseq (list :minor-triad :major) 2))
;; (pbind :note (psync (pseq (pnary #'nchord (pk :chord)) 2) 8))
(psync (pbind :note (pseq (pnary #'nchord (pk :chord)) 2)) 4)))
;; (play :maybe-arpegio-padded)
;; (end :maybe-arpegio-padded)
;; (stop :maybe-arpegio-padded)
(next-upto-n (pdef :maybe-arpegio-padded) 30)
;; (next-upto-n (psync (pseq (list 1 2 3) 6) 8) 30) ;; maybe that doesn't work because #'PSYNC need to be in context of bound stream, with :dur present?
;; that's possible
(next-upto-n (psync (pbind
:attr (pseq (list 1 2 3) 6)
:dur 1) 8) 30)
;; yup, thats it
;; so. ugh. if I have arpeggio.
;; then how do I add padding? possibly around the whole thing?
;; but then I'm loosing information about each particular chord
;;; well, now I have arpegios psync'ed to 8 beats \ 2 tacts
;; so I could try to do per tact legato
(pdef :legato-per-tact
(pseq (list
(pfindur (pbind :legato 1 :dur (pk :dur)) 8)
(pfindur (pbind :legato 0.7 :dur (pk :dur)) 8)
(pfindur (pbind :legato 0.2 :dur (pk :dur)) 8))
))
(next-upto-n (pdef :legato-per-tact) 30)
(pb :arpegio-synced-and-per-tact-legato
:embed :maybe-arpegio-padded
:embed :legato-per-tact)
;; (play :arpegio-synced-and-per-tact-legato)
;; (stop :arpegio-synced-and-per-tact-legato)
(next-upto-n (pdef :arpegio-synced-and-per-tact-legato) 30)
;;; that is kind of a solution
;; and likely mapping patterns is a thing, so I could have
;; now, let's try overwriting duration?
;;; well, current padding is still "outside" of pseq that is limited to 2 repetitions.
;; so, I'd want psync somehow inside of pseq?
;; arpegiator is like this
(next-upto-n (pseq (list 0 1 2 3) 2) 30)
;; but I want it to be 0 1 2 3 .... repeated as many times as needed to be inside of 8 beats, and padded with pauses
(next-upto-n (psync (pbind :degree (pseq (list 0 1 2 3))) 8 8 ) 30)
;; nope.
;; well, i guess maybe it's here where I'd need pmeta?
(pdef :maybe-arpegio-padded-2
(parp (pbind :chord (pseq (list :minor-triad :major) 2))
;; (pbind :note (psync (pseq (pnary #'nchord (pk :chord)) 2) 8))
(psync (pbind :note (pseq (pnary #'nchord (pk :chord)))) 8 8)))
;; (play :maybe-arpegio-padded-2)
;; (end :maybe-arpegio-padded-2)
;; (stop :maybe-arpegio-padded-2)
(next-upto-n (pdef :maybe-arpegio-padded-2) 30)
;; or maybe I need to make pseq repeat 1 time
;; and then wrap that in repeat, and then do psync over that?
(next-upto-n (psync (pn (pbind :degree (pseq (list 0 1 2) 1))) 8 8 ) 30)
;; pr - repeats each event - so 0 1 2 repeated once
;; pn - loops source pattern - so 0 1 2 0 1 2 0 1 | psynced here
;; because psync still considers per single event
;;; so the question is:
;; how can I write a pseq and have it repeating for duration,
;; taking into account durations of notes that can be set in the outer stream
;; so that repeat would end on a final note and padded rest with pause, not breaking last loop?
;;; well, while I don't know the answer, let's work with "per phrase legato"
;; just have 'breaking last loop iteration' repeat
;; and play around with durations
(pb :lets-vary-durations-in-arpegio-with-phrase-legato
:instrument :fmrhodes1
:octave 3
:embed :maybe-arpegio-padded-2
:embed :legato-per-tact
:dur 1/3
)
;; (play :lets-vary-durations-in-arpegio-with-phrase-legato)
;; (end :lets-vary-durations-in-arpegio-with-phrase-legato)
;; (stop :lets-vary-durations-in-arpegio-with-phrase-legato)
;; during the playthrough setting :dur to different 1 1/2 1/3 1/6, that's nice
;;; now let's copy things over so that all components are close together:
;; exhibit A
(defun not-perfect-but-arpeggio (chords &optional (phrase-dur 8))
(parp
(pbind :chord (pseq chords 2)) ; base for arpegio - for each chord next pattern will play out
(psync (pbind :note (pseq (pnary #'nchord (pk :chord)))) phrase-dur phrase-dur)))
(pdef :maybe-arpegio-padded-3 (not-perfect-but-arpeggio (list :major :minor)))
;; (play :maybe-arpegio-padded-3)
;; (end :maybe-arpegio-padded-3)
;; (stop :maybe-arpegio-padded-3)
;; (next-upto-n (pdef :maybe-arpegio-padded-3))
;; (next-upto-n (pdef (not-perfect-but-arpeggio (list :major :minor))) 30)
;; (next-upto-n (not-perfect-but-arpeggio (list :major :minor)) 30)
;; (next-upto-n (not-perfect-but-arpeggio (list :major :minor :minor-6th)) 30)
;; so to have patterns with arguments
;; I just need to return the pattern - pbind or another constructor from the function
;; and then bind it to the name with pdef, or just pass in to #NEXT-UPTO-N or to key in #'PB (likely, right?)
;; can I do same thing with legato per phrase?
(defun attr-per-phrase (attr-name values &optional (phrase-dur 8))
(pseq (mapcar (lambda (val) (pfindur (pbind attr-name val :dur (pk :dur)) phrase-dur phrase-dur)) values)))
(attr-per-phrase :legato (list 1 0.7 0.2))
;; #<PSEQ (#<PFINDUR (PBIND :LEGATO 1 :DUR #<PK :DUR 1>) 8 0>
;; #<PFINDUR (PBIND :LEGATO 0.7 :DUR #<PK :DUR 1>) 8 0>
;; #<PFINDUR (PBIND :LEGATO 0.2 :DUR #<PK :DUR 1>) 8 0>) :INF 0>
;; wowy, is that what I think it is?
(pb :lets-have-arpeggio-with-phrase-settings-and-vary-other-things-manually
:embed (not-perfect-but-arpeggio (list :major :minor :minor-6th :minor-7th :major-7th :major)) ; each chord plays arpeggio for whole phrase
:embed (attr-per-phrase :legato (list 1 0.7 0.2 0.8)) ; each phrase takes single value for legato
; even if amount of events in phrase change with change of :dur
:dur 1/3
)
;; (play :lets-have-arpeggio-with-phrase-settings-and-vary-other-things-manually)
;; (end :lets-have-arpeggio-with-phrase-settings-and-vary-other-things-manually)
;; (stop :lets-have-arpeggio-with-phrase-settings-and-vary-other-things-manually)
;; and now I'm limited by my understanding of chords and how to select progressions
;; also - the base for the chord! currently we only select root
;; it's maybe not as clean as have root coupled with the chord, but could add attr-per-phrase with root seleciton, that could work?
;; but! the root is in "note" mode or "degree" mode?
(pb :is-root-degree-or-note
:degree 0
:root (pseq (list 0 1 2 3 4 5 6 7) 1))
;; (play :is-root-degree-or-note)
;; (end :is-root-degree-or-note)
;; definitely degree, right?
;; so let's do arpegios for some of the chord progressions I had as whole chords?
;; i - III - iv - VI
(pb :lets-arpegio-i-III-iv-VI
:embed (not-perfect-but-arpeggio (list :minor :major :minor :major)) ; each chord plays arpeggio for whole phrase
:embed (attr-per-phrase :legato (list 1 0.7 0.2 0.8)) ; each phrase takes single value for legato
; even if amount of events in phrase change with change of :dur
:embed (attr-per-phrase :root (list 0 2 3 5))
:dur 1/4
)
;; (play :lets-arpegio-i-III-iv-VI)
;; (end :lets-arpegio-i-III-iv-VI)
;; (stop :lets-arpegio-i-III-iv-VI)
;; IV V iii vi
(pb :lets-arpegio-IV-V-iii-vi
:embed (not-perfect-but-arpeggio (list :major :major :minor :minor)) ; each chord plays arpeggio for whole phrase
:embed (attr-per-phrase :legato (list 1 0.7 0.2 0.8)) ; each phrase takes single value for legato
; even if amount of events in phrase change with change of :dur
:embed (attr-per-phrase :root (list 3 4 2 5))
:dur 1
)
;; (play :lets-arpegio-IV-V-iii-vi)
;; (end :lets-arpegio-IV-V-iii-vi)
;; (stop :lets-arpegio-IV-V-iii-vi)
;;; now, if I want a simple pase line?
;;; like taking a chord and holding it, or playing whole with simle pattern?
(next-upto-n (pdef :lets-arpegio-iv-v-iii-vi) 30)
;; well, #'not-perfect-but-arpeggio does inject :chord as an attribute
;; but if I don't merge this with base line, and only #'PPAR, then base pattern \ stream wouldn't have it
;; so, I guess I'd want to have "generic base line" that takes in a list of chords
;; and pass in same list (or maybe even a different list sometimes)
;; and well, I'd also need to pass in roots for those chords, since right now they are separate, oh well
(setq *my-chords* (list :major :major :minor :minor))
;; (setq *my-chords* (list :major :minor))
;; (setq *my-bases* (list 3 4))
(setq *my-bases* (list 3 4 2 5))
;; let's have a phrase that plays chord over base for 4 beats - 2 tacts
;; still would need parp, right?
(pb :simple-base-line
(parp
(pbind
:chord (pseq *my-chords* 2)
:root (pseq *my-bases* 2)
)
(pbind
:note (pnary #'chord-notes (pk :chord))
:dur (pseq (list 4 1/2 1/2 (prest 3)) 1)) ; that's 2 tacts
))
(pb :simple-base
:instrument :fmbass
:embed :simple-base-line
:embed (attr-per-phrase :octave (list 3 2) (* 4 2 4))) ; 4 beats per tact, 2 tacts per chord, 4 hard coded chords
;; (play :simple-base)
;; (end :simple-base)
;; (stop :simple-base)
;; other simpler way would be to make parp - with simple-base-line playing for each :octave
(next-upto-n (pdef :simple-base) 60)
;;; and yes this could also be more configurable, let's just try to combine these first
;; IV V iii vi - same 3 4 2 5 from :simple-base
(pdef :try-one-arpeggio-and-bass
(ppar (list (pdef :simple-base) (pdef :lets-arpegio-IV-V-iii-vi))))
;; (play :try-one-arpeggio-and-bass)
;; (stop :try-one-arpeggio-and-bass)
;; (end :try-one-arpeggio-and-bass)
;;; wait, so my arpeggio doesn't keep whole 2 tacts of same chord, oh, sad
;; IV V iii vi
(pb :lets-arpegio-IV-V-iii-vi
;; :instrument :strings
:embed (not-perfect-but-arpeggio (list :major :major :minor :minor) 1/4) ; each chord plays arpeggio for whole phrase
:embed (attr-per-phrase :legato (list 1 0.7 0.2 0.8)) ; each phrase takes single value for legato
; even if amount of events in phrase change with change of :dur
:embed (attr-per-phrase :root (list 3 4 2 5))
:dur 1/4
)
;; (next-upto-n (pdef :lets-arpegio-iv-v-iii-vi) 30)
;; (play :lets-arpegio-IV-V-iii-vi)
;; (end :lets-arpegio-IV-V-iii-vi)
;; (stop :lets-arpegio-IV-V-iii-vi)
;; yup, :dur 1 and :dur 1/2 still produce 8 notes for the :chord
;; exhibit B
(defun not-perfect-but-arpeggio (chords &optional (dur 1) (phrase-dur 8))
(parp
(pbind :chord (pseq chords 2)) ; base for arpegio - for each chord next pattern will play out
(psync (pbind :note (pseq (pnary #'nchord (pk :chord)))
;; :dur (pk :dur) ; looks like parent :dur here inaccessible
:dur dur
)
phrase-dur phrase-dur)))
;; and now it's worse, since need to specify durations twice
;; but should align with simple bass
;; same as before
;; IV V iii vi - same 3 4 2 5 from :simple-base
(pdef :try-one-arpeggio-and-bass
(ppar (list (pdef :simple-base) (pdef :lets-arpegio-IV-V-iii-vi))))
;; (play :try-one-arpeggio-and-bass)
;; (stop :try-one-arpeggio-and-bass)
;; (end :try-one-arpeggio-and-bass)
;;; let's try updating and rendering again?
;; (render (pdef :try-one-arpeggio-and-bass) "/tmp/arpeggio-and-bass-1.wav" :dur 16)
;; well, let' copy long recording thingy and just record already
;; https://github.com/byulparan/cl-collider#record-audio-output
;;; write a single channel to disk
;; we can write to buffer number out_buf_num by reading in from the 0 bus
;; (in-package cl-collider)
;; (defsynth disk_writer ((out_buf_num 99))
;; (disk-out.ar out_buf_num (in.ar 0)))
;; (setf mybuffer (buffer-alloc (expt 2 17)))
;; mybuffer
;; ;; start a disk_writer synth
;; (setf writer_0 (synth 'disk_writer))
;; ;; make it output to buffer you allocated
;; (ctrl writer_0 :out_buf_num (bufnum mybuffer))
;; ;; continuously write the buffer contents to a file
;; (buffer-write mybuffer "/tmp/arpeggio-and-bass.aiff" :leave-open-p t)
;; ;; now play whatever sounds you like
;; ;; e.g.
;; (in-package :cl-patterns)
;; (play :try-one-arpeggio-and-bass)
;; (stop :try-one-arpeggio-and-bass)
;; ;; then when you are done
;; (in-package cl-collider)
;; ;; stop the disk_writer synth
;; (free writer_0)
;; ;; close and free the buffer
;; (buffer-close mybuffer)
;; (buffer-free mybuffer)
;; ;; then you can play what you recorded with a utility like mpv:
;; ;; mpv /tmp/foo.aiff

View File

@@ -0,0 +1,176 @@
(in-package :cl-patterns)
(defun attr-per-phrase (attr-name values &optional (phrase-dur 8))
(pseq (mapcar (lambda (val) (pfindur (pbind attr-name val :dur (pk :dur)) phrase-dur phrase-dur)) values)))
;;; change with previous - another attempt after advice to move :dur higher in outer pattern, that this /should/ pick up (pk :dur)
;; and function wouldn't need dur argument
(defun not-perfect-but-arpeggio (chords &optional (dur 1) (phrase-dur 8))
(parp
(pbind :chord (pseq chords 2)) ; base for arpegio - for each chord next pattern will play out
(psync (pbind :note (pseq (pnary #'nchord (pk :chord)))
:dur (pk :dur) ; yes, that is picked up, if :dur is defined above :embed in the outer pattern, yay
)
phrase-dur phrase-dur)))
;; IV V iii vi
(pb :lets-arpegio-IV-V-iii-vi
:dur 1/2
:embed (not-perfect-but-arpeggio (list :major :minor)) ; each chord plays arpeggio for whole phrase (two bars)
:embed (attr-per-phrase :legato (list 1 0.7)) ; each phrase takes single value for legato
; even if amount of events in phrase change with change of :dur
:embed (attr-per-phrase :root (list 3 4))
)
;; (next-upto-n (pdef :lets-arpegio-iv-v-iii-vi) 30)
;; (play :lets-arpegio-IV-V-iii-vi)
;; (end :lets-arpegio-IV-V-iii-vi)
;; (stop :lets-arpegio-IV-V-iii-vi)
;; Now, if I have totally repeating phrases (like here)
;; I suppose it would be much better to just use PARP to set per phrase attributes?
(pb :lets-arpegio-in-arpegio
(parp (pbind
:legato (pseq (list 1 0.7))
:root (pseq (list 3 2)))
(pbind
:dur 1/3
:embed (not-perfect-but-arpeggio (list :major :minor)))))
;; I already see how this wouldn't be the same!
;; PARP would play both chords :major and :minor for setting of (:legato 1 :root 3) and then again both for setting (:legato 0.7 :root 2)
;; so ATTR-PER-PHRASE does something different
;; yup. generally it does (pseq (list (pfindur (pbind .. value ..)) ..)
;; ok!
;;; now let's clean up bass thingy?
;; pattern (list 4 1/2 1/2 (prest 3))
(defun simple-bass-line (chords strum-pattern)
(parp (pbind :chord (pseq chords 2))
(pbind
:note (pnary #'chord-notes (pk :chord)) ; repeated list of chord notes - played together
:dur (pseq strum-pattern 1))))
(pb :simple-base
:instrument :fmbass
:embed (simple-bass-line (list :major :minor) (list 4 1/2 1/2 (prest 3)))
:embed (attr-per-phrase :root (list 3 2) 8)
:embed (attr-per-phrase :octave (list 3 2) (* 4 2 2))) ; 4 beats per tact, 2 tacts per chord, 2 hard coded chords
(next-upto-n (pdef :simple-base) 40)
;; (play :simple-base)
;; (end :simple-base)
;; (stop :simple-base)
(pdef :new-arpegio-and-bass-1
(ppar (list :lets-arpegio-iv-v-iii-vi :simple-base)))
;; (play :new-arpegio-and-bass-1)
;; (end :new-arpegio-and-bass-1)
;; (stop :new-arpegio-and-bass-1)
;;; notes:
;; arpegio hardcodes 2 repetitions
;; base hardcodes now 2 repetiitons as well, to match with :octave change thing
;; also #'SIMPLE-BASE-LINE could just take in pattern for strum-pattern,
;; not list to be used in #'PSEQ
;;; ok! now let's do 4 bars of same, then 4 bars with 1/3 duration in arpeggios
;; IV V iii vi
;; (setq *my-chords* (list :major :major :minor :minor)
;; *my-roots* (list 3 4 2 5))
;; for now will set in 09-11.lisp
(pb :lets-arpegio-before-duration
:embed (not-perfect-but-arpeggio *my-chords*) ; each chord plays arpeggio for whole phrase (two bars)
:embed (attr-per-phrase :root *my-roots*)
:embed (attr-per-phrase :legato (list 1 0.8 0.6 0.9)) ; each phrase takes single value for legato
; even if amount of events in phrase change with change of :dur
)
;; (next-upto-n (pdef :lets-arpegio-iv-v-iii-vi) 30)
;; (play :lets-arpegio-IV-V-iii-vi)
;; (end :lets-arpegio-IV-V-iii-vi)
;; (stop :lets-arpegio-IV-V-iii-vi)
(pb :arpegio-in-halves
:dur 1/2
:embed :lets-arpegio-before-duration)
(pb :arpegio-in-thirds
:dur 1/4
:embed :lets-arpegio-before-duration)
;; (play :arpegio-in-halves)
;; (stop :arpegio-in-halves)
;; (play :arpegio-in-thirds)
;; (stop :arpegio-in-thirds)
(pb :simple-base-2
:instrument :fmbass
:embed (simple-bass-line *my-chords* (list 4 1/2 1/2 (prest 3)))
:embed (attr-per-phrase :root *my-roots* 8)
:embed (attr-per-phrase :octave (list 3 2) (* 4 2 4))) ; 4 beats per tact, 2 tacts per chord, 4 hard coded chords
(next-upto-n (pdef :simple-base-2) 40)
;; (play :simple-base-2)
;; (end :simple-base-2)
;; (stop :simple-base-2)
;; now. I want 8 bars of base, and 8 bars of arp-in-halves
;; then another 8 bars of base and 8 bars of arp-in-thirds
(pb :arpegios-one-after-another
(pseq (list (pdef :arpegio-in-halves) (pdef :arpegio-in-thirds)) 1))
;; (play :arpegios-one-after-another)
;; (end :arpegios-one-after-another)
;; (stop :arpegios-one-after-another)
(pb :arpegios-and-bass
(ppar (list :arpegios-one-after-another (pn (pdef :simple-base-2) 2))))
;; (play :arpegios-and-bass)
;; (end :arpegios-and-bass)
;; (stop :arpegios-and-bass)
;;; note - and through all of this I'm forgetting about :quant setting
;; that would help align patterns if I start \ end them manually
;; now let's record this and share and get on with the day
;; well, let' copy long recording thingy and just record already
;; https://github.com/byulparan/cl-collider#record-audio-output
;;; write a single channel to disk
;; we can write to buffer number out_buf_num by reading in from the 0 bus
;; (in-package cl-collider)
;; (defsynth disk_writer ((out_buf_num 99))
;; (disk-out.ar out_buf_num (in.ar 0)))
;; (setf mybuffer (buffer-alloc (expt 2 17)))
;; mybuffer
;; ;; start a disk_writer synth
;; (setf writer_0 (synth 'disk_writer))
;; ;; make it output to buffer you allocated
;; (ctrl writer_0 :out_buf_num (bufnum mybuffer))
;; ;; continuously write the buffer contents to a file
;; (buffer-write mybuffer "/tmp/two-arpeggios-and-bass.aiff" :leave-open-p t)
;; ;; now play whatever sounds you like
;; ;; e.g.
;; (in-package :cl-patterns)
;; (play :arpegios-and-bass)
;; (end :arpegios-and-bass)
;; ;; then when you are done
;; (in-package cl-collider)
;; ;; stop the disk_writer synth
;; (free writer_0)
;; ;; close and free the buffer
;; (buffer-close mybuffer)
;; (buffer-free mybuffer)
;; ;; then you can play what you recorded with a utility like mpv:
;; ;; mpv /tmp/foo.aiff

View File

@@ -0,0 +1,232 @@
;;; today I'd like to do bass arpegios, with high chords
;; and maybe drums for both parts (from 09-09)
;; and join them?
;; IV V iii vi
;; (setq *my-chords* (list :major :major :minor :minor)
;; *my-roots* (list 3 4 2 5))
;; (setq *my-chords* (list :major)
;; *my-roots* (list 3))
;; Am F C G (i VI III VII)
;; (setq *my-chords* (list :minor :major :major :major)
;; *my-roots* (list 0 3 2 6))
;; i - III - iv - VI
(setq *my-chords* (list :minor :major :minor :major)
*my-roots* (list 0 2 3 5))
(in-package :cl-patterns)
(start-clock-loop :tempo 90/60 :force t)
(pb :lets-slow-bass-arpegio
:dur 2
:octave 3
;; :instrument :fmbass
:embed (not-perfect-but-arpeggio *my-chords*)
:embed (attr-per-phrase :root *my-roots*)
)
;; (play :lets-slow-bass-arpegio)
;; (stop :lets-slow-bass-arpegio)
;; well, what if I rather take my simple-bass thing
;; and give it some kind of slow pattern
;; nope, that simple-bass plays whole chords
;;
;; at this point I'm just tempted to not use chords,
;; and have a PARP
(pdef :chord-defs
(pbind :chord (pseq *my-chords* 1)
:chord-base (pseq *my-roots* 1)))
(pb :lets-slow-bass-melody
(parp
(pdef :chord-defs)
(pbind :step (pseq (list 0 1 0 1 2 0 1 2) 1)
:dur (pseq (list 1/4 1/4 1 1 1 1 1 5/2) 1)
;; :note (pfunc (lambda ()
;; (event-value *event* :step)))
:note (pfunc (lambda ()
(+ (event-value *event* :chord-base)
(nth (event-value *event* :step)
(chord-notes (event-value *event* :chord))))))
)))
;; (next-upto-n (pdef :lets-slow-bass-melody) 10)
;; (play :lets-slow-bass-melody)
;; (end :lets-slow-bass-melody)
;; (stop :lets-slow-bass-melody)
(pb :embedding-bass-melogy-into-pattern
(pseq (list (pbind
:quant 4
:dur (pseq (list (prest 7/2)) 1))
(pbind
:octave 2 ; let's add these later? when join both?
:instrument :fmbass
:embed :lets-slow-bass-melody))
1))
(next-upto-n (pdef :embedding-bass-melogy-into-pattern) 20)
;; (play :embedding-bass-melogy-into-pattern)
;; (stop :embedding-bass-melogy-into-pattern)
;; (end :embedding-bass-melogy-into-pattern)
;; now. let's brainstorm the pattern on a single chord?
;; and well, my guess is that pattern should start from 1/2 before tha bar start?
;; so is there a "timer shift" for pattern?
;; if I can only align by quant
;; ( upbeat ? )
;; well 3 6 9 - and we have -1 +2 and +1 over the quant :4
;; ok, let's for not simulate that stuff by writing continuous bass melody
;; and adding 3 1/2 rest in the beginning
;; I'd like to add bottom note repeating at 1/2 ?
;;; let's just do same? quant 4, wait for the upbeat of next bar
;;; and start playing 1/2 8 times?
(pb :lets-slow-bass-melody-root-repeating
(pseq (list (pbind :dur (pseq (list (prest 4)) 1)
:quant 4)
(parp
(pdef :chord-defs)
(pbind
:octave 1
:instrument :fmbass
:dur (pseq (list (prest 5/2) (pfindur 1/2 7/2) (prest 2)) 1)
:legato 0.5
:note (pk :chord-base)))
(pbind :dur (pseq (list (prest 1)) 1)))
1))
(next-upto-n (pdef :lets-slow-bass-melody-root-repeating) 20)
;; (play :lets-slow-bass-melody-root-repeating)
;; (end :lets-slow-bass-melody-root-repeating)
;; (stop :lets-slow-bass-melody-root-repeating)
(pdef :full-bass-melody
(ppar (list :embedding-bass-melogy-into-pattern :lets-slow-bass-melody-root-repeating)))
;; (play :full-bass-melody)
;; (stop :full-bass-melody)
;; yay, not sure whether I want :octave 1 or 2, but overall, cool,
;; even though - so much still to learn to not have to do manual calculaitons of prest and such
;; let's have some kind of light chord holding. not sure what I want, maybe default
;; maybe strings? or pluck
(pb :high-chords-hold
:embed :chord-defs
:instrument :tone-buzz
:dur 8
:quant 4
:amp 0.05
:note (p+ (pk :chord-base) (pnary #'chord-notes (pk :chord))))
(next-upto-n (pdef :high-chords-hold) 30)
;; (play :high-chords-hold)
;; (end :high-chords-hold)
;; (stop :high-chords-hold)
(pb :high-chords-with-pre-bar
(pseq (list
(pbind :dur (pseq (list (prest 4)) 1)) ; most awkward thing
(pdef :high-chords-hold))
1))
(pdef :total-base-section
(ppar (list :full-bass-melody :high-chords-with-pre-bar)))
;; (play :total-base-section)
;; (stop :total-base-section)
;; well, it seems that with restarts defsynts of fmbass start playing worse?
;; responding less and less to short notes and legato?
;; is that due to not restarting sbcl?
;; let's try full restart
;;; I've done full restart, didn't totally help.
;; and I've set slower clock speed
;;; now, let's add intro, connection and ending?
(pb :intro
:embed :chord-defs
:dur (pseq (list 2 2 4) 1)
:instrument :strings
:amp 0.1
:note (p+ (first *my-roots*) (pnary #'chord-notes (first *my-chords*))))
;; (play :intro)
;; (stop :intro)
;; (end :intro)
;; idea for not now - third chord make in two octaves?
;;; maybe add a scratch inbetween?
(pb :phrase-connection
:instrument :fmbass
:dur (pseq (list (prest 2) 12 (prest 4)) 1)
:embed :chord-defs
:octave 2
:note (p+ (first *my-roots*) (pnary #'chord-notes (first *my-chords*)))
)
;; (play :phrase-connection)
;; (stop :phrase-connection)
;;; for this to work, also evaluate ~/Documents/personal/common-lisp-study/music/dirty-journal/2022-09-09-maybe-cleanup-bass-from-chords.lisp
;; maybe later on cleanup I'd put everything into same file
(pdef :is-that-first-experiment
(pseq (list (pdef :intro)
(pdef :total-base-section)
(pdef :phrase-connection)
(pdef :arpegios-and-bass))
1))
;; (play :is-that-first-experiment)
;; (stop :is-that-first-experiment)
;; (end :is-that-first-experiment)
;; welp, when notes are too quick, they are not produced
;; and I also kind of wanted a percussion line, but oh well
;; ;;; ok, let's record that,
;; ;; we can write to buffer number out_buf_num by reading in from the 0 bus
;; (in-package cl-collider)
;; (defsynth disk_writer ((out_buf_num 99))
;; (disk-out.ar out_buf_num (in.ar 0)))
;; (setf mybuffer (buffer-alloc (expt 2 17)))
;; mybuffer
;; ;; start a disk_writer synth
;; (setf writer_0 (synth 'disk_writer))
;; ;; make it output to buffer you allocated
;; (ctrl writer_0 :out_buf_num (bufnum mybuffer))
;; ;; continuously write the buffer contents to a file
;; ;; ;; IV V iii vi
;; ;; Am F C G (i VI III VII)
;; ;; i - III - iv - VI
;; (buffer-write mybuffer "/tmp/first-experiment-i-III-iv-VI.aiff" :leave-open-p t)
;; ;; now play whatever sounds you like
;; ;; e.g.
;; (in-package :cl-patterns)
;; (play :is-that-first-experiment)
;; (stop :is-that-first-experiment)
;; (end :is-that-first-experiment)
;; ;; then when you are done
;; (in-package cl-collider)
;; ;; stop the disk_writer synth
;; (free writer_0)
;; ;; close and free the buffer
;; (buffer-close mybuffer)
;; (buffer-free mybuffer)
;; ;; then you can play what you recorded with a utility like mpv:
;; ;; mpv /tmp/foo.aiff

View File

@@ -0,0 +1,171 @@
(in-package #:cl-patterns)
;; i want to get arpeggios of configurable speed
;; and configured by chord
;; and configured by places of notes in a chord
;; let's again first do consecutive notes from a chord
;; idea is to have
;; a) endless loop of notes from a chord
;; b) have pdurstutter - for the duration of desired arpeggio, with maybe figuring out to make each part of stutter into a separate item in arpeggio
(all-chords)
(chord-notes (chord "Minor 7th"))
(pdef :at-first-chords
(pbind :note (pseq (chord-notes (chord "Minor 7th")))))
;; (play :at-first-chords)
;; (stop :at-first-chords)
(pdef :initial-stutter
(pdurstutter (pbind
:dur (pseq (list 4) 1)) 16))
;; (play :initial-stutter)
;; (end :initial-stutter)
;; (stop :initial-stutter)
(pb :initial-combination
;; :embed :initial-stutter
;; :arpeggio-chord :minor-6th
:dur (pdurstutter (pseq (list 4) 1) 16)
:note (pseq (pnary #'chord-notes (pk :arpeggio-chord)))
)
;; (next-upto-n (pdef :initial-combination) 32)
;; (play :initial-combination)
;; (end :initial-combination)
;; (stop :initial-combination)
(chord-notes :minor-6th)
;; now do arpegio pattern to play arpegio per each chord?
(pb :with-changing-chords
(parp
(pbind :arpeggio-chord (pseq (list :minor-6th :minor :minor-7th :minor)))
(pdef :initial-combination)))
;; (next-upto-n (pdef :with-changing-chords) 40)
;; (play :with-changing-chords)
;; (stop :with-changing-chords)
;; that's kind of ok if chords have same amount of notes in it?
(mapcar #'chord-notes (list :minor-6th :minor :minor-7th :minor))
(chord :major)
;; would it be better if it's all in single def?
(pb :with-changing-chords-2
(parp
(pbind :arpeggio-chord (pseq (list :major :minor :major :minor) 1)
:chord-root (pseq (list 0 3 2 6) 1))
(pbind
:dur (pdurstutter (pseq (list 4) 1) 24)
:note (pseq (p+ (pk :chord-root) (pnary #'chord-notes (pk :arpeggio-chord)))))))
;; (play :with-changing-chords-2)
;; (end :with-changing-chords-2)
;; now I could use stats of the :arpeggio-chord in the :dur part
;; i guess i'd like to what?
;; to be adding root of the chord
;; and then pattern to be played over the chord
;; let's first make simple endless pattern that takes list of steps, and takes them out of chord-notes
(pb :initial-patterned
:pattern (list 0 1 2 0 3)
:note (pnary (lambda (a) (nth a (chord-notes :major-7th))) (pseq (pk :pattern))))
(next-upto-n (pdef :initial-patterned) 20)
;; (play :initial-patterned)
;; (stop :initial-patterned)
;; and now i want what? i want to do pnary? pfunc
(pb :with-patterned-changing-chords
(parp
;;; first part of parp is "base values" for each event whole second pattern will be played
;;; so this pattern produces "settings for each phrase"
(pbind :arpeggio-chord (pseq (list :minor-6th :minor :minor-7th :minor))
:chord-root (pseq (list 0 3 2 6) 1)
:pattern (list 0 1 2 1 2 1 2 0))
;;; this patten would play our fully with settings values
(pbind
:note (pnary (lambda (chord-step chord chord-root)
(+ chord-root (nth chord-step (chord-notes chord))))
(pseq (pk :pattern))
(pk :arpeggio-chord)
(pk :chord-root))
:dur (pdurstutter (pseq (list 8) 1) 32))))
;; (next-upto-n (pdef :with-patterned-changing-chords) 30)
;; (play :with-patterned-changing-chords)
;; (stop :with-patterned-changing-chords)
;; next I'd probably want to what? somehow align chords that have 3 \ 4 \ 5 notes in them
;; not sure what could be done though logically
;; we could have different patterns, based on chord size, yup
(pb :instrumented-play
:instrument :fmbass
:legato 0.5
:octave 2
:embed :with-patterned-changing-chords)
;; (play :instrumented-play)
;; (end :instrumented-play)
;; i guess next is making this pattern a function that takes patterns to provice chords, roots and pattrn
;; then could use embed and set attributes in place
;; this is actually fun
(defun patterned-arpeggio (chords roots patterns &optional (chord-duration 8) (events-in-chord 32))
(parp
;;; first part of parp is "base values" for each event whole second pattern will be played
;;; so this pattern produces "settings for each phrase"
(pbind :arpeggio-chord chords
:chord-root roots
:pattern patterns)
;;; this patten would play our fully with settings values
(pbind
:note (pnary (lambda (chord-step chord chord-root)
(+ chord-root (nth chord-step (chord-notes chord))))
(pseq (pk :pattern))
(pk :arpeggio-chord)
(pk :chord-root))
:dur (pdurstutter (pseq (list chord-duration) 1) events-in-chord))))
(pb :first-try-of-function
:instrument :fmbass
:legato 0.5
:octave 2
:embed (patterned-arpeggio
(pseq (list :minor-6th :minor :minor-7th :minor))
(pseq (list 0 3 2 6) 1)
(list 0 1 2 1 2 1 2 0)))
;; (play :first-try-of-function)
;; (end :first-try-of-function)
;; taking progressions from
;; https://en.wikipedia.org/wiki/List_of_chord_progressions
(pb :second-try-of-function
:instrument :fmbass
:legato 0.5
:octave 2
:embed (patterned-arpeggio
(pseq (list :major :minor :major :major))
(pseq (list 0 5 3 4) 1)
(list 0 1 2 1 2 1 2 0)
2 8))
;; (play :second-try-of-function)
;; (end :second-try-of-function)
;; andalusian cadence iv-III-II-I
(pb :third-try-of-function
;; :instrument :fmbass
;; :instrument :strings
:instrument :prophet5pwmstrings
:legato 1
:octave 5
:embed (patterned-arpeggio
(pseq (list :minor :major :major :major))
(pseq (list 3 2 1 0) 1)
(list 0 1 2 1 2 1 2 0)
;; 2 16
8 16
))
;; (play :third-try-of-function)
;; (stop :third-try-of-function)

View File

@@ -290,10 +290,6 @@ with fixed synthdefs
** tried synths in a pattern and they work!
even though they don't stop on their own,
so maybe `gate` is a default argument that passes control from the pattern system, using `dur`
** NEXT - learn more about puttin melodies in, midinotes and stuff
what I want is "pitch model"
http://doc.sccode.org/Tutorials/Streams-Patterns-Events5.html
** NEXT - how to keep same note pattern repeating with different settings of legato \ duration
* [2022-09-04 Sun]
** evil marcro for wrapping consecutive values (or args) into pairwise brackets:
well, not being inserted due to backspace, sad
@@ -318,3 +314,117 @@ Example:
is that pause?
but why would event then still have :DEGREE attribute?
* [2022-09-05 Mon]
** let's what? move instruments into separate organized files?
meh, let's try for arpeggio from chords?
or something
** DONE - learn more about puttin melodies in, midinotes and stuff
what I want is "pitch model"
http://doc.sccode.org/Tutorials/Streams-Patterns-Events5.html
:degree - is from an octave, and :octave 5 default and quite high, :root is which octave to take
** DONE - how to keep same note pattern repeating with different settings of legato \ duration
I'll try to define notes separately with pdef and insert it? would then single length would be for all?
** so, I tried to figure out how to change parameters for whole "phrases"
"automatic jazz" does that with getting new random value, that gets repeated "forever" until the end of the pattern
if I try to use not random, but "from sequence", then on pattern restart I'd get first element of the sequence every time.
so then "kind of working" solution, is keep melogy repeating,
then - know what is the length of the melody and repeat for "amount of events" in the melody,
* [2022-09-08 Thu]
** one day I'll move all instruments into easy to evaluate \ import \ use package
but not today? because I don't yet too comfortable with the concept of Common-Lisp packages
** and today?
*** TODO get more code on creating arpeggios by specifying chords
not quite, but yeah
*** DONE and maybe how to combine \ merge \ include patterns
so that chord pattern is defined separately and merged into separate patterns for base \ melogy
one convenient way to do it is to use :embed key in the pdef
#+begin_src common-lisp
(pb :with-lengths-2
:dur 2)
(pb :attempt-5
:instrument :fmrhodes1
:legato 1
:embed :with-lengths-2)
(next-upto-n (pdef :attempt-5) 10)
#+end_src
and there can be several :embed's yay
another pay is #'PCHAIN
judging by documentation it's very similar, not sure when it would be more convenient
#+begin_src common-lisp
(pdef :attempt-3
(pchain (pdef :legato-keys) (pdef :maybe-arpegio)))
(next-upto-n (pdef :attempt-3) 10)
#+end_src
*** DONE also - maybe I'd learn about setting parameters "per tact" and not "per event"
- I already guess that it would be infinitely repeating pattern that somehow aligns by beat number, maybe?
then we'd get emitting for example :legato for each event in a tact regardless of it being 1 or 1/16s
I think something similar I saw at #'PMETA, like connecting patterns with some kind of measuring
kind of have some kind of solution here
** so what was going on today:
*** :embed - in pb
if I have separate stream \ patter with some of the values
I can "include" it into currently defined stream.
so for example notes and durations are saved under :melody-pattern
and other patterns embed it and specify own :instrument and :octave
[[file:2022-09-08-more-on-chord-melodies.lisp::(pb :attempt-5]]
*** trying "attribute per tact" - with PARP - arpegio
**** starting with durations per tact:
[[file:2022-09-08-more-on-chord-melodies.lisp::(pdef :durations-per-tact]]
not quite
**** then attribute per tact:
[[file:2022-09-08-more-on-chord-melodies.lisp::(pdef :abc-per-tact]]
**** the simplest hardcoded version
and with :legato
[[file:2022-09-08-more-on-chord-melodies.lisp::(pdef :legato-per-tact]]
**** to probably what I want?
[[file:2022-09-08-more-on-chord-melodies.lisp::defun attr-per-phrase (attr-name values &optional (phrase-dur 8)]]
*** also wanted to "pad" arpeggio, so that it would fill full two tacts, but only have complete loop iterations
in that I didn't succeed
having PSYNC around PSEQ - inner pattern started last incomplete iteration instead of producing rest
**** initial implementation also didn't fill two tacts
[[file:2022-09-08-more-on-chord-melodies.lisp::defun not-perfect-but-arpeggio (chords &optional (phrase-dur 8)]]
in it the #'PSYNC didn't really work because it was around pattern that didn't have :dur
**** next iteration that starts unfinished last loops
[[file:2022-09-08-more-on-chord-melodies.lisp::defun not-perfect-but-arpeggio (chords &optional (dur 1) (phrase-dur 8)]]
but I have to pass in :dur,
so in pattern I currently have to change it in two places.
seems that "parent" pattern is inaccessible with (pk :dur)
- note: I somewhere read phrase "parent pattern", so possibly in some #'PFUNC or #'PNARY
maybe I could access attributes of a pattern that :embed this one
** what I want next - clean up defsynths, clean up arpegio thing, bass thing
maybe put everything under "dirty-journal" directory
and start a "clean" journal
* [2022-09-09 Fri]
** let's move everything into "dirty-journal"
* [2022-09-11 Sun]
** so, today I've been writing bass arpeggios
** biggest questin - upbeat before first bar,
how to effectively write that?
so that it would be easy to sync things on :quant
** thing I found out -
it would be nice to specify chords and chord-bases as a pattern
to be embedded
that way I'd be able to switch it up on the go and all patterns extending it would pick it up?
well, maybe not all at the same time, if they are not synched =C
** would be nice to put everything of 09-09 and 09-11 into single file
to make it easier to restart whole first experiment with different chords
also, have I saved a link to the side where I saw the chord progressions I used?
also-also having a keyboard could be a nice help

View File

@@ -0,0 +1,4 @@
(in-package :cl-patterns)
(defun nchord (symbol &optional (base 0))
"Return list of notes for chord names by SYMBOL over the BASE."
(mapcar (lambda (note) (+ base note)) (chord-notes (chord symbol))))

View File

@@ -1,4 +1,3 @@
;; https://defaultxr.github.io/cl-collider-tutorial/02-getting-started.html
(ql:quickload :cl-collider)
@@ -8,6 +7,7 @@
(server-boot *s*) ; already in use
(ql:quickload :cl-patterns)
(ql:quickload :cl-patterns/supercollider)
;; ...this will take care of loading cl-collider for you if it's not already loaded.

View File

@@ -0,0 +1,170 @@
(in-package #:cl-collider)
;;; keys
(defsynth FMRhodes1 ((out 0) (freq 440) (gate 1) (pan 0) (amp 0.1) (att 0.001) (rel 1) (lfoSpeed 4.8) (inputLevel 0.2)
(modIndex 0.2) (mix 0.2) (lfoDepth 0.1)) ;; all of these range from 0 to 1
(let* ((env1 (env-gen.kr (perc att (* rel 1.25) inputLevel :lin)))
(env2 (env-gen.kr (perc att rel inputLevel :lin)))
(env3 (env-gen.kr (perc att (* rel 1.25) inputLevel :lin)))
(env4 (env-gen.kr (perc att (* rel 1.25) inputLevel :lin)))
(osc4 (* (sin-osc.ar freq) 6.7341546494171 modIndex env4))
(osc3 (* (sin-osc.ar (* freq 2) osc4) env3))
(osc2 (* (sin-osc.ar (* freq 30)) 0.683729941 env2))
(osc1 (* (sin-osc.ar (* freq 2)) env1))
(snd-step-1 (+ (mix (* osc3 (- 1 mix))) (* osc1 mix)))
(snd-step-2 (* snd-step-1 (range (sin-osc.ar lfoSpeed) (- 1 lfoDepth) 1)))
(snd-step-3 (* snd-step-2 (env-gen.kr (asr 0 1 0.1) :gate gate :act :free)))
(snd-step-4 (pan2.ar snd-step-3 pan amp)))
(out.ar out snd-step-4)))
;;; strings
(defsynth tone-pluck ((freq 440) (amp 0.2))
(out.ar 0 (* (saw.ar (let ((detune (* freq 0.01)))
(list (- freq detune) (+ freq detune))))
(env-gen.kr (perc 0.1 1.8)
:level-scale amp
:act :free))))
(defsynth prophet5pwmStrings ((out 0) (pan 0.0) (freq 440) (amp 1.0) (gate 1) (att 0.01)
(rel 0) (sus 1) (dec 0.5) (lforate 10) (lfowidth 0.5) (cutoff 12000) (rq 0.5))
(let* ((lfo (lf-tri.kr (mapcar (lambda (x) (* lforate x)) (list 1 1.01)) (make-list 2 :initial-element (rand.ir 0 2.0))))
(pulse (pulse.ar (mapcar (lambda (x) (* freq x)) (list 1 1.01)) (+ (* lfo lfowidth) 0.5)))
(filter (rlpf.ar pulse cutoff rq))
(env (env-gen.ar (adsr att dec sus rel amp) :gate gate :act :free)))
(out.ar out (pan2.ar (* (mix filter) env 0.5) pan))))
(defsynth strings ((out 0) (freq 440) (amp 1) (gate 1) (pan 0) (freqLag 0.2) (att 0.001) (dec 0.1) (sus 0.75) (rel 0.3)
(rq 0.001) (combHarmonic 4) (sawHarmonic 1.5) (mix 0.33))
(let* ((combFreq (/ 1 (* (lag.kr freq (/ freqLag 2)) combHarmonic)))
(envelope (env-gen.kr (adsr att dec sus rel amp) :gate gate :act :free))
(snd-step-1 (sync-saw.ar (* freq (range (white-noise.kr) (/ 1 1.025) 1.025)) (* freq sawHarmonic) 8))
(snd-step-2 (+ (* snd-step-1 (- 1 mix)) (pink-noise.ar (* 180 mix))))
(snd-step-3 (comb-l.ar snd-step-2 combFreq combFreq -1)) ; try 1 for decay as well
(snd-step-4 (abs (resonz.ar snd-step-3 (lag.kr freq freqLag) rq)))
(snd-step-5 (* snd-step-4 envelope))
(snd-step-6 (limiter.ar snd-step-5 amp)))
(out.ar out (pan2.ar snd-step-6 pan))))
(defsynth violin ((freq 440) (gate 1) (amp 1) (pan 0) (out 0) (att 0.1) (dec 0.1) (sus 0.5) (rel 0.1)
(vRate 4.6) (vDepth 0.02) (vAtt 0.15) (vRateVar 0.25) (vDepthVar 0.05)
(pwmVarRate 2) (pwmMin 0.7) (pwmMax 0.8) (pwmRate 5)
(bridgeFreq 2500) (scratchDepth 0.15))
(let* ((scratch (+ 1.025 (env-gen.kr (perc att (* 1.25 dec) scratchDepth))))
(envelope (env-gen.kr (adsr att dec sus rel) :gate gate :act :free))
(freq (vibrato.kr freq vRate vDepth (+ att dec) vAtt vRateVar vDepthVar))
(pwm-step-1 (range (sin-osc.kr pwmRate (rand.ir 0.0 1.0)) pwmMin pwmMax))
(pwm-step-2 (* pwm-step-1 (range (lf-noise2.kr pwmVarRate) 0.2 0.8)))
(snd-step-1 (var-saw.ar (*
(lag.kr freq)
(range (lf-pulse.ar (* freq 1.5)) (/ 1 scratch) scratch))))
(snd-step-2 (+ (* snd-step-1 0.7)
(bpf.ar snd-step-1 bridgeFreq 2 2)))
(snd-step-3 (* snd-step-2 amp envelope)))
(out.ar out (pan2.ar snd-step-3 pan))))
;;; percussion
(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 bdrum ((amp 0.5) (out 0) )
(out.ar out (* amp (sin-osc.ar (line.ar 120 60 1) 0 (env-gen.ar (env (list 0 1 0) (list 0.005 0.5)) :act :free)))))
(defsynth snare ((amp 0.5) (out 0))
(out.ar out (* amp (white-noise.ar (env-gen.ar (env (list 0 1 0.3 0) (list 0.005 0.01 0.5)) :act :free)))))
(defsynth hihat ((amp 0.5) (out 0))
(out.ar out (* amp (hpf.ar (white-noise.ar 1) 10000) (env-gen.ar (env (list 0 1 0) (list 0.005 0.5)) :act :free))))
;;; bass
(defsynth acid0to3091 ((amp 0.5) (out 0) (gate 1) (freq 440) (pan 0) (att 0.001) (dec 0.5) (sus 0.1) (rel 0.5) (curve -4) (lagTime 0.12) (filterRange 6) (width 0.51) (rq 0.3))
(let* ((freq (lag.kr freq lagTime))
(ampEnv (env-gen.kr (adsr att dec sus rel amp 0) :gate gate))
(filterEnv (env-gen.kr (adsr att (* 2 dec) (/ sus 2) (* 2 rel) (expt 2 filterRange) (list (* -1 curve) curve curve) 1) :gate gate :act :free))
(sndStep1 (range (lf-pulse.ar freq 0.0 width) -1 1))
(sndStep2 (rlpf.ar sndStep1 (* freq filterEnv) rq))
(sndStep3 (* sndStep2 ampEnv)))
(out.ar out (pan2.ar sndStep3 pan))))
(defsynth fmBass ((out 0) (freq 440) (gate 1) (amp 0.5) (pan 0) (att 0.01) (dec 0.3) (sus 0.4) (rel 0.1) (slideTime 0.17) (cutoff 1100) (width 0.15) (detune 1.005) (preamp 4))
(let* ((env (env-gen.kr (adsr att dec sus rel) :gate gate :act :free))
(freq (lag.kr freq slideTime))
(sndStep1 (var-saw.ar (list freq (* freq detune)) 0 width preamp))
(sndStep2 (distort (mix sndStep1)))
(sndStep3 (* sndStep2 env))
(sndStep4 (lpf.ar sndStep3 cutoff amp)))
(out.ar out (pan2.ar sndStep4 pan))))
;;; air
;; doesn't seem to work, right?
(defsynth waveguideFlute ((scl 0.2) (freq 440) (ipress 0.9) (ibreath 0.09) (ifeedbk1 0.4) (ifeedbk2 0.4)
(dur 1) (gate 1) (amp 2))
(let* ((sr (sample-rate.ir))
(cr (control-rate.ir))
(a-block (reciprocal cr))
(ifqc freq)
(kenv1 (env-gen.kr (env
(list 0.0 (* 1.1 ipress) ipress ipress 0.0)
(list 0.06 0.2 (- dur 0.46) 0.2)
:linear))) ; noise envelope
(kenv2 (env-gen.kr (env
(list 0.0 amp amp 0.0)
(list 0.1 (- dur 0.2) 0.1)
:linear))) ; overall envelope
(kenvibr (env-gen.kr (env
(list 0.0 0.0 1 1 0.0)
(list 0.5 0.5 (- dur 1.5) 0.5)
:linear))) ; vibrato envelope
(aflow1 (lf-clip-noise.ar sr kenv1)) ; create air flow and vibrato
(kvibr (sin-osc.ar 5 0 (* 0.1 kenvibr)))
(asum1 (+ (* ibreath aflow1) kenv1 kvibr))
(afqc (+ (reciprocal ifqc) (/ ifqc 12000000) (- (/ asum1 20000)) (- (/ 9 sr)) (- a-block)))
(fdbckArray (local-in.ar 1))
(aflute1 fdbckArray)
(asum2 (+ asum1 (* aflute1 ifeedbk1)))
(ax (delay-c.ar asum2
(- (reciprocal ifqc) (* a-block 0.5)) ; original has strange asum1/ifqc/cr thing, is that consequtive division, or third is on top?
(* afqc 0.5)))
(apoly (- ax (cubed ax)))
(asum3 (+ apoly (* aflute1 ifeedbk2)))
(avalue (lpf.ar asum3 2000))
(aflute2 (delay-c.ar avalue (- (reciprocal ifqc) a-block) afqc))
(fdbckArray (list aflute2))
;; (no-name (local-out.ar fdbckArray)) ; does that work at all? are there side effects?
(signalOut avalue))
(local-out.ar fdbckArray)
(offset-out.ar 0 (list (* signalOut kenv2) (* signalOut kenv2)))))
;;; simplistic
(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 tone-buzz ((freq 440) (amp 0.2) (gate 1))
(out.ar 0 (*
(saw.ar (let ((detune (* freq 0.01)))
(list (- freq detune) (+ freq detune)))
(/ amp 2))
(env-gen.kr (asr 0 1 0.1) :gate gate :act :free))))
(defsynth tone-pluck ((freq 440) (amp 0.2))
(out.ar 0 (* (saw.ar (let ((detune (* freq 0.01)))
(list (- freq detune) (+ freq detune))))
(env-gen.kr (perc 0.1 1.8)
:level-scale amp
:act :free))))
(defsynth sine-wave ((note 60) (freq 400))
(let* ((freq (midicps note))
(sig (sin-osc.ar freq 0 .2)))
(out.ar 0 sig)))