new RegionCommand object; remove unused string argument from Region::thaw(); add map<ID,Region> in RegionFactory so that we can look up regions by ID

git-svn-id: svn://localhost/ardour2/branches/3.0@6652 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-02-08 19:39:17 +00:00
parent 1afb1cfea4
commit e2baff4f7d
15 changed files with 490 additions and 9 deletions

View File

@ -162,7 +162,7 @@ class Region
void recompute_position_from_lock_style ();
void freeze ();
void thaw (const std::string& why);
void thaw ();
bool covers (nframes_t frame) const {
return first_frame() <= frame && frame <= last_frame();

View File

@ -0,0 +1,104 @@
#ifndef __libardour_region_command_h__
#define __libardour_region_command_h__
#include <sstream>
#include <string>
#include <vector>
#include "pbd/command.h"
namespace ARDOUR {
class Region;
class RegionCommand : public Command {
public:
enum Property {
Name,
PositionLockStyle,
Length,
Start,
Position,
PositionOnTop,
Layer,
SyncPosition,
Hidden,
Muted,
Opaque,
Locked,
PositionLocked,
/* audio */
ScaleAmplitude,
FadeInActive,
FadeInShape,
FadeInLength,
FadeIn,
FadeOutActive,
FadeOutShape,
FadeOutLength,
FadeOut,
EnvelopActive,
DefaultEnvelope
};
RegionCommand (boost::shared_ptr<Region>);
RegionCommand (boost::shared_ptr<Region>, const XMLNode&);
RegionCommand (boost::shared_ptr<Region>, Property, const std::string& target_value);
/* this is mildly type-unsafe, in that we could pass in the wrong types for before&after
given the value of `property'. however, its just as safe as a variant that accepts
strings, and makes this whole class much easier to use.
*/
template<typename T> void add_property_change (Property property, const T& before, const T& after) {
std::stringstream sb, sa;
/* in case T is a floating point value ...
*/
sb.precision (15);
sa.precision (15);
/* format */
sb << before;
sa << after;
/* and stash it away */
_add_property_change (property, sb.str(), sa.str());
}
void set_name (const std::string& str) { _name = str; }
const std::string& name() const { return _name; }
void operator() ();
void undo();
void redo() { (*this)(); }
XMLNode &get_state();
int set_state (const XMLNode&, int /*version*/);
private:
struct PropertyTriple {
Property property;
std::string before;
std::string after;
PropertyTriple (Property p, const std::string& b, const std::string& a)
: property (p), before (b), after (a) {}
};
boost::shared_ptr<Region> region;
typedef std::vector<PropertyTriple> PropertyTriples;
PropertyTriples property_changes;
void do_property_change (Property prop, const std::string& value);
void _add_property_change (Property, const std::string& before_value, const std::string& after_value);
};
}
#endif /* __libardour_region_command_h__ */

View File

@ -20,6 +20,10 @@
#ifndef __ardour_region_factory_h__
#define __ardour_region_factory_h__
#include <map>
#include "pbd/id.h"
#include "ardour/types.h"
#include "ardour/region.h"
@ -33,6 +37,10 @@ class AudioRegion;
class RegionFactory {
public:
static boost::shared_ptr<Region> region_by_id (const PBD::ID&);
static void clear_map ();
/** This is emitted only when a new id is assigned. Therefore,
in a pure Region copy, it will not be emitted.
@ -59,6 +67,10 @@ class RegionFactory {
static boost::shared_ptr<Region> create (const SourceList &, nframes_t start, nframes_t length, const std::string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
static boost::shared_ptr<Region> create (Session&, XMLNode&, bool);
static boost::shared_ptr<Region> create (SourceList &, const XMLNode&);
private:
static std::map<PBD::ID,boost::weak_ptr<Region> > region_map;
static void map_add (boost::shared_ptr<Region>);
};
}

View File

@ -767,7 +767,7 @@ AudioRegion::set_live_state (const XMLNode& node, int version, Change& what_chan
}
_envelope->thaw ();
thaw ("");
thaw ();
if (send) {
cerr << _name << ": audio final change: " << hex << what_changed << dec << endl;

View File

@ -33,6 +33,7 @@
#include "ardour/midi_track.h"
#include "ardour/mute_master.h"
#include "ardour/panner.h"
#include "ardour/region_command.h"
#include "ardour/route_group.h"
#include "ardour/session.h"
#include "ardour/track.h"
@ -121,6 +122,7 @@ setup_enum_writer ()
Session::PostTransportWork _Session_PostTransportWork;
Session::SlaveState _Session_SlaveState;
MTC_Status _MIDI_MTC_Status;
RegionCommand::Property _RegionCommandProperty;
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@ -583,6 +585,31 @@ setup_enum_writer ()
REGISTER_ENUM(Groove);
REGISTER(_QuantizeType);
REGISTER_CLASS_ENUM (RegionCommand, Name);
REGISTER_CLASS_ENUM (RegionCommand, PositionLockStyle);
REGISTER_CLASS_ENUM (RegionCommand, Length);
REGISTER_CLASS_ENUM (RegionCommand, Start);
REGISTER_CLASS_ENUM (RegionCommand, Position);
REGISTER_CLASS_ENUM (RegionCommand, PositionOnTop);
REGISTER_CLASS_ENUM (RegionCommand, Layer);
REGISTER_CLASS_ENUM (RegionCommand, SyncPosition);
REGISTER_CLASS_ENUM (RegionCommand, Hidden);
REGISTER_CLASS_ENUM (RegionCommand, Muted);
REGISTER_CLASS_ENUM (RegionCommand, Opaque);
REGISTER_CLASS_ENUM (RegionCommand, Locked);
REGISTER_CLASS_ENUM (RegionCommand, PositionLocked);
REGISTER_CLASS_ENUM (RegionCommand, ScaleAmplitude);
REGISTER_CLASS_ENUM (RegionCommand, FadeInActive);
REGISTER_CLASS_ENUM (RegionCommand, FadeInShape);
REGISTER_CLASS_ENUM (RegionCommand, FadeInLength);
REGISTER_CLASS_ENUM (RegionCommand, FadeIn);
REGISTER_CLASS_ENUM (RegionCommand, FadeOutActive);
REGISTER_CLASS_ENUM (RegionCommand, FadeOutShape);
REGISTER_CLASS_ENUM (RegionCommand, FadeOutLength);
REGISTER_CLASS_ENUM (RegionCommand, FadeOut);
REGISTER_CLASS_ENUM (RegionCommand, EnvelopActive);
REGISTER_CLASS_ENUM (RegionCommand, DefaultEnvelope);
REGISTER(_RegionCommandProperty);
}
} /* namespace ARDOUR */

View File

@ -44,7 +44,7 @@ ExportGraphBuilder::~ExportGraphBuilder ()
}
int
ExportGraphBuilder::process (nframes_t frames, bool last_cycle)
ExportGraphBuilder::process (nframes_t /* frames */, bool last_cycle)
{
for (ChannelMap::iterator it = channels.begin(); it != channels.end(); ++it) {
it->first->read (process_buffer, process_buffer_frames);

View File

@ -34,7 +34,7 @@ const MuteMaster::MutePoint MuteMaster::AllPoints = MutePoint (MuteMaster::PreFa
MuteMaster::Listen|
MuteMaster::Main);
MuteMaster::MuteMaster (Session& s, const std::string& name)
MuteMaster::MuteMaster (Session&, const std::string&)
: _mute_point (MutePoint (0))
{
}

View File

@ -762,7 +762,7 @@ Playlist::partition (nframes_t start, nframes_t end, bool cut)
partition_internal (start, end, cut, thawlist);
for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
(*i)->thaw ("separation");
(*i)->thaw ();
}
}
@ -1027,7 +1027,7 @@ Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
partition_internal (start, start+cnt-1, true, thawlist);
for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
(*i)->thaw ("playlist cut");
(*i)->thaw ();
}
return the_copy;
@ -1900,7 +1900,7 @@ Playlist::set_state (const XMLNode& node, int version)
region->freeze ();
if (region->set_live_state (*child, version, what_changed, false)) {
region->thaw ("");
region->thaw ();
continue;
}
@ -1915,7 +1915,7 @@ Playlist::set_state (const XMLNode& node, int version)
// So that layer_op ordering doesn't get screwed up
region->set_last_layer_op( region->layer());
region->thaw ("");
region->thaw ();
}
}

View File

@ -1324,7 +1324,7 @@ Region::freeze ()
}
void
Region::thaw (const string& /*why*/)
Region::thaw ()
{
Change what_changed = Change (0);

View File

@ -0,0 +1,274 @@
#include "pbd/convert.h"
#include "pbd/xml++.h"
#include "pbd/locale_guard.h"
#include "pbd/enumwriter.h"
#include "ardour/region.h"
#include "ardour/region_command.h"
#include "ardour/utils.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
using namespace std;
RegionCommand::RegionCommand (boost::shared_ptr<Region> r, const XMLNode& node)
: region (r)
{
if (set_state (node, 0)) {
throw failed_constructor();
}
}
RegionCommand::RegionCommand (boost::shared_ptr<Region> r)
: region (r)
{
}
RegionCommand::RegionCommand (boost::shared_ptr<Region> r, Property prop, const std::string& target_value)
: region (r)
{
LocaleGuard lg ("POSIX");
string before;
char buf[128];
/* get current value as a string */
switch (prop) {
case Name:
before = r->name();
break;
case PositionLockStyle:
before = enum_2_string (r->positional_lock_style());
break;
case Length:
snprintf (buf, sizeof (buf), "%" PRId32, r->length());
before = buf;
break;
case Start:
snprintf (buf, sizeof (buf), "%" PRId32, r->start());
before = buf;
break;
case Position:
snprintf (buf, sizeof (buf), "%" PRId32, r->position());
before = buf;
break;
case PositionOnTop:
snprintf (buf, sizeof (buf), "%" PRId32, r->position());
before = buf;
break;
case Layer:
snprintf (buf, sizeof (buf), "%" PRId32, r->layer());
before = buf;
break;
case SyncPosition:
snprintf (buf, sizeof (buf), "%" PRId32, r->sync_position());
before = buf;
break;
case Hidden:
before = (r->hidden() ? "yes" : "no");
break;
case Muted:
before = (r->muted() ? "yes" : "no");
break;
case Opaque:
before = (r->opaque() ? "yes" : "no");
break;
case Locked:
before = (r->locked() ? "yes" : "no");
break;
case PositionLocked:
before = (r->position_locked() ? "yes" : "no");
break;
/* audio */
case ScaleAmplitude:
break;
case FadeInActive:
break;
case FadeInShape:
break;
case FadeInLength:
break;
case FadeIn:
break;
case FadeOutActive:
break;
case FadeOutShape:
break;
case FadeOutLength:
break;
case FadeOut:
break;
case EnvelopActive:
break;
case DefaultEnvelope:
break;
}
add_property_change (prop, before, target_value);
}
void
RegionCommand::_add_property_change (Property prop, const std::string& before, const std::string& after)
{
property_changes.push_back (PropertyTriple (prop, before, after));
}
void
RegionCommand::operator() ()
{
region->freeze ();
for (PropertyTriples::iterator i= property_changes.begin(); i != property_changes.end(); ++i) {
do_property_change (i->property, i->after);
}
region->thaw ();
}
void
RegionCommand::undo ()
{
region->freeze ();
for (PropertyTriples::iterator i= property_changes.begin(); i != property_changes.end(); ++i) {
do_property_change (i->property, i->before);
}
region->thaw ();
}
void
RegionCommand::do_property_change (Property prop, const std::string& value)
{
Region::PositionLockStyle pls;
switch (prop) {
case Name:
region->set_name (value);
break;
case PositionLockStyle:
region->set_position_lock_style ((Region::PositionLockStyle) string_2_enum (value, pls));
break;
case Length:
region->set_length (atoll (value), this);
break;
case Start:
region->set_start (atoll (value), this);
break;
case Position:
region->set_position (atoll (value), this);
break;
case PositionOnTop:
region->set_position_on_top (atoll (value), this);
break;
case Layer:
region->set_layer (atoi (value));
break;
case SyncPosition:
region->set_sync_position (atoi (value));
break;
case Hidden:
region->set_hidden (string_is_affirmative (value));
break;
case Muted:
region->set_muted (string_is_affirmative (value));
break;
case Opaque:
region->set_opaque (string_is_affirmative (value));
break;
case Locked:
region->set_locked (string_is_affirmative (value));
break;
case PositionLocked:
region->set_position_locked (string_is_affirmative (value));
break;
/* audio */
case ScaleAmplitude:
break;
case FadeInActive:
break;
case FadeInShape:
break;
case FadeInLength:
break;
case FadeIn:
break;
case FadeOutActive:
break;
case FadeOutShape:
break;
case FadeOutLength:
break;
case FadeOut:
break;
case EnvelopActive:
break;
case DefaultEnvelope:
break;
}
}
XMLNode&
RegionCommand::get_state ()
{
XMLNode* node = new XMLNode (X_("RegionCommand"));
XMLNode* child;
node->add_property (X_("region"), region->id().to_s());
for (PropertyTriples::iterator i = property_changes.begin(); i != property_changes.end(); ++i) {
child = new XMLNode (X_("Op"));
child->add_property (X_("property"), enum_2_string (i->property));
child->add_property (X_("before"), i->before);
child->add_property (X_("after"), i->after);
node->add_child_nocopy (*child);
}
return *node;
}
int
RegionCommand::set_state (const XMLNode& node, int /* version */)
{
const XMLNodeList& children (node.children());
Property property;
string before;
string after;
const XMLProperty* prop;
for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
if ((*i)->name() != X_("Op")) {
continue;
}
if ((prop = (*i)->property (X_("property"))) == 0) {
return -1;
}
property = (Property) string_2_enum (prop->value(), property);
if ((prop = (*i)->property (X_("before"))) == 0) {
return -1;
}
before = prop->value();
if ((prop = (*i)->property (X_("after"))) == 0) {
return -1;
}
after = prop->value();
add_property_change (property, before, after);
}
return 0;
}

View File

@ -35,6 +35,7 @@ using namespace ARDOUR;
using namespace PBD;
PBD::Signal1<void,boost::shared_ptr<Region> > RegionFactory::CheckNewRegion;
map<PBD::ID,boost::weak_ptr<Region> > RegionFactory::region_map;
boost::shared_ptr<Region>
RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
@ -50,6 +51,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -59,6 +61,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
boost::shared_ptr<MidiRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -82,6 +85,7 @@ RegionFactory::create (boost::shared_ptr<const Region> region)
boost_debug_shared_ptr_mark_interesting (arn, "Region");
boost::shared_ptr<Region> ret (arn);
ret->unlock_property_changes ();
map_add (ret);
/* pure copy constructor - no CheckNewRegion emitted */
return ret;
} else if ((mr = boost::dynamic_pointer_cast<const MidiRegion>(region)) != 0) {
@ -122,6 +126,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, const SourceList& srcs,
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -141,6 +146,7 @@ RegionFactory::create (Session& session, XMLNode& node, bool yn)
if (r) {
r->unlock_property_changes ();
map_add (r);
CheckNewRegion (r);
}
@ -161,6 +167,7 @@ RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -172,6 +179,7 @@ RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length
boost::shared_ptr<MidiRegion> mrp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (mrp));
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -194,11 +202,13 @@ RegionFactory::create (SourceList& srcs, const XMLNode& node)
boost_debug_shared_ptr_mark_interesting (ar, "Region");
boost::shared_ptr<Region> ret (ar);
ret->unlock_property_changes ();
map_add (ret);
CheckNewRegion (ret);
return ret;
} else if (srcs[0]->type() == DataType::MIDI) {
boost::shared_ptr<Region> ret (new MidiRegion (srcs, node));
ret->unlock_property_changes ();
map_add (ret);
CheckNewRegion (ret);
return ret;
}
@ -217,6 +227,7 @@ RegionFactory::create (boost::shared_ptr<Source> src, nframes_t start, nframes_t
boost_debug_shared_ptr_mark_interesting (ar, "Region");
boost::shared_ptr<Region> ret (ar);
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -224,6 +235,7 @@ RegionFactory::create (boost::shared_ptr<Source> src, nframes_t start, nframes_t
} else if ((ms = boost::dynamic_pointer_cast<MidiSource>(src)) != 0) {
boost::shared_ptr<Region> ret (new MidiRegion (ms, start, length, name, layer, flags));
ret->unlock_property_changes ();
map_add (ret);
if (announce) {
CheckNewRegion (ret);
}
@ -232,3 +244,31 @@ RegionFactory::create (boost::shared_ptr<Source> src, nframes_t start, nframes_t
return boost::shared_ptr<Region>();
}
void
RegionFactory::map_add (boost::shared_ptr<Region> r)
{
pair<ID,boost::weak_ptr<Region> > p;
p.first = r->id();
p.second = r;
region_map.insert (p);
}
boost::shared_ptr<Region>
RegionFactory::region_by_id (const PBD::ID& id)
{
map<ID,boost::weak_ptr<Region> >::iterator i = region_map.find (id);
if (i == region_map.end()) {
return boost::shared_ptr<Region>();
}
return i->second.lock();
}
void
RegionFactory::clear_map ()
{
region_map.clear ();
}

View File

@ -352,6 +352,10 @@ Session::destroy ()
_engine.remove_session ();
/* clear region map. it doesn't hold references, but lets just be sensible here */
RegionFactory::clear_map ();
/* clear history so that no references to objects are held any more */
_history.clear ();

View File

@ -83,32 +83,40 @@ Session::memento_command_factory(XMLNode *n)
/* create command */
string obj_T = n->property ("type-name")->value();
if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (MidiRegion).name() || obj_T == typeid (Region).name()) {
if (regions.count(id)) {
return new MementoCommand<Region>(*regions[id], before, after);
}
} else if (obj_T == typeid (AudioSource).name() || obj_T == typeid (MidiSource).name()) {
if (sources.count(id))
return new MementoCommand<Source>(*sources[id], before, after);
} else if (obj_T == typeid (Location).name()) {
Location* loc = _locations.get_location_by_id(id);
if (loc) {
return new MementoCommand<Location>(*loc, before, after);
}
} else if (obj_T == typeid (Locations).name()) {
return new MementoCommand<Locations>(_locations, before, after);
} else if (obj_T == typeid (TempoMap).name()) {
return new MementoCommand<TempoMap>(*_tempo_map, before, after);
} else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name() || obj_T == typeid (MidiPlaylist).name()) {
if (boost::shared_ptr<Playlist> pl = playlists->by_name(child->property("name")->value())) {
return new MementoCommand<Playlist>(*(pl.get()), before, after);
}
} else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name() || obj_T == typeid(MidiTrack).name()) {
if (boost::shared_ptr<Route> r = route_by_id(id)) {
return new MementoCommand<Route>(*r, before, after);
} else {
error << string_compose (X_("Route %1 not found in session"), id) << endmsg;
}
} else if (obj_T == typeid (Evoral::Curve).name() || obj_T == typeid (AutomationList).name()) {
std::map<PBD::ID, AutomationList*>::iterator i = automation_lists.find(id);
if (i != automation_lists.end()) {

View File

@ -91,6 +91,7 @@
#include "ardour/midi_track.h"
#include "ardour/named_selection.h"
#include "ardour/processor.h"
#include "ardour/region_command.h"
#include "ardour/region_factory.h"
#include "ardour/route_group.h"
#include "ardour/send.h"
@ -2944,6 +2945,16 @@ Session::restore_history (string snapshot_name)
error << _("Failed to downcast MidiSource for DeltaCommand") << endmsg;
}
} else if (n->name() == "RegionCommand") {
PBD::ID id (n->property ("region")->value());
boost::shared_ptr<Region> region = RegionFactory::region_by_id (id);
if (region) {
ut->add_command (new RegionCommand (region, *n));
} else {
error << string_compose (_("Region command references an unknown region ID=%1"), id.to_s()) << endmsg;
}
} else {
error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
}

View File

@ -144,6 +144,7 @@ libardour_sources = [
'rc_configuration.cc',
'recent_sessions.cc',
'region.cc',
'region_command.cc',
'region_factory.cc',
'resampled_source.cc',
'return.cc',