OSClisten updating global K-rate variables seems to clog

Hello all

In preparation for the CSoundConf next month, I am dipping my toes back (after a 26 year hiatus!) - I really welcome the global variables and OSC support… but when I connect the two, it seems I’m getting clogging (MacOS, terminal or Cabbage, same result)

I am certain it is my error, so here I am, asking for help :slight_smile:

if you have an osc controller that generates values for x and y, this should work smoothly, no?

any pointers welcome!

<CsoundSynthesizer>

<CsOptions>
-m 128
-odac
</CsOptions>

<CsInstruments>
; Initialize the global variables. 
ksmps = 64
nchnls = 2
0dbfs = 1

giNbBands init 40
gaSum init 0
gaIn init 0
gklow init 15
gkhigh init 131
gkwidth init (131 - 15) / giNbBands
giPort OSCinit 7773

; test sines summing
instr voice
  asin poscil 0.1, mtof((p4 * gkwidth) + gklow)
  gaSum = gaSum + asin
endin

instr input
  kx[] init 10
  ky[] init 10
  
  nxtmsg:
    kk1, kx OSClisten giPort, "/sb3/mb/x", "ffffffffff"
    kk2, ky OSClisten giPort, "/sb3/mb/y", "ffffffffff"
    if ((kk1 == 0) && (kk2 == 0)) goto ex
    gklow scale kx[1], ftom(400), ftom(20), 1, 0
    gkhigh scale ky[1], ftom(16000), ftom(800), 1, 0
    gkwidth = (gkhigh - gklow) / giNbBands
    ; printk 0.04, gklow
    kgoto nxtmsg
  ex:
endin

instr output
  outs gaSum, gaSum
  clear gaSum
endin

instr   test
  iBandID = 0
  
  schedule("input", 0, p3)

  loop:
    schedule("voice", 0, p3, iBandID)
  loop_lt iBandID, 1, giNbBands, loop

  schedule("output", 0, p3)
endin

schedule("test",0,10000)

</CsInstruments>

<CsScore>
</CsScore>

</CsoundSynthesizer>

Hi,

I created a csd for OSCsend to test your code and they work without problem.
I tested with Cabbage/MacOS.
What device or code do you use to send OSC message? You can check the sent messages with Protokol.app.

<CsoundSynthesizer>
<CsLicense>
</CsLicense>
<CsOptions>
-m 128 -odac
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 64
nchnls = 2
0dbfs = 1

instr 1
kx[] init 10
ky[] init 10
iport = 7773

kx[0] = jitter:k(0.5,1,2)+0.5
kx[1] = jitter:k(0.5,1,10)+0.5
kx[2] = jitter:k(0.5,0.1,2)+0.5
kx[3] = jitter:k(0.5,0.1,0.5)+0.5
kx[4] = randomh:k(0,1,1)
kx[5] = randomh:k(0,1,5)
kx[6] = phasor:k(0.1)
kx[7] = phasor:k(0.5)
kx[8] = phasor:k(1)
kx[9] = phasor:k(5)

ky = 1-kx

OSCsend kx[0], "localhost", iport, "/sb3/mb/x", "ffffffffff", kx[0],kx[1],kx[2],kx[3],kx[4],kx[5],kx[6],kx[7],kx[8],kx[9]
OSCsend ky[0], "localhost", iport, "/sb3/mb/y", "ffffffffff", ky[0],ky[1],ky[2],ky[3],ky[4],ky[5],ky[6],ky[7],ky[8],ky[9]
endin
</CsInstruments>
<CsScore>
i1 0 10000
</CsScore>
</CsoundSynthesizer>

hello!

Thanks for this. I am running the same code in SuperCollider smoothly (driven by the same iPad in local network running a Lemur app with 10 balls in the xy multipoint), hence thinking there was something clogging in the OSC I wrote… Protokol

Indeed your code doesn’t clog at all my synth. So I will investigate why CSound and SC do not behave the same with the external OSC. It might be to do with the casting in Lemur, the array of 10 might not be complete, or something else.

Is OSCRaw a good opcode in CSound to spy the input unformatted?

Hi,

Does my OSCsend code work with your code in SuperCollider? If not, I would check the range of the value sent from Lemur to SuperCollider because your Csound code assumes the range is from 0 to 1.

Oh this is embarassing, and leads to a further question and a suggestion.

The embarrassment:
I read from kx[1] and not kx[0] in my code. This is looking at the 2nd finger, not the first, hence the jitter… :person_facepalming:

The further question:
It is still a lot less smooth than sc… so my first hypothesis was:

  • I tried to emulate SC for real, which will interpolate K to A over one KSMP period - I was trying to smooth/lag/interpolate/upsample linearly the pitch input in my ‘voice’ but searching for all these words in the list of opcode didn’t help. Eventually, after searching manually for the word ‘smooth’ in the floss manual I found a()

(but that didn’t help much) - your code generates much higher density of control and it sounds smooth. I’m puzzled

Thanks for any pointer.

p

ps the suggestion is for the discourse platform - adding the code copy/paste plugin would be great!

In my OSCsend code, sr = 44100 and ksmps = 64. Theoretically it can send OSC message every ksmps/sr=0.0015 sec. Meanwhile, it also depends ‘kwhen’ parameter which is a trigger to send OSC message.

OSCsend kwhen, ihost, iport, idestination[, itype , xdata1, xdata2, …]

In my code, kx[0] (= jitter:k(0.5,1,2)+0.5) is assigned to kwhen, which will trigger sending OSC message almost every k cycle.
If you change kwhen to kx[4](= randomh:k(0,1,1)), OSC message will be sent every second because kx[4] changes every second.

Does your Lemur app send OSC message frequently enough for smooth sound?
Protokol.app(by Hexler Limited) is a handy tool to monitor OSC message.

Could you please share your SC code if possible? I can test it though I’m not a heavy user of SC.

Hello

Indeed Protokol is great - my Lemur app gives about 320 messages / sec. In SC, this is smooth:

~nbBands = 40;

(
~resynth = {arg low = 15, high = 131;
	var width = (high - low) / ~nbBands;
	var bands = ~nbBands.collect{arg i;
		var bcentre = (((i + 0.5) * width) + low).midicps;
		var blow = (((i) * width) + low).midicps;
		var bhigh = (((i + 1) * width) + low).midicps;
		var bwidth =  ((bhigh - blow) / bcentre);
		SinOsc.ar(bcentre, mul:0.01);
	};
	Out.ar(0,bands.sum.dup);
}.play;

OSCdef(\ballX, {|x| ~resynth.set(\low, x[1].linlin(0, 1, 20.cpsmidi,400.cpsmidi))}, "/sb3/mb/x", recvPort:  7773);
OSCdef(\ballY, {|y| ~resynth.set(\high, y[1].linlin(0, 1, 800.cpsmidi, 16000.cpsmidi))}, "/sb3/mb/y", recvPort:  7773);
)

My current hypothesis is OSC service time now… but again, I don’t want to be presumptuous, just candid!

Hi,

I don’t see any big difference between your Csound and SuperCollider code.
It’s very interesting that they may work differently in some cases, but I am not sure what causes it…

I’ll try to create a timer in Csound to give the time diff between 2 osc messages… more soon!

Hello again.

So, I tried to understand why it was more blocky. I checked in Protokol, and in SC with this code:

(
~nbms = 0;
~max = 0;

OSCdef(\ballX, {~nbms = ~nbms + 1}, "/sb3/mb/x", recvPort:  7773);
OSCdef(\ballY, {~nbms = ~nbms + 1}, "/sb3/mb/y", recvPort:  7773);
OSCdef(\ballZ, {~nbms = ~nbms + 1}, "/sb3/mb/z", recvPort:  7773);

Routine{
	{
		~max = ~nbms.max(~max);
		"% items in the last second. % max so far\n".postf(~nbms, ~max);
		~nbms = 0;
		1.wait;
	}.loop;
}.play
)

and get around 230 messages per second max with my Lemur, and 1400 with your OSCSend code (again in Protokol and SC). In Csound, with the code below, I get 110 m/s max from Lemur, and 726 from your OSCsend code.

Is there anything I do wrong in Csound, or is there a cap on the OSC parsing?

<CsoundSynthesizer>

<CsOptions>
-m 128
-odac
</CsOptions>

<CsInstruments>
; Initialize the global variables. 
ksmps = 64
nchnls = 2
0dbfs = 1

gkcount init 0
giPort OSCinit 7773

instr   ReceiveOSC
  kx[] init 10
  ky[] init 10
  kz[] init 10
  kk1 init 0
  kk2 init 0
  kk3 init 0

  nxtmsg:
    kk1, kx OSClisten giPort, "/sb3/mb/x", "ffffffffff"
    kk2, ky OSClisten giPort, "/sb3/mb/y", "ffffffffff"
    kk3, kz OSClisten giPort, "/sb3/mb/z", "ffffffffff"
    if ((kk1 == 0) && (kk2 == 0) && (kk2 == 0)) goto ex
    ; printks "count: %d x: %f y: %f\\n", 0.04, kcount, kx[0], ky[0]
    gkcount = gkcount + 1
    kgoto nxtmsg
  ex:

endin

instr PeriodicPrinter
  schedule("ReceiveOSC", 0, 10000)
  kmax init 0
  kTrig metro 1
  printf "count: %d messages. Max so far: %d m/s\n", kTrig, gkcount, kmax
  kLate delayk kTrig, 0.1
  if kLate == 1 then
    kmax max kmax, gkcount
    gkcount = 0
  endif
endin

schedule("PeriodicPrinter", 0, 10000)

</CsInstruments>

<CsScore>
</CsScore>

</CsoundSynthesizer>

Final post here, until I find an answer. If I take the OSCraw, I get even weirder results. I’ll go on GitHub now and will report once I have a working solution. In the meantime, replacing my ReceiveOSC above by:

instr ReceiveAll
Smess[] init 100
top:
Smess,ka OSCraw 7773
kn = 0
while kn < ka do
  ; printf ": %s ", kn+1, Smess[kn]
  kn += 1
od
printf "%d items\n", ka, kn
gkcount = gkcount + 1
if ka > 0 kgoto top
endin

gives me bundled arrays of 24 or 36, but more strangely, 620 m/s when doing nothing. I’m certain I’m the cause…