X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fregion.cc;h=66c0b84ae9c201f66264614ab1760a6f32627e2d;hb=ecae912da9f6805d4939e657e3a591f79b0ae542;hp=da3564552a397f1e0391729a912fe8a97de1995f;hpb=4e1f451520975868659f4c00d00883f5f1cd5805;p=ardour.git diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index da3564552a..66c0b84ae9 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2003 Paul Davis + Copyright (C) 2000-2003 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,22 +23,24 @@ #include #include -#include -#include - #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include "pbd/xml++.h" +#include "pbd/stacktrace.h" +#include "pbd/enumwriter.h" + +#include "ardour/debug.h" +#include "ardour/file_source.h" +#include "ardour/filter.h" +#include "ardour/playlist.h" +#include "ardour/playlist_source.h" +#include "ardour/profile.h" +#include "ardour/region.h" +#include "ardour/region_factory.h" +#include "ardour/session.h" +#include "ardour/source.h" +#include "ardour/source_factory.h" +#include "ardour/tempo.h" +#include "ardour/utils.h" #include "i18n.h" @@ -46,403 +48,367 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -Change Region::FadeChanged = ARDOUR::new_change (); -Change Region::SyncOffsetChanged = ARDOUR::new_change (); -Change Region::MuteChanged = ARDOUR::new_change (); -Change Region::OpacityChanged = ARDOUR::new_change (); -Change Region::LockChanged = ARDOUR::new_change (); -Change Region::LayerChanged = ARDOUR::new_change (); -Change Region::HiddenChanged = ARDOUR::new_change (); +namespace ARDOUR { + namespace Properties { + PBD::PropertyDescriptor muted; + PBD::PropertyDescriptor opaque; + PBD::PropertyDescriptor locked; + PBD::PropertyDescriptor automatic; + PBD::PropertyDescriptor whole_file; + PBD::PropertyDescriptor import; + PBD::PropertyDescriptor external; + PBD::PropertyDescriptor sync_marked; + PBD::PropertyDescriptor left_of_split; + PBD::PropertyDescriptor right_of_split; + PBD::PropertyDescriptor hidden; + PBD::PropertyDescriptor position_locked; + PBD::PropertyDescriptor valid_transients; + PBD::PropertyDescriptor start; + PBD::PropertyDescriptor length; + PBD::PropertyDescriptor position; + PBD::PropertyDescriptor sync_position; + PBD::PropertyDescriptor layer; + PBD::PropertyDescriptor ancestral_start; + PBD::PropertyDescriptor ancestral_length; + PBD::PropertyDescriptor stretch; + PBD::PropertyDescriptor shift; + PBD::PropertyDescriptor position_lock_style; + PBD::PropertyDescriptor layering_index; + } +} + +PBD::Signal2,const PropertyChange&> Region::RegionPropertyChanged; + +void +Region::make_property_quarks () +{ + Properties::muted.property_id = g_quark_from_static_string (X_("muted")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id)); + Properties::opaque.property_id = g_quark_from_static_string (X_("opaque")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id)); + Properties::locked.property_id = g_quark_from_static_string (X_("locked")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id)); + Properties::automatic.property_id = g_quark_from_static_string (X_("automatic")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id)); + Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id)); + Properties::import.property_id = g_quark_from_static_string (X_("import")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id)); + Properties::external.property_id = g_quark_from_static_string (X_("external")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id)); + Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id)); + Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id)); + Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id)); + Properties::hidden.property_id = g_quark_from_static_string (X_("hidden")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id)); + Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id)); + Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id)); + Properties::start.property_id = g_quark_from_static_string (X_("start")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id)); + Properties::length.property_id = g_quark_from_static_string (X_("length")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id)); + Properties::position.property_id = g_quark_from_static_string (X_("position")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id)); + Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id)); + Properties::layer.property_id = g_quark_from_static_string (X_("layer")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id)); + Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id)); + Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id)); + Properties::stretch.property_id = g_quark_from_static_string (X_("stretch")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id)); + Properties::shift.property_id = g_quark_from_static_string (X_("shift")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id)); + Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id)); + Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id)); +} -sigc::signal > Region::RegionPropertyChanged; +void +Region::register_properties () +{ + _xml_node_name = X_("Region"); + + add_property (_muted); + add_property (_opaque); + add_property (_locked); + add_property (_automatic); + add_property (_whole_file); + add_property (_import); + add_property (_external); + add_property (_sync_marked); + add_property (_left_of_split); + add_property (_right_of_split); + add_property (_hidden); + add_property (_position_locked); + add_property (_valid_transients); + add_property (_start); + add_property (_length); + add_property (_position); + add_property (_sync_position); + add_property (_ancestral_start); + add_property (_ancestral_length); + add_property (_stretch); + add_property (_shift); + add_property (_position_lock_style); + add_property (_layering_index); +} + +#define REGION_DEFAULT_STATE(s,l) \ + _sync_marked (Properties::sync_marked, false) \ + , _left_of_split (Properties::left_of_split, false) \ + , _right_of_split (Properties::right_of_split, false) \ + , _valid_transients (Properties::valid_transients, false) \ + , _start (Properties::start, (s)) \ + , _length (Properties::length, (l)) \ + , _position (Properties::position, 0) \ + , _sync_position (Properties::sync_position, (s)) \ + , _muted (Properties::muted, false) \ + , _opaque (Properties::opaque, true) \ + , _locked (Properties::locked, false) \ + , _automatic (Properties::automatic, false) \ + , _whole_file (Properties::whole_file, false) \ + , _import (Properties::import, false) \ + , _external (Properties::external, false) \ + , _hidden (Properties::hidden, false) \ + , _position_locked (Properties::position_locked, false) \ + , _ancestral_start (Properties::ancestral_start, (s)) \ + , _ancestral_length (Properties::ancestral_length, (l)) \ + , _stretch (Properties::stretch, 1.0) \ + , _shift (Properties::shift, 1.0) \ + , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \ + , _layering_index (Properties::layering_index, 0) + +#define REGION_COPY_STATE(other) \ + _sync_marked (Properties::sync_marked, other->_sync_marked) \ + , _left_of_split (Properties::left_of_split, other->_left_of_split) \ + , _right_of_split (Properties::right_of_split, other->_right_of_split) \ + , _valid_transients (Properties::valid_transients, other->_valid_transients) \ + , _start(Properties::start, other->_start) \ + , _length(Properties::length, other->_length) \ + , _position(Properties::position, other->_position) \ + , _sync_position(Properties::sync_position, other->_sync_position) \ + , _muted (Properties::muted, other->_muted) \ + , _opaque (Properties::opaque, other->_opaque) \ + , _locked (Properties::locked, other->_locked) \ + , _automatic (Properties::automatic, other->_automatic) \ + , _whole_file (Properties::whole_file, other->_whole_file) \ + , _import (Properties::import, other->_import) \ + , _external (Properties::external, other->_external) \ + , _hidden (Properties::hidden, other->_hidden) \ + , _position_locked (Properties::position_locked, other->_position_locked) \ + , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \ + , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \ + , _stretch (Properties::stretch, other->_stretch) \ + , _shift (Properties::shift, other->_shift) \ + , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \ + , _layering_index (Properties::layering_index, other->_layering_index) /* derived-from-derived constructor (no sources in constructor) */ -Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags) +Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type) : SessionObject(s, name) , _type(type) - , _flags(flags) - , _start(start) - , _length(length) - , _position(0) - , _last_position(0) - , _positional_lock_style(AudioTime) - , _sync_position(_start) - , _layer(layer) - , _first_edit(EditChangesNothing) - , _frozen(0) - , _stretch(1.0) - , _shift(1.0) - , _read_data_count(0) - , _pending_changed(Change (0)) - , _last_layer_op(0) + , REGION_DEFAULT_STATE(start,length) + , _last_length (length) + , _last_position (0) + , _first_edit (EditChangesNothing) + , _layer (0) { - /* no sources at this point */ -} - -/** Basic Region constructor (single source) */ -Region::Region (boost::shared_ptr src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags) - : SessionObject(src->session(), name) - , _type(type) - , _flags(flags) - , _start(start) - , _length(length) - , _position(0) - , _last_position(0) - , _positional_lock_style(AudioTime) - , _sync_position(_start) - , _layer(layer) - , _first_edit(EditChangesNothing) - , _frozen(0) - , _ancestral_start (0) - , _ancestral_length (0) - , _stretch (1.0) - , _shift (1.0) - , _valid_transients(false) - , _read_data_count(0) - , _pending_changed(Change (0)) - , _last_layer_op(0) - -{ - _sources.push_back (src); - _master_sources.push_back (src); - - src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src)); + register_properties (); - assert(_sources.size() > 0); - _positional_lock_style = AudioTime; + /* no sources at this point */ } /** Basic Region constructor (many sources) */ -Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags) - : SessionObject(srcs.front()->session(), name) - , _type(type) - , _flags(flags) - , _start(start) - , _length(length) - , _position(0) - , _last_position(0) - , _positional_lock_style(AudioTime) - , _sync_position(_start) - , _layer(layer) - , _first_edit(EditChangesNothing) - , _frozen(0) - , _stretch(1.0) - , _shift(1.0) - , _read_data_count(0) - , _pending_changed(Change (0)) - , _last_layer_op(0) +Region::Region (const SourceList& srcs) + : SessionObject(srcs.front()->session(), "toBeRenamed") + , _type (srcs.front()->type()) + , REGION_DEFAULT_STATE(0,0) + , _last_length (0) + , _last_position (0) + , _first_edit (EditChangesNothing) + , _layer (0) { - - set > unique_srcs; + register_properties (); - for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) { - _sources.push_back (*i); - (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i))); - unique_srcs.insert (*i); - } + _type = srcs.front()->type(); + + use_sources (srcs); - for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) { - _master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i))); - } - } - assert(_sources.size() > 0); + assert (_type == srcs.front()->type()); } -/** Create a new Region from part of an existing one */ -Region::Region (boost::shared_ptr other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags) - : SessionObject(other->session(), name) +/** Create a new Region from an existing one */ +Region::Region (boost::shared_ptr other) + : SessionObject(other->session(), other->name()) , _type (other->data_type()) - + , REGION_COPY_STATE (other) + , _last_length (other->_last_length) + , _last_position(other->_last_position) \ + , _first_edit (EditChangesNothing) + , _layer (other->_layer) { - _start = other->_start + offset; - copy_stuff (other, offset, length, name, layer, flags); + register_properties (); - /* if the other region had a distinct sync point - set, then continue to use it as best we can. - otherwise, reset sync point back to start. - */ + /* override state that may have been incorrectly inherited from the other region + */ - if (other->flags() & SyncMarked) { - if (other->_sync_position < _start) { - _flags = Flag (_flags & ~SyncMarked); - _sync_position = _start; - } else { - _sync_position = other->_sync_position; - } - } else { - _flags = Flag (_flags & ~SyncMarked); - _sync_position = _start; - } - - if (Profile->get_sae()) { - /* reset sync point to start if its ended up - outside region bounds. - */ + _position = 0; + _locked = false; + _whole_file = false; + _hidden = false; - if (_sync_position < _start || _sync_position >= _start + _length) { - _flags = Flag (_flags & ~SyncMarked); - _sync_position = _start; - } - } -} + use_sources (other->_sources); -Region::Region (boost::shared_ptr other, nframes_t length, const string& name, layer_t layer, Flag flags) - : SessionObject(other->session(), name) - , _type (other->data_type()) -{ - /* create a new Region exactly like another but starting at 0 in its sources */ + _position_lock_style = other->_position_lock_style; + _first_edit = other->_first_edit; - _start = 0; - copy_stuff (other, 0, length, name, layer, flags); + _start = 0; // It seems strange _start is not inherited here? /* sync pos is relative to start of file. our start-in-file is now zero, so set our sync position to whatever the the difference between - _start and _sync_pos was in the other region. + _start and _sync_pos was in the other region. - result is that our new sync pos points to the same point in our source(s) + result is that our new sync pos points to the same point in our source(s) as the sync in the other region did in its source(s). since we start at zero in our source(s), it is not possible to use a sync point that is before the start. reset it to _start if that was true in the other region. */ - - if (other->flags() & SyncMarked) { + + if (other->sync_marked()) { if (other->_start < other->_sync_position) { /* sync pos was after the start point of the other region */ _sync_position = other->_sync_position - other->_start; } else { /* sync pos was before the start point of the other region. not possible here. */ - _flags = Flag (_flags & ~SyncMarked); + _sync_marked = false; _sync_position = _start; } } else { - _flags = Flag (_flags & ~SyncMarked); + _sync_marked = false; _sync_position = _start; } - + if (Profile->get_sae()) { /* reset sync point to start if its ended up outside region bounds. */ if (_sync_position < _start || _sync_position >= _start + _length) { - _flags = Flag (_flags & ~SyncMarked); + _sync_marked = false; _sync_position = _start; } } - /* reset a couple of things that copy_stuff() gets wrong in this particular case */ - - _positional_lock_style = other->_positional_lock_style; - _first_edit = other->_first_edit; + assert (_type == other->data_type()); } -/** Pure copy constructor */ -Region::Region (boost::shared_ptr other) +/** Create a new Region from part of an existing one. + + the start within \a other is given by \a offset + (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start() +*/ +Region::Region (boost::shared_ptr other, frameoffset_t offset) : SessionObject(other->session(), other->name()) - , _type(other->data_type()) - , _flags(Flag(other->_flags & ~(Locked|PositionLocked))) - , _start(other->_start) - , _length(other->_length) - , _position(other->_position) - , _last_position(other->_last_position) - , _positional_lock_style(other->_positional_lock_style) - , _sync_position(other->_sync_position) - , _layer(other->_layer) - , _first_edit(EditChangesID) - , _frozen(0) - , _ancestral_start (other->_ancestral_start) - , _ancestral_length (other->_ancestral_length) - , _stretch (other->_stretch) - , _shift (other->_shift) - , _valid_transients(false) - , _read_data_count(0) - , _pending_changed(Change(0)) - , _last_layer_op(other->_last_layer_op) + , _type (other->data_type()) + , REGION_COPY_STATE (other) + , _last_length (other->_last_length) + , _last_position(other->_last_position) \ + , _first_edit (EditChangesNothing) + , _layer (other->_layer) { - other->_first_edit = EditChangesName; + register_properties (); - if (other->_extra_xml) { - _extra_xml = new XMLNode (*other->_extra_xml); - } else { - _extra_xml = 0; - } + /* override state that may have been incorrectly inherited from the other region + */ - set > unique_srcs; + _position = 0; + _locked = false; + _whole_file = false; + _hidden = false; - for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) { - _sources.push_back (*i); - (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i))); - unique_srcs.insert (*i); + use_sources (other->_sources); + + _start = other->_start + offset; + + /* if the other region had a distinct sync point + set, then continue to use it as best we can. + otherwise, reset sync point back to start. + */ + + if (other->sync_marked()) { + if (other->_sync_position < _start) { + _sync_marked = false; + _sync_position = _start; + } else { + _sync_position = other->_sync_position; + } + } else { + _sync_marked = false; + _sync_position = _start; } - for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) { - _master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i))); + if (Profile->get_sae()) { + /* reset sync point to start if its ended up + outside region bounds. + */ + + if (_sync_position < _start || _sync_position >= _start + _length) { + _sync_marked = false; + _sync_position = _start; } } - - assert(_sources.size() > 0); + + assert (_type == other->data_type()); } -Region::Region (const SourceList& srcs, const XMLNode& node) - : SessionObject(srcs.front()->session(), X_("error: XML did not reset this")) - , _type(DataType::NIL) // to be loaded from XML - , _flags(Flag(0)) - , _start(0) - , _length(0) - , _position(0) - , _last_position(0) - , _positional_lock_style(AudioTime) - , _sync_position(_start) - , _layer(0) - , _first_edit(EditChangesNothing) - , _frozen(0) - , _stretch(1.0) - , _shift(1.0) - , _read_data_count(0) - , _pending_changed(Change(0)) - , _last_layer_op(0) +/** Create a copy of @param other but with different sources. Used by filters */ +Region::Region (boost::shared_ptr other, const SourceList& srcs) + : SessionObject (other->session(), other->name()) + , _type (srcs.front()->type()) + , REGION_COPY_STATE (other) + , _last_length (other->_last_length) + , _last_position (other->_last_position) + , _first_edit (EditChangesID) + , _layer (other->_layer) { - set > unique_srcs; + register_properties (); - for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) { - _sources.push_back (*i); - (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i))); - unique_srcs.insert (*i); - } + _locked = false; + _position_locked = false; - for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) { - _master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i))); - } - } + other->_first_edit = EditChangesName; - if (set_state (node)) { - throw failed_constructor(); + if (other->_extra_xml) { + _extra_xml = new XMLNode (*other->_extra_xml); + } else { + _extra_xml = 0; } - assert(_type != DataType::NIL); - assert(_sources.size() > 0); -} - -Region::Region (boost::shared_ptr src, const XMLNode& node) - : SessionObject(src->session(), X_("error: XML did not reset this")) - , _type(DataType::NIL) - , _flags(Flag(0)) - , _start(0) - , _length(0) - , _position(0) - , _last_position(0) - , _positional_lock_style(AudioTime) - , _sync_position(_start) - , _layer(0) - , _first_edit(EditChangesNothing) - , _frozen(0) - , _stretch(1.0) - , _shift(1.0) - , _read_data_count(0) - , _pending_changed(Change(0)) - , _last_layer_op(0) -{ - _sources.push_back (src); - - if (set_state (node)) { - throw failed_constructor(); - } - - assert(_type != DataType::NIL); + use_sources (srcs); assert(_sources.size() > 0); } Region::~Region () { - boost::shared_ptr pl (playlist()); - - if (pl) { - for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { - (*i)->remove_playlist (pl); - } - for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { - (*i)->remove_playlist (pl); - } - } - - notify_callbacks (); - GoingAway (); /* EMIT SIGNAL */ -} - -void -Region::copy_stuff (boost::shared_ptr other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags) -{ - _frozen = 0; - _pending_changed = Change (0); - _read_data_count = 0; - _valid_transients = false; - - _length = length; - _last_length = length; - _sync_position = other->_sync_position; - _ancestral_start = other->_ancestral_start; - _ancestral_length = other->_ancestral_length; - _stretch = other->_stretch; - _shift = other->_shift; - _name = name; - _last_position = 0; - _position = 0; - _layer = layer; - _flags = Flag (flags & ~(Locked|WholeFile|Hidden)); - _first_edit = EditChangesNothing; - _last_layer_op = 0; - _positional_lock_style = AudioTime; + DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this)); + drop_sources (); } void Region::set_playlist (boost::weak_ptr wpl) { - boost::shared_ptr old_playlist = (_playlist.lock()); - - boost::shared_ptr pl (wpl.lock()); - - if (old_playlist == pl) { - return; - } - - _playlist = pl; - - if (pl) { - if (old_playlist) { - for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { - (*i)->remove_playlist (_playlist); - (*i)->add_playlist (pl); - } - for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { - (*i)->remove_playlist (_playlist); - (*i)->add_playlist (pl); - } - } else { - for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { - (*i)->add_playlist (pl); - } - for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { - (*i)->add_playlist (pl); - } - } - } else { - if (old_playlist) { - for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { - (*i)->remove_playlist (old_playlist); - } - for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { - (*i)->remove_playlist (old_playlist); - } - } - } + _playlist = wpl.lock(); } bool @@ -450,56 +416,62 @@ Region::set_name (const std::string& str) { if (_name != str) { SessionObject::set_name(str); // EMIT SIGNAL NameChanged() - assert(_name == str); - send_change (ARDOUR::NameChanged); + assert(_name == str); + + send_change (Properties::name); } return true; } void -Region::set_length (nframes_t len, void *src) +Region::set_length (framecnt_t len) { //cerr << "Region::set_length() len = " << len << endl; - if (_flags & Locked) { + if (locked()) { return; } if (_length != len && len != 0) { - /* check that the current _position wouldn't make the new + /* check that the current _position wouldn't make the new length impossible. */ - if (max_frames - len < _position) { + if (max_framepos - len < _position) { return; } if (!verify_length (len)) { return; } - - _last_length = _length; - _length = len; - - _flags = Region::Flag (_flags & ~WholeFile); + _last_length = _length; + set_length_internal (len); + _whole_file = false; first_edit (); maybe_uncopy (); invalidate_transients (); - if (!_frozen) { + if (!property_changes_suspended()) { recompute_at_end (); } - send_change (LengthChanged); + send_change (Properties::length); } } +void +Region::set_length_internal (framecnt_t len) +{ + _length = len; +} + void Region::maybe_uncopy () { + /* this does nothing but marked a semantic moment once upon a time */ } void @@ -509,10 +481,11 @@ Region::first_edit () if (_first_edit != EditChangesNothing && pl) { - _name = pl->session().new_region_name (_name); + _name = RegionFactory::new_region_name (_name); _first_edit = EditChangesNothing; - send_change (ARDOUR::NameChanged); + send_change (Properties::name); + RegionFactory::CheckNewRegion (shared_from_this()); } } @@ -525,7 +498,7 @@ Region::at_natural_position () const if (!pl) { return false; } - + boost::shared_ptr whole_file_region = get_parent(); if (whole_file_region) { @@ -538,25 +511,25 @@ Region::at_natural_position () const } void -Region::move_to_natural_position (void *src) +Region::move_to_natural_position () { boost::shared_ptr pl (playlist()); if (!pl) { return; } - + boost::shared_ptr whole_file_region = get_parent(); if (whole_file_region) { - set_position (whole_file_region->position() + _start, src); + set_position (whole_file_region->position() + _start); } } - + void -Region::special_set_position (nframes_t pos) +Region::special_set_position (framepos_t pos) { - /* this is used when creating a whole file region as + /* this is used when creating a whole file region as a way to store its "natural" or "captured" position. */ @@ -567,144 +540,128 @@ Region::special_set_position (nframes_t pos) void Region::set_position_lock_style (PositionLockStyle ps) { - boost::shared_ptr pl (playlist()); + if (_position_lock_style != ps) { - if (!pl) { - return; - } + boost::shared_ptr pl (playlist()); + + _position_lock_style = ps; - _positional_lock_style = ps; + if (_position_lock_style == MusicTime) { + _session.bbt_time (_position, _bbt_time); + } - if (_positional_lock_style == MusicTime) { - pl->session().tempo_map().bbt_time (_position, _bbt_time); + send_change (Properties::position_lock_style); } - } void -Region::update_position_after_tempo_map_change () +Region::update_after_tempo_map_change () { boost::shared_ptr pl (playlist()); - - if (!pl || _positional_lock_style != MusicTime) { + + if (!pl || _position_lock_style != MusicTime) { return; } - TempoMap& map (pl->session().tempo_map()); - nframes_t pos = map.frame_time (_bbt_time); + TempoMap& map (_session.tempo_map()); + framepos_t pos = map.frame_time (_bbt_time); set_position_internal (pos, false); + + /* do this even if the position is the same. this helps out + a GUI that has moved its representation already. + */ + send_change (Properties::position); } void -Region::set_position (nframes_t pos, void *src) +Region::set_position (framepos_t pos) { if (!can_move()) { return; } set_position_internal (pos, true); + + /* do this even if the position is the same. this helps out + a GUI that has moved its representation already. + */ + send_change (Properties::position); + } void -Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute) +Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) { + /* We emit a change of Properties::position even if the position hasn't changed + (see Region::set_position), so we must always set this up so that + e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position. + */ + _last_position = _position; + if (_position != pos) { - _last_position = _position; _position = pos; /* check that the new _position wouldn't make the current - length impossible - if so, change the length. + length impossible - if so, change the length. XXX is this the right thing to do? */ - if (max_frames - _length < _position) { + if (max_framepos - _length < _position) { _last_length = _length; - _length = max_frames - _position; + _length = max_framepos - _position; } if (allow_bbt_recompute) { recompute_position_from_lock_style (); } - invalidate_transients (); + //invalidate_transients (); } - - /* do this even if the position is the same. this helps out - a GUI that has moved its representation already. - */ - - send_change (PositionChanged); -} - -void -Region::set_position_on_top (nframes_t pos, void *src) -{ - if (_flags & Locked) { - return; - } - - if (_position != pos) { - _last_position = _position; - _position = pos; - } - - boost::shared_ptr pl (playlist()); - - if (pl) { - pl->raise_region_to_top (shared_from_this ()); - } - - /* do this even if the position is the same. this helps out - a GUI that has moved its representation already. - */ - - send_change (PositionChanged); } void Region::recompute_position_from_lock_style () { - if (_positional_lock_style == MusicTime) { - boost::shared_ptr pl (playlist()); - if (pl) { - pl->session().tempo_map().bbt_time (_position, _bbt_time); - } + if (_position_lock_style == MusicTime) { + _session.bbt_time (_position, _bbt_time); } } - + void -Region::nudge_position (nframes64_t n, void *src) +Region::nudge_position (frameoffset_t n) { - if (_flags & Locked) { + if (locked()) { return; } if (n == 0) { return; } - - _last_position = _position; + + framepos_t new_position = _position; if (n > 0) { - if (_position > max_frames - n) { - _position = max_frames; + if (_position > max_framepos - n) { + new_position = max_framepos; } else { - _position += n; + new_position += n; } } else { - if (_position < (nframes_t) -n) { - _position = 0; + if (_position < -n) { + new_position = 0; } else { - _position += n; + new_position += n; } } - send_change (PositionChanged); + set_position_internal (new_position, true); + + send_change (Properties::position); } void -Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh) +Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh) { _ancestral_length = l; _ancestral_start = s; @@ -713,9 +670,9 @@ Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh) } void -Region::set_start (nframes_t pos, void *src) +Region::set_start (framepos_t pos) { - if (_flags & (Locked|PositionLocked)) { + if (locked() || position_locked()) { return; } /* This just sets the start, nothing else. It effectively shifts @@ -730,33 +687,27 @@ Region::set_start (nframes_t pos, void *src) } _start = pos; - _flags = Region::Flag (_flags & ~WholeFile); + _whole_file = false; first_edit (); invalidate_transients (); - send_change (StartChanged); + send_change (Properties::start); } } void -Region::trim_start (nframes_t new_position, void *src) +Region::trim_start (framepos_t new_position) { - if (_flags & (Locked|PositionLocked)) { + if (locked() || position_locked()) { return; } - nframes_t new_start; - int32_t start_shift; - - if (new_position > _position) { - start_shift = new_position - _position; - } else { - start_shift = -(_position - new_position); - } + framepos_t new_start; + frameoffset_t const start_shift = new_position - _position; if (start_shift > 0) { - if (_start > max_frames - start_shift) { - new_start = max_frames; + if (_start > max_framepos - start_shift) { + new_start = max_framepos; } else { new_start = _start + start_shift; } @@ -767,11 +718,12 @@ Region::trim_start (nframes_t new_position, void *src) } else if (start_shift < 0) { - if (_start < (nframes_t) -start_shift) { + if (_start < -start_shift) { new_start = 0; } else { new_start = _start + start_shift; } + } else { return; } @@ -779,23 +731,41 @@ Region::trim_start (nframes_t new_position, void *src) if (new_start == _start) { return; } - + _start = new_start; - _flags = Region::Flag (_flags & ~WholeFile); + _whole_file = false; first_edit (); - send_change (StartChanged); + send_change (Properties::start); +} + +void +Region::trim_front (framepos_t new_position) +{ + modify_front (new_position, false); +} + +void +Region::cut_front (framepos_t new_position) +{ + modify_front (new_position, true); +} + +void +Region::cut_end (framepos_t new_endpoint) +{ + modify_end (new_endpoint, true); } void -Region::trim_front (nframes_t new_position, void *src) +Region::modify_front (framepos_t new_position, bool reset_fade) { - if (_flags & Locked) { + if (locked()) { return; } - nframes_t end = last_frame(); - nframes_t source_zero; + framepos_t end = last_frame(); + framepos_t source_zero; if (_position > _start) { source_zero = _position - _start; @@ -804,89 +774,109 @@ Region::trim_front (nframes_t new_position, void *src) } if (new_position < end) { /* can't trim it zero or negative length */ - - nframes_t newlen; - - /* can't trim it back passed where source position zero is located */ - - new_position = max (new_position, source_zero); - - + + framecnt_t newlen = 0; + framepos_t delta = 0; + + if (!can_trim_start_before_source_start ()) { + /* can't trim it back past where source position zero is located */ + new_position = max (new_position, source_zero); + } + if (new_position > _position) { newlen = _length - (new_position - _position); + delta = -1 * (new_position - _position); } else { newlen = _length + (_position - new_position); + delta = _position - new_position; + } + + trim_to_internal (new_position, newlen); + + if (reset_fade) { + _right_of_split = true; } - - trim_to_internal (new_position, newlen, src); - if (!_frozen) { + + if (!property_changes_suspended()) { recompute_at_start (); } + + if (_transients.size() > 0){ + adjust_transients(delta); + } } } void -Region::trim_end (nframes_t new_endpoint, void *src) +Region::modify_end (framepos_t new_endpoint, bool reset_fade) { - if (_flags & Locked) { + if (locked()) { return; } if (new_endpoint > _position) { - trim_to_internal (_position, new_endpoint - _position, this); - if (!_frozen) { + trim_to_internal (_position, new_endpoint - _position); + if (reset_fade) { + _left_of_split = true; + } + if (!property_changes_suspended()) { recompute_at_end (); } } } +/** @param new_endpoint New region end point, such that, for example, + * a region at 0 of length 10 has an endpoint of 9. + */ + void -Region::trim_to (nframes_t position, nframes_t length, void *src) +Region::trim_end (framepos_t new_endpoint) { - if (_flags & Locked) { + modify_end (new_endpoint, false); +} + +void +Region::trim_to (framepos_t position, framecnt_t length) +{ + if (locked()) { return; } - trim_to_internal (position, length, src); + trim_to_internal (position, length); - if (!_frozen) { + if (!property_changes_suspended()) { recompute_at_start (); recompute_at_end (); } } void -Region::trim_to_internal (nframes_t position, nframes_t length, void *src) +Region::trim_to_internal (framepos_t position, framecnt_t length) { - int32_t start_shift; - nframes_t new_start; + framepos_t new_start; - if (_flags & Locked) { + if (locked()) { return; } - if (position > _position) { - start_shift = position - _position; - } else { - start_shift = -(_position - position); - } + frameoffset_t const start_shift = position - _position; if (start_shift > 0) { - if (_start > max_frames - start_shift) { - new_start = max_frames; + if (_start > max_framepos - start_shift) { + new_start = max_framepos; } else { new_start = _start + start_shift; } - } else if (start_shift < 0) { - if (_start < (nframes_t) -start_shift) { + if (_start < -start_shift && !can_trim_start_before_source_start ()) { new_start = 0; } else { new_start = _start + start_shift; } + } else { new_start = _start; } @@ -895,65 +885,82 @@ Region::trim_to_internal (nframes_t position, nframes_t length, void *src) return; } - Change what_changed = Change (0); + PropertyChange what_changed; if (_start != new_start) { _start = new_start; - what_changed = Change (what_changed|StartChanged); - } - if (_length != length) { - if (!_frozen) { - _last_length = _length; - } - _length = length; - what_changed = Change (what_changed|LengthChanged); + what_changed.add (Properties::start); } + + /* Set position before length, otherwise for MIDI regions this bad thing happens: + * 1. we call set_length_internal; length in beats is computed using the region's current + * (soon-to-be old) position + * 2. we call set_position_internal; position is set and length in frames re-computed using + * length in beats from (1) but at the new position, which is wrong if the region + * straddles a tempo/meter change. + */ + if (_position != position) { - if (!_frozen) { + if (!property_changes_suspended()) { _last_position = _position; } - _position = position; - what_changed = Change (what_changed|PositionChanged); + set_position_internal (position, true); + what_changed.add (Properties::position); } - - _flags = Region::Flag (_flags & ~WholeFile); - if (what_changed & (StartChanged|LengthChanged)) { + if (_length != length) { + if (!property_changes_suspended()) { + _last_length = _length; + } + set_length_internal (length); + what_changed.add (Properties::length); + } + + _whole_file = false; + + PropertyChange start_and_length; + + start_and_length.add (Properties::start); + start_and_length.add (Properties::length); + + if (what_changed.contains (start_and_length)) { first_edit (); - } + } - if (what_changed) { + if (!what_changed.empty()) { send_change (what_changed); } -} +} void Region::set_hidden (bool yn) { if (hidden() != yn) { + _hidden = yn; + send_change (Properties::hidden); + } +} - if (yn) { - _flags = Flag (_flags|Hidden); - } else { - _flags = Flag (_flags & ~Hidden); - } +void +Region::set_whole_file (bool yn) +{ + _whole_file = yn; + /* no change signal */ +} - send_change (HiddenChanged); - } +void +Region::set_automatic (bool yn) +{ + _automatic = yn; + /* no change signal */ } void Region::set_muted (bool yn) { if (muted() != yn) { - - if (yn) { - _flags = Flag (_flags|Muted); - } else { - _flags = Flag (_flags & ~Muted); - } - - send_change (MuteChanged); + _muted = yn; + send_change (Properties::muted); } } @@ -961,12 +968,8 @@ void Region::set_opaque (bool yn) { if (opaque() != yn) { - if (yn) { - _flags = Flag (_flags|Opaque); - } else { - _flags = Flag (_flags & ~Opaque); - } - send_change (OpacityChanged); + _opaque = yn; + send_change (Properties::opaque); } } @@ -974,12 +977,8 @@ void Region::set_locked (bool yn) { if (locked() != yn) { - if (yn) { - _flags = Flag (_flags|Locked); - } else { - _flags = Flag (_flags & ~Locked); - } - send_change (LockChanged); + _locked = yn; + send_change (Properties::locked); } } @@ -987,56 +986,52 @@ void Region::set_position_locked (bool yn) { if (position_locked() != yn) { - if (yn) { - _flags = Flag (_flags|PositionLocked); - } else { - _flags = Flag (_flags & ~PositionLocked); - } - send_change (LockChanged); + _position_locked = yn; + send_change (Properties::locked); } } +/** Set the region's sync point. + * @param absolute_pos Session time. + */ void -Region::set_sync_position (nframes_t absolute_pos) +Region::set_sync_position (framepos_t absolute_pos) { - nframes_t file_pos; - - file_pos = _start + (absolute_pos - _position); + /* position within our file */ + framepos_t const file_pos = _start + (absolute_pos - _position); if (file_pos != _sync_position) { - + _sync_marked = true; _sync_position = file_pos; - _flags = Flag (_flags|SyncMarked); - - if (!_frozen) { + if (!property_changes_suspended()) { maybe_uncopy (); } - send_change (SyncOffsetChanged); + + send_change (Properties::sync_position); } } void Region::clear_sync_position () { - if (_flags & SyncMarked) { - _flags = Flag (_flags & ~SyncMarked); - - if (!_frozen) { + if (sync_marked()) { + _sync_marked = false; + if (!property_changes_suspended()) { maybe_uncopy (); } - send_change (SyncOffsetChanged); + + send_change (Properties::sync_position); } } -nframes_t +/* @return the sync point relative the first frame of the region */ +frameoffset_t Region::sync_offset (int& dir) const { - /* returns the sync point relative the first frame of the region */ - - if (_flags & SyncMarked) { + if (sync_marked()) { if (_sync_position > _start) { dir = 1; - return _sync_position - _start; + return _sync_position - _start; } else { dir = -1; return _start - _sync_position; @@ -1047,14 +1042,14 @@ Region::sync_offset (int& dir) const } } -nframes_t -Region::adjust_to_sync (nframes_t pos) const +framepos_t +Region::adjust_to_sync (framepos_t pos) const { int sync_dir; - nframes_t offset = sync_offset (sync_dir); + frameoffset_t offset = sync_offset (sync_dir); // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl; - + if (sync_dir > 0) { if (pos > offset) { pos -= offset; @@ -1062,7 +1057,7 @@ Region::adjust_to_sync (nframes_t pos) const pos = 0; } } else { - if (max_frames - pos > offset) { + if (max_framepos - pos > offset) { pos += offset; } } @@ -1070,13 +1065,15 @@ Region::adjust_to_sync (nframes_t pos) const return pos; } -nframes_t +/** @return Sync position in session time */ +framepos_t Region::sync_position() const { - if (_flags & SyncMarked) { - return _sync_position; + if (sync_marked()) { + return _position - _start + _sync_position; } else { - return _start; + /* if sync has not been marked, use the start of the region */ + return _position; } } @@ -1120,39 +1117,24 @@ Region::lower_to_bottom () void Region::set_layer (layer_t l) { - if (_layer != l) { - _layer = l; - - send_change (LayerChanged); - } + _layer = l; } XMLNode& -Region::state (bool full_state) +Region::state () { XMLNode *node = new XMLNode ("Region"); char buf[64]; + char buf2[64]; + LocaleGuard lg (X_("POSIX")); const char* fe = NULL; - _id.print (buf, sizeof (buf)); + add_properties (*node); + + id().print (buf, sizeof (buf)); node->add_property ("id", buf); - node->add_property ("name", _name); node->add_property ("type", _type.to_string()); - snprintf (buf, sizeof (buf), "%u", _start); - node->add_property ("start", buf); - snprintf (buf, sizeof (buf), "%u", _length); - node->add_property ("length", buf); - snprintf (buf, sizeof (buf), "%u", _position); - node->add_property ("position", buf); - snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start); - node->add_property ("ancestral-start", buf); - snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length); - node->add_property ("ancestral-length", buf); - snprintf (buf, sizeof (buf), "%.12g", _stretch); - node->add_property ("stretch", buf); - snprintf (buf, sizeof (buf), "%.12g", _shift); - node->add_property ("shift", buf); - + switch (_first_edit) { case EditChangesNothing: fe = X_("nothing"); @@ -1172,289 +1154,158 @@ Region::state (bool full_state) /* note: flags are stored by derived classes */ - snprintf (buf, sizeof (buf), "%d", (int) _layer); - node->add_property ("layer", buf); - snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position); - node->add_property ("sync-position", buf); - - if (_positional_lock_style != AudioTime) { - node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style)); + if (_position_lock_style != AudioTime) { stringstream str; str << _bbt_time; node->add_property ("bbt-position", str.str()); } - return *node; -} - -XMLNode& -Region::get_state () -{ - return state (true); -} + for (uint32_t n=0; n < _sources.size(); ++n) { + snprintf (buf2, sizeof(buf2), "source-%d", n); + _sources[n]->id().print (buf, sizeof(buf)); + node->add_property (buf2, buf); + } -int -Region::set_live_state (const XMLNode& node, Change& what_changed, bool send) -{ - const XMLNodeList& nlist = node.children(); - const XMLProperty *prop; - nframes_t val; + for (uint32_t n=0; n < _master_sources.size(); ++n) { + snprintf (buf2, sizeof(buf2), "master-source-%d", n); + _master_sources[n]->id().print (buf, sizeof (buf)); + node->add_property (buf2, buf); + } - /* this is responsible for setting those aspects of Region state - that are mutable after construction. + /* Only store nested sources for the whole-file region that acts + as the parent/root of all regions using it. */ - if ((prop = node.property ("name")) == 0) { - error << _("XMLNode describing a Region is incomplete (no name)") << endmsg; - return -1; - } + if (_whole_file && max_source_level() > 0) { - _name = prop->value(); - - if ((prop = node.property ("type")) == 0) { - _type = DataType::AUDIO; - } else { - _type = DataType(prop->value()); - } + XMLNode* nested_node = new XMLNode (X_("NestedSource")); - if ((prop = node.property ("start")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu32, &val); - if (val != _start) { - what_changed = Change (what_changed|StartChanged); - _start = val; - } - } else { - _start = 0; - } + /* region is compound - get its playlist and + store that before we list the region that + needs it ... + */ - if ((prop = node.property ("length")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu32, &val); - if (val != _length) { - what_changed = Change (what_changed|LengthChanged); - _last_length = _length; - _length = val; + for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) { + nested_node->add_child_nocopy ((*s)->get_state ()); } - } else { - _last_length = _length; - _length = 1; - } - if ((prop = node.property ("position")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu32, &val); - if (val != _position) { - what_changed = Change (what_changed|PositionChanged); - _last_position = _position; - _position = val; + if (nested_node) { + node->add_child_nocopy (*nested_node); } - } else { - _last_position = _position; - _position = 0; } - if ((prop = node.property ("layer")) != 0) { - layer_t x; - x = (layer_t) atoi (prop->value().c_str()); - if (x != _layer) { - what_changed = Change (what_changed|LayerChanged); - _layer = x; - } - } else { - _layer = 0; + if (_extra_xml) { + node->add_child_copy (*_extra_xml); } - if ((prop = node.property ("sync-position")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu32, &val); - if (val != _sync_position) { - what_changed = Change (what_changed|SyncOffsetChanged); - _sync_position = val; - } - } else { - _sync_position = _start; - } - - if ((prop = node.property ("positional-lock-style")) != 0) { - _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style)); - - if (_positional_lock_style == MusicTime) { - if ((prop = node.property ("bbt-position")) == 0) { - /* missing BBT info, revert to audio time locking */ - _positional_lock_style = AudioTime; - } else { - if (sscanf (prop->value().c_str(), "%d|%d|%d", - &_bbt_time.bars, - &_bbt_time.beats, - &_bbt_time.ticks) != 3) { - _positional_lock_style = AudioTime; - } - } - } - - } else { - _positional_lock_style = AudioTime; - } + return *node; +} - /* XXX FIRST EDIT !!! */ - - /* these 3 properties never change as a result of any editing */ +XMLNode& +Region::get_state () +{ + return state (); +} - if ((prop = node.property ("ancestral-start")) != 0) { - _ancestral_start = atoi (prop->value()); - } else { - _ancestral_start = _start; - } +int +Region::set_state (const XMLNode& node, int version) +{ + PropertyChange what_changed; + return _set_state (node, version, what_changed, true); +} - if ((prop = node.property ("ancestral-length")) != 0) { - _ancestral_length = atoi (prop->value()); - } else { - _ancestral_length = _length; - } +int +Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send) +{ + const XMLProperty* prop; - if ((prop = node.property ("stretch")) != 0) { - _stretch = atof (prop->value()); + Stateful::save_extra_xml (node); - /* fix problem with old sessions corrupted by an impossible - value for _stretch - */ - if (_stretch == 0.0) { - _stretch = 1.0; - } - } else { - _stretch = 1.0; - } + what_changed = set_values (node); - if ((prop = node.property ("shift")) != 0) { - _shift = atof (prop->value()); + set_id (node); - /* fix problem with old sessions corrupted by an impossible - value for _shift - */ - if (_shift == 0.0) { - _shift = 1.0; + if (_position_lock_style == MusicTime) { + if ((prop = node.property ("bbt-position")) == 0) { + /* missing BBT info, revert to audio time locking */ + _position_lock_style = AudioTime; + } else { + if (sscanf (prop->value().c_str(), "%d|%d|%d", + &_bbt_time.bars, + &_bbt_time.beats, + &_bbt_time.ticks) != 3) { + _position_lock_style = AudioTime; + } } - } else { - _shift = 1.0; } + /* fix problems with old sessions corrupted by impossible + values for _stretch or _shift + */ + if (_stretch == 0.0f) { + _stretch = 1.0f; + } - /* note: derived classes set flags */ - - delete _extra_xml; - _extra_xml = 0; - - for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { - - XMLNode *child; - - child = (*niter); - - if (child->name () == "extra") { - _extra_xml = new XMLNode (*child); - break; - } + if (_shift == 0.0f) { + _shift = 1.0f; } if (send) { send_change (what_changed); } - return 0; -} - -int -Region::set_state (const XMLNode& node) -{ - const XMLProperty *prop; - Change what_changed = Change (0); - - /* ID is not allowed to change, ever */ - - if ((prop = node.property ("id")) == 0) { - error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg; - return -1; + /* Quick fix for 2.x sessions when region is muted */ + if ((prop = node.property (X_("flags")))) { + if (string::npos != prop->value().find("Muted")){ + set_muted (true); + } } - _id = prop->value(); - - _first_edit = EditChangesNothing; - - set_live_state (node, what_changed, true); return 0; } void -Region::freeze () +Region::suspend_property_changes () { - _frozen++; + Stateful::suspend_property_changes (); _last_length = _length; _last_position = _position; } void -Region::thaw (const string& why) +Region::mid_thaw (const PropertyChange& what_changed) { - Change what_changed = Change (0); - - { - Glib::Mutex::Lock lm (_lock); - - if (_frozen && --_frozen > 0) { - return; - } - - if (_pending_changed) { - what_changed = _pending_changed; - _pending_changed = Change (0); - } - } - - if (what_changed == Change (0)) { - return; - } - - if (what_changed & LengthChanged) { - if (what_changed & PositionChanged) { + if (what_changed.contains (Properties::length)) { + if (what_changed.contains (Properties::position)) { recompute_at_start (); - } + } recompute_at_end (); } - - StateChanged (what_changed); } void -Region::send_change (Change what_changed) +Region::send_change (const PropertyChange& what_changed) { - { - Glib::Mutex::Lock lm (_lock); - if (_frozen) { - _pending_changed = Change (_pending_changed|what_changed); - return; - } + if (what_changed.empty()) { + return; } - StateChanged (what_changed); - - if (!(_flags & DoNotSaveState)) { - + Stateful::send_change (what_changed); + + if (!Stateful::property_changes_suspended()) { + /* Try and send a shared_pointer unless this is part of the constructor. If so, do nothing. */ - + try { boost::shared_ptr rptr = shared_from_this(); - RegionPropertyChanged (rptr); + RegionPropertyChanged (rptr, what_changed); } catch (...) { /* no shared_ptr available, relax; */ } } - -} - -void -Region::set_last_layer_op (uint64_t when) -{ - _last_layer_op = when; } bool @@ -1485,10 +1336,21 @@ Region::region_list_equivalent (boost::shared_ptr other) const } void -Region::source_deleted (boost::shared_ptr) +Region::source_deleted (boost::weak_ptr) { - _sources.clear (); - drop_references (); + drop_sources (); + + if (!_session.deletion_in_progress()) { + /* this is a very special case: at least one of the region's + sources has bee deleted, so invalidate all references to + ourselves. Do NOT do this during session deletion, because + then we run the risk that this will actually result + in this object being deleted (as refcnt goes to zero) + while emitting DropReferences. + */ + + drop_references (); + } } vector @@ -1507,7 +1369,16 @@ Region::master_source_names () void Region::set_master_sources (const SourceList& srcs) { + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->dec_use_count (); + } + _master_sources = srcs; + assert (_sources.size() == _master_sources.size()); + + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->inc_use_count (); + } } bool @@ -1516,6 +1387,11 @@ Region::source_equivalent (boost::shared_ptr other) const if (!other) return false; + if ((_sources.size() != other->_sources.size()) || + (_master_sources.size() != other->_master_sources.size())) { + return false; + } + SourceList::const_iterator i; SourceList::const_iterator io; @@ -1534,35 +1410,83 @@ Region::source_equivalent (boost::shared_ptr other) const return true; } +std::string +Region::source_string () const +{ + //string res = itos(_sources.size()); + + stringstream res; + res << _sources.size() << ":"; + + SourceList::const_iterator i; + + for (i = _sources.begin(); i != _sources.end(); ++i) { + res << (*i)->id() << ":"; + } + + for (i = _master_sources.begin(); i != _master_sources.end(); ++i) { + res << (*i)->id() << ":"; + } + + return res.str(); +} + bool -Region::verify_length (nframes_t len) +Region::uses_source (boost::shared_ptr source) const +{ + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + if (*i == source) { + return true; + } + + boost::shared_ptr ps = boost::dynamic_pointer_cast (*i); + + if (ps) { + if (ps->playlist()->uses_source (source)) { + return true; + } + } + } + + return false; +} + +framecnt_t +Region::source_length(uint32_t n) const +{ + assert (n < _sources.size()); + return _sources[n]->length (_position - _start); +} + +bool +Region::verify_length (framecnt_t len) { if (source() && (source()->destructive() || source()->length_mutable())) { return true; } - nframes_t maxlen = 0; + framecnt_t maxlen = 0; - for (uint32_t n=0; n < _sources.size(); ++n) { - maxlen = max (maxlen, _sources[n]->length() - _start); + for (uint32_t n = 0; n < _sources.size(); ++n) { + maxlen = max (maxlen, source_length(n) - _start); } - + len = min (len, maxlen); - + return true; } bool -Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length) +Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length) { if (source() && (source()->destructive() || source()->length_mutable())) { return true; } - nframes_t maxlen = 0; + framecnt_t maxlen = 0; - for (uint32_t n=0; n < _sources.size(); ++n) { - maxlen = max (maxlen, _sources[n]->length() - new_start); + for (uint32_t n = 0; n < _sources.size(); ++n) { + maxlen = max (maxlen, source_length(n) - new_start); } new_length = min (new_length, maxlen); @@ -1571,14 +1495,14 @@ Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length) } bool -Region::verify_start (nframes_t pos) +Region::verify_start (framepos_t pos) { if (source() && (source()->destructive() || source()->length_mutable())) { return true; } - for (uint32_t n=0; n < _sources.size(); ++n) { - if (pos > _sources[n]->length() - _length) { + for (uint32_t n = 0; n < _sources.size(); ++n) { + if (pos > source_length(n) - _length) { return false; } } @@ -1586,15 +1510,15 @@ Region::verify_start (nframes_t pos) } bool -Region::verify_start_mutable (nframes_t& new_start) +Region::verify_start_mutable (framepos_t& new_start) { if (source() && (source()->destructive() || source()->length_mutable())) { return true; } - for (uint32_t n=0; n < _sources.size(); ++n) { - if (new_start > _sources[n]->length() - _length) { - new_start = _sources[n]->length() - _length; + for (uint32_t n = 0; n < _sources.size(); ++n) { + if (new_start > source_length(n) - _length) { + new_start = source_length(n) - _length; } } return true; @@ -1608,19 +1532,19 @@ Region::get_parent() const if (pl) { boost::shared_ptr r; boost::shared_ptr grrr2 = boost::dynamic_pointer_cast (shared_from_this()); - - if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) { + + if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) { return boost::static_pointer_cast (r); } } - + return boost::shared_ptr(); } int -Region::apply (Filter& filter) +Region::apply (Filter& filter, Progress* progress) { - return filter.run (shared_from_this()); + return filter.run (shared_from_this(), progress); } @@ -1629,5 +1553,98 @@ Region::invalidate_transients () { _valid_transients = false; _transients.clear (); + + send_change (PropertyChange (Properties::valid_transients)); +} + +void +Region::drop_sources () +{ + for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) { + (*i)->dec_use_count (); + } + + _sources.clear (); + + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->dec_use_count (); + } + + _master_sources.clear (); +} + +void +Region::use_sources (SourceList const & s) +{ + set > unique_srcs; + + for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) { + + _sources.push_back (*i); + (*i)->inc_use_count (); + _master_sources.push_back (*i); + (*i)->inc_use_count (); + + /* connect only once to DropReferences, even if sources are replicated + */ + + if (unique_srcs.find (*i) == unique_srcs.end ()) { + unique_srcs.insert (*i); + (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr(*i))); + } + } +} + +Trimmable::CanTrim +Region::can_trim () const +{ + CanTrim ct = CanTrim (0); + + if (locked()) { + return ct; + } + + /* if not locked, we can always move the front later, and the end earlier + */ + + ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier); + + if (start() != 0 || can_trim_start_before_source_start ()) { + ct = CanTrim (ct | FrontTrimEarlier); + } + + if (!_sources.empty()) { + if ((start() + length()) < _sources.front()->length (0)) { + ct = CanTrim (ct | EndTrimLater); + } + } + + return ct; +} + +uint32_t +Region::max_source_level () const +{ + uint32_t lvl = 0; + + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + lvl = max (lvl, (*i)->level()); + } + + return lvl; +} + +bool +Region::is_compound () const +{ + return max_source_level() > 0; +} + +void +Region::post_set (const PropertyChange& pc) +{ + if (pc.contains (Properties::position)) { + recompute_position_from_lock_style (); + } }