diff options
author | David Robillard <d@drobilla.net> | 2008-09-19 00:47:49 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2008-09-19 00:47:49 +0000 |
commit | d357eca668044badcb4bab318e2e74cfffa9a0b0 (patch) | |
tree | eab9bf33b194f9e37c20f84375e5caa748ee994a /libs/ardour | |
parent | 3d976c5b727e4d55ce439b1d7c055a814477fa1a (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')
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 |