2 Copyright (C) 2007 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #ifndef __ardour_midi_model_h__
22 #define __ardour_midi_model_h__
27 #include <boost/utility.hpp>
28 #include <glibmm/thread.h>
29 #include <pbd/command.h>
30 #include <ardour/types.h>
31 #include <ardour/midi_buffer.h>
32 #include <ardour/midi_ring_buffer.h>
33 #include <ardour/automatable.h>
34 #include <ardour/note.h>
42 typedef std::pair<boost::shared_ptr<const AutomationList>, std::pair<double,double> >
46 /** This is a slightly higher level (than MidiBuffer) model of MIDI note data.
47 * Currently it only represents note data, which is represented as complete
48 * note events (ie with a start time and a duration) rather than separate
49 * note on and off events (controller data is not here since it's represented
50 * as an AutomationList)
52 * FIXME: Currently this stores event time stamps in frames. This is almost
53 * certainly wrong, or at least wrong most of the time (if we add an option).
54 * This reeeeeeally needs fixing, but frame time runs deep in Ardour...
56 class MidiModel : public boost::noncopyable, public Automatable {
58 MidiModel(MidiSource *s, size_t size=0);
63 void read_lock() const;
64 void read_unlock() const;
66 void clear() { _notes.clear(); }
68 NoteMode note_mode() const { return _note_mode; }
69 void set_note_mode(NoteMode mode) { _note_mode = mode; }
72 bool writing() const { return _writing; }
73 void end_write(bool delete_stuck=false);
75 size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset, nframes_t negative_stamp_offset) const;
77 /** Resizes vector if necessary (NOT realtime safe) */
78 void append(const MIDI::Event& ev);
80 inline const boost::shared_ptr<const Note> note_at(unsigned i) const { return _notes[i]; }
81 inline const boost::shared_ptr<Note> note_at(unsigned i) { return _notes[i]; }
83 inline size_t n_notes() const { return _notes.size(); }
84 inline bool empty() const { return _notes.size() == 0 && _controls.size() == 0; }
86 /* FIXME: use better data structure */
87 typedef std::vector< boost::shared_ptr<Note> > Notes;
89 inline static bool note_time_comparator (const boost::shared_ptr<const Note> a,
90 const boost::shared_ptr<const Note> b) {
91 return a->time() < b->time();
94 struct LaterNoteEndComparator {
95 typedef const Note* value_type;
96 inline bool operator()(const boost::shared_ptr<const Note> a,
97 const boost::shared_ptr<const Note> b) const {
98 return a->end_time() > b->end_time();
102 inline Notes& notes() { return _notes; }
103 inline const Notes& notes() const { return _notes; }
105 /** Add/Remove notes.
106 * Technically all operations can be implemented as one of these.
108 class DeltaCommand : public Command
111 DeltaCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
112 DeltaCommand (boost::shared_ptr<MidiModel>, const XMLNode& node);
114 const std::string& name() const { return _name; }
119 int set_state (const XMLNode&);
120 XMLNode& get_state ();
122 void add(const boost::shared_ptr<Note> note);
123 void remove(const boost::shared_ptr<Note> note);
126 XMLNode &marshal_note(const boost::shared_ptr<Note> note);
127 boost::shared_ptr<Note> unmarshal_note(XMLNode *xml_note);
129 boost::shared_ptr<MidiModel> _model;
130 const std::string _name;
132 typedef std::list< boost::shared_ptr<Note> > NoteList;
134 NoteList _added_notes;
135 NoteList _removed_notes;
138 MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit");
139 void apply_command(Command* cmd);
141 bool edited() const { return _edited; }
142 void set_edited(bool yn) { _edited = yn; }
143 bool write_to(boost::shared_ptr<MidiSource> source);
145 // MidiModel doesn't use the normal AutomationList serialisation code, as CC data is in the .mid
146 XMLNode& get_state();
147 int set_state(const XMLNode&) { return 0; }
149 sigc::signal<void> ContentsChanged;
152 class const_iterator {
154 const_iterator(const MidiModel& model, double t);
157 inline bool locked() const { return _locked; }
159 const MIDI::Event& operator*() const { return _event; }
160 const MIDI::Event* operator->() const { return &_event; }
162 const const_iterator& operator++(); // prefix only
163 bool operator==(const const_iterator& other) const;
164 bool operator!=(const const_iterator& other) const { return ! operator==(other); }
166 const_iterator& operator=(const const_iterator& other);
169 friend class MidiModel;
171 const MidiModel* _model;
174 typedef std::priority_queue<
175 boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
176 LaterNoteEndComparator>
179 mutable ActiveNotes _active_notes;
183 Notes::const_iterator _note_iter;
184 std::vector<MidiControlIterator> _control_iters;
185 std::vector<MidiControlIterator>::iterator _control_iter;
188 const_iterator begin() const { return const_iterator(*this, 0); }
189 const const_iterator& end() const { return _end_iter; }
191 const MidiSource *midi_source() const { return _midi_source; }
192 void set_midi_source(MidiSource *source) { _midi_source = source; }
195 friend class DeltaCommand;
196 void add_note_unlocked(const boost::shared_ptr<Note> note);
197 void remove_note_unlocked(const boost::shared_ptr<const Note> note);
199 friend class const_iterator;
200 bool control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& iter) const;
203 bool is_sorted() const;
206 void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
207 void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
208 void append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t value);
210 mutable Glib::RWLock _lock;
215 typedef std::vector<size_t> WriteNotes;
216 WriteNotes _write_notes[16];
220 const const_iterator _end_iter;
222 mutable nframes_t _next_read;
223 mutable const_iterator _read_iter;
225 typedef std::priority_queue<
226 boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
227 LaterNoteEndComparator>
230 // We cannot use a boost::shared_ptr here to avoid a retain cycle
231 MidiSource *_midi_source;
234 } /* namespace ARDOUR */
236 #endif /* __ardour_midi_model_h__ */