f1fcabfb1f1948fd0d7fec23a071015fe01fa09d
[ardour.git] / libs / ardour / ardour / midi_model.h
1 /*
2     Copyright (C) 2007 Paul Davis
3     Author: Dave Robillard
4
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.
9
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.
14
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.
18
19 */
20
21 #ifndef __ardour_midi_model_h__ 
22 #define __ardour_midi_model_h__
23
24 #include <queue>
25 #include <boost/utility.hpp>
26 #include <pbd/command.h>
27 #include <ardour/types.h>
28 #include <ardour/midi_buffer.h>
29 #include <ardour/midi_ring_buffer.h>
30
31 namespace ARDOUR {
32
33 class Session;
34
35
36 /** This is a slightly higher level (than MidiBuffer) model of MIDI note data.
37  * Currently it only represents note data, which is represented as complete
38  * note events (ie with a start time and a duration) rather than separate
39  * note on and off events (controller data is not here since it's represented
40  * as an AutomationList)
41  */
42 class MidiModel : public boost::noncopyable {
43 public:
44         struct Note {
45                 Note(double time=0, double dur=0, uint8_t note=0, uint8_t vel=0x40);
46                 Note(const Note& copy);
47                 
48                 const MidiModel::Note& operator=(const MidiModel::Note& copy);
49
50                 inline bool operator==(const Note& other)
51                         { return time() == other.time() && note() == other.note(); }
52
53                 inline double  time()     const { return _on_event.time(); }
54                 inline double  end_time() const { return _off_event.time(); }
55                 inline uint8_t note()     const { return _on_event.note(); }
56                 inline uint8_t velocity() const { return _on_event.velocity(); }
57                 inline double  duration() const { return _off_event.time() - _on_event.time(); }
58
59                 inline void set_time(double t)      { _off_event.time() = t + duration(); _on_event.time() = t; }
60                 inline void set_note(uint8_t n)     { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; }
61                 inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; }
62                 inline void set_duration(double d)  { _off_event.time() = _on_event.time() + d; }
63
64                 inline MidiEvent& on_event()  { return _on_event; }
65                 inline MidiEvent& off_event() { return _off_event; }
66         
67                 inline const MidiEvent& on_event()  const { return _on_event; }
68                 inline const MidiEvent& off_event() const { return _off_event; }
69
70         private:
71                 // Event buffers are self-contained
72                 MidiEvent _on_event;
73                 MidiEvent _off_event;
74         };
75
76         MidiModel(Session& s, size_t size=0);
77
78         void clear() { _notes.clear(); }
79
80         NoteMode note_mode() const            { return _note_mode; }
81         void     set_note_mode(NoteMode mode) { _note_mode = mode; }
82
83         void start_write();
84         bool currently_writing() const { return _writing; }
85         void end_write(bool delete_stuck=false);
86
87         size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const;
88
89         /** Resizes vector if necessary (NOT realtime safe) */
90         void append(const MidiBuffer& data);
91         
92         /** Resizes vector if necessary (NOT realtime safe) */
93         void append(double time, size_t size, const Byte* in_buffer);
94         
95         inline const Note& note_at(unsigned i) const { return _notes[i]; }
96
97         inline size_t n_notes() const { return _notes.size(); }
98
99         typedef std::vector<Note> Notes;
100         
101         inline static bool note_time_comparator (const Note& a, const Note& b) { 
102                 return a.time() < b.time();
103         }
104
105         struct LaterNoteEndComparator {
106                 typedef const Note* value_type;
107                 inline bool operator()(const Note* const a, const Note* const b) { 
108                         return a->end_time() > b->end_time();
109                 }
110         };
111
112         inline       Notes& notes()       { return _notes; }
113         inline const Notes& notes() const { return _notes; }
114         
115         /** Add/Remove notes.
116          * Technically all operations can be implemented as one of these.
117          */
118         class DeltaCommand : public Command
119         {
120         public:
121                 DeltaCommand (MidiModel& m, const std::string& name)
122                         : Command(name), _model(m), _name(name) {}
123                 //DeltaCommand (MidiModel&, const XMLNode& node);
124
125                 const std::string& name() const { return _name; }
126                 
127                 void operator()();
128                 void undo();
129                 
130                 /*int set_state (const XMLNode&);
131                 XMLNode& get_state ();*/
132
133                 void add(const Note& note);
134                 void remove(const Note& note);
135
136         private:
137                 MidiModel&      _model;
138                 std::string     _name;
139                 std::list<Note> _added_notes;
140                 std::list<Note> _removed_notes;
141         };
142
143         MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit");
144         void                     apply_command(Command* cmd);
145
146         bool write_new_source(const std::string& path);
147
148         sigc::signal<void> ContentsChanged;
149         
150 private:
151         friend class DeltaCommand;
152         void add_note(const Note& note);
153         void remove_note(const Note& note);
154
155         bool is_sorted() const;
156
157         void append_note_on(double time, uint8_t note, uint8_t velocity);
158         void append_note_off(double time, uint8_t note);
159
160         Session& _session;
161
162         Notes    _notes;
163         NoteMode _note_mode;
164         
165         typedef std::vector<size_t> WriteNotes;
166         WriteNotes _write_notes;
167         bool       _writing;
168         
169         // note state for read():
170         
171         typedef std::priority_queue<const Note*,std::vector<const Note*>,
172                         LaterNoteEndComparator> ActiveNotes;
173
174         mutable ActiveNotes _active_notes;
175 };
176
177 } /* namespace ARDOUR */
178
179 #endif /* __ardour_midi_model_h__ */
180