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