Fix more broken whitespace.
[ardour.git] / libs / ardour / midi_state_tracker.cc
1 /*
2     Copyright (C) 2006-2008 Paul Davis
3     Author: Torben Hohn
4
5     This program is free software; you can redistribute it and/or modify it
6     under the terms of the GNU General Public License as published by the Free
7     Software Foundation; either version 2 of the License, or (at your option)
8     any later version.
9
10     This program is distributed in the hope that it will be useful, but WITHOUT
11     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13     for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <iostream>
21 #include "ardour/event_type_map.h"
22 #include "ardour/midi_ring_buffer.h"
23 #include "ardour/midi_source.h"
24 #include "ardour/midi_state_tracker.h"
25
26 using namespace std;
27 using namespace ARDOUR;
28
29
30 MidiStateTracker::MidiStateTracker ()
31 {
32         reset ();
33 }
34
35 void
36 MidiStateTracker::reset ()
37 {
38         memset (_active_notes, 0, sizeof (_active_notes));
39         _on = 0;
40 }
41
42 void
43 MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent<MidiBuffer::TimeType>& event)
44 {
45         if (event.is_note_on()) {
46                 add (event.note(), event.channel());
47         } else if (event.is_note_off()){
48                 remove (event.note(), event.channel());
49         }
50 }
51
52 void
53 MidiStateTracker::add (uint8_t note, uint8_t chn)
54 {
55         ++_active_notes[note + 128 * chn];
56         ++_on;
57 }
58
59 void
60 MidiStateTracker::remove (uint8_t note, uint8_t chn)
61 {
62         switch (_active_notes[note + 128 * chn]) {
63         case 0:
64                 break;
65         case 1:
66                 --_on;
67                 _active_notes [note + 128 * chn] = 0;
68                 break;
69         default:
70                 --_active_notes [note + 128 * chn];
71                                 break;
72
73         }
74 }
75
76 void
77 MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to, bool& looped)
78 {
79         looped = false;
80
81         for (MidiBuffer::iterator i = from; i != to; ++i) {
82                 const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
83                 if (ev.event_type() == LoopEventType) {
84                         looped = true;
85                         continue;
86                 }
87
88                 track_note_onoffs (ev);
89         }
90 }
91
92 void
93 MidiStateTracker::resolve_notes (MidiBuffer &dst, framepos_t time)
94 {
95         if (!_on) {
96                 return;
97         }
98
99         for (int channel = 0; channel < 16; ++channel) {
100                 for (int note = 0; note < 128; ++note) {
101                         while (_active_notes[note + 128 * channel]) {
102                                 uint8_t buffer[3] = { MIDI_CMD_NOTE_OFF | channel, note, 0 };
103                                 Evoral::MIDIEvent<MidiBuffer::TimeType> noteoff
104                                         (MIDI_CMD_NOTE_OFF, time, 3, buffer, false);
105                                 dst.push_back (noteoff);
106                                 _active_notes[note + 128 * channel]--;
107                         }
108                 }
109         }
110         _on = 0;
111 }
112
113 void
114 MidiStateTracker::resolve_notes (Evoral::EventSink<framepos_t> &dst, framepos_t time)
115 {
116         uint8_t buf[3];
117
118         if (!_on) {
119                 return;
120         }
121
122         for (int channel = 0; channel < 16; ++channel) {
123                 for (int note = 0; note < 128; ++note) {
124                         while (_active_notes[note + 128 * channel]) {
125                                 buf[0] = MIDI_CMD_NOTE_OFF|channel;
126                                 buf[1] = note;
127                                 buf[2] = 0;
128                                 dst.write (time, EventTypeMap::instance().midi_event_type (buf[0]), 3, buf);
129                                 _active_notes[note + 128 * channel]--;
130                         }
131                 }
132         }
133         _on = 0;
134 }
135
136 void
137 MidiStateTracker::resolve_notes (MidiSource& src, Evoral::MusicalTime time)
138 {
139         if (!_on) {
140                 return;
141         }
142
143         /* NOTE: the src must be locked */
144
145         for (int channel = 0; channel < 16; ++channel) {
146                 for (int note = 0; note < 128; ++note) {
147                         while (_active_notes[note + 128 * channel]) {
148                                 Evoral::MIDIEvent<Evoral::MusicalTime> ev ((MIDI_CMD_NOTE_OFF|channel), time, 3, 0, true);
149                                 ev.set_type (MIDI_CMD_NOTE_OFF);
150                                 ev.set_channel (channel);
151                                 ev.set_note (note);
152                                 ev.set_velocity (0);
153                                 src.append_event_unlocked_beats (ev);
154                                 _active_notes[note + 128 * channel]--;
155                                 /* don't stack events up at the same time */
156                                 time += 1.0/128.0;
157                         }
158                 }
159         }
160         _on = 0;
161 }
162
163 void
164 MidiStateTracker::dump (ostream& o)
165 {
166         o << "******\n";
167         for (int c = 0; c < 16; ++c) {
168                 for (int x = 0; x < 128; ++x) {
169                         if (_active_notes[c * 128 + x]) {
170                                 o << "Channel " << c+1 << " Note " << x << " is on ("
171                                   << (int) _active_notes[c*128+x] <<  "times)\n";
172                         }
173                 }
174         }
175         o << "+++++\n";
176 }