[CM] The simplest defsynth possible

Mario Lang mlang@delysid.org
Fri, 30 Sep 2005 11:01:12 +0200


Since I am a SC fanatic with a bias towards Lisp, I'd really
like to play with CM's SC support, but the fact that SynthDef
and scheduling code is separate really turns me off. This
is soooo csound! :-/  Ideally, we should be able to define
the synth graph in the same language IMO.  Below is the probably
simplest implementation to do this, as an inspiration.  It uses
Emacs's interface to SCLang, translating synth definition in
Lisp into sclang code and evaluating it in sclang to
generate the required def (actually, it already sends it to the server
using .store).
I see two approaches if someone wants to do this in CM directly:
 1: Either do the same as below, but send the string to
    sclang as a subprocess, simply fork sclang and pass the code to it
    so it can write the def file or send the def to the server.
 2: Emulate the behaviour of SynthDef.writeDef in the macro
    directly and generate the necessary binary blob.  Its actually
    not *that* complicated, the most important issue is
    that we don't know the class definitions of sclang in Lisp
    so we *need* to make defsynth a macro to be able to
    use arbitrary symbol names.

Now, here is the code, with a usage example at the end.  Now, wouldnt
that be sweet for CM directly?  Ideally, the macro should
be a little more intelligent, allowing real lisp code inside
the definition which is evaluated at macro expansion time.
But for a pure graph definition, the system below is enough.

(defmacro defsynth (name args &rest body)
  "Define a synth graph with NAME and ARGS and BODY.
Returns NAME as symbol with property 'sclang-code.
Use `sclang-store-synth' to actually send the generated code to sclang."
  (put name 'sclang-code
	"SynthDef(%o, {%s%s})"
	(if args
	    (concat "arg "(mapconcat 
			   (lambda (arg)
			     (if (consp arg)
				 (sclang-format "%s=%o" (car arg) (cadr arg))
			       (sclang-format "%s" arg)))
			   args ", ")";\n")
	(mapconcat #'sclang-lisp-to-sc body "\n")))

(defun sclang-lisp-to-sc (expr)
   ((consp expr)
     (t (sclang-format "%s(%s);" (car expr) (mapconcat
					    #'sclang-lisp-to-sc (cdr expr)
					    ", ")))))
   (t (format "%S" expr))))

(defun sclang-store-synth (synth)
  (sclang-eval-string (sclang-format "%s.store" (get synth 'sclang-code))))

 (defsynth fasl ((freq 440) (amp 0.2) (out 0))
   (Out.ar out (SinOsc.ar freq 0 amp))))