Using a boolean value to determine if a ctlbus value is set

Hmm, still getting an error with this updated code using K2A.

		var signal = Trig.ar( delay_allId * button, 0.4);

		var outSignal = Select.ar(device==deviceId, [signal, K2A.ar(0)]); 
		
		Out.ar(ctlBus, outSignal); // Fails
		//Out.ar(ctlBus, signal); // Works

This is the first part of the error:

Select arg: 'which' has bad input: false
 ARGS:
   which: false False
   array: a Trig Trig
   2: a K2A K2A
SynthDef trigDetector build failed
ERROR: Select arg: 'which' has bad input: false

could you post the complete def you are using with the changes?

Here’s the complete SynthDef

	var digitalPins = [ 0, 1, 2, 3, 4, 5, 6, 7];
	var triggerCount = 1;

  	SynthDef(\trigDetector, {
		arg ctlBus, deviceId;

		var all = Array.fill(digitalPins.size, { |i|
		    DigitalIn.ar(digitalPins[i]);
		});
		
		// Convert all the bit array to a binary value
		var allId = all.reverse.reduce({ arg total, bit; total * 2 + bit }, 0);

		// Make sure they are set by delaying a little bit
		var delay_allId = TDelay.ar(in: allId, dur: 0.003);

		// Create bitmasks.  
		//  velMask is how many bit used for velocity
		//  devMask used for devices, of which there are only 2
		var velMask = pow(2, digitalPins.size - triggerCount) -1;
		var devMask = pow(2, triggerCount) - 1;

		// Use the masks to get the velocity and device that was activated
		var velocity = allId.bitAnd(velMask);
		var device = (allId >> (digitalPins.size - triggerCount)) & devMask;

		// Determine which device is set, left=0 or right foot=1
		var devtest = (device == deviceId);

		// scale button between 0 and 1 based on velMask
		var button = velocity / velMask;

		var signal = Trig.ar( delay_allId * button, 0.4);

		var outSignal = Select.ar(device==deviceId, [signal, K2A.ar(0)]); 
		
		Out.ar(ctlBus, outSignal); // Fails
		//Out.ar(ctlBus, signal); // Works
	}).send(s);

I don’t have DigitalIn installed, but substituting In.ar this synthDef compiles without errors over here…

I tried the same change as a test, and still got the same error. I modified this part. I believe it does build, but perhaps this is a runtime error?

		// var all = Array.fill(digitalPins.size, { |i|
		//     DigitalIn.ar(digitalPins[i]);
		// });
		
		// // Convert all the bit array to a binary value
		// var allId = all.reverse.reduce({ arg total, bit; total * 2 + bit }, 0);
		
		var allId = In.ar(0);

What does the error mean?

Select arg: 'which' has bad input: false

it means that the which arg for Select.new is boolean value false - the required type is Float - what happens if you use >= instead of == ? IIRC == does not produce a BinaryOpUGen so doesn’t work cheerfully in this context (an annoying gotcha).

Yes, >= doesn’t produce an error, though it doesn’t produce a sound either so I think it must be taking the K2A.ar(0) route? Should I have my channels reversed since 0 means signal and 1 means K2A.ar(0)?

I tested, and yes it works. But I need equivalency. How can I do an == like test?

I’m sure there is a better way to do this but if these are integer values you could do something like (x - y).abs < 0.9 ?

Try using |==|, that will create a BinaryOpUGen which will check for equivalency on the server.

Hooray, |==| worked! I had tried that before in a different context and it failed so I thought it wasn’t supported, but I guess it is. Thanks all for the help!

Hmm, wonder if I spoke too soon. 0 |==| 0 worked, but 1 |==| 1 doesn’t seem to work. Adding SendTrig I can see they are both 1. What happened?

	var digitalPins = [ 0, 1, 2, 3, 4, 5, 6, 7];
	var triggerCount = 1;

  	SynthDef(\trigDetector, {
		arg ctlBus, deviceId;

		var all = Array.fill(digitalPins.size, { |i|
		    DigitalIn.ar(digitalPins[i]);
		});
		
		// Convert all the bit array to a binary value
		var allId = all.reverse.reduce({ arg total, bit; total * 2 + bit }, 0);
		
		// Make sure they are set by delaying a little bit
		var delay_allId = TDelay.ar(in: allId, dur: 0.003);

		// Create bitmasks.  
		//  velMask is how many bit used for velocity
		//  devMask used for devices, of which there are only 2
		var velMask = pow(2, digitalPins.size - triggerCount) -1;
		var devMask = pow(2, triggerCount) - 1;

		// Use the masks to get the velocity and device that was activated
		var velocity = allId.bitAnd(velMask);
		var device = (allId >> (digitalPins.size - triggerCount)) & devMask;

		// scale button between 0 and 1 based on velMask
		var button = velocity / velMask;

		var signal = Trig.ar( delay_allId * button, 0.4);

		var outSignal = Select.ar(device |==| deviceId, [K2A.ar(0), signal]); 
		
		Out.ar(ctlBus, outSignal);
		Out.kr(ctlBus, outSignal);
		
		SendTrig.ar(HPZ1.ar(delay_allId), 23, device);
		SendTrig.ar(HPZ1.ar(delay_allId), 21, deviceId);
	}).send(s);

Output:

[ 189.401508982, [ /tr, 1001, 21, 1.0 ] ]
[ 189.402132955, [ /tr, 1001, 23, 1.0 ] ]
[ 190.399960345, [ /tr, 1001, 21, 1.0 ] ]
[ 190.400606776, [ /tr, 1001, 23, 1.0 ] ]

Just guessing, but maybe it’s due to a small fractional difference between the two floats which doesn’t show up in the posted representation. Could something like this be an option, outputting 1 when the difference is small enough?

Select.ar((device - deviceId).abs < 1e-06, [K2A.ar(0), signal]);

Though this does work. However, I would like to understand why |==| didn’t work.

		var outSignal = Select.ar(device - deviceId < 0.1, [K2A.ar(0), signal]); 
(0.1 + 0.1 + 0.1)
-> 0.3

(0.1 + 0.1 + 0.1) == 0.3
-> false

Basically: Floating point numbers lie to you. In binary, the only time they’re exact is if the denominator is a power of two. Otherwise, they’re approximations and == isn’t quite trustworthy with them.

Better keep the abs: abs(device - deviceId) < 0.1. Or write device absdif: deviceId.

hjh

OK, thanks for the explanation and code fix/tweak. Suppose when I do my bit twiddling the value I thought was 1.0 was not, though for whole numbers I thought it wasn’t an issue. Obviously, it is :slight_smile:

One thing with sclang that bites me all the time is the weak typing. Is there any way to make it strongly type so I can deal with integers instead? Or is everything a float for a reason?

everything is a Float on the server - this makes a good deal of sense as everything is a signal that could potentially be output - can’t send Chars out the DAC…- sclang itself is duck-typed. There is an experimental type system in the FPLib quark (though I can’t vouch for it not having tried it myself!)

You might also try ScalaCollider if you want to drive scsynth from a strongly typed language: GitHub - Sciss/ScalaCollider: A Scala sound synthesis library based on SuperCollider. Mirror of https://codeberg.org/sciss/ScalaCollider

I think my code is still not working as I expect. It doesn’t identify the device, and is always 1. Maybe because allId a float? Is it a signal or a just a value?

Is this doing shifts on a float? I’m trying to see if the highest bit, in this example bit 8, it one or zero. Is it doing what I think it’s doing?

Obviously I don’t grok yet :slight_smile: I think my problem is in my play routine which uses the control bus to trigger the sound. If anybody has any epiphanies to share or videos that spark them, let me know.

Below is the synthdef that listens on the control bus and outputs the trigger based on the incoming value. I used SendTrig to see that the signal being sent to Our.ar(ctlBus, outSignal) is zero. But still the buffer was played because I hear it. So next I’m going to experiment with the CtrlBus signal. Maybe I need a UGen or something there?

	var digitalPins = [ 0, 1, 2, 3, 4, 5, 6, 7];
	var triggerCount = 1;

  	SynthDef(\trigDetector, {
		arg ctlBus, deviceId;

		var all = Array.fill(digitalPins.size, { |i|
		    DigitalIn.ar(digitalPins[i]);
		});
		
		// Convert all the bit array to a binary value
		var allId = all.reverse.reduce({ arg total, bit; total * 2 + bit }, 0);
		
		// Make sure they are set by delaying a little bit
		var delay_allId = TDelay.ar(in: allId, dur: 0.003);

		// Create bitmasks.  
		//  velMask is how many bit used for velocity
		//  devMask used for devices, of which there are only 2
		var velMask = pow(2, digitalPins.size - triggerCount) -1;
		var devMask = pow(2, triggerCount) - 1;

		// Use the masks to get the velocity and device that was activated
		var velocity = allId.bitAnd(velMask);
		var device = (allId >> (digitalPins.size - triggerCount)).bitAnd(devMask);
		//var device = (allId >> (digitalPins.size - triggerCount));

		// scale button between 0 and 1 based on velMask
		var button = velocity / velMask;

		var signal = Trig.ar( delay_allId * button, 0.4);

		var outSignal = Select.ar(abs(device - deviceId) < 0.1, [signal, K2A.ar(0)]); 
		
		Out.ar(ctlBus, outSignal);
		Out.kr(ctlBus, outSignal);
		
		SendTrig.ar(HPZ1.ar(delay_allId), 20, device);
		SendTrig.ar(HPZ1.ar(delay_allId), 21, deviceId);
		SendTrig.ar(HPZ1.ar(delay_allId), 22, outSignal);
	}).send(s);
	
  SynthDef("sh",{ 
		arg buf = 0, rate = 1.0, loop = 0, scale = 1.0, vol = 1.0, t_reset=0, wetBus = 0, deviceId = 0, trigBus;

		var snd;
	

		var button = In.ar(trigBus);

		var latch = SetResetFF.ar(button, t_reset) ;
		
		var volmultraw = ((1.0 - scale) + (button*scale));
		
		var volmult = LastValue.ar((((1.0 - scale) + (button*scale))) * Schmidt.ar(button, 0.1, 0.1) ) ;
		
		//button.belaScope(1);

		n = LastValue.ar((((1.0 - scale) + ((button/3.2)*scale))) * Schmidt.ar(button, 0.1, 0.1) ) ;
		snd=PlayBuf.ar(2, buf, BufRateScale.kr(buf) * rate, trigger: button, loop: loop * latch, startPos: 0, doneAction: 0) * volmultraw * vol;

		// If we don't use LastValue, then the value is zero the next time and the sound is abruptly ended
		Out.ar(wetBus, snd);
		

		// Trigger debug msg
		// SendTrig.ar(button, 5, BufSamples.kr(buf));
		//SendTrig.ar(button, 5, button);
		//SendTrig.ar(HPZ1.ar(button), 5, volmultraw);
  }).send(s);

...

  b = Bus.audio(s, 1);
	
  //Synth.new("scope2", [\ctlBus, b]);
  k = Buffer.read(s, "/root/src/HarmProject/data/samples/Kick2.wav");
  Synth.new("sh", [trigBus: b, buf: k]);
  Synth.new("trigDetector", [\deviceId, 1.0, \ctlBus, b]);
  
  //SynthDef("scope2", { In.ar(b).belaScope(2); }).play;
  //SynthDef("scope2", { SinOsc.ar(550.2, 0, 1).belaScope(2); }).play;
  
  o = OSCFunc({ arg msg, time; [time, msg].postln; },'/tr');

This is the solution I found that works. Not really sure why. The problem seemed to be in the trigDetector SynthDef, not my sh SynthDef like I mentioned previously, though it has a different problem now. Perhaps new thread on that if I can’t figure it out :slight_smile: The main change was how I set signal, which I called outSignal before. BTW, using the belaScope tool helped a bunch. I think using SendTrig is messing me and my normal programming brain up.

	SynthDef(\trigDetector, {
		arg ctlBus, deviceId;

		var all = Array.fill(digitalPins.size, { |i|
		    DigitalIn.ar(digitalPins[i]);
		});
		
		// Convert all the bit array to a binary value
		var allId = all.reverse.reduce({ arg total, bit; total * 2 + bit }, 0);
		
		// Make sure they are set by delaying a little bit
		var delay_allId = TDelay.ar(in: allId, dur: 0.001);

		// Create bitmasks.  
		//  velMask is how many bit used for velocity
		//  devMask used for devices, of which there are only 2
		var velMask = pow(2, digitalPins.size - triggerCount) -1;
		var devMask = pow(2, triggerCount) - 1;

		// Use the masks to get the velocity and device that was activated
		var velocity = allId.bitAnd(velMask);
		var device = (allId >> (digitalPins.size - triggerCount)).bitAnd(devMask);

		// scale button between 0 and 1 based on velMask
		var button = velocity / velMask;

		// Combined this line to make it work
		var signal = Trig.ar( Select.ar(abs(device - deviceId) < 0.1, [K2A.ar(0), delay_allId * button]), 0.1);
		
		Out.ar(ctlBus, signal);
		Out.kr(ctlBus, signal);
		
		// SendTrig.ar(HPZ1.ar(delay_allId), 25, allId);
		// button.belaScope(2);
		// delay_allId.belaScope(0);
		// Pulse.ar(330.0, 0.5, 1.0, 0.0).belaScope(1);
	}).send(s);

Thanks everyone for all the help, each reply gets me a little closer to understanding.