Realtime Csound from Grace using OSC routing

06 February 2015

2022 note: CM may nearly be a dead project, so I'm publishing this more for myself.

Intro

While working with Grace’s Csound rendering recently, things got a little bogged down as I tried to access the same score file from multiple processes. Here’s a post I made to the CM list a little while back, which sums up my problem: I’m stuck with a problem trying to sprout processes and work with Csound.
I’m trying to do something more complex with a piece I’m working on, but managed to boil down the problem I’m having by using the Csound Scheme example. If you take a look at that example, you’ll see a function called ransco:

(define (ransco len rhy lb ub amp)
      (let ((dur (* rhy 2)))
        (process repeat len
                 for t = (elapsed #t) ; get true score time
                 for k = lb then (between lb ub)
                 do
                 (cs:i 1 t dur k amp)
                 (wait rhy))))

A bit further down in the example, there’s some instruction on sprouting this bit multiple times, using :write #f to ‘collect’ the events generated into one score:

		; This will generate a score without writing an audio file. execute
    ; the expression several times and use the Audio>Csound>Export... item
    ; to export all the score data in various formats

    (sprout (ransco 10 .2 60 72 1000) "test.sco" :write #f)

I was assuming I’d be able to do this same thing from a process, but I’m getting an error that Grace is unable to get a file handle to “test.sco”. Here’s the function:

    (define (f1)
      (process repeat 3
      do
      (sprout (ransco 10 .2 60 72 1000) "test.sco" :write #f)
      (wait 1)))

…and I try to execute it like so:

    (sprout (f1))

Instead of trying to bend CM to my will, I decided to use OSC to fire Csound events in realtime. This has been pretty successful so far, so I’m posting my ‘OSC Router’ Csound score and example Scheme file for others to use.

Links:

The .csd is here

Sample scheme file is here

Scheme file

My .scm file is pretty verbose for this illustration, but I figured more is more right? :) At line 2, I open up an osc listener:

(osc:open 7779 7825)

I’m not receiving anything incoming, but not the outbound port 7825 - you’ll see that again in the .csd file. The lion’s share of the file is 4 nearly-identical functions which generate separate lines, ultimately to be played by guitar quartet. Instead of the familiar call to cs:i, we use osc:message:

(osc:message "/router" 1 t dur amp pitch pan dist pct )

Essentially routing p-fields of a score event to outbound port 7825. At this point, we can just sprout a list of calls like I do at lines 128-134:

(sprout (list 
         (quartetlet-1 10 300 (make-heap '(gs4 b4 a4 fs4)))
         (quartetlet-2 30 300 (make-heap '(gs4 b4 a4 fs4)))
         (quartetlet-3 60 300 (make-heap '(e5 fs5)))
         (quartetlet-4 45 300 (make-heap '(fs3)))
         )
) 

…but I wanted to sprout them within a process, along rhythmic lines. Hence the function beginning at line 136:

(define (launch num)
  (let*  (
   (rhythms (make-cycle '(w w+h w+w w+w+w)))
)
  (process 
           for r = (rhythm (next rhythms) 72)
           for iternum from 0 to num
           do
           (set! iternum (+ iternum 1))
           (sprout (list 
            (quartetlet-1 10 5 (make-heap '(gs4 b4 a4 fs4)))
            (quartetlet-2 30 5 (make-heap '(gs4 b4 a4 fs4)))
            (quartetlet-3 60 5 (make-heap '(e5 fs5)))
            (quartetlet-4 45 5 (make-heap '(fs3)))
         )
                    )
           (wait r)
           )
  )
)

Launch like so:

(sprout (launch 50))

You’ll hear bursts of quartet material initiated according to the rhythm generated by

(rhythms (make-cycle '(w w+h w+w w+w+w)))

which generates a 5-second burst of quartet material for each rhythm generated. Here’s a sample (player at top)

Osc Router

Let’s look at the csd, which routes incoming OSC data from Grace. At line 10, we open up an osc listener on line 10:

gihandle OSCinit 7825

Instr 1 uses the pluck ugen with the familiar parameters for duration, amplitude and pitch, along with parameters to locate the note in stereo space using locsig/locsend. Instr 99 provides reverb (actually not used here..).. Instr 1000 is the relevant instrument here:

instr   1000
kinst init 0
kstart init 0
kdur init 0
kamp init 0
kpitch init 0
kpan init 0
kdist init 0
kpct init 0
kwhen init 0

nxtmsg:
    kk  OSClisten gihandle, "/router", "ifffffff", kinst, kstart, kdur, kamp, kpitch, kpan, kdist, kpct
    if (kk == 0) goto exit
    schedkwhen kk, -1, -1, kinst, kwhen, kdur, kamp, kpitch, kpan, kdist, kpct
    kgoto nxtmsg
    exit:
endin  

I init k-rate variables to hold incoming p-fields, and fill them with incoming data via OSClisten. If I get an osc message (signalled with kk, the trigger from OSClisten), I use schedwhen to fire an event to the intended instrument.

On my macbook, I run the csd with the following params:

csound -odac1 -+rtaudio=CoreAudio -Q0 -B512 -b64 osc_router.csd

Conclusion

The Common Music family of releases has shaped my music making, and getting back up to speed with the latest from Rick Taube, Bill Schottstaedt + co. at CCRMA has been rewarding. These projects (Common Music 1, 2 and 3.x, Grace, CLM, Snd) have little in terms of PR out there, but deserve more airtime out there IMHO. I hope that this examples serves to steer others in productive directions. More soon!

Once again, the links:

The .csd is here

Sample scheme file is here

Comments powered by Talkyard.