NRT CtkScore rendering problem

Hi there,

i am trying to render some external data through nrt in supercollider using CtkScore. everything works fine most of the times but some other times the audio file does not render the full data and becomes corrupted. when I try to render the data again from the point it failed it renders some more and then after a while it becomes corrupted again.
You can see in the following image the issue.

Does anyone know why this happens? it is not the data’s problem since i can render the corrupted part if i rerender it from the previous point of corruption but still the corruption comes in after a while…

any help would be really appreciated

this looks like some filters exploding or a horrible DC offset.

what bit depth are you rendering at? If you aren’t doing as float, I’d recommend doing that so you can see more what may be causing these kinds of levels. There isn’t anything in Ctk that should be causing this, but I’ve seen reverbs that crank up some DC that, in a sound editor, could look like this. But without seeing samples or code / CtkSynthDefs, it is hard to know what could be causing that.

Josh

Hi Josh!

thank you for your answer.
I think i figured out what was the issue. Do to the large amount of data I need to sonify, I am creating many envelopes within the score. I noticed that when the envelopes reach more than 15000 the effect shown in the above image occurs. Does the CtKscore have a maximum amount of envelopes that it can handle? If yes is there a way to increase that limit?

thanx again!

how are you adding the envelopes? Are they buffers of data? How many breakpoints in the envlopes (if you are doing something like .env_(Env(… some env))?
This shouldn’t matter for a CtkScore, but there may be some server options you need to pass in depending on the number of nodes running, mem settings, etc.

Hey josh!

I have created beforehand many environmental variables that store the arrays of each envelope and place them inside an Env and then with CtkControl.env I send them to the synthdef. The envs can have from 2 to 30 points since if i used more than 30 I used to have problems. The number of points though inside an array is not an issue if the points are less than 30, it is the number of the actual Env objects created that seems to be the issue.
these are the server options I pass at the begining

var server = Server(\nrt,
options: ServerOptions.new
.numOutputBusChannels_(2)
.numInputBusChannels_(2)
.memSize_(819200)
.maxNodes_(1700000)
.maxSynthDefs_(1700000)
.blockSize_(4)
.numAudioBusChannels_(1700000)
),
defaultGroup = Group.basicNew(server);

do you think that the issue are these?

thanx!

Can you show me the CtkSynthDefs that you send the envs to?
More soon (on my phone)

/*
Josh Parmenter
www.realizedsound.net/josh
*/

Hey!

here is an simplified version so I can illustrate the issue…
Although the overall length of the audio should be around 25 sec, I changed the length to 6s so you wont need to wait too long since the problem in this instance starts around 4s.
First I generate some random envs so it can run.
28131 is the number of envs from the external data.

(
~size={rrand(2,5)}!28131;
~time=Array.new;
~time4Env=Array.new;

(~size.size).do({|i,index|
~time=~time.add( rrand(1,20.0));
~time4Env=~time4Env.add( rrand(0.0001,20))});
~time4Env.sort;
)

(
var server = Server(\nrt2,
options: ServerOptions.new
.numOutputBusChannels_(2)
.numInputBusChannels_(2)
.memSize_(819200)
.maxNodes_(1700000)
.maxSynthDefs_(1700000)
.blockSize_(32/8)
.numAudioBusChannels_(1700000)
),
defaultGroup = Group.basicNew(server);

var pnotes, group,playsin;
var score, now;
score = CtkScore.new;

pnotes = CtkProtoNotes(
SynthDef(\sin, {arg buffer, freq= 1, amp,pan,outbus,duration;
var envperc=EnvGen.kr(Env.sine(duration, 1),doneAction: 2);
OffsetOut.ar(0,
Pan2.ar(
SinOsc.ar(freq,mul: amp)envperc0.2,pan));
}).load(server)
);

playsin= {arg starttime, duration, freqenv,ampenv, panenv,buss;
var note, now, ratio, rate;
pnotes[\sin].note(starttime,duration)
.freq_(CtkControl.env(freqenv))
.amp_(CtkControl.env(ampenv))
.pan_(CtkControl.env(panenv))
.outbus_(buss)
.duration_(duration)
.addTo(score);

};

score.add([0.0, defaultGroup.newMsg]);

~size.do({|i,index|
var size=i;
var time=({rrand(0.1,1.0)}!(size-1));
var timesum= (time.sum );
var start=(~time4Env[index]);

playsin.value(start, timesum,
	Env(((({rrand(0,10000.0)}!(size)))),time,\lin),   
	Env(((({rrand(0,1.0)}!(size))/10)),time,\sin),
	Env((({rrand(-1,1)}!(size))),time,\sin),  
) ;

});

score.write(“/SuperColliderRecordings/nrt_test.aiff”.standardizePath,6,sampleRate:44100,sampleFormat:“float”, options: server.options/.numOutputBusChannels_(2)/);

server.remove;
)

thanx again!

well, that certainly took some digging, but the code below should do what you want.
Basically - the server allocators (for bus id allocation) was running out of IDs for a couple different reasons - I commented the code below, hopefully that answers all the questions!

(
~size={rrand(2,5)}!28131;
~time=Array.new;
~time4Env=Array.new;

~size.size.do({|i,index|
	~time=~time.add( rrand(1,20.0));
	~time4Env=~time4Env.add( rrand(0.0001,20))});
~time4Env.sort;
)

(
// this server isn't used anywhere, and the options aren't either!
/*
var server = Server(\nrt2,
options: ServerOptions.new
.numOutputBusChannels_(2)
.numInputBusChannels_(2)
.memSize_(819200)
.maxNodes_(1700000)
.maxSynthDefs_(1700000)
.blockSize_(32/8)
.numAudioBusChannels_(1700000)
)
*/
// not needed - the default group in the basic NRT server should suffice
// var defaultGroup = Group.basicNew(server);

var pnotes, group, playsin;
var score, now;
var options;

// feed this in to the 'write' - note - options should be powers of 2
// here, I'm using the number of notes to calculate the number of control
// channels
options = ServerOptions.new
.numOutputBusChannels_(2)
.numInputBusChannels_(2)
.memSize_(32768 * 8)
.maxNodes_(32768 * 8)
.blockSize_(32/8)
.numControlBusChannels_((~size.size * 3).nextPowerOfTwo); // since each note needs 3 CtkControls

// this is needed for the allocators to have enough space AND later to allocate the channels
// in the NRT server
s.options = options;

// With this, with every render you reset the allocator indexes
s.newAllocators;

score = CtkScore.new;

pnotes = CtkProtoNotes(
	SynthDef(\sin, {arg buffer, freq= 1, amp,pan,outbus,duration;
		// no need for doneAction-  the duration arg to the CTK note will handle this for you
		// as long as the durations you feed in are the same! Gets rid of all the failure messages
		// in the NRT render
		// var envperc=EnvGen.kr(Env.sine(duration, 1),doneAction: 2);
		var envperc=EnvGen.kr(Env.sine(duration, 1));
		OffsetOut.ar(0,
			Pan2.ar(
				SinOsc.ar(freq, mul: amp) * envperc * 0.2, pan));
	}).load(s)
);

playsin= {arg starttime, duration, freqenv,ampenv, panenv,buss;
	var note, now, ratio, rate;
	pnotes[\sin].note(starttime,duration)
	.freq_(CtkControl.env(freqenv))
	.amp_(CtkControl.env(ampenv))
	.pan_(CtkControl.env(panenv))
	.outbus_(buss)
	.duration_(duration)
	.addTo(score);

};
// no need - just use the default NRT server
//score.add([0.0, defaultGroup.newMsg]);
~size.do({|i,index|
	var size=i;
	var time=({rrand(0.1,1.0)}!(size-1));
	var timesum= (time.sum );
	var start=(~time4Env[index]);
	var freqenv = Env(((({rrand(300,1000.0)}!(size)))),time,\lin);
	var ampenv = Env(((({rrand(0.001,1.0)}!(size))/10)),time,\sin);
	var panenv = Env((({rrand(-1.0,1.0)}!(size))),time,\sin);
	playsin.value(start, timesum, freqenv, ampenv, panenv);
});

score.write("~/Desktop/nrt_test.aiff".standardizePath, 6, sampleRate:44100, sampleFormat:"float", options: options);

// check the score if needed - when I did this, I eventually found 'cnil' for some of the
// envelope mappings... that told me I needed to update the options for score creation
// and rendering.. somethings a handy debugging tool!
// score.saveToFile("~/Desktop/nrt_test.sc".standardizePath);
)```

Josh thank you so much for spending time on this, this has been extremely helpful!
Everything works fine now and really faster, and your comments were really explanatory!

I have two more questions to ask though. The Synthdef I am trying to load apparently is quite big and I get
ERROR: makeSynthMsgWithTags: buffer overflow

I tried substituting “.load(s)” with “.store” and “.writeDefFile” but non of the two seamed to work (maybe I misplaced them or did not add something additional that was needed).
Would you have any suggestion on how to resolve this?

I am also loading some samples to a few CtkBuffers, do I need to change anything at the options for this?

thank you again

Can you post or send me the problem synthdef? You can actually include them in the score (but I need to remember how to do that… I remember figuring it out then didn’t do it again).
CtkBuffers should be fine with the caveat of buffer ids. I believe there is a server option for this as well that can be increased I’m not at my computer, but I can look it up in the morning.

/*
Josh Parmenter
www.realizedsound.net/josh
*/