SuperCollider 3.9dev Classes (extension) | GUI | Conductor | External Control > MIDI | External Control > OSC

CVWidget
ExtensionExtension

The abstract superclass for all CVWidgets
Inherits from: Object

Description

CVWidget is the abstract superclass of all CVWidgets (CVWidgetKnob, CVWidget2D and CVWidgetMS). However, it implements a couple of useful methods that are common to all its subclasses.

Class Methods

CVWidget.removeResponders

CVWidget.removeResponders = value

A Boolean, indicating whether MIDI- and OSC-responders shall be removed upon hitting Cmd/Ctrl-period. If it is set to false unreferenced ghost-responders are left that may be hard to remove.

Returns:

this (CVWidget)

CVWidget.debug

CVWidget.debug = value

A Boolean, allowing (or disallowing) introspection of the internal working of a CVWidget. This is e.g. useful if the user wants to extend the widget's API. Whenever a the content of a model changes the corresponding controller gets triggered and executes its actions. So, if a message like

widget 'freq' (CVWidget2D) at slot 'lo' midiDisplay.model: `(( 'learn': L, 'src': source, 'chan': chan, 'ctrl': ctrl ))

gets posted, it means the midiDisplay.controller has just executed its actions using the model's values.

Also see Models%20and%20Controllers,%20internal%20bookkeeping and Extending%20the%20API.

Returns:

this (CVWidget)

CVWidget.midiSources

CVWidget.midiSources = value

An Event, containing all currently registered MIDIEndPoints and their correspondant numeric IDs. The IDs can be used to identify a device when creating a MIDI-responder though this is usually not necessary as the inbuilt learn functionality will take care of this automatically.

Returns:

an Event

CVWidget.shortcuts

CVWidget.shortcuts = value

An IdentityDictionary containing all currently defined shortcuts for any CVWidget. Though this is a getter/setter it is recomended to add/remove shortcuts via the GUI within the preferences-interface (changes will become active after recompilation of the class-library) or the shortcuts-interface (changes become active immediatly but get reset after recompilation of the class-library).

NOTE: For added shortcuts to become active the user will have to call KeyDownActions: *setShortcuts on any currently existing CVWidget. This procedure will be handled automatically behind the scenes if a shortcut has been added via CVCenter's inbuilt shortcut-editor.

See KeyDownActions for more information about the internal structure of the shortcuts dictionary resp. the workings of shortcuts in general. Also have a look at the list of default shortcuts that can be modified by the user at any time.

Returns:

Inherited class methods

Instance Methods

.setup

The current widget-setup, returned as an Event. If the widget is a CVWidget2D each key of the returned Event will be split in a \lo and a \hi value:

midiMode
as set by -setMidiMode. default: 0
calibrate
indicates whether OSC-calibration is active or not, set by -setCalibrate. default: true
ctrlButtonBank
indicates whether the ctrlButtonBank parameter, reflecting a MIDI-device's bank-layout is set. This can be set with -setCtrlButtonBank. default: nil
midiMean
if a MIDI-device is set to in-/decremental mode reps. midiMode is set to 1 this will be the mean output-value. Can be set with -setMidiMean. default: 64
midiResolution
if midiMode is set to 1 the step-size of each slider is determined by this parameter. Can be set with -setMidiResolution. default: 1
softWithin
if midiMode is set to 0 this determines the tolerance at which a MIDI-slider will respond when moved. For a more detailed explanation see -setSoftWithin. default: 0.1

Returns:

an Event

.setMidiMode(mode, slot)

Different MIDI-devices may have different output modes: either values from 0-127 or an in-/decremental value (e.g. -1 or +1). These modes may be taken in account as follows:

0the device outputs a values 0-127
1the device outputs in-/decremental values

Arguments:

mode

an Integer

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getMidiMode(slot)

Get the current midiMode (0 or 1).

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

.setMidiMean(meanval, slot)

Devices which output a in-/decremental may output a standard value + in-/decrement. midiMean gets automatically subtracted from this value, so in-/decrement remains. Applies only if midiMode is set to 1.

Arguments:

meanval

an Integer. default: 64

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getMidiMean(slot)

Get the current midiMean value.

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

.setSoftWithin(threshold, slot)

If midiMode has been set to 0 moving a widget-slider will set the CV to a new value. However, if a MIDI-slider is connected to that widget, moving the MIDI-slider will set the CV's value immediatly to the value that is stored in the MIDI-slider i.e. a "jump" will happen. softWithin will ease this behavior by setting the CV's value only if the slider gets within softWithin/2. A threshold =< 0 will deactivate snap-to. Applies only if midiMode is set to 0.

Arguments:

threshold

a Float - default: 0.1.

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getSoftWithin(slot)

Get the current softWithin threshold.

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

.setCtrlButtonBank(numSliders, slot)

Some MIDI-devices provide several banks of sliders. I.e. a device may be equipped with 16 sliders and 4 banks that can be switched. So, slider 1 in bank 2 is slider nr. 17, slider 3 in bank 3 is slider nr. 35. By default these sliders would have to be addressed in a CCResponder as 16 (slider 17) and 34 (slider 35) which makes it hard to immediately get the right slider from what is displayed within the GUI. ctrlButtonBank translates the hardware-layout in a way that makes it easy to see the slider's bank and number: slider 17 becomes 2:1 (bank 2, nr. 1).

Arguments:

numSliders

an Integer, representing the number of sliders in one bank.

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getCtrlButtonBank(slot)

Get the current ctrlButtonBank value

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

an Integer, representing the number of sliders in one bank.

.setMidiResolution(resolution, slot)

If midiMode has been set to 1 (by calling -setMidiMode), this method allows to set the resolution (= stepsize) of the connected hardware MIDI-sliders.

Arguments:

resolution

a Float, representing the stepsize:

lower values -> higher resolution

higher values -> lower resolution

default: 1

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getMidiResolution(slot)

Get the current value midiResolution value.

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

.setCalibrate(bool, slot)

Unlike MIDI the range of incoming OSC-values isn't 0-127 - it is unknown at the time of initialization of the OSC-responder. All CVWidgets have an inbuilt calibration mechanism that determines the range automatically. At initialization the range is set to [0.0001, 0.0001]. If the mechanism detects a value that is lower or higher than the values set at initialization it will set the constraints accordingly. This method allows to stop or start the calibration-process.

Arguments:

bool

a Boolean, indicating whether the calibration-process shall be started or stopped.

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getCalibrate(slot)

Get the current calibration-status

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

.setSpec(spec, slot)

Every CVWidget wraps one or more CVs whose internal spec can be set with this method.

Arguments:

spec

can either be:

  • a ControlSpec
  • an Array that can be converted to a valid ControlSpec by calling asSpec on it
  • a Symbol representing the name of a valid ControlSpec (e.g. \freq)
slot

only needed if the widget is a CVWidget2D - either \lo or \hi

Returns:

the receiver

.getSpec(slot)

Get the current spec of the widget's CV.

Arguments:

slot

only needed if the widget is a CVWidget2D - either \lo or \hi

Returns:

.setOscMapping(mapping, slot)

Within an OSCresponder's function values coming in are being mapped to the ControlSpec's range, defined by its minval and maxval. Furthermore a spec may implement a non-linear warp for the transition from minval to maxval. Especially when work with accelerometers and orientation-sensors setting oscMapping to some non-linear mode will allow a much more fine-grained control.

Arguments:

mapping

a Symbol - can be:

  • \linlin - linear to linear mapping
  • \linexp - linear to exponential mapping
  • \explin - exponential to linear mapping
  • \expexp - exponential to exponential mapping
slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getOscMapping(slot)

Get the current oscMapping-mode

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

a Symbol, indicating the oscMapping-mode

.oscConnect(ip, port, name, oscMsgIndex: 1, slot)

Connect a widget to an OSC-device resp. a program that sends OSC-messages to SuperCollider

Arguments:

ip

optional - if set the OSCresponder will only listen to messages coming from that IP-address.

port

optional - if set the OSCresponder will only listen to messages coming from that port.

name

a String or a Symbol\: The OSC-command-name to which the OSCresponder will listen. E.g. '/touch/x' or '/accelerometer/x'. Every widget has an inbuilt mechanism that allows the user to scan connected devices for possible command-names. This mechanism is implemented in the class OSCCommands which may not only be used in connection with CVWidgets. OSCCommands stores a list of devices and commands to disk so the user does not have to rescan every time (s)he restarts SC.

oscMsgIndex

messages you receive from an OSC-device/-program usually consist of the commend-name and one or more slots, containing numerical values. An orientation-sensor might e.g. send a message like the following:

[ '/orientation', 178, 67, 78 ]

the first slot is the command-name and the subsequent slots are x, y and z. oscMsgIndex allows you to select which of those three values you want to use in your widget.

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.oscDisconnect(slot)

Disconnects the OSC-device/-application reps. removes the OSCresponder

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.midiConnect(uid, chan, num, slot)

Connect a widget to a MIDI-device utilizing a CCResponder.

Arguments:

uid

optional - the ID under which the device gets registered in SuperCollider

chan

optional - the MIDI-channel to which the program will listen

num

optional - the controller-number to which the program will listen

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.midiDisconnect(slot)

Terminate a MIDi-connection reps. remove the CCResponder.

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.setOscInputConstraints(constraintsHiLo, slot)

Any widget has a mechanism built in that is supposed to detect the constraints of the values coming in via OSC. However, you my set these constraints manually as well with this method.

Arguments:

constraintsHiLo

a Point - e.g. Point(-20, 20) or 0@360

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

the receiver

.getOscInputConstraints(slot)

Get the current oscInputConstraints. This will return nil as the widget is not connected and the calibration-mechanism hasn't set any values.

Arguments:

slot

only needed if the widget is a CVWidget2D or a CVWidgetMS - either \lo or \hi (CVWidget2D) or an integer index (CVWidgetMS)

Returns:

nil or an Event containing the constraints in the keys \lo and \hi (not related to the \lo and \hi keys in a CVWidget2D)

.addAction(name, action, slot, active: true)

Add an action to the widget's CV.

See also the related class method CVCenter: *addActionAt

Arguments:

name

a Symbol or a String, representing the name under which the action will be stored

action

a Function or a String that compiles to one if interpret is called on it. If the function contains an argument the CV will be provided in this argument: { |cv| "the CV's current value is %\n".postf(cv.value) }

slot

only needed if the widget is a CVWidget2D - either \lo or \hi

active

a Boolean, indicating whether the action shall become active immediatly

Returns:

the receiver

.removeAction(name, slot)

Remove an action given by its name

Arguments:

name

a Symbol or a String, representing the action's name

slot

only needed if the widget is a CVWidget2D - either \lo or \hi

Returns:

the receiver

.activateAction(name, activate: true, slot)

Activate or deactivate a stored action

Arguments:

name

a Symbol or a String, representing the action's name

activate

a Boolean, indicating whether the action shall be activated or deactivated

slot

only needed if the widget is a CVWidget2D - either \lo or \hi

Returns:

the receiver

Models and Controllers, internal bookkeeping

.wdgtControllersAndModels

CVWidgets are designed in an MVC-architecture (MVC = "model - view - controller"). Any time a new CVWidget gets instantiated the models get initialized. Any time the model is changed the function in the regarding controller gets invoked.

WARNING: Do not try to change the models directly, e.g. by doing something like

myWidget.wdgtControllersAndModels.someModel = someValue

Models are designed for internal bookkeeping and all methods within CVWidget are supposed to do the right thing with them.

All models and controllers are stored within the wdgtControllersAndModels instance-var. If the widget is a CVWidget2D wdgtControllersAndModels will be split up in a \lo and a \hi slot, each containing the following models ( CVWidgetKnob simply keeps them under wdgtControllersAndModels):

calibrate
the current calibration-state as set with -setCalibrate - either Ref(true) (default at initialization) or Ref(false).
cvSpec
the CV's current spec as set at initialization or with setSpec - a Ref to a ControlSpec.
oscInputRange
the current input-range, set by the widget's input mechanism with setInputRange - default at initialization: Ref([0.0001, 0.0001]).
oscConnection
the current OSC-connection (if present): Ref([<IP-address>, <port>, <command-name>, <message-index>]). If no connection is present it will be Ref(false).
oscDisplay
stores all OSC-related visual properties of a widget and its editor. A Ref to an Event, containing the following slots:
  • but: the state of the OSC-button ("edit OSC")
  • ipField: the IP-field under the OSC-tab of the editor (see CVWidgetEditor)
  • portField: the port-field under the OSC-tab of the editor (see CVWidgetEditor)
  • nameField: the field for the OSC-command-name under the OSC-tab of the editor (see CVWidgetEditor)
  • index: the field for the message-index under the OSC-tab of the editor (see CVWidgetEditor)
  • connectorButVal: the value of the connect-button under the OSC-tab of the editor connectorButVal (see CVWidgetEditor)
  • editEnabled: if a connection is established editor-fields will be made uneditable and this slot is set to false

midiConnection
the currentMIDI-connection (if present): Ref((src\: <val>, chan\: <val>, num\: <val>)). If no connection is present this will be: Ref(nil).
midiDisplay
stores all MIDI-related visual properties of a widget and its editor. A Ref to an Event, containing the following slots:
  • learn: the current state of the 'learn'-button of the widget and the 'learn'-button under the MIDI-tab of the editor
  • src: the current string of the 'src'-field of the widget and the 'src'-field under the MIDI-tab of the editor (the ID under which the device gets registered in SC)
  • chan: the current string of the 'chan'-field of the widget and the 'chan'-field under the MIDI-tab of the editor (the MIDI-channel)
  • ctrl: the current string of the 'ctrl'-field of the widget and the 'ctrl'-field under the MIDI-tab of the editor (the controller-number of the device)

midiOptions
the current MIDI-setup, analogue to -setup:

mapConstrainterLo
a CV, containing the spec [-inf, inf].asSpec and oscInputRange.model.value[0] as value
mapConstrainterHi
a CV, containing the spec [-inf, inf].asSpec and oscInputRange.model.value[1] as value
actions
a Ref to an Event: Ref((numActions\: <val>, activeActions\: <val>)). This model reflects the number of actions resp. active actions as displayed in the 'actions'-button of the widget.

Returns:

an Event

.midiOscEnv

Get the current MIDI-/OSC-environment of the widget. If the widget is a CVWidget2D calling this method will return an Event containing the environments in 2 slots: \lo and \hi, else the environment will be returned:

oscMapping
input- to output-mapping of the values coming from the OSCresponder\: either \linlin, \linexp, \explin or \expexp (see also: -setOscMapping). By default the entry will be \linlin.
oscMsgIndex
if an OSCresponder is present this will reflect the index of the message at which the values are received (see also: -oscConnect).
calibConstraints
if an OSCresponder is present this will reflect the current constraints for values coming in via OSC. Usually the constraints are set automatically by the widget's internal calibration-mechanism. However, you may set them manually by -setOscInputConstraints or deactivate the calibration-mechanism by -setCalibrate.
oscResponder
if an if an OSCresponder is present it will be stored under this slot.
midiResponder
if a CCResponder is present it will stored under this slot.

Returns:

an Event

.widgetCV

The widget's CV. If the widget is a CVWidget2D an Event, containing to slots \lo and \hi is returned.

Returns:

either a CV ( CVWidgetKnob) or an Event ( CVWidget2D)

.wdgtActions

.wdgtActions = value

All actions (active and inactive) specified for the given widget.

WARNING: Though this has to be a setter/getter for some reason. Do not attempt to set an action like myWidget.wdgtActions_(some action). Rather use -addAction, -removeAction resp. -activateAction

Returns:

an Event, containing active and inactive actions of a widget.

.alwaysPositive

If \explin or \expexp has been chosen for input to output mapping with -setOscMapping both constraints of the input-range have to be same-signed - otherwise the operation would produce NaNs. alwaysPositive will be calculated automatically, so the user shouldn't have to worry about it.

Returns:

the receiver

Extending the API

WARNING: The following features are experimental and one should study the internal workings of CVWidget closely before using them - especially the structure of controllers and models: -wdgtControllersAndModels.

Within a CVWidget the functionality of most of its methods is implemented within a MVC-paradigm (model-view-controller) which means that rather than executing an action within a method directly the method updates a model (an object keeping some data) and triggers the controller via a 'changed'-message (non-working example-code):

myModel.value_(someValue).changed(\key)

When the 'changed'-message is sent the controller will execute its action. By default there is only one key specified: \default (see -synchKeys). However, it is possible to extend the functionality of a controller with one or more custom key/function pairs which means one can sync custom-guis and its elements to a given CVWidget (e.g. a button in some GUI cannot only connect MIDI or OSC but can also immediatly reflect the current connection-status). Have a look at the examples-section for a simple example. Extending the API in the suggested way should keep the CVWidget-functionality unobstrusive!

// create a widget
~knob = CVWidgetKnob(bounds: Rect(490, 0, 80, 210)).front;

// create a window that displays properties of OSC-connections in ~knob
(
~win = Window("model", Rect(100, 100, 400, 40)).front;
~responderDisplay = StaticText(~win, Rect(7, 7, ~win.bounds.width-14, ~win.bounds.height-14))
.background_(Color.white)
.font_(Font("Andale Mono", 10));
)


// a simple monitor displaying changed models
/*
   models used in CVWidget are:
   calibrate, cvSpec, oscInputRange,
   oscConnection, oscDisplay
   midiConnection, midiDisplay
   midiOptions, actions

   have a look at the section 'wdgtControllersAndModels'
   for more information
*/

/*
   not to be used with CVWidget:-extend:
   mapConstrainterLo, mapConstrainterHi
*/

// the function within extend will be put in any possible controller
// thus whenever one of them is triggered something will be displayed

(
~knob.extend(\mySync, { |theChanger, what, more|
    // have a look at what's being passed into the models
    ~responderDisplay.string_(" model changed:"+theChanger.value);
})
)

// remove the previously added functionality
// the window is no longer synched with the CVWidget

~knob.reduce(\mySync);
~win.close;

A slightly more practical (but also more complex) example: Edit an OSC-connection.

(
var flow, staticTextFont, textFieldFont, buttonFont;

// create a widget
~knob = CVWidgetKnob(bounds: Rect(490, 0, 80, 210)).front;

// another window with a button that shall get synched to the widget
staticTextFont = Font("Arial", 12);
textFieldFont = Font("Andala Mono", 12);
buttonFont = Font("Arial", 14, true);

// the window and its elements
~win = Window("connect OSC", Rect(50, 100, 400, 100));

~win.view.decorator = flow = FlowLayout(~win.view.bounds, 7@7, 2@2);

StaticText(~win.view, 120@20).string_("IP-address").font_(staticTextFont);
StaticText(~win.view, 50@20).string_("port").font_(staticTextFont);
StaticText(~win.view, 170@20).string_("command-name").font_(staticTextFont);
StaticText(~win.view, flow.indentedRemaining.width@20).string_("slot").font_(staticTextFont);

flow.nextLine;

~ip = TextField(~win.view, 120@20).font_(textFieldFont).string_("192.168.1.23");
~port = NumberBox(~win.view, 50@20).font_(textFieldFont).value_(11111);
~cmd = TextField(~win.view, 170@20).font_(textFieldFont).string_("/my/osc/command/name");
~slot = NumberBox(~win.view, flow.indentedRemaining.width@20).font_(textFieldFont).value_(1).clipLo_(1);

flow.nextLine;

// a button that lets the user connect OSC
~connect = Button(~win.view, flow.indentedRemaining.width@flow.indentedRemaining.height)
.states_([
    ["connect OSC", Color.white, Color.blue],
    ["", Color.white, Color.red]
])
.font_(buttonFont)
.action_({ |b|
    switch(b.value,
        1, { ~knob.oscConnect(~ip.string, ~port.value, ~cmd.string, ~slot.value) },
        0, { ~knob.oscDisconnect }
    )
});
~win.front;

// extend the widget's controller
// we only need the controller 'oscConnection
~knob.extend(\oscConnectSync, { |theChanger, what, more|
    // on calling ~knob.oscConnect theChanger.value will contain an array with 4 slots:
    // the IP-address, port, the command-name, the message-slot
    // on calling ~knob.oscDisconnect theChanger.value will only contain 'false'
    if(theChanger.value.size == 4, {
        theChanger.value.postln;
        ~connect.states_([
            ~connect.states[0],
            ["connected: %, %, %, %".format(*theChanger.value), ~connect.states[1][1], ~connect.states[1][2]]
        ]).value_(1)
    }, {
        ~connect.states_([
            ["re-connect OSC", ~connect.states[0][1], ~connect.states[0][2]],
            ~connect.states[1]
        ]).value_(0)
    })
}, \oscConnection)
)

// the user may also establish connect/disconnect programmatically
// ~knob as well as the custom window ~win should reflect changes immediately
~knob.oscConnect("192.168.1.23", 11111, "/my/osc/command/name", 1);
~knob.oscDisconnect;

// clean up
~knob.reduce(\oscConnectSync);
[~knob, ~win].do(_.close);

.extend(key, func ... controllers)

adds a custom function to one or all of the widget's internal SimpleControllers. These can also keep references to user-defined GUIs resp. their elements, thus allowing the user to synch his/her GUIs with CVWidgets.

Arguments:

key

a Symbol or a String - mandatory, used internally by the widget's SimpleControllers

func

a Function - mandatory. A custom function, extending the widget's resp. your custom GUI's functionality. The user may pass the content of the model, the key and more to the function if they are stated as arguments at the beginning of the function. See the SimpleController-helpfile for more info.

... controllers

Controllers, given as Symbols or Strings. A CVWidget contains several models and controllers, contained in -wdgtControllersAndModels. If no specific controllers are given the function will be added to all controllers within -wdgtControllersAndModels. If one or more specific controllers are provided the function will only be added to these controllers which might make calculations a bit cheaper. However, if the user provides a specific controller (s)he should know under which circumstances the given controller is being triggered in order to get the desired result.

Returns:

the receiver

.reduce(key)

removes user-defined functions that have been added to the widget's inbuilt SimpleControllers.

Arguments:

key

a Symbol or a String - indicating which function shall be removed. Will not touch the default functionality of a CVWidget. If no key is given all functions added by the user will be removed.

Returns:

the receiver

.synchKeys

an Array of Symbols, keeping the keys over which a SimpleController within a CVWidget will iterate. By default it is [ \default ]. The user should not alter this directly as adding and removing keys is handled within -extend resp. -reduce.

Returns:

an Array of Symbols

GUI properties and methods

optional - CVWidget implements a few GUI-elements that are common to CVWidgetKnob as well as CVWidget2D. Descriptions of the rest of the elements can be found in the documentation for the regarding classes.

.window

The window containing the widget

Returns:

.guiEnv

An Event containing certain elements of the GUI.

Returns:

an Event

.focusElements

CVWidgets cannot gain focus themselves. However, their elements (buttons, slider, textfields etc.) can. focusElements returns a collection of elements which, when focused (indicated by the green border), function as the widget's shortcut transmitters.

Returns:

an Array of GUI elements

.msSize

Though this is an instance var defined in CVWidget it applies to CVWidgetMS only: It returns the number of slots of the multi-slider of a CVWidgetMS.

Returns:

.cvArray

CVWidgetMS only.

Returns:

an Array of CVs after applying the method split on a given CVWidgetMS.

.front

Sends the widget's window to front.

Returns:

the receiver

.editor

.editor = value

Every widget has one or more editors that will open in a new window ( CVWidgetKnob 1 editor, CVWidget2D 2 editors - \lo and \hi). This method returns a reference to them.

Returns:

a CVWidgetEditor or an Event, containing a reference to 2 or more CVWidgetEditors

.name

Get the name of a widget. This corresponds with the key under which the widget's CV(s) is/are stored in CVCenter: *all.

Returns:

.parent

Get the parent view of a CVWidget

Returns:

a Window or a View resp. a subclass of it

.widgetBg

A CompositeView upon which all other elements of the GUI will be placed

Returns:

.label

A button, containing the name of the widget. When clicked the widget will switch to a TextView that can be used to write down notices.

Returns:

.nameField

A TextView that can be used to write down notices.

Returns:

.toggleComment(visible)

Toggles between nameField and the regular widget-appearance.

Arguments:

visible

a Boolean

Returns:

the receiver

.connectGUI(connectSlider: true, connectTextField: true)

Determine whether sliders and number/textfields CV shall update according to the value of the internal CV. This may be useful especially if many CVs (e.g. within CVCenter) are updated simultaniously at a high rate as that will cause a high CPU load and the GUI may quickly freeze.

Arguments:

connectSlider

a Boolean (optional), determining whether the CVWidget's sliders/knob shall update to the value of the internal CV

connectTextField

a Boolean (optional), determining whether the CVWidget's number-/textfield shall update to the value of the internal CV

Returns:

the receiver

.widgetXY

.widgetXY = point

Sets/gets the XY-position of a widget within its parent window.

Arguments:

point

a Point

Returns:

.widgetProps

Returns the width/height of a widget as Point.

Returns:

.bounds

Returns the bounds of a widget as Rect.

Returns:

a Rect

.remove

Removes all GUI-elements (buttons, text-fields, sliders etc.) from a widget.

Returns:

the receiver

.close

If the widget is part of the CVCenter-GUI all its elements will be removed, otherwise close the widget.

Returns:

the receiver

.isCVCWidget

Returns:

a Boolean, indicating whether the given CVWidget is part of CVCenter

.isClosed

Returns:

true if the widget has been closed, otherwise false

Inherited instance methods

Examples

basic usage

// create a CVWidget2D
~twoDee = CVWidget2D.new.front;
// and a multi-slider widget
~ms = CVWidgetMS(numSliders: 5).front;

// define an action to be executed when the knob is turned
~twoDee.addAction(\post, { |cv| "current value[lo]: %\n".postf(cv.value) }, \lo);
~twoDee.addAction(\post, { |cv| "current value[hi]: %\n".postf(cv.value) }, \hi);
~ms.addAction(\post, { |cv| "~ms current value: %\n".postf(cv.value) });

// some noise
(
Server.default.waitForBoot{
    ~noise = { |freq=#[1, 3, 4, 7, 11 ], trigFreq=10, freqMod=0|
        var trig, seq, freqvar;
        trig = Impulse.kr(trigFreq);
        seq = Drand([Dseq(freq, 1), Drand((1..4).collect(Array.geom(5, _, 3)), 8)], 2000);
        freqvar = Demand.kr(trig, 0, seq * 100);
        Splay.ar(SinOsc.ar(freqvar + [0,0.7]).scaleneg(freqMod)).tanh;
    }.play
}
)

// add an action to ~ms that sets freq dynamically
~ms.addAction(\setFreq, { |cv| ~noise.setn(\freq, cv.value) });

// change ~ms' spec
// move the sliders to hear the difference
// between various specs
~ms.setSpec(\lofreq);
~ms.setSpec(\widefreq);
~ms.setSpec(\freq);

// add another action to set trigFreq in ~noise
~twoDee.addAction(\trigFreq, { |cv| ~noise.set(\trigFreq, cv.value) }, \lo);

// change the widget's spec to something nore suitable
// a linear ControlSpec, reaching from 10 to 30
~twoDee.setSpec(#[10, 30], \lo);

// add another action to set freqMod in ~noise
~twoDee.addAction(\trigFreq, { |cv| ~noise.set(\freqMod, cv.value) }, \hi);

// change the widget's spec to something nore suitable
// a spec can be set as the spec's name which automatically gets converted
// to a ControlSpec if a spec under that name exists - see the ControlSpec helpfile
~twoDee.setSpec(\pan, \hi);

// deactivate posting values to the post-window
// the action can be reactivated at any time with the same
// method-call, providing true as its parameter
~twoDee.activateAction(\post, false, \lo);
~twoDee.activateAction(\post, false, \hi);
~ms.activateAction(\post, false);

~noise.release;
[~twoDee, ~ms].do(_.close;

reusable widgets

By default windows created in SC lack the ability to be opened again once they're closed (even evaluating the variable under which the window has been created will still return the window). The following section describes a workaround in CVWidget (resp. CVWidgetKnob and CVWidget2D) that enables the user to keep a widget's responders and open and close it as many times as the user needs to ( open is implemented in CVWidgetKnob and CVWidget2D).

// create some widgets
// if a widget is made 'persistent' its OSC-/MIDI-responders
// will not be removed when the widget gets closed
~knob = CVWidgetKnob(bounds: Rect(100, 100, 80, 210), persistent: true).front;
~twoDee = CVWidget2D(bounds: Rect(180, 100, 140, 210), persistent: true).front;
~ms = CVWidgetMS(bounds: Rect(320, 100, 140, 210), persistant: true).front;

// make some noise
(
Server.default.waitForBoot{ ~noise = {
    Splay.ar(
        SinOsc.ar(\freq.kr(Array.fib(5, 5, 3)*20), \phase.kr([0, 0]), mul: \amp.kr)
    )
}.play }
);

// set various properties of the widgets
(
~ms.msSize.do({ |i|
    ~ms.setMidiMode(1, i).setCtrlButtonBank(16, i)
});
~ms.addAction(\setFreq, { |cv| ~noise.set(\freq, cv.value) });
)

~knob.setMidiMode(1).setCtrlButtonBank(16).addAction(\setAmp, { |cv| ~noise.set(\amp, cv.value) });

#[lo, hi].do({ |hilo| ~twoDee.setSpec(\phase, hilo).setMidiMode(1, hilo).setCtrlButtonBank(16, hilo) });
~twoDee.addAction(\phaseIt, { |cv| ~noise.setn(\phase, [cv.value, ~twoDee.widgetCV.hi.value]) }, \lo);
~twoDee.addAction(\phaseIt, { |cv| ~noise.setn(\phase, [~twoDee.widgetCV.lo.value, cv.value]) }, \hi);

// close the widgets and open them again
// note: rather than simply opening them you should re-assign while opening them
// as the open-method always returns a new widget but it will keep properties,
// actions, responders etc. of the old one
~knob = ~knob.open;
~twoDee = ~twoDee.open;
~ms = ~ms.open;

Shortcuts

When CVWidgets get created within CVCenter GUI a number of shortcuts apply after a widget has gained focus (i.e. rather than the widget itself one of its GUI-elements gained focus which will be indicated by a green border around the regarding element).

NOTE: All shortcuts are configurable by the user. Handling shortcuts is basically handled by a class named KeyDownActions. They can be altered (actions as well as the action-triggering key-combinations), removed or new shortcuts can be added. This can be done manually by editing *shortcuts (not recommended) or using the KeyDownActionsEditor in the preferences-interface (persistent) or editing short-term shortcuts in the shortcuts-editor (shortcuts will be valid until next recompilation of the class-library). However, this is still an experimental feature. Especially in detached tabs shortcuts may not work as expected

alt arrow right
Select next widget in alphabetical order
alt arrow left
Select previous widget in alphabetical order
s
Open the CVWidgetEitor of the focused widget and focus its Specs-tab
m
Open the CVWidgetEitor of the focused widget and focus its MIDI-tab
o
Open the CVWidgetEitor of the focused widget and focus its OSC-tab
a
Open the CVWidgetEitor of the focused widget and focus its Actions-tab
c
Start or stop OSC calibration
r
Reset and restart OSC calibration
esc
Move focus from the currently focused widget back to the containing view in the CVCenter GUI