-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProcessings_with_controls.mw
170 lines (120 loc) · 6.28 KB
/
Processings_with_controls.mw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
Controls are another kind of connector for processing modules, just like ports.
While ports queue received data tokens and must be consumed in order when Do is run,
controls receive data at the same time they are sent.
A processing may setup a callback to receive them or
just take the last received value when the Do method is eventually executed.
You can define and initialize InControls and OutControls in a similar way you did with In/OutPorts but they are not templated (to the date) since they are always CLAM::TControlData which renders to float or double depending on your compilation flags.
First you should add the necessary includes:
#include<CLAM/InControl.hxx>
#include<CLAM/OutControl.hxx>
Then you are ready to add your input and output controls to the class declaration:
[[Image:MyProcessing-withControls.png|thumb|NetworkEditor represents controls as little squares on the top and the bottom of the processing box. Control flow is up-down.]]
...
CLAM::InPort<MyInputDataType> mIn;
CLAM::OutPort<MyOutputDataType> mOut;
CLAM::InControl mInControl; // <- New
CLAM::OutControl mOutControl; // <- New
...
And at the initialization of the class:
MyProcessing(const Config & config=Config())
: mIn("My Input", this)
, mOut("My Output", this)
, mInControl("In Control", this) // <- New
, mOutControl("Out Control", this) // <- New
{
....
TODO: Correct place to set default input values: constructor, ConcreteConfigure or ConcreteStart?
....
mInControl.DoControl(3.1416);
....
Within the Do method, whenever we want to read a input value just do:
....
CLAM::TControlData controlValue = mInControl.GetLastValue();
....
And to send a value through a output control:
....
mOutControl.SendControl(3.1416);
....
[[Image:ControlRelatedProcessings.png|thumb|Several control related processing are available on the NetworkEditor.]]
When playing with controls there are several useful processings available on the NetworkEditor:
* ControlSender: Controls a single output control with a Slider, a Knob or an Spinbox.
* ControlSurface: Controls two output controls at a time by moving a 2D point.
* ControlPrinter: Shows the values it gets on its input controls.
* ...
TODO: Put here a note on ControlSource and ControlSink as soon as they are working on the Network editor.
= Beyond 1.3.0, typed controls =
'''Note:''' This documentation version is the one for 1.4.0 and beyond.
The [[Version Migration Guide]] will help you to easily migrate from 1.3 to 1.4 typed controls.
Controls are another kind of connector for processing modules, just like ports.
While ports queue received data tokens and must be consumed in order when Do is run,
controls receive data at the same time they are sent.
A processing may setup a callback to receive them or
just take the last received value when the Do method is eventually executed.
Traditionally, controls in CLAM managed just floats defined as TControlData.
Since version 1.4 this is no more and you can use any copìable and default initiable C++ object.
Anyway you should avoid control types with expensive or realtime unsafe copy or initialization operations
because controls are sent in bursts and this may have a serious impact on the performance of your system.
== Adding the control ==
You can define and initialize InControls and OutControls in a similar way you did with In/OutPorts.
First you should add the necessary includes:
#include<CLAM/InControl.hxx>
#include<CLAM/OutControl.hxx>
Then you are ready to add your input and output controls to the class declaration:
[[Image:MyProcessing-withControls.png|thumb|NetworkEditor represents controls as little squares on the top and the bottom of the processing box. Control flow is up-down.]]
...
CLAM::InPort<MyInputDataType> mIn;
CLAM::OutPort<MyOutputDataType> mOut;
CLAM::InControl<TControlData> mInControl; // <- New
CLAM::OutControl<TControlData> mOutControl; // <- New
...
And at the initialization of the class:
MyProcessing(const Config & config=Config())
: mIn("My Input", this)
, mOut("My Output", this)
, mInControl("In Control", this) // <- New
, mOutControl("Out Control", this) // <- New
{
....
TODO: How to setup bounds
== Using the control ==
TODO: Correct place to set default input values: constructor, ConcreteConfigure or ConcreteStart?
....
mInControl.DoControl(3.1416);
....
Within the Do method, whenever we want to read a input value just do:
....
CLAM::TControlData controlValue = mInControl.GetLastValue();
....
And to send a value through a output control:
....
mOutControl.SendControl(3.1416);
....
== Callback InControls ==
Alternatively you can setup a callback to respond to incoming controls.
Such callback could be executed in bursts so do not do anything expensive or realtime unsafe there.
MyProcessing(const Config & config=Config())
: mIn("My Input", this)
, mOut("My Output", this)
, mInControl("In Control", this, &MyProcessing::MyControlCallback) // <- Changed!
, mOutControl("Out Control", this)
{
....
void MyControlCallback(const TControlData & value)
{
// Take value and do whatever to processing internal state.
You may setup a different callback for each control,
or you could use a control identifier to know which control calls the callback,
which is particularly usefull when having [[Processings with variable number of ports|a dynamic number of controls]].
In that case, the first parameter of the constructor is the identifier.
, mInControl(4, "In Control", this, &MyProcessing::MyControlCallback)
and the callback signature should be:
void MyControlCallback(unsigned controlId, const TControlData & value)
TODO: Thread safety
== Helper processings to manage controls ==
[[Image:ControlRelatedProcessings.png|thumb|Several control related processing are available on the NetworkEditor.]]
When playing with controls there are several useful processings available on the NetworkEditor:
* ControlSender: Controls a single output control with a Slider, a Knob or an Spinbox.
* ControlSurface: Controls two output controls at a time by moving a 2D point.
* ControlPrinter: Shows the values it gets on its input controls.
* ...
TODO: Put here a note on ControlSource and ControlSink as soon as they are working on the Network editor.