Accessing array items in synth throws Error

I have defined a global variable holding an array of buffers, which I try to access by indexing it inside a synthdef. Here is my code, the ~bufsEins.at(0) etc. seems to be causing the error! Can anyone see where the error

ERROR: Primitive ‘_BasicNew’ failed.
Index not an Integer
RECEIVER: Array

comes from?

(
SynthDef(\eins, {
	arg
	count1=1, count2=1, count3=1, count4=1, count5=1, count6=1, count7=1, count8=1,
	buf1rateA=1, buf1rateB=1,
	buf2rateA=1, buf2rateB=1,
	buf3rateA=1, buf3rateB=1,
	buf4rateA=1, buf4rateB=1,
	buf5rateA=1, buf5rateB=1,
	buf6rateA=1, buf6rateB=1,
	buf7rateA=1, buf7rateB=1,
	buf8rateA=1, buf8rateB=1,
	// Duration
	atktime=0.01,
	reltime=1;
	var duration = atktime + reltime;
	var b1 = ~bufsEins.at(0);
	var b2 = ~bufsEins.at(1);
	var b3 = ~bufsEins.at(2);
	var b4 = ~bufsEins.at(3);
	var b5 = ~bufsEins.at(4);
	var b6 = ~bufsEins.at(5);
	var b7 = ~bufsEins.at(6);
	var b8 = ~bufsEins.at(7);
	var trig1 = Impulse.ar(count1 / duration);
	var trig2 = Impulse.ar(count2 / duration);
	var trig3 = Impulse.ar(count3 / duration);
	var trig4 = Impulse.ar(count4 / duration);
	var trig5 = Impulse.ar(count5 / duration);
	var trig6 = Impulse.ar(count6 / duration);
	var trig7 = Impulse.ar(count7 / duration);
	var trig8 = Impulse.ar(count8 / duration);
	var allowTrig1 = (PulseCount.ar(trig1) <= count1);
	var allowTrig2 = (PulseCount.ar(trig2) <= count2);
	var allowTrig3 = (PulseCount.ar(trig3) <= count3);
	var allowTrig4 = (PulseCount.ar(trig4) <= count4);
	var allowTrig5 = (PulseCount.ar(trig5) <= count5);
	var allowTrig6 = (PulseCount.ar(trig6) <= count6);
	var allowTrig7 = (PulseCount.ar(trig7) <= count7);
	var allowTrig8 = (PulseCount.ar(trig8) <= count8);
	var mix = Mix.fill(
		[
			PlayBuf.ar(
				numChannels: b1.numChannels,
				bufnum: b1,
				rate: BufRateScale.kr(b1) * Line.kr(buf1rateA, buf1rateB, duration),
				trigger: trig1 * allowTrig1,
				doneAction: 2 - (2 * allowTrig1)
			),
			PlayBuf.ar(
				numChannels: b2.numChannels,
				bufnum: b2,
				rate: BufRateScale.kr(b2) * Line.kr(buf2rateA, buf2rateB, duration),
				trigger: trig2 * allowTrig2,
				doneAction: 2 - (2 * allowTrig2)
			),
			PlayBuf.ar(
				numChannels: b3.numChannels,
				bufnum: b3,
				rate: BufRateScale.kr(b3) * Line.kr(buf3rateA, buf3rateB, duration),
				trigger: trig3 * allowTrig3,
				doneAction: 2 - (2 * allowTrig3)
			),
			PlayBuf.ar(
				numChannels: b4.numChannels,
				bufnum: b4,
				rate: BufRateScale.kr(b4) * Line.kr(buf4rateA, buf4rateB, duration),
				trigger: trig4 * allowTrig4,
				doneAction: 2 - (2 * allowTrig4)
			),
			PlayBuf.ar(
				numChannels: b5.numChannels,
				bufnum: b5,
				rate: BufRateScale.kr(b5) * Line.kr(buf5rateA, buf5rateB, duration),
				trigger: trig5 * allowTrig5,
				doneAction: 2 - (2 * allowTrig5)
			),
			PlayBuf.ar(
				numChannels: b6.numChannels,
				bufnum: b6,
				rate: BufRateScale.kr(b6) * Line.kr(buf6rateA, buf6rateB, duration),
				trigger: trig6 * allowTrig6,
				doneAction: 2 - (2 * allowTrig6)
			),
			PlayBuf.ar(
				numChannels: b7.numChannels,
				bufnum: b7,
				rate: BufRateScale.kr(b7) * Line.kr(buf7rateA, buf7rateB, duration),
				trigger: trig7 * allowTrig7,
				doneAction: 2 - (2 * allowTrig7)
			),
			PlayBuf.ar(
				numChannels: b8.numChannels,
				bufnum: b8,
				rate: BufRateScale.kr(b8) * Line.kr(buf8rateA, buf8rateB, duration),
				trigger: trig8 * allowTrig8,
				doneAction: 2 - (2 * allowTrig8)
			)
		]
	);
	Out.ar(0, mix * EnvGen.kr(Env.perc(attackTime: atktime, releaseTime: reltime)));
}).add;
)

Here is my code, the ~bufsEins.at(0) etc. seems to be causing the error!

In your code snippet ~bufsEins is not defined anywhere…

BTW, whenever you find yourself typing variables with lots of sequential number suffixes (e.g. var b1, b2, b3 ...), what you really need are Arrays!

There is lots of unnecessary code duplication in your example. By using arrays, that whole snippet could be reduced to roughly 16 lines of code!

If at were the cause, then the error would say _BasicAt instead of _BasicNew.

I don’t see where new is being called in the SynthDef, so I’d have to guess that the error is somewhere else.

hjh

1 Like

How would you avoid the code-repetitions in my example with an array?
Like an array of Impulses etc? Btw. ~bufsEins is just a global variable somewhere else defined, I didnt want to paste too much code! :slightly_smiling_face:

The top-part of the error says:

ERROR: Primitive ‘_BasicNew’ failed.
Index not an Integer
RECEIVER:
class Array (0x560272e593c0) {
instance variables [19]
name : Symbol ‘Array’
nextclass : instance of Meta_Array2D (0x560274b4cf80, size=19, set=5)
superclass : Symbol ‘ArrayedCollection’
subclasses : nil
methods : instance of Array (0x560274c02400, size=53, set=6)
instVarNames : nil
classVarNames : nil
iprototype : nil
cprototype : nil
constNames : nil
constValues : nil
instanceFormat : Integer 1
instanceFlags : Integer 0
classIndex : Integer 1551
classFlags : Integer 3
maxSubclassIndex : Integer 1551
filenameSymbol : Symbol ‘/usr/local/share/SuperCollider/SCClassLibrary/Common/Collections/Array.sc’
charPos : Integer 0
classVarIndex : Integer 5
}

Ok, I found the bug :exploding_head:
I had used Mix.fill instead of Mix.new
Such a pity that the error-reporting system of SC still is so un-understandable! :sleepy:

How would you avoid the code-repetitions in my example with an array?

Something like this:

(
SynthDef(\eins, { arg count = #[ 1, 1, 1, 1, 1, 1, 1, 1],
        bufrateA=#[ 1, 1, 1, 1, 1, 1, 1, 1 ],
        bufrateB=#[ 1, 1, 1, 1, 1, 1, 1, 1 ],
        atktime=0.01, reltime=1;
    
    var duration = atktime + reltime;
    var sigs = Array.fill(count.size, { |i|
        var b = ~bufsEins.at(i);
        var trig = Impulse.ar(count[i] / duration);
        var allowTrig = (PulseCount.ar(trig) <= count[i]);
        PlayBuf.ar(
            numChannels: b.numChannels,
            bufnum: b,
            rate: BufRateScale.kr(b) * Line.kr(bufrateA[i], bufrateB[i], duration),
            trigger: trig * allowTrig,
            doneAction: 2 - (2 * allowTrig)
        ) 
    });
    Out.ar(0, Mix.fill(sigs) * EnvGen.kr(Env.perc(attackTime: atktime, releaseTime: reltime)));
}).add;
)

Not tested, but I think you get the idea.

Again, whenever you find yourself writing something like var a1, a2, a3 etc., stop immediately and use Arrays! Code duplication is not only about code size, it is also very error prone. It is easy to make a tiny typo in one of the iterations, which can be very hard to debug. If you make the same typo in a loop, the error becomes much easier to spot. Also, with Arrays + loops you can easily change the number of iterations.

1 Like

Incidentally, there’s been some advice floating around, recommending to avoid Mix. I tend to agree – Mix isn’t necessary at all, because there’s .sum for arrays, and then it doesn’t matter whether you got the array by writing [stuff, otherStuff] or by writing Array.fill or anArray.collect – all cases get mixed down by .sum.

“Design an error reporting system that can provide cogent human-language explanations of every possible error that anyone could ever make” is not quite a realistically solvable problem. There have been efforts to provide better error messages on a case by case basis, but there are just too many possible scenarios – there’s no way to cover them all.

hjh

Very nice! Thank you for your comment!