expand and correct accepted syntax for ControllableDescriptor strings
[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
138         if (path[1] == "gain") {
139                 _subtype = Gain;
140
141         } else if (path[1] == "trim") {
142                 _subtype = Trim;
143
144         } else if (path[1] == "solo") {
145                 _subtype = Solo;
146
147         } else if (path[1] == "mute") {
148                 _subtype = Mute;
149
150         } else if (path[1] == "recenable") {
151                 _subtype = Recenable;
152
153         } else if (path[1] == "balance") {
154                 _subtype = Balance;
155
156         } else if (path[1] == "panwidth") {
157                 _subtype = PanWidth;
158
159         } else if (path[1] == "pandirection") {
160                 _subtype = PanDirection;
161
162         } else if (path[1] == "plugin") {
163                 if (path.size() == 3 && rest.size() == 3) {
164                         if (path[2] == "parameter") {
165                                 _subtype = PluginParameter;
166                                 _target.push_back (atoi (rest[1]));
167                                 _target.push_back (atoi (rest[2]));
168                         } else {
169                                 return -1;
170                         }
171                 } else {
172                         return -1;
173                 }
174         } else if (path[1] == "send") {
175
176                 if (path.size() == 3 && rest.size() == 2) {
177                         if (path[2] == "gain") {
178                                 _subtype = SendGain;
179                                 _target.push_back (atoi (rest[1]));
180                         } else {
181                                 return -1;
182                         }
183                 } else {
184                         return -1;
185                 }
186         }
187
188         return 0;
189 }
190
191 uint32_t
192 ControllableDescriptor::presentation_order () const
193 {
194         if (banked()) {
195                 return _presentation_order + _bank_offset;
196         }
197
198         return _presentation_order;
199 }
200
201 uint32_t
202 ControllableDescriptor::selection_id () const
203 {
204         if (banked()) {
205                 return _selection_id + _bank_offset;
206         }
207
208         return _selection_id;
209 }
210
211 uint32_t
212 ControllableDescriptor::target (uint32_t n) const
213 {
214         if (n < _target.size()) {
215                 return _target[n];
216         }
217
218         return 0;
219 }