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?

              eyeversuseye yes, just add a .round(1) to it and it should be fine.
              linlin could also start at 0, so .linlin(0,1,0,19).round(1)

              9 months later

              Hey everyone!

              I developed your code trying to add one light as feedback for the synth. Could you verify what am I forgetting or doing wrong on this example?

              ....
              
              s.waitForBoot({
              	
              	SynthDef(\mic, {| inChan = 0,inPin, outPin| 
              		var in, outLed, button;
              		in = SoundIn.ar(inChan);
              		in.poll;
              		
              		button = DigitalIn.ar(inPin);
              		outLed = DigitalOut.ar(outPin, button); //Light  Digital pin 1 - Button
              	    
              	    Out.ar(0,in!2);
              	    
              	}).send(s);
              	
              
                s.sync;
                
              
              	~buttonMonitor = {
              			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(d1+d2+d3), '/buttonMonitor', [ d1, d2, d3]);
              		}.play;
              
              
              		~button1 = 0;  
              		~button2 = 0;   
              		~button3 = 0;   
              
                
              // Listen to the buttons
              		OSCdef('listenToButtons', {
              			arg msg;
              			// Buttons
              			~button1 = msg[3].asInteger;
              			~button2 = msg[4].asInteger;
              			~button3 = msg[5].asInteger;
              
              			["Buttons: " ++ ~button1, ~button2, ~button3].postln;
              		}, '/buttonMonitor');
              
              	
              	{
              			q = Synth(\mic, ['inPin', 0, 'outPin', 1]);
               			q.set(\t_trig, Pfunc({~button1}));
               	
              		};
              
              });
              5 years later

              Hi all,

              Excuse me diving back into this thread but I can't find a simple example of sending digital messages between the server and the client.

              Does anyone an example they could share?

              Many thanks

              Simon

              Ok this works for me....

              /*
              // obviously there are ways to shorten this code but it works for me and is 
              // a simple way to get buttons into the SuperCollider client environment.
              // a SynthDef running on the server to read buttons. 
              // (As I understand they have to be read on the server)
              // SendReply sends the button value 10 times a second from the server to the client
              */
              
              SynthDef('button_button_reads', {
              		var button1 = DigitalIn.ar(1);
              		var button2 = DigitalIn.ar(2);
              		SendReply.kr(Impulse.kr(10), '/button1', button1.value);
              		SendReply.kr(Impulse.kr(10), '/button2', button2.value);
              	}).play;	
              
              
              
              // this code picks up the button values.
              
              ~button1 = OSCFunc({ arg msg; ~button1value = msg[3]}, '/button');
              ~button2 = OSCFunc({ arg msg; ~buttontvalue = msg[3]}, '/button');