A MethodController is a Controller Class that links a Model to multiple Views.
The class is a generalization of the CV class from the Conductor Quark.
The data stored in the Model is accessed by getter and setter methods chosen when the MethodController is created.
MethodController:value gets the Models data.
The View is accessed by getter and setter methods chosen when the View is linked to the controller.
Often the data in a Model is of a specific type and has a specific range because of that it makes sense to associate it with a ControlSpec.
The unmaped value of the models data ( in the range 0 to 1) can be accessed by the MethodController:input.
This allows us to map the data to the 0 to 1 range often used in Views.
If the data in the Model can not be easily specified but the views should make use of of their own interpretation of the data a spec can be provided to the link method.
The setter methods can be derived from the getter methods.
The default getter method is value.
To be able to access elements of an Array it is possible to define a getter or setter with initial arguments.
A shortcut for this is provided by the forArray classmethod.
The MethodController becomes a dependant of the Model and the linked Objects, if a link is set up. When a link is released (unlink) these dependancies are removed. Views usually remove themselves from the Dictionary onClose. (This behaviour would break if someone make use of the onClose variable and overwrites the function that got put there) To avoid memory leaks links have to be unlinked.
Create a MethodController
model |
The Object that holds the data |
modelget |
Symbol, Array or Function that is used to get the data from the model. A Symbol of the name of the method that gets the data. default is \value. a Array of the form [a Symbol, ... args] to be able to get data from the Model with methods with multiple arguments like [\at, 0]. or a Function a function that gets as first argument the model for Example { |m|m.value*2 }. |
modelset |
Nil, Symbol, Array or Function that is used to get the data from the model. If no modelset is specified modelget.asSetter is called. This works well with symbols. a Symbol of the name of the method that sets the data. default is modelset.asSetter i.e. \value_ . a Array of the form [a Symbol, ... args] to be able to set data in the Model with methods with multiple arguments like [\at, 0]. or a Function a function that gets as first argument the Model and as a second argument the value for example { |m, v|m.value = v/2 }. |
spec |
A ControlSpec that specifies the data of the Model. The spec is used to unmap the data to the 0 to 1 range used by many Views. The default value is a NonSpec a spec that does not specify anything. |
updateObjectOnChange |
This argument is true or false. default value is true. If the Model has a ObjectController as a dependant it might be reasonable to assume that the controller needs update after data in the model changed therefore the ObjectController is called. If this behavious is not undesirable the variable can be set to false. |
msg |
msg is the msg used to identify the specific parameter that is updated in the Model. if model.changed( msg) is called the MethodController is updated. usually msg is derived from the modelget variable. if modelget is a symbol msg is that Symbol. if modelget is a array a msg is derived from that Array [\at, 0] becomes \at_0_ . if modelget is a function the msg is the symbol \methodControllerSync . |
a MethodController
If the Model is an Array or similar ArrayedCollection that where data is accessed through \at and \put this method simplifies the specification of getter and setter.
model |
the model |
pos |
The position of the data in the model that is accessed. resulting in a getter array of the form [\at, pos] and a setter array of the form [\put, pos] |
spec |
a ControlSpec |
updateObjectOnChange |
default is true |
msg |
default is derived from the getter method \at_pos_ |
a MethodController
getter gets the unmaped data from the model ( making use of the spec of the MethodController)
setter maps and sets the data in the model ( making use of the spec of the MethodController)
val |
Usually a number in the range 0 to 1 |
if a ControlSpec is specified the getter usually returns a number in the range 0 to 1
getter gets the data from the model.
setter sets the data in the model.
val |
the data from the model.
calls MethodController: -value for compatibility with Streams
shortcut for linkInput
Links to a object ( often a View ) so that the object is updated on a models change.
Linking means here a bidirectional connection.
The object/view gets the model as unmaped by the provided spec.
Model gets the object/views state as mapped by the provided spec.
This link makes use of the MethodController: -input method.
obj |
Object to be linked often a View. |
objget |
Method used to get data from the View. Default is \value. Either Symbol, Array, or Function ( see MethodController: *new modelget) |
objset |
Method used to set data in the View. Default is \value_. Either Symbol, Array, or Function ( see MethodController: *new modelget) |
spec |
A ControlSpec that can be used to map the values returned by MethodController: -input to the range of the View() |
links a object ( often a View) to the Model via the value methods of the controller.
obj |
Object to be linked often a View. |
objget |
Method used to get data from the View. Default is \value. Either Symbol, Array, or Function ( see MethodController: *new modelget) |
objset |
Method used to set data in the View. Default is \value_. Either Symbol, Array, or Function ( see MethodController: *new modelget) |
spec |
A ControlSpec that can be used to map the values returned by MethodController: -value to the range of the View() |
In some cases only a onedirectional connection is needed.
linkInputFrom updates the model from the linked View.
For details on the arguments look at MethodController: -linkInput.
In some cases only a onedirectional connection is needed.
linkInputFrom updates the model from the linked View.
For details on the arguments look at MethodController: -linkValue.
In some cases only a onedirectional connection is needed.
linkInputTo updates the linked View from the model.
For details on the arguments look at MethodController: -linkInput.
In some cases only a onedirectional connection is needed.
linkValueTo updates the linked View from the model.
For details on the arguments look at MethodController: -linkValue.
update is called by model.changed( msg).
if the model might have changed but one is not sure one can use this method to update the linked Views.
releases or unlinks the obj.
unlink is assiged to be called by View:onClose automatically if View:onClose is not overwritten by another function. If the Object is not a View it has to be called explicitly to avoid memory leaks.
obj |
object to be released |
Remove this MethodController from its models dependancy. If all links are released it is called. Because calling MethodController:update would be of no use.
replaces the model
newModel |
Model to replace the old model. |
to make clear the value of this class I create three windows that are updated seamlessly.
It makes use of the ObjectController class.
This example is like the previous a color chooser. But in this case the model is not a color itself but rather an array of 3 frequencies. This example aims to make clear why I implemented MethodController and its link functions with two specs.
In the following I introduce a few examples for commonly used Views
Because MultiSliderView returns an Array we need an object that holds an Array.
A List similar to a Ref holding an Array as a reference.
Unfortunately EnvelopeView is not really a view of an envelope but rather a View of a connected dots.
In this case the EnvelopeView is just only displays the Envelop. The Slider2D changes the Env.
This is not the most reasonable example but it showed me that it must be possible to hook more than one controller to a View.
The following is similar to the SV of the Conductor Quark.
The following is similar to the TV of the Conductor Quark.
It is possible to link objects that are not Views but in this case
not a view
This is basically stolen from CV from the Conductor and/or CVCenter Quark ( including the documentation).
Synths specify initial values of parameters as a flat Array of pairs consisting of a name and its initial value:
"Extended argument arrays" allow MethodControllers to be used in place of the initial value. This is the standard syntax for establishing connections between MethodControllers and a server. In an extended argument array, the MethodController's value can be altered before being sent, multiple MethodController's can determine the value to be sent, and the value to be sent can be determined by a function ( here freq
is just meant as an example key):
value | [freq: 440] |
MethodController | [freq: aMethodController] |
altered MethodController | [freq: [aMethodController, aMethodController.midicps]] |
combination | [freq: [[aMethodController, bMethodController], aMethodController.midicps + bMethodController]] |
function | [freq: [aMethodController, { aMethodController.midicps.value + 33.rand }]] |
For example, the method Synth: *controls is identical to Synth: *new except the args
parameter is extended:
basic MethodController connection
modified MethodController connection
multiple modified connection
In the previous two examples, the modifying expression is actually a combination of Streams altered with binary and unary operators. This is concise, but in some cases, it may be necessary to use a Function to define the modification.
A simple synth controlling GUI
In this example a synth is started by a button and released. the button is representing if the synth is running or not.
to link a midifunc to a controller is so simple that i don't know what to describe about it.
MIDIIn.doNoteOnAction( 1, 1, 128.rand, 128.rand); // spoof
more complex views:
My implementation is shaped by my use of CV but because I aimed for a implementation that is clear to me I simplified code to use cases that I know this means especially that i didn't implemented links to Node, NodeProxy, and Bus. For the case you have use cases for that please feel free to contact me.