Overwriting/editing plotMode \bars

Hi,

for an additive synthesis project, I am trying to visualize some control signals: I basically have two arrays with signals that only slowly change, one with frequencies and a corresponding one with amplitudes. Ideally, I would want a plot that draws bars or lines for each entry whereas the y-value corresponds with the amplitude and the x-value with the frequency. However, when I use the plotMode \bars I can’t set a custom width, instead some sort of gap is automatically calculated, which is not what I want.

Here is my approach:

(
var plot;
var max_freq = 2000;

x = {
	var freqs = [100, 200, 400] * MouseX.kr(1, 2);
	var amps = [1, 1, 0.5] * MouseY.kr(0, 1);
	SendReply.kr(Impulse.kr(10), '/kr_signals', [amps++freqs]);
}.play;

plot = Plotter("the plot", Rect(600, 30, 600, 400));
plot.plotMode_(\bars);
plot.refresh;
o = OSCFunc(
	{
		arg msg;
		{
			plot.setValue(arrays:msg[3..5], minval:0, maxval:1);
			plot.domainSpecs_([0, max_freq, \lin].asSpec);
			plot.domain_(msg[6..]);
		}.defer;
	},
	'/kr_signals',
	s.addr
);
)

And here is the implementation of \bars:

Is there any way to write my own version of bars and easily integrate it?

Alternatively, I tried to solve this using Pen functions, however, I am stuck with getting some Qt: Usage of QPen is not allowed at this point! errors when switching from constants to signals in my arrays:

(
var plot;
var max_freq = 2000;
var width = 800;
var height = 200;
var margin_bottom = 10;
var margin_top = 20;
var window = Window("The Plot", width@height).front;
var y0, y1, x0;

x = {
	var freqs = [100, 200, 400] * MouseX.kr(1, 2);
	var amps = [1, 0.75, 0.5] * MouseY.kr(0, 1);
	SendReply.kr(Impulse.kr(10), '/kr_signals', [amps++freqs]);
}.play;


window.drawFunc_({

	// x-axis:
	Pen.line(0@(height - margin_bottom), width@(height - margin_bottom));

	o = OSCFunc(
		{
			arg msg;
			{
				var freqs = msg[6..];
				var amps = msg[3..5];
				freqs.postln;
				// draw lines:
				freqs.do(
					{
						arg item, index;
						x0 = width/max_freq * item;
						y0 = height - margin_bottom;
						y1 = y0 - (amps[index] * (height - margin_bottom - margin_top));
						Pen.line(x0@y0, x0@y1);
					}
				);
				Pen.stroke;
			}.defer;
		},
		'/kr_signals',
		s.addr
	)
});
)

I don’t know about the first question, but the second question – about Pen:

The drawFunc should only do the drawing, using Pen. But your drawFunc doesn’t do any drawing – it installs an OSCFunc. (Also note that this means you’ll create a new OSCFunc every time the window is refreshed – so, eventually, you could have hundreds or thousands of OSCFuncs.)

When the OSCFunc is triggered, this is not in the context of drawing – it’s in the context of receiving OSC.

A better structure would be to use the OSCFunc to save the data to be drawn and trigger a refresh:

(
var plot;
var max_freq = 2000;
var width = 800;
var height = 200;
var margin_bottom = 10;
var margin_top = 20;
var window = Window("The Plot", width@height).front;
var y0, y1, x0;

var freqs, amps;

o = OSCFunc({ arg msg;
	freqs = msg[6..];
	amps = msg[3..5];
	freqs.postln;
	// HERE is how to trigger drawing from OSC
	defer { window.refresh };
},
'/kr_signals',
s.addr
);

x = {
	var freqs = [100, 200, 400] * MouseX.kr(1, 2);
	var amps = [1, 0.75, 0.5] * MouseY.kr(0, 1);
	SendReply.kr(Impulse.kr(10), '/kr_signals', amps++freqs);
}.play;

window.drawFunc_({
	
	// x-axis:
	Pen.line(0@(height - margin_bottom), width@(height - margin_bottom));
	
	freqs.do(
		{
			arg item, index;
			x0 = width/max_freq * item;
			y0 = height - margin_bottom;
			y1 = y0 - (amps[index] * (height - margin_bottom - margin_top));
			Pen.line(x0@y0, x0@y1);
		}
	);
	Pen.stroke;
	
});
)

hjh

1 Like

Thanks @jamshark70, this worked perfectly and thanks for the explanation! I wasn’t really so sure about my structure to begin with, but yours makes much more sense!