Make (MIDI) event time stamp type a template parameter.
[ardour.git] / libs / ardour / midi_port.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cassert>
20 #include <iostream>
21
22 #include <ardour/midi_port.h>
23 #include <ardour/data_type.h>
24
25 using namespace ARDOUR;
26 using namespace std;
27
28 MidiPort::MidiPort (const std::string& name, Flags flags, bool ext, nframes_t capacity)
29         : Port (name, DataType::MIDI, flags, ext)
30         , _has_been_mixed_down (false)
31 {
32         // FIXME: size kludge (see BufferSet::ensure_buffers)
33         // Jack needs to tell us this
34         _buffer = new MidiBuffer (capacity * 32);
35 }
36
37 MidiPort::~MidiPort()
38 {
39         delete _buffer;
40 }
41
42
43 void
44 MidiPort::cycle_start (nframes_t nframes, nframes_t offset)
45 {
46         if (external ()) {
47                 _buffer->clear ();
48                 assert (_buffer->size () == 0);
49
50                 if (sends_output ()) {
51                         jack_midi_clear_buffer (jack_port_get_buffer (_jack_port, nframes));
52                 }
53         }
54 }
55
56 MidiBuffer &
57 MidiPort::get_midi_buffer (nframes_t nframes, nframes_t offset)
58 {
59         if (_has_been_mixed_down) {
60             return *_buffer;
61         }
62
63         if (receives_input ()) {
64                         
65                 if (external ()) {
66                 
67                         void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
68                         const nframes_t event_count = jack_midi_get_event_count(jack_buffer);
69
70                         assert (event_count < _buffer->capacity());
71
72                         jack_midi_event_t ev;
73
74                         for (nframes_t i = 0; i < event_count; ++i) {
75
76                                 jack_midi_event_get (&ev, jack_buffer, i);
77
78                                 // i guess this should do but i leave it off to test the rest first.
79                                 //if (ev.time > offset && ev.time < offset+nframes)
80                                 _buffer->push_back (ev);
81                         }
82
83                         if (nframes) {
84                                 _has_been_mixed_down = true;
85                         }
86
87                         if (!_connections.empty()) {
88                                 mixdown (nframes, offset, false);
89                         }
90
91                 } else {
92                 
93                         if (_connections.empty()) {
94                                 _buffer->silence (nframes, offset);
95                         } else {
96                                 mixdown (nframes, offset, true);
97                         }
98                 }
99
100         } else {
101                 _buffer->silence (nframes, offset);
102         }
103         
104         if (nframes) {
105                 _has_been_mixed_down = true;
106         }
107
108         return *_buffer;
109 }
110
111         
112 void
113 MidiPort::cycle_end (nframes_t nframes, nframes_t offset)
114 {
115 #if 0
116
117         if (external () && sends_output ()) {
118                 /* FIXME: offset */
119
120                 // We're an output - copy events from source buffer to Jack buffer
121                 
122                 void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
123                 
124                 jack_midi_clear_buffer (jack_buffer);
125                 
126                 for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
127                         const Evoral::Event& ev = *i;
128
129                         // event times should be frames, relative to cycle start
130                         assert(ev.time() >= 0);
131                         assert(ev.time() < nframes);
132                         jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size());
133                 }
134         }
135 #endif
136
137         _has_been_mixed_down = false;
138 }
139
140 void
141 MidiPort::flush_buffers (nframes_t nframes, nframes_t offset)
142 {
143         /* FIXME: offset */
144         
145         if (external () && sends_output ()) {
146                 
147                 void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
148
149                 for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
150                         const Evoral::Event<double>& ev = *i;
151                         // event times should be frames, relative to cycle start
152                         assert(ev.time() >= 0);
153                         assert(ev.time() < (nframes+offset));
154                         if (ev.time() >= offset) {
155                                 jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size());
156                         }
157                 }
158         }
159 }
160
161 void
162 MidiPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite)
163 {
164         set<Port*>::const_iterator p = _connections.begin();
165
166         if (first_overwrite) {
167                 _buffer->read_from ((dynamic_cast<MidiPort*>(*p))->get_midi_buffer (cnt, offset), cnt, offset);
168                 ++p;
169         }
170
171         // XXX DAVE: this is just a guess
172
173         for (; p != _connections.end(); ++p) {
174                 _buffer->merge (*_buffer, (dynamic_cast<MidiPort*>(*p))->get_midi_buffer (cnt, offset));
175         }
176 }
177