TIRand not in range

I’ve got 2 TIRand expression that are keeping providing values just outside of the range.

This is the trigger (recursive)


The code:

// .. buffer and cue points choice
bufidx1=TIRand.ar(0,nbuf-1,trig1); // OK
bufnum1=Latch.ar(BufRd.ar(1,bBufnum,bufidx1).asInteger,trig1); // Latch and asInteger as attempts to solve the issue, not sure it is needed.
ncue1=Latch.ar(BufRd.ar(1,bBufnum,nbuf+bufidx1),trig1).poll(poll,"n_cue 1");
cueidx10=TIRand.ar(0,ncue1-2,trig1).poll(poll,"cue start 1");
// KO : when ncue1 = 3, the TIRand range should be in [0,1] but I end up with a value of 2.
cueidx11=TIRand.ar(cueidx10+1,ncue1-1,trig1).poll(poll,"cue end 1");
 // KO: when ncue1 = 3, the TIRand range should be in [cueidx10,2] but I end up with a value of 3. 

The 2 last TIRand don’t behaves like expected.
I tried with some separated POC and it works fine, but there, no, it doesn’t work fine.

I tried to limit with max : cueidx10=TIRand.ar(0,ncue1-2,trig1).max(ncue1-2) but it doesn’t help.

Any idea ?

The buffer reads like this


This code snippet, sorry, is opaque to me. Out of context it’s hard to guess what’s actually happening.

In any case, ‘asInteger’ is a pure language-side operation, server-side you’d want ‘round’ as the server doesn’t know the Integer class. Then, the signal from LocalIn is delayed by one block. I cannot see how this all works together, but these two things could be responsible for unexpected behavior.

‘asInteger’ was just an attempt to solve my issue. I removed it.

This is a simplified version of the code.
It is about a “self-triggering” loop player. An initial trigger. The Synth computes a duration. Releases the first loop and starts the second one. The Synth computes a duration. for that one too. Upon release restart the loop 1 with new randomly selected parameters.

// loop 1
trig1=LocalIn.ar(1,0)+Impulse.ar(0); // loop1's trigger is an initial trigger + the release of the loop2

// .. buffer and cue points choice
bufidx1=TIRand.ar(0,nbuf-1,trig1).poll(poll,";1_buff index"); // randomly select the buffer index for the loop1
bufnum1=BufRd.ar(1,bBufnum,bufidx1); // bufnum the choosen buffer
ncue1=BufRd.ar(1,bBufnum,nbuf+bufidx1); // # cue points for that buffer
// vvv Those are the ones behaving strangely
cueidx10=TIRand.ar(0,ncue1-2,trig1).poll(poll,";1_cue start");  // randomly select a start cuepoint
cueidx11=TIRand.ar(cueidx10+1,ncue1-1,trig1).poll(poll,";1_cue end"); // randomly select a end cuepoint (after the start cuepoint)
// ^^^ Those are the ones behaving strangely

offset1=Latch.ar(BufRd.ar(1,bBufnum,2*nbuf+bufidx1),trig1); // offset for the buffer in the cuepoint array/buffer
start1=Latch.ar(BufRd.ar(1,cBufnum,offset1+cueidx10),trig1).poll(poll,";1_start"); // real start cuepoint
end1=Latch.ar(BufRd.ar(1,cBufnum,offset1+cueidx11),trig1).poll(poll,";1_end"); // real end cue point

// .. gate
delay1=Latch.ar(((end1-start1)/BufSampleRate.kr(bufnum1)),trig1).poll(poll,";1_delay"); // duration between start and end
rel1=DelayN.ar(trig1,\maxdelaytime.ir(10),delay1); // delay the trigger to get the release trigger
gate1=SetResetFF.ar(trig1,rel1); // build a gate to be used in SelectX

// loop 2
trig2=rel1; // loop2's trigger is loop1's release
// .. buffer and cue points choice
bufidx2=TIRand.ar(0,nbuf-1,trig2).poll(poll,";2_buff index");
// vvv Those are the ones behaving strangely
cueidx20=TIRand.ar(0,ncue2-2,trig2).poll(poll,";2_cue start");
cueidx21=TIRand.ar(cueidx20+1,ncue2-1,trig2).poll(poll,";2_cue end");
// ^^^ Those are the ones behaving strangely


// .. gate
delay2=Latch.ar((end2-start2)/BufSampleRate.kr(bufnum2),trig2).poll(poll,";2_delay");// /BufRateScale.kr(bufnum2);
// gate2=(1-gate1)*EnvGen.kr(Env([0,0,1], [0.1, 0]));

Poll.ar(trig1,delay1, "----TRIG 1-- delay1");
Poll.ar(trig2,delay2, "----TRIG 2-- delay2");

// publish loop2's release, to be used as loop1's trigger in next iteration

From time to time, one of the delays ‘delay1’ and ‘delay2’ gets negative.
The reason is that cueidx10/cueidx11 and/or cueidx20/cueidx20 are out-of-range.
The ‘hi’ limit of the TIRand is 2, and the TIRand outputs 3.
And then it is a cascade. The entire synth starts making non-sense.

Full code is here.

Phew, I’d need much more time to look through that and I haven’t (late here) –
maybe someone else can chime in …

My first guess is that it has to do with block calculation, you could check after server options set to blockSize 1 (and reboot).

From my notes on TIRand:

Note: Audio-rate inputs for lo and hi are currently broken in SuperCollider

So I guess you are running into that bug… You can try inserting A2K.kr for audio-rate inputs.

That’s why I didn’t post the full code initially :innocent:

I wrote it like this:


And although the random part seems to be done correctly, I end up loosing triggers. Probably due to the mix of Control and Audio rates… :pensive:

No positive impact. Neither on original version nor on the K2A version.

There is one thing I don’t get: how are initialized the variables ?

cueidx20=K2A.ar(TIRand.kr(0,ncue2-2,trig2)).poll(poll,";2_cue start");

How does SC initialize the value of cueidx20 before trig2 occurs ? I expected it to be 0 or nil. But there is a value
“;2_cue start: 2
It seems that SC “play” the TIRand at the begining, ignoring default values.
Why ? Is it due to the bug I went into the other day ?

From cursory glance on your code (without understanding every detail), you may want to:

  • if you have an audio rate trigger, and want to use it for a kr signal, use T2K instead of A2K
  • if you read single values from a buffer, like looking up the cue numbers, better use Index instead of BufRd, also here I guess you can use Index.kr instead of .ar. I think all of your BufRd are probably easier as Index.
  • I think the kr extends to the other parts; do you need Latch.ar or just Latch.kr?
  • LocalIn / LocalOut stuff is always prone to errors, because of initialisation and delay. Easy to get it wrong and get glitches.

I hope that helps

1 Like

I’ll rewrite my code. With proper segregation between .ar and .kr

Two causes I think:

  • a buggy TIRand.ar (I’ll try to make a mcve for this and report the bug on github if not already done)
  • Some confusion (read misconception) and unseeded use of Audio rates instead of Control Rates.

@Sciss, @dkmayer Thanks a lot for your support.

Search reveals this ticket: https://github.com/supercollider/supercollider/issues/1278

But it says it was closed with PR and tests (which apparently do not fix the issues). I re-opened the ticket.