Calling the Csound API from MzScheme

MzScheme is a first-rate multi-platform open source implementation of the scheme language.

Here is how to call the Csound API from MzScheme using its foreign function interface (which comes with the basic distribution).

First we import the foreign function interface module:

(require (lib "foreign.ss"))

We call the unsafe macro because we want to have access to the unsafe operations (get-ffi-obj is one of them).

(unsafe!)

Now we can load the csound shared library.

(define libcsound (ffi-lib "libcsound")) 

Below I have defined some procedures to interface to the Csound API functions. I defined just those needed to compile a predefined .csd file (which will contain the instruments definitions) and the csoundInputMessage() which can be used to populate the score.

(define csound-create
	(get-ffi-obj "csoundCreate" libcsound
		     (_fun _int -> _pointer)))

(define csound-compile
	(get-ffi-obj "csoundCompile" libcsound 
		     (_fun _pointer _int _cvector -> _int)))

(define csound-input-message
	(get-ffi-obj "csoundInputMessage" libcsound
		     (_fun _pointer _string -> _void)))

(define csound-perform
	(get-ffi-obj "csoundPerformKsmps" libcsound
		     (_fun _pointer -> _int)))

(define csound-destroy
	(get-ffi-obj "csoundDestroy" libcsound
		     (_fun _pointer -> _void)))

Here I define a loop to execute csoundPerformKsmps() until the performance is done:

(define (csloop) 
	(if (zero? (csound-perform *cs*)) (csloop)))

csoundCompile expects the argument list as a vector:

(define *csargs* (list->cvector '("csound" "mycsdfile.csd") _string))

Now we have everything we need to start Csound with our mycsdfile.csd and fill the score with notes (I'll send just one note, as an example):

(define *cs* (csound-create 0))

(csound-compile *cs* 2 *csargs*) ;2 is the number of the args

;this is a note sent to the csound score
(csound-input-message *cs* "i1 0 1 7.00 10000\n")

(csloop)
(csound-destroy *cs*)
(exit)

In the example above, I'm filling the score before calling the csound perform loop. But you can feed the events in real-time, too. Just put the call to csloop inside a separate thread:

(thread csloop)

Then you can call csound-input-message to send events in real-time (if p2 = 0, or delay them for p2 seconds if p2 > 0). In MzScheme you can use:

(sleep seconds)

to delay the calls to csound-input-message inside a loop.

Keep in mind, also, that you should include an i statement to play a dummy instrument (or any instrument you have defined in your orchestra with 0 amplitude) in your csd file score section with the duration (the p3 field) set to as long as you want your performance to be kept alive.