Plot Buffer in Parent Window as GUI Action

EDITED: if this is against community guidelines, please let me know what the problem is.y post was flagged as inappropriate and I’m a bit confused.

I made a function that evaluates the Collatz conjecture (3n+1) for an integer, loads the result as the amplitude array argument of Signal.sineFill, which is then converted to a wavetable, loaded to a buffer, and so on.

I wanted to make a GUI with a slider and number box to choose the initial value of n (which is assigned to x in the code), but I can’t find a way to

  1. plot the buffer on the parent window of my GUI (I did see this post, but it didn’t really seem to work when I tried to use this idea in the code.

  2. redraw the plotter with the new buffer whenever the value of x changes.

  3. I posted about this earlier, but it’s the same issue and I don’t understand it: I get an error message when the buffer tmp file is erased and I then try to load a new collection to the allocated buffer. It does replace the collection with whatever new wavetable data I have, but the post window throws an error every time. Can I just block the error message somehow? Or just deal with it? It doesn’t disrupt anything, it just is annoying. (EDIT: apologies if this sounded like I was annoyed that no one had responded. I was annoyed by the post window error.)

(

var list = List.new;
var sig, wt, size = 2.pow(11);
var val;

x=1;

s = Server.local;

s.freeAllBuffers;

s.waitForBoot({
	
	b = Buffer.alloc(s, size*2, 1);
	
	w = Window("3x+1", Rect(300,300,800,600)).front;
	
	h = Slider(w, Rect(70, 570, 720, 20))
	.value_(x.linlin(1,99999,0.0,1.0))
	.step_(1.linlin(1,99999,0.0,1.0))
	.action_({
		
		//collatz
		
		n.value_(h.value.linlin(0.0,1.0,1,99999));
		while({x>1}, 
	{list.add(x);
		if (x.mod(2)==0, {val = x/2}, {val = (3*x)+1});
		x = val;
});
		
		//collect in list

list.add(1);

list = list.asArray;

sig = Signal.sineFill(size, list);

wt = sig.asWavetable;
		
		b.loadCollection(wt);
		
	});
	
	n = NumberBox(w, Rect(10, 570, 50, 20))
	.value_(x)
	.maxDecimals_(0)
	.action_({
		h.valueAction_(n.value.linlin(1,99999,0.0,1.0));
	});
	
	v = CompositeView(w, Rect(10,10,780,550)).background_(Color.white);
	
	s.sync;
	
	SynthDef(\wt, {
		arg amp = 0.5;
		var sig, freq;
		freq = MouseX.kr(10,1000,1);
		sig = Osc.ar(b, freq, 0.0, amp)!2;
		Out.ar(0, sig);
	}).add;
});

)

At risk of perhaps bypassing the question – you’re generating buffer data in the language and sending them to the server. Plotting also takes place in the language.

So it seems to me that a more direct data flow would be:

Generate data
|_ Send to buffer
|_ Plot based on the collection that already exists in the language

The other way that you seem to be proposing seems unnecessarily roundabout:

Generate data
|
Send to buffer
|
Retrieve from buffer
|
Plot based on retrieved collection

If you avoid the round-trip data transfer, then the file-related error message will go away.

plot the buffer on the parent window of my GUI (I did see this post, but it didn’t really seem to work here.

What went wrong? Since your code example doesn’t reference plot, it’s hard to guess how you tried to implement that suggestion.

hjh

OK, I decided to play with it some more. Here’s a working example (as far as I know).

There were some problems with your 3x+1 logic. You never initialized ‘x’ to the actual starting value – so the while loop wasn’t doing anything. You were simply accumulating 1.0 values. Then, by converting list to an array, you lose the ability to do list.add without reassignment. So this example fixes both of those bugs.

Also, I now see that the problem with the temporary file is not getting the data back into the language, but sending it to the server. So I was wrong that the error message would go away.

AFAICS it isn’t supported to loadCollection hundreds of times per second (which could happen from a GUI action function). IMO the best solution is to prevent the action function from firing too often. An easy way to do that is with the ddwSpeedLim quark (used here).

Edit: One other bug (fixed below) – sig = Signal.sineFill(size div: 2, list); instead of sig = Signal.sineFill(size, list);.

hjh

(

var list = List.new;
var sig, wt, size = 2.pow(11);
var val;

var plotter = Plotter("", Rect(800, 200, 500, 400));
var plotView = plotter.interactionView;

x=1;

s = Server.local;

s.freeAllBuffers;

s.waitForBoot({
	
	b = Buffer.alloc(s, size*2, 1);
	
	w = Window("3x+1", Rect(300,300,800,600)).front;
	
	h = Slider(w, Rect(70, 570, 720, 20))
	.value_(x.linlin(1,99999,0.0,1.0))
	.step_(1.linlin(1,99999,0.0,1.0))
	.action_(SpeedLim(0.1, {
		
		//collatz
		x = h.value.linlin(0.0,1.0,1,99999);
		list = List.new;
		n.value_(x);
		while({x>1}, 
			{list.add(x);
				if (x.mod(2)==0, {val = x/2}, {val = (3*x)+1});
				x = val;
		});
		
		//collect in list
		
		list.add(1);
		
		list = list.asArray;
		
		sig = Signal.sineFill(size div: 2, list);
		
		// update plot
		plotter.value = sig;
		plotView.refresh;

		wt = sig.asWavetable;
		
		b.loadCollection(wt);
	}, AppClock));
	
	n = NumberBox(w, Rect(10, 570, 50, 20))
	.value_(x)
	.maxDecimals_(0)
	.action_({
		h.valueAction_(n.value.linlin(1,99999,0.0,1.0));
	});
	
	v = CompositeView(w, Rect(10,10,780,550)).background_(Color.white);
	v.layout = VLayout(
		plotView
	);
	plotter.parent.close;
	
	s.sync;
	
	SynthDef(\wt, {
		arg amp = 0.5;
		var sig, freq;
		freq = MouseX.kr(10,1000,1);
		sig = Osc.ar(b, freq, 0.0, amp)!2;
		Out.ar(0, sig);
	}).add;
});

)

Excellent! Thank you so much. I had x set to rrand(1,99999) at first and then changed it to 1 because I wanted it to initialize at 1, forgetting for a moment about the number of different issues that would cause.

And your speed limiter quark is super helpful!

FWIW my first attempt at plotting was to try plotting the buffer directly into the CompositeView, and that just didn’t work at all. The other post seemed more relevant to an arrayed collection, so I thought it was an issue with using a buffer due to the size.