add well known controls to list accessible via a MIDI binding map (or OSC?)
[ardour.git] / libs / ardour / controllable_descriptor.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifdef COMPILER_MSVC
20 #include <io.h> // Microsoft's nearest equivalent to <unistd.h>
21 #include <ardourext/misc.h>
22 #else
23 #include <regex.h>
24 #endif
25
26 #include "pbd/strsplit.h"
27 #include "pbd/convert.h"
28
29 #include "ardour/controllable_descriptor.h"
30
31 using namespace std;
32 using namespace PBD;
33 using namespace ARDOUR;
34
35 int
36 ControllableDescriptor::set (const std::string& str)
37 {
38         string::size_type first_space = str.find_first_of (" ");
39
40         if (first_space == string::npos) {
41                 return -1;
42         }
43
44         string front = str.substr (0, first_space);
45         string back = str.substr (first_space);
46
47         vector<string> path;
48         split (front, path, '/');
49
50         if (path.size() < 2) {
51                 return -1;
52         }
53
54         vector<string> rest;
55         split (back, rest, ' ');
56
57         if (rest.size() < 1) {
58                 return -1;
59         }
60
61         bool stripable = false;
62         regex_t compiled_pattern;
63         const char * const pattern = "^[BS]?[0-9]+";
64
65         if (path[0] == "route" || path[0] == "rid") {
66
67                 /* this is not going to fail */
68                 regcomp (&compiled_pattern, pattern, REG_EXTENDED|REG_NOSUB);
69                 bool matched = (regexec (&compiled_pattern, rest[0].c_str(), 0, 0, 0) == 0);
70                 regfree (&compiled_pattern);
71
72                 if (matched) {
73                         _top_level_type = PresentationOrderRoute;
74                         stripable = true;
75                 } else {
76                         _top_level_type = NamedRoute;
77                         _top_level_name = rest[0];
78                 }
79
80         } else if (path[0] == "vca") {
81                 _top_level_type = PresentationOrderVCA;
82                 stripable = true;
83         } else if (path[0] == "bus") {
84                 /* digits, or B<digits> or S<digits> will be used as for route;
85                    anything else will be treated as a track name.
86                 */
87
88                 /* this is not going to fail */
89
90                 regcomp (&compiled_pattern, pattern, REG_EXTENDED|REG_NOSUB);
91                 bool matched = (regexec (&compiled_pattern, rest[0].c_str(), 0, 0, 0) == 0);
92                 regfree (&compiled_pattern);
93
94                 if (matched) {
95                         _top_level_type = PresentationOrderBus;
96                         stripable = true;
97                 } else {
98                         _top_level_type = NamedRoute;
99                         _top_level_name = rest[0];
100                 }
101
102         } else if (path[0] == "track") {
103
104                 /* digits, or B<digits> or S<digits> will be used as for route;
105                    anything else will be treated as a track name.
106                 */
107
108                 /* this is not going to fail */
109                 regcomp (&compiled_pattern, pattern, REG_EXTENDED|REG_NOSUB);
110                 bool matched = (regexec (&compiled_pattern, rest[0].c_str(), 0, 0, 0) == 0);
111                 regfree (&compiled_pattern);
112
113                 if (matched) {
114                         _top_level_type = PresentationOrderTrack;
115                         stripable = true;
116                 } else {
117                         _top_level_type = NamedRoute;
118                         _top_level_name = rest[0];
119                 }
120         }
121
122         if (stripable) {
123                 if (rest[0][0] == 'B') {
124                         _banked = true;
125                         _presentation_order = atoi (rest[0].substr (1));
126                 } else if (rest[0][0] == 'S') {
127                         _top_level_type = SelectionCount;
128                         _banked = true;
129                         _selection_id = atoi (rest[0].substr (1));
130                 } else if (isdigit (rest[0][0])) {
131                         _banked = false;
132                         _presentation_order = atoi (rest[0]);
133                 } else {
134                         return -1;
135                 }
136
137                 _presentation_order -= 1; /* order is zero-based, but maps use 1-based */
138         }
139
140         if (path[1] == "gain") {
141                 _subtype = GainAutomation;
142
143         } else if (path[1] == "trim") {
144                 _subtype = TrimAutomation;
145
146         } else if (path[1] == "solo") {
147                 _subtype = SoloAutomation;
148
149         } else if (path[1] == "mute") {
150                 _subtype = MuteAutomation;
151
152         } else if (path[1] == "recenable") {
153                 _subtype = RecEnableAutomation;
154
155         } else if (path[1] == "panwidth") {
156                 _subtype = PanWidthAutomation;
157
158         } else if (path[1] == "pandirection" || path[1] == "balance") {
159                 _subtype = PanAzimuthAutomation;
160
161         } else if (path[1] == "plugin") {
162                 if (path.size() == 3 && rest.size() == 3) {
163                         if (path[2] == "parameter") {
164                                 _subtype = PluginAutomation;
165                                 _target.push_back (atoi (rest[1]));
166                                 _target.push_back (atoi (rest[2]));
167                         } else {
168                                 return -1;
169                         }
170                 } else {
171                         return -1;
172                 }
173         } else if (path[1] == "send") {
174
175                 if (path.size() == 3 && rest.size() == 2) {
176                         if (path[2] == "gain") {
177                                 _subtype = SendLevelAutomation;
178                                 _target.push_back (atoi (rest[1]));
179
180                         } else if (path[2] == "gain") {
181                                 _subtype = SendLevelAutomation;
182                                 _target.push_back (atoi (rest[1]));
183                         } else if (path[2] == "enable") {
184                                 _subtype = SendLevelAutomation;
185                                 _target.push_back (atoi (rest[1]));
186                         } else {
187                                 return -1;
188
189                         }
190                 } else {
191                         return -1;
192                 }
193         } else if (path[1] == "eq") {
194
195                 /* /route/eq/gain/<band> */
196
197                 if (path.size() != 3) {
198                         return -1;
199                 }
200
201                 _target.push_back (atoi (path[3])); /* band number */
202
203                 if (path[2] == "enable") {
204                         _subtype = EQEnableAutomation;
205                 } else if (path[2] == "gain") {
206                         _subtype = EQGainAutomation;
207                 } else if (path[2] == "freq") {
208                         _subtype = EQFreqAutomation;
209                 } else if (path[2] == "q") {
210                         _subtype = EQQAutomation;
211                 } else if (path[2] == "shape") {
212                         _subtype = EQShapeAutomation;
213                 } else {
214                         return -1;
215                 }
216
217                 /* get desired band number */
218                 _target.push_back (atoi (rest[1]));
219
220         } else if (path[1] == "filter") {
221
222                 /* /route/filter/hi/freq */
223
224                 if (path.size() != 4) {
225                         return -1;
226                 }
227
228                 if (path[2] == "hi") {
229                         _target.push_back (1); /* high pass filter */
230                 } else {
231                         _target.push_back (0); /* low pass filter */
232                 }
233
234                 if (path[3] == "enable") {
235                         _subtype = FilterFreqAutomation;
236                 } else if (path[3] == "freq") {
237                         _subtype = FilterFreqAutomation;
238                 } else if (path[3] == "slope") {
239                         _subtype = FilterSlopeAutomation;
240                 } else {
241                         return -1;
242                 }
243
244                 _target.push_back (atoi (rest[1]));
245
246         } else if (path[1] == "compressor") {
247
248                 if (path.size() != 3) {
249                         return -1;
250                 }
251
252                 if (path[2] == "enable") {
253                         _subtype = CompressorEnableAutomation;
254                 } else if (path[2] == "threshold") {
255                         _subtype = CompressorThresholdAutomation;
256                 } else if (path[2] == "mode") {
257                         _subtype = CompressorModeAutomation;
258                 } else if (path[2] == "speed") {
259                         _subtype = CompressorSpeedAutomation;
260                 } else if (path[2] == "makeup") {
261                         _subtype = CompressorMakeupAutomation;
262                 } else {
263                         return -1;
264                 }
265         }
266
267         return 0;
268 }
269
270 uint32_t
271 ControllableDescriptor::presentation_order () const
272 {
273         if (banked()) {
274                 return _presentation_order + _bank_offset;
275         }
276
277         return _presentation_order;
278 }
279
280 uint32_t
281 ControllableDescriptor::selection_id () const
282 {
283         if (banked()) {
284                 return _selection_id + _bank_offset;
285         }
286
287         return _selection_id;
288 }
289
290 uint32_t
291 ControllableDescriptor::target (uint32_t n) const
292 {
293         if (n < _target.size()) {
294                 return _target[n];
295         }
296
297         return 0;
298 }