diff --git a/README.org b/README.org new file mode 100644 index 0000000..1ab444f --- /dev/null +++ b/README.org @@ -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 diff --git a/2022-08-12-setting-up-cl-collider.lisp b/dirty-journal/2022-08-12-setting-up-cl-collider.lisp similarity index 100% rename from 2022-08-12-setting-up-cl-collider.lisp rename to dirty-journal/2022-08-12-setting-up-cl-collider.lisp diff --git a/2022-08-12-supercollider-example.lisp b/dirty-journal/2022-08-12-supercollider-example.lisp similarity index 100% rename from 2022-08-12-supercollider-example.lisp rename to dirty-journal/2022-08-12-supercollider-example.lisp diff --git a/2022-08-12-trying-includine-sound.lisp b/dirty-journal/2022-08-12-trying-includine-sound.lisp similarity index 100% rename from 2022-08-12-trying-includine-sound.lisp rename to dirty-journal/2022-08-12-trying-includine-sound.lisp diff --git a/2022-08-19-patterns-guide.lisp b/dirty-journal/2022-08-19-patterns-guide.lisp similarity index 100% rename from 2022-08-19-patterns-guide.lisp rename to dirty-journal/2022-08-19-patterns-guide.lisp diff --git a/2022-08-20-will-i-get-instruments.lisp b/dirty-journal/2022-08-20-will-i-get-instruments.lisp similarity index 100% rename from 2022-08-20-will-i-get-instruments.lisp rename to dirty-journal/2022-08-20-will-i-get-instruments.lisp diff --git a/2022-08-21-parallel-and-precussion.lisp b/dirty-journal/2022-08-21-parallel-and-precussion.lisp similarity index 100% rename from 2022-08-21-parallel-and-precussion.lisp rename to dirty-journal/2022-08-21-parallel-and-precussion.lisp diff --git a/2022-08-28-trying-for-percussion-again.lisp b/dirty-journal/2022-08-28-trying-for-percussion-again.lisp similarity index 100% rename from 2022-08-28-trying-for-percussion-again.lisp rename to dirty-journal/2022-08-28-trying-for-percussion-again.lisp diff --git a/2022-09-01-more-percussions-and-write-to-file.lisp b/dirty-journal/2022-09-01-more-percussions-and-write-to-file.lisp similarity index 100% rename from 2022-09-01-more-percussions-and-write-to-file.lisp rename to dirty-journal/2022-09-01-more-percussions-and-write-to-file.lisp diff --git a/2022-09-02.lisp b/dirty-journal/2022-09-02.lisp similarity index 100% rename from 2022-09-02.lisp rename to dirty-journal/2022-09-02.lisp diff --git a/2022-09-03-small-time-more-synthdefs.lisp b/dirty-journal/2022-09-03-small-time-more-synthdefs.lisp similarity index 100% rename from 2022-09-03-small-time-more-synthdefs.lisp rename to dirty-journal/2022-09-03-small-time-more-synthdefs.lisp diff --git a/2022-09-04-more-synths-and-chord-progressions.lisp b/dirty-journal/2022-09-04-more-synths-and-chord-progressions.lisp similarity index 100% rename from 2022-09-04-more-synths-and-chord-progressions.lisp rename to dirty-journal/2022-09-04-more-synths-and-chord-progressions.lisp diff --git a/2022-09-05-maybe-sequences-from-chords.lisp b/dirty-journal/2022-09-05-maybe-sequences-from-chords.lisp similarity index 100% rename from 2022-09-05-maybe-sequences-from-chords.lisp rename to dirty-journal/2022-09-05-maybe-sequences-from-chords.lisp diff --git a/2022-09-06-maybe-chord-melodies.lisp b/dirty-journal/2022-09-06-maybe-chord-melodies.lisp similarity index 100% rename from 2022-09-06-maybe-chord-melodies.lisp rename to dirty-journal/2022-09-06-maybe-chord-melodies.lisp diff --git a/2022-09-07-trying-more-arpegioing-chords.lisp b/dirty-journal/2022-09-07-trying-more-arpegioing-chords.lisp similarity index 100% rename from 2022-09-07-trying-more-arpegioing-chords.lisp rename to dirty-journal/2022-09-07-trying-more-arpegioing-chords.lisp diff --git a/2022-09-08-more-on-chord-melodies.lisp b/dirty-journal/2022-09-08-more-on-chord-melodies.lisp similarity index 100% rename from 2022-09-08-more-on-chord-melodies.lisp rename to dirty-journal/2022-09-08-more-on-chord-melodies.lisp diff --git a/dirty-journal/2022-09-09-maybe-cleanup-bass-from-chords.lisp b/dirty-journal/2022-09-09-maybe-cleanup-bass-from-chords.lisp new file mode 100644 index 0000000..d025253 --- /dev/null +++ b/dirty-journal/2022-09-09-maybe-cleanup-bass-from-chords.lisp @@ -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 diff --git a/programming-music-journal.org b/dirty-journal/programming-music-journal.org similarity index 98% rename from programming-music-journal.org rename to dirty-journal/programming-music-journal.org index bb5781a..893171c 100644 --- a/programming-music-journal.org +++ b/dirty-journal/programming-music-journal.org @@ -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" diff --git a/stabler-things/functions.lisp b/stabler-things/functions.lisp new file mode 100644 index 0000000..e5271d4 --- /dev/null +++ b/stabler-things/functions.lisp @@ -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)))) diff --git a/attempt-at-setup.lisp b/stabler-things/setting-up.lisp similarity index 99% rename from attempt-at-setup.lisp rename to stabler-things/setting-up.lisp index ae35a7d..e906d16 100644 --- a/attempt-at-setup.lisp +++ b/stabler-things/setting-up.lisp @@ -1,4 +1,3 @@ - ;; https://defaultxr.github.io/cl-collider-tutorial/02-getting-started.html (ql:quickload :cl-collider) diff --git a/stabler-things/synthesizers.lisp b/stabler-things/synthesizers.lisp new file mode 100644 index 0000000..8630eda --- /dev/null +++ b/stabler-things/synthesizers.lisp @@ -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)))