giuliomoro Nice, I spoke to some others about it, but since DigitalIn is a Bela specific ugen, there's no documentation about it's ability to control anything within supercollider on Bela

Fair enough, however I think this can be generalized to a "vanilla" Supercollider question as: "How do I trigger a synth on the language in response to SendReply()message from the server?"

For something to happen on the server completely: similar examples would be in the MouseButton UGen documentation. That is basically a digital input, running on the server, just like DigitalIn on Bela.

For more complex situations, like instantiating a new synth, you will have to use SendReply, to send an OSC message to the language, and instantiate the synth from the OSCFunc that reacts to the SendReply.

Or, alternatively: use the Pause UGen in the synth you want to start/stop and route the DigitalIn to that (e.g. via a bus).

And feel free to post your code, it is much easier to give advice if we can see the code that you are using to attempt what you want to achieve.

Wicked - there is no documentation of AnalogIn or DigitalIn, so knowing what they can actually do with examples is really needed:

Code i'm trying:

		// 1am anger.
		SynthDef(\shh, {
			arg out=~outBack, t_trig=0;
			var sound, env;
			sound = Mix(LFPulse.ar(110*[1,5/2],0.0,0.5,0.2));
			env = EnvGen.ar(Env.perc(0.02,0.2), t_trig);
			sound = Pan2.ar(sound * env,0.0);
			Out.ar(out, sound);
		}, [\tr]).add;


		~buttonMonitor = {
			var d0 = DigitalIn.kr(0); // Digital pin 0 - Button
			var d1 = DigitalIn.kr(1); // Digital pin 1 - Button
			var d2 = DigitalIn.kr(2); // Digital pin 2 - Button
			var d3 = DigitalIn.kr(3); // Digital pin 3 - Button

			SendReply.kr(Impulse.kr(10), '/buttonMonitor', [d0, d1, d2, d3]);
		}.play;


		~button1 = 0;
		~button2 = 0;
		~button3 = 0;
		~button4 = 1;

		// Listen to the buttons
		OSCdef('listenToButtons', {
			arg msg;
			// Buttons
			~button1 = msg[3].asInteger;
			~button2 = msg[4].asInteger;
			~button3 = msg[5].asInteger;
			~button4 = msg[6].asInteger;

			["Buttons: " ++ ~button1, ~button2, ~button3, ~button4 ].postln;
		}, '/buttonMonitor');



		{
			q = Synth(\shh);
 			q.set(\t_trig, Pfunc({~button3}));
		};

Trying to get any 'button' to actually trigger a sound, nothing seems to work and it's an endless hole of errors in the console.

Trying to also trigger one sound in a sequence of buffers, so each button is the next buffer number, which is as simple as saying, have a DigitalIn choose from an array of numbers.

Also, MouseButton is almost nothing like DigitalIn, in the sense that DigitalIn(0) is pin D0, but what are the extra values I can pass through to this like this example:

{ SinOsc.ar(MouseButton.kr(440, 740, 2), 0, 0.1) }.play;

How do you replace MouseButton with DigitalIn in this example?

    5 days later

    Ok, four days into the Expo and I'd really love to introduce buffers into the code, the synths are ok, but could be improved with samples.

    This is the code i'm running, I'm trying to get the analogin to chose the buffer number, but 'Index not integer' is my problem.

    I found a crude way to change sounds on the fly without the bela exploding, but it means running the ugens for digitalin and analogin right in the synthdef.

    SynthDef(\samplePlaying, {
    	arg atk=0, sus=0, rel=3, c1=1, c2=(-1),
    	buf=0, rate=1, spos=0, freq=440, rq=1, bpfmix=0,
    	pan=0, amp=1, out=0;
    	var sig, env, sound, sample, 
    buffersAvailable=[0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
    	sample = Select.ar( ((0.4).linlin(0.01, 1, 0, 19).nearestInList(buffersAvailable)), buffersAvailable);
    	sound = b[\drum_kit][1 * sample];
    	
    	env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1,0,c2]), gate: 1 );
    	sig = PlayBuf.ar(1, sound, rate*BufRateScale.ir(sound), startPos:spos);
    	sig = XFade2.ar(sig, BPF.ar(sig, freq, rq, 1/rq.sqrt), bpfmix*2-1);
    	sig = sig * amp;
    	sig = Pan2.ar(sig, pan, amp);
    	Out.ar(out, sig);
    }).send(s);

    Whats the approach I should be taking to trigger this synth when a button is pressed and to map a sensor to choosing a new buffer number?

    ok, I think the issue may be with using Impulse to send over the messages.

    What if you change the button monitor to:

    ~buttonMonitor = {
    			var d0 = DigitalIn.kr(0); // Digital pin 0 - Button
    			var d1 = DigitalIn.kr(1); // Digital pin 1 - Button
    			var d2 = DigitalIn.kr(2); // Digital pin 2 - Button
    			var d3 = DigitalIn.kr(3); // Digital pin 3 - Button
    
    			SendReply.kr(Changed.kr(d0+d1+d2+d3), '/buttonMonitor', [d0, d1, d2, d3]);
    		}.play;

    Then a message gets sent each time one of the DigitalIn values changes, and not 10 times per second. With 10 times per second you may miss a button change.

    I'm also not entirely sure how you use Pfunc in your code, Pfunc is something you'd normally use in Patterns and would allow you to access the button value in a running pattern sequence, but the timing of when the button is then read is determined by the pattern, not by when the button value changes.

    But I think for your application, I would look at Dseq and use the button input as a trigger for the Demand.kr ugen (the button input can of course first be sent to a bus with Out.kr, and then read into your synth with In.kr, this is normal routing on the server). See the Dseq helpfile.

    PS, I forgot to turn on 'following' for this thread, so I didn't get notifications when new messages appeared. I'm not a regular visitor to the forum, but when I see an email message (which is generated when putting @... in a reply) I will try and go to the forum if I have the time.

    PPS, and yes, it would be great if there was incredibly extensive documentation on how to use UGens. We put in a lot of volunteer effort into making SuperCollider run on Bela and writing the UGens, writing basic helpfiles, and then in making basic examples, which are available as example projects in Bela, see e.g. https://github.com/BelaPlatform/Bela/blob/master/examples/12-SuperCollider/2-digital-in/_main.scd. So it is not like there is no documentation at all.

    DigitalIn is a UGen that produces a 1 or a 0 based on a button press. From there on it is regular supercollider usage. Of course, since Bela's strength is running everything on the server, rather than in the language, that does require a different thinking than most usual SuperCollider programming. I'd love to write an extensive tutorial on this, but I'd need to find time for this. But this is hard: I'm working as a freelancer with a bunch of other (paid) projects on my plate right now.

    eyeversuseye
    MouseButton.kr( lag: 0 ) would be the same as DigitalIn.kr

    A replacement would be:
    { SinOsc.ar( DigitalIn.kr( 0 ).lag(2).range(440,740), 0, 0.1 ) }.play

    Absolutely, I understand that writing software that is open-sourced and non-paid is time consuming and doesn't put food on the table, so I really appreciate your help on this.

    I'll give Changed.ar a try with triggering.

    An alternative way of asking this question, is how do we use DigitalIn to create a new synth and destroy the previous one - the machine i've built has a turnwheel that triggers a button with every rotation. I tried loading a buffer of 20 samples to trigger a new sample with every button press, but the walls i've hit are too tall for me to pass

    I think you are already quite close, change the synthdef to:

    SynthDef(\samplePlaying, {
    	arg atk=0, sus=0, rel=3, c1=1, c2=(-1),
    	firstbuf=0, rate=1, spos=0, freq=440, rq=1, bpfmix=0,
    	pan=0, amp=1, out=0;
    	var sig, env, sound, sample;
        var trig;
        var buffersAvailable=(0..19);
    	var bufseq;
        trig = DigitalIn.kr( 0 );
    	bufseq = Dseq( buffersAvailable, inf );
    	sample = Demand.kr( trig, 0, bufseq ) + firstbuf; // firstbuf is the index of the first buffer
    	
    	env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1,0,c2]), trig );
    	sig = PlayBuf.ar(1, sample, rate*BufRateScale.ir(sound), trig, startPos:spos);
    	sig = XFade2.ar(sig, BPF.ar(sig, freq, rq, 1/rq.sqrt), bpfmix*2-1);
    	sig = sig * amp;
    	sig = Pan2.ar(sig, pan, amp);
    	Out.ar(out, sig);
    }).send(s);

    Not tested, but should be something along those lines.

    It assumes that you load the samples into 20 consequetive buffers and you can pass firstbuf as an argument to set the bufnum of the first buffer. The DigitalIn will trigger changing to a new buffer, and starting to play the buffer and retriggering the envelope.

      nescivi Almost, but the error:

      The preceding error dump is for ERROR: Primitive '_BasicAt' failed.
      Index not an Integer

      appears, as i can't seem to get this:

      sample = Select.ar( ((0.4).linlin(0.01, 1, 0, 19).nearestInList(buffersAvailable)), buffersAvailable);

      To be an integer, no matter what I've tried

        nescivi This is the one! All that is missing is how I control the buffers being played — Using a dictionary to load buffers from subfolders and assign them symbols like so:

        	b = Dictionary.new;
        	PathName(~path).entries.do {
        		arg subfolder;
        		b.add(
        			subfolder.folderName.asSymbol ->
        			Array.fill(
        				subfolder.entries.size,
        				{
        					arg i;
        					Buffer.read(s, subfolder.entries[i].fullPath);
        				}
        			)
        		);
        	};

        Allows me to say b[\drum_kit][0].play;

        With the code you've just changed, would I be right in thinking I can't simply prepend the sample name to the Demand.ar

          Oh, but we don't have to use Demand at all do we 😃

          		(
          		// Buffers/Sound files loaded from dictionary
          		SynthDef(\samplePlaying, {
          			arg atk=0, sus=0, rel=3, c1=1, c2=(-1),
          			firstbuf=0, rate=1, spos=0, freq=440, rq=1, bpfmix=0,
          			pan=0, amp=1, out=0;
          			var sig, env, sound, sample;
          		    var trig;
          		    var buffersAvailable=(0..19).scramble;
          			var bufseq;
          			trig = DigitalIn.kr(0);
          			bufseq = Dseq( buffersAvailable, inf );
          			
                                  /////////////////////
                                  sample = AnalogIn.ar(0).linlin(0.01, 1, 0, 19); // Pick the buffer, based on Analog sensor
          			/////////////////////
          			
          			env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1,0,c2]), trig );
          			sig = PlayBuf.ar(1, sample, rate*BufRateScale.ir(sample), trig, startPos:spos);
          			sig = XFade2.ar(sig, BPF.ar(sig, freq, rq, 1/rq.sqrt), bpfmix*2-1);
          			sig = sig * amp;
          			sig = Pan2.ar(sig, pan, amp);
          			Out.ar(out, sig);
          		}).send(s);
          		);

            eyeversuseye
            the notations b[\drum_kit][0] works on the language side, not on the server side - that is also why you got the error messages for the buffer selection in your first version of the synthdef: you were trying to use the language representation of a buffer (an instance of Buffer) within the Synthdef. For things like that please check the "client-vs-server"-helpfile to get a better understanding of what happens in the language and what on the server.

            You would pass on the index of your first drumkit buffer to the Synth like this:

            a = Synth.new( \samplePlaying, [ \firstbuf, b[\drum_kit][0].bufnum ] );

            eyeversuseye Ok, I thought you wanted to play a new sample at each button press from a sequence of buffers. I missed that you wanted to select the sample with that analog control.
            Yes, then your solution works. And you can even leave out the bufseq=....
            I would add the firstbuf to sample, as your first buffer is not necessarily always the one at bufnum 0:
            sample = AnalogIn.ar(0).linlin(0.01, 1, 0, 19) + firstbuf;

              nescivi interestingly, the analogIn can trigger the samples and cause a bunch of glitching - perhaps rounding would solve the issue?