Using plot data as modulation source

Hi guys,

Happy xmas to everyone, hope you are having a good one.

I am trying to recreate some stuff I would do easily on my other environments to use with my wacom tablet, but couldn’t find the solution yet in SC.

Basically what I would like is to use the plot.value as a modulation source, so I can create let’s say a “custom LFO’s” for synth parameters. However I am stuck reading the plot.value with tableRead , as you can see in the tableOut variable (which is just pseudo-code to show what I am trying to archive).

Thanks a lot in advance!

var tableRead, 
	tableSpeed = 1, 
	tableSteps = 100, 
	tableOut = 0;

  tableRead = {, 0, 0.5, 0.5)}.play; // can be any other shape.
  t = Array.series(tableSteps , 0.0, 1 / tableSteps ).plot; // Start with a ramp then can be anything using "e" shortcut.
  tableOut = t.value[tableRead.range(0, tableSteps)] // >>> How can we return the current table value at index from readTable Ramp? <<<

My suggestion would be to store or read the data into a Buffer and then use something like PlayBuf or BufRd to access it in the synth.

1 Like

hey @shiihs.

Thank you, I was looking BufWr / BufRd example (below) in the documentation, but I am not familiarized enough yet with SC. I’ve tried but I am not really sure how to write/read the values from an edited plot. It doesn’t need to be Audio Rate , can be Kr. What I am looking for is basically to sequence synth parameters by drawing plots. Would be too much to ask for a simple example that I can study?

Thanks a lot in advance.

// allocate a buffer for writinig into
s = Server.local;
s.sendMsg(“/b_alloc”, 0, 44100 * 2);

//write into the buffer with a BufWr
y = { arg rate=1;
var in;
in =, 300, 400), 0, 0.1);, 0,, * rate, 0,;
0.0 //quiet

//read it with a BufRd
x = { arg rate=1;, 0,, * rate, 0,

x.set(\rate, 5);
y.set(\rate, 2.0.rand);
x.set(\rate, 2);

For a mono signal all values will be stored in ~p.value[0], for a stereo signal the right side values will be stored in ~p.value[1];

~p = { }.plot();
~p.value[0].size // 479, at 48000 and a default plot duration of 0.01 second I was expecting 480, not sure where the last value went, maybe rounding error or something.
/// accessing values sample by sample
~p.value[0][0] // = 0.01833
~p.value[0][1] //  = 0.3666

Hope this helps

1 Like

Maybe you are looking for this?
Make sure to look at the demo video… pretty impressive stuff :smiley:

1 Like

Thanks Thor, that helps a lot indeed.

Wow, superb stuff! Thanks for sharing, I will check this out.

However what I am trying to do/understand should be lots easier to do, here a more simple example:

This is my plot data:

and here the simple code:

p = Array.series(10).plot(); // data 
v = p.value.normalize;  // normalize plot values
i = {, max: p.value.size - 1)}.play;  // a counter to access to v indexes.
o = v[i]; // should return the output value, got error saying Index is not a integer?

I am trying to understand why the “o” variable is not working? Any ideas what I am doing wrong here?

Thanks again guys!

Things are slightly more complicated than you expect because we’re mixing up two worlds here:

  • Arrays are a language-side concept,
  • but the synthesis stuff happes in the audio server, and both are pretty much separated from each other

The interpreter can run in an entirely different computer than the audio server. The distinction between the two worlds is one of those concepts that new users struggle with (I guess because the syntax of the language doesn’t make this distinction very explicit).

Anyway to cut a long story short - forget about using Array in the audio server: if you want to access tables in the audio server, you have to put them into a Buffer. You can transfer data from an Array to a Buffer via the Buffer.loadCollection method.

My apologies, I don’t have time at the moment to make new code dedicated to your use case, but part of what you need is demonstrated in this code: transfering data from array to buffer and accessing it on the server:

1 Like

Thanks a lot mate,

Very appreciated, that makes total sense, I need to learn/practice some concepts, some stuff is relative easy to follow, but I go stuck often mostly because I am trying to extrapolate stuff from my environments, so I will keep reading more stuff, so deep and awesome app.

I will check Buffer.collect :+1:


Quick and dirty demo:


// some random data
a = Array.fill(10, { 1.0.rand2 });

// as a buffer
// (loadCollection uses a temp disk file.
// this array is so short, that's not necessary.)
b = Buffer.sendCollection(s, a, numChannels: 1);

// modulation value bus
c = Bus.control(s, 1);

m = {
	// normalize to 0-1
	var phase = * 0.5 + 0.5;
	// loop, plus cubic interpolation
	// if you want steps, use interpolation: 1, b, phase *, loop: 1, interpolation: 4);
}.play(outbus: c);

x = {
	var mod =, 1);
	// 'linexp' is just to map the normalized modulator onto real frequencies
	// you can use any function you need here
	(, 1, 200, 800)) * 0.1).dup



wow, so useful! Thanks for making this example. I’ve learnt a lot from it. Love the bus example, this is a thing I’ve not explored yet, and seems very important to know it well.

I’ve made a quick test using plotted data to control GrainBuf Sample Position and it worked great.

Also I’ve added a speed variable, it should look like this?

m = {
	// normalize to 0-1
    var speed = 1/4; // Speed 
	var phase = * 0.5 + 0.5;
	// loop, plus cubic interpolation
	// if you want steps, use interpolation: 1, b, phase * , loop: 1, interpolation: 4);
}.play(outbus: c);

Thank you once again, your guys rule.

1 Like