mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-13 18:16:35 +01:00
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
18 changed files with 524 additions and 113 deletions
|
|
@ -46,16 +46,11 @@ namespace Properties {
|
||||||
extern PBD::PropertyDescriptor<bool> fade_in_active;
|
extern PBD::PropertyDescriptor<bool> fade_in_active;
|
||||||
extern PBD::PropertyDescriptor<bool> fade_out_active;
|
extern PBD::PropertyDescriptor<bool> fade_out_active;
|
||||||
extern PBD::PropertyDescriptor<float> scale_amplitude;
|
extern PBD::PropertyDescriptor<float> scale_amplitude;
|
||||||
|
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > fade_in;
|
||||||
/* the envelope and fades are not scalar items and so
|
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > inverse_fade_in;
|
||||||
currently (2010/02) are not stored using Property.
|
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > fade_out;
|
||||||
However, these descriptors enable us to notify
|
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > inverse_fade_out;
|
||||||
about changes to them via PropertyChange.
|
extern PBD::PropertyDescriptor<boost::shared_ptr<AutomationList> > envelope;
|
||||||
*/
|
|
||||||
|
|
||||||
extern PBD::PropertyDescriptor<bool> envelope;
|
|
||||||
extern PBD::PropertyDescriptor<bool> fade_in;
|
|
||||||
extern PBD::PropertyDescriptor<bool> fade_out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Playlist;
|
class Playlist;
|
||||||
|
|
@ -99,11 +94,11 @@ class AudioRegion : public Region
|
||||||
bool fade_out_is_short() const { return _fade_out_is_short; }
|
bool fade_out_is_short() const { return _fade_out_is_short; }
|
||||||
void set_fade_out_is_short (bool yn);
|
void set_fade_out_is_short (bool yn);
|
||||||
|
|
||||||
boost::shared_ptr<AutomationList> fade_in() { return _fade_in; }
|
boost::shared_ptr<AutomationList> fade_in() { return _fade_in.val (); }
|
||||||
boost::shared_ptr<AutomationList> inverse_fade_in() { return _inverse_fade_in; }
|
boost::shared_ptr<AutomationList> inverse_fade_in() { return _inverse_fade_in.val (); }
|
||||||
boost::shared_ptr<AutomationList> fade_out() { return _fade_out; }
|
boost::shared_ptr<AutomationList> fade_out() { return _fade_out.val (); }
|
||||||
boost::shared_ptr<AutomationList> inverse_fade_out() { return _inverse_fade_out; }
|
boost::shared_ptr<AutomationList> inverse_fade_out() { return _inverse_fade_out.val (); }
|
||||||
boost::shared_ptr<AutomationList> envelope() { return _envelope; }
|
boost::shared_ptr<AutomationList> envelope() { return _envelope.val (); }
|
||||||
|
|
||||||
Evoral::Range<framepos_t> body_range () const;
|
Evoral::Range<framepos_t> body_range () const;
|
||||||
|
|
||||||
|
|
@ -231,13 +226,13 @@ class AudioRegion : public Region
|
||||||
void connect_to_analysis_changed ();
|
void connect_to_analysis_changed ();
|
||||||
void connect_to_header_position_offset_changed ();
|
void connect_to_header_position_offset_changed ();
|
||||||
|
|
||||||
Automatable _automatable;
|
|
||||||
|
|
||||||
boost::shared_ptr<AutomationList> _fade_in;
|
AutomationListProperty _fade_in;
|
||||||
boost::shared_ptr<AutomationList> _inverse_fade_in;
|
AutomationListProperty _inverse_fade_in;
|
||||||
boost::shared_ptr<AutomationList> _fade_out;
|
AutomationListProperty _fade_out;
|
||||||
boost::shared_ptr<AutomationList> _inverse_fade_out;
|
AutomationListProperty _inverse_fade_out;
|
||||||
boost::shared_ptr<AutomationList> _envelope;
|
AutomationListProperty _envelope;
|
||||||
|
Automatable _automatable;
|
||||||
uint32_t _fade_in_suspended;
|
uint32_t _fade_in_suspended;
|
||||||
uint32_t _fade_out_suspended;
|
uint32_t _fade_out_suspended;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "pbd/undo.h"
|
#include "pbd/undo.h"
|
||||||
#include "pbd/xml++.h"
|
#include "pbd/xml++.h"
|
||||||
#include "pbd/statefuldestructible.h"
|
#include "pbd/statefuldestructible.h"
|
||||||
|
#include "pbd/properties.h"
|
||||||
|
|
||||||
#include "ardour/ardour.h"
|
#include "ardour/ardour.h"
|
||||||
|
|
||||||
|
|
@ -36,6 +37,28 @@
|
||||||
|
|
||||||
namespace ARDOUR {
|
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
|
class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -82,6 +105,8 @@ class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlL
|
||||||
XMLNode& state (bool full);
|
XMLNode& state (bool full);
|
||||||
XMLNode& serialize_events ();
|
XMLNode& serialize_events ();
|
||||||
|
|
||||||
|
bool operator!= (const AutomationList &) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void create_curve_if_necessary ();
|
void create_curve_if_necessary ();
|
||||||
int deserialize_events (const XMLNode&);
|
int deserialize_events (const XMLNode&);
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ namespace ARDOUR {
|
||||||
PBD::PropertyDescriptor<bool> fade_out_is_short;
|
PBD::PropertyDescriptor<bool> fade_out_is_short;
|
||||||
PBD::PropertyDescriptor<bool> fade_in_is_xfade;
|
PBD::PropertyDescriptor<bool> fade_in_is_xfade;
|
||||||
PBD::PropertyDescriptor<bool> fade_in_is_short;
|
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));
|
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"));
|
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));
|
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
|
void
|
||||||
|
|
@ -181,6 +196,11 @@ AudioRegion::register_properties ()
|
||||||
add_property (_fade_out_is_short);
|
add_property (_fade_out_is_short);
|
||||||
add_property (_fade_in_is_xfade);
|
add_property (_fade_in_is_xfade);
|
||||||
add_property (_fade_in_is_short);
|
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 \
|
#define AUDIOREGION_STATE_DEFAULT \
|
||||||
|
|
@ -193,7 +213,11 @@ AudioRegion::register_properties ()
|
||||||
, _fade_in_is_xfade (Properties::fade_in_is_xfade, false) \
|
, _fade_in_is_xfade (Properties::fade_in_is_xfade, false) \
|
||||||
, _fade_out_is_xfade (Properties::fade_out_is_xfade, false) \
|
, _fade_out_is_xfade (Properties::fade_out_is_xfade, false) \
|
||||||
, _fade_in_is_short (Properties::fade_in_is_short, 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) \
|
#define AUDIOREGION_COPY_STATE(other) \
|
||||||
_envelope_active (Properties::envelope_active, other->_envelope_active) \
|
_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_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_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_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() */
|
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -227,12 +255,8 @@ AudioRegion::init ()
|
||||||
AudioRegion::AudioRegion (Session& s, framepos_t start, framecnt_t len, std::string name)
|
AudioRegion::AudioRegion (Session& s, framepos_t start, framecnt_t len, std::string name)
|
||||||
: Region (s, start, len, name, DataType::AUDIO)
|
: Region (s, start, len, name, DataType::AUDIO)
|
||||||
, AUDIOREGION_STATE_DEFAULT
|
, AUDIOREGION_STATE_DEFAULT
|
||||||
|
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation))))
|
||||||
, _automatable (s)
|
, _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_in_suspended (0)
|
||||||
, _fade_out_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)
|
AudioRegion::AudioRegion (const SourceList& srcs)
|
||||||
: Region (srcs)
|
: Region (srcs)
|
||||||
, AUDIOREGION_STATE_DEFAULT
|
, AUDIOREGION_STATE_DEFAULT
|
||||||
|
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation))))
|
||||||
, _automatable(srcs[0]->session())
|
, _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_in_suspended (0)
|
||||||
, _fade_out_suspended (0)
|
, _fade_out_suspended (0)
|
||||||
{
|
{
|
||||||
|
|
@ -260,15 +280,11 @@ AudioRegion::AudioRegion (const SourceList& srcs)
|
||||||
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
|
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
|
||||||
: Region (other)
|
: Region (other)
|
||||||
, AUDIOREGION_COPY_STATE (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
|
/* 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.
|
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_in_suspended (0)
|
||||||
, _fade_out_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)
|
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, framecnt_t offset)
|
||||||
: Region (other, offset)
|
: Region (other, offset)
|
||||||
, AUDIOREGION_COPY_STATE (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
|
/* 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.
|
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_in_suspended (0)
|
||||||
, _fade_out_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)
|
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const SourceList& srcs)
|
||||||
: Region (boost::static_pointer_cast<const Region>(other), srcs)
|
: Region (boost::static_pointer_cast<const Region>(other), srcs)
|
||||||
, AUDIOREGION_COPY_STATE (other)
|
, AUDIOREGION_COPY_STATE (other)
|
||||||
|
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val())))
|
||||||
, _automatable (other->session())
|
, _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_in_suspended (0)
|
||||||
, _fade_out_suspended (0)
|
, _fade_out_suspended (0)
|
||||||
{
|
{
|
||||||
|
|
@ -335,12 +343,8 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const Sour
|
||||||
AudioRegion::AudioRegion (SourceList& srcs)
|
AudioRegion::AudioRegion (SourceList& srcs)
|
||||||
: Region (srcs)
|
: Region (srcs)
|
||||||
, AUDIOREGION_STATE_DEFAULT
|
, AUDIOREGION_STATE_DEFAULT
|
||||||
|
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList(Evoral::Parameter(EnvelopeAutomation))))
|
||||||
, _automatable(srcs[0]->session())
|
, _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_in_suspended (0)
|
||||||
, _fade_out_suspended (0)
|
, _fade_out_suspended (0)
|
||||||
{
|
{
|
||||||
|
|
@ -988,7 +992,7 @@ void
|
||||||
AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
|
AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
|
||||||
{
|
{
|
||||||
_fade_in->freeze ();
|
_fade_in->freeze ();
|
||||||
*_fade_in = *f;
|
*(_fade_in.val()) = *f;
|
||||||
_fade_in->thaw ();
|
_fade_in->thaw ();
|
||||||
_default_fade_in = false;
|
_default_fade_in = false;
|
||||||
|
|
||||||
|
|
@ -1010,23 +1014,23 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
|
||||||
case FadeLinear:
|
case FadeLinear:
|
||||||
_fade_in->fast_simple_add (0.0, 0.0);
|
_fade_in->fast_simple_add (0.0, 0.0);
|
||||||
_fade_in->fast_simple_add (len, 1.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;
|
break;
|
||||||
|
|
||||||
case FadeFast:
|
case FadeFast:
|
||||||
generate_db_fade (_fade_in, len, 10, -60);
|
generate_db_fade (_fade_in.val(), len, 10, -60);
|
||||||
reverse_curve (c1, _fade_in);
|
reverse_curve (c1, _fade_in.val());
|
||||||
_fade_in->copy_events (*c1);
|
_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;
|
break;
|
||||||
|
|
||||||
case FadeSlow:
|
case FadeSlow:
|
||||||
generate_db_fade (c1, len, 10, -1); // start off with a slow fade
|
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
|
generate_db_fade (c2, len, 10, -80); // end with a fast fade
|
||||||
merge_curves (_fade_in, c1, c2);
|
merge_curves (_fade_in.val(), c1, c2);
|
||||||
reverse_curve (c3, _fade_in);
|
reverse_curve (c3, _fade_in.val());
|
||||||
_fade_in->copy_events (*c3);
|
_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;
|
break;
|
||||||
|
|
||||||
case FadeConstantPower:
|
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*dist, sin (dist*M_PI/2));
|
||||||
}
|
}
|
||||||
_fade_in->fast_simple_add (len, 1.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;
|
break;
|
||||||
|
|
||||||
case FadeSymmetric:
|
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* (breakpoint+((1.0-breakpoint)*(double)i/(double)num_steps)), coeff);
|
||||||
}
|
}
|
||||||
_fade_in->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
_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);
|
_fade_in->copy_events (*c3);
|
||||||
reverse_curve (_inverse_fade_in, _fade_in );
|
reverse_curve (_inverse_fade_in.val(), _fade_in.val());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1068,7 +1072,7 @@ void
|
||||||
AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
|
AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
|
||||||
{
|
{
|
||||||
_fade_out->freeze ();
|
_fade_out->freeze ();
|
||||||
*_fade_out = *f;
|
*(_fade_out.val()) = *f;
|
||||||
_fade_out->thaw ();
|
_fade_out->thaw ();
|
||||||
_default_fade_out = false;
|
_default_fade_out = false;
|
||||||
|
|
||||||
|
|
@ -1089,19 +1093,19 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
|
||||||
case FadeLinear:
|
case FadeLinear:
|
||||||
_fade_out->fast_simple_add (0.0, 1.0);
|
_fade_out->fast_simple_add (0.0, 1.0);
|
||||||
_fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
_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;
|
break;
|
||||||
|
|
||||||
case FadeFast:
|
case FadeFast:
|
||||||
generate_db_fade (_fade_out, len, 10, -60);
|
generate_db_fade (_fade_out.val(), len, 10, -60);
|
||||||
generate_inverse_power_curve (_inverse_fade_out, _fade_out);
|
generate_inverse_power_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FadeSlow:
|
case FadeSlow:
|
||||||
generate_db_fade (c1, len, 10, -1); //start off with a slow fade
|
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
|
generate_db_fade (c2, len, 10, -80); //end with a fast fade
|
||||||
merge_curves (_fade_out, c1, c2);
|
merge_curves (_fade_out.val(), c1, c2);
|
||||||
generate_inverse_power_curve (_inverse_fade_out, _fade_out);
|
generate_inverse_power_curve (_inverse_fade_out.val(), _fade_out.val());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FadeConstantPower:
|
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 * dist), cos(dist*M_PI/2));
|
||||||
}
|
}
|
||||||
_fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
_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;
|
break;
|
||||||
|
|
||||||
case FadeSymmetric:
|
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* (breakpoint+((1.0-breakpoint)*(double)i/(double)num_steps)), coeff);
|
||||||
}
|
}
|
||||||
_fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL);
|
_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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -510,3 +510,24 @@ AutomationList::set_state (const XMLNode& node, int version)
|
||||||
return 0;
|
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;
|
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
|
void
|
||||||
setup_hardware_optimization (bool try_optimization)
|
setup_hardware_optimization (bool try_optimization)
|
||||||
{
|
{
|
||||||
|
|
@ -248,7 +220,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization)
|
||||||
PBD::ID::init ();
|
PBD::ID::init ();
|
||||||
SessionEvent::init_event_pool ();
|
SessionEvent::init_event_pool ();
|
||||||
|
|
||||||
make_property_quarks ();
|
|
||||||
SessionObject::make_property_quarks ();
|
SessionObject::make_property_quarks ();
|
||||||
Region::make_property_quarks ();
|
Region::make_property_quarks ();
|
||||||
MidiRegion::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 = bld(features = 'cxx cxxprogram')
|
||||||
testobj.source = '''
|
testobj.source = '''
|
||||||
test/dummy_lxvst.cc
|
test/dummy_lxvst.cc
|
||||||
|
test/test_util.cc
|
||||||
test/test_needing_session.cc
|
test/test_needing_session.cc
|
||||||
test/audio_region_test.cc
|
test/audio_region_test.cc
|
||||||
test/test_globals.cc
|
test/test_globals.cc
|
||||||
test/audio_region_read_test.cc
|
test/audio_region_read_test.cc
|
||||||
|
test/automation_list_property_test.cc
|
||||||
test/bbt_test.cc
|
test/bbt_test.cc
|
||||||
test/tempo_test.cc
|
test/tempo_test.cc
|
||||||
test/interpolation_test.cc
|
test/interpolation_test.cc
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,8 @@ public:
|
||||||
static void set_thinning_factor (double d);
|
static void set_thinning_factor (double d);
|
||||||
static double thinning_factor() { return _thinning_factor; }
|
static double thinning_factor() { return _thinning_factor; }
|
||||||
|
|
||||||
|
bool operator!= (ControlList const &) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** Called by unlocked_eval() to handle cases of 3 or more control points. */
|
/** 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;
|
_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
|
} // namespace Evoral
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "pbd/property_basics.h"
|
#include "pbd/property_basics.h"
|
||||||
#include "pbd/property_list.h"
|
#include "pbd/property_list.h"
|
||||||
#include "pbd/enumwriter.h"
|
#include "pbd/enumwriter.h"
|
||||||
|
#include "pbd/stateful.h"
|
||||||
|
|
||||||
namespace PBD {
|
namespace PBD {
|
||||||
|
|
||||||
|
|
@ -342,6 +343,120 @@ private:
|
||||||
EnumProperty (EnumProperty const &);
|
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 */
|
} /* namespace PBD */
|
||||||
|
|
||||||
#include "pbd/property_list_impl.h"
|
#include "pbd/property_list_impl.h"
|
||||||
|
|
|
||||||
|
|
@ -652,13 +652,19 @@ static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string& xpath)
|
||||||
void
|
void
|
||||||
XMLNode::dump (ostream& s, string p) const
|
XMLNode::dump (ostream& s, string p) const
|
||||||
{
|
{
|
||||||
s << p << _name << " ";
|
if (_is_content) {
|
||||||
|
s << p << " " << content() << "\n";
|
||||||
|
} else {
|
||||||
|
s << p << "<" << _name;
|
||||||
for (XMLPropertyList::const_iterator i = _proplist.begin(); i != _proplist.end(); ++i) {
|
for (XMLPropertyList::const_iterator i = _proplist.begin(); i != _proplist.end(); ++i) {
|
||||||
s << (*i)->name() << "=" << (*i)->value() << " ";
|
s << " " << (*i)->name() << "=\"" << (*i)->value() << "\"";
|
||||||
}
|
}
|
||||||
s << "\n";
|
s << ">\n";
|
||||||
|
|
||||||
for (XMLNodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
|
for (XMLNodeList::const_iterator i = _children.begin(); i != _children.end(); ++i) {
|
||||||
(*i)->dump (s, p + " ");
|
(*i)->dump (s, p + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s << p << "</" << _name << ">\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue