add User metadata. user metadata is edited from the same dialog and read/writable...
[ardour.git] / libs / ardour / rc_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 */
19
20 #include <unistd.h>
21 #include <cstdio> /* for snprintf, grrr */
22
23 #include <glib.h>
24 #include <glib/gstdio.h> /* for g_stat() */
25 #include <glibmm/miscutils.h>
26
27 #include "pbd/failed_constructor.h"
28 #include "pbd/xml++.h"
29 #include "pbd/filesystem.h"
30 #include "pbd/file_utils.h"
31
32 #include "midi++/manager.h"
33
34 #include "ardour/ardour.h"
35 #include "ardour/rc_configuration.h"
36 #include "ardour/audio_diskstream.h"
37 #include "ardour/control_protocol_manager.h"
38 #include "ardour/filesystem_paths.h"
39 #include "ardour/session_metadata.h"
40
41 #include "i18n.h"
42
43 using namespace ARDOUR;
44 using namespace std;
45 using namespace PBD;
46
47 /* this is global so that we do not have to indirect through an object pointer
48    to reference it.
49 */
50
51 namespace ARDOUR {
52     float speed_quietning = 0.251189; // -12dB reduction for ffwd or rewind
53 }
54
55 RCConfiguration::RCConfiguration ()
56         :
57 /* construct variables */
58 #undef  CONFIG_VARIABLE
59 #undef  CONFIG_VARIABLE_SPECIAL
60 #define CONFIG_VARIABLE(Type,var,name,value) var (name,value),
61 #define CONFIG_VARIABLE_SPECIAL(Type,var,name,value,mutator) var (name,value,mutator),
62 #include "ardour/rc_configuration_vars.h"
63 #undef  CONFIG_VARIABLE
64 #undef  CONFIG_VARIABLE_SPECIAL
65         _control_protocol_state (0)
66 {
67 }
68
69
70 RCConfiguration::~RCConfiguration ()
71 {
72         for (list<XMLNode*>::iterator i = _midi_port_states.begin(); i != _midi_port_states.end(); ++i) {
73                 delete *i;
74         }
75
76         delete _control_protocol_state;
77 }
78
79 int
80 RCConfiguration::load_state ()
81 {
82         sys::path system_rc_file;
83         struct stat statbuf;
84
85         /* load system configuration first */
86
87         if (find_file_in_search_path (ardour_search_path() + system_config_search_path(), "ardour_system.rc", system_rc_file)) {
88                 string rcfile = system_rc_file.to_string();
89
90                 /* stupid XML Parser hates empty files */
91
92                 if (g_stat (rcfile.c_str(), &statbuf)) {
93                         return -1;
94                 }
95
96                 if (statbuf.st_size != 0) {
97                         info << string_compose (_("Loading system configuration file %1"), rcfile) << endl;
98
99                         XMLTree tree;
100                         if (!tree.read (rcfile.c_str())) {
101                                 error << string_compose(_("%1: cannot read system configuration file \"%2\""), PROGRAM_NAME, rcfile) << endmsg;
102                                 return -1;
103                         }
104
105                         if (set_state (*tree.root(), Stateful::current_state_version)) {
106                                 error << string_compose(_("%1: system configuration file \"%2\" not loaded successfully."), PROGRAM_NAME, rcfile) << endmsg;
107                                 return -1;
108                         }
109                 } else {
110                         error << string_compose (_("your system %1 configuration file is empty. This probably means that there as an error installing %1"), PROGRAM_NAME) << endmsg;
111                 }
112         }
113
114         /* now load configuration file for user */
115
116         sys::path user_rc_file;
117
118         if (find_file_in_search_path (ardour_search_path() + user_config_directory(), "ardour.rc", user_rc_file)) {
119                 string rcfile = user_rc_file.to_string();
120
121                 /* stupid XML parser hates empty files */
122
123                 if (g_stat (rcfile.c_str(), &statbuf)) {
124                         return -1;
125                 }
126
127                 if (statbuf.st_size != 0) {
128                         info << string_compose (_("Loading user configuration file %1"), rcfile) << endl;
129
130                         XMLTree tree;
131                         if (!tree.read (rcfile)) {
132                                 error << string_compose(_("%1: cannot read configuration file \"%2\""), PROGRAM_NAME, rcfile) << endmsg;
133                                 return -1;
134                         }
135
136                         if (set_state (*tree.root(), Stateful::current_state_version)) {
137                                 error << string_compose(_("%1: user configuration file \"%2\" not loaded successfully."), PROGRAM_NAME, rcfile) << endmsg;
138                                 return -1;
139                         }
140                 } else {
141                         warning << string_compose (_("your %1 configuration file is empty. This is not normal."), PROGRAM_NAME) << endmsg;
142                 }
143         }
144
145         return 0;
146 }
147
148 int
149 RCConfiguration::save_state()
150 {
151         try
152         {
153                 sys::create_directories (user_config_directory ());
154         }
155         catch (const sys::filesystem_error& ex)
156         {
157                 error << "Could not create user configuration directory" << endmsg;
158                 return -1;
159         }
160
161         sys::path rcfile_path(user_config_directory());
162
163         rcfile_path /= "ardour.rc";
164         const string rcfile = rcfile_path.to_string();
165
166         // this test seems bogus?
167         if (!rcfile.empty()) {
168                 XMLTree tree;
169                 tree.set_root (&get_state());
170                 if (!tree.write (rcfile.c_str())){
171                         error << string_compose (_("Config file %1 not saved"), rcfile) << endmsg;
172                         return -1;
173                 }
174         }
175
176         return 0;
177 }
178
179 void
180 RCConfiguration::add_instant_xml(XMLNode& node)
181 {
182         Stateful::add_instant_xml (node, user_config_directory ());
183 }
184
185 XMLNode*
186 RCConfiguration::instant_xml(const string& node_name)
187 {
188         return Stateful::instant_xml (node_name, user_config_directory ());
189 }
190
191
192 XMLNode&
193 RCConfiguration::get_state ()
194 {
195         XMLNode* root;
196         LocaleGuard lg (X_("POSIX"));
197
198         root = new XMLNode("Ardour");
199
200         MIDI::Manager* mm = MIDI::Manager::instance();
201
202         if (mm) {
203                 boost::shared_ptr<const MIDI::Manager::PortList> ports = mm->get_midi_ports();
204
205                 for (MIDI::Manager::PortList::const_iterator i = ports->begin(); i != ports->end(); ++i) {
206                         root->add_child_nocopy((*i)->get_state());
207                 }
208         }
209
210         root->add_child_nocopy (get_variables ());
211
212         root->add_child_nocopy (SessionMetadata::Metadata()->get_user_state());
213
214         if (_extra_xml) {
215                 root->add_child_copy (*_extra_xml);
216         }
217
218         root->add_child_nocopy (ControlProtocolManager::instance().get_state());
219
220         return *root;
221 }
222
223 XMLNode&
224 RCConfiguration::get_variables ()
225 {
226         XMLNode* node;
227         LocaleGuard lg (X_("POSIX"));
228
229         node = new XMLNode ("Config");
230
231 #undef  CONFIG_VARIABLE
232 #undef  CONFIG_VARIABLE_SPECIAL
233 #define CONFIG_VARIABLE(type,var,Name,value) \
234         var.add_to_node (*node);
235 #define CONFIG_VARIABLE_SPECIAL(type,var,Name,value,mutator) \
236         var.add_to_node (*node);
237 #include "ardour/rc_configuration_vars.h"
238 #undef  CONFIG_VARIABLE
239 #undef  CONFIG_VARIABLE_SPECIAL
240
241         return *node;
242 }
243
244 int
245 RCConfiguration::set_state (const XMLNode& root, int version)
246 {
247         if (root.name() != "Ardour") {
248                 return -1;
249         }
250
251         XMLNodeList nlist = root.children();
252         XMLNodeConstIterator niter;
253         XMLNode *node;
254
255         for (list<XMLNode*>::iterator i = _midi_port_states.begin(); i != _midi_port_states.end(); ++i) {
256                 delete *i;
257         }
258
259         _midi_port_states.clear ();
260
261         Stateful::save_extra_xml (root);
262
263         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
264
265                 node = *niter;
266
267                 if (node->name() == "Config") {
268                         set_variables (*node);
269                 } else if (node->name() == "Metadata") {
270                         SessionMetadata::Metadata()->set_state (*node, version);
271                 } else if (node->name() == ControlProtocolManager::state_node_name) {
272                         _control_protocol_state = new XMLNode (*node);
273                 } else if (node->name() == MIDI::Port::state_node_name) {
274                         _midi_port_states.push_back (new XMLNode (*node));
275                 }
276         }
277
278         Diskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample));
279
280         return 0;
281 }
282
283 void
284 RCConfiguration::set_variables (const XMLNode& node)
285 {
286 #undef  CONFIG_VARIABLE
287 #undef  CONFIG_VARIABLE_SPECIAL
288 #define CONFIG_VARIABLE(type,var,name,value) \
289         if (var.set_from_node (node)) { \
290                 ParameterChanged (name);                  \
291         }
292 #define CONFIG_VARIABLE_SPECIAL(type,var,name,value,mutator) \
293         if (var.set_from_node (node)) {    \
294                 ParameterChanged (name);                     \
295         }
296
297 #include "ardour/rc_configuration_vars.h"
298 #undef  CONFIG_VARIABLE
299 #undef  CONFIG_VARIABLE_SPECIAL
300
301 }
302 void
303 RCConfiguration::map_parameters (boost::function<void (std::string)>& functor)
304 {
305 #undef  CONFIG_VARIABLE
306 #undef  CONFIG_VARIABLE_SPECIAL
307 #define CONFIG_VARIABLE(type,var,name,value)                 functor (name);
308 #define CONFIG_VARIABLE_SPECIAL(type,var,name,value,mutator) functor (name);
309 #include "ardour/rc_configuration_vars.h"
310 #undef  CONFIG_VARIABLE
311 #undef  CONFIG_VARIABLE_SPECIAL
312 }