mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-17 20:26:30 +01:00
Fix crossfade undo using the stateful diff system. Fixes #3257.
git-svn-id: svn://localhost/ardour2/branches/3.0@7694 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
df2fd94919
commit
c243a02c99
21 changed files with 225 additions and 72 deletions
|
|
@ -791,7 +791,7 @@ CrossfadeEditor::apply ()
|
||||||
|
|
||||||
_apply_to (xfade);
|
_apply_to (xfade);
|
||||||
|
|
||||||
_session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state()));
|
_session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state ()));
|
||||||
_session->commit_reversible_command ();
|
_session->commit_reversible_command ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1037,6 +1037,15 @@ RegionMoveDrag::finished_no_copy (
|
||||||
playlist->freeze ();
|
playlist->freeze ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this movement may result in a crossfade being modified, so we need to get undo
|
||||||
|
data from the playlist as well as the region.
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = modified_playlists.insert (playlist);
|
||||||
|
if (r.second) {
|
||||||
|
playlist->clear_changes ();
|
||||||
|
}
|
||||||
|
|
||||||
rv->region()->set_position (where, (void*) this);
|
rv->region()->set_position (where, (void*) this);
|
||||||
|
|
||||||
_editor->session()->add_command (new StatefulDiffCommand (rv->region()));
|
_editor->session()->add_command (new StatefulDiffCommand (rv->region()));
|
||||||
|
|
@ -1172,7 +1181,12 @@ void
|
||||||
RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & playlists)
|
RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & playlists)
|
||||||
{
|
{
|
||||||
for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
||||||
_editor->session()->add_command (new StatefulDiffCommand (*i));
|
StatefulDiffCommand* c = new StatefulDiffCommand (*i);
|
||||||
|
if (!c->empty()) {
|
||||||
|
_editor->session()->add_command (new StatefulDiffCommand (*i));
|
||||||
|
} else {
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2820,11 +2820,9 @@ Editor::separate_regions_between (const TimeSelection& ts)
|
||||||
|
|
||||||
/* pick up changes to existing regions */
|
/* pick up changes to existing regions */
|
||||||
|
|
||||||
vector<StatefulDiffCommand*> cmds;
|
vector<Command*> cmds;
|
||||||
playlist->rdiff (cmds);
|
playlist->rdiff (cmds);
|
||||||
for (vector<StatefulDiffCommand*>::iterator j = cmds.begin(); j != cmds.end(); ++j) {
|
_session->add_commands (cmds);
|
||||||
_session->add_command (*j);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pick up changes to the playlist itself (adds/removes)
|
/* pick up changes to the playlist itself (adds/removes)
|
||||||
*/
|
*/
|
||||||
|
|
@ -3773,11 +3771,9 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
|
||||||
playlist->add_region (r, start);
|
playlist->add_region (r, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<StatefulDiffCommand*> cmds;
|
vector<Command*> cmds;
|
||||||
playlist->rdiff (cmds);
|
playlist->rdiff (cmds);
|
||||||
for (vector<StatefulDiffCommand*>::iterator j = cmds.begin(); j != cmds.end(); ++j) {
|
_session->add_commands (cmds);
|
||||||
_session->add_command (*j);
|
|
||||||
}
|
|
||||||
|
|
||||||
_session->add_command (new StatefulDiffCommand (playlist));
|
_session->add_command (new StatefulDiffCommand (playlist));
|
||||||
}
|
}
|
||||||
|
|
@ -4492,13 +4488,10 @@ Editor::nudge_track (bool use_edit, bool forwards)
|
||||||
|
|
||||||
playlist->nudge_after (start, distance, forwards);
|
playlist->nudge_after (start, distance, forwards);
|
||||||
|
|
||||||
vector<StatefulDiffCommand*> cmds;
|
vector<Command*> cmds;
|
||||||
|
|
||||||
playlist->rdiff (cmds);
|
playlist->rdiff (cmds);
|
||||||
|
_session->add_commands (cmds);
|
||||||
for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
|
|
||||||
_session->add_command (*c);
|
|
||||||
}
|
|
||||||
|
|
||||||
_session->add_command (new StatefulDiffCommand (playlist));
|
_session->add_command (new StatefulDiffCommand (playlist));
|
||||||
}
|
}
|
||||||
|
|
@ -6568,13 +6561,9 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
|
||||||
|
|
||||||
pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
|
pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
|
||||||
|
|
||||||
vector<StatefulDiffCommand*> cmds;
|
vector<Command*> cmds;
|
||||||
|
|
||||||
pl->rdiff (cmds);
|
pl->rdiff (cmds);
|
||||||
|
_session->add_commands (cmds);
|
||||||
for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
|
|
||||||
_session->add_command (*c);
|
|
||||||
}
|
|
||||||
|
|
||||||
_session->add_command (new StatefulDiffCommand (pl));
|
_session->add_command (new StatefulDiffCommand (pl));
|
||||||
commit = true;
|
commit = true;
|
||||||
|
|
|
||||||
|
|
@ -1339,13 +1339,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
||||||
if ((what_we_got = playlist->cut (time)) != 0) {
|
if ((what_we_got = playlist->cut (time)) != 0) {
|
||||||
_editor.get_cut_buffer().add (what_we_got);
|
_editor.get_cut_buffer().add (what_we_got);
|
||||||
|
|
||||||
vector<StatefulDiffCommand*> cmds;
|
vector<Command*> cmds;
|
||||||
|
|
||||||
playlist->rdiff (cmds);
|
playlist->rdiff (cmds);
|
||||||
|
_session->add_commands (cmds);
|
||||||
|
|
||||||
for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
|
|
||||||
_session->add_command (*c);
|
|
||||||
}
|
|
||||||
_session->add_command (new StatefulDiffCommand (playlist));
|
_session->add_command (new StatefulDiffCommand (playlist));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1357,13 +1354,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
||||||
|
|
||||||
case Clear:
|
case Clear:
|
||||||
if ((what_we_got = playlist->cut (time)) != 0) {
|
if ((what_we_got = playlist->cut (time)) != 0) {
|
||||||
vector<StatefulDiffCommand*> cmds;
|
|
||||||
|
|
||||||
|
vector<Command*> cmds;
|
||||||
playlist->rdiff (cmds);
|
playlist->rdiff (cmds);
|
||||||
|
_session->add_commands (cmds);
|
||||||
for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
|
|
||||||
_session->add_command (*c);
|
|
||||||
}
|
|
||||||
_session->add_command (new StatefulDiffCommand (playlist));
|
_session->add_command (new StatefulDiffCommand (playlist));
|
||||||
what_we_got->release ();
|
what_we_got->release ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,39 @@ class Region;
|
||||||
class AudioRegion;
|
class AudioRegion;
|
||||||
class Source;
|
class Source;
|
||||||
|
|
||||||
|
namespace Properties {
|
||||||
|
/* fake the type, since crossfades are handled by SequenceProperty which doesn't
|
||||||
|
care about such things.
|
||||||
|
*/
|
||||||
|
extern PBD::PropertyDescriptor<bool> crossfades;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AudioPlaylist;
|
||||||
|
|
||||||
|
class CrossfadeListProperty : public PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CrossfadeListProperty (AudioPlaylist &);
|
||||||
|
|
||||||
|
void get_content_as_xml (boost::shared_ptr<Crossfade>, XMLNode &) const;
|
||||||
|
boost::shared_ptr<Crossfade> get_content_from_xml (XMLNode const &) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CrossfadeListProperty* clone () const;
|
||||||
|
CrossfadeListProperty* create () const;
|
||||||
|
|
||||||
|
friend class AudioPlaylist;
|
||||||
|
/* we live and die with our playlist, no lifetime management needed */
|
||||||
|
AudioPlaylist& _playlist;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class AudioPlaylist : public ARDOUR::Playlist
|
class AudioPlaylist : public ARDOUR::Playlist
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::list<boost::shared_ptr<Crossfade> > Crossfades;
|
typedef std::list<boost::shared_ptr<Crossfade> > Crossfades;
|
||||||
|
static void make_property_quarks ();
|
||||||
|
|
||||||
public:
|
|
||||||
AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
|
AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
|
||||||
AudioPlaylist (Session&, std::string name, bool hidden = false);
|
AudioPlaylist (Session&, std::string name, bool hidden = false);
|
||||||
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, std::string name, bool hidden = false);
|
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, std::string name, bool hidden = false);
|
||||||
|
|
@ -59,6 +86,8 @@ class AudioPlaylist : public ARDOUR::Playlist
|
||||||
|
|
||||||
bool destroy_region (boost::shared_ptr<Region>);
|
bool destroy_region (boost::shared_ptr<Region>);
|
||||||
|
|
||||||
|
void update (const CrossfadeListProperty::ChangeRecord &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/* playlist "callbacks" */
|
/* playlist "callbacks" */
|
||||||
|
|
@ -72,7 +101,7 @@ class AudioPlaylist : public ARDOUR::Playlist
|
||||||
void remove_dependents (boost::shared_ptr<Region> region);
|
void remove_dependents (boost::shared_ptr<Region> region);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Crossfades _crossfades;
|
CrossfadeListProperty _crossfades;
|
||||||
Crossfades _pending_xfade_adds;
|
Crossfades _pending_xfade_adds;
|
||||||
|
|
||||||
void crossfade_invalidated (boost::shared_ptr<Region>);
|
void crossfade_invalidated (boost::shared_ptr<Region>);
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class Crossfade : public ARDOUR::AudioRegion
|
||||||
|
|
||||||
/* the usual XML constructor */
|
/* the usual XML constructor */
|
||||||
|
|
||||||
Crossfade (const Playlist&, XMLNode&);
|
Crossfade (const Playlist&, XMLNode const &);
|
||||||
virtual ~Crossfade();
|
virtual ~Crossfade();
|
||||||
|
|
||||||
static void make_property_quarks ();
|
static void make_property_quarks ();
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_
|
||||||
RegionListProperty (Playlist&);
|
RegionListProperty (Playlist&);
|
||||||
|
|
||||||
RegionListProperty* clone () const;
|
RegionListProperty* clone () const;
|
||||||
|
void get_content_as_xml (boost::shared_ptr<Region>, XMLNode &) const;
|
||||||
boost::shared_ptr<Region> lookup_id (const PBD::ID& id) const;
|
boost::shared_ptr<Region> get_content_from_xml (XMLNode const &) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RegionListProperty* create () const;
|
RegionListProperty* create () const;
|
||||||
|
|
@ -90,7 +90,7 @@ public:
|
||||||
|
|
||||||
void update (const RegionListProperty::ChangeRecord&);
|
void update (const RegionListProperty::ChangeRecord&);
|
||||||
void clear_owned_changes ();
|
void clear_owned_changes ();
|
||||||
void rdiff (std::vector<PBD::StatefulDiffCommand*>&) const;
|
void rdiff (std::vector<Command*>&) const;
|
||||||
|
|
||||||
boost::shared_ptr<Region> region_by_id (const PBD::ID&) const;
|
boost::shared_ptr<Region> region_by_id (const PBD::ID&) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||||
_current_trans.top()->add_command (cmd);
|
_current_trans.top()->add_command (cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_commands (std::vector<Command*> const & cmds);
|
||||||
|
|
||||||
std::map<PBD::ID,PBD::StatefulDestructible*> registry;
|
std::map<PBD::ID,PBD::StatefulDestructible*> registry;
|
||||||
|
|
||||||
// these commands are implemented in libs/ardour/session_command.cc
|
// these commands are implemented in libs/ardour/session_command.cc
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
#include "ardour/debug.h"
|
#include "ardour/debug.h"
|
||||||
#include "ardour/configuration.h"
|
#include "ardour/configuration.h"
|
||||||
|
|
@ -38,14 +37,70 @@ using namespace ARDOUR;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
namespace Properties {
|
||||||
|
PBD::PropertyDescriptor<bool> crossfades;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioPlaylist::make_property_quarks ()
|
||||||
|
{
|
||||||
|
Properties::crossfades.property_id = g_quark_from_static_string (X_("crossfades"));
|
||||||
|
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for crossfades = %1\n", Properties::crossfades.property_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
|
||||||
|
: SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
|
||||||
|
, _playlist (pl)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CrossfadeListProperty *
|
||||||
|
CrossfadeListProperty::create () const
|
||||||
|
{
|
||||||
|
return new CrossfadeListProperty (_playlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
CrossfadeListProperty *
|
||||||
|
CrossfadeListProperty::clone () const
|
||||||
|
{
|
||||||
|
return new CrossfadeListProperty (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
|
||||||
|
{
|
||||||
|
/* Crossfades are not written to any state when they are no
|
||||||
|
longer in use, so we must write their state here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
XMLNode& c = xfade->get_state ();
|
||||||
|
node.add_child_nocopy (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<Crossfade>
|
||||||
|
CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
|
||||||
|
{
|
||||||
|
XMLNodeList const c = node.children ();
|
||||||
|
assert (c.size() == 1);
|
||||||
|
return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
|
AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
|
||||||
: Playlist (session, node, DataType::AUDIO, hidden)
|
: Playlist (session, node, DataType::AUDIO, hidden)
|
||||||
|
, _crossfades (*this)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const XMLProperty* prop = node.property("type");
|
const XMLProperty* prop = node.property("type");
|
||||||
assert(!prop || DataType(prop->value()) == DataType::AUDIO);
|
assert(!prop || DataType(prop->value()) == DataType::AUDIO);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
add_property (_crossfades);
|
||||||
|
|
||||||
in_set_state++;
|
in_set_state++;
|
||||||
set_state (node, Stateful::loading_state_version);
|
set_state (node, Stateful::loading_state_version);
|
||||||
in_set_state--;
|
in_set_state--;
|
||||||
|
|
@ -53,12 +108,17 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden
|
||||||
|
|
||||||
AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
|
AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
|
||||||
: Playlist (session, name, DataType::AUDIO, hidden)
|
: Playlist (session, name, DataType::AUDIO, hidden)
|
||||||
|
, _crossfades (*this)
|
||||||
{
|
{
|
||||||
|
add_property (_crossfades);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
|
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
|
||||||
: Playlist (other, name, hidden)
|
: Playlist (other, name, hidden)
|
||||||
|
, _crossfades (*this)
|
||||||
{
|
{
|
||||||
|
add_property (_crossfades);
|
||||||
|
|
||||||
RegionList::const_iterator in_o = other->regions.begin();
|
RegionList::const_iterator in_o = other->regions.begin();
|
||||||
RegionList::iterator in_n = regions.begin();
|
RegionList::iterator in_n = regions.begin();
|
||||||
|
|
||||||
|
|
@ -99,7 +159,10 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, stri
|
||||||
|
|
||||||
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
|
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
|
||||||
: Playlist (other, start, cnt, name, hidden)
|
: Playlist (other, start, cnt, name, hidden)
|
||||||
|
, _crossfades (*this)
|
||||||
{
|
{
|
||||||
|
add_property (_crossfades);
|
||||||
|
|
||||||
/* this constructor does NOT notify others (session) */
|
/* this constructor does NOT notify others (session) */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -795,3 +858,13 @@ AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossf
|
||||||
s (*i);
|
s (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
|
||||||
|
{
|
||||||
|
for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
|
||||||
|
add_crossfade (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't remove crossfades here; they will be dealt with by the dependency code */
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
|
||||||
initialize ();
|
initialize ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
|
Crossfade::Crossfade (const Playlist& playlist, XMLNode const & node)
|
||||||
: AudioRegion (playlist.session(), 0, 0, "unnamed crossfade")
|
: AudioRegion (playlist.session(), 0, 0, "unnamed crossfade")
|
||||||
, CROSSFADE_DEFAULT_PROPERTIES
|
, CROSSFADE_DEFAULT_PROPERTIES
|
||||||
, _fade_in (Evoral::Parameter(FadeInAutomation)) // linear (gain coefficient) => -inf..+6dB
|
, _fade_in (Evoral::Parameter(FadeInAutomation)) // linear (gain coefficient) => -inf..+6dB
|
||||||
|
|
@ -132,7 +132,7 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Region> r;
|
boost::shared_ptr<Region> r;
|
||||||
XMLProperty* prop;
|
XMLProperty const * prop;
|
||||||
LocaleGuard lg (X_("POSIX"));
|
LocaleGuard lg (X_("POSIX"));
|
||||||
|
|
||||||
/* we have to find the in/out regions before we can do anything else */
|
/* we have to find the in/out regions before we can do anything else */
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
#include "ardour/debug.h"
|
#include "ardour/debug.h"
|
||||||
#include "ardour/filesystem_paths.h"
|
#include "ardour/filesystem_paths.h"
|
||||||
#include "ardour/mix.h"
|
#include "ardour/mix.h"
|
||||||
#include "ardour/playlist.h"
|
#include "ardour/audioplaylist.h"
|
||||||
#include "ardour/plugin_manager.h"
|
#include "ardour/plugin_manager.h"
|
||||||
#include "ardour/process_thread.h"
|
#include "ardour/process_thread.h"
|
||||||
#include "ardour/profile.h"
|
#include "ardour/profile.h"
|
||||||
|
|
@ -251,6 +251,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
|
||||||
AudioRegion::make_property_quarks ();
|
AudioRegion::make_property_quarks ();
|
||||||
RouteGroup::make_property_quarks ();
|
RouteGroup::make_property_quarks ();
|
||||||
Playlist::make_property_quarks ();
|
Playlist::make_property_quarks ();
|
||||||
|
AudioPlaylist::make_property_quarks ();
|
||||||
|
|
||||||
/* this is a useful ready to use PropertyChange that many
|
/* this is a useful ready to use PropertyChange that many
|
||||||
things need to check. This avoids having to compose
|
things need to check. This avoids having to compose
|
||||||
|
|
|
||||||
|
|
@ -110,12 +110,40 @@ RegionListProperty::RegionListProperty (Playlist& pl)
|
||||||
: SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
|
: SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
|
||||||
, _playlist (pl)
|
, _playlist (pl)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RegionListProperty *
|
||||||
|
RegionListProperty::clone () const
|
||||||
|
{
|
||||||
|
return new RegionListProperty (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegionListProperty *
|
||||||
|
RegionListProperty::create () const
|
||||||
|
{
|
||||||
|
return new RegionListProperty (_playlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
|
||||||
|
{
|
||||||
|
/* All regions (even those which are deleted) have their state saved by other
|
||||||
|
code, so we can just store ID here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
node.add_property ("id", region->id().to_s ());
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<Region>
|
boost::shared_ptr<Region>
|
||||||
RegionListProperty::lookup_id (const ID& id) const
|
RegionListProperty::get_content_from_xml (XMLNode const & node) const
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
|
XMLProperty const * prop = node.property ("id");
|
||||||
|
assert (prop);
|
||||||
|
|
||||||
|
PBD::ID id (prop->value ());
|
||||||
|
|
||||||
|
boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = RegionFactory::region_by_id (id);
|
ret = RegionFactory::region_by_id (id);
|
||||||
|
|
@ -124,16 +152,6 @@ RegionListProperty::lookup_id (const ID& id) const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionListProperty* RegionListProperty::clone () const
|
|
||||||
{
|
|
||||||
return new RegionListProperty (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
RegionListProperty* RegionListProperty::create () const
|
|
||||||
{
|
|
||||||
return new RegionListProperty (_playlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
|
Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
|
||||||
: SessionObject(sess, nom)
|
: SessionObject(sess, nom)
|
||||||
, regions (*this)
|
, regions (*this)
|
||||||
|
|
@ -2100,7 +2118,7 @@ Playlist::mark_session_dirty ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Playlist::rdiff (vector<StatefulDiffCommand*>& cmds) const
|
Playlist::rdiff (vector<Command*>& cmds) const
|
||||||
{
|
{
|
||||||
RegionLock rlock (const_cast<Playlist *> (this));
|
RegionLock rlock (const_cast<Playlist *> (this));
|
||||||
Stateful::rdiff (cmds);
|
Stateful::rdiff (cmds);
|
||||||
|
|
|
||||||
|
|
@ -2312,6 +2312,14 @@ Session::finish_reversible_command (UndoTransaction& ut)
|
||||||
_history.add (&ut);
|
_history.add (&ut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Session::add_commands (vector<Command*> const & cmds)
|
||||||
|
{
|
||||||
|
for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
|
||||||
|
add_command (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Session::begin_reversible_command(const string& name)
|
Session::begin_reversible_command(const string& name)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ def build(bld):
|
||||||
obj.includes = ['.', '../surfaces/control_protocol', '..']
|
obj.includes = ['.', '../surfaces/control_protocol', '..']
|
||||||
obj.name = 'libardour'
|
obj.name = 'libardour'
|
||||||
obj.target = 'ardour'
|
obj.target = 'ardour'
|
||||||
obj.uselib = 'GLIBMM GTHREAD AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX COREAUDIO'
|
obj.uselib = 'GLIBMM GTHREAD AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX COREAUDIO CURL DL'
|
||||||
obj.uselib_local = 'libpbd libmidipp libevoral libvamphost libvampplugin libtaglib librubberband libaudiographer'
|
obj.uselib_local = 'libpbd libmidipp libevoral libvamphost libvampplugin libtaglib librubberband libaudiographer'
|
||||||
obj.vnum = LIBARDOUR_LIB_VERSION
|
obj.vnum = LIBARDOUR_LIB_VERSION
|
||||||
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
|
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ public:
|
||||||
virtual XMLNode &get_state();
|
virtual XMLNode &get_state();
|
||||||
virtual int set_state(const XMLNode&, int /*version*/) { /* noop */ return 0; }
|
virtual int set_state(const XMLNode&, int /*version*/) { /* noop */ return 0; }
|
||||||
|
|
||||||
|
virtual bool empty () const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Command() {}
|
Command() {}
|
||||||
Command(const std::string& name) : _name(name) {}
|
Command(const std::string& name) : _name(name) {}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ public:
|
||||||
virtual void get_changes_as_properties (PropertyList& changes, Command *) const = 0;
|
virtual void get_changes_as_properties (PropertyList& changes, Command *) const = 0;
|
||||||
|
|
||||||
/** Collect StatefulDiffCommands for changes to anything that we own */
|
/** Collect StatefulDiffCommands for changes to anything that we own */
|
||||||
virtual void rdiff (std::vector<StatefulDiffCommand*> &) const {}
|
virtual void rdiff (std::vector<Command*> &) const {}
|
||||||
|
|
||||||
/** Look in an XML node written by get_changes_as_xml and, if XML from this property
|
/** Look in an XML node written by get_changes_as_xml and, if XML from this property
|
||||||
* is found, create a property with the changes from the XML.
|
* is found, create a property with the changes from the XML.
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "pbd/id.h"
|
#include "pbd/id.h"
|
||||||
#include "pbd/property_basics.h"
|
#include "pbd/property_basics.h"
|
||||||
#include "pbd/property_list.h"
|
#include "pbd/property_list.h"
|
||||||
|
#include "pbd/stateful_diff_command.h"
|
||||||
|
|
||||||
namespace PBD {
|
namespace PBD {
|
||||||
|
|
||||||
|
|
@ -80,8 +81,6 @@ class SequenceProperty : public PropertyBase
|
||||||
SequenceProperty (PropertyID id, const boost::function<void(const ChangeRecord&)>& update)
|
SequenceProperty (PropertyID id, const boost::function<void(const ChangeRecord&)>& update)
|
||||||
: PropertyBase (id), _update_callback (update) {}
|
: PropertyBase (id), _update_callback (update) {}
|
||||||
|
|
||||||
virtual typename Container::value_type lookup_id (const PBD::ID&) const = 0;
|
|
||||||
|
|
||||||
void invert () {
|
void invert () {
|
||||||
_changes.removed.swap (_changes.added);
|
_changes.removed.swap (_changes.added);
|
||||||
}
|
}
|
||||||
|
|
@ -97,18 +96,25 @@ class SequenceProperty : public PropertyBase
|
||||||
for (typename ChangeContainer::iterator i = _changes.added.begin(); i != _changes.added.end(); ++i) {
|
for (typename ChangeContainer::iterator i = _changes.added.begin(); i != _changes.added.end(); ++i) {
|
||||||
XMLNode* add_node = new XMLNode ("Add");
|
XMLNode* add_node = new XMLNode ("Add");
|
||||||
child->add_child_nocopy (*add_node);
|
child->add_child_nocopy (*add_node);
|
||||||
add_node->add_property ("id", (*i)->id().to_s());
|
get_content_as_xml (*i, *add_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_changes.removed.empty()) {
|
if (!_changes.removed.empty()) {
|
||||||
for (typename ChangeContainer::iterator i = _changes.removed.begin(); i != _changes.removed.end(); ++i) {
|
for (typename ChangeContainer::iterator i = _changes.removed.begin(); i != _changes.removed.end(); ++i) {
|
||||||
XMLNode* remove_node = new XMLNode ("Remove");
|
XMLNode* remove_node = new XMLNode ("Remove");
|
||||||
child->add_child_nocopy (*remove_node);
|
child->add_child_nocopy (*remove_node);
|
||||||
remove_node->add_property ("id", (*i)->id().to_s());
|
get_content_as_xml (*i, *remove_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get a representation of one of our items as XML. The representation must be sufficient to
|
||||||
|
* restore the item's state later; an ID is ok if someone else is storing the item state,
|
||||||
|
* otherwise it needs to be the full state. The supplied node is an <Add> or <Remove>
|
||||||
|
* which this method can either add properties or children to.
|
||||||
|
*/
|
||||||
|
virtual void get_content_as_xml (typename ChangeContainer::value_type, XMLNode &) const = 0;
|
||||||
|
|
||||||
bool set_value (XMLNode const &) {
|
bool set_value (XMLNode const &) {
|
||||||
/* XXX: not used, but probably should be */
|
/* XXX: not used, but probably should be */
|
||||||
assert (false);
|
assert (false);
|
||||||
|
|
@ -191,11 +197,10 @@ class SequenceProperty : public PropertyBase
|
||||||
|
|
||||||
XMLNodeList const & grandchildren = (*i)->children ();
|
XMLNodeList const & grandchildren = (*i)->children ();
|
||||||
for (XMLNodeList::const_iterator j = grandchildren.begin(); j != grandchildren.end(); ++j) {
|
for (XMLNodeList::const_iterator j = grandchildren.begin(); j != grandchildren.end(); ++j) {
|
||||||
XMLProperty const * prop = (*j)->property ("id");
|
|
||||||
assert (prop);
|
typename Container::value_type v = get_content_from_xml (**j);
|
||||||
PBD::ID id (prop->value ());
|
|
||||||
typename Container::value_type v = lookup_id (id);
|
|
||||||
assert (v);
|
assert (v);
|
||||||
|
|
||||||
if ((*j)->name() == "Add") {
|
if ((*j)->name() == "Add") {
|
||||||
p->_changes.added.insert (v);
|
p->_changes.added.insert (v);
|
||||||
} else if ((*j)->name() == "Remove") {
|
} else if ((*j)->name() == "Remove") {
|
||||||
|
|
@ -206,13 +211,16 @@ class SequenceProperty : public PropertyBase
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Given an <Add> or <Remove> node as passed into get_content_to_xml, obtain an item */
|
||||||
|
virtual typename Container::value_type get_content_from_xml (XMLNode const & node) const = 0;
|
||||||
|
|
||||||
void clear_owned_changes () {
|
void clear_owned_changes () {
|
||||||
for (typename Container::iterator i = begin(); i != end(); ++i) {
|
for (typename Container::iterator i = begin(); i != end(); ++i) {
|
||||||
(*i)->clear_changes ();
|
(*i)->clear_changes ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdiff (std::vector<StatefulDiffCommand*>& cmds) const {
|
void rdiff (std::vector<Command*>& cmds) const {
|
||||||
for (typename Container::const_iterator i = begin(); i != end(); ++i) {
|
for (typename Container::const_iterator i = begin(); i != end(); ++i) {
|
||||||
if ((*i)->changed ()) {
|
if ((*i)->changed ()) {
|
||||||
StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
|
StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
|
||||||
|
|
@ -255,6 +263,11 @@ class SequenceProperty : public PropertyBase
|
||||||
return _val.erase (f, l);
|
return _val.erase (f, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remove (const typename Container::value_type& v) {
|
||||||
|
_changes.remove (v);
|
||||||
|
_val.remove (v);
|
||||||
|
}
|
||||||
|
|
||||||
void push_back (const typename Container::value_type& v) {
|
void push_back (const typename Container::value_type& v) {
|
||||||
_changes.add (v);
|
_changes.add (v);
|
||||||
_val.push_back (v);
|
_val.push_back (v);
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ class Stateful {
|
||||||
void clear_changes ();
|
void clear_changes ();
|
||||||
virtual void clear_owned_changes ();
|
virtual void clear_owned_changes ();
|
||||||
PropertyList* get_changes_as_properties (Command *) const;
|
PropertyList* get_changes_as_properties (Command *) const;
|
||||||
virtual void rdiff (std::vector<StatefulDiffCommand*> &) const;
|
virtual void rdiff (std::vector<Command*> &) const;
|
||||||
bool changed() const;
|
bool changed() const;
|
||||||
|
|
||||||
/* create a property list from an XMLNode
|
/* create a property list from an XMLNode
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ public:
|
||||||
|
|
||||||
XMLNode& get_state ();
|
XMLNode& get_state ();
|
||||||
|
|
||||||
|
bool empty () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::weak_ptr<Stateful> _object; ///< the object in question
|
boost::weak_ptr<Stateful> _object; ///< the object in question
|
||||||
PBD::PropertyList* _changes; ///< property changes to execute this command
|
PBD::PropertyList* _changes; ///< property changes to execute this command
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,7 @@ Stateful::property_factory (const XMLNode& history_node) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Stateful::rdiff (vector<StatefulDiffCommand*>& cmds) const
|
Stateful::rdiff (vector<Command*>& cmds) const
|
||||||
{
|
{
|
||||||
for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
|
for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
|
||||||
i->second->rdiff (cmds);
|
i->second->rdiff (cmds);
|
||||||
|
|
|
||||||
|
|
@ -118,3 +118,9 @@ StatefulDiffCommand::get_state ()
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StatefulDiffCommand::empty () const
|
||||||
|
{
|
||||||
|
return _changes->empty();
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue