Cycling Through Samples With A MIDI Device

I have stored my samples in a dictionary. Maybe this is superfluous but then I assigned each sample in the dictionary to a letter ~a - ~z so I can index them in my sampler SynthDef.

I can’t figure out the correct syntax for my sampler SynthDef.

Then I’d like to cycle through the different samples on my MIDI with a knob (ccNum = 1), but not play them. Once I choose the correct sample, play the sample with a button (ccNum = 17). But if one sample is playing and I choose another sample to play, I’d like the previous sample to stop.

I’d appreciate any help.

(
d = Dictionary.new;
d.add(\samples ->
	PathName("/Users/daniel/Documents/musicProjects/superColliderSamples/").entries.collect({
	arg sf;
	Buffer.read(s, sf.fullPath);
});
);
)


~a = d[\samples][0];
~b = d[\samples][1];
~c = d[\samples][2];
~d = d[\samples][3];
~e = d[\samples][4];
~f = d[\samples][5];
~g = d[\samples][6];
~h = d[\samples][7];
~i = d[\samples][8];
~j = d[\samples][9];
~k = d[\samples][10];
~l = d[\samples][11];
~m = d[\samples][12];
~n = d[\samples][13];
~o = d[\samples][14];
~p = d[\samples][15];
~q = d[\samples][16];
~r = d[\samples][17];
~s = d[\samples][18];
~t = d[\samples][19];
~u = d[\samples][20];
~v = d[\samples][21];
~w = d[\samples][22];
~x = d[\samples][23];
~y = d[\samples][24];
~z = d[\samples][25];


~samples1 = [
	~a, ~b, ~c, ~d, ~e, ~f,
	~g, ~h, ~i, ~j, ~k, ~l, ~m,
	~n, ~o, ~p, ~q, ~r, ~s, ~t, ~u, 
	~v, ~w, ~x, ~y, ~z;
];


(
~sampler = SynthDef(\sampler,{ arg out=0, val=~b, start, end, rate;
		var env, ptr, sig;
	env=	EnvGen.ar(Env([0,1,0], [0.1, 50]), doneAction:2);
	ptr = Phasor.ar(1, BufRateScale.kr(~samples1[val])*rate, start, end);
    sig = BufRd.ar(2, ~samples1[val], ptr);
		FreeSelfWhenDone.kr(sig);
		Out.ar(out, sig);
	}).add;
)


MIDIdef.cc(\on1, {
	arg val, num;
	case
	{num==17 && val==127} {a = Synth(\sampler, [\bufnum, ~a, \start, 0, \end,  0, \rate, 0.midiratio])}
})


MIDIdef.cc(\cc, {|val, ccNum|
	var index = val.linlin(0, 127, 0, ~samples.size - 1).round.debug(\incomingvalToIndex);
	a.do{|n, i| n.set(\bufnum, ~samples1[index][i]) }
}, 1, 0)

as you may have noticed, your SynthDef doesn’t compile. This is because you are trying to index into a language-side array (~samples1) using a server-side control (val)

Instead, just pass the appropriate Buffer into the synthdef:

(
SynthDef(\sampler, { arg out=0, buf, start, end, rate;
  var env, ptr, sig;
  env =	EnvGen.ar(Env([0,1,0], [0.1, 50]), doneAction:2);
  ptr = Phasor.ar(1, BufRateScale.kr(buf)*rate, start, end);
  sig = BufRd.ar(2, buf, ptr);
  FreeSelfWhenDone.kr(sig);
  Out.ar(out, sig);
}).add; 
)

Synth(\sampler, [buf: ~a, start: 0, end: ~a.numFrames, rate: 1])

But you will notice that this will not free itself after the file has played (because Phasor will just loop back to the beginning of the file), and the envelope is also not doing anything except freeing the synth 50.1 seconds after it starts… I’m not sure if either of these things is what you want; but if you want to play from start to end and then free the synth, one way is to use Line:

(
SynthDef(\sampler,{ arg out=0, buf, start, end, rate;
  var ptr, sig;
  ptr = Line.ar(start, end, (end - start) * rate / BufSampleRate.kr(buf));
  sig = BufRd.ar(2, buf, ptr);
  FreeSelfWhenDone.kr(ptr);
  Out.ar(out, sig);
}).add; 
)

Whichever of these is the behavior you want, now you can store the selected sample index in an environment var:

~selectedIndex = 4;

and make a function that will stop the currently playing sample and start the chosen one:

(
~startFunc = {
  var buf = ~samples1[~selectedIndex];
  ~synth.free;
  ~synth = Synth(\sampler, [buf: buf, start: 0, end: buf.numFrames, rate: 1]);
};
)

~startFunc.()

Now it should be simple to make MIDI functions that set the selected index and call the start function

2 Likes

I really appreciate the help. I have gotten farther.

When I hit the button (ccNum 17) on my device, the sample will play, but I have to quickly rotate the knob (ccNum 1) before the Synth leaves the server, otherwise it will just automatically choose index 1, which is what the global variable states, ~selectedIndex=1.

I tried using doneAction = 0 so the sampler SynthDef stays on the server but that doesn’t seem to work. And I need the knob to overwrite the global variable ~selectedIndex = 1, otherwise it just keeps overwriting the knob so it always equals 1.

~samples1 = [
	~b, ~c, ~d, ~e, ~f,
	~g, ~h, ~i, ~j, ~k, ~l, ~m,
	~n, ~o, ~p, ~q, ~r, ~s, ~t, ~u, 
	~v, ~w, ~x, ~y, ~z;
];



(
SynthDef(\sampler,{ arg out=0, buf, start, end, rate;
  var ptr, sig;
  ptr = Line.ar(start, end, (end - start) * rate / BufSampleRate.kr(buf), doneAction:0);
  sig = BufRd.ar(2, buf, ptr);
  FreeSelfWhenDone.kr(ptr);
  Out.ar(out, sig);
}).add; 
)


~selectedIndex = 1;


(
~startFunc = {
  var buf = ~samples1[~selectedIndex];
  ~synth.free;
  ~synth = Synth(\sampler, [buf: buf, start: 0, end: buf.numFrames, rate: 1]);
};
)

~startFunc.()


MIDIdef.cc(\on1, {
	arg val, num;
	case
	{num==17 && val==127} {~startFunc.()}
})



MIDIdef.cc(\cc, {|val, ccNum|
	var index = val.linlin(0, 127, 1, 25).round.debug(\incomingvalToIndex);
	~selectedIndex = index;
}, 1, 0)

I don’t really understand this. The knob isn’t setting anything on the server, and there is nothing changing the value of the environment variable ~selectedIndex except for the midi function.

(
~selectedIndex = 1;

MIDIClient.init;
MIDIIn.connectAll;

MIDIdef.cc(\cc, {|val, ccNum|
	var index = val.linlin(0, 127, 1, 25).round.debug(\incomingvalToIndex);
	~selectedIndex = index;
}, 1, 0);
)

then move the knob and evaluate

~selectedIndex

and see that its value is whatever the knob last set…

and

~startFunc.()

will then start the selected sample playing…

edit: it just occurred to me that the issue might be with the incoming midi? when you move the knob are you seeing your e.g. incomingvalToIndex: 18.0 debug messages?

I tried what you suggested but still running into the same issue.

Yeah, I’m seeing the 'incomingvalToIndex messages. I want to see which sample I’m choosing with the knob.

I notice that the incoming messages are almost always ‘0’, except when I move the knob, I see the other numbers but they are constantly jumping back to ‘0’. It’s not the value I last set with the knob.

ok then I think this is the problem: you are getting some errant MIDI input that is constantly sending 0 on cc 1.

  • what is the MIDI device you are using?
  • do you have other MIDI devices connected to your computer?
  • are other cc numbers also getting lots of 0s?

you can evaluate

MIDIFunc.trace

to post all incoming midi messages, which might help you figure out where they’re coming from

oh and

MIDIFunc.trace(false)

to stop the deluge :slight_smile:

When I press ccNum = 17 (button), I’m getting the incoming '0’s for as long as the sample lasts.

The sample is a couple of seconds long, and in that time, I get about 22 incoming zeroes, every time I press ccNum=17. Those '0’s corresponding to ~selectIndex

And the incoming zeroes keep going even when I’m not using the MIDI…

I’m using a MIDI device that has 4 buttons, and 16 knobs. That’s it. It’s a custom MIDI device that I bought on Etsy from a guy who builds his own MIDI boxes.

I don’t have any other MIDI devices plugged in.

if you run

MIDIFunc.trace

while you do this do you see a MIDI message before each incomingvalToIndex like this?

MIDI Message Received:
	type: control
	src: -702286827
	chan: 0
	num: 1
	val: 11

incomingvalToIndex: 3.0

I do see:

MIDI Message Received:
	type: control
	src: -702286827
	chan: 0
	num: 1
	val: 11

incomingvalToIndex: 3.0

and I don’t see the incomingvalToIndex messages anymore, but it’s the same pattern. I’m just getting approximately 22 of those MIDIFunc trace messages now whenever I hit the ccNum=17 button

can you copy and paste just what gets posted after you hit the cc17 button once?

It says ‘FAILURE IN SERVER…’ but I hear the sample

FAILURE IN SERVER /n_free Node 1002 not found
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0
incomingvalToIndex: 0.0

I get way more messages when I try the MIDIFunc.trace after pressing ccNum17. What’s pasted below is not even everything, it won’t all fit in the post window.

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 6
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 32
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 33
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 34
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 35
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 36
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 37
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 38
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 39
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 48
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 49
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 50
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 51
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 52
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 53
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 54
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 55
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 64
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 65
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 66
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 67
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 68
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 69
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 70
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 71
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 16
	val: 101

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 17
	val: 63

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 18
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 19
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 20
	val: 101

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 21
	val: 63

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 22
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 23
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 0
	val: 0

incomingvalToIndex: 0.0
MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 1
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 2
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 3
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 4
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 5
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 6
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 32
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 33
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 34
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 35
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 36
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 37
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 38
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 39
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 48
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 49
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 50
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 51
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 52
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 53
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 54
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 55
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 64
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 65
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 66
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 67
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 68
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 69
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 70
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 71
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 16
	val: 101

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 17
	val: 63

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 18
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 19
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 20
	val: 101

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 21
	val: 63

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 22
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 23
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 0
	val: 0

incomingvalToIndex: 0.0
MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 1
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 2
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 3
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 4
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 5
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 6
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 32
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 33
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 34
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 35
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 36
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 37
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 38
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 39
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 48
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 49
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 50
	val: 0

MIDI Message Received:
	type: control
	src: -443775684
	chan: 0
	num: 51
	val: 0

And then the zeroes just keep coming in even when I’m not doing anything… I have no idea what’s going on haha

well then use

MIDIFunc.trace(false)

to stop the messages and then

MIDIdef.cc(\cc, {|val, ccNum|
  if (val != 0) {
    var index = val.linlin(0, 127, 1, 25).round.debug(\incomingvalToIndex);
    ~selectedIndex = index;
  };
}, 1, 0)

to filter out all the 0s, is a quick fix

edit: but more broadly I think there might be something wrong with this controller?

1 Like

Wow that worked!! Haha, it’s now tracking whichever value the knob is at. No more of those zeroes. Thank you!!

happy to help. enjoy!