533 lines
20 KiB
Common Lisp
533 lines
20 KiB
Common Lisp
|
||
(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 pattern’s 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
|