small refactor of old notes and more arpeggios
This commit is contained in:
parent
788c27c54b
commit
00515cd9df
|
@ -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
|
|
@ -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))
|
||||
|
||||
(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.7 0.5 0.8)) ; 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
|
|
@ -405,3 +405,8 @@ 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"
|
|
@ -0,0 +1,3 @@
|
|||
(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))))
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
;; https://defaultxr.github.io/cl-collider-tutorial/02-getting-started.html
|
||||
|
||||
(ql:quickload :cl-collider)
|
|
@ -0,0 +1,168 @@
|
|||
(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))
|
||||
(out.ar 0 (saw.ar (let ((detune (* freq 0.01)))
|
||||
(list (- freq detune) (+ freq detune)))
|
||||
(/ amp 2))))
|
||||
|
||||
(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)))
|
Loading…
Reference in New Issue