2 Copyright (C) 2000-2007 Paul Davis
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.
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.
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.
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>
32 #include <pbd/statefuldestructible.h>
33 #include <pbd/failed_constructor.h>
36 using namespace ARDOUR
;
40 void Session::register_with_memento_command_factory(PBD::ID id
, PBD::StatefulThingWithGoingAway
*ptr
)
46 Session::memento_command_factory(XMLNode
*n
)
49 XMLNode
*before
= 0, *after
= 0;
53 id
= PBD::ID(n
->property("obj_id")->value());
55 /* get before/after */
57 if (n
->name() == "MementoCommand") {
58 before
= new XMLNode(*n
->children().front());
59 after
= new XMLNode(*n
->children().back());
61 } else if (n
->name() == "MementoUndoCommand") {
62 before
= new XMLNode(*n
->children().front());
64 } else if (n
->name() == "MementoRedoCommand") {
65 after
= new XMLNode(*n
->children().front());
67 } else if (n
->name() == "PlaylistCommand") {
68 before
= new XMLNode(*n
->children().front());
69 after
= new XMLNode(*n
->children().back());
75 error
<< _("Tried to reconstitute a MementoCommand with no contents, failing. id=") << id
.to_s() << endmsg
;
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
);
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 Location
* loc
= _locations
.get_location_by_id(id
);
91 return new MementoCommand
<Location
>(*loc
, before
, after
);
93 } else if (obj_T
== typeid (Locations
).name()) {
94 return new MementoCommand
<Locations
>(_locations
, before
, after
);
95 } else if (obj_T
== typeid (TempoMap
).name()) {
96 return new MementoCommand
<TempoMap
>(*_tempo_map
, before
, after
);
97 } else if (obj_T
== typeid (Playlist
).name() || obj_T
== typeid (AudioPlaylist
).name()) {
98 if (boost::shared_ptr
<Playlist
> pl
= playlist_by_name(child
->property("name")->value())) {
99 return new MementoCommand
<Playlist
>(*(pl
.get()), before
, after
);
101 } else if (obj_T
== typeid (Route
).name() || obj_T
== typeid (AudioTrack
).name()) {
102 return new MementoCommand
<Route
>(*route_by_id(id
), before
, after
);
103 } else if (obj_T
== typeid (Curve
).name() || obj_T
== typeid (AutomationList
).name()) {
104 if (automation_lists
.count(id
))
105 return new MementoCommand
<AutomationList
>(*automation_lists
[id
], before
, after
);
106 } else if (registry
.count(id
)) { // For Editor and AutomationLine which are off-limits here
107 return new MementoCommand
<PBD::StatefulThingWithGoingAway
>(*registry
[id
], before
, after
);
111 error
<< string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T
, id
.to_s()) << endmsg
;
117 Session::global_state_command_factory (const XMLNode
& node
)
119 const XMLProperty
* prop
;
120 Command
* command
= 0;
122 if ((prop
= node
.property ("type")) == 0) {
123 error
<< _("GlobalRouteStateCommand has no \"type\" node, ignoring") << endmsg
;
129 if (prop
->value() == "solo") {
130 command
= new GlobalSoloStateCommand (*this, node
);
131 } else if (prop
->value() == "mute") {
132 command
= new GlobalMuteStateCommand (*this, node
);
133 } else if (prop
->value() == "rec-enable") {
134 command
= new GlobalRecordEnableStateCommand (*this, node
);
135 } else if (prop
->value() == "metering") {
136 command
= new GlobalMeteringStateCommand (*this, node
);
138 error
<< string_compose (_("unknown type of GlobalRouteStateCommand (%1), ignored"), prop
->value()) << endmsg
;
142 catch (failed_constructor
& err
) {
149 Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session
& s
, void* p
)
154 Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session
& s
, const XMLNode
& node
)
155 : sess (s
), src (this)
157 if (set_state (node
)) {
158 throw failed_constructor ();
163 Session::GlobalRouteStateCommand::set_state (const XMLNode
& node
)
165 GlobalRouteBooleanState states
;
167 const XMLProperty
* prop
;
169 XMLNodeConstIterator niter
;
175 for (loop
= 0; loop
< 2; ++loop
) {
185 if ((child
= node
.child (str
)) == 0) {
186 warning
<< string_compose (_("global route state command has no \"%1\" node, ignoring entire command"), str
) << endmsg
;
190 nlist
= child
->children();
192 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
194 RouteBooleanState rbs
;
195 boost::shared_ptr
<Route
> route
;
198 prop
= (*niter
)->property ("id");
201 if ((route
= sess
.route_by_id (id
)) == 0) {
202 warning
<< string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id
.to_s()) << endmsg
;
206 rbs
.first
= boost::weak_ptr
<Route
> (route
);
208 prop
= (*niter
)->property ("yn");
209 rbs
.second
= (prop
->value() == "1");
212 after
.push_back (rbs
);
214 before
.push_back (rbs
);
223 Session::GlobalRouteStateCommand::get_state ()
225 XMLNode
* node
= new XMLNode (X_("GlobalRouteStateCommand"));
226 XMLNode
* nbefore
= new XMLNode (X_("before"));
227 XMLNode
* nafter
= new XMLNode (X_("after"));
229 for (Session::GlobalRouteBooleanState::iterator x
= before
.begin(); x
!= before
.end(); ++x
) {
230 XMLNode
* child
= new XMLNode ("s");
231 boost::shared_ptr
<Route
> r
= x
->first
.lock();
234 child
->add_property (X_("id"), r
->id().to_s());
235 child
->add_property (X_("yn"), (x
->second
? "1" : "0"));
236 nbefore
->add_child_nocopy (*child
);
240 for (Session::GlobalRouteBooleanState::iterator x
= after
.begin(); x
!= after
.end(); ++x
) {
241 XMLNode
* child
= new XMLNode ("s");
242 boost::shared_ptr
<Route
> r
= x
->first
.lock();
245 child
->add_property (X_("id"), r
->id().to_s());
246 child
->add_property (X_("yn"), (x
->second
? "1" : "0"));
247 nafter
->add_child_nocopy (*child
);
251 node
->add_child_nocopy (*nbefore
);
252 node
->add_child_nocopy (*nafter
);
259 Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session
&sess
, void *src
)
260 : GlobalRouteStateCommand (sess
, src
)
262 after
= before
= sess
.get_global_route_boolean(&Route::soloed
);
265 Session::GlobalSoloStateCommand::GlobalSoloStateCommand (Session
& sess
, const XMLNode
& node
)
266 : Session::GlobalRouteStateCommand (sess
, node
)
271 Session::GlobalSoloStateCommand::mark()
273 after
= sess
.get_global_route_boolean(&Route::soloed
);
277 Session::GlobalSoloStateCommand::operator()()
279 sess
.set_global_solo(after
, src
);
283 Session::GlobalSoloStateCommand::undo()
285 sess
.set_global_solo(before
, src
);
289 Session::GlobalSoloStateCommand::get_state()
291 XMLNode
& node
= GlobalRouteStateCommand::get_state();
292 node
.add_property ("type", "solo");
297 Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session
&sess
, void *src
)
298 : GlobalRouteStateCommand (sess
, src
)
300 after
= before
= sess
.get_global_route_boolean(&Route::muted
);
303 Session::GlobalMuteStateCommand::GlobalMuteStateCommand (Session
& sess
, const XMLNode
& node
)
304 : Session::GlobalRouteStateCommand (sess
, node
)
309 Session::GlobalMuteStateCommand::mark()
311 after
= sess
.get_global_route_boolean(&Route::muted
);
315 Session::GlobalMuteStateCommand::operator()()
317 sess
.set_global_mute(after
, src
);
321 Session::GlobalMuteStateCommand::undo()
323 sess
.set_global_mute(before
, src
);
327 Session::GlobalMuteStateCommand::get_state()
329 XMLNode
& node
= GlobalRouteStateCommand::get_state();
330 node
.add_property ("type", "mute");
335 Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session
&sess
, void *src
)
336 : GlobalRouteStateCommand (sess
, src
)
338 after
= before
= sess
.get_global_route_boolean(&Route::record_enabled
);
341 Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand (Session
& sess
, const XMLNode
& node
)
342 : Session::GlobalRouteStateCommand (sess
, node
)
347 Session::GlobalRecordEnableStateCommand::mark()
349 after
= sess
.get_global_route_boolean(&Route::record_enabled
);
353 Session::GlobalRecordEnableStateCommand::operator()()
355 sess
.set_global_record_enable(after
, src
);
359 Session::GlobalRecordEnableStateCommand::undo()
361 sess
.set_global_record_enable(before
, src
);
365 Session::GlobalRecordEnableStateCommand::get_state()
367 XMLNode
& node
= GlobalRouteStateCommand::get_state();
368 node
.add_property ("type", "rec-enable");
373 Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session
&s
, void *p
)
376 after
= before
= sess
.get_global_route_metering();
379 Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand (Session
& s
, const XMLNode
& node
)
380 : sess (s
), src (this)
382 if (set_state (node
)) {
383 throw failed_constructor();
388 Session::GlobalMeteringStateCommand::mark()
390 after
= sess
.get_global_route_metering();
394 Session::GlobalMeteringStateCommand::operator()()
396 sess
.set_global_route_metering(after
, src
);
400 Session::GlobalMeteringStateCommand::undo()
402 sess
.set_global_route_metering(before
, src
);
406 Session::GlobalMeteringStateCommand::get_state()
408 XMLNode
* node
= new XMLNode (X_("GlobalRouteStateCommand"));
409 XMLNode
* nbefore
= new XMLNode (X_("before"));
410 XMLNode
* nafter
= new XMLNode (X_("after"));
412 for (Session::GlobalRouteMeterState::iterator x
= before
.begin(); x
!= before
.end(); ++x
) {
413 XMLNode
* child
= new XMLNode ("s");
414 boost::shared_ptr
<Route
> r
= x
->first
.lock();
417 child
->add_property (X_("id"), r
->id().to_s());
419 const char* meterstr
= 0;
423 meterstr
= X_("input");
426 meterstr
= X_("pre");
429 meterstr
= X_("post");
432 fatal
<< string_compose (_("programming error: %1") , "no meter state in Session::GlobalMeteringStateCommand::get_state") << endmsg
;
435 child
->add_property (X_("meter"), meterstr
);
436 nbefore
->add_child_nocopy (*child
);
440 for (Session::GlobalRouteMeterState::iterator x
= after
.begin(); x
!= after
.end(); ++x
) {
441 XMLNode
* child
= new XMLNode ("s");
442 boost::shared_ptr
<Route
> r
= x
->first
.lock();
445 child
->add_property (X_("id"), r
->id().to_s());
447 const char* meterstr
;
451 meterstr
= X_("input");
454 meterstr
= X_("pre");
457 meterstr
= X_("post");
459 default: meterstr
= "";
462 child
->add_property (X_("meter"), meterstr
);
463 nafter
->add_child_nocopy (*child
);
467 node
->add_child_nocopy (*nbefore
);
468 node
->add_child_nocopy (*nafter
);
470 node
->add_property ("type", "metering");
476 Session::GlobalMeteringStateCommand::set_state (const XMLNode
& node
)
478 GlobalRouteBooleanState states
;
480 const XMLProperty
* prop
;
482 XMLNodeConstIterator niter
;
488 for (loop
= 0; loop
< 2; ++loop
) {
498 if ((child
= node
.child (str
)) == 0) {
499 warning
<< string_compose (_("global route meter state command has no \"%1\" node, ignoring entire command"), str
) << endmsg
;
503 nlist
= child
->children();
505 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
508 boost::shared_ptr
<Route
> route
;
511 prop
= (*niter
)->property ("id");
514 if ((route
= sess
.route_by_id (id
)) == 0) {
515 warning
<< string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id
.to_s()) << endmsg
;
519 rms
.first
= boost::weak_ptr
<Route
> (route
);
521 prop
= (*niter
)->property ("meter");
523 if (prop
->value() == X_("pre")) {
524 rms
.second
= MeterPreFader
;
525 } else if (prop
->value() == X_("post")) {
526 rms
.second
= MeterPostFader
;
528 rms
.second
= MeterInput
;
532 after
.push_back (rms
);
534 before
.push_back (rms
);