PageRenderTime 35ms CodeModel.GetById 7ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/polysynth.scm

http://github.com/digego/extempore
Lisp | 127 lines | 75 code | 16 blank | 36 comment | 0 complexity | b83ae0d7eef582958223215049a0d862 MD5 | raw file
  1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2;;
  3;; This example shows how to define your own polyphonic synths
  4;;
  5;; You will first need to load and compile dsp_library.scm
  6;;
  7;; Then you're OK to go
  8;;
  9;; NOTE [at the moment compiling in a secondary thread is a little
 10;;      [flakey.  I'm working on this so in the mean time you'll
 11;;      [just have to put up with the audio delays while compiling
 12;;
 13
 14
 15;; first let's play with the default synth defined in dsp_library
 16;; the default synth is called .... synth
 17(define loop
 18  (lambda (beat offset dur)
 19    (play-note (*metro* beat) synth (+ offset (random '(60 62 63 65 67))) 80 2000)
 20    (callback (*metro* (+ beat (* dur .5))) 'loop
 21	      (+ beat dur)
 22	      offset
 23	      dur)))
 24
 25
 26(loop (*metro* 'get-beat 4) 0 1/2) ;; start one playing quavers
 27(loop (*metro* 'get-beat 4) 12 1/3) ;; another playing triplets
 28
 29;; to create our own instrument
 30;; we first need to compile a kernel function
 31;; this is the dsp code that gets rendered for each note
 32;; it must be a closure that returns a closure
 33;; 
 34;; lets try a simple sawwave synth
 35(definec my-saw-synth
 36  (lambda ()
 37    (let ((sawl (make-saw))
 38	  (sawr (make-saw)))
 39      (lambda (time:double chan:double freq:double amp:double)
 40	(cond ((< chan 1.0)
 41	       (sawl amp freq))
 42	      ((< chan 2.0)
 43	       (sawr amp freq))
 44	      (else 0.0)))))))
 45
 46;; now define an instrument to use my-additive-synth note kernel
 47;; with a default (i.e. pass through) default-effect
 48(define-instrument my-synth my-saw-synth default-effect)
 49    
 50
 51;; finally we need to add the new synth to the dsp routine
 52;; this is only slightly modified from the on in dsp_library
 53;; we just sum my-synth with synth and add some delay
 54;;
 55;; NOTE: then 100000 is extra memory for our
 56;; comb filters
 57(definec dsp 1000000
 58  (let ((combl (make-comb (dtoi64 (* 0.25 *samplerate*))))
 59	(combr (make-comb (dtoi64 (* 0.33333333 *samplerate*)))))
 60    (lambda (in:double time:double chan:double dat:double*)
 61      (cond ((< chan 1.0)
 62	     (combl (+ (* 1.0 (synth in time chan dat))
 63		       (my-synth in time chan dat))))
 64	    ((< chan 2.0)	     
 65	     (combr (+ (* 1.0 (synth in time chan dat))
 66		       (my-synth in time chan dat))))
 67	    (else 0.0)))))
 68
 69;;make my-synth active
 70(my-synth.active 1)
 71
 72;; now start a temporal recursion to play the new synth
 73(define loop2
 74  (lambda (beat dur)
 75    (let ((pitch (random '(55 36 63 70 72))))
 76      (play-note (*metro* beat) my-synth pitch 
 77      		 (if (= pitch 36) 105 95) 3000)
 78      (callback (*metro* (+ beat (* dur .5))) 'loop2
 79		(+ beat dur)
 80		dur))))
 81
 82(loop2 (*metro* 'get-beat 4) 1/3) ;; play our new synth
 83
 84
 85;; we can recompile my-saw-synth into something 
 86;; else whenever we like
 87;; here's something more complex
 88(definec my-saw-synth
 89  (let ((res 15.0)
 90	(cof 8000.0))
 91    (lambda ()
 92      (let ((sawl (make-saw))
 93	    (sawl2 (make-saw))
 94	    (modl (make-oscil 0.0))
 95	    (lpfl (make-lpf))
 96	    (lpflmod (make-oscil 0.0))
 97	    (sawr (make-saw))
 98	    (sawr2 (make-saw))
 99	    (modr (make-oscil 0.0))
100	    (lpfr (make-lpf))
101	    (lpfrmod (make-oscil 0.0)))
102	(lpfl.res res)
103	(lpfr.res res)
104	(lambda (time:double chan:double freq:double amp:double)
105	  (cond ((< chan 1.0)
106		 (lpfl (* amp (+ (sawl (* 1.0 amp) freq) 
107				 (sawl2 amp (+ freq (modl 10.0 0.2)))))
108		       (+ cof (lpflmod freq 1.0))))
109		((< chan 2.0)			     		  
110		 (lpfr (* amp (+ (sawr (* 1.0 amp) freq) 
111				 (sawr2 amp (+ freq (modr 50.0 0.5)))))
112		       (+ cof (lpfrmod 1400.0 2.0))))
113		(else 0.0)))))))
114
115
116;; some event level modification to my-synth
117;; adjust res cof of my-additive-synth (dsp kernel)
118;; adjust release of my-synth (instrument)
119(define res-sweep
120  (lambda (beat dur)
121    (my-synth.release (cosr 12000.0 11000.0 1/29)) 
122    (my-saw-synth.res (cosr 40.0 30.0 1/37))
123    (my-saw-synth.cof (cosr 5000.0 3500.0 1/19))
124    (callback (*metro* (+ beat (* dur .5))) 'res-sweep
125	      (+ beat dur) dur)))
126
127(res-sweep (*metro* 'get-beat 4.0) 1/8)