|Subject:||[PD] Implementing a scheme extension language|
|From:||Larry Troxler (lt...@westnet.com)|
|Date:||Apr 28, 2001 3:21:40 pm|
I am attempting to implement an library which will provide a scheme extension language, and would welcome any comments.
First I should say what my motivation is. I have found PD very fun and practical, except where any kind of serious programming logic is needed. In these cases, I have found it a mind bender to try to implement graphically what could be accomplished very easily using a text-oriented language. As a case in point, I want to create a PD piano instrument that uses a piano sample CD. Although I got it working with a particular set of sample files, it is clear that the graphical hookup technique is certainly not a sensible way to go about this. As a result (well, not only because of this, but also because of several other similar situations), I have longed to drop down into a textual language to implement PD objects.
True, I could use C and implement what I need directly as a loadable object, but I though that an interpreted language would be in general nicer, and fast enough, for most purposes like this.
I have decided at first to use "scheme in one defun" (siod), simply because my time is limited, and siod it takes much less brain power to integrate siod, then to learn how to implement guile or elk. Of course, guile/elk is more complete and probably will run a lot faster, and this is a future option.
I'd like to present my first-attempt specs for how this would work, and see if anyone has any comments. This is very rough-draft and not precise, but just to give a general idea...
1) implement a global receiver (like "pd"), that when it receives any message, sends it to the sheme interpreter to evaluate. This would not be as nice as a seperate interpreter console, but for now, it will avoid me to have to deal with a new gui for an interpreter. Question: what to name this? I will take "scm" for now, so that for example, in a message box, "; scm foo `( 1 2)" will call the scheme function "foo" with the list (1 2) as an argument. The outer pair of parenthesis is implicitly added.
2) The scheme function (pdsend 'receiver arg1 arg2 ..) will send its args to the pd receiver named "receiver". For example, (pdsend 'pd 'quit).
3) The scheme function (pdreceive 'x fn) will create a pd receiver, so that when pd sends a message to "x", the scheme function "fn" will be called, and passed the message as a list.
4) The pd object "scmob" (Question: better name?) will instantiate a pd object implemented in scheme (for now I won't deal with DSP signals). Its first argument, prepended with "make-", will be the name of a scheme function which will create a closure which will become the object. The number of inlets to this object will be determined by the number of the arguments in the lambda expression returned by the generation function. And the number of outlets will be determined by, well I don't know yet. The additional creation arguments will be passed to the creation function. Within the lambda, the function (pdout n val) would send val to the n'th outlet of the object. When anything is received at the first inlet to the object, the arguments of the lambda will be bound to the current values at the inlets, and the lambda will be called.
For example, say we have in the scheme environment (note, I just typed this in without a proper editor, so there could be paren mismatches, etc, but to give the general idea...) :
(define (make-integrator initial-value) (let ((current initial-value)) (lambda (x) (cond ((and (symbol? x) (eq x 'reset)) (set! current initial-value)) ((number? x) (set! current (+ current x)))) (pdout 0 current) (pdout 1 x)))
Given that the above has been evaluated in the scheme environment, then typing "scmob integrator 10" into a PD object would create a an object with one inlet, whose first outlet would be a sum of the number object received at the inlet, or be reset to 10 if the "reset" message is received at the inlet. The second outlet would be a copy of the inlet.