CLASS:: ScopeView
summary:: A buffer plotting view.
categories:: GUI>Views
related:: Classes/Stethoscope, Classes/FreqScopeView, Classes/FreqScope

DESCRIPTION::

ScopeView is mainly intended to support the implementation of link::Classes/Stethoscope:: (an oscilloscope), link::Classes/FreqScopeView:: (a basic frequency spectrum plotting view) and link::Classes/FreqScope:: (a frequency spectrum analyzer tool).

It is optimized to efficiently perform frequent plotting of the contents of a link::Classes/Buffer:: into which a link::Classes/ScopeOut:: UGen is writing. It will periodically poll the buffer for data and update the plot, as long as the ScopeOut UGen is writing into it; the buffer will not be plotted otherwise.


CLASSMETHODS::

PRIVATE:: key


INSTANCEMETHODS::

METHOD:: bufnum
    The number of the Buffer to plot.

    As soon as a valid buffer number is set and a link::Classes/ScopeOut:: UGen is writing into it, the view starts periodically plotting the buffer. If the ScopeOut UGen stops writing, or an invalid buffer number is set, the plotting will pause.

    argument::
        An integer.

METHOD:: style
    The plotting style:
    list::
    ## 0 = the channels are vertically spaced
    ## 1 = the channels are overlaid
    ## 2 = lissajou; the first two channels are used for 2D plotting (as streams of x and y coordinates).
    ::

    argument::
        One of the above Integers.

METHOD:: xZoom
    The scaling factor on the horizontal axis.

    argument::
        A Float.

METHOD:: yZoom
    The scaling factor on the vertical axis.

    argument::
        A Float.

METHOD:: x
    The horizontal offset.
    argument::
        A Float.

METHOD:: y
    The vertical offset.
    argument::
        A Float.

METHOD:: fill
    Fill area under scope.
    argument::
        A Boolean.

METHOD:: waveColors
    The colors used to plot each of the channels.

    argument::
        An Array of Colors, one per channel.

EXAMPLES::

SUBSECTION:: A step-by-step example

code::
// execute these in succession
(
s.boot;
)
(
f = Buffer.alloc(s,1024,2);
b = Bus.audio(s,1);

w=Window.new.front;
c = ScopeView(w.view,w.view.bounds.insetAll(10,10,10,10));
c.bufnum = f.bufnum;
)
(
// listening to the bus, using ScopeOut to write it to the buffer
a=SynthDef("monoscope", { arg bus, bufnum;
                var z;
                z = In.ar(bus,2);
                // ScopeOut writes the audio to the buffer
                ScopeOut.ar(z, bufnum);
            }).play(
                RootNode(s),
                [\bus,b.index, \bufnum, f.bufnum] ,
                \addToTail // make sure it goes after what you are scoping
            );

// making noise onto the buffer
d=SynthDef("noise", { arg bus;
                var z;
                z = LFSaw.ar(SinOsc.kr(0.1).range(300,1000),[0,1]*pi) * 0.1;
                Out.ar(bus, z);
            }).play(
                s,
                [\bus,b.index]
            );
)

c.style = 0 // vertically spaced
c.style = 1 // overlapped
c.style = 2 // x/y

(
//remember to free your stuff when finished
a.free;
d.free;
f.free;
b.free;
w.close;
)
::

SUBSECTION:: An interactive example with sound

This explains all the options:

code::
(
s.waitForBoot(
{

    var func, sdef1, sdef2, syn1, syn2,startButton ;
    f = Buffer.alloc(s,1024,2);
    b = Bus.audio(s,1);

    w=Window("Scope", Rect(150, Window.screenBounds.height-500,790,400)).front;
    c = ScopeView(w,Rect(10,10,380,380)); // this is SCScope
    c.bufnum = f.bufnum;

	// IMPORTANT
	c.server_(s);

    v=CompositeView(w,Rect(400,10,380,380)).background_(Color.rand(0.7));
    v.decorator = n = FlowLayout(v.bounds, margin: 0@0, gap: 5@5);

    a = StaticText(v, Rect(20, 70, 90, 20)).string_(" xZoom = 1").background_(Color.rand);
    m = Slider(v, Rect(20, 60, 285, 20)).background_(a.background).action_({func.value}).value_(0.5);
    d = StaticText(v, Rect(20, 70, 90, 20)).string_(" yZoom = 1").background_(Color.rand);
    g = Slider(v, Rect(20, 60, 285, 20)).background_(d.background).action_({func.value}).value_(0.5);

    h = StaticText(v, Rect(20, 70, 90, 20)).string_(" x = 0").background_(Color.rand);
    i = Slider(v, Rect(20, 60, 285, 20)).background_(h.background).action_({func.value}).value_(0.5);

    Button(v, Rect(0,0,380, 20))
        .states_([["waveColors = [ Color.rand, ... ]",Color.black,Color.rand]])
        .action_({c.waveColors = [Color.rand,Color.rand]});

    Button(v, Rect(0,0,380, 20))
        .states_([[" background = Color.rand(0.1,0.3) ",Color.black,Color.rand]])
        .action_({c.background = Color.rand(0.1,0.3) });

    t= Button(v, Rect(0,0,380, 20))
        .states_([["Current style is 0",Color.black,Color.rand],
            ["Current style is 1",Color.black,Color.rand],
            ["Current style is 2",Color.black,Color.rand]])
        .action_({func.value});

    func={
        c.xZoom = ([0.25, 10, \exp, 1/8, 1].asSpec.map(m.value)); a.string = " xZoom = %".format(c.xZoom);
        c.yZoom = ([0.25, 10, \exp, 1/8, 1].asSpec.map(g.value)); d.string = " yZoom = %".format(c.yZoom);
        c.x = ([ -1024,1024, \linear, 1/8, 1].asSpec.map(i.value)); h.string = " x = %".format(c.x);
        c.style=t.value
        };

    startButton = Button.new(v, Rect(0,0,380, 50))
        .states_([["Start Sound",Color.black,Color.green],["Stop Sound",Color.black,Color.red]]).action_({});


    startButton.action_{
        (startButton.value==1).if{
    syn1=SynthDef("test1", { arg bus, bufnum;
                    var z;
                    z = In.ar(bus,2);
                    // ScopeOut writes the audio to the buffer
				//                     ScopeOut.ar(z, bufnum);
				// IMPORTANT - ScopeOut2, not ScopeOut
                    ScopeOut2.ar(z, bufnum);
                    Out.ar(0,z);
                }).play(
                    RootNode(s),
                    [\bus,b.index, \bufnum, f.bufnum] ,
                    \addToTail // make sure it goes after what you are scoping
                );

    // making noise onto the buffer
    syn2=SynthDef("test2", { arg bus;
                    var z;
                    z = PMOsc.ar([300,250],*SinOsc.ar([0.027,0.017])*pi) * 0.1;
                    Out.ar(bus, z);
                }).play(s,[\bus,b.index]);



        }{syn1.free; syn2.free};

    };

	// IMPORTANT
	c.start;

    w.onClose={syn1.free; syn2.free; b.free; f.free};
    CmdPeriod.doOnce({w.close});
})
)
::
