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>
35 #include <ardour/types.h>
43 * This class keeps track of the current x and y for a control
45 class MidiControlIterator {
47 boost::shared_ptr<const AutomationList> automation_list;
51 MidiControlIterator(boost::shared_ptr<const AutomationList> a_list,
54 : automation_list(a_list)
61 /** This is a higher level (than MidiBuffer) model of MIDI data, with separate
62 * representations for notes (instead of just unassociated note on/off events)
63 * and controller data. Controller data is represented as part of the
64 * Automatable base (i.e. in a map of AutomationList, keyed by Parameter).
66 class MidiModel : public boost::noncopyable, public Automatable {
68 MidiModel(MidiSource* s, size_t size=0);
73 void read_lock() const;
74 void read_unlock() const;
78 NoteMode note_mode() const { return _note_mode; }
79 void set_note_mode(NoteMode mode) { _note_mode = mode; }
82 bool writing() const { return _writing; }
83 void end_write(bool delete_stuck=false);
85 size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset, nframes_t negative_stamp_offset) const;
87 /** Resizes vector if necessary (NOT realtime safe) */
88 void append(const MIDI::Event& ev);
90 inline const boost::shared_ptr<const Note> note_at(unsigned i) const { return _notes[i]; }
91 inline const boost::shared_ptr<Note> note_at(unsigned i) { return _notes[i]; }
93 inline size_t n_notes() const { return _notes.size(); }
94 inline bool empty() const { return _notes.size() == 0 && _controls.size() == 0; }
96 inline static bool note_time_comparator (const boost::shared_ptr<const Note> a,
97 const boost::shared_ptr<const Note> b) {
98 return a->time() < b->time();
101 struct LaterNoteEndComparator {
102 typedef const Note* value_type;
103 inline bool operator()(const boost::shared_ptr<const Note> a,
104 const boost::shared_ptr<const Note> b) const {
105 return a->end_time() > b->end_time();
109 typedef std::vector< boost::shared_ptr<Note> > Notes;
110 inline Notes& notes() { return _notes; }
111 inline const Notes& notes() const { return _notes; }
113 /** Add/Remove notes.
114 * Technically all operations can be implemented as one of these.
116 class DeltaCommand : public Command
119 DeltaCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
120 DeltaCommand (boost::shared_ptr<MidiModel>, const XMLNode& node);
122 const std::string& name() const { return _name; }
127 int set_state (const XMLNode&);
128 XMLNode& get_state ();
130 void add(const boost::shared_ptr<Note> note);
131 void remove(const boost::shared_ptr<Note> note);
134 XMLNode &marshal_note(const boost::shared_ptr<Note> note);
135 boost::shared_ptr<Note> unmarshal_note(XMLNode *xml_note);
137 boost::shared_ptr<MidiModel> _model;
138 const std::string _name;
140 typedef std::list< boost::shared_ptr<Note> > NoteList;
142 NoteList _added_notes;
143 NoteList _removed_notes;
146 MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit");
147 void apply_command(Command* cmd);
149 bool edited() const { return _edited; }
150 void set_edited(bool yn) { _edited = yn; }
151 bool write_to(boost::shared_ptr<MidiSource> source);
153 // MidiModel doesn't use the normal AutomationList serialisation code
154 // since controller data is stored in the .mid
155 XMLNode& get_state();
156 int set_state(const XMLNode&) { return 0; }
158 sigc::signal<void> ContentsChanged;
161 class const_iterator {
163 const_iterator(const MidiModel& model, double t);
166 inline bool locked() const { return _locked; }
168 const MIDI::Event& operator*() const { return *_event; }
169 const boost::shared_ptr<MIDI::Event> operator->() const { return _event; }
170 const boost::shared_ptr<MIDI::Event> get_event_pointer() { return _event; }
172 const const_iterator& operator++(); // prefix only
173 bool operator==(const const_iterator& other) const;
174 bool operator!=(const const_iterator& other) const { return ! operator==(other); }
176 const_iterator& operator=(const const_iterator& other);
179 friend class MidiModel;
181 const MidiModel* _model;
182 boost::shared_ptr<MIDI::Event> _event;
184 typedef std::priority_queue<
185 boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
186 LaterNoteEndComparator>
189 mutable ActiveNotes _active_notes;
193 Notes::const_iterator _note_iter;
194 std::vector<MidiControlIterator> _control_iters;
195 std::vector<MidiControlIterator>::iterator _control_iter;
198 const_iterator begin() const { return const_iterator(*this, 0); }
199 const const_iterator& end() const { return _end_iter; }
201 const MidiSource* midi_source() const { return _midi_source; }
202 void set_midi_source(MidiSource* source) { _midi_source = source; }
203 bool control_to_midi_event(boost::shared_ptr<MIDI::Event>& ev, const MidiControlIterator& iter) const;
206 friend class DeltaCommand;
207 void add_note_unlocked(const boost::shared_ptr<Note> note);
208 void remove_note_unlocked(const boost::shared_ptr<const Note> note);
210 friend class const_iterator;
213 bool is_sorted() const;
216 void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
217 void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
218 void append_automation_event_unlocked(AutomationType type, uint8_t chan, double time, uint8_t first_byte, uint8_t second_byte);
219 void append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number);
221 mutable Glib::RWLock _lock;
227 typedef std::vector<size_t> WriteNotes;
228 WriteNotes _write_notes[16];
232 typedef std::vector< boost::shared_ptr<const ARDOUR::AutomationList> > AutomationLists;
233 AutomationLists _dirty_automations;
235 const const_iterator _end_iter;
237 mutable nframes_t _next_read;
238 mutable const_iterator _read_iter;
240 typedef std::priority_queue<
241 boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
242 LaterNoteEndComparator>
245 // We cannot use a boost::shared_ptr here to avoid a retain cycle
246 MidiSource* _midi_source;
249 } /* namespace ARDOUR */
251 #endif /* __ardour_midi_model_h__ */