LV2 support.
[ardour.git] / libs / ardour / session_command.cc
1 /*
2     Copyright (C) 2000-2007 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 <ardour/session.h>
21 #include <ardour/route.h>
22 #include <pbd/memento_command.h>
23 #include <ardour/diskstream.h>
24 #include <ardour/playlist.h>
25 #include <ardour/audioplaylist.h>
26 #include <ardour/audio_track.h>
27 #include <ardour/tempo.h>
28 #include <ardour/audiosource.h>
29 #include <ardour/audioregion.h>
30 #include <pbd/error.h>
31 #include <pbd/id.h>
32 #include <pbd/statefuldestructible.h>
33 #include <pbd/failed_constructor.h>
34
35 using namespace PBD;
36 using namespace ARDOUR;
37
38 #include "i18n.h"
39
40 void Session::register_with_memento_command_factory(PBD::ID id, PBD::StatefulThingWithGoingAway *ptr)
41 {
42     registry[id] = ptr;
43 }
44     
45 Command *
46 Session::memento_command_factory(XMLNode *n)
47 {
48     PBD::ID id;
49     XMLNode *before = 0, *after = 0;
50     XMLNode *child = 0;
51
52     /* get id */
53     id = PBD::ID(n->property("obj_id")->value());
54
55     /* get before/after */
56
57     if (n->name() == "MementoCommand") {
58             before = new XMLNode(*n->children().front());
59             after = new XMLNode(*n->children().back());
60             child = before;
61     } else if (n->name() == "MementoUndoCommand") {
62             before = new XMLNode(*n->children().front());
63             child = before;
64     } else if (n->name() == "MementoRedoCommand") {
65             after = new XMLNode(*n->children().front());
66             child = after;
67     } else if (n->name() == "PlaylistCommand") {
68             before = new XMLNode(*n->children().front());
69             after = new XMLNode(*n->children().back());
70             child = before;
71     }
72                     
73     if (!child)
74     {
75         error << _("Tried to reconstitute a MementoCommand with no contents, failing. id=") << id.to_s() << endmsg;
76         return 0;
77     }
78
79     /* create command */
80     string obj_T = n->property ("type_name")->value();
81     if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (Region).name()) {
82             if (audio_regions.count(id)) {
83                     return new MementoCommand<AudioRegion>(*audio_regions[id], before, after);
84             }
85     } else if (obj_T == typeid (AudioSource).name()) {
86             if (audio_sources.count(id))
87                     return new MementoCommand<AudioSource>(*audio_sources[id], before, after);
88     } else if (obj_T == typeid (Location).name()) {
89             return new MementoCommand<Location>(*_locations.get_location_by_id(id), before, after);
90     } else if (obj_T == typeid (Locations).name()) {
91             return new MementoCommand<Locations>(_locations, before, after);
92     } else if (obj_T == typeid (TempoMap).name()) {
93             return new MementoCommand<TempoMap>(*_tempo_map, before, after);
94     } else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) {
95             if (boost::shared_ptr<Playlist> pl = playlist_by_name(child->property("name")->value())) {
96                     return new MementoCommand<Playlist>(*(pl.get()), before, after);
97             }
98     } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) { 
99             return new MementoCommand<Route>(*route_by_id(id), before, after);
100     } else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
101             if (automation_lists.count(id))
102                     return new MementoCommand<AutomationList>(*automation_lists[id], before, after);
103     } else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits here
104             return new MementoCommand<PBD::StatefulThingWithGoingAway>(*registry[id], before, after);
105     }
106
107     /* we failed */
108     error << string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T, id.to_s()) << endmsg;
109
110     return 0 ;
111 }
112
113 Command *
114 Session::global_state_command_factory (const XMLNode& node)
115 {
116         const XMLProperty* prop;
117         Command* command = 0;
118
119         if ((prop = node.property ("type")) == 0) {
120                 error << _("GlobalRouteStateCommand has no \"type\" node, ignoring") << endmsg;
121                 return 0;
122         }
123         
124         try {
125
126                 if (prop->value() == "solo") {
127                         command = new GlobalSoloStateCommand (*this, node);
128                 } else if (prop->value() == "mute") {
129                         command = new GlobalMuteStateCommand (*this, node);
130                 } else if (prop->value() == "rec-enable") {
131                         command = new GlobalRecordEnableStateCommand (*this, node);
132                 } else if (prop->value() == "metering") {
133                         command = new GlobalMeteringStateCommand (*this, node);
134                 } else {
135                         error << string_compose (_("unknown type of GlobalRouteStateCommand (%1), ignored"), prop->value()) << endmsg;
136                 }
137         }
138
139         catch (failed_constructor& err) {
140                 return 0;
141         }
142
143         return command;
144 }
145
146 Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, void* p)
147         : sess (s), src (p)
148 {
149 }
150
151 Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, const XMLNode& node)
152         : sess (s), src (this)
153 {
154         if (set_state (node)) {
155                 throw failed_constructor ();
156         }
157 }
158
159 int
160 Session::GlobalRouteStateCommand::set_state (const XMLNode& node)
161 {
162         GlobalRouteBooleanState states;
163         XMLNodeList nlist;
164         const XMLProperty* prop;
165         XMLNode* child;
166         XMLNodeConstIterator niter;
167         int loop;
168
169         before.clear ();
170         after.clear ();
171         
172         for (loop = 0; loop < 2; ++loop) {
173
174                 const char *str;
175
176                 if (loop) {
177                         str = "after";
178                 } else {
179                         str = "before";
180                 }
181                 
182                 if ((child = node.child (str)) == 0) {
183                         warning << string_compose (_("global route state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
184                         return -1;
185                 }
186
187                 nlist = child->children();
188
189                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
190                         
191                         RouteBooleanState rbs;
192                         boost::shared_ptr<Route> route;
193                         ID id;
194                         
195                         prop = (*niter)->property ("id");
196                         id = prop->value ();
197                         
198                         if ((route = sess.route_by_id (id)) == 0) {
199                                 warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
200                                 continue;
201                         }
202                         
203                         rbs.first = boost::weak_ptr<Route> (route);
204                         
205                         prop = (*niter)->property ("yn");
206                         rbs.second = (prop->value() == "1");
207                         
208                         if (loop) {
209                                 after.push_back (rbs);
210                         } else {
211                                 before.push_back (rbs);
212                         }
213                 }
214         }
215
216         return 0;
217 }
218
219 XMLNode&
220 Session::GlobalRouteStateCommand::get_state ()
221 {
222         XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
223         XMLNode* nbefore = new XMLNode (X_("before"));
224         XMLNode* nafter = new XMLNode (X_("after"));
225
226         for (Session::GlobalRouteBooleanState::iterator x = before.begin(); x != before.end(); ++x) {
227                 XMLNode* child = new XMLNode ("s");
228                 boost::shared_ptr<Route> r = x->first.lock();
229
230                 if (r) {
231                         child->add_property (X_("id"), r->id().to_s());
232                         child->add_property (X_("yn"), (x->second ? "1" : "0"));
233                         nbefore->add_child_nocopy (*child);
234                 }
235         }
236
237         for (Session::GlobalRouteBooleanState::iterator x = after.begin(); x != after.end(); ++x) {
238                 XMLNode* child = new XMLNode ("s");
239                 boost::shared_ptr<Route> r = x->first.lock();
240
241                 if (r) {
242                         child->add_property (X_("id"), r->id().to_s());
243                         child->add_property (X_("yn"), (x->second ? "1" : "0"));
244                         nafter->add_child_nocopy (*child);
245                 }
246         }
247
248         node->add_child_nocopy (*nbefore);
249         node->add_child_nocopy (*nafter);
250
251         return *node;
252 }
253
254 // solo
255
256 Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src)
257         : GlobalRouteStateCommand (sess, src)
258 {
259     after = before = sess.get_global_route_boolean(&Route::soloed);
260 }
261
262 Session::GlobalSoloStateCommand::GlobalSoloStateCommand (Session& sess, const XMLNode& node)
263         : Session::GlobalRouteStateCommand (sess, node)
264 {
265 }
266
267 void 
268 Session::GlobalSoloStateCommand::mark()
269 {
270     after = sess.get_global_route_boolean(&Route::soloed);
271 }
272
273 void 
274 Session::GlobalSoloStateCommand::operator()()
275 {
276     sess.set_global_solo(after, src);
277 }
278
279 void 
280 Session::GlobalSoloStateCommand::undo()
281 {
282     sess.set_global_solo(before, src);
283 }
284
285 XMLNode&
286 Session::GlobalSoloStateCommand::get_state()
287 {
288         XMLNode& node = GlobalRouteStateCommand::get_state();
289         node.add_property ("type", "solo");
290         return node;
291 }
292
293 // mute
294 Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session &sess, void *src)
295         : GlobalRouteStateCommand (sess, src)
296 {
297     after = before = sess.get_global_route_boolean(&Route::muted);
298 }
299
300 Session::GlobalMuteStateCommand::GlobalMuteStateCommand (Session& sess, const XMLNode& node)
301         : Session::GlobalRouteStateCommand (sess, node)
302 {
303 }
304
305 void 
306 Session::GlobalMuteStateCommand::mark()
307 {
308         after = sess.get_global_route_boolean(&Route::muted);
309 }
310
311 void 
312 Session::GlobalMuteStateCommand::operator()()
313 {
314         sess.set_global_mute(after, src);
315 }
316
317 void 
318 Session::GlobalMuteStateCommand::undo()
319 {
320         sess.set_global_mute(before, src);
321 }
322
323 XMLNode&
324 Session::GlobalMuteStateCommand::get_state()
325 {
326         XMLNode& node = GlobalRouteStateCommand::get_state();
327         node.add_property ("type", "mute");
328         return node;
329 }
330
331 // record enable
332 Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session &sess, void *src) 
333         : GlobalRouteStateCommand (sess, src)
334 {
335         after = before = sess.get_global_route_boolean(&Route::record_enabled);
336 }
337
338 Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand (Session& sess, const XMLNode& node)
339         : Session::GlobalRouteStateCommand (sess, node)
340 {
341 }
342
343 void 
344 Session::GlobalRecordEnableStateCommand::mark()
345 {
346         after = sess.get_global_route_boolean(&Route::record_enabled);
347 }
348
349 void 
350 Session::GlobalRecordEnableStateCommand::operator()()
351 {
352         sess.set_global_record_enable(after, src);
353 }
354
355 void 
356 Session::GlobalRecordEnableStateCommand::undo()
357 {
358         sess.set_global_record_enable(before, src);
359 }
360
361 XMLNode& 
362 Session::GlobalRecordEnableStateCommand::get_state()
363 {
364         XMLNode& node = GlobalRouteStateCommand::get_state();
365         node.add_property ("type", "rec-enable");
366         return node;
367 }
368
369 // metering
370 Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &s, void *p) 
371         : sess (s), src (p)
372 {
373         after = before = sess.get_global_route_metering();
374 }
375
376 Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand (Session& s, const XMLNode& node)
377         : sess (s), src (this)
378 {
379         if (set_state (node)) {
380                 throw failed_constructor();
381         }
382 }
383
384 void 
385 Session::GlobalMeteringStateCommand::mark()
386 {
387         after = sess.get_global_route_metering();
388 }
389
390 void 
391 Session::GlobalMeteringStateCommand::operator()()
392 {
393         sess.set_global_route_metering(after, src);
394 }
395
396 void 
397 Session::GlobalMeteringStateCommand::undo()
398 {
399         sess.set_global_route_metering(before, src);
400 }
401
402 XMLNode&
403 Session::GlobalMeteringStateCommand::get_state()
404 {
405         XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
406         XMLNode* nbefore = new XMLNode (X_("before"));
407         XMLNode* nafter = new XMLNode (X_("after"));
408
409         for (Session::GlobalRouteMeterState::iterator x = before.begin(); x != before.end(); ++x) {
410                 XMLNode* child = new XMLNode ("s");
411                 boost::shared_ptr<Route> r = x->first.lock();
412
413                 if (r) {
414                         child->add_property (X_("id"), r->id().to_s());
415
416                         const char* meterstr = 0;
417                         
418                         switch (x->second) {
419                         case MeterInput:
420                                 meterstr = X_("input");
421                                 break;
422                         case MeterPreFader:
423                                 meterstr = X_("pre");
424                                 break;
425                         case MeterPostFader:
426                                 meterstr = X_("post");
427                                 break;
428                         default:
429                                 fatal << string_compose (_("programming error: %1") , "no meter state in Session::GlobalMeteringStateCommand::get_state") << endmsg;
430                         }
431
432                         child->add_property (X_("meter"), meterstr);
433                         nbefore->add_child_nocopy (*child);
434                 }
435         }
436
437         for (Session::GlobalRouteMeterState::iterator x = after.begin(); x != after.end(); ++x) {
438                 XMLNode* child = new XMLNode ("s");
439                 boost::shared_ptr<Route> r = x->first.lock();
440
441                 if (r) {
442                         child->add_property (X_("id"), r->id().to_s());
443
444                         const char* meterstr;
445                         
446                         switch (x->second) {
447                         case MeterInput:
448                                 meterstr = X_("input");
449                                 break;
450                         case MeterPreFader:
451                                 meterstr = X_("pre");
452                                 break;
453                         case MeterPostFader:
454                                 meterstr = X_("post");
455                                 break;
456                         default: meterstr = "";
457                         }
458
459                         child->add_property (X_("meter"), meterstr);
460                         nafter->add_child_nocopy (*child);
461                 }
462         }
463
464         node->add_child_nocopy (*nbefore);
465         node->add_child_nocopy (*nafter);
466
467         node->add_property ("type", "metering");
468
469         return *node;
470 }
471
472 int
473 Session::GlobalMeteringStateCommand::set_state (const XMLNode& node)
474 {
475         GlobalRouteBooleanState states;
476         XMLNodeList nlist;
477         const XMLProperty* prop;
478         XMLNode* child;
479         XMLNodeConstIterator niter;
480         int loop;
481
482         before.clear ();
483         after.clear ();
484         
485         for (loop = 0; loop < 2; ++loop) {
486
487                 const char *str;
488
489                 if (loop) {
490                         str = "after";
491                 } else {
492                         str = "before";
493                 }
494                 
495                 if ((child = node.child (str)) == 0) {
496                         warning << string_compose (_("global route meter state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
497                         return -1;
498                 }
499
500                 nlist = child->children();
501
502                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
503                         
504                         RouteMeterState rms;
505                         boost::shared_ptr<Route> route;
506                         ID id;
507                         
508                         prop = (*niter)->property ("id");
509                         id = prop->value ();
510                         
511                         if ((route = sess.route_by_id (id)) == 0) {
512                                 warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
513                                 continue;
514                         }
515                         
516                         rms.first = boost::weak_ptr<Route> (route);
517                         
518                         prop = (*niter)->property ("meter");
519
520                         if (prop->value() == X_("pre")) {
521                                 rms.second = MeterPreFader;
522                         } else if (prop->value() == X_("post")) {
523                                 rms.second = MeterPostFader;
524                         } else {
525                                 rms.second = MeterInput;
526                         }
527                         
528                         if (loop) {
529                                 after.push_back (rms);
530                         } else {
531                                 before.push_back (rms);
532                         }
533                 }
534         }
535
536         return 0;
537 }