more arpeggio, per-phrase-attr

This commit is contained in:
efim 2022-09-08 15:28:08 +00:00
parent 12f0c80af7
commit 788c27c54b
2 changed files with 608 additions and 1 deletions

View File

@ -0,0 +1,533 @@
(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

@ -322,7 +322,7 @@ or something
what I want is "pitch model" what I want is "pitch model"
http://doc.sccode.org/Tutorials/Streams-Patterns-Events5.html 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 :degree - is from an octave, and :octave 5 default and quite high, :root is which octave to take
** NEXT - how to keep same note pattern repeating with different settings of legato \ duration ** 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? 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" ** 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 "automatic jazz" does that with getting new random value, that gets repeated "forever" until the end of the pattern
@ -331,3 +331,77 @@ if I try to use not random, but "from sequence", then on pattern restart I'd get
so then "kind of working" solution, is keep melogy repeating, 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, 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