X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Fmidi_model.h;h=16d972c3ccc6ef44101e220f9d8a0f0e4ea019e3;hb=022818b4a796f52c0a91eea42e65aec0bc7bed43;hp=5d16c3083626e6b62111d2281124e511c89d581a;hpb=1a0044b35d2cca7e7316d6afbb8e4955b6d7a627;p=ardour.git diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index 5d16c30836..16d972c3cc 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -30,87 +30,40 @@ #include #include #include -#include -#include +#include +#include +#include +#include namespace ARDOUR { class Session; class MidiSource; - -// x , y -typedef std::pair, std::pair > - MidiControlIterator; - - -/** This is a slightly higher level (than MidiBuffer) model of MIDI note data. - * Currently it only represents note data, which is represented as complete - * note events (ie with a start time and a duration) rather than separate - * note on and off events (controller data is not here since it's represented - * as an AutomationList) - * - * FIXME: Currently this stores event time stamps in frames. This is almost - * certainly wrong, or at least wrong most of the time (if we add an option). - * This reeeeeeally needs fixing, but frame time runs deep in Ardour... + +/** 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 AutomatableSequence { public: - MidiModel(MidiSource& s, size_t size=0); - - // This is crap. - void write_lock(); - void write_unlock(); - void read_lock() const; - void read_unlock() const; - - void clear() { _notes.clear(); } + typedef double TimeType; - 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); + MidiModel(MidiSource* s, size_t size=0); - inline const boost::shared_ptr note_at(unsigned i) const { return _notes[i]; } - inline const boost::shared_ptr note_at(unsigned i) { return _notes[i]; } + NoteMode note_mode() const { return (percussive() ? Percussive : Sustained); } + void set_note_mode(NoteMode mode) { set_percussive(mode == Percussive); }; - inline size_t n_notes() const { return _notes.size(); } - inline bool empty() const { return _notes.size() == 0 && _controls.size() == 0; } - - /* FIXME: use better data structure */ - typedef std::vector< boost::shared_ptr > Notes; - - inline static bool note_time_comparator (const boost::shared_ptr a, - const boost::shared_ptr b) { - return a->time() < b->time(); - } - - struct LaterNoteEndComparator { - typedef const Note* value_type; - inline bool operator()(const boost::shared_ptr a, - const boost::shared_ptr b) const { - return a->end_time() > b->end_time(); - } - }; - - inline Notes& notes() { return _notes; } - inline const Notes& notes() const { return _notes; } - /** Add/Remove notes. - * Technically all operations can be implemented as one of these. + * Technically all note operations can be implemented as one of these, but + * a custom command can be more efficient. */ - class DeltaCommand : public Command - { + class DeltaCommand : public Command { public: - DeltaCommand (MidiModel& m, const std::string& name) - : Command(name), _model(m), _name(name) {} - DeltaCommand (MidiModel&, const XMLNode& node); + DeltaCommand (boost::shared_ptr m, const std::string& name); + DeltaCommand (boost::shared_ptr m, const XMLNode& node); const std::string& name() const { return _name; } @@ -120,118 +73,42 @@ public: int set_state (const XMLNode&); XMLNode& get_state (); - void add(const boost::shared_ptr note); - void remove(const boost::shared_ptr note); + void add(const boost::shared_ptr< Evoral::Note > note); + void remove(const boost::shared_ptr< Evoral::Note > note); private: - class NoteMarshaller { - public: - XMLNode *operator()(const boost::shared_ptr note); - }; + XMLNode &marshal_note(const boost::shared_ptr< Evoral::Note > note); + boost::shared_ptr< Evoral::Note > unmarshal_note(XMLNode *xml_note); + + boost::shared_ptr _model; + const std::string _name; + + typedef std::list< boost::shared_ptr< Evoral::Note > > NoteList; - class NoteUnmarshaller { - public: - boost::shared_ptr operator()(XMLNode *xml_note); - }; - - MidiModel& _model; - const std::string _name; - std::list< boost::shared_ptr > _added_notes; - std::list< boost::shared_ptr > _removed_notes; + NoteList _added_notes; + NoteList _removed_notes; }; MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit"); - void apply_command(Command* cmd); + void apply_command(Session& session, Command* cmd); - bool edited() const { return _edited; } - void set_edited(bool yn) { _edited = yn; } bool write_to(boost::shared_ptr source); - // MidiModel doesn't use the normal AutomationList serialisation code, as CC data is in the .mid + // MidiModel doesn't use the normal AutomationList serialisation code + // since controller data is stored in the .mid XMLNode& get_state(); int set_state(const XMLNode&) { return 0; } sigc::signal 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 MIDI::Event* operator->() const { 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; - MIDI::Event _event; - - typedef std::priority_queue< - boost::shared_ptr, std::deque< boost::shared_ptr >, - LaterNoteEndComparator> - ActiveNotes; - - mutable ActiveNotes _active_notes; - - bool _is_end; - bool _locked; - Notes::const_iterator _note_iter; - std::vector _control_iters; - std::vector::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; } + const MidiSource* midi_source() const { return _midi_source; } + void set_midi_source(MidiSource* source) { _midi_source = source; } private: friend class DeltaCommand; - void add_note_unlocked(const boost::shared_ptr note); - void remove_note_unlocked(const boost::shared_ptr note); - - friend class const_iterator; - bool control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& iter) const; - -#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_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t value); - - mutable Glib::RWLock _lock; - - Notes _notes; - NoteMode _note_mode; - - typedef std::vector WriteNotes; - WriteNotes _write_notes[16]; - bool _writing; - bool _edited; - - const const_iterator _end_iter; - - mutable nframes_t _next_read; - mutable const_iterator _read_iter; - - typedef std::priority_queue< - boost::shared_ptr, std::deque< boost::shared_ptr >, - LaterNoteEndComparator> - ActiveNotes; - MidiSource& _midi_source; + // We cannot use a boost::shared_ptr here to avoid a retain cycle + MidiSource* _midi_source; }; } /* namespace ARDOUR */