Add new SharedStatefulProperty which manages a shared_ptr to
some Stateful object, and a subclass to use this for AutomationList. SharedStatefulProperty will manage undo / redo using full copies of the XML state, like MementoCommand, but does it within the Property undo system. git-svn-id: svn://localhost/ardour2/branches/3.0@12740 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
9429401f11
commit
5ac22e9095
@ -46,16 +46,11 @@ namespace Properties {
|
||||
extern PBD::PropertyDescriptor<bool> fade_in_active;
|
||||
extern PBD::PropertyDescriptor<bool> fade_out_active;
|
||||
extern PBD::PropertyDescriptor<float> scale_amplitude;
|
||||
|
||||
/* the envelope and fades are not scalar items and so
|
||||
currently (2010/02) are not stored using Property.
|
||||
However, these descriptors enable us to notify
|
||||
about changes to them via PropertyChange.
|
||||
*/
|
||||
|
||||
extern PBD::PropertyDescriptor<bool> envelope;
|
||||
extern PBD::PropertyDescriptor<bool> fade_in;
|
||||
extern PBD::PropertyDescriptor<bool> fade_out;
|
||||
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > fade_in;
|
||||
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > inverse_fade_in;
|
||||
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > fade_out;
|
||||
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > inverse_fade_out;
|
||||
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > envelope;
|
||||
}
|
||||
|
||||
class Playlist;
|
||||
@ -99,11 +94,11 @@ class AudioRegion : public Region
|
||||
bool fade_out_is_short() const { return _fade_out_is_short; }
|
||||
void set_fade_out_is_short (bool yn);
|
||||
|
||||
boost::shared_ptr<AutomationList> fade_in() { return _fade_in; }
|
||||
boost::shared_ptr<AutomationList> inverse_fade_in() { return _inverse_fade_in; }
|
||||
boost::shared_ptr<AutomationList> fade_out() { return _fade_out; }
|
||||
boost::shared_ptr<AutomationList> inverse_fade_out() { return _inverse_fade_out; }
|
||||
boost::shared_ptr<AutomationList> envelope() { return _envelope; }
|
||||
boost::shared_ptr<AutomationList> fade_in() { return _fade_in.val (); }
|
||||
boost::shared_ptr<AutomationList> inverse_fade_in() { return _inverse_fade_in.val (); }
|
||||
boost::shared_ptr<AutomationList> fade_out() { return _fade_out.val (); }
|
||||
boost::shared_ptr<AutomationList> inverse_fade_out() { return _inverse_fade_out.val (); }
|
||||
boost::shared_ptr<AutomationList> envelope() { return _envelope.val (); }
|
||||
|
||||
Evoral::Range<framepos_t> body_range () const;
|
||||
|
||||
@ -231,15 +226,15 @@ class AudioRegion : public Region
|
||||
void connect_to_analysis_changed ();
|
||||
void connect_to_header_position_offset_changed ();
|
||||
|
||||
Automatable _automatable;
|
||||
|
||||
boost::shared_ptr<AutomationList> _fade_in;
|
||||
boost::shared_ptr<AutomationList> _inverse_fade_in;
|
||||
boost::shared_ptr<AutomationList> _fade_out;
|
||||
boost::shared_ptr<AutomationList> _inverse_fade_out;
|
||||
boost::shared_ptr<AutomationList> _envelope;
|
||||
uint32_t _fade_in_suspended;
|
||||
uint32_t _fade_out_suspended;
|
||||
AutomationListProperty _fade_in;
|
||||
AutomationListProperty _inverse_fade_in;
|
||||
AutomationListProperty _fade_out;
|
||||
AutomationListProperty _inverse_fade_out;
|
||||
AutomationListProperty _envelope;
|
||||
Automatable _automatable;
|
||||
uint32_t _fade_in_suspended;
|
||||
uint32_t _fade_out_suspended;
|
||||
|
||||
boost::shared_ptr<ARDOUR::Region> get_single_other_xfade_region (bool start) const;
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "pbd/undo.h"
|
||||
#include "pbd/xml++.h"
|
||||
#include "pbd/statefuldestructible.h"
|
||||
#include "pbd/properties.h"
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
|
||||
@ -36,6 +37,28 @@
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AutomationList;
|
||||
|
||||
/** A SharedStatefulProperty for AutomationLists */
|
||||
class AutomationListProperty : public PBD::SharedStatefulProperty<AutomationList>
|
||||
{
|
||||
public:
|
||||
AutomationListProperty (PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > d, Ptr p)
|
||||
: PBD::SharedStatefulProperty<AutomationList> (d.property_id, p)
|
||||
{}
|
||||
|
||||
AutomationListProperty (PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > d, Ptr o, Ptr c)
|
||||
: PBD::SharedStatefulProperty<AutomationList> (d.property_id, o, c)
|
||||
{}
|
||||
|
||||
PBD::PropertyBase* clone () const;
|
||||
|
||||
private:
|
||||
/* No copy-construction nor assignment */
|
||||
AutomationListProperty (AutomationListProperty const &);
|
||||
AutomationListProperty& operator= (AutomationListProperty const &);
|
||||
};
|
||||
|
||||
class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlList
|
||||
{
|
||||
public:
|
||||
@ -82,6 +105,8 @@ class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlL
|
||||
XMLNode& state (bool full);
|
||||
XMLNode& serialize_events ();
|
||||
|
||||
bool operator!= (const AutomationList &) const;
|
||||
|
||||
private:
|
||||
void create_curve_if_necessary ();
|
||||
int deserialize_events (const XMLNode&);
|
||||
|
@ -65,6 +65,11 @@ namespace ARDOUR {
|
||||
PBD::PropertyDescriptor<bool> fade_out_is_short;
|
||||
PBD::PropertyDescriptor<bool> fade_in_is_xfade;
|
||||
PBD::PropertyDescriptor<bool> fade_in_is_short;
|
||||
PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > fade_in;
|
||||
PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > inverse_fade_in;
|
||||
PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > fade_out;
|
||||
PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > inverse_fade_out;
|
||||
PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > envelope;
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +169,16 @@ AudioRegion::make_property_quarks ()
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-in-is-xfade = %1\n", Properties::fade_in_is_xfade.property_id));
|
||||
Properties::fade_in_is_short.property_id = g_quark_from_static_string (X_("fade-in-is-short"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-in-is-short = %1\n", Properties::fade_in_is_short.property_id));
|
||||
Properties::fade_in.property_id = g_quark_from_static_string (X_("FadeIn"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for FadeIn = %1\n", Properties::fade_in.property_id));
|
||||
Properties::inverse_fade_in.property_id = g_quark_from_static_string (X_("InverseFadeIn"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for InverseFadeIn = %1\n", Properties::inverse_fade_in.property_id));
|
||||
Properties::fade_out.property_id = g_quark_from_static_string (X_("FadeOut"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for FadeOut = %1\n", Properties::fade_out.property_id));
|
||||
Properties::inverse_fade_out.property_id = g_quark_from_static_string (X_("InverseFadeOut"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for InverseFadeOut = %1\n", Properties::inverse_fade_out.property_id));
|
||||
Properties::envelope.property_id = g_quark_from_static_string (X_("Envelope"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for Envelope = %1\n", Properties::envelope.property_id));
|
||||
}
|
||||
|
||||
void
|
||||
@ -181,6 +196,11 @@ AudioRegion::register_properties ()
|
||||
add_property (_fade_out_is_short);
|
||||
add_property (_fade_in_is_xfade);
|
||||
add_property (_fade_in_is_short);
|
||||
add_property (_fade_in);
|
||||
add_property (_inverse_fade_in);
|
||||
add_property (_fade_out);
|
||||
add_property (_inverse_fade_out);
|
||||
add_property (_envelope);
|
||||
}
|
||||
|
||||
#define AUDIOREGION_STATE_DEFAULT \
|
||||
@ -193,7 +213,11 @@ AudioRegion::register_properties ()
|
||||
, _fade_in_is_xfade (Properties::fade_in_is_xfade, false) \
|
||||
, _fade_out_is_xfade (Properties::fade_out_is_xfade, false) \
|
||||
, _fade_in_is_short (Properties::fade_in_is_short, false) \
|
||||
, _fade_out_is_short (Properties::fade_out_is_short, false)
|
||||
, _fade_out_is_short (Properties::fade_out_is_short, false) \
|
||||
, _fade_in (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation)))) \
|
||||
, _inverse_fade_in (Properties::inverse_fade_in, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation)))) \
|
||||
, _fade_out (Properties::fade_out, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeOutAutomation)))) \
|
||||
, _inverse_fade_out (Properties::inverse_fade_out, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeOutAutomation))))
|
||||
|
||||
#define AUDIOREGION_COPY_STATE(other) \
|
||||
_envelope_active (Properties::envelope_active, other->_envelope_active) \
|
||||
@ -205,7 +229,11 @@ AudioRegion::register_properties ()
|
||||
, _fade_in_is_xfade (Properties::fade_in_is_xfade, other->_fade_in_is_xfade) \
|
||||
, _fade_out_is_xfade (Properties::fade_out_is_xfade, other->_fade_out_is_xfade) \
|
||||
, _fade_in_is_short (Properties::fade_in_is_short, other->_fade_in_is_short) \
|
||||
, _fade_out_is_short (Properties::fade_out_is_short, other->_fade_out_is_short)
|
||||
, _fade_out_is_short (Properties::fade_out_is_short, other->_fade_out_is_short) \
|
||||
, _fade_in (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (*other->_fade_in.val()))) \
|
||||
, _inverse_fade_in (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_in.val()))) \
|
||||
, _fade_out (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (*other->_fade_out.val()))) \
|
||||
, _inverse_fade_out (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_out.val())))
|
||||
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
|
||||
|
||||
void
|
||||
@ -227,12 +255,8 @@ AudioRegion::init ()
|
||||
AudioRegion::AudioRegion (Session& s, framepos_t start, framecnt_t len, std::string name)
|
||||
: Region (s, start, len, name, DataType::AUDIO)
|
||||
, AUDIOREGION_STATE_DEFAULT
|
||||
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation))))
|
||||
, _automatable (s)
|
||||
, _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
|
||||
, _inverse_fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
|
||||
, _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
|
||||
, _inverse_fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
|
||||
, _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
|
||||
, _fade_in_suspended (0)
|
||||
, _fade_out_suspended (0)
|
||||
{
|
||||
@ -244,12 +268,8 @@ AudioRegion::AudioRegion (Session& s, framepos_t start, framecnt_t len, std::str
|
||||
AudioRegion::AudioRegion (const SourceList& srcs)
|
||||
: Region (srcs)
|
||||
, AUDIOREGION_STATE_DEFAULT
|
||||
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation))))
|
||||
, _automatable(srcs[0]->session())
|
||||
, _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
|
||||
, _inverse_fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
|
||||
, _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
|
||||
, _inverse_fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
|
||||
, _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
|
||||
, _fade_in_suspended (0)
|
||||
, _fade_out_suspended (0)
|
||||
{
|
||||
@ -260,15 +280,11 @@ AudioRegion::AudioRegion (const SourceList& srcs)
|
||||
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
|
||||
: Region (other)
|
||||
, AUDIOREGION_COPY_STATE (other)
|
||||
, _automatable (other->session())
|
||||
, _fade_in (new AutomationList (*other->_fade_in))
|
||||
, _inverse_fade_in (new AutomationList(*other->_inverse_fade_in))
|
||||
, _fade_out (new AutomationList (*other->_fade_out))
|
||||
, _inverse_fade_out (new AutomationList (*other->_inverse_fade_out))
|
||||
/* As far as I can see, the _envelope's times are relative to region position, and have nothing
|
||||
to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset.
|
||||
*/
|
||||
, _envelope (new AutomationList (*other->_envelope, 0, other->_length))
|
||||
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val(), 0, other->_length)))
|
||||
, _automatable (other->session())
|
||||
, _fade_in_suspended (0)
|
||||
, _fade_out_suspended (0)
|
||||
{
|
||||
@ -286,15 +302,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
|
||||
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, framecnt_t offset)
|
||||
: Region (other, offset)
|
||||
, AUDIOREGION_COPY_STATE (other)
|
||||
, _automatable (other->session())
|
||||
, _fade_in (new AutomationList (*other->_fade_in))
|
||||
, _inverse_fade_in (new AutomationList(*other->_inverse_fade_in))
|
||||
, _fade_out (new AutomationList (*other->_fade_out))
|
||||
, _inverse_fade_out (new AutomationList (*other->_inverse_fade_out))
|
||||
/* As far as I can see, the _envelope's times are relative to region position, and have nothing
|
||||
to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset.
|
||||
*/
|
||||
, _envelope (new AutomationList (*other->_envelope, offset, other->_length))
|
||||
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val(), offset, other->_length)))
|
||||
, _automatable (other->session())
|
||||
, _fade_in_suspended (0)
|
||||
, _fade_out_suspended (0)
|
||||
{
|
||||
@ -312,12 +324,8 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, framecnt_t
|
||||
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const SourceList& srcs)
|
||||
: Region (boost::static_pointer_cast<const Region>(other), srcs)
|
||||
, AUDIOREGION_COPY_STATE (other)
|
||||
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val())))
|
||||
, _automatable (other->session())
|
||||
, _fade_in (new AutomationList (*other->_fade_in))
|
||||
, _inverse_fade_in (new AutomationList(*other->_inverse_fade_in))
|
||||
, _fade_out (new AutomationList (*other->_fade_out))
|
||||
, _inverse_fade_out (new AutomationList (*other->_inverse_fade_out))
|
||||
, _envelope (new AutomationList (*other->_envelope))
|
||||
, _fade_in_suspended (0)
|
||||
, _fade_out_suspended (0)
|
||||
{
|
||||
@ -335,12 +343,8 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const Sour
|
||||
AudioRegion::AudioRegion (SourceList& srcs)
|
||||
: Region (srcs)
|
||||
, AUDIOREGION_STATE_DEFAULT
|
||||
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList(Evoral::Parameter(EnvelopeAutomation))))
|
||||
, _automatable(srcs[0]->session())
|
||||
, _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
|
||||
, _inverse_fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
|
||||
, _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
|
||||
, _inverse_fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
|
||||
, _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
|
||||
, _fade_in_suspended (0)
|
||||
, _fade_out_suspended (0)
|
||||
{
|
||||
@ -988,7 +992,7 @@ void
|
||||
AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
|
||||
{
|
||||
_fade_in->freeze ();
|
||||
*_fade_in = *f;
|
||||
*(_fade_in.val()) = *f;
|
||||
_fade_in->thaw ();
|
||||
_default_fade_in = false;
|
||||
|
||||
@ -1010,23 +1014,23 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
|
||||
case FadeLinear:
|
||||
_fade_in->fast_simple_add (0.0, 0.0);
|
||||
_fade_in->fast_simple_add (len, 1.0);
|
||||
reverse_curve (_inverse_fade_in, _fade_in);
|
||||
reverse_curve (_inverse_fade_in.val(), _fade_in.val());
|
||||
break;
|
||||
|
||||
case FadeFast:
|
||||
generate_db_fade (_fade_in, len, 10, -60);
|
||||
reverse_curve (c1, _fade_in);
|
||||
generate_db_fade (_fade_in.val(), len, 10, -60);
|
||||
reverse_curve (c1, _fade_in.val());
|
||||
_fade_in->copy_events (*c1);
|
||||
generate_inverse_power_curve (_inverse_fade_in, _fade_in);
|
||||
generate_inverse_power_curve (_inverse_fade_in.val(), _fade_in.val());
|
||||
break;
|
||||
|
||||
case FadeSlow:
|
||||
generate_db_fade (c1, len, 10, -1); // start off with a slow fade
|
||||
generate_db_fade (c2, len, 10, -80); // end with a fast fade
|
||||
merge_curves (_fade_in, c1, c2);
|
||||
reverse_curve (c3, _fade_in);
|
||||
merge_curves (_fade_in.val(), c1, c2);
|
||||
reverse_curve (c3, _fade_in.val());
|
||||
_fade_in->copy_events (*c3);
|
||||
generate_inverse_power_curve (_inverse_fade_in, _fade_in);
|
||||
generate_inverse_power_curve (_inverse_fade_in.val(), _fade_in.val());
|
||||
break;
|
||||
|
||||
case FadeConstantPower:
|
||||
@ -1035,7 +1039,7 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
|
||||
_fade_in->fast_simple_add (len*dist, sin (dist*M_PI/2));
|
||||
}
|
||||
_fade_in->fast_simple_add (len, 1.0);
|
||||
reverse_curve (_inverse_fade_in, _fade_in);
|
||||
reverse_curve (_inverse_fade_in.val(), _fade_in.val());
|
||||
break;
|
||||
|
||||
case FadeSymmetric:
|
||||
@ -1053,9 +1057,9 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
|
||||
_fade_in->fast_simple_add (len* (breakpoint+((1.0-breakpoint)*(double)i/(double)num_steps)), coeff);
|
||||
}
|
||||
_fade_in->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
||||
reverse_curve (c3, _fade_in);
|
||||
reverse_curve (c3, _fade_in.val());
|
||||
_fade_in->copy_events (*c3);
|
||||
reverse_curve (_inverse_fade_in, _fade_in );
|
||||
reverse_curve (_inverse_fade_in.val(), _fade_in.val());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1068,7 +1072,7 @@ void
|
||||
AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
|
||||
{
|
||||
_fade_out->freeze ();
|
||||
*_fade_out = *f;
|
||||
*(_fade_out.val()) = *f;
|
||||
_fade_out->thaw ();
|
||||
_default_fade_out = false;
|
||||
|
||||
@ -1089,19 +1093,19 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
|
||||
case FadeLinear:
|
||||
_fade_out->fast_simple_add (0.0, 1.0);
|
||||
_fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
||||
reverse_curve (_inverse_fade_out, _fade_out);
|
||||
reverse_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||
break;
|
||||
|
||||
case FadeFast:
|
||||
generate_db_fade (_fade_out, len, 10, -60);
|
||||
generate_inverse_power_curve (_inverse_fade_out, _fade_out);
|
||||
generate_db_fade (_fade_out.val(), len, 10, -60);
|
||||
generate_inverse_power_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||
break;
|
||||
|
||||
case FadeSlow:
|
||||
generate_db_fade (c1, len, 10, -1); //start off with a slow fade
|
||||
generate_db_fade (c2, len, 10, -80); //end with a fast fade
|
||||
merge_curves (_fade_out, c1, c2);
|
||||
generate_inverse_power_curve (_inverse_fade_out, _fade_out);
|
||||
merge_curves (_fade_out.val(), c1, c2);
|
||||
generate_inverse_power_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||
break;
|
||||
|
||||
case FadeConstantPower:
|
||||
@ -1113,7 +1117,7 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
|
||||
_fade_out->fast_simple_add ((len * dist), cos(dist*M_PI/2));
|
||||
}
|
||||
_fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
||||
reverse_curve (_inverse_fade_out, _fade_out);
|
||||
reverse_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||
break;
|
||||
|
||||
case FadeSymmetric:
|
||||
@ -1132,7 +1136,7 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
|
||||
_fade_out->fast_simple_add (len* (breakpoint+((1.0-breakpoint)*(double)i/(double)num_steps)), coeff);
|
||||
}
|
||||
_fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
||||
reverse_curve (_inverse_fade_out, _fade_out);
|
||||
reverse_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -510,3 +510,24 @@ AutomationList::set_state (const XMLNode& node, int version)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
AutomationList::operator!= (AutomationList const & other) const
|
||||
{
|
||||
return (
|
||||
static_cast<ControlList const &> (*this) != static_cast<ControlList const &> (other) ||
|
||||
_state != other._state ||
|
||||
_style != other._style ||
|
||||
_touching != other._touching
|
||||
);
|
||||
}
|
||||
|
||||
PBD::PropertyBase *
|
||||
AutomationListProperty::clone () const
|
||||
{
|
||||
return new AutomationListProperty (
|
||||
this->property_id(),
|
||||
boost::shared_ptr<AutomationList> (new AutomationList (*this->_old.get())),
|
||||
boost::shared_ptr<AutomationList> (new AutomationList (*this->_current.get()))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -115,34 +115,6 @@ extern void setup_enum_writer ();
|
||||
*/
|
||||
PBD::PropertyChange ARDOUR::bounds_change;
|
||||
|
||||
namespace ARDOUR {
|
||||
namespace Properties {
|
||||
|
||||
/* the envelope and fades are not scalar items and so
|
||||
currently (2010/02) are not stored using Property.
|
||||
However, these descriptors enable us to notify
|
||||
about changes to them via PropertyChange.
|
||||
|
||||
Declared in ardour/audioregion.h ...
|
||||
*/
|
||||
|
||||
PBD::PropertyDescriptor<bool> fade_in;
|
||||
PBD::PropertyDescriptor<bool> fade_out;
|
||||
PBD::PropertyDescriptor<bool> envelope;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::make_property_quarks ()
|
||||
{
|
||||
Properties::fade_in.property_id = g_quark_from_static_string (X_("fade_in_FAKE"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_in_FAKE = %1\n", Properties::fade_in.property_id));
|
||||
Properties::fade_out.property_id = g_quark_from_static_string (X_("fade_out_FAKE"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade_out_FAKE = %1\n", Properties::fade_out.property_id));
|
||||
Properties::envelope.property_id = g_quark_from_static_string (X_("envelope_FAKE"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope_FAKE = %1\n", Properties::envelope.property_id));
|
||||
}
|
||||
|
||||
void
|
||||
setup_hardware_optimization (bool try_optimization)
|
||||
{
|
||||
@ -248,7 +220,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization)
|
||||
PBD::ID::init ();
|
||||
SessionEvent::init_event_pool ();
|
||||
|
||||
make_property_quarks ();
|
||||
SessionObject::make_property_quarks ();
|
||||
Region::make_property_quarks ();
|
||||
MidiRegion::make_property_quarks ();
|
||||
|
123
libs/ardour/test/automation_list_property_test.cc
Normal file
123
libs/ardour/test/automation_list_property_test.cc
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright (C) 2012 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "pbd/properties.h"
|
||||
#include "pbd/stateful_diff_command.h"
|
||||
#include "ardour/automation_list.h"
|
||||
#include "automation_list_property_test.h"
|
||||
#include "test_util.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (AutomationListPropertyTest);
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
void
|
||||
AutomationListPropertyTest::basicTest ()
|
||||
{
|
||||
PropertyDescriptor<boost::shared_ptr<AutomationList> > descriptor;
|
||||
descriptor.property_id = g_quark_from_static_string ("FadeIn");
|
||||
AutomationListProperty property (
|
||||
descriptor,
|
||||
boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation)))
|
||||
);
|
||||
|
||||
property.clear_changes ();
|
||||
|
||||
/* No change since we just cleared them */
|
||||
CPPUNIT_ASSERT_EQUAL (false, property.changed());
|
||||
|
||||
property->add (1, 2);
|
||||
property->add (3, 4);
|
||||
|
||||
/* Now it has changed */
|
||||
CPPUNIT_ASSERT_EQUAL (true, property.changed());
|
||||
|
||||
XMLNode* foo = new XMLNode ("test");
|
||||
property.get_changes_as_xml (foo);
|
||||
check_xml (foo, "../libs/ardour/test/data/automation_list_property_test1.ref");
|
||||
|
||||
/* Do some more */
|
||||
property.clear_changes ();
|
||||
CPPUNIT_ASSERT_EQUAL (false, property.changed());
|
||||
property->add (5, 6);
|
||||
property->add (7, 8);
|
||||
CPPUNIT_ASSERT_EQUAL (true, property.changed());
|
||||
foo = new XMLNode ("test");
|
||||
property.get_changes_as_xml (foo);
|
||||
check_xml (foo, "../libs/ardour/test/data/automation_list_property_test2.ref");
|
||||
}
|
||||
|
||||
/** Here's a StatefulDestructible class that has a AutomationListProperty */
|
||||
class Fred : public StatefulDestructible
|
||||
{
|
||||
public:
|
||||
Fred ()
|
||||
: _jim (_descriptor, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation))))
|
||||
|
||||
{
|
||||
add_property (_jim);
|
||||
}
|
||||
|
||||
XMLNode & get_state () {
|
||||
XMLNode* n = new XMLNode ("State");
|
||||
add_properties (*n);
|
||||
return *n;
|
||||
}
|
||||
|
||||
int set_state (XMLNode const & node, int) {
|
||||
set_values (node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void make_property_quarks () {
|
||||
_descriptor.property_id = g_quark_from_static_string ("FadeIn");
|
||||
}
|
||||
|
||||
AutomationListProperty _jim;
|
||||
static PropertyDescriptor<boost::shared_ptr<AutomationList> > _descriptor;
|
||||
};
|
||||
|
||||
PropertyDescriptor<boost::shared_ptr<AutomationList> > Fred::_descriptor;
|
||||
|
||||
void
|
||||
AutomationListPropertyTest::undoTest ()
|
||||
{
|
||||
Fred::make_property_quarks ();
|
||||
|
||||
boost::shared_ptr<Fred> sheila (new Fred);
|
||||
|
||||
/* Add some data */
|
||||
sheila->_jim->add (1, 2);
|
||||
sheila->_jim->add (3, 4);
|
||||
|
||||
/* Do a `command' */
|
||||
sheila->clear_changes ();
|
||||
sheila->_jim->add (5, 6);
|
||||
sheila->_jim->add (7, 8);
|
||||
StatefulDiffCommand sdc (sheila);
|
||||
|
||||
/* Undo */
|
||||
sdc.undo ();
|
||||
check_xml (&sheila->get_state(), "../libs/ardour/test/data/automation_list_property_test3.ref");
|
||||
|
||||
/* Redo */
|
||||
sdc.redo ();
|
||||
check_xml (&sheila->get_state(), "../libs/ardour/test/data/automation_list_property_test4.ref");
|
||||
}
|
32
libs/ardour/test/automation_list_property_test.h
Normal file
32
libs/ardour/test/automation_list_property_test.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright (C) 2012 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
class AutomationListPropertyTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (AutomationListPropertyTest);
|
||||
CPPUNIT_TEST (basicTest);
|
||||
CPPUNIT_TEST (undoTest);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void basicTest ();
|
||||
void undoTest ();
|
||||
};
|
17
libs/ardour/test/data/automation_list_property_test1.ref
Normal file
17
libs/ardour/test/data/automation_list_property_test1.ref
Normal file
@ -0,0 +1,17 @@
|
||||
<test>
|
||||
<FadeIn>
|
||||
<from>
|
||||
<AutomationList automation-id="fadein" id="162" default="0" min-yval="0" max-yval="2" interpolation-style="Linear" state="Off" style="Absolute">
|
||||
</AutomationList>
|
||||
</from>
|
||||
<to>
|
||||
<AutomationList automation-id="fadein" id="162" default="0" min-yval="0" max-yval="2" interpolation-style="Linear" state="Off" style="Absolute">
|
||||
<events>
|
||||
1 2
|
||||
3 4
|
||||
|
||||
</events>
|
||||
</AutomationList>
|
||||
</to>
|
||||
</FadeIn>
|
||||
</test>
|
24
libs/ardour/test/data/automation_list_property_test2.ref
Normal file
24
libs/ardour/test/data/automation_list_property_test2.ref
Normal file
@ -0,0 +1,24 @@
|
||||
<test>
|
||||
<FadeIn>
|
||||
<from>
|
||||
<AutomationList automation-id="fadein" id="162" default="0" min-yval="0" max-yval="2" interpolation-style="Linear" state="Off" style="Absolute">
|
||||
<events>
|
||||
1 2
|
||||
3 4
|
||||
|
||||
</events>
|
||||
</AutomationList>
|
||||
</from>
|
||||
<to>
|
||||
<AutomationList automation-id="fadein" id="162" default="0" min-yval="0" max-yval="2" interpolation-style="Linear" state="Off" style="Absolute">
|
||||
<events>
|
||||
1 2
|
||||
3 4
|
||||
5 6
|
||||
7 8
|
||||
|
||||
</events>
|
||||
</AutomationList>
|
||||
</to>
|
||||
</FadeIn>
|
||||
</test>
|
11
libs/ardour/test/data/automation_list_property_test3.ref
Normal file
11
libs/ardour/test/data/automation_list_property_test3.ref
Normal file
@ -0,0 +1,11 @@
|
||||
<State>
|
||||
<FadeIn>
|
||||
<AutomationList automation-id="fadein" id="166" default="0" min-yval="0" max-yval="2" interpolation-style="Linear" state="Off" style="Absolute">
|
||||
<events>
|
||||
1 2
|
||||
3 4
|
||||
|
||||
</events>
|
||||
</AutomationList>
|
||||
</FadeIn>
|
||||
</State>
|
13
libs/ardour/test/data/automation_list_property_test4.ref
Normal file
13
libs/ardour/test/data/automation_list_property_test4.ref
Normal file
@ -0,0 +1,13 @@
|
||||
<State>
|
||||
<FadeIn>
|
||||
<AutomationList automation-id="fadein" id="166" default="0" min-yval="0" max-yval="2" interpolation-style="Linear" state="Off" style="Absolute">
|
||||
<events>
|
||||
1 2
|
||||
3 4
|
||||
5 6
|
||||
7 8
|
||||
|
||||
</events>
|
||||
</AutomationList>
|
||||
</FadeIn>
|
||||
</State>
|
20
libs/ardour/test/test_util.cc
Normal file
20
libs/ardour/test/test_util.cc
Normal file
@ -0,0 +1,20 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "pbd/xml++.h"
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
check_xml (XMLNode* node, string ref_file)
|
||||
{
|
||||
system ("rm -f libs/ardour/test/test.xml");
|
||||
ofstream f ("libs/ardour/test/test.xml");
|
||||
node->dump (f);
|
||||
f.close ();
|
||||
|
||||
stringstream cmd;
|
||||
cmd << "diff -u libs/ardour/test/test.xml " << ref_file;
|
||||
CPPUNIT_ASSERT_EQUAL (0, system (cmd.str().c_str ()));
|
||||
}
|
||||
|
2
libs/ardour/test/test_util.h
Normal file
2
libs/ardour/test/test_util.h
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
extern void check_xml (XMLNode *, std::string);
|
@ -424,10 +424,12 @@ def build(bld):
|
||||
testobj = bld(features = 'cxx cxxprogram')
|
||||
testobj.source = '''
|
||||
test/dummy_lxvst.cc
|
||||
test/test_util.cc
|
||||
test/test_needing_session.cc
|
||||
test/audio_region_test.cc
|
||||
test/test_globals.cc
|
||||
test/audio_region_read_test.cc
|
||||
test/automation_list_property_test.cc
|
||||
test/bbt_test.cc
|
||||
test/tempo_test.cc
|
||||
test/interpolation_test.cc
|
||||
|
@ -255,6 +255,8 @@ public:
|
||||
static void set_thinning_factor (double d);
|
||||
static double thinning_factor() { return _thinning_factor; }
|
||||
|
||||
bool operator!= (ControlList const &) const;
|
||||
|
||||
protected:
|
||||
|
||||
/** Called by unlocked_eval() to handle cases of 3 or more control points. */
|
||||
|
@ -1529,5 +1529,33 @@ ControlList::set_thinning_factor (double v)
|
||||
_thinning_factor = v;
|
||||
}
|
||||
|
||||
bool
|
||||
ControlList::operator!= (ControlList const & other) const
|
||||
{
|
||||
if (_events.size() != other._events.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
EventList::const_iterator i = _events.begin ();
|
||||
EventList::const_iterator j = other._events.begin ();
|
||||
|
||||
while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
|
||||
if (i != _events.end ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
_parameter != other._parameter ||
|
||||
_interpolation != other._interpolation ||
|
||||
_min_yval != other._min_yval ||
|
||||
_max_yval != other._max_yval ||
|
||||
_default_value != other._default_value
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Evoral
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "pbd/property_basics.h"
|
||||
#include "pbd/property_list.h"
|
||||
#include "pbd/enumwriter.h"
|
||||
#include "pbd/stateful.h"
|
||||
|
||||
namespace PBD {
|
||||
|
||||
@ -341,7 +342,121 @@ private:
|
||||
/* no copy-construction */
|
||||
EnumProperty (EnumProperty const &);
|
||||
};
|
||||
|
||||
/** A Property which holds a shared_ptr to a Stateful object,
|
||||
* and handles undo using the somewhat inefficient approach
|
||||
* of saving the complete XML state of its object before and
|
||||
* after changes. A sort of half-way house between the old
|
||||
* complete-state undo system and the new difference-based
|
||||
* one.
|
||||
*/
|
||||
template <class T>
|
||||
class SharedStatefulProperty : public PropertyBase
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<T> Ptr;
|
||||
|
||||
SharedStatefulProperty (PropertyID d, Ptr p)
|
||||
: PropertyBase (d)
|
||||
, _current (p)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SharedStatefulProperty (PropertyID d, Ptr o, Ptr c)
|
||||
: PropertyBase (d)
|
||||
, _old (o)
|
||||
, _current (c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool set_value (XMLNode const & node) {
|
||||
|
||||
/* Look for our node */
|
||||
XMLNode* n = node.child (property_name ());
|
||||
if (!n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* And there should be one child which is the state of our T */
|
||||
XMLNodeList const & children = n->children ();
|
||||
if (children.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_current->set_state (*children.front (), Stateful::current_state_version);
|
||||
return true;
|
||||
}
|
||||
|
||||
void get_value (XMLNode & node) const {
|
||||
XMLNode* n = node.add_child (property_name ());
|
||||
n->add_child_nocopy (_current->get_state ());
|
||||
}
|
||||
|
||||
void clear_changes () {
|
||||
/* We are starting to change things, so _old gets set up
|
||||
with the current state.
|
||||
*/
|
||||
_old.reset (new T (*_current.get()));
|
||||
}
|
||||
|
||||
bool changed () const {
|
||||
/* Expensive, but, hey; this requires operator!= in
|
||||
our T
|
||||
*/
|
||||
return (*_old != *_current);
|
||||
}
|
||||
|
||||
void invert () {
|
||||
_current.swap (_old);
|
||||
}
|
||||
|
||||
void get_changes_as_xml (XMLNode* history_node) const {
|
||||
/* We express the diff as before and after state, just
|
||||
as MementoCommand does.
|
||||
*/
|
||||
XMLNode* p = history_node->add_child (property_name ());
|
||||
XMLNode* from = p->add_child ("from");
|
||||
from->add_child_nocopy (_old->get_state ());
|
||||
XMLNode* to = p->add_child ("to");
|
||||
to->add_child_nocopy (_current->get_state ());
|
||||
}
|
||||
|
||||
void get_changes_as_properties (PropertyList& changes, Command *) const {
|
||||
if (changed ()) {
|
||||
changes.add (clone ());
|
||||
}
|
||||
}
|
||||
|
||||
void apply_changes (PropertyBase const * p) {
|
||||
*_current = *(dynamic_cast<SharedStatefulProperty const *> (p))->val ();
|
||||
}
|
||||
|
||||
Ptr val () const {
|
||||
return _current;
|
||||
}
|
||||
|
||||
T* operator-> () const {
|
||||
return _current.operator-> ();
|
||||
}
|
||||
|
||||
operator bool () const {
|
||||
return _current;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Ptr _old;
|
||||
Ptr _current;
|
||||
|
||||
private:
|
||||
|
||||
/* No copy-construction nor assignment */
|
||||
SharedStatefulProperty (SharedStatefulProperty<T> const &);
|
||||
SharedStatefulProperty<T>& operator= (SharedStatefulProperty<T> const &);
|
||||
};
|
||||
|
||||
} /* namespace PBD */
|
||||
|
||||
#include "pbd/property_list_impl.h"
|
||||
|
@ -652,13 +652,19 @@ static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string& xpath)
|
||||
void
|
||||
XMLNode::dump (ostream& s, string p) const
|
||||
{
|
||||
s << p << _name << " ";
|
||||
for (XMLPropertyList::const_iterator i = _proplist.begin(); i != _proplist.end(); ++i) {
|
||||
s << (*i)->name() << "=" << (*i)->value() << " ";
|
||||
}
|
||||
s << "\n";
|
||||
|
||||
for (XMLNodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
|
||||
(*i)->dump (s, p + " ");
|
||||
if (_is_content) {
|
||||
s << p << " " << content() << "\n";
|
||||
} else {
|
||||
s << p << "<" << _name;
|
||||
for (XMLPropertyList::const_iterator i = _proplist.begin(); i != _proplist.end(); ++i) {
|
||||
s << " " << (*i)->name() << "=\"" << (*i)->value() << "\"";
|
||||
}
|
||||
s << ">\n";
|
||||
|
||||
for (XMLNodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
|
||||
(*i)->dump (s, p + " ");
|
||||
}
|
||||
|
||||
s << p << "</" << _name << ">\n";
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user