177 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
| (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
 |