the BIG CONFIG patch
[ardour.git] / libs / ardour / configuration.cc
1 /*
2     Copyright (C) 1999-2006 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     $Id$
19 */
20
21 #include <unistd.h>
22 #include <cstdio> /* for snprintf, grrr */
23
24 #include <pbd/failed_constructor.h>
25 #include <pbd/xml++.h>
26
27 #include <ardour/ardour.h>
28 #include <ardour/audio_library.h>
29 #include <ardour/configuration.h>
30 #include <ardour/audio_diskstream.h>
31 #include <ardour/destructive_filesource.h>
32 #include <ardour/control_protocol_manager.h>
33
34 #include "i18n.h"
35
36 using namespace ARDOUR;
37 using namespace std;
38 using namespace PBD;
39
40 /* this is global so that we do not have to indirect through an object pointer
41    to reference it.
42 */
43
44 namespace ARDOUR {
45     float speed_quietning = 0.251189; // -12dB reduction for ffwd or rewind
46 }
47
48 Configuration::Configuration ()
49         :
50 /* construct variables */
51 #undef  CONFIG_VARIABLE
52 #undef  CONFIG_VARIABLE_SPECIAL 
53 #define CONFIG_VARIABLE(Type,var,name,value) var (name,value),
54 #define CONFIG_VARIABLE_SPECIAL(Type,var,name,value,mutator) var (name,value,mutator),
55 #include "ardour/configuration_vars.h"
56 #undef  CONFIG_VARIABLE
57 #undef  CONFIG_VARIABLE_SPECIAL 
58
59         current_owner (ConfigVariableBase::Default)
60 {
61         _control_protocol_state = 0;
62 }
63
64 Configuration::~Configuration ()
65 {
66 }
67
68 void
69 Configuration::set_current_owner (ConfigVariableBase::Owner owner)
70 {
71         current_owner = owner;
72 }
73
74 int
75 Configuration::load_state ()
76 {
77         string rcfile;
78         
79         /* load system configuration first */
80
81         rcfile = find_config_file ("ardour_system.rc");
82
83         if (rcfile.length()) {
84
85                 XMLTree tree;
86
87                 cerr << string_compose (_("loading system configuration file %1"), rcfile) << endl;
88                 
89                 if (!tree.read (rcfile.c_str())) {
90                         error << string_compose(_("Ardour: cannot read system configuration file \"%1\""), rcfile) << endmsg;
91                         return -1;
92                 }
93
94                 current_owner = ConfigVariableBase::System;
95
96                 if (set_state (*tree.root())) {
97                         error << string_compose(_("Ardour: system configuration file \"%1\" not loaded successfully."), rcfile) << endmsg;
98                         return -1;
99                 }
100         }
101
102
103         /* now load configuration file for user */
104         
105         rcfile = find_config_file ("ardour.rc");
106
107         if (rcfile.length()) {
108
109                 XMLTree tree;
110                 
111                 cerr << string_compose (_("loading user configuration file %1"), rcfile) << endl;
112
113                 if (!tree.read (rcfile)) {
114                         error << string_compose(_("Ardour: cannot read configuration file \"%1\""), rcfile) << endmsg;
115                         return -1;
116                 }
117
118                 current_owner = ConfigVariableBase::Config;
119
120                 if (set_state (*tree.root())) {
121                         error << string_compose(_("Ardour: user configuration file \"%1\" not loaded successfully."), rcfile) << endmsg;
122                         return -1;
123                 }
124         }
125
126         return 0;
127 }
128
129 int
130 Configuration::save_state()
131 {
132         XMLTree tree;
133         string rcfile;
134
135         /* Note: this only writes the state not touched by Session or Interface
136         */
137
138         rcfile = get_user_ardour_path ();
139         rcfile += "ardour.rc";
140
141         if (rcfile.length()) {
142                 tree.set_root (&state (ConfigVariableBase::Config));
143                 if (!tree.write (rcfile.c_str())){
144                         error << string_compose (_("Config file %1 not saved"), rcfile) << endmsg;
145                         return -1;
146                 }
147         }
148
149         return 0;
150 }
151
152 XMLNode&
153 Configuration::get_state ()
154 {
155         return state (ConfigVariableBase::Config);
156 }
157
158 XMLNode&
159 Configuration::get_partial_state (ConfigVariableBase::Owner owner)
160 {
161         return state (owner);
162 }
163
164 XMLNode&
165 Configuration::state (ConfigVariableBase::Owner owner)
166 {
167         XMLNode* root;
168         XMLNode* node;
169         LocaleGuard lg (X_("POSIX"));
170
171         node = new XMLNode("Config");
172
173 #undef  CONFIG_VARIABLE
174 #undef  CONFIG_VARIABLE_SPECIAL 
175 #define CONFIG_VARIABLE(type,var,name,value) \
176          if (var.owner() <= owner) var.add_to_node (*node);
177 #define CONFIG_VARIABLE_SPECIAL(type,var,name,value,mutator) \
178          if (var.owner() <= owner) var.add_to_node (*node);
179 #include "ardour/configuration_vars.h"
180 #undef  CONFIG_VARIABLE
181 #undef  CONFIG_VARIABLE_SPECIAL 
182
183         if (owner == ConfigVariableBase::Config) {
184
185                 root = new XMLNode("Ardour");
186                 typedef map<string, MidiPortDescriptor*>::const_iterator CI;
187                 for(CI m = midi_ports.begin(); m != midi_ports.end(); ++m){
188                         root->add_child_nocopy(m->second->get_state());
189                 }
190
191                 root->add_child_nocopy (*node);
192
193                 if (_extra_xml) {
194                         root->add_child_copy (*_extra_xml);
195                 }
196                 
197                 root->add_child_nocopy (ControlProtocolManager::instance().get_state());
198                 root->add_child_nocopy (Library->get_state());
199
200         } else {
201
202                 root = node;
203         }
204                 
205         return *root;
206 }
207
208 int
209 Configuration::set_state (const XMLNode& root)
210 {
211         if (root.name() != "Ardour") {
212                 return -1;
213         }
214
215         XMLNodeList nlist = root.children();
216         XMLNodeConstIterator niter;
217         XMLNode *node;
218
219         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
220
221                 node = *niter;
222
223                 if (node->name() == "MIDI-port") {
224
225                         try {
226                                 pair<string,MidiPortDescriptor*> newpair;
227                                 newpair.second = new MidiPortDescriptor (*node);
228                                 newpair.first = newpair.second->tag;
229                                 midi_ports.insert (newpair);
230                         }
231
232                         catch (failed_constructor& err) {
233                                 warning << _("ill-formed MIDI port specification in ardour rcfile (ignored)") << endmsg;
234                         }
235
236                 } else if (node->name() == "Config") {
237                         
238                         set_variables (*node, ConfigVariableBase::Config);
239                         
240                 } else if (node->name() == "extra") {
241                         _extra_xml = new XMLNode (*node);
242
243                 } else if (node->name() == ControlProtocolManager::state_node_name) {
244                         _control_protocol_state = new XMLNode (*node);
245                 } else if (node->name() == AudioLibrary::state_node_name) {
246                         Library->set_state (*node);
247                 }
248         }
249
250         Diskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample));
251
252         return 0;
253 }
254
255 void
256 Configuration::set_variables (const XMLNode& node, ConfigVariableBase::Owner owner)
257 {
258 #undef  CONFIG_VARIABLE
259 #undef  CONFIG_VARIABLE_SPECIAL 
260 #define CONFIG_VARIABLE(type,var,name,value) \
261          if (var.set_from_node (node, owner)) { \
262                  ParameterChanged (name); \
263          }
264 #define CONFIG_VARIABLE_SPECIAL(type,var,name,value,mutator) \
265          if (var.set_from_node (node, owner)) { \
266                  ParameterChanged (name); \
267          }
268 #include "ardour/configuration_vars.h"
269 #undef  CONFIG_VARIABLE
270 #undef  CONFIG_VARIABLE_SPECIAL 
271
272 }
273
274 Configuration::MidiPortDescriptor::MidiPortDescriptor (const XMLNode& node)
275 {
276         const XMLProperty *prop;
277         bool have_tag = false;
278         bool have_device = false;
279         bool have_type = false;
280         bool have_mode = false;
281
282         if ((prop = node.property ("tag")) != 0) {
283                 tag = prop->value();
284                 have_tag = true;
285         }
286
287         if ((prop = node.property ("device")) != 0) {
288                 device = prop->value();
289                 have_device = true;
290         }
291
292         if ((prop = node.property ("type")) != 0) {
293                 type = prop->value();
294                 have_type = true;
295         }
296
297         if ((prop = node.property ("mode")) != 0) {
298                 mode = prop->value();
299                 have_mode = true;
300         }
301
302         if (!have_tag || !have_device || !have_type || !have_mode) {
303                 throw failed_constructor();
304         }
305 }
306
307 XMLNode&
308 Configuration::MidiPortDescriptor::get_state()
309 {
310         XMLNode* root = new XMLNode("MIDI-port");
311
312         root->add_property("tag", tag);
313         root->add_property("device", device);
314         root->add_property("type", type);
315         root->add_property("mode", mode);
316
317         return *root;
318 }
319
320 void
321 Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
322 {
323 #undef  CONFIG_VARIABLE
324 #undef  CONFIG_VARIABLE_SPECIAL 
325 #define CONFIG_VARIABLE(type,var,name,value)                 theSlot (name);
326 #define CONFIG_VARIABLE_SPECIAL(type,var,name,value,mutator) theSlot (name);
327 #include "ardour/configuration_vars.h"
328 #undef  CONFIG_VARIABLE
329 #undef  CONFIG_VARIABLE_SPECIAL 
330 }