.plot after .play and .scope or new methods to do these functionality

Dear developers,

The following works,

Env.perc.test.plot

while the following does not:

{ SinOsc.ar(440) * Env.perc(0.01, 0.04).ar(Done.freeSelf)* 0.1}.play.plot

I think allowing .play.plot and .scope.plot will reduce often the code complexity. How do you think?

Let’s see the following examples:

// to plot:
{ SinOsc.ar(660) * Env.perc(0.01, 0.04).ar * 0.1}.plot(0.04, minval:-0.2, maxval:0.2)

// to scope:
{ SinOsc.ar(660) * Env.perc(0.01, 0.04).ar(Done.freeSelf)* 0.1}.scope 

We need two separate codes currently. However, my proposal is implemented, we need only one code:

// to scope and plot
{ SinOsc.ar(660) * Env.perc(0.01, 0.04).ar(Done.freeSelf)* 0.1}.scope.plot(0.04, minval:-0.2, maxval:0.2)

also as follows:

// to play and plot
{ SinOsc.ar(660) * Env.perc(0.01, 0.04).ar(Done.freeSelf)* 0.1}.play.plot(0.04, minval:-0.2, maxval:0.2)

play returns the synth instance. You cannot plot a synth, and to not return it would leak the resource.
Env gets around this by enforcing that the synth has a fixed duration.

The only reason you can plot a function is because it assumes you are not using an Out.ar but instead the return of the function should be played. Synth doesn’t have these restrictions and so getting it to work everywhere would not be possible.

You could instead return a new synth-like class that assumes the limits of the synth made by a function (FunctionSynth perhaps?) This is probably the most reasonable as its just a class containing a Synth with some extra methods.

Take a look at Function:asBuffer, Function:toFloatArray, and Function:plot, they are already pretty complex.

2 Likes

My wish is to implement such convenient ways in the core class library… Anyway, thanks for your answer, I will look at them!

A case to consider – I think this captures the main difficulty. If you can find a clean way to do this, it would cover a lot of territory.

a = { (VarSaw.ar(440) * 0.1).dup }.play;

// currently not supported but wish to be
b = { SinOsc.ar(330) * 0.1).dup }.play.scope;

Two synths are played, both onto bus 0.

Presumably you would want .scope to show only b’s signal – but a and b are mixed onto bus 0.

So there’s the rub – { }.play currently assumes that the synths should be mixed onto their target bus. If the desired feature is to .plot or .scope play-ed synths separately, then… { }.play doesn’t know in advance if the signal should or shouldn’t be isolated. So you would need to do one of the following: a/ isolate every { }.play onto temporarily allocated buses, because you might need them to be isolated, or b/ upon .scope / .plot, switch to a private bus and add a second synth to mix the signal from the private bus back into the (old) target bus.

Probably “b” is better (in that it would do the more complicated things only when needed).

hjh

1 Like

Thank you for your comment!
I have not considered the issue you raise. To be honest, I missed the point.

Anyway, your example of the problem with scope

could be currently avoided as follows (even though it is), I believe:

a = { (VarSaw.ar(440) * 0.1).dup }.play;
b = { (SinOsc.ar(330) * 0.1).dup.scope }.play;

However, I have no idea with .plot to do similar thing.

How about a new method like this?

+ Function {
	demo {
		arg duration = 0.05, numChannels, outbus = 0, fadeTime = 0.05, bufsize = 4096, zoom;
		var screenBounds = Window.screenBounds;
		var point = (screenBounds.width / 2)@(screenBounds.height / 2);
		this.scope(numChannels, outbus, fadeTime, bufsize, zoom);
		this.plotAudio(duration, bounds:Rect(point.x - 125, point.y + 183, 265, 250))
	}
}

Would it be useful?
Would one window in the middle of the display be better than two separate windows?