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