Confused as to how to control buffer playback with TouchOSC

I am trying to make a sample payback machine, like an MPC, that will be playable with Touch OSC. Im using the second page of the Simple MKII layout from Touch OSC (for now). I want the first push button to play the first 16th of a buffer, the second to play the second slice of audio, etc. I was told to use a gate or something? I could probably create 16 different synths and write the code that way but i want to use the array capabilities of SuperCollider.

[Is there an area or topic I would like specific feedback on?]

Buffer.freeAll;

/*(
~buffers = "C:/Users/ludov/OneDrive/Bureau/UNIVERSITY Projects/SuperCollider/Projet Final/PROJET FINAL/audio/AMEN_BREAK.wav".resolveRelative.pathMatch.collect({
	arg path;
	Buffer.read(s, path);
});
)
*/

~b0 = Buffer.read(s,"C:/Users/ludov/OneDrive/Bureau/UNIVERSITY Projects/SuperCollider/Projet Final/PROJET FINAL/audio/AMEN_BREAK.wav.wav");


~b0.play;
~b0.query;

(
SynthDef.new(\AmenBreak1, {
		arg bufnum = 0, rate = 1.0, amp = 1.0, pos = 0.0, pan = 0.0, loop = 0.0, dur = 0.5;
		var sig;
		16.do{
			sig = PlayBuf.ar(
			numChannels: 2,
			bufnum: bufnum,
			rate: BufRateScale.kr(bufnum)*rate,
			trigger:1,
			startPos: 0,
			loop:0,
			doneAction:2,
		);
		Out.ar(0, sig);

}})
)

(
~notes = Array.fill(16, {
	arg i ;
	i = (1/16)*i
});
)



(
16.do({//de 0 à 15
	arg num;
	OSCdef(("push"++(num+1)), {
		arg msg;
		msg.postln;

	}, "/2/push"++(num+1));
})
)

(
OSCdef(\play1, {
	arg msg;
	msg.postln;
	(msg[1] ==1).if(
		{~synths = ~notes.collect{
			arg note;
			Synth(\AmenBreak1,
				\startPos, ~notes[num]) ,
	}
	}),
		{~synths.do{
			arg synth;
			synth.free}
		};
}, "/2/toggle1");

)

First rule of thumb for interface work is: Get it working in code first. When you’ve got code that does what you want, then you can put hooks to the code into the interface objects’ action functions.

About the code – your SynthDef makes 16 buffer players, which look like they’re all doing the same thing. I think you don’t need 16.do at all.

You have a pos control name, but it isn’t plugged into anything, so your SynthDef can play only from the start of the buffer. Better connect that to startPos (which btw is in sample frames, not seconds). Seems you want pos to be 0.0-1.0 so: startPos: pos * BufFrames.kr(bufnum).

The synth should also have an envelope to control dur. Currently, wherever you start, it will play to the end of the buffer, and then release.

Your OSCdef code mentions startPos, but the SynthDef doesn’t have an argument with that name, so it will be ignored.

You don’t need to create a bunch of silent synths in response to the toggle. You could even just delete that whole block.

The push responder should just create a Synth to play its segment, on demand. The synth would free itself (doneAction: 2) when it’s finished.

After you can play any buffer segment by a Synth call, then you can put the Synth call into the push responder.

hjh

Hey! Thanks for the asnwer, i reworked my program, heres a updated version of it. Only problem now is that it seems the TouchOSC buttons are not working well, sending multiple copies of the send message (i.e. "
[ /2/push1, 1.0 ]
2
[ /2/push1, 1.0 ]
2
[ /2/push1, 1.0 ]
2
[ /2/push1, 1.0 ]
0
[ /2/push1, 1.0 ]
0
")

New program:

~b0 = Buffer.read(s,"C:/Users/ludov/OneDrive/Bureau/UNIVERSITY Projects/SuperCollider/Projet Final/PROJET FINAL/audio/AMEN_BREAK.wav.wav");


~b0.play;
~b0.query;



(
SynthDef.new(\AmenBreak1, {
		arg bufnum = 0, rate = 1.0, amplitude = 1.0, pos = 0.0, pan = 0.0, loop = 0.0, dur = 0.5, trig = 0.0;
		var sig,env ;
	        env = EnvGen.kr(Env([0, 1, 0.5, 1, 0], [0.001, 0.5, 0, 0]), 1.0, doneAction:2);
			sig = PlayBuf.ar(
			numChannels: 2,
			bufnum: bufnum,
			rate: BufRateScale.kr(bufnum)*rate,
			trigger:1,
			startPos: pos * BufFrames.kr(bufnum),
			loop:0,
			doneAction:2,
		);
		Out.ar(0, sig*env);

}).add;
)

(
~notes = Array.fill(16, {
	arg i ;
	i = (1/16)*i;
	});
)

(
16.do({
	arg num;
	OSCdef("push"++(num+1), {
		arg msg;
		msg.postln;
		num.postln;
		//~synths[num].set(\gate, msg[1]);
		Synth(\AmenBreak1, [\pos, ~notes[num+1]]);
	}, "/2/push"++(num+1));
});
)

I’m going to take a bit of an educated wild guess here (is that even a thing?) and suggest:

OSCdef(("push"++(num+1)).asSymbol, {
    ... responder code...
}, "/2/push"++(num+1));

The first value given to OSCdef is an identifier, which will be matched by an identity test (===), and not an equality test (==), because the identity test is much faster.

For names in collections, such as OSCdef, you should use symbols because symbols pass the identity test, while strings may not:

var a = "abc" ++ "def";
var b = "abc" ++ "def";

a == b
-> true

a === b
-> false

a.asSymbol === b.asSymbol
-> true

If you’re running the OSCdef block multiple times, you may end up with duplicate responders, unless you use symbols.

(I could be wrong – maybe OSCdef automatically converts to symbols…? In which case it would be a different issue. I’m not at the computer to check the code right now.)

hjh