summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/midi_model.h
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
commit449aab3c465bbbf66d221fac3d7ea559f1720357 (patch)
tree6843cc40c88250a132acac701271f1504cd2df04 /libs/ardour/ardour/midi_model.h
parent9c0d7d72d70082a54f823cd44c0ccda5da64bb6f (diff)
rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/ardour/midi_model.h')
-rw-r--r--libs/ardour/ardour/midi_model.h252
1 files changed, 252 insertions, 0 deletions
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
new file mode 100644
index 0000000000..2481aa8d34
--- /dev/null
+++ b/libs/ardour/ardour/midi_model.h
@@ -0,0 +1,252 @@
+/*
+ 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_midi_model_h__
+#define __ardour_midi_model_h__
+
+#include <queue>
+#include <deque>
+#include <utility>
+#include <boost/utility.hpp>
+#include <glibmm/thread.h>
+#include <pbd/command.h>
+#include <ardour/types.h>
+#include <ardour/midi_buffer.h>
+#include <ardour/midi_ring_buffer.h>
+#include <ardour/automatable.h>
+#include <ardour/note.h>
+#include <ardour/types.h>
+
+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).
+ */
+class MidiModel : public boost::noncopyable, public Automatable {
+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; }
+
+ /** Add/Remove notes.
+ * Technically all operations can be implemented as one of these.
+ */
+ class DeltaCommand : public Command
+ {
+ public:
+ DeltaCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
+ DeltaCommand (boost::shared_ptr<MidiModel>, const XMLNode& node);
+
+ const std::string& name() const { return _name; }
+
+ void operator()();
+ void undo();
+
+ int set_state (const XMLNode&);
+ XMLNode& get_state ();
+
+ void add(const boost::shared_ptr<Note> note);
+ void remove(const boost::shared_ptr<Note> note);
+
+ private:
+ XMLNode &marshal_note(const boost::shared_ptr<Note> note);
+ boost::shared_ptr<Note> unmarshal_note(XMLNode *xml_note);
+
+ boost::shared_ptr<MidiModel> _model;
+ const std::string _name;
+
+ typedef std::list< boost::shared_ptr<Note> > NoteList;
+
+ NoteList _added_notes;
+ NoteList _removed_notes;
+ };
+
+ 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
+ // since controller data is stored in the .mid
+ XMLNode& get_state();
+ int set_state(const XMLNode&) { return 0; }
+
+ 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;
+};
+
+} /* namespace ARDOUR */
+
+#endif /* __ardour_midi_model_h__ */
+