summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-09-19 00:47:49 +0000
committerDavid Robillard <d@drobilla.net>2008-09-19 00:47:49 +0000
commitd357eca668044badcb4bab318e2e74cfffa9a0b0 (patch)
treeeab9bf33b194f9e37c20f84375e5caa748ee994a /libs/ardour
parent3d976c5b727e4d55ce439b1d7c055a814477fa1a (diff)
Factor out sequencing related things into an independant new library: "evoral".
Anything related to the storage of events/values over a range of time lives in evoral. This includes MidiModel (Evoral::Sequence) and automation data (AutomationList (Evoral::ControlList), Automatable (Evoral::ControlSet), etc). libs/evoral synced with http://svn.drobilla.net/lad/trunk/evoral r1511. git-svn-id: svn://localhost/ardour2/branches/3.0@3754 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/SConscript2
-rw-r--r--libs/ardour/ardour/automatable.h34
-rw-r--r--libs/ardour/ardour/automation_control.h40
-rw-r--r--libs/ardour/ardour/automation_event.h238
-rw-r--r--libs/ardour/ardour/midi_buffer.h14
-rw-r--r--libs/ardour/ardour/midi_model.h161
-rw-r--r--libs/ardour/ardour/midi_region.h4
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h11
-rw-r--r--libs/ardour/ardour/midi_source.h2
-rw-r--r--libs/ardour/ardour/midi_track.h2
-rw-r--r--libs/ardour/ardour/note.h82
-rw-r--r--libs/ardour/ardour/panner.h10
-rw-r--r--libs/ardour/ardour/parameter.h156
-rw-r--r--libs/ardour/ardour/plugin_insert.h2
-rw-r--r--libs/ardour/ardour/smf_source.h4
-rw-r--r--libs/ardour/audio_track.cc6
-rw-r--r--libs/ardour/audioregion.cc48
-rw-r--r--libs/ardour/automatable.cc201
-rw-r--r--libs/ardour/automation_control.cc41
-rw-r--r--libs/ardour/automation_event.cc1264
-rw-r--r--libs/ardour/crossfade.cc12
-rw-r--r--libs/ardour/gain.cc2
-rw-r--r--libs/ardour/import.cc2
-rw-r--r--libs/ardour/io.cc21
-rw-r--r--libs/ardour/jack_midi_port.cc2
-rw-r--r--libs/ardour/meter.cc2
-rw-r--r--libs/ardour/midi_buffer.cc14
-rw-r--r--libs/ardour/midi_diskstream.cc2
-rw-r--r--libs/ardour/midi_model.cc689
-rw-r--r--libs/ardour/midi_source.cc2
-rw-r--r--libs/ardour/midi_stretch.cc2
-rw-r--r--libs/ardour/midi_track.cc4
-rw-r--r--libs/ardour/note.cc110
-rw-r--r--libs/ardour/panner.cc22
-rw-r--r--libs/ardour/parameter.cc8
-rw-r--r--libs/ardour/plugin_insert.cc41
-rw-r--r--libs/ardour/route.cc4
-rw-r--r--libs/ardour/smf_source.cc6
38 files changed, 364 insertions, 2903 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 4bdbf7d88a..b51e81c2ca 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -109,7 +109,6 @@ mix.cc
mtc_slave.cc
midi_clock_slave.cc
named_selection.cc
-note.cc
onset_detector.cc
panner.cc
parameter.cc
@@ -330,6 +329,7 @@ ardour.Merge ([
libraries['glibmm2'],
libraries['lrdf'],
libraries['midi++2'],
+ libraries['evoral'],
libraries['pbd'],
libraries['raptor'],
libraries['samplerate'],
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index a2c1d98ae7..ce31721802 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -27,49 +27,33 @@
#include <ardour/automation_event.h>
#include <ardour/automation_control.h>
#include <ardour/parameter.h>
+#include <evoral/ControlSet.hpp>
namespace ARDOUR {
class Session;
class AutomationControl;
-class Automatable : public SessionObject
+class Automatable : public SessionObject, virtual public Evoral::ControlSet
{
public:
Automatable(Session&, const std::string& name);
virtual ~Automatable() {}
- // shorthand for gain, pan, etc
- inline boost::shared_ptr<AutomationControl>
- control(AutomationType type, bool create_if_missing=false) {
- return control(Parameter(type), create_if_missing);
- }
-
- virtual boost::shared_ptr<AutomationControl> control(Parameter id, bool create_if_missing=false);
- virtual boost::shared_ptr<const AutomationControl> control(Parameter id) const;
+ boost::shared_ptr<Evoral::Control> control_factory(boost::shared_ptr<Evoral::ControlList> list) const;
+ boost::shared_ptr<Evoral::ControlList> control_list_factory(const Evoral::Parameter& param) const;
- boost::shared_ptr<AutomationControl> control_factory(boost::shared_ptr<AutomationList> list);
+ virtual void add_control(boost::shared_ptr<Evoral::Control>);
- typedef std::map<Parameter,boost::shared_ptr<AutomationControl> > Controls;
- Controls& controls() { return _controls; }
- const Controls& controls() const { return _controls; }
-
- virtual void add_control(boost::shared_ptr<AutomationControl>);
-
virtual void automation_snapshot(nframes_t now, bool force);
bool should_snapshot (nframes_t now) {
return (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval);
}
virtual void transport_stopped(nframes_t now);
- virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
-
virtual string describe_parameter(Parameter param);
- virtual float default_parameter_value(Parameter param) { return 1.0f; }
- virtual void clear_automation();
-
AutoState get_parameter_automation_state (Parameter param, bool lock = true);
virtual void set_parameter_automation_state (Parameter param, AutoState);
@@ -78,14 +62,11 @@ public:
void protect_automation ();
- void what_has_automation(std::set<Parameter>&) const;
- void what_has_visible_automation(std::set<Parameter>&) const;
+ void what_has_visible_data(std::set<Parameter>&) const;
const std::set<Parameter>& what_can_be_automated() const { return _can_automate_list; }
void mark_automation_visible(Parameter, bool);
- Glib::Mutex& automation_lock() const { return _automation_lock; }
-
static void set_automation_interval (jack_nframes_t frames) {
_automation_interval = frames;
}
@@ -106,9 +87,6 @@ protected:
int load_automation (const std::string& path);
int old_set_automation_state(const XMLNode&);
- mutable Glib::Mutex _automation_lock;
-
- Controls _controls;
std::set<Parameter> _visible_controls;
std::set<Parameter> _can_automate_list;
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index 68ac5797dc..c414f7bc40 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -24,6 +24,8 @@
#include <boost/shared_ptr.hpp>
#include <pbd/controllable.h>
#include <ardour/parameter.h>
+#include <evoral/Control.hpp>
+#include <ardour/automation_event.h>
namespace ARDOUR {
@@ -34,28 +36,42 @@ class Automatable;
/** A PBD:Controllable with associated automation data (AutomationList)
*/
-class AutomationControl : public PBD::Controllable
+class AutomationControl : public PBD::Controllable, public Evoral::Control
{
public:
AutomationControl(ARDOUR::Session&,
boost::shared_ptr<ARDOUR::AutomationList>,
std::string name="unnamed controllable");
+
+ boost::shared_ptr<AutomationList> alist() { return boost::dynamic_pointer_cast<AutomationList>(_list); }
+
+ void set_list(boost::shared_ptr<Evoral::ControlList>);
+
+ inline bool automation_playback() const {
+ return ((ARDOUR::AutomationList*)_list.get())->automation_playback();
+ }
+
+ inline bool automation_write() const {
+ return ((ARDOUR::AutomationList*)_list.get())->automation_write();
+ }
+
+ inline AutoState automation_state() {
+ return ((ARDOUR::AutomationList*)_list.get())->automation_state();
+ }
+
+ inline void start_touch() {
+ return ((ARDOUR::AutomationList*)_list.get())->start_touch();
+ }
+
+ inline void stop_touch() {
+ return ((ARDOUR::AutomationList*)_list.get())->stop_touch();
+ }
void set_value(float val);
float get_value() const;
- float user_value() const;
-
- void set_list(boost::shared_ptr<ARDOUR::AutomationList>);
-
- boost::shared_ptr<ARDOUR::AutomationList> list() { return _list; }
- boost::shared_ptr<const ARDOUR::AutomationList> list() const { return _list; }
-
- Parameter parameter() const;
protected:
- ARDOUR::Session& _session;
- boost::shared_ptr<ARDOUR::AutomationList> _list;
- float _user_value;
+ ARDOUR::Session& _session;
};
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index 4362b9c867..ed3379bc15 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -37,105 +37,29 @@
#include <ardour/ardour.h>
#include <ardour/parameter.h>
-namespace ARDOUR {
-
-class Curve;
-
-struct ControlEvent {
-
- ControlEvent (double w, double v)
- : when (w), value (v), coeff (0) {
- }
+#include <evoral/ControlList.hpp>
- ControlEvent (const ControlEvent& other)
- : when (other.when), value (other.value), coeff (0) {
- if (other.coeff) {
- create_coeffs();
- for (size_t i=0; i < 4; ++i)
- coeff[i] = other.coeff[i];
- }
- }
-
- ~ControlEvent() { if (coeff) delete[] coeff; }
+using Evoral::ControlEvent;
- void create_coeffs() {
- if (!coeff)
- coeff = new double[4];
-
- coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
- }
-
- double when;
- double value;
- double* coeff; ///< double[4] allocated by Curve as needed
-};
-
-/* automation lists use a pool allocator that does not use a lock and
- allocates 8k of new pointers at a time
-*/
-
-typedef boost::fast_pool_allocator<ControlEvent*,
- boost::default_user_allocator_new_delete,
- boost::details::pool::null_mutex,
- 8192> ControlEventAllocator;
+namespace ARDOUR {
-class AutomationList : public PBD::StatefulDestructible
+class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlList
{
public:
- typedef std::list<ControlEvent*,ControlEventAllocator> EventList;
- typedef EventList::iterator iterator;
- typedef EventList::reverse_iterator reverse_iterator;
- typedef EventList::const_iterator const_iterator;
-
- AutomationList (Parameter id, double min_val, double max_val, double default_val);
+ AutomationList (Parameter id);
AutomationList (const XMLNode&, Parameter id);
~AutomationList();
+ virtual boost::shared_ptr<Evoral::ControlList> create(Evoral::Parameter id);
+
AutomationList (const AutomationList&);
AutomationList (const AutomationList&, double start, double end);
AutomationList& operator= (const AutomationList&);
bool operator== (const AutomationList&);
-
- const Parameter& parameter() const { return _parameter; }
- void set_parameter(Parameter p) { _parameter = p; }
-
+
void freeze();
void thaw ();
-
- EventList::size_type size() const { return _events.size(); }
- bool empty() const { return _events.empty(); }
-
- void reset_default (double val) {
- _default_value = val;
- }
-
- void clear ();
- void x_scale (double factor);
- bool extend_to (double);
- void slide (iterator before, double distance);
-
- void reposition_for_rt_add (double when);
- void rt_add (double when, double value);
- void add (double when, double value);
- /* this should be private but old-school automation loading needs it in IO/IOProcessor */
- void fast_simple_add (double when, double value);
-
- void reset_range (double start, double end);
- void erase_range (double start, double end);
- void erase (iterator);
- void erase (iterator, iterator);
- void move_range (iterator start, iterator end, double, double);
- void modify (iterator, double, double);
-
- AutomationList* cut (double, double);
- AutomationList* copy (double, double);
- void clear (double, double);
-
- AutomationList* cut (iterator, iterator);
- AutomationList* copy (iterator, iterator);
- void clear (iterator, iterator);
-
- bool paste (AutomationList&, double position, float times);
+ void mark_dirty () const;
void set_automation_state (AutoState);
AutoState automation_state() const { return _state; }
@@ -151,157 +75,29 @@ class AutomationList : public PBD::StatefulDestructible
bool automation_write () const {
return (_state & Write) || ((_state & Touch) && _touching);
}
+
+ sigc::signal<void> StateChanged;
+
+ static sigc::signal<void, AutomationList*> AutomationListCreated;
+ mutable sigc::signal<void> Dirty;
void start_touch ();
void stop_touch ();
bool touching() const { return _touching; }
- void set_yrange (double min, double max) {
- _min_yval = min;
- _max_yval = max;
- }
-
- double get_max_y() const { return _max_yval; }
- double get_min_y() const { return _min_yval; }
-
- void truncate_end (double length);
- void truncate_start (double length);
-
- iterator begin() { return _events.begin(); }
- iterator end() { return _events.end(); }
-
- ControlEvent* back() { return _events.back(); }
- ControlEvent* front() { return _events.front(); }
-
- const_iterator const_begin() const { return _events.begin(); }
- const_iterator const_end() const { return _events.end(); }
-
- std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
-
- template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
- Glib::Mutex::Lock lm (_lock);
- (obj.*method)(*this);
- }
-
- sigc::signal<void> StateChanged;
-
XMLNode& get_state(void);
int set_state (const XMLNode &s);
XMLNode& state (bool full);
XMLNode& serialize_events ();
- void set_max_xval (double);
- double get_max_xval() const { return _max_xval; }
-
- double eval (double where) {
- Glib::Mutex::Lock lm (_lock);
- return unlocked_eval (where);
- }
-
- double rt_safe_eval (double where, bool& ok) {
-
- Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
-
- if ((ok = lm.locked())) {
- return unlocked_eval (where);
- } else {
- return 0.0;
- }
- }
-
- static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) {
- return a->when < b->when;
- }
-
- /** Lookup cache for eval functions, range contains equivalent values */
- struct LookupCache {
- LookupCache() : left(-1) {}
- double left; /* leftmost x coordinate used when finding "range" */
- std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
- };
-
- /** Lookup cache for point finding, range contains points between left and right */
- struct SearchCache {
- SearchCache() : left(-1), right(-1) {}
- double left; /* leftmost x coordinate used when finding "range" */
- double right; /* rightmost x coordinate used when finding "range" */
- std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
- };
-
- static sigc::signal<void, AutomationList*> AutomationListCreated;
-
- const EventList& events() const { return _events; }
- double default_value() const { return _default_value; }
-
- // teeny const violations for Curve
- mutable sigc::signal<void> Dirty;
- Glib::Mutex& lock() const { return _lock; }
- LookupCache& lookup_cache() const { return _lookup_cache; }
- SearchCache& search_cache() const { return _search_cache; }
-
- /** Called by locked entry point and various private
- * locations where we already hold the lock.
- *
- * FIXME: Should this be private? Curve needs it..
- */
- double unlocked_eval (double x) const;
-
- bool rt_safe_earliest_event (double start, double end, double& x, double& y, bool start_inclusive=false) const;
- bool rt_safe_earliest_event_unlocked (double start, double end, double& x, double& y, bool start_inclusive=false) const;
-
- Curve& curve() { return *_curve; }
- const Curve& curve() const { return *_curve; }
-
- enum InterpolationStyle {
- Discrete,
- Linear,
- Curved
- };
-
- InterpolationStyle interpolation() const { return _interpolation; }
- void set_interpolation(InterpolationStyle style) { _interpolation = style; }
-
private:
-
- /** Called by unlocked_eval() to handle cases of 3 or more control points.
- */
- double multipoint_eval (double x) const;
-
- void build_search_cache_if_necessary(double start, double end) const;
-
- bool rt_safe_earliest_event_discrete_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
- bool rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
-
- AutomationList* cut_copy_clear (double, double, int op);
-
int deserialize_events (const XMLNode&);
void maybe_signal_changed ();
- void mark_dirty ();
- void _x_scale (double factor);
-
- mutable LookupCache _lookup_cache;
- mutable SearchCache _search_cache;
- Parameter _parameter;
- InterpolationStyle _interpolation;
- EventList _events;
- mutable Glib::Mutex _lock;
- int8_t _frozen;
- bool _changed_when_thawed;
- AutoState _state;
- AutoStyle _style;
- bool _touching;
- bool _new_touch;
- double _max_xval;
- double _min_yval;
- double _max_yval;
- double _default_value;
- bool _sort_pending;
- iterator _rt_insertion_point;
- double _rt_pos;
-
- Curve* _curve;
+ AutoState _state;
+ AutoStyle _style;
+ bool _touching;
};
} // namespace
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h
index 699f461b17..0c13199825 100644
--- a/libs/ardour/ardour/midi_buffer.h
+++ b/libs/ardour/ardour/midi_buffer.h
@@ -39,7 +39,7 @@ public:
void copy(const MidiBuffer& copy);
- bool push_back(const MIDI::Event& event);
+ bool push_back(const Evoral::Event& event);
bool push_back(const jack_midi_event_t& event);
uint8_t* reserve(double time, size_t size);
@@ -50,7 +50,7 @@ public:
struct iterator {
iterator(MidiBuffer& b, size_t i) : buffer(b), index(i) {}
- inline MIDI::Event& operator*() const { return buffer[index]; }
+ inline Evoral::Event& operator*() const { return buffer[index]; }
inline iterator& operator++() { ++index; return *this; } // prefix
inline bool operator!=(const iterator& other) const { return index != other.index; }
@@ -61,7 +61,7 @@ public:
struct const_iterator {
const_iterator(const MidiBuffer& b, size_t i) : buffer(b), index(i) {}
- inline const MIDI::Event& operator*() const { return buffer[index]; }
+ inline const Evoral::Event& operator*() const { return buffer[index]; }
inline const_iterator& operator++() { ++index; return *this; } // prefix
inline bool operator!=(const const_iterator& other) const { return index != other.index; }
@@ -80,8 +80,8 @@ private:
friend class iterator;
friend class const_iterator;
- const MIDI::Event& operator[](size_t i) const { assert(i < _size); return _events[i]; }
- MIDI::Event& operator[](size_t i) { assert(i < _size); return _events[i]; }
+ const Evoral::Event& operator[](size_t i) const { assert(i < _size); return _events[i]; }
+ Evoral::Event& operator[](size_t i) { assert(i < _size); return _events[i]; }
// FIXME: Eliminate this
static const size_t MAX_EVENT_SIZE = 4; // bytes
@@ -92,8 +92,8 @@ private:
/* FIXME: this is utter crap. rewrite as a flat/packed buffer like MidiRingBuffer */
- MIDI::Event* _events; ///< Event structs that point to offsets in _data
- uint8_t* _data; ///< MIDI, straight up. No time stamps.
+ Evoral::Event* _events; ///< Event structs that point to offsets in _data
+ uint8_t* _data; ///< MIDI, straight up. No time stamps.
};
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index 2481aa8d34..51bddfde44 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -31,84 +31,28 @@
#include <ardour/midi_buffer.h>
#include <ardour/midi_ring_buffer.h>
#include <ardour/automatable.h>
-#include <ardour/note.h>
#include <ardour/types.h>
+#include <evoral/Note.hpp>
+#include <evoral/Sequence.hpp>
namespace ARDOUR {
class Session;
class MidiSource;
-/**
- * This class keeps track of the current x and y for a control
- */
-class MidiControlIterator {
-public:
- boost::shared_ptr<const AutomationList> automation_list;
- double x;
- double y;
-
- MidiControlIterator(boost::shared_ptr<const AutomationList> a_list,
- double a_x,
- double a_y)
- : automation_list(a_list)
- , x(a_x)
- , y(a_y)
- {}
-};
-
-
/** This is a higher level (than MidiBuffer) model of MIDI data, with separate
* representations for notes (instead of just unassociated note on/off events)
* and controller data. Controller data is represented as part of the
* Automatable base (i.e. in a map of AutomationList, keyed by Parameter).
+ * Because of this MIDI controllers and automatable controllers/widgets/etc
+ * are easily interchangeable.
*/
-class MidiModel : public boost::noncopyable, public Automatable {
+class MidiModel : public Automatable, public Evoral::Sequence {
public:
MidiModel(MidiSource* s, size_t size=0);
- void write_lock();
- void write_unlock();
-
- void read_lock() const;
- void read_unlock() const;
-
- void clear();
-
- NoteMode note_mode() const { return _note_mode; }
- void set_note_mode(NoteMode mode) { _note_mode = mode; }
-
- void start_write();
- bool writing() const { return _writing; }
- void end_write(bool delete_stuck=false);
-
- size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset, nframes_t negative_stamp_offset) const;
-
- /** Resizes vector if necessary (NOT realtime safe) */
- void append(const MIDI::Event& ev);
-
- inline const boost::shared_ptr<const Note> note_at(unsigned i) const { return _notes[i]; }
- inline const boost::shared_ptr<Note> note_at(unsigned i) { return _notes[i]; }
-
- inline size_t n_notes() const { return _notes.size(); }
- inline bool empty() const { return _notes.size() == 0 && _controls.size() == 0; }
-
- inline static bool note_time_comparator (const boost::shared_ptr<const Note> a,
- const boost::shared_ptr<const Note> b) {
- return a->time() < b->time();
- }
-
- struct LaterNoteEndComparator {
- typedef const Note* value_type;
- inline bool operator()(const boost::shared_ptr<const Note> a,
- const boost::shared_ptr<const Note> b) const {
- return a->end_time() > b->end_time();
- }
- };
-
- typedef std::vector< boost::shared_ptr<Note> > Notes;
- inline Notes& notes() { return _notes; }
- inline const Notes& notes() const { return _notes; }
+ NoteMode note_mode() const { return (percussive() ? Percussive : Sustained); }
+ void set_note_mode(NoteMode mode) { set_percussive(mode == Percussive); };
/** Add/Remove notes.
* Technically all operations can be implemented as one of these.
@@ -127,17 +71,17 @@ public:
int set_state (const XMLNode&);
XMLNode& get_state ();
- void add(const boost::shared_ptr<Note> note);
- void remove(const boost::shared_ptr<Note> note);
+ void add(const boost::shared_ptr<Evoral::Note> note);
+ void remove(const boost::shared_ptr<Evoral::Note> note);
private:
- XMLNode &marshal_note(const boost::shared_ptr<Note> note);
- boost::shared_ptr<Note> unmarshal_note(XMLNode *xml_note);
+ XMLNode &marshal_note(const boost::shared_ptr<Evoral::Note> note);
+ boost::shared_ptr<Evoral::Note> unmarshal_note(XMLNode *xml_note);
boost::shared_ptr<MidiModel> _model;
const std::string _name;
- typedef std::list< boost::shared_ptr<Note> > NoteList;
+ typedef std::list< boost::shared_ptr<Evoral::Note> > NoteList;
NoteList _added_notes;
NoteList _removed_notes;
@@ -146,8 +90,6 @@ public:
MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit");
void apply_command(Command* cmd);
- bool edited() const { return _edited; }
- void set_edited(bool yn) { _edited = yn; }
bool write_to(boost::shared_ptr<MidiSource> source);
// MidiModel doesn't use the normal AutomationList serialisation code
@@ -157,90 +99,11 @@ public:
sigc::signal<void> ContentsChanged;
- /** Read iterator */
- class const_iterator {
- public:
- const_iterator(const MidiModel& model, double t);
- ~const_iterator();
-
- inline bool locked() const { return _locked; }
-
- const MIDI::Event& operator*() const { return *_event; }
- const boost::shared_ptr<MIDI::Event> operator->() const { return _event; }
- const boost::shared_ptr<MIDI::Event> get_event_pointer() { return _event; }
-
- const const_iterator& operator++(); // prefix only
- bool operator==(const const_iterator& other) const;
- bool operator!=(const const_iterator& other) const { return ! operator==(other); }
-
- const_iterator& operator=(const const_iterator& other);
-
- private:
- friend class MidiModel;
-
- const MidiModel* _model;
- boost::shared_ptr<MIDI::Event> _event;
-
- typedef std::priority_queue<
- boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
- LaterNoteEndComparator>
- ActiveNotes;
-
- mutable ActiveNotes _active_notes;
-
- bool _is_end;
- bool _locked;
- Notes::const_iterator _note_iter;
- std::vector<MidiControlIterator> _control_iters;
- std::vector<MidiControlIterator>::iterator _control_iter;
- };
-
- const_iterator begin() const { return const_iterator(*this, 0); }
- const const_iterator& end() const { return _end_iter; }
-
const MidiSource* midi_source() const { return _midi_source; }
void set_midi_source(MidiSource* source) { _midi_source = source; }
- bool control_to_midi_event(boost::shared_ptr<MIDI::Event>& ev, const MidiControlIterator& iter) const;
private:
friend class DeltaCommand;
- void add_note_unlocked(const boost::shared_ptr<Note> note);
- void remove_note_unlocked(const boost::shared_ptr<const Note> note);
-
- friend class const_iterator;
-
-#ifndef NDEBUG
- bool is_sorted() const;
-#endif
-
- void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
- void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
- void append_automation_event_unlocked(AutomationType type, uint8_t chan, double time, uint8_t first_byte, uint8_t second_byte);
- void append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number);
-
- mutable Glib::RWLock _lock;
-
- Notes _notes;
-
- NoteMode _note_mode;
-
- typedef std::vector<size_t> WriteNotes;
- WriteNotes _write_notes[16];
- bool _writing;
- bool _edited;
-
- typedef std::vector< boost::shared_ptr<const ARDOUR::AutomationList> > AutomationLists;
- AutomationLists _dirty_automations;
-
- const const_iterator _end_iter;
-
- mutable nframes_t _next_read;
- mutable const_iterator _read_iter;
-
- typedef std::priority_queue<
- boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
- LaterNoteEndComparator>
- ActiveNotes;
// We cannot use a boost::shared_ptr here to avoid a retain cycle
MidiSource* _midi_source;
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index 44f775dc1c..66257372a9 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -80,10 +80,10 @@ class MidiRegion : public Region
Controls& controls() { return midi_source()->model()->controls(); }
const Controls& controls() const { return midi_source()->model()->controls(); }
- boost::shared_ptr<AutomationControl> control(Parameter id, bool create_if_missing=false)
+ boost::shared_ptr<Evoral::Control> control(Evoral::Parameter id, bool create_if_missing=false)
{ return midi_source()->model()->control(id, create_if_missing); }
- boost::shared_ptr<const AutomationControl> control(Parameter id) const
+ boost::shared_ptr<const Evoral::Control> control(Evoral::Parameter id) const
{ return midi_source()->model()->control(id); }
int exportme (ARDOUR::Session&, ARDOUR::ExportSpecification&);
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index ff0be5c997..db0c3029a8 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -23,6 +23,7 @@
#include <algorithm>
#include <ardour/types.h>
#include <ardour/buffer.h>
+#include <evoral/EventSink.hpp>
namespace ARDOUR {
@@ -243,7 +244,7 @@ MidiRingBufferBase<T>::write(size_t size, const T* src)
*
* [timestamp][size][size bytes of raw MIDI][timestamp][size][etc..]
*/
-class MidiRingBuffer : public MidiRingBufferBase<uint8_t> {
+class MidiRingBuffer : public MidiRingBufferBase<uint8_t>, public Evoral::EventSink {
public:
/** @param size Size in bytes.
*/
@@ -251,8 +252,8 @@ public:
: MidiRingBufferBase<uint8_t>(size), _channel_mask(0x0000FFFF)
{}
- size_t write(double time, size_t size, const uint8_t* buf);
- bool read(double* time, size_t* size, uint8_t* buf);
+ size_t write(double time, uint32_t size, const uint8_t* buf);
+ bool read(double* time, uint32_t* size, uint8_t* buf);
bool read_prefix(double* time, size_t* size);
bool read_contents(size_t size, uint8_t* buf);
@@ -292,7 +293,7 @@ private:
inline bool
-MidiRingBuffer::read(double* time, size_t* size, uint8_t* buf)
+MidiRingBuffer::read(double* time, uint32_t* size, uint8_t* buf)
{
bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)time);
@@ -333,7 +334,7 @@ MidiRingBuffer::read_contents(size_t size, uint8_t* buf)
inline size_t
-MidiRingBuffer::write(double time, size_t size, const uint8_t* buf)
+MidiRingBuffer::write(double time, uint32_t size, const uint8_t* buf)
{
/*fprintf(stderr, "MRB %p write (t = %f) ", this, time);
for (size_t i = 0; i < size; ++i)
diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h
index 997f3f9d69..9cb222d207 100644
--- a/libs/ardour/ardour/midi_source.h
+++ b/libs/ardour/ardour/midi_source.h
@@ -58,7 +58,7 @@ class MidiSource : public Source
virtual nframes_t midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset, nframes_t negative_stamp_offset) const;
virtual nframes_t midi_write (MidiRingBuffer& src, nframes_t cnt);
- virtual void append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev) = 0;
+ virtual void append_event_unlocked(EventTimeUnit unit, const Evoral::Event& ev) = 0;
virtual void mark_for_remove() = 0;
virtual void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time);
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 6e4677df22..7eda6f904b 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -75,7 +75,7 @@ public:
struct MidiControl : public AutomationControl {
MidiControl(MidiTrack* route, boost::shared_ptr<AutomationList> al)
- : AutomationControl (route->session(), al, al->parameter().to_string())
+ : AutomationControl (route->session(), al, al->parameter().symbol())
, _route (route)
{}
diff --git a/libs/ardour/ardour/note.h b/libs/ardour/ardour/note.h
deleted file mode 100644
index 0f649b3370..0000000000
--- a/libs/ardour/ardour/note.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- Copyright (C) 2007 Paul Davis
- Author: Dave Robillard
-
- 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.
-
-*/
-
-#ifndef __ardour_note_h__
-#define __ardour_note_h__
-
-#include <stdint.h>
-#include <midi++/event.h>
-
-namespace ARDOUR {
-
-
-/** A MIDI Note.
- *
- * A note is (unfortunately) special and not just another MIDI::Event as it
- * has a duration and two separate MIDI events (on and off).
- */
-class Note {
-public:
- Note(uint8_t chan=0, double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40);
- Note(const Note& copy);
- ~Note();
-
- const Note& operator=(const Note& copy);
-
- inline bool operator==(const Note& other)
- { return time() == other.time() &&
- note() == other.note() &&
- duration() == other.duration() &&
- velocity() == other.velocity() &&
- channel() == other.channel();
- }
-
- inline double time() const { return _on_event.time(); }
- inline double end_time() const { return _off_event.time(); }
- inline uint8_t note() const { return _on_event.note(); }
- inline uint8_t velocity() const { return _on_event.velocity(); }
- inline double duration() const { return _off_event.time() - _on_event.time(); }
- inline uint8_t channel() const {
- assert(_on_event.channel() == _off_event.channel());
- return _on_event.channel();
- }
-
- inline void set_time(double t) { _off_event.time() = t + duration(); _on_event.time() = t; }
- inline void set_note(uint8_t n) { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; }
- inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; }
- inline void set_duration(double d) { _off_event.time() = _on_event.time() + d; }
- inline void set_channel(uint8_t c) { _on_event.set_channel(c); _off_event.set_channel(c); }
-
- inline MIDI::Event& on_event() { return _on_event; }
- inline MIDI::Event& off_event() { return _off_event; }
-
- inline const MIDI::Event& on_event() const { return _on_event; }
- inline const MIDI::Event& off_event() const { return _off_event; }
-
-private:
- // Event buffers are self-contained
- MIDI::Event _on_event;
- MIDI::Event _off_event;
-};
-
-
-} // namespace ARDOUR
-
-#endif /* __ardour_note_h__ */
diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h
index 2559eed003..1b85495d7a 100644
--- a/libs/ardour/ardour/panner.h
+++ b/libs/ardour/ardour/panner.h
@@ -101,14 +101,16 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
float effective_y;
float effective_z;
- bool _muted;
+ bool _muted;
struct PanControllable : public AutomationControl {
PanControllable (Session& s, std::string name, StreamPanner& p, Parameter param)
- : AutomationControl (s, boost::shared_ptr<AutomationList>(new AutomationList(
- param, 0.0, 1.0, 0.5)), name)
- , panner (p) { assert(param.type() != NullAutomation); }
+ : AutomationControl (s,
+ boost::shared_ptr<AutomationList>(new AutomationList(param)), name)
+ , panner (p)
+ { assert(param.type() != NullAutomation); }
+ AutomationList* alist() { return (AutomationList*)_list.get(); }
StreamPanner& panner;
void set_value (float);
diff --git a/libs/ardour/ardour/parameter.h b/libs/ardour/ardour/parameter.h
index a5dd9cdca9..dbcccd811f 100644
--- a/libs/ardour/ardour/parameter.h
+++ b/libs/ardour/ardour/parameter.h
@@ -24,140 +24,86 @@
#include <pbd/compose.h>
#include <pbd/error.h>
#include <ardour/types.h>
+#include <evoral/Parameter.hpp>
+#include <evoral/MIDIParameters.hpp>
namespace ARDOUR {
-
/** ID of an automatable parameter.
*
* A given automatable object has a number of automatable parameters. This is
* the unique ID for those parameters. Anything automatable (AutomationList,
- * Curve) must have an ID unique with respect to it's Automatable parent.
- *
- * A parameter ID has two parts, a type and an int (only used by some types).
+ * Curve) must have unique Parameter ID with respect to it's Automatable parent.
*
- * This is a bit more ugly than it could be, due to using the existing/legacy
- * ARDOUR::AutomationType: GainAutomation, PanAutomation, SoloAutomation,
- * and MuteAutomation use only the type(), but PluginAutomation and
- * MidiCCAutomation use the id() as port number and CC number, respectively.
+ * These are fast to compare, but passing a (const) reference around is
+ * probably more efficient than copying because the Parameter contains
+ * metadata not used for comparison.
*
- * Future types may use a string or URI or whatever, as long as these are
- * comparable anything may be added. ints are best as these should be fast to
- * copy and compare with one another.
+ * See evoral/Parameter.hpp for precise definition.
*/
-class Parameter
+class Parameter : public Evoral::Parameter
{
public:
Parameter(AutomationType type = NullAutomation, uint32_t id=0, uint8_t channel=0)
- : _type(type), _id(id), _channel(channel)
- {}
-
- Parameter(const std::string& str);
-
- inline AutomationType type() const { return _type; }
- inline uint32_t id() const { return _id; }
- inline uint8_t channel() const { return _channel; }
-
- /**
- * Equivalence operator
- * It is obvious from the definition that this operator
- * is transitive, as required by stict weak ordering
- * (see: http://www.sgi.com/tech/stl/StrictWeakOrdering.html)
- */
- inline bool operator==(const Parameter& id) const {
- return (_type == id._type && _id == id._id && _channel == id._channel);
+ : Evoral::Parameter((uint32_t)type, id, channel)
+ {
+ init(type);
}
- /** Strict weak ordering
- * (see: http://www.sgi.com/tech/stl/StrictWeakOrdering.html)
- * This is necessary so that std::set works):
- * Sort Parameters first according to type then to id and lastly to channel.
- *
- * Proof:
- * <ol>
- * <li>Irreflexivity: f(x, x) is false because of the irreflexivity of \c < in each branch.</li>
- *
- * <li>Antisymmetry: given x != y, f(x, y) implies !f(y, x) because of the same
- * property of \c < in each branch and the symmetry of operator==. </li>
- *
- * <li>Transitivity: let f(x, y) and f(y, z) be true. We prove by assuming the contrary,
- * that f(x, z) does not hold.
- * That would imply exactly one of the following:
- * <ol>
- * <li> x == z which contradicts the assumption f(x, y) and f(y, x)
- * because of antisymmetry.
- * </li>
- * <li> f(z, x) is true. That would imply that one of the ivars (we call it i)
- * of x is greater than the same ivar in z while all "previous" ivars
- * are equal. That would imply that also in y all those "previous"
- * ivars are equal and because if x.i > z.i it is impossible
- * that there is an y that satisfies x.i < y.i < z.i at the same
- * time which contradicts the assumption.
- * </li>
- * </ol>
- * </li>
- * </ol>
- */
- inline bool operator<(const Parameter& id) const {
-#ifndef NDEBUG
- if (_type == NullAutomation)
- PBD::warning << "Uninitialized Parameter compared." << endmsg;
-#endif
- if (_type < id._type) {
- return true;
- } else if (_type == id._type && _id < id._id) {
- return true;
- } else if (_id == id._id && _channel < id._channel) {
- return true;
- }
-
- return false;
+ Parameter(AutomationType type, double min, double max, double normal)
+ : Evoral::Parameter((uint32_t)type, 0, 0, min, max, normal)
+ {}
+
+ Parameter(const Evoral::Parameter& copy)
+ : Evoral::Parameter(copy)
+ {
+ init((AutomationType)_type);
}
- inline operator bool() const { return (_type != 0); }
-
- std::string to_string() const;
-
- /* The below properties are only used for CC right now, but unchanging properties
- * of parameters (rather than changing parameters of automation lists themselves)
- * should be moved here */
-
- inline double min() const {
- switch(_type) {
+ void init(AutomationType type) {
+ _normal = 0.0f;
+ switch(type) {
+ case NullAutomation:
+ case GainAutomation:
+ _min = 0.0f;
+ _max = 2.0f;
+ _normal = 1.0f;
+ break;
+ case PanAutomation:
+ _min = 0.0f;
+ _max = 1.0f;
+ _normal = 0.5f;
+ case PluginAutomation:
+ case SoloAutomation:
+ case MuteAutomation:
+ case FadeInAutomation:
+ case FadeOutAutomation:
+ case EnvelopeAutomation:
+ _min = 0.0f;
+ _max = 2.0f;
+ _normal = 1.0f;
case MidiCCAutomation:
+ Evoral::MIDI::ContinuousController::set_range(*this); break;
case MidiPgmChangeAutomation:
+ Evoral::MIDI::ProgramChange::set_range(*this); break;
case MidiPitchBenderAutomation:
+ Evoral::MIDI::PitchBender::set_range(*this); break;
case MidiChannelAftertouchAutomation:
- return 0.0;
-
- default:
- return DBL_MIN;
+ Evoral::MIDI::ChannelAftertouch::set_range(*this); break;
}
}
- inline double max() const {
- switch(_type) {
- case MidiCCAutomation:
- case MidiPgmChangeAutomation:
- case MidiChannelAftertouchAutomation:
- return 127.0;
- case MidiPitchBenderAutomation:
- return 16383.0;
-
- default:
- return DBL_MAX;
- }
- }
+ Parameter(const std::string& str);
+
+ inline AutomationType type() const { return (AutomationType)_type; }
+
+ std::string symbol() const;
inline bool is_integer() const {
return (_type >= MidiCCAutomation && _type <= MidiChannelAftertouchAutomation);
}
-private:
- // default copy constructor is ok
- AutomationType _type;
- uint32_t _id;
- uint8_t _channel;
+ inline operator Parameter() { return (Parameter)*this; }
};
diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h
index c19d113256..8db9fb14fe 100644
--- a/libs/ardour/ardour/plugin_insert.h
+++ b/libs/ardour/ardour/plugin_insert.h
@@ -77,7 +77,7 @@ class PluginInsert : public Processor
void set_parameter (Parameter param, float val);
float get_parameter (Parameter param);
- float default_parameter_value (Parameter param);
+ float default_parameter_value (Evoral::Parameter param);
struct PluginControl : public AutomationControl
{
diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h
index 88bf1e5d13..3217c8e3e8 100644
--- a/libs/ardour/ardour/smf_source.h
+++ b/libs/ardour/ardour/smf_source.h
@@ -26,6 +26,8 @@
#include <ardour/midi_source.h>
+namespace Evoral { class Event; }
+
namespace ARDOUR {
class MidiRingBuffer;
@@ -71,7 +73,7 @@ class SMFSource : public MidiSource {
void set_allow_remove_if_empty (bool yn);
void mark_for_remove();
- void append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev);
+ void append_event_unlocked(EventTimeUnit unit, const Evoral::Event& ev);
int flush_header ();
int flush_footer ();
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index cd05e5fc86..532abeb123 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -604,9 +604,9 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
if (!diskstream->record_enabled() && _session.transport_rolling()) {
- Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (_control_lock, Glib::TRY_LOCK);
- if (am.locked() && gain_control()->list()->automation_playback()) {
+ if (am.locked() && gain_control()->automation_playback()) {
apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
}
}
@@ -702,7 +702,7 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
}
}
- if (gain_control()->list()->automation_state() == Play) {
+ if (gain_control()->automation_state() == Play) {
gain_control()->list()->curve().get_vector (start, start + nframes, gain_automation, nframes);
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 271544297d..707f10e91a 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -77,9 +77,9 @@ AudioRegion::init ()
/* constructor for use by derived types only */
AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string name)
: Region (s, start, length, name, DataType::AUDIO)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
init ();
}
@@ -87,9 +87,9 @@ AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string
/** Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length)
: Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0, Region::Flag(Region::DefaultFlags|Region::External))
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
@@ -102,9 +102,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (src, start, length, name, DataType::AUDIO, layer, flags)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
@@ -117,9 +117,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (many channels) */
AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
init ();
listen_to_my_sources ();
@@ -128,9 +128,9 @@ AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t len
/** Create a new AudioRegion, that is part of an existing one */
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (other, offset, length, name, layer, flags)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
set<boost::shared_ptr<Source> > unique_srcs;
@@ -180,9 +180,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
: Region (other)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
assert(_type == DataType::AUDIO);
_scale_amplitude = other->_scale_amplitude;
@@ -196,9 +196,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
: Region (src, node)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
@@ -217,9 +217,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
: Region (srcs, node)
- , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
- , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
- , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
+ , _fade_in (new AutomationList(Parameter(FadeInAutomation)))
+ , _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
+ , _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
{
init ();
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index cacebe59a4..349c09e136 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -92,7 +92,7 @@ Automatable::load_automation (const string& path)
return 1;
}
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
set<Parameter> tosave;
_controls.clear ();
@@ -108,7 +108,7 @@ Automatable::load_automation (const string& path)
in >> value; if (!in) goto bad;
/* FIXME: this is legacy and only used for plugin inserts? I think? */
- boost::shared_ptr<AutomationControl> c = control (Parameter(PluginAutomation, port), true);
+ boost::shared_ptr<Evoral::Control> c = control (Parameter(PluginAutomation, port), true);
c->list()->add (when, value);
tosave.insert (Parameter(PluginAutomation, port));
}
@@ -122,12 +122,10 @@ Automatable::load_automation (const string& path)
}
void
-Automatable::add_control(boost::shared_ptr<AutomationControl> ac)
+Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
{
Parameter param = ac->parameter();
- _controls[param] = ac;
-
_can_automate_list.insert(param);
// Sync everything (derived classes) up to initial values
@@ -135,21 +133,9 @@ Automatable::add_control(boost::shared_ptr<AutomationControl> ac)
}
void
-Automatable::what_has_automation (set<Parameter>& s) const
-{
- Glib::Mutex::Lock lm (_automation_lock);
- Controls::const_iterator li;
-
- // FIXME: correct semantics?
- for (li = _controls.begin(); li != _controls.end(); ++li) {
- s.insert ((*li).first);
- }
-}
-
-void
-Automatable::what_has_visible_automation (set<Parameter>& s) const
+Automatable::what_has_visible_data (set<Parameter>& s) const
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
set<Parameter>::const_iterator li;
for (li = _visible_controls.begin(); li != _visible_controls.end(); ++li) {
@@ -157,42 +143,6 @@ Automatable::what_has_visible_automation (set<Parameter>& s) const
}
}
-/** Returns NULL if we don't have an AutomationList for \a parameter.
- */
-boost::shared_ptr<AutomationControl>
-Automatable::control (Parameter parameter, bool create_if_missing)
-{
- Controls::iterator i = _controls.find(parameter);
-
- if (i != _controls.end()) {
- return i->second;
-
- } else if (create_if_missing) {
- boost::shared_ptr<AutomationList> al (new AutomationList (
- parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter)));
- boost::shared_ptr<AutomationControl> ac(control_factory(al));
- add_control(ac);
- return ac;
-
- } else {
- //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
- return boost::shared_ptr<AutomationControl>();
- }
-}
-
-boost::shared_ptr<const AutomationControl>
-Automatable::control (Parameter parameter) const
-{
- Controls::const_iterator i = _controls.find(parameter);
-
- if (i != _controls.end()) {
- return i->second;
- } else {
- //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
- return boost::shared_ptr<AutomationControl>();
- }
-}
-
string
Automatable::describe_parameter (Parameter param)
{
@@ -213,7 +163,7 @@ Automatable::describe_parameter (Parameter param)
} else if (param.type() == MidiChannelAftertouchAutomation) {
return string_compose("Aftertouch [%1]", int(param.channel()) + 1);
} else {
- return param.to_string();
+ return param.symbol();
}
}
@@ -237,37 +187,6 @@ Automatable::mark_automation_visible (Parameter what, bool yn)
}
}
-bool
-Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
-{
- Controls::const_iterator li;
-
- next_event.when = max_frames;
-
- for (li = _controls.begin(); li != _controls.end(); ++li) {
-
- AutomationList::const_iterator i;
- boost::shared_ptr<const AutomationList> alist (li->second->list());
- ControlEvent cp (now, 0.0f);
-
- for (i = lower_bound (alist->const_begin(), alist->const_end(), &cp, AutomationList::time_comparator);
- i != alist->const_end() && (*i)->when < end; ++i) {
- if ((*i)->when > now) {
- break;
- }
- }
-
- if (i != alist->const_end() && (*i)->when < end) {
-
- if ((*i)->when < next_event.when) {
- next_event.when = (*i)->when;
- }
- }
- }
-
- return next_event.when != max_frames;
-}
-
/** \a legacy_param is used for loading legacy sessions where an object (IO, Panner)
* had a single automation parameter, with it's type implicit. Derived objects should
* pass that type and it will be used for the untyped AutomationList found.
@@ -275,7 +194,7 @@ Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_e
int
Automatable::set_automation_state (const XMLNode& node, Parameter legacy_param)
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
/* Don't clear controls, since some may be special derived Controllable classes */
@@ -301,11 +220,11 @@ Automatable::set_automation_state (const XMLNode& node, Parameter legacy_param)
if (!id_prop) {
warning << "AutomationList node without automation-id property, "
- << "using default: " << legacy_param.to_string() << endmsg;
+ << "using default: " << legacy_param.symbol() << endmsg;
al->set_parameter(legacy_param);
}
- boost::shared_ptr<AutomationControl> existing = control(param);
+ boost::shared_ptr<Evoral::Control> existing = control(param);
if (existing)
existing->set_list(al);
else
@@ -324,7 +243,7 @@ Automatable::set_automation_state (const XMLNode& node, Parameter legacy_param)
XMLNode&
Automatable::get_automation_state ()
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
XMLNode* node = new XMLNode (X_("Automation"));
if (_controls.empty()) {
@@ -332,30 +251,24 @@ Automatable::get_automation_state ()
}
for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
- node->add_child_nocopy (li->second->list()->get_state ());
+ boost::shared_ptr<AutomationList> l
+ = boost::dynamic_pointer_cast<AutomationList>(li->second->list());
+ node->add_child_nocopy (l->get_state ());
}
return *node;
}
void
-Automatable::clear_automation ()
-{
- Glib::Mutex::Lock lm (_automation_lock);
-
- for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li)
- li->second->list()->clear();
-}
-
-void
Automatable::set_parameter_automation_state (Parameter param, AutoState s)
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
- boost::shared_ptr<AutomationControl> c = control (param, true);
+ boost::shared_ptr<Evoral::Control> c = control (param, true);
+ boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
- if (s != c->list()->automation_state()) {
- c->list()->set_automation_state (s);
+ if (s != l->automation_state()) {
+ l->set_automation_state (s);
_session.set_dirty ();
}
}
@@ -366,15 +279,16 @@ Automatable::get_parameter_automation_state (Parameter param, bool lock)
AutoState result = Off;
if (lock)
- _automation_lock.lock();
+ _control_lock.lock();
- boost::shared_ptr<AutomationControl> c = control(param);
+ boost::shared_ptr<Evoral::Control> c = control(param);
+ boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
if (c)
- result = c->list()->automation_state();
+ result = l->automation_state();
if (lock)
- _automation_lock.unlock();
+ _control_lock.unlock();
return result;
}
@@ -382,12 +296,13 @@ Automatable::get_parameter_automation_state (Parameter param, bool lock)
void
Automatable::set_parameter_automation_style (Parameter param, AutoStyle s)
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
- boost::shared_ptr<AutomationControl> c = control(param, true);
+ boost::shared_ptr<Evoral::Control> c = control(param, true);
+ boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
- if (s != c->list()->automation_style()) {
- c->list()->set_automation_style (s);
+ if (s != l->automation_style()) {
+ l->set_automation_style (s);
_session.set_dirty ();
}
}
@@ -395,12 +310,13 @@ Automatable::set_parameter_automation_style (Parameter param, AutoStyle s)
AutoStyle
Automatable::get_parameter_automation_style (Parameter param)
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
- boost::shared_ptr<AutomationControl> c = control(param);
+ boost::shared_ptr<Evoral::Control> c = control(param);
+ boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
if (c) {
- return c->list()->automation_style();
+ return l->automation_style();
} else {
return Absolute; // whatever
}
@@ -409,20 +325,22 @@ Automatable::get_parameter_automation_style (Parameter param)
void
Automatable::protect_automation ()
{
- set<Parameter> automated_params;
+ typedef set<Evoral::Parameter> ParameterSet;
+ ParameterSet automated_params;
- what_has_automation (automated_params);
+ what_has_data (automated_params);
- for (set<Parameter>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
+ for (ParameterSet::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
- boost::shared_ptr<AutomationControl> c = control(*i);
+ boost::shared_ptr<Evoral::Control> c = control(*i);
+ boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
- switch (c->list()->automation_state()) {
+ switch (l->automation_state()) {
case Write:
- c->list()->set_automation_state (Off);
+ l->set_automation_state (Off);
break;
case Touch:
- c->list()->set_automation_state (Play);
+ l->set_automation_state (Play);
break;
default:
break;
@@ -436,8 +354,10 @@ Automatable::automation_snapshot (nframes_t now, bool force)
if (force || _last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
- if (i->second->list()->automation_write()) {
- i->second->list()->rt_add (now, i->second->user_value());
+ boost::shared_ptr<AutomationControl> c
+ = boost::dynamic_pointer_cast<AutomationControl>(i->second);
+ if (c->automation_write()) {
+ c->list()->rt_add (now, i->second->user_value());
}
}
@@ -450,29 +370,34 @@ Automatable::transport_stopped (nframes_t now)
{
for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
- boost::shared_ptr<AutomationControl> c = li->second;
+ boost::shared_ptr<AutomationControl> c
+ = boost::dynamic_pointer_cast<AutomationControl>(li->second);
+ boost::shared_ptr<AutomationList> l
+ = boost::dynamic_pointer_cast<AutomationList>(c->list());
c->list()->reposition_for_rt_add (now);
- if (c->list()->automation_state() != Off) {
+ if (c->automation_state() != Off) {
c->set_value(c->list()->eval(now));
}
}
}
-/* FIXME: this probably doesn't belong here */
-boost::shared_ptr<AutomationControl>
-Automatable::control_factory(boost::shared_ptr<AutomationList> list)
+boost::shared_ptr<Evoral::Control>
+Automatable::control_factory(boost::shared_ptr<Evoral::ControlList> list) const
{
- if (
- list->parameter().type() == MidiCCAutomation ||
- list->parameter().type() == MidiPgmChangeAutomation ||
- list->parameter().type() == MidiChannelAftertouchAutomation
- ) {
- // FIXME: this will die horribly if this is not a MidiTrack
- return boost::shared_ptr<AutomationControl>(new MidiTrack::MidiControl((MidiTrack*)this, list));
+ boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(list);
+ assert(l);
+ if (l->parameter().type() >= MidiCCAutomation
+ && l->parameter().type() <= MidiChannelAftertouchAutomation) {
+ return boost::shared_ptr<Evoral::Control>(new MidiTrack::MidiControl((MidiTrack*)this, l));
} else {
- return boost::shared_ptr<AutomationControl>(new AutomationControl(_session, list));
+ return boost::shared_ptr<Evoral::Control>(new AutomationControl(_session, l));
}
}
+boost::shared_ptr<Evoral::ControlList>
+Automatable::control_list_factory(const Evoral::Parameter& param) const
+{
+ return boost::shared_ptr<Evoral::ControlList>(new AutomationList(param));
+}
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
index 4885a6fed9..a16306838a 100644
--- a/libs/ardour/automation_control.cc
+++ b/libs/ardour/automation_control.cc
@@ -30,10 +30,9 @@ using namespace PBD;
AutomationControl::AutomationControl(Session& session, boost::shared_ptr<AutomationList> list, string name)
- : Controllable((name == "unnamed controllable") ? list->parameter().to_string() : name)
+ : Controllable((name == "unnamed controllable") ? list->parameter().symbol() : name)
+ , Evoral::Control(list)
, _session(session)
- , _list(list)
- , _user_value(list->default_value())
{
}
@@ -43,49 +42,27 @@ AutomationControl::AutomationControl(Session& session, boost::shared_ptr<Automat
float
AutomationControl::get_value() const
{
- if (_list->automation_playback())
- return _list->eval(_session.transport_frame());
- else
- return _user_value;
+ bool from_list = ((AutomationList*)_list.get())->automation_playback();
+ return Control::get_value(from_list, _session.transport_frame());
}
void
AutomationControl::set_value(float value)
{
- _user_value = value;
+ bool to_list = _session.transport_stopped()
+ && ((AutomationList*)_list.get())->automation_playback();
- if (_session.transport_stopped() && _list->automation_write())
- _list->add(_session.transport_frame(), value);
+ Control::set_value(value, to_list, _session.transport_frame());
Changed(); /* EMIT SIGNAL */
}
-/** Get the latest user-set value, which may not equal get_value() when automation
- * is playing back, etc.
- *
- * Automation write/touch works by periodically sampling this value and adding it
- * to the AutomationList.
- */
-float
-AutomationControl::user_value() const
-{
- return _user_value;
-}
-
-
void
-AutomationControl::set_list(boost::shared_ptr<ARDOUR::AutomationList> list)
+AutomationControl::set_list(boost::shared_ptr<Evoral::ControlList> list)
{
- _list = list;
- _user_value = list->default_value();
+ Control::set_list(list);
Changed(); /* EMIT SIGNAL */
}
-
-Parameter
-AutomationControl::parameter() const
-{
- return _list->parameter();
-}
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index af390953f4..2d98f1c27c 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -39,11 +39,6 @@ using namespace PBD;
sigc::signal<void,AutomationList *> AutomationList::AutomationListCreated;
-static bool sort_events_by_time (ControlEvent* a, ControlEvent* b)
-{
- return a->when < b->when;
-}
-
#if 0
static void dumpit (const AutomationList& al, string prefix = "")
{
@@ -56,92 +51,33 @@ static void dumpit (const AutomationList& al, string prefix = "")
#endif
/* XXX: min_val max_val redundant? (param.min() param.max()) */
-AutomationList::AutomationList (Parameter id, double min_val, double max_val, double default_val)
- : _parameter(id)
- , _interpolation(Linear)
- , _curve(new Curve(*this))
-{
- _parameter = id;
- _frozen = 0;
- _changed_when_thawed = false;
+AutomationList::AutomationList (Parameter id)
+ : ControlList(id)
+{
_state = Off;
_style = Absolute;
- _min_yval = min_val;
- _max_yval = max_val;
_touching = false;
- _max_xval = 0; // means "no limit"
- _default_value = default_val;
- _rt_insertion_point = _events.end();
- _lookup_cache.left = -1;
- _lookup_cache.range.first = _events.end();
- _search_cache.left = -1;
- _search_cache.range.first = _events.end();
- _sort_pending = false;
assert(_parameter.type() != NullAutomation);
AutomationListCreated(this);
}
AutomationList::AutomationList (const AutomationList& other)
- : _parameter(other._parameter)
- , _interpolation(Linear)
- , _curve(new Curve(*this))
+ : ControlList(other)
{
- _frozen = 0;
- _changed_when_thawed = false;
- _style = other._style;
- _min_yval = other._min_yval;
- _max_yval = other._max_yval;
- _max_xval = other._max_xval;
- _default_value = other._default_value;
_state = other._state;
_touching = other._touching;
- _rt_insertion_point = _events.end();
- _lookup_cache.range.first = _events.end();
- _search_cache.range.first = _events.end();
- _sort_pending = false;
-
- for (const_iterator i = other._events.begin(); i != other._events.end(); ++i) {
- _events.push_back (new ControlEvent (**i));
- }
-
- mark_dirty ();
+
assert(_parameter.type() != NullAutomation);
AutomationListCreated(this);
}
AutomationList::AutomationList (const AutomationList& other, double start, double end)
- : _parameter(other._parameter)
- , _interpolation(Linear)
- , _curve(new Curve(*this))
+ : ControlList(other)
{
- _frozen = 0;
- _changed_when_thawed = false;
_style = other._style;
- _min_yval = other._min_yval;
- _max_yval = other._max_yval;
- _max_xval = other._max_xval;
- _default_value = other._default_value;
_state = other._state;
_touching = other._touching;
- _rt_insertion_point = _events.end();
- _lookup_cache.range.first = _events.end();
- _search_cache.range.first = _events.end();
- _sort_pending = false;
-
- /* now grab the relevant points, and shift them back if necessary */
-
- AutomationList* section = const_cast<AutomationList*>(&other)->copy (start, end);
-
- if (!section->empty()) {
- for (iterator i = section->begin(); i != section->end(); ++i) {
- _events.push_back (new ControlEvent ((*i)->when, (*i)->value));
- }
- }
-
- delete section;
-
- mark_dirty ();
assert(_parameter.type() != NullAutomation);
AutomationListCreated(this);
@@ -151,21 +87,11 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
* in or below the <AutomationList> node. It is used if \a id is non-null.
*/
AutomationList::AutomationList (const XMLNode& node, Parameter id)
- : _interpolation(Linear)
- , _curve(new Curve(*this))
+ : ControlList(id)
{
- _frozen = 0;
- _changed_when_thawed = false;
_touching = false;
- _min_yval = FLT_MIN;
- _max_yval = FLT_MAX;
- _max_xval = 0; // means "no limit"
_state = Off;
_style = Absolute;
- _rt_insertion_point = _events.end();
- _lookup_cache.range.first = _events.end();
- _search_cache.range.first = _events.end();
- _sort_pending = false;
set_state (node);
@@ -179,10 +105,12 @@ AutomationList::AutomationList (const XMLNode& node, Parameter id)
AutomationList::~AutomationList()
{
GoingAway ();
-
- for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
- delete (*x);
- }
+}
+
+boost::shared_ptr<Evoral::ControlList>
+AutomationList::create(Evoral::Parameter id)
+{
+ return boost::shared_ptr<Evoral::ControlList>(new AutomationList(id));
}
bool
@@ -217,12 +145,10 @@ AutomationList::operator= (const AutomationList& other)
void
AutomationList::maybe_signal_changed ()
{
- mark_dirty ();
+ ControlList::maybe_signal_changed ();
- if (_frozen) {
- _changed_when_thawed = true;
- } else {
- StateChanged ();
+ if (!_frozen) {
+ StateChanged (); /* EMIT SIGNAL */
}
}
@@ -248,390 +174,14 @@ void
AutomationList::start_touch ()
{
_touching = true;
- _new_touch = true;
+ _new_value = true;
}
void
AutomationList::stop_touch ()
{
_touching = false;
- _new_touch = false;
-}
-
-void
-AutomationList::clear ()
-{
- {
- Glib::Mutex::Lock lm (_lock);
- _events.clear ();
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-}
-
-void
-AutomationList::x_scale (double factor)
-{
- Glib::Mutex::Lock lm (_lock);
- _x_scale (factor);
-}
-
-bool
-AutomationList::extend_to (double when)
-{
- Glib::Mutex::Lock lm (_lock);
- if (_events.empty() || _events.back()->when == when) {
- return false;
- }
- double factor = when / _events.back()->when;
- _x_scale (factor);
- return true;
-}
-
-void AutomationList::_x_scale (double factor)
-{
- for (iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->when = floor ((*i)->when * factor);
- }
-
- mark_dirty ();
-}
-
-void
-AutomationList::reposition_for_rt_add (double when)
-{
- _rt_insertion_point = _events.end();
-}
-
-void
-AutomationList::rt_add (double when, double value)
-{
- /* this is for automation recording */
-
- if ((_state & Touch) && !_touching) {
- return;
- }
-
- // cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- iterator where;
- ControlEvent cp (when, 0.0);
- bool done = false;
-
- if ((_rt_insertion_point != _events.end()) && ((*_rt_insertion_point)->when < when) ) {
-
- /* we have a previous insertion point, so we should delete
- everything between it and the position where we are going
- to insert this point.
- */
-
- iterator after = _rt_insertion_point;
-
- if (++after != _events.end()) {
- iterator far = after;
-
- while (far != _events.end()) {
- if ((*far)->when > when) {
- break;
- }
- ++far;
- }
-
- if (_new_touch) {
- where = far;
- _rt_insertion_point = where;
-
- if ((*where)->when == when) {
- (*where)->value = value;
- done = true;
- }
- } else {
- where = _events.erase (after, far);
- }
-
- } else {
-
- where = after;
-
- }
-
- iterator previous = _rt_insertion_point;
- --previous;
-
- if (_rt_insertion_point != _events.begin() && (*_rt_insertion_point)->value == value && (*previous)->value == value) {
- (*_rt_insertion_point)->when = when;
- done = true;
-
- }
-
- } else {
-
- where = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
-
- if (where != _events.end()) {
- if ((*where)->when == when) {
- (*where)->value = value;
- done = true;
- }
- }
- }
-
- if (!done) {
- _rt_insertion_point = _events.insert (where, new ControlEvent (when, value));
- }
-
- _new_touch = false;
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-}
-
-void
-AutomationList::fast_simple_add (double when, double value)
-{
- /* to be used only for loading pre-sorted data from saved state */
- _events.insert (_events.end(), new ControlEvent (when, value));
- assert(_events.back());
-}
-
-void
-AutomationList::add (double when, double value)
-{
- /* this is for graphical editing */
-
- {
- Glib::Mutex::Lock lm (_lock);
- ControlEvent cp (when, 0.0f);
- bool insert = true;
- iterator insertion_point;
-
- for (insertion_point = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); insertion_point != _events.end(); ++insertion_point) {
-
- /* only one point allowed per time point */
-
- if ((*insertion_point)->when == when) {
- (*insertion_point)->value = value;
- insert = false;
- break;
- }
-
- if ((*insertion_point)->when >= when) {
- break;
- }
- }
-
- if (insert) {
-
- _events.insert (insertion_point, new ControlEvent (when, value));
- reposition_for_rt_add (0);
-
- }
-
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-}
-
-void
-AutomationList::erase (iterator i)
-{
- {
- Glib::Mutex::Lock lm (_lock);
- _events.erase (i);
- reposition_for_rt_add (0);
- mark_dirty ();
- }
- maybe_signal_changed ();
-}
-
-void
-AutomationList::erase (iterator start, iterator end)
-{
- {
- Glib::Mutex::Lock lm (_lock);
- _events.erase (start, end);
- reposition_for_rt_add (0);
- mark_dirty ();
- }
- maybe_signal_changed ();
-}
-
-void
-AutomationList::reset_range (double start, double endt)
-{
- bool reset = false;
-
- {
- Glib::Mutex::Lock lm (_lock);
- ControlEvent cp (start, 0.0f);
- iterator s;
- iterator e;
-
- if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) != _events.end()) {
-
- cp.when = endt;
- e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
-
- for (iterator i = s; i != e; ++i) {
- (*i)->value = _default_value;
- }
-
- reset = true;
-
- mark_dirty ();
- }
- }
-
- if (reset) {
- maybe_signal_changed ();
- }
-}
-
-void
-AutomationList::erase_range (double start, double endt)
-{
- bool erased = false;
-
- {
- Glib::Mutex::Lock lm (_lock);
- ControlEvent cp (start, 0.0f);
- iterator s;
- iterator e;
-
- if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) != _events.end()) {
- cp.when = endt;
- e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
- _events.erase (s, e);
- reposition_for_rt_add (0);
- erased = true;
- mark_dirty ();
- }
-
- }
-
- if (erased) {
- maybe_signal_changed ();
- }
-}
-
-void
-AutomationList::move_range (iterator start, iterator end, double xdelta, double ydelta)
-{
- /* note: we assume higher level logic is in place to avoid this
- reordering the time-order of control events in the list. ie. all
- points after end are later than (end)->when.
- */
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- while (start != end) {
- (*start)->when += xdelta;
- (*start)->value += ydelta;
- if (isnan ((*start)->value)) {
- abort ();
- }
- ++start;
- }
-
- if (!_frozen) {
- _events.sort (sort_events_by_time);
- } else {
- _sort_pending = true;
- }
-
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-}
-
-void
-AutomationList::slide (iterator before, double distance)
-{
- {
- Glib::Mutex::Lock lm (_lock);
-
- if (before == _events.end()) {
- return;
- }
-
- while (before != _events.end()) {
- (*before)->when += distance;
- ++before;
- }
- }
-
- maybe_signal_changed ();
-}
-
-void
-AutomationList::modify (iterator iter, double when, double val)
-{
- /* note: we assume higher level logic is in place to avoid this
- reordering the time-order of control events in the list. ie. all
- points after *iter are later than when.
- */
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- (*iter)->when = when;
- (*iter)->value = val;
-
- if (isnan (val)) {
- abort ();
- }
-
- if (!_frozen) {
- _events.sort (sort_events_by_time);
- } else {
- _sort_pending = true;
- }
-
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-}
-
-std::pair<AutomationList::iterator,AutomationList::iterator>
-AutomationList::control_points_adjacent (double xval)
-{
- Glib::Mutex::Lock lm (_lock);
- iterator i;
- ControlEvent cp (xval, 0.0f);
- std::pair<iterator,iterator> ret;
-
- ret.first = _events.end();
- ret.second = _events.end();
-
- for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
-
- if (ret.first == _events.end()) {
- if ((*i)->when >= xval) {
- if (i != _events.begin()) {
- ret.first = i;
- --ret.first;
- } else {
- return ret;
- }
- }
- }
-
- if ((*i)->when > xval) {
- ret.second = i;
- break;
- }
- }
-
- return ret;
+ _new_value = false;
}
void
@@ -643,790 +193,20 @@ AutomationList::freeze ()
void
AutomationList::thaw ()
{
- if (_frozen == 0) {
- PBD::stacktrace (cerr);
- fatal << string_compose (_("programming error: %1"), X_("AutomationList::thaw() called while not frozen")) << endmsg;
- /*NOTREACHED*/
- }
-
- if (--_frozen > 0) {
- return;
- }
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- if (_sort_pending) {
- _events.sort (sort_events_by_time);
- _sort_pending = false;
- }
- }
+ ControlList::thaw();
if (_changed_when_thawed) {
StateChanged(); /* EMIT SIGNAL */
}
}
-void
-AutomationList::set_max_xval (double x)
-{
- _max_xval = x;
-}
-
void
-AutomationList::mark_dirty ()
+AutomationList::mark_dirty () const
{
- _lookup_cache.left = -1;
- _search_cache.left = -1;
+ ControlList::mark_dirty ();
Dirty (); /* EMIT SIGNAL */
}
-void
-AutomationList::truncate_end (double last_coordinate)
-{
- {
- Glib::Mutex::Lock lm (_lock);
- ControlEvent cp (last_coordinate, 0);
- AutomationList::reverse_iterator i;
- double last_val;
-
- if (_events.empty()) {
- return;
- }
-
- if (last_coordinate == _events.back()->when) {
- return;
- }
-
- if (last_coordinate > _events.back()->when) {
-
- /* extending end:
- */
-
- iterator foo = _events.begin();
- bool lessthantwo;
-
- if (foo == _events.end()) {
- lessthantwo = true;
- } else if (++foo == _events.end()) {
- lessthantwo = true;
- } else {
- lessthantwo = false;
- }
-
- if (lessthantwo) {
- /* less than 2 points: add a new point */
- _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
- } else {
-
- /* more than 2 points: check to see if the last 2 values
- are equal. if so, just move the position of the
- last point. otherwise, add a new point.
- */
-
- iterator penultimate = _events.end();
- --penultimate; /* points at last point */
- --penultimate; /* points at the penultimate point */
-
- if (_events.back()->value == (*penultimate)->value) {
- _events.back()->when = last_coordinate;
- } else {
- _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
- }
- }
-
- } else {
-
- /* shortening end */
-
- last_val = unlocked_eval (last_coordinate);
- last_val = max ((double) _min_yval, last_val);
- last_val = min ((double) _max_yval, last_val);
-
- i = _events.rbegin();
-
- /* make i point to the last control point */
-
- ++i;
-
- /* now go backwards, removing control points that are
- beyond the new last coordinate.
- */
-
- uint32_t sz = _events.size();
-
- while (i != _events.rend() && sz > 2) {
- AutomationList::reverse_iterator tmp;
-
- tmp = i;
- ++tmp;
-
- if ((*i)->when < last_coordinate) {
- break;
- }
-
- _events.erase (i.base());
- --sz;
-
- i = tmp;
- }
-
- _events.back()->when = last_coordinate;
- _events.back()->value = last_val;
- }
-
- reposition_for_rt_add (0);
- mark_dirty();
- }
-
- maybe_signal_changed ();
-}
-
-void
-AutomationList::truncate_start (double overall_length)
-{
- {
- Glib::Mutex::Lock lm (_lock);
- iterator i;
- double first_legal_value;
- double first_legal_coordinate;
-
- if (_events.empty()) {
- fatal << _("programming error:")
- << "AutomationList::truncate_start() called on an empty list"
- << endmsg;
- /*NOTREACHED*/
- return;
- }
-
- if (overall_length == _events.back()->when) {
- /* no change in overall length */
- return;
- }
-
- if (overall_length > _events.back()->when) {
-
- /* growing at front: duplicate first point. shift all others */
-
- double shift = overall_length - _events.back()->when;
- uint32_t np;
-
- for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
- (*i)->when += shift;
- }
-
- if (np < 2) {
-
- /* less than 2 points: add a new point */
- _events.push_front (new ControlEvent (0, _events.front()->value));
-
- } else {
-
- /* more than 2 points: check to see if the first 2 values
- are equal. if so, just move the position of the
- first point. otherwise, add a new point.
- */
-
- iterator second = _events.begin();
- ++second; /* points at the second point */
-
- if (_events.front()->value == (*second)->value) {
- /* first segment is flat, just move start point back to zero */
- _events.front()->when = 0;
- } else {
- /* leave non-flat segment in place, add a new leading point. */
- _events.push_front (new ControlEvent (0, _events.front()->value));
- }
- }
-
- } else {
-
- /* shrinking at front */
-
- first_legal_coordinate = _events.back()->when - overall_length;
- first_legal_value = unlocked_eval (first_legal_coordinate);
- first_legal_value = max (_min_yval, first_legal_value);
- first_legal_value = min (_max_yval, first_legal_value);
-
- /* remove all events earlier than the new "front" */
-
- i = _events.begin();
-
- while (i != _events.end() && !_events.empty()) {
- AutomationList::iterator tmp;
-
- tmp = i;
- ++tmp;
-
- if ((*i)->when > first_legal_coordinate) {
- break;
- }
-
- _events.erase (i);
-
- i = tmp;
- }
-
-
- /* shift all remaining points left to keep their same
- relative position
- */
-
- for (i = _events.begin(); i != _events.end(); ++i) {
- (*i)->when -= first_legal_coordinate;
- }
-
- /* add a new point for the interpolated new value */
-
- _events.push_front (new ControlEvent (0, first_legal_value));
- }
-
- reposition_for_rt_add (0);
-
- mark_dirty();
- }
-
- maybe_signal_changed ();
-}
-
-double
-AutomationList::unlocked_eval (double x) const
-{
- pair<EventList::iterator,EventList::iterator> range;
- int32_t npoints;
- double lpos, upos;
- double lval, uval;
- double fraction;
-
- npoints = _events.size();
-
- switch (npoints) {
- case 0:
- return _default_value;
-
- case 1:
- if (x >= _events.front()->when) {
- return _events.front()->value;
- } else {
- // return _default_value;
- return _events.front()->value;
- }
-
- case 2:
- if (x >= _events.back()->when) {
- return _events.back()->value;
- } else if (x == _events.front()->when) {
- return _events.front()->value;
- } else if (x < _events.front()->when) {
- // return _default_value;
- return _events.front()->value;
- }
-
- lpos = _events.front()->when;
- lval = _events.front()->value;
- upos = _events.back()->when;
- uval = _events.back()->value;
-
- if (_interpolation == Discrete)
- return lval;
-
- /* linear interpolation betweeen the two points
- */
-
- fraction = (double) (x - lpos) / (double) (upos - lpos);
- return lval + (fraction * (uval - lval));
-
- default:
-
- if (x >= _events.back()->when) {
- return _events.back()->value;
- } else if (x == _events.front()->when) {
- return _events.front()->value;
- } else if (x < _events.front()->when) {
- // return _default_value;
- return _events.front()->value;
- }
-
- return multipoint_eval (x);
- break;
- }
-
- /*NOTREACHED*/ /* stupid gcc */
- return 0.0;
-}
-
-double
-AutomationList::multipoint_eval (double x) const
-{
- double upos, lpos;
- double uval, lval;
- double fraction;
-
- /* "Stepped" lookup (no interpolation) */
- /* FIXME: no cache. significant? */
- if (_interpolation == Discrete) {
- const ControlEvent cp (x, 0);
- EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
-
- // shouldn't have made it to multipoint_eval
- assert(i != _events.end());
-
- if (i == _events.begin() || (*i)->when == x)
- return (*i)->value;
- else
- return (*(--i))->value;
- }
-
- /* Only do the range lookup if x is in a different range than last time
- * this was called (or if the lookup cache has been marked "dirty" (left<0) */
- if ((_lookup_cache.left < 0) ||
- ((_lookup_cache.left > x) ||
- (_lookup_cache.range.first == _events.end()) ||
- ((*_lookup_cache.range.second)->when < x))) {
-
- const ControlEvent cp (x, 0);
-
- _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
- }
-
- pair<const_iterator,const_iterator> range = _lookup_cache.range;
-
- if (range.first == range.second) {
-
- /* x does not exist within the list as a control point */
-
- _lookup_cache.left = x;
-
- if (range.first != _events.begin()) {
- --range.first;
- lpos = (*range.first)->when;
- lval = (*range.first)->value;
- } else {
- /* we're before the first point */
- // return _default_value;
- return _events.front()->value;
- }
-
- if (range.second == _events.end()) {
- /* we're after the last point */
- return _events.back()->value;
- }
-
- upos = (*range.second)->when;
- uval = (*range.second)->value;
-
- /* linear interpolation betweeen the two points
- on either side of x
- */
-
- fraction = (double) (x - lpos) / (double) (upos - lpos);
- return lval + (fraction * (uval - lval));
-
- }
-
- /* x is a control point in the data */
- _lookup_cache.left = -1;
- return (*range.first)->value;
-}
-
-void
-AutomationList::build_search_cache_if_necessary(double start, double end) const
-{
- /* Only do the range lookup if x is in a different range than last time
- * this was called (or if the search cache has been marked "dirty" (left<0) */
- if (!_events.empty() && ((_search_cache.left < 0) ||
- ((_search_cache.left > start) ||
- (_search_cache.right < end)))) {
-
- const ControlEvent start_point (start, 0);
- const ControlEvent end_point (end, 0);
-
- //cerr << "REBUILD: (" << _search_cache.left << ".." << _search_cache.right << ") := ("
- // << start << ".." << end << ")" << endl;
-
- _search_cache.range.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
- _search_cache.range.second = upper_bound (_events.begin(), _events.end(), &end_point, time_comparator);
-
- _search_cache.left = start;
- _search_cache.right = end;
- }
-}
-
-/** Get the earliest event between \a start and \a end, using the current interpolation style.
- *
- * If an event is found, \a x and \a y are set to its coordinates.
- *
- * \param inclusive Include events with timestamp exactly equal to \a start
- * \return true if event is found (and \a x and \a y are valid).
- */
-bool
-AutomationList::rt_safe_earliest_event(double start, double end, double& x, double& y, bool inclusive) const
-{
- // FIXME: It would be nice if this was unnecessary..
- Glib::Mutex::Lock lm(_lock, Glib::TRY_LOCK);
- if (!lm.locked()) {
- return false;
- }
-
- return rt_safe_earliest_event_unlocked(start, end, x, y, inclusive);
-}
-
-
-/** Get the earliest event between \a start and \a end, using the current interpolation style.
- *
- * If an event is found, \a x and \a y are set to its coordinates.
- *
- * \param inclusive Include events with timestamp exactly equal to \a start
- * \return true if event is found (and \a x and \a y are valid).
- */
-bool
-AutomationList::rt_safe_earliest_event_unlocked(double start, double end, double& x, double& y, bool inclusive) const
-{
- if (_interpolation == Discrete)
- return rt_safe_earliest_event_discrete_unlocked(start, end, x, y, inclusive);
- else
- return rt_safe_earliest_event_linear_unlocked(start, end, x, y, inclusive);
-}
-
-
-/** Get the earliest event between \a start and \a end (Discrete (lack of) interpolation)
- *
- * If an event is found, \a x and \a y are set to its coordinates.
- *
- * \param inclusive Include events with timestamp exactly equal to \a start
- * \return true if event is found (and \a x and \a y are valid).
- */
-bool
-AutomationList::rt_safe_earliest_event_discrete_unlocked (double start, double end, double& x, double& y, bool inclusive) const
-{
- build_search_cache_if_necessary(start, end);
-
- const pair<const_iterator,const_iterator>& range = _search_cache.range;
-
- if (range.first != _events.end()) {
- const ControlEvent* const first = *range.first;
-
- const bool past_start = (inclusive ? first->when >= start : first->when > start);
-
- /* Earliest points is in range, return it */
- if (past_start >= start && first->when < end) {
-
- x = first->when;
- y = first->value;
-
- /* Move left of cache to this point
- * (Optimize for immediate call this cycle within range) */
- _search_cache.left = x;
- ++_search_cache.range.first;
-
- assert(x >= start);
- assert(x < end);
- return true;
-
- } else {
- return false;
- }
-
- /* No points in range */
- } else {
- return false;
- }
-}
-
-/** Get the earliest time the line crosses an integer (Linear interpolation).
- *
- * If an event is found, \a x and \a y are set to its coordinates.
- *
- * \param inclusive Include events with timestamp exactly equal to \a start
- * \return true if event is found (and \a x and \a y are valid).
- */
-bool
-AutomationList::rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const
-{
- //cerr << "earliest_event(" << start << ", " << end << ", " << x << ", " << y << ", " << inclusive << endl;
-
- if (_events.size() == 0)
- return false;
- else if (_events.size() == 1)
- return rt_safe_earliest_event_discrete_unlocked(start, end, x, y, inclusive);
-
- // Hack to avoid infinitely repeating the same event
- build_search_cache_if_necessary(start, end);
-
- pair<const_iterator,const_iterator> range = _search_cache.range;
-
- if (range.first != _events.end()) {
-
- const ControlEvent* first = NULL;
- const ControlEvent* next = NULL;
-
- /* Step is after first */
- if (range.first == _events.begin() || (*range.first)->when == start) {
- first = *range.first;
- next = *(++range.first);
- ++_search_cache.range.first;
-
- /* Step is before first */
- } else {
- const_iterator prev = range.first;
- --prev;
- first = *prev;
- next = *range.first;
- }
-
- if (inclusive && first->when == start) {
- x = first->when;
- y = first->value;
- /* Move left of cache to this point
- * (Optimize for immediate call this cycle within range) */
- _search_cache.left = x;
- //++_search_cache.range.first;
- return true;
- }
-
- if (abs(first->value - next->value) <= 1) {
- if (next->when <= end && (!inclusive || next->when > start)) {
- x = next->when;
- y = next->value;
- /* Move left of cache to this point
- * (Optimize for immediate call this cycle within range) */
- _search_cache.left = x;
- //++_search_cache.range.first;
- return true;
- } else {
- return false;
- }
- }
-
- const double slope = (next->value - first->value) / (double)(next->when - first->when);
- //cerr << "start y: " << start_y << endl;
-
- //y = first->value + (slope * fabs(start - first->when));
- y = first->value;
-
- if (first->value < next->value) // ramping up
- y = ceil(y);
- else // ramping down
- y = floor(y);
-
- x = first->when + (y - first->value) / (double)slope;
-
- while ((inclusive && x < start) || (x <= start && y != next->value)) {
-
- if (first->value < next->value) // ramping up
- y += 1.0;
- else // ramping down
- y -= 1.0;
-
- x = first->when + (y - first->value) / (double)slope;
- }
-
- /*cerr << first->value << " @ " << first->when << " ... "
- << next->value << " @ " << next->when
- << " = " << y << " @ " << x << endl;*/
-
- assert( (y >= first->value && y <= next->value)
- || (y <= first->value && y >= next->value) );
-
-
- const bool past_start = (inclusive ? x >= start : x > start);
- if (past_start && x < end) {
- /* Move left of cache to this point
- * (Optimize for immediate call this cycle within range) */
- _search_cache.left = x;
-
- return true;
-
- } else {
- return false;
- }
-
- /* No points in the future, so no steps (towards them) in the future */
- } else {
- return false;
- }
-}
-
-AutomationList*
-AutomationList::cut (iterator start, iterator end)
-{
- AutomationList* nal = new AutomationList (_parameter, _min_yval, _max_yval, _default_value);
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- for (iterator x = start; x != end; ) {
- iterator tmp;
-
- tmp = x;
- ++tmp;
-
- nal->_events.push_back (new ControlEvent (**x));
- _events.erase (x);
-
- reposition_for_rt_add (0);
-
- x = tmp;
- }
-
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-
- return nal;
-}
-
-AutomationList*
-AutomationList::cut_copy_clear (double start, double end, int op)
-{
- AutomationList* nal = new AutomationList (_parameter, _min_yval, _max_yval, _default_value);
- iterator s, e;
- ControlEvent cp (start, 0.0);
- bool changed = false;
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
- return nal;
- }
-
- cp.when = end;
- e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
-
- if (op != 2 && (*s)->when != start) {
- nal->_events.push_back (new ControlEvent (0, unlocked_eval (start)));
- }
-
- for (iterator x = s; x != e; ) {
- iterator tmp;
-
- tmp = x;
- ++tmp;
-
- changed = true;
-
- /* adjust new points to be relative to start, which
- has been set to zero.
- */
-
- if (op != 2) {
- nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
- }
-
- if (op != 1) {
- _events.erase (x);
- }
-
- x = tmp;
- }
-
- if (op != 2 && nal->_events.back()->when != end - start) {
- nal->_events.push_back (new ControlEvent (end - start, unlocked_eval (end)));
- }
-
- if (changed) {
- reposition_for_rt_add (0);
- }
-
- mark_dirty ();
- }
-
- maybe_signal_changed ();
-
- return nal;
-
-}
-
-AutomationList*
-AutomationList::copy (iterator start, iterator end)
-{
- AutomationList* nal = new AutomationList (_parameter, _min_yval, _max_yval, _default_value);
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- for (iterator x = start; x != end; ) {
- iterator tmp;
-
- tmp = x;
- ++tmp;
-
- nal->_events.push_back (new ControlEvent (**x));
-
- x = tmp;
- }
- }
-
- return nal;
-}
-
-AutomationList*
-AutomationList::cut (double start, double end)
-{
- return cut_copy_clear (start, end, 0);
-}
-
-AutomationList*
-AutomationList::copy (double start, double end)
-{
- return cut_copy_clear (start, end, 1);
-}
-
-void
-AutomationList::clear (double start, double end)
-{
- (void) cut_copy_clear (start, end, 2);
-}
-
-bool
-AutomationList::paste (AutomationList& alist, double pos, float times)
-{
- if (alist._events.empty()) {
- return false;
- }
-
- {
- Glib::Mutex::Lock lm (_lock);
- iterator where;
- iterator prev;
- double end = 0;
- ControlEvent cp (pos, 0.0);
-
- where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
-
- for (iterator i = alist.begin();i != alist.end(); ++i) {
- _events.insert (where, new ControlEvent( (*i)->when+pos,( *i)->value));
- end = (*i)->when + pos;
- }
-
-
- /* move all points after the insertion along the timeline by
- the correct amount.
- */
-
- while (where != _events.end()) {
- iterator tmp;
- if ((*where)->when <= end) {
- tmp = where;
- ++tmp;
- _events.erase(where);
- where = tmp;
-
- } else {
- break;
- }
- }
-
- reposition_for_rt_add (0);
- mark_dirty ();
- }
-
- maybe_signal_changed ();
- return true;
-}
-
XMLNode&
AutomationList::get_state ()
{
@@ -1440,7 +220,7 @@ AutomationList::state (bool full)
char buf[64];
LocaleGuard lg (X_("POSIX"));
- root->add_property ("automation-id", _parameter.to_string());
+ root->add_property ("automation-id", _parameter.symbol());
root->add_property ("id", _id.to_s());
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 213e7504b0..b6ca322c73 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -78,8 +78,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
nframes_t position,
AnchorPoint ap)
: AudioRegion (in->session(), position, length, "foobar"),
- _fade_in (Parameter(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
- _fade_out (Parameter(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
+ _fade_in (Parameter(FadeInAutomation)), // linear (gain coefficient) => -inf..+6dB
+ _fade_out (Parameter(FadeOutAutomation)) // linear (gain coefficient) => -inf..+6dB
{
_in = in;
@@ -95,8 +95,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
: AudioRegion (a->session(), 0, 0, "foobar"),
- _fade_in (Parameter(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
- _fade_out (Parameter(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
+ _fade_in (Parameter(FadeInAutomation)), // linear (gain coefficient) => -inf..+6dB
+ _fade_out (Parameter(FadeOutAutomation)) // linear (gain coefficient) => -inf..+6dB
{
_in_update = false;
_fixed = false;
@@ -114,8 +114,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
: AudioRegion (playlist.session(), 0, 0, "foobar"),
- _fade_in (Parameter(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
- _fade_out (Parameter(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
+ _fade_in (Parameter(FadeInAutomation)), // linear (gain coefficient) => -inf..+6dB
+ _fade_out (Parameter(FadeOutAutomation)) // linear (gain coefficient) => -inf..+6dB
{
boost::shared_ptr<Region> r;
diff --git a/libs/ardour/gain.cc b/libs/ardour/gain.cc
index 49596d6614..741ac2b57a 100644
--- a/libs/ardour/gain.cc
+++ b/libs/ardour/gain.cc
@@ -22,7 +22,7 @@
using namespace ARDOUR;
Gain::Gain ()
- : AutomationList (Parameter(GainAutomation), 0.0, 2.0, 1.0f) /* XXX yuck; clamps gain to -inf .. +6db */
+ : AutomationList (Parameter(GainAutomation)) /* XXX yuck; clamps gain to -inf .. +6db */
{
}
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index d4afda8b5a..199a2fd1a4 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -305,7 +305,7 @@ static void
write_midi_data_to_new_files (SMFReader* source, Session::import_status& status,
vector<boost::shared_ptr<Source> >& newfiles)
{
- MIDI::Event ev(0.0, 4, NULL, true);
+ Evoral::Event ev(0.0, 4, NULL, true);
status.progress = 0.0f;
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 1b3c2e2378..69c74f5f03 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -137,7 +137,7 @@ IO::IO (Session& s, const string& name,
deferred_state = 0;
boost::shared_ptr<AutomationList> gl(
- new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
+ new AutomationList(Parameter(GainAutomation)));
_gain_control = boost::shared_ptr<GainControl>(
new GainControl(X_("gaincontrol"), *this, gl));
@@ -178,7 +178,7 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
apply_gain_automation = false;
boost::shared_ptr<AutomationList> gl(
- new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
+ new AutomationList(Parameter(GainAutomation)));
_gain_control = boost::shared_ptr<GainControl>(
new GainControl(X_("gaincontrol"), *this, gl));
@@ -1153,7 +1153,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
gain_t
IO::effective_gain () const
{
- if (_gain_control->list()->automation_playback()) {
+ if (_gain_control->automation_playback()) {
return _gain_control->get_value();
} else {
return _desired_gain;
@@ -2266,7 +2266,7 @@ IO::meter ()
void
IO::clear_automation ()
{
- Automatable::clear_automation (); // clears gain automation
+ Automatable::clear (); // clears gain automation
_panner->clear_automation ();
}
@@ -2280,9 +2280,10 @@ IO::set_parameter_automation_state (Parameter param, AutoState state)
bool changed = false;
{
- Glib::Mutex::Lock lm (_automation_lock);
+ Glib::Mutex::Lock lm (_control_lock);
- boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
+ boost::shared_ptr<AutomationList> gain_auto
+ = boost::dynamic_pointer_cast<AutomationList>(_gain_control->list());
if (state != gain_auto->automation_state()) {
changed = true;
@@ -2337,7 +2338,7 @@ IO::set_gain (gain_t val, void *src)
_gain = val;
}
- if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
+ if (_session.transport_stopped() && src != 0 && src != this && _gain_control->automation_write()) {
_gain_control->list()->add (_session.transport_frame(), val);
}
@@ -2349,7 +2350,7 @@ void
IO::start_pan_touch (uint32_t which)
{
if (which < _panner->size()) {
- (*_panner)[which]->pan_control()->list()->start_touch();
+ (*_panner)[which]->pan_control()->start_touch();
}
}
@@ -2357,7 +2358,7 @@ void
IO::end_pan_touch (uint32_t which)
{
if (which < _panner->size()) {
- (*_panner)[which]->pan_control()->list()->stop_touch();
+ (*_panner)[which]->pan_control()->stop_touch();
}
}
@@ -2380,7 +2381,7 @@ IO::transport_stopped (nframes_t frame)
{
_gain_control->list()->reposition_for_rt_add (frame);
- if (_gain_control->list()->automation_state() != Off) {
+ if (_gain_control->automation_state() != Off) {
/* the src=0 condition is a special signal to not propagate
automation gain changes into the mix group when locating.
diff --git a/libs/ardour/jack_midi_port.cc b/libs/ardour/jack_midi_port.cc
index 6d8e4c8c5d..d831864ec9 100644
--- a/libs/ardour/jack_midi_port.cc
+++ b/libs/ardour/jack_midi_port.cc
@@ -82,7 +82,7 @@ JackMidiPort::cycle_end (nframes_t nframes, nframes_t offset)
jack_midi_clear_buffer (jack_buffer);
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
- const MIDI::Event& ev = *i;
+ const Evoral::Event& ev = *i;
// event times should be frames, relative to cycle start
assert(ev.time() >= 0);
assert(ev.time() < nframes);
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index aedfd17be8..363cbe242f 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -47,7 +47,7 @@ PeakMeter::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_f
// GUI needs a better MIDI meter, not much information can be
// expressed through peaks alone
for (MidiBuffer::iterator i = bufs.get_midi(n).begin(); i != bufs.get_midi(n).end(); ++i) {
- const MIDI::Event& ev = *i;
+ const Evoral::Event& ev = *i;
if (ev.is_note_on()) {
const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
//printf("V %d -> %f\n", (int)((Byte)ev.buffer[2]), this_vel);
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index 1530babe34..afd8481795 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -74,10 +74,10 @@ MidiBuffer::resize (size_t size)
_capacity = size;
#ifdef NO_POSIX_MEMALIGN
- _events = (MIDI::Event *) malloc(sizeof(MIDI::Event) * _capacity);
+ _events = (Evoral::Event *) malloc(sizeof(Evoral::Event) * _capacity);
_data = (uint8_t *) malloc(sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
#else
- posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MIDI::Event) * _capacity);
+ posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(Evoral::Event) * _capacity);
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
#endif
assert(_data);
@@ -115,7 +115,7 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
// FIXME: slow
for (size_t i=0; i < msrc.size(); ++i) {
- const MIDI::Event& ev = msrc[i];
+ const Evoral::Event& ev = msrc[i];
if (ev.time() >= offset && ev.time() < offset+nframes) {
//cout << "MidiBuffer::read_from got event, " << int(ev.type()) << " time: " << ev.time() << " buffer size: " << _size << endl;
push_back(ev);
@@ -136,7 +136,7 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
* @return false if operation failed (not enough room)
*/
bool
-MidiBuffer::push_back(const MIDI::Event& ev)
+MidiBuffer::push_back(const Evoral::Event& ev)
{
if (_size == _capacity)
return false;
@@ -223,7 +223,7 @@ MidiBuffer::silence(nframes_t dur, nframes_t offset)
if (offset != 0)
cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
- memset(_events, 0, sizeof(MIDI::Event) * _capacity);
+ memset(_events, 0, sizeof(Evoral::Event) * _capacity);
memset(_data, 0, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
_size = 0;
_silent = true;
@@ -262,8 +262,8 @@ MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
push_back(b[b_index]);
++b_index;
} else {
- const MIDI::Event& a_ev = a[a_index];
- const MIDI::Event& b_ev = b[b_index];
+ const Evoral::Event& a_ev = a[a_index];
+ const Evoral::Event& b_ev = b[b_index];
if (a_ev.time() <= b_ev.time()) {
push_back(a_ev);
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 5b4716d51e..b2991c1a7f 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -520,7 +520,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t
MidiBuffer::iterator port_iter = _source_port->get_midi_buffer().begin();
for (size_t i=0; i < to_write; ++i) {
- const MIDI::Event& ev = *port_iter;
+ const Evoral::Event& ev = *port_iter;
assert(ev.buffer());
_capture_buf->write(ev.time() + transport_frame, ev.size(), ev.buffer());
++port_iter;
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index b21bf38873..da0fa364b9 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -35,655 +35,15 @@
using namespace std;
using namespace ARDOUR;
-void MidiModel::write_lock() {
- _lock.writer_lock();
- _automation_lock.lock();
-}
-
-void MidiModel::write_unlock() {
- _lock.writer_unlock();
- _automation_lock.unlock();
-}
-
-void MidiModel::read_lock() const {
- _lock.reader_lock();
- /*_automation_lock.lock();*/
-}
-
-void MidiModel::read_unlock() const {
- _lock.reader_unlock();
- /*_automation_lock.unlock();*/
-}
-
-// Read iterator (const_iterator)
-
-MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
- : _model(&model)
- , _is_end( (t == DBL_MAX) || model.empty() )
- , _locked( !_is_end )
-{
- //cerr << "Created MIDI iterator @ " << t << " (is end: " << _is_end << ")" << endl;
-
- if (_is_end) {
- return;
- }
-
- model.read_lock();
-
- _note_iter = model.notes().end();
- // find first note which begins after t
- for (MidiModel::Notes::const_iterator i = model.notes().begin(); i != model.notes().end(); ++i) {
- if ((*i)->time() >= t) {
- _note_iter = i;
- break;
- }
- }
-
- MidiControlIterator earliest_control(boost::shared_ptr<AutomationList>(), DBL_MAX, 0.0);
-
- _control_iters.reserve(model.controls().size());
-
- // find the earliest control event available
- for (Automatable::Controls::const_iterator i = model.controls().begin();
- i != model.controls().end(); ++i) {
-
- assert(
- i->first.type() == MidiCCAutomation ||
- i->first.type() == MidiPgmChangeAutomation ||
- i->first.type() == MidiPitchBenderAutomation ||
- i->first.type() == MidiChannelAftertouchAutomation);
-
- double x, y;
- bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
- if (!ret) {
- //cerr << "MIDI Iterator: CC " << i->first.id() << " (size " << i->second->list()->size()
- // << ") has no events past " << t << endl;
- continue;
- }
-
- assert(x >= 0);
-
- if (y < i->first.min() || y > i->first.max()) {
- cerr << "ERROR: Controller (" << i->first.to_string() << ") value '" << y
- << "' out of range [" << i->first.min() << "," << i->first.max()
- << "], event ignored" << endl;
- continue;
- }
-
- const MidiControlIterator new_iter(i->second->list(), x, y);
-
- //cerr << "MIDI Iterator: CC " << i->first.id() << " added (" << x << ", " << y << ")" << endl;
- _control_iters.push_back(new_iter);
-
- // if the x of the current control is less than earliest_control
- // we have a new earliest_control
- if (x < earliest_control.x) {
- earliest_control = new_iter;
- _control_iter = _control_iters.end();
- --_control_iter;
- // now _control_iter points to the last Element in _control_iters
- }
- }
-
- if (_note_iter != model.notes().end()) {
- _event = boost::shared_ptr<MIDI::Event>(new MIDI::Event((*_note_iter)->on_event(), true));
- }
-
- double time = DBL_MAX;
- // in case we have no notes in the region, we still want to get controller messages
- if (_event.get()) {
- time = _event->time();
- // if the note is going to make it this turn, advance _note_iter
- if (earliest_control.x > time) {
- _active_notes.push(*_note_iter);
- ++_note_iter;
- }
- }
-
- // <=, because we probably would want to send control events first
- if (earliest_control.automation_list.get() && earliest_control.x <= time) {
- model.control_to_midi_event(_event, earliest_control);
- } else {
- _control_iter = _control_iters.end();
- }
-
- if ( (! _event.get()) || _event->size() == 0) {
- //cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
- _is_end = true;
-
- // eliminate possible race condition here (ugly)
- static Glib::Mutex mutex;
- Glib::Mutex::Lock lock(mutex);
- if (_locked) {
- _model->read_unlock();
- _locked = false;
- }
- } else {
- //printf("New MIDI Iterator = %X @ %lf\n", _event->type(), _event->time());
- }
-
- assert(_is_end || (_event->buffer() && _event->buffer()[0] != '\0'));
-}
-
-MidiModel::const_iterator::~const_iterator()
-{
- if (_locked) {
- _model->read_unlock();
- }
-}
-
-const MidiModel::const_iterator& MidiModel::const_iterator::operator++()
-{
- if (_is_end) {
- throw std::logic_error("Attempt to iterate past end of MidiModel");
- }
-
- assert(_event->buffer() && _event->buffer()[0] != '\0');
-
- /*cerr << "const_iterator::operator++: " << _event->to_string() << endl;*/
-
- if (! (_event->is_note() || _event->is_cc() || _event->is_pgm_change() || _event->is_pitch_bender() || _event->is_channel_aftertouch()) ) {
- cerr << "FAILED event buffer: " << hex << int(_event->buffer()[0]) << int(_event->buffer()[1]) << int(_event->buffer()[2]) << endl;
- }
- assert((_event->is_note() || _event->is_cc() || _event->is_pgm_change() || _event->is_pitch_bender() || _event->is_channel_aftertouch()));
-
- // Increment past current control event
- if (!_event->is_note() && _control_iter != _control_iters.end() && _control_iter->automation_list.get()) {
- double x = 0.0, y = 0.0;
- const bool ret = _control_iter->automation_list->rt_safe_earliest_event_unlocked(
- _control_iter->x, DBL_MAX, x, y, false);
-
- if (ret) {
- _control_iter->x = x;
- _control_iter->y = y;
- } else {
- _control_iter->automation_list.reset();
- _control_iter->x = DBL_MAX;
- }
- }
-
- const std::vector<MidiControlIterator>::iterator old_control_iter = _control_iter;
- _control_iter = _control_iters.begin();
-
- // find the _control_iter with the earliest event time
- for (std::vector<MidiControlIterator>::iterator i = _control_iters.begin();
- i != _control_iters.end(); ++i) {
- if (i->x < _control_iter->x) {
- _control_iter = i;
- }
- }
-
- enum Type {NIL, NOTE_ON, NOTE_OFF, AUTOMATION};
-
- Type type = NIL;
- double t = 0;
-
- // Next earliest note on
- if (_note_iter != _model->notes().end()) {
- type = NOTE_ON;
- t = (*_note_iter)->time();
- }
-
- // Use the next earliest note off iff it's earlier than the note on
- if (_model->note_mode() == Sustained && (! _active_notes.empty())) {
- if (type == NIL || _active_notes.top()->end_time() <= (*_note_iter)->time()) {
- type = NOTE_OFF;
- t = _active_notes.top()->end_time();
- }
- }
-
- // Use the next earliest controller iff it's earlier than the note event
- if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX /*&& _control_iter != old_control_iter */) {
- if (type == NIL || _control_iter->x < t) {
- type = AUTOMATION;
- }
- }
-
- if (type == NOTE_ON) {
- //cerr << "********** MIDI Iterator = note on" << endl;
- *_event = (*_note_iter)->on_event();
- cerr << "Event contents on note on: " << _event->to_string() << endl;
- _active_notes.push(*_note_iter);
- ++_note_iter;
- } else if (type == NOTE_OFF) {
- //cerr << "********** MIDI Iterator = note off" << endl;
- *_event = _active_notes.top()->off_event();
- _active_notes.pop();
- } else if (type == AUTOMATION) {
- //cerr << "********** MIDI Iterator = Automation" << endl;
- _model->control_to_midi_event(_event, *_control_iter);
- } else {
- //cerr << "********** MIDI Iterator = End" << endl;
- _is_end = true;
- }
-
- assert(_is_end || _event->size() > 0);
-
- return *this;
-}
-
-bool MidiModel::const_iterator::operator==(const const_iterator& other) const
-{
- if (_is_end || other._is_end) {
- return (_is_end == other._is_end);
- } else {
- return (_event == other._event);
- }
-}
-
-MidiModel::const_iterator& MidiModel::const_iterator::operator=(const const_iterator& other)
-{
- if (_locked && _model != other._model) {
- _model->read_unlock();
- }
-
- _model = other._model;
- _active_notes = other._active_notes;
- _is_end = other._is_end;
- _locked = other._locked;
- _note_iter = other._note_iter;
- _control_iters = other._control_iters;
- size_t index = other._control_iter - other._control_iters.begin();
- _control_iter = _control_iters.begin() + index;
-
- if (!_is_end) {
- _event = boost::shared_ptr<MIDI::Event>(new MIDI::Event(*other._event, true));
- }
-
- return *this;
-}
-
-// MidiModel
MidiModel::MidiModel(MidiSource *s, size_t size)
- : Automatable(s->session(), "midi model")
- , _notes(size)
- , _note_mode(Sustained)
- , _writing(false)
- , _edited(false)
- , _end_iter(*this, DBL_MAX)
- , _next_read(UINT32_MAX)
- , _read_iter(*this, DBL_MAX)
+ : ControlSet()
+ , Automatable(s->session(), "midi model")
+ , Sequence(size)
, _midi_source(s)
{
- assert(_end_iter._is_end);
- assert( ! _end_iter._locked);
}
-/** Read events in frame range \a start .. \a start+cnt into \a dst,
- * adding \a stamp_offset to each event's timestamp.
- * \return number of events written to \a dst
- */
-size_t MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes,
- nframes_t stamp_offset, nframes_t negative_stamp_offset) const
-{
- //cerr << this << " MM::read @ " << start << " frames: " << nframes << " -> " << stamp_offset << endl;
- //cerr << this << " MM # notes: " << n_notes() << endl;
-
- size_t read_events = 0;
-
- if (start != _next_read) {
- _read_iter = const_iterator(*this, (double)start);
- //cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
- } else {
- //cerr << "Using cached iterator at " << _next_read << endl;
- }
-
- _next_read = start + nframes;
-
- while (_read_iter != end() && _read_iter->time() < start + nframes) {
- assert(_read_iter->size() > 0);
- assert(_read_iter->buffer());
- dst.write(_read_iter->time() + stamp_offset - negative_stamp_offset,
- _read_iter->size(),
- _read_iter->buffer());
-
- /*cerr << this << " MidiModel::read event @ " << _read_iter->time()
- << " type: " << hex << int(_read_iter->type()) << dec
- << " note: " << int(_read_iter->note())
- << " velocity: " << int(_read_iter->velocity())
- << endl;*/
-
- ++_read_iter;
- ++read_events;
- }
-
- return read_events;
-}
-
-/** Write the controller event pointed to by \a iter to \a ev.
- * The buffer of \a ev will be allocated or resized as necessary.
- * \return true on success
- */
-bool
-MidiModel::control_to_midi_event(boost::shared_ptr<MIDI::Event>& ev, const MidiControlIterator& iter) const
-{
- assert(iter.automation_list.get());
- if (!ev) {
- ev = boost::shared_ptr<MIDI::Event>(new MIDI::Event(0, 3, NULL, true));
- }
-
- switch (iter.automation_list->parameter().type()) {
- case MidiCCAutomation:
- assert(iter.automation_list.get());
- assert(iter.automation_list->parameter().channel() < 16);
- assert(iter.automation_list->parameter().id() <= INT8_MAX);
- assert(iter.y <= INT8_MAX);
-
- ev->time() = iter.x;
- ev->realloc(3);
- ev->buffer()[0] = MIDI_CMD_CONTROL + iter.automation_list->parameter().channel();
- ev->buffer()[1] = (uint8_t)iter.automation_list->parameter().id();
- ev->buffer()[2] = (uint8_t)iter.y;
- break;
-
- case MidiPgmChangeAutomation:
- assert(iter.automation_list.get());
- assert(iter.automation_list->parameter().channel() < 16);
- assert(iter.automation_list->parameter().id() == 0);
- assert(iter.y <= INT8_MAX);
-
- ev->time() = iter.x;
- ev->realloc(2);
- ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.automation_list->parameter().channel();
- ev->buffer()[1] = (uint8_t)iter.y;
- break;
-
- case MidiPitchBenderAutomation:
- assert(iter.automation_list.get());
- assert(iter.automation_list->parameter().channel() < 16);
- assert(iter.automation_list->parameter().id() == 0);
- assert(iter.y < (1<<14));
-
- ev->time() = iter.x;
- ev->realloc(3);
- ev->buffer()[0] = MIDI_CMD_BENDER + iter.automation_list->parameter().channel();
- ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
- ev->buffer()[2] = (uint16_t(iter.y) >> 7) & 0x7F; // MSB
- //cerr << "Pitch bender event: " << ev->to_string() << " value: " << ev->pitch_bender_value() << " original value: " << iter.y << std::endl;
- break;
-
- case MidiChannelAftertouchAutomation:
- assert(iter.automation_list.get());
- assert(iter.automation_list->parameter().channel() < 16);
- assert(iter.automation_list->parameter().id() == 0);
- assert(iter.y <= INT8_MAX);
-
- ev->time() = iter.x;
- ev->realloc(2);
- ev->buffer()[0]
- = MIDI_CMD_CHANNEL_PRESSURE + iter.automation_list->parameter().channel();
- ev->buffer()[1] = (uint8_t)iter.y;
- break;
-
- default:
- return false;
- }
-
- return true;
-}
-
-
-/** Clear all events from the model.
- */
-void MidiModel::clear()
-{
- _lock.writer_lock();
- _notes.clear();
- clear_automation();
- _next_read = 0;
- _read_iter = end();
- _lock.writer_unlock();
-}
-
-
-/** Begin a write of events to the model.
- *
- * If \a mode is Sustained, complete notes with duration are constructed as note
- * on/off events are received. Otherwise (Percussive), only note on events are
- * stored; note off events are discarded entirely and all contained notes will
- * have duration 0.
- */
-void MidiModel::start_write()
-{
- //cerr << "MM " << this << " START WRITE, MODE = " << enum_2_string(_note_mode) << endl;
- write_lock();
- _writing = true;
- for (int i = 0; i < 16; ++i)
- _write_notes[i].clear();
-
- _dirty_automations.clear();
- write_unlock();
-}
-
-/** Finish a write of events to the model.
- *
- * If \a delete_stuck is true and the current mode is Sustained, note on events
- * that were never resolved with a corresonding note off will be deleted.
- * Otherwise they will remain as notes with duration 0.
- */
-void MidiModel::end_write(bool delete_stuck)
-{
- write_lock();
- assert(_writing);
-
- //cerr << "MM " << this << " END WRITE: " << _notes.size() << " NOTES\n";
-
- if (_note_mode == Sustained && delete_stuck) {
- for (Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
- if ((*n)->duration() == 0) {
- cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
- n = _notes.erase(n);
- // we have to break here because erase invalidates the iterator
- break;
- } else {
- ++n;
- }
- }
- }
-
- for (int i = 0; i < 16; ++i) {
- if (!_write_notes[i].empty()) {
- cerr << "WARNING: MidiModel::end_write: Channel " << i << " has "
- << _write_notes[i].size() << " stuck notes" << endl;
- }
- _write_notes[i].clear();
- }
-
- for (AutomationLists::const_iterator i = _dirty_automations.begin(); i != _dirty_automations.end(); ++i) {
- (*i)->Dirty.emit();
- (*i)->lookup_cache().left = -1;
- (*i)->search_cache().left = -1;
- }
-
- _writing = false;
- write_unlock();
-}
-
-/** Append \a in_event to model. NOT realtime safe.
- *
- * Timestamps of events in \a buf are expected to be relative to
- * the start of this model (t=0) and MUST be monotonically increasing
- * and MUST be >= the latest event currently in the model.
- */
-void MidiModel::append(const MIDI::Event& ev)
-{
- write_lock();
- _edited = true;
-
- assert(_notes.empty() || ev.time() >= _notes.back()->time());
- assert(_writing);
-
- if (ev.is_note_on()) {
- append_note_on_unlocked(ev.channel(), ev.time(), ev.note(),
- ev.velocity());
- } else if (ev.is_note_off()) {
- append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
- } else if (ev.is_cc()) {
- append_automation_event_unlocked(MidiCCAutomation, ev.channel(),
- ev.time(), ev.cc_number(), ev.cc_value());
- } else if (ev.is_pgm_change()) {
- append_automation_event_unlocked(MidiPgmChangeAutomation, ev.channel(),
- ev.time(), ev.pgm_number(), 0);
- } else if (ev.is_pitch_bender()) {
- append_automation_event_unlocked(MidiPitchBenderAutomation,
- ev.channel(), ev.time(), ev.pitch_bender_lsb(),
- ev.pitch_bender_msb());
- } else if (ev.is_channel_aftertouch()) {
- append_automation_event_unlocked(MidiChannelAftertouchAutomation,
- ev.channel(), ev.time(), ev.channel_aftertouch(), 0);
- } else {
- printf("WARNING: MidiModel: Unknown event type %X\n", ev.type());
- }
-
- write_unlock();
-}
-
-void MidiModel::append_note_on_unlocked(uint8_t chan, double time,
- uint8_t note_num, uint8_t velocity)
-{
- /*cerr << "MidiModel " << this << " chan " << (int)chan <<
- " note " << (int)note_num << " on @ " << time << endl;*/
-
- assert(note_num <= 127);
- assert(chan < 16);
- assert(_writing);
- _edited = true;
-
- boost::shared_ptr<Note> new_note(new Note(chan, time, 0, note_num, velocity));
- _notes.push_back(new_note);
- if (_note_mode == Sustained) {
- //cerr << "MM Sustained: Appending active note on " << (unsigned)(uint8_t)note_num << endl;
- _write_notes[chan].push_back(_notes.size() - 1);
- }/* else {
- cerr << "MM Percussive: NOT appending active note on" << endl;
- }*/
-}
-
-void MidiModel::append_note_off_unlocked(uint8_t chan, double time,
- uint8_t note_num)
-{
- /*cerr << "MidiModel " << this << " chan " << (int)chan <<
- " note " << (int)note_num << " off @ " << time << endl;*/
-
- assert(note_num <= 127);
- assert(chan < 16);
- assert(_writing);
- _edited = true;
-
- if (_note_mode == Percussive) {
- cerr << "MidiModel Ignoring note off (percussive mode)" << endl;
- return;
- }
-
- /* FIXME: make _write_notes fixed size (127 noted) for speed */
-
- /* FIXME: note off velocity for that one guy out there who actually has
- * keys that send it */
-
- bool resolved = false;
-
- for (WriteNotes::iterator n = _write_notes[chan].begin(); n
- != _write_notes[chan].end(); ++n) {
- Note& note = *_notes[*n].get();
- if (note.note() == note_num) {
- assert(time >= note.time());
- note.set_duration(time - note.time());
- _write_notes[chan].erase(n);
- //cerr << "MM resolved note, duration: " << note.duration() << endl;
- resolved = true;
- break;
- }
- }
-
- if (!resolved) {
- cerr << "MidiModel " << this << " spurious note off chan " << (int)chan
- << ", note " << (int)note_num << " @ " << time << endl;
- }
-}
-
-void MidiModel::append_automation_event_unlocked(AutomationType type,
- uint8_t chan, double time, uint8_t first_byte, uint8_t second_byte)
-{
- //cerr << "MidiModel " << this << " chan " << (int)chan <<
- // " CC " << (int)number << " = " << (int)value << " @ " << time << endl;
-
- assert(chan < 16);
- assert(_writing);
- _edited = true;
- double value;
-
- uint32_t id = 0;
-
- switch (type) {
- case MidiCCAutomation:
- id = first_byte;
- value = double(second_byte);
- break;
- case MidiChannelAftertouchAutomation:
- case MidiPgmChangeAutomation:
- id = 0;
- value = double(first_byte);
- break;
- case MidiPitchBenderAutomation:
- id = 0;
- value = double((0x7F & second_byte) << 7 | (0x7F & first_byte));
- break;
- default:
- assert(false);
- }
-
- Parameter param(type, id, chan);
- boost::shared_ptr<AutomationControl> control = Automatable::control(param, true);
- control->list()->rt_add(time, value);
-}
-
-void MidiModel::add_note_unlocked(const boost::shared_ptr<Note> note)
-{
- //cerr << "MidiModel " << this << " add note " << (int)note.note() << " @ " << note.time() << endl;
- _edited = true;
- Notes::iterator i = upper_bound(_notes.begin(), _notes.end(), note,
- note_time_comparator);
- _notes.insert(i, note);
-}
-
-void MidiModel::remove_note_unlocked(const boost::shared_ptr<const Note> note)
-{
- _edited = true;
- //cerr << "MidiModel " << this << " remove note " << (int)note.note() << " @ " << note.time() << endl;
- for (Notes::iterator n = _notes.begin(); n != _notes.end(); ++n) {
- Note& _n = *(*n);
- const Note& _note = *note;
- // TODO: There is still the issue, that after restarting ardour
- // persisted undo does not work, because of rounding errors in the
- // event times after saving/restoring to/from MIDI files
- /*cerr << "======================================= " << endl;
- cerr << int(_n.note()) << "@" << int(_n.time()) << "[" << int(_n.channel()) << "] --" << int(_n.duration()) << "-- #" << int(_n.velocity()) << endl;
- cerr << int(_note.note()) << "@" << int(_note.time()) << "[" << int(_note.channel()) << "] --" << int(_note.duration()) << "-- #" << int(_note.velocity()) << endl;
- cerr << "Equal: " << bool(_n == _note) << endl;
- cerr << endl << endl;*/
- if (_n == _note) {
- _notes.erase(n);
- // we have to break here, because erase invalidates all iterators, ie. n itself
- break;
- }
- }
-}
-
-/** Slow! for debugging only. */
-#ifndef NDEBUG
-bool MidiModel::is_sorted() const {
- bool t = 0;
- for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n)
- if ((*n)->time() < t)
- return false;
- else
- t = (*n)->time();
-
- return true;
-}
-#endif
-
/** Start a new command.
*
* This has no side-effects on the model or Session, the returned command
@@ -701,7 +61,8 @@ MidiModel::DeltaCommand* MidiModel::new_delta_command(const string name)
* Ownership of cmd is taken, it must not be deleted by the caller.
* The command will constitute one item on the undo stack.
*/
-void MidiModel::apply_command(Command* cmd)
+void
+MidiModel::apply_command(Command* cmd)
{
_session.begin_reversible_command(cmd->name());
(*cmd)();
@@ -710,7 +71,8 @@ void MidiModel::apply_command(Command* cmd)
_edited = true;
}
-// MidiEditCommand
+
+// DeltaCommand
MidiModel::DeltaCommand::DeltaCommand(boost::shared_ptr<MidiModel> m,
const std::string& name)
@@ -727,21 +89,24 @@ MidiModel::DeltaCommand::DeltaCommand(boost::shared_ptr<MidiModel> m,
set_state(node);
}
-void MidiModel::DeltaCommand::add(const boost::shared_ptr<Note> note)
+void
+MidiModel::DeltaCommand::add(const boost::shared_ptr<Evoral::Note> note)
{
//cerr << "MEC: apply" << endl;
_removed_notes.remove(note);
_added_notes.push_back(note);
}
-void MidiModel::DeltaCommand::remove(const boost::shared_ptr<Note> note)
+void
+MidiModel::DeltaCommand::remove(const boost::shared_ptr<Evoral::Note> note)
{
//cerr << "MEC: remove" << endl;
_added_notes.remove(note);
_removed_notes.push_back(note);
}
-void MidiModel::DeltaCommand::operator()()
+void
+MidiModel::DeltaCommand::operator()()
{
// This could be made much faster by using a priority_queue for added and
// removed notes (or sort here), and doing a single iteration over _model
@@ -763,10 +128,10 @@ void MidiModel::DeltaCommand::operator()()
_model->write_lock();
- for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
+ for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
_model->add_note_unlocked(*i);
- for (std::list< boost::shared_ptr<Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
+ for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
_model->remove_note_unlocked(*i);
_model->write_unlock();
@@ -778,7 +143,8 @@ void MidiModel::DeltaCommand::operator()()
_model->ContentsChanged(); /* EMIT SIGNAL */
}
-void MidiModel::DeltaCommand::undo()
+void
+MidiModel::DeltaCommand::undo()
{
// This could be made much faster by using a priority_queue for added and
// removed notes (or sort here), and doing a single iteration over _model
@@ -800,11 +166,11 @@ void MidiModel::DeltaCommand::undo()
_model->write_lock();
- for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i
+ for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i = _added_notes.begin(); i
!= _added_notes.end(); ++i)
_model->remove_note_unlocked(*i);
- for (std::list< boost::shared_ptr<Note> >::iterator i =
+ for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i =
_removed_notes.begin(); i != _removed_notes.end(); ++i)
_model->add_note_unlocked(*i);
@@ -817,7 +183,8 @@ void MidiModel::DeltaCommand::undo()
_model->ContentsChanged(); /* EMIT SIGNAL */
}
-XMLNode & MidiModel::DeltaCommand::marshal_note(const boost::shared_ptr<Note> note)
+XMLNode&
+MidiModel::DeltaCommand::marshal_note(const boost::shared_ptr<Evoral::Note> note)
{
XMLNode *xml_note = new XMLNode("note");
ostringstream note_str(ios::ate);
@@ -843,7 +210,7 @@ XMLNode & MidiModel::DeltaCommand::marshal_note(const boost::shared_ptr<Note> no
return *xml_note;
}
-boost::shared_ptr<Note> MidiModel::DeltaCommand::unmarshal_note(XMLNode *xml_note)
+boost::shared_ptr<Evoral::Note> MidiModel::DeltaCommand::unmarshal_note(XMLNode *xml_note)
{
unsigned int note;
istringstream note_str(xml_note->property("note")->value());
@@ -865,7 +232,7 @@ boost::shared_ptr<Note> MidiModel::DeltaCommand::unmarshal_note(XMLNode *xml_not
istringstream velocity_str(xml_note->property("velocity")->value());
velocity_str >> velocity;
- boost::shared_ptr<Note> note_ptr(new Note(channel, time, duration, note, velocity));
+ boost::shared_ptr<Evoral::Note> note_ptr(new Evoral::Note(channel, time, duration, note, velocity));
return note_ptr;
}
@@ -913,8 +280,8 @@ XMLNode& MidiModel::DeltaCommand::get_state()
}
struct EventTimeComparator {
- typedef const MIDI::Event* value_type;
- inline bool operator()(const MIDI::Event& a, const MIDI::Event& b) const {
+ typedef const Evoral::Event* value_type;
+ inline bool operator()(const Evoral::Event& a, const Evoral::Event& b) const {
return a.time() >= b.time();
}
};
@@ -930,14 +297,14 @@ bool MidiModel::write_to(boost::shared_ptr<MidiSource> source)
{
read_lock();
- const NoteMode old_note_mode = _note_mode;
- _note_mode = Sustained;
+ const bool old_percussive = percussive();
+ set_percussive(false);
for (const_iterator i = begin(); i != end(); ++i) {
source->append_event_unlocked(Frames, *i);
}
- _note_mode = old_note_mode;
+ set_percussive(old_percussive);
read_unlock();
_edited = false;
diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc
index 4e83413c13..d6d27a1f89 100644
--- a/libs/ardour/midi_source.cc
+++ b/libs/ardour/midi_source.cc
@@ -106,7 +106,7 @@ MidiSource::midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nfra
Glib::Mutex::Lock lm (_lock);
if (_model) {
//const size_t n_events =
- _model->read(dst, start, cnt, stamp_offset, negative_stamp_offset);
+ _model->read(dst, start, cnt, stamp_offset - negative_stamp_offset);
//cout << "Read " << n_events << " events from model." << endl;
return cnt;
} else {
diff --git a/libs/ardour/midi_stretch.cc b/libs/ardour/midi_stretch.cc
index f33c58a0fd..c11963c9d5 100644
--- a/libs/ardour/midi_stretch.cc
+++ b/libs/ardour/midi_stretch.cc
@@ -91,7 +91,7 @@ MidiStretch::run (boost::shared_ptr<Region> r)
const double new_time = i->time() * _request.time_fraction;
// FIXME: double copy
- MIDI::Event ev = MIDI::Event(*i, true);
+ Evoral::Event ev = Evoral::Event(*i, true);
ev.time() = new_time;
new_model->append(ev);
}
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 4588d6f5b9..c1203d7ba9 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -590,7 +590,7 @@ MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start_fra
uint8_t buf[3]; // CC = 3 bytes
buf[0] = MIDI_CMD_CONTROL;
- MIDI::Event ev(0, 3, buf, false);
+ Evoral::Event ev(0, 3, buf, false);
// Write track controller automation
// This now lives in MidiModel. Any need for track automation like this?
@@ -733,7 +733,7 @@ MidiTrack::MidiControl::set_value(float val)
assert(val <= _list->parameter().max());
size_t size = 3;
- if ( ! _list->automation_playback()) {
+ if ( ! automation_playback()) {
uint8_t ev[3] = { _list->parameter().channel(), int(val), 0 };
switch(_list->parameter().type()) {
case MidiCCAutomation:
diff --git a/libs/ardour/note.cc b/libs/ardour/note.cc
deleted file mode 100644
index ea1e7133af..0000000000
--- a/libs/ardour/note.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- Copyright (C) 2007 Paul Davis
- Author: Dave Robillard
-
- 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 <ardour/note.h>
-#include <iostream>
-
-namespace ARDOUR {
-
-Note::Note(uint8_t chan, double t, double d, uint8_t n, uint8_t v)
- : _on_event(t, 3, NULL, true)
- , _off_event(t + d, 3, NULL, true)
-{
- assert(chan < 16);
-
- _on_event.buffer()[0] = MIDI_CMD_NOTE_ON + chan;
- _on_event.buffer()[1] = n;
- _on_event.buffer()[2] = v;
-
- _off_event.buffer()[0] = MIDI_CMD_NOTE_OFF + chan;
- _off_event.buffer()[1] = n;
- _off_event.buffer()[2] = 0x40;
-
- assert(time() == t);
- assert(duration() == d);
- assert(note() == n);
- assert(velocity() == v);
- assert(_on_event.channel() == _off_event.channel());
- assert(channel() == chan);
-}
-
-
-Note::Note(const Note& copy)
- : _on_event(copy._on_event, true)
- , _off_event(copy._off_event, true)
-{
- assert(_on_event.buffer());
- assert(_off_event.buffer());
- /*
- assert(copy._on_event.size == 3);
- _on_event.buffer = _on_event_buffer;
- memcpy(_on_event_buffer, copy._on_event_buffer, 3);
-
- assert(copy._off_event.size == 3);
- _off_event.buffer = _off_event_buffer;
- memcpy(_off_event_buffer, copy._off_event_buffer, 3);
- */
-
- assert(time() == copy.time());
- assert(end_time() == copy.end_time());
- assert(note() == copy.note());
- assert(velocity() == copy.velocity());
- assert(duration() == copy.duration());
- assert(_on_event.channel() == _off_event.channel());
- assert(channel() == copy.channel());
-}
-
-Note::~Note()
-{
- std::cerr << "Note::~Note() Note time: " << time()
- << " pitch: " << int(note())
- << " duration: " << duration()
- << " end-time: " << end_time()
- << " velocity: " << int(velocity())
- << std::endl;
-}
-
-
-const Note&
-Note::operator=(const Note& copy)
-{
- _on_event = copy._on_event;
- _off_event = copy._off_event;
- /*_on_event.time = copy._on_event.time;
- assert(copy._on_event.size == 3);
- memcpy(_on_event_buffer, copy._on_event_buffer, 3);
-
- _off_event.time = copy._off_event.time;
- assert(copy._off_event.size == 3);
- memcpy(_off_event_buffer, copy._off_event_buffer, 3);
- */
-
- assert(time() == copy.time());
- assert(end_time() == copy.end_time());
- assert(note() == copy.note());
- assert(velocity() == copy.velocity());
- assert(duration() == copy.duration());
- assert(_on_event.channel() == _off_event.channel());
- assert(channel() == copy.channel());
-
- return *this;
-}
-
-} // namespace ARDOUR
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index 2163ba5cc0..b89c021042 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -228,7 +228,7 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
/* now that we are done loading */
- _control->list()->StateChanged ();
+ ((AutomationList*)_control->list().get())->StateChanged ();
return 0;
}
@@ -486,7 +486,7 @@ EqualPowerStereoPanner::state (bool full_state)
root->add_property (X_("type"), EqualPowerStereoPanner::name);
XMLNode* autonode = new XMLNode (X_("Automation"));
- autonode->add_child_nocopy (_control->list()->state (full_state));
+ autonode->add_child_nocopy (((AutomationList*)_control->list().get())->state (full_state));
root->add_child_nocopy (*autonode);
StreamPanner::add_state (*root);
@@ -519,9 +519,9 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
} else if ((*iter)->name() == X_("Automation")) {
- _control->list()->set_state (*((*iter)->children().front()));
+ _control->alist()->set_state (*((*iter)->children().front()));
- if (_control->list()->automation_state() != Off) {
+ if (_control->alist()->automation_state() != Off) {
set_position (_control->list()->eval (parent.session().transport_frame()));
}
}
@@ -917,7 +917,7 @@ void
Panner::set_automation_style (AutoStyle style)
{
for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) {
- (*i)->pan_control()->list()->set_automation_style (style);
+ ((AutomationList*)(*i)->pan_control()->list().get())->set_automation_style (style);
}
_session.set_dirty ();
}
@@ -926,7 +926,7 @@ void
Panner::set_automation_state (AutoState state)
{
for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) {
- (*i)->pan_control()->list()->set_automation_state (state);
+ ((AutomationList*)(*i)->pan_control()->list().get())->set_automation_state (state);
}
_session.set_dirty ();
}
@@ -935,7 +935,7 @@ AutoState
Panner::automation_state () const
{
if (!empty()) {
- return front()->pan_control()->list()->automation_state ();
+ return ((AutomationList*)front()->pan_control()->list().get())->automation_state ();
} else {
return Off;
}
@@ -945,7 +945,7 @@ AutoStyle
Panner::automation_style () const
{
if (!empty()) {
- return front()->pan_control()->list()->automation_style ();
+ return ((AutomationList*)front()->pan_control()->list().get())->automation_style ();
} else {
return Absolute;
}
@@ -955,7 +955,7 @@ void
Panner::transport_stopped (nframes_t frame)
{
for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) {
- (*i)->pan_control()->list()->reposition_for_rt_add (frame);
+ ((AutomationList*)(*i)->pan_control()->list().get())->reposition_for_rt_add (frame);
}
}
@@ -963,7 +963,7 @@ void
Panner::snapshot (nframes_t now)
{
for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) {
- boost::shared_ptr<AutomationList> list = (*i)->pan_control()->list();
+ AutomationList* list = ((AutomationList*)(*i)->pan_control()->list().get());
if (list->automation_write())
list->rt_add(now, (*i)->pan_control()->get_value());
}
@@ -1127,7 +1127,7 @@ bool
Panner::touching () const
{
for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) {
- if ((*i)->pan_control()->list()->touching ()) {
+ if (((AutomationList*)(*i)->pan_control()->list().get())->touching ()) {
return true;
}
}
diff --git a/libs/ardour/parameter.cc b/libs/ardour/parameter.cc
index 1b94e5dc4d..ea70ea7927 100644
--- a/libs/ardour/parameter.cc
+++ b/libs/ardour/parameter.cc
@@ -26,9 +26,7 @@ using namespace ARDOUR;
* (AutomationList automation-id property)
*/
Parameter::Parameter(const std::string& str)
- : _type(NullAutomation)
- , _id(0)
- , _channel(0)
+ : Evoral::Parameter (NullAutomation, 0)
{
if (str == "gain") {
_type = GainAutomation;
@@ -80,6 +78,8 @@ Parameter::Parameter(const std::string& str)
} else {
PBD::warning << "Unknown Parameter '" << str << "'" << endmsg;
}
+
+ init((AutomationType)_type); // set min/max/normal
}
@@ -87,7 +87,7 @@ Parameter::Parameter(const std::string& str)
* e.g. <AutomationList automation-id="whatthisreturns">
*/
std::string
-Parameter::to_string() const
+Parameter::symbol() const
{
if (_type == GainAutomation) {
return "gain";
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index f44a5df003..8158e55cc2 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -152,9 +152,10 @@ PluginInsert::auto_state_changed (Parameter which)
if (which.type() != PluginAutomation)
return;
- boost::shared_ptr<AutomationControl> c = control (which);
+ boost::shared_ptr<AutomationControl> c
+ = boost::dynamic_pointer_cast<AutomationControl>(control (which));
- if (c && c->list()->automation_state() != Off) {
+ if (c && ((AutomationList*)c->list().get())->automation_state() != Off) {
_plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame()));
}
}
@@ -225,15 +226,10 @@ PluginInsert::set_automatable ()
if (i->type() == PluginAutomation) {
can_automate (*i);
_plugins.front()->get_parameter_descriptor(i->id(), desc);
- boost::shared_ptr<AutomationList> list(new AutomationList(
- *i,
- //(desc.min_unbound ? FLT_MIN : desc.lower),
- //(desc.max_unbound ? FLT_MAX : desc.upper),
- desc.lower, desc.upper,
- _plugins.front()->default_value(i->id())));
-
- add_control(boost::shared_ptr<AutomationControl>(
- new PluginControl(*this, list)));
+ Parameter param(*i);
+ param.set_range(desc.lower, desc.upper, _plugins.front()->default_value(i->id()));
+ boost::shared_ptr<AutomationList> list(new AutomationList(param));
+ add_control(boost::shared_ptr<AutomationControl>(new PluginControl(*this, list)));
}
}
}
@@ -296,9 +292,10 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li, ++n) {
- boost::shared_ptr<AutomationControl> c = li->second;
+ boost::shared_ptr<AutomationControl> c
+ = boost::dynamic_pointer_cast<AutomationControl>(li->second);
- if (c->parameter().type() == PluginAutomation && c->list()->automation_playback()) {
+ if (c->parameter().type() == PluginAutomation && c->automation_playback()) {
bool valid;
const float val = c->list()->rt_safe_eval (now, valid);
@@ -371,8 +368,7 @@ PluginInsert::set_parameter (Parameter param, float val)
_plugins[0]->set_parameter (param.id(), val);
- boost::shared_ptr<AutomationControl> c = control (param);
-
+ boost::shared_ptr<Evoral::Control> c = control (param);
if (c)
c->set_value(val);
@@ -396,7 +392,7 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
nframes_t now = _session.transport_frame ();
nframes_t end = now + nframes;
- Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock lm (_control_lock, Glib::TRY_LOCK);
if (!lm.locked()) {
connect_and_run (bufs, nframes, offset, false);
@@ -434,7 +430,7 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
}
float
-PluginInsert::default_parameter_value (Parameter param)
+PluginInsert::default_parameter_value (Evoral::Parameter param)
{
if (param.type() != PluginAutomation)
return 1.0;
@@ -640,7 +636,7 @@ PluginInsert::state (bool full)
child->add_child_nocopy (automation_list (*x).state (full));
autonode->add_child_nocopy (*child);
*/
- autonode->add_child_nocopy (control(*x)->list()->state (full));
+ autonode->add_child_nocopy (((AutomationList*)control(*x)->list().get())->state (full));
}
node.add_child_nocopy (*autonode);
@@ -763,8 +759,11 @@ PluginInsert::set_state(const XMLNode& node)
continue;
}
+ boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(
+ control(Parameter(PluginAutomation, port_id), true));
+
if (!child->children().empty()) {
- control (Parameter(PluginAutomation, port_id), true)->list()->set_state (*child->children().front());
+ c->alist()->set_state (*child->children().front());
} else {
if ((cprop = child->property("auto")) != 0) {
@@ -772,13 +771,13 @@ PluginInsert::set_state(const XMLNode& node)
int x;
sscanf (cprop->value().c_str(), "0x%x", &x);
- control (Parameter(PluginAutomation, port_id), true)->list()->set_automation_state (AutoState (x));
+ c->alist()->set_automation_state (AutoState (x));
} else {
/* missing */
- control (Parameter(PluginAutomation, port_id), true)->list()->set_automation_state (Off);
+ c->alist()->set_automation_state (Off);
}
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 638c026056..79d2b4f9b6 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -2528,11 +2528,11 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
apply_gain_automation = false;
{
- Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (_control_lock, Glib::TRY_LOCK);
if (am.locked() && _session.transport_rolling()) {
- if (_gain_control->list()->automation_playback()) {
+ if (_gain_control->alist()->automation_playback()) {
apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
start_frame, end_frame, _session.gain_automation_buffer(), nframes);
}
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index bb43d4791a..2d5c0af0d5 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -450,7 +450,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
if (_model && ! _model->writing())
_model->start_write();
- MIDI::Event ev(0.0, 4, NULL, true);
+ Evoral::Event ev(0.0, 4, NULL, true);
while (true) {
bool ret = src.full_peek(sizeof(double), (uint8_t*)&time);
@@ -500,7 +500,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
void
-SMFSource::append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev)
+SMFSource::append_event_unlocked(EventTimeUnit unit, const Evoral::Event& ev)
{
if (ev.size() == 0)
return;
@@ -925,7 +925,7 @@ SMFSource::load_model(bool lock, bool force_reload)
fseek(_fd, _header_size, SEEK_SET);
uint64_t time = 0; /* in SMF ticks */
- MIDI::Event ev;
+ Evoral::Event ev;
size_t scratch_size = 0; // keep track of scratch and minimize reallocs