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