~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/surfaces/mackie/device_profile.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
        Copyright (C) 2006,2007 John Anderson
 
3
        Copyright (C) 2012 Paul Davis
 
4
 
 
5
        This program is free software; you can redistribute it and/or modify
 
6
        it under the terms of the GNU General Public License as published by
 
7
        the Free Software Foundation; either version 2 of the License, or
 
8
        (at your option) any later version.
 
9
 
 
10
        This program is distributed in the hope that it will be useful,
 
11
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
        GNU General Public License for more details.
 
14
 
 
15
        You should have received a copy of the GNU General Public License
 
16
        along with this program; if not, write to the Free Software
 
17
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
*/
 
19
 
 
20
#include <cerrno>
 
21
#include <cstdlib>
 
22
#include <cstring>
 
23
#include <glibmm/miscutils.h>
 
24
 
 
25
#include "pbd/xml++.h"
 
26
#include "pbd/error.h"
 
27
#include "pbd/pathscanner.h"
 
28
#include "pbd/replace_all.h"
 
29
 
 
30
#include "ardour/filesystem_paths.h"
 
31
 
 
32
#include "mackie_control_protocol.h"
 
33
#include "device_profile.h"
 
34
 
 
35
#include "i18n.h"
 
36
 
 
37
using namespace Mackie;
 
38
using namespace PBD;
 
39
using namespace ARDOUR;
 
40
using std::string;
 
41
using std::vector;
 
42
 
 
43
std::map<std::string,DeviceProfile> DeviceProfile::device_profiles;
 
44
 
 
45
DeviceProfile::DeviceProfile (const string& n)
 
46
        : _name (n)
 
47
{
 
48
}
 
49
 
 
50
DeviceProfile::~DeviceProfile()
 
51
{
 
52
}
 
53
 
 
54
static const char * const devprofile_env_variable_name = "ARDOUR_MCP_PATH";
 
55
static const char* const devprofile_dir_name = "mcp";
 
56
static const char* const devprofile_suffix = ".profile";
 
57
 
 
58
static SearchPath
 
59
devprofile_search_path ()
 
60
{
 
61
        bool devprofile_path_defined = false;
 
62
        std::string spath_env (Glib::getenv (devprofile_env_variable_name, devprofile_path_defined));
 
63
 
 
64
        if (devprofile_path_defined) {
 
65
                return spath_env;
 
66
        }
 
67
 
 
68
        SearchPath spath (ardour_data_search_path());
 
69
        spath.add_subdirectory_to_paths(devprofile_dir_name);
 
70
 
 
71
        return spath;
 
72
}
 
73
 
 
74
static std::string
 
75
user_devprofile_directory ()
 
76
{
 
77
        return Glib::build_filename (user_config_directory(), devprofile_dir_name);
 
78
}
 
79
 
 
80
static bool
 
81
devprofile_filter (const string &str, void */*arg*/)
 
82
{
 
83
        return (str.length() > strlen(devprofile_suffix) &&
 
84
                str.find (devprofile_suffix) == (str.length() - strlen (devprofile_suffix)));
 
85
}
 
86
 
 
87
void
 
88
DeviceProfile::reload_device_profiles ()
 
89
{
 
90
        DeviceProfile dp;
 
91
        vector<string> s;
 
92
        vector<string *> *devprofiles;
 
93
        PathScanner scanner;
 
94
        SearchPath spath (devprofile_search_path());
 
95
 
 
96
        devprofiles = scanner (spath.to_string(), devprofile_filter, 0, false, true);
 
97
        device_profiles.clear ();
 
98
 
 
99
        if (!devprofiles) {
 
100
                error << "No MCP device info files found using " << spath.to_string() << endmsg;
 
101
                return;
 
102
        }
 
103
 
 
104
        if (devprofiles->empty()) {
 
105
                error << "No MCP device info files found using " << spath.to_string() << endmsg;
 
106
                return;
 
107
        }
 
108
 
 
109
        for (vector<string*>::iterator i = devprofiles->begin(); i != devprofiles->end(); ++i) {
 
110
                string fullpath = *(*i);
 
111
 
 
112
                XMLTree tree;
 
113
 
 
114
                if (!tree.read (fullpath.c_str())) {
 
115
                        continue;
 
116
                }
 
117
 
 
118
                XMLNode* root = tree.root ();
 
119
                if (!root) {
 
120
                        continue;
 
121
                }
 
122
 
 
123
                if (dp.set_state (*root, 3000) == 0) { /* version is ignored for now */
 
124
                        dp.set_path (fullpath);
 
125
                        device_profiles[dp.name()] = dp;
 
126
                }
 
127
        }
 
128
 
 
129
        delete devprofiles;
 
130
}
 
131
 
 
132
int
 
133
DeviceProfile::set_state (const XMLNode& node, int /* version */)
 
134
{
 
135
        const XMLProperty* prop;
 
136
        const XMLNode* child;
 
137
 
 
138
        if (node.name() != "MackieDeviceProfile") {
 
139
                return -1;
 
140
        }
 
141
 
 
142
        /* name is mandatory */
 
143
 
 
144
        if ((child = node.child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
 
145
                return -1;
 
146
        } else {
 
147
                _name = prop->value();
 
148
        }
 
149
 
 
150
        if ((child = node.child ("Buttons")) != 0) {
 
151
                XMLNodeConstIterator i;
 
152
                const XMLNodeList& nlist (child->children());
 
153
 
 
154
                for (i = nlist.begin(); i != nlist.end(); ++i) {
 
155
 
 
156
                        if ((*i)->name() == "Button") {
 
157
 
 
158
                                if ((prop = (*i)->property ("name")) == 0) {
 
159
                                        error << string_compose ("Button without name in device profile \"%1\" - ignored", _name) << endmsg;
 
160
                                        continue;
 
161
                                }
 
162
 
 
163
                                int id = Button::name_to_id (prop->value());
 
164
                                if (id < 0) {
 
165
                                        error << string_compose ("Unknow button ID \"%1\"", prop->value()) << endmsg;
 
166
                                        continue;
 
167
                                }
 
168
 
 
169
                                Button::ID bid = (Button::ID) id;
 
170
 
 
171
                                ButtonActionMap::iterator b = _button_map.find (bid);
 
172
 
 
173
                                if (b == _button_map.end()) {
 
174
                                        b = _button_map.insert (_button_map.end(), std::pair<Button::ID,ButtonActions> (bid, ButtonActions()));
 
175
                                }
 
176
 
 
177
                                if ((prop = (*i)->property ("plain")) != 0) {
 
178
                                        b->second.plain = prop->value ();
 
179
                                }
 
180
                                if ((prop = (*i)->property ("control")) != 0) {
 
181
                                        b->second.control = prop->value ();
 
182
                                }
 
183
                                if ((prop = (*i)->property ("shift")) != 0) {
 
184
                                        b->second.shift = prop->value ();
 
185
                                }
 
186
                                if ((prop = (*i)->property ("option")) != 0) {
 
187
                                        b->second.option = prop->value ();
 
188
                                }
 
189
                                if ((prop = (*i)->property ("cmdalt")) != 0) {
 
190
                                        b->second.cmdalt = prop->value ();
 
191
                                }
 
192
                                if ((prop = (*i)->property ("shiftcontrol")) != 0) {
 
193
                                        b->second.shiftcontrol = prop->value ();
 
194
                                }
 
195
                        }
 
196
                }
 
197
        }
 
198
 
 
199
        return 0;
 
200
}
 
201
 
 
202
XMLNode&
 
203
DeviceProfile::get_state () const
 
204
{
 
205
        XMLNode* node = new XMLNode ("MackieDeviceProfile");
 
206
        XMLNode* child = new XMLNode ("Name");
 
207
 
 
208
        child->add_property ("value", _name);
 
209
        node->add_child_nocopy (*child);
 
210
 
 
211
        if (_button_map.empty()) {
 
212
                return *node;
 
213
        }
 
214
 
 
215
        XMLNode* buttons = new XMLNode ("Buttons");
 
216
        node->add_child_nocopy (*buttons);
 
217
 
 
218
        for (ButtonActionMap::const_iterator b = _button_map.begin(); b != _button_map.end(); ++b) {
 
219
                XMLNode* n = new XMLNode ("Button");
 
220
 
 
221
                n->add_property ("name", Button::id_to_name (b->first));
 
222
 
 
223
                if (!b->second.plain.empty()) {
 
224
                        n->add_property ("plain", b->second.plain);
 
225
                }
 
226
                if (!b->second.control.empty()) {
 
227
                        n->add_property ("control", b->second.control);
 
228
                }
 
229
                if (!b->second.shift.empty()) {
 
230
                        n->add_property ("shift", b->second.shift);
 
231
                }
 
232
                if (!b->second.option.empty()) {
 
233
                        n->add_property ("option", b->second.option);
 
234
                }
 
235
                if (!b->second.cmdalt.empty()) {
 
236
                        n->add_property ("cmdalt", b->second.cmdalt);
 
237
                }
 
238
                if (!b->second.shiftcontrol.empty()) {
 
239
                        n->add_property ("shiftcontrol", b->second.shiftcontrol);
 
240
                }
 
241
 
 
242
                buttons->add_child_nocopy (*n);
 
243
        }
 
244
 
 
245
        return *node;
 
246
}
 
247
 
 
248
string
 
249
DeviceProfile::get_button_action (Button::ID id, int modifier_state) const
 
250
{
 
251
        ButtonActionMap::const_iterator i = _button_map.find (id);
 
252
 
 
253
        if (i == _button_map.end()) {
 
254
                return string();
 
255
        }
 
256
 
 
257
        if (modifier_state == MackieControlProtocol::MODIFIER_CONTROL) {
 
258
                return i->second.control;
 
259
        } else if (modifier_state == MackieControlProtocol::MODIFIER_SHIFT) {
 
260
                return i->second.shift;
 
261
        } else if (modifier_state == MackieControlProtocol::MODIFIER_OPTION) {
 
262
                return i->second.option;
 
263
        } else if (modifier_state == MackieControlProtocol::MODIFIER_CMDALT) {
 
264
                return i->second.cmdalt;
 
265
        } else if (modifier_state == (MackieControlProtocol::MODIFIER_CONTROL|MackieControlProtocol::MODIFIER_SHIFT)) {
 
266
                return i->second.shiftcontrol;
 
267
        }
 
268
 
 
269
        return i->second.plain;
 
270
}
 
271
 
 
272
void
 
273
DeviceProfile::set_button_action (Button::ID id, int modifier_state, const string& act)
 
274
{
 
275
        ButtonActionMap::iterator i = _button_map.find (id);
 
276
 
 
277
        if (i == _button_map.end()) {
 
278
                i = _button_map.insert (std::make_pair (id, ButtonActions())).first;
 
279
        }
 
280
 
 
281
        string action (act);
 
282
        replace_all (action, "<Actions>/", "");
 
283
 
 
284
        if (modifier_state == MackieControlProtocol::MODIFIER_CONTROL) {
 
285
                i->second.control = action;
 
286
        } else if (modifier_state == MackieControlProtocol::MODIFIER_SHIFT) {
 
287
                i->second.shift = action;
 
288
        } else if (modifier_state == MackieControlProtocol::MODIFIER_OPTION) {
 
289
                i->second.option = action;
 
290
        } else if (modifier_state == MackieControlProtocol::MODIFIER_CMDALT) {
 
291
                i->second.cmdalt = action;
 
292
        } else if (modifier_state == (MackieControlProtocol::MODIFIER_CONTROL|MackieControlProtocol::MODIFIER_SHIFT)) {
 
293
                i->second.shiftcontrol = action;
 
294
        }
 
295
 
 
296
        if (modifier_state == 0) {
 
297
                i->second.plain = action;
 
298
        }
 
299
 
 
300
        save ();
 
301
}
 
302
 
 
303
const string&
 
304
DeviceProfile::name() const
 
305
{
 
306
        return _name;
 
307
}
 
308
 
 
309
void
 
310
DeviceProfile::set_path (const string& p)
 
311
{
 
312
        _path = p;
 
313
}
 
314
 
 
315
/* XXX copied from libs/ardour/utils.cc */
 
316
 
 
317
static string
 
318
legalize_for_path (const string& str)
 
319
{
 
320
        string::size_type pos;
 
321
        string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
 
322
        string legal;
 
323
 
 
324
        legal = str;
 
325
        pos = 0;
 
326
 
 
327
        while ((pos = legal.find_first_of (illegal_chars, pos)) != string::npos) {
 
328
                legal.replace (pos, 1, "_");
 
329
                pos += 1;
 
330
        }
 
331
 
 
332
        return string (legal);
 
333
}
 
334
 
 
335
 
 
336
void
 
337
DeviceProfile::save ()
 
338
{
 
339
        std::string fullpath = user_devprofile_directory();
 
340
 
 
341
        if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
 
342
                error << string_compose(_("Session: cannot create user MCP profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
 
343
                return;
 
344
        }
 
345
 
 
346
        fullpath = Glib::build_filename (fullpath, legalize_for_path (_name) + ".profile");
 
347
        
 
348
        XMLTree tree;
 
349
        tree.set_root (&get_state());
 
350
 
 
351
        if (!tree.write (fullpath)) {
 
352
                error << string_compose ("MCP profile not saved to %1", fullpath) << endmsg;
 
353
        }
 
354
}
 
355