What is the best way to plot a 'Synth()'?

Hi there,

I’m still discovering sound synthesis, and SC is awesome for this, as you have a direct correlation between mathematical operations and sound output, without having a GUI abstraction hiding the hard part.

Since I don’t know much, I use the plot function to understand what does what, for example I discovered by myself this soft distortion :

{ SinOsc.ar( 440, mul: pi ).tanh }.plot

So far so good. But when composing, it becomes really convenient to use SynthDefs, with tons of parameters. I’d like to be able to compare different parameters settings quickly, like this :

Synth( \mySynth, [ \freq, 220, \modIndex, 4, \overlap, 0.5 ] ).plot;
Synth( \mySynth, [ \freq, 440, \modIndex, 16, \overlap, 1 ] ).plot;

Obviously, this is not working…

I think it’s because Synth() is not a UGen, it’s kind of a message from sclang to scsynth telling 'yo ! play this note !".

But what confuses me is that the function in the first example is not a ‘real’ UGen either…

{ SinOsc.ar( 440, mul: pi ).tanh }.inspect

results in < closed FunctionDef > . I have the feeling it’s implicitly converted as a UGen representation, but I don’t know where I can find more information about this process. So if you have a clue about this, please can you help me find where I can find out what’s going on.

Then, the main question. The plot method documentation says it’s supposed to work primarily on Arrayed Collection, but also works on other classes, including Function, Bus, Env, Buffer, SoundFile, Wavetable.

So I supposed the best way to plot the result of the Synth() call was to output it’s sound to a Buffer, then to call plot on the result, but it seems inelegant and adds a lot of extra steps to the process. I was wondering if there was an easier way to achieve this ?

Many thanks, D.

EDIT : should have searched the forum before posting, the answer is here already.

BTW the reason why we can have { ... }.plot but not SynthDef(...).plot is:

  • When plotting a function, we can assume that the function’s return value (which is a network of UGen connections) is the signal that you want to plot.
  • If it’s a SynthDef, there is no guaranteed, reliable way to know what signal to plot. SynthDefs use Out.ar to write the signal to a bus. To plot, we would need to know which bus. There is a loose convention that SynthDefs should have an out argument for the output bus number. But if the user said outbus or bus or audioOutputBus, how would SynthDef:plot know this? (Worse, a lot of new users take a shortcut and write Out.ar(0, ...) in which case it would be impossible for a hypothetical SynthDef:plot method to isolate the signal from other things playing at the same time.)

poll is one workaround.

Another is to write a RecordBuf into the SynthDef (temporarily, delete it later), then plot the buffer’s contents.

I still think that having the RecordBuf inside the SynthDef is not convenient because you have to setup a “live” SynthDef and a “production” SynthDef.

So, this

s.boot;

(
var bufferSize = s.sampleRate * 1; // Buffer size is fixed. s.sampleRate * seconds makes sense.

if( ~plotterIn == nil, { ~plotterIn = Bus.audio( s, 2 ) } ); // Declare a global channel for the plotter input, stereo

if( ~plotterBuffer != nil, { ~plotterBuffer.free } ); // Reset the buffer if existant
~plotterBuffer = Buffer.alloc( s, bufferSize, 2 ); // Create our buffer, stereo

SynthDef( \toBuffer, { // A simple routing synth
	| bufNum |
	var in = In.ar( ~plotterIn, 2 ); // Takes an input
	RecordBuf.ar( in, bufNum, loop: 0, doneAction: 2 ); // And outputs it in our buffer
} ).add;
)

( // Demo Synth
SynthDef( \demoSynth, {
	| out = 0, freq = 220 |

	var snd = SinOsc.ar( freq!2 );
	snd = snd * EnvGen.kr( Env.perc( 0.1, 0.9 ), doneAction: 2 );

	Out.ar( out, snd );
} ).add
)

(
Synth( \toBuffer, [ \bufNum, ~plotterBuffer ] ); // Trigger the buffer synth
Synth( \demoSynth, [ \out, ~plotterIn, \freq, 110 ] ); // Then our favorite synth
)

// You will need to wait the bufferSize length before plotting it !
~plotterBuffer.plot // Finally print the result

if( ~plotterBuffer != nil, { ~plotterBuffer.free } ); // Free the buffer if existant

Just extracted the RecordBuf from the SynthDef. It can now be shared across SynthDefs, and is silent when used.

If you see anything wrong, comment ! :slight_smile:

1 Like

Why not just plot the bus? Seems much easier:

(
~bus = Bus.audio(s,2);
Synth( \demoSynth, [ \out, ~bus, \freq, 110 ] ); // Then our favorite synth
~bus.plot(1)
)

Sam

2 Likes

Why not just plot the bus? Seems much easier:

Well, that’s what I was asking, indeed, it’s much simpler !
I didn’t dare to plot a Bus, since it’s something ‘continuous’, I didn’t think it would behave like this, and feared SuperCollider would explode…

If you fear an explosion, turn down the volume! But in this case, the fear is not justified.

Actually, I didn’t know you could plot a bus until you asked this question, so I learned something here as well.

Sam