fix conflicts and merge with master
[ardour.git] / libs / ardour / async_midi_port.cc
1 /*
2     Copyright (C) 1998 Paul Barton-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     $Id$
19 */
20
21 #include <iostream>
22
23 #include "pbd/error.h"
24 #include "pbd/stacktrace.h"
25
26 #include "midi++/types.h"
27
28 #include "ardour/async_midi_port.h"
29 #include "ardour/audioengine.h"
30 #include "ardour/midi_buffer.h"
31
32 using namespace MIDI;
33 using namespace ARDOUR;
34 using namespace std;
35 using namespace PBD;
36
37 namespace Evoral {
38         template class EventRingBuffer<MIDI::timestamp_t>;
39 }
40
41 pthread_t AsyncMIDIPort::_process_thread;
42
43 #define port_engine AudioEngine::instance()->port_engine()
44
45 AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
46         : MidiPort (name, flags)
47         , MIDI::Port (name, MIDI::Port::Flags (0))
48         , _currently_in_cycle (false)
49         , _last_write_timestamp (0)
50         , output_fifo (512)
51         , input_fifo (1024)
52         , xthread (true)
53 {
54 }
55
56 AsyncMIDIPort::~AsyncMIDIPort ()
57 {
58 }
59
60 void
61 AsyncMIDIPort::flush_output_fifo (pframes_t nframes)
62 {
63         RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
64         size_t written;
65
66         output_fifo.get_read_vector (&vec);
67
68         MidiBuffer& mb (get_midi_buffer (nframes));
69                         
70         if (vec.len[0]) {
71                 Evoral::Event<double>* evp = vec.buf[0];
72                 
73                 for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
74                         mb.push_back (evp->time(), evp->size(), evp->buffer());
75                 }
76         }
77         
78         if (vec.len[1]) {
79                 Evoral::Event<double>* evp = vec.buf[1];
80
81                 for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
82                         mb.push_back (evp->time(), evp->size(), evp->buffer());
83                 }
84         }
85         
86         if ((written = vec.len[0] + vec.len[1]) != 0) {
87                 output_fifo.increment_read_idx (written);
88         }
89 }
90
91 void
92 AsyncMIDIPort::cycle_start (pframes_t nframes)
93 {
94         _currently_in_cycle = true;
95         MidiPort::cycle_start (nframes);
96
97         /* dump anything waiting in the output FIFO at the start of the port
98          * buffer
99          */
100
101         if (ARDOUR::Port::sends_output()) {
102                 flush_output_fifo (nframes);
103         } 
104         
105         /* copy incoming data from the port buffer into the input FIFO
106            and if necessary wakeup the reader
107         */
108
109         if (ARDOUR::Port::receives_input()) {
110                 MidiBuffer& mb (get_midi_buffer (nframes));
111                 pframes_t when = AudioEngine::instance()->sample_time_at_cycle_start();
112
113                 for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
114                         input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer());
115                 }
116                 
117                 if (!mb.empty()) {
118                         xthread.wakeup ();
119                 }
120         }
121
122 }
123
124 void
125 AsyncMIDIPort::cycle_end (pframes_t nframes)
126 {
127         if (ARDOUR::Port::sends_output()) {
128                 /* move any additional data from output FIFO into the port
129                    buffer.
130                 */
131                 flush_output_fifo (nframes);
132         }
133
134         MidiPort::cycle_end (nframes);
135
136         _currently_in_cycle = false;
137 }
138
139 /** wait for the output FIFO to be emptied by successive process() callbacks.
140  *
141  * Cannot be called from a processing thread.
142  */
143 void
144 AsyncMIDIPort::drain (int check_interval_usecs)
145 {
146         RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
147
148         if (!AudioEngine::instance()->running() || AudioEngine::instance()->session() == 0) {
149                 /* no more process calls - it will never drain */
150                 return;
151         }
152
153
154         if (is_process_thread()) {
155                 error << "Process thread called MIDI::AsyncMIDIPort::drain() - this cannot work" << endmsg;
156                 return;
157         }
158
159         while (1) {
160                 output_fifo.get_write_vector (&vec);
161                 if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) {
162                         break;
163                 }
164                 usleep (check_interval_usecs);
165         }
166 }
167
168 int
169 AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t timestamp)
170 {
171         int ret = 0;
172
173         if (!ARDOUR::Port::sends_output()) {
174                 return ret;
175         }
176
177         if (!is_process_thread()) {
178
179                 /* this is the best estimate of "when" this MIDI data is being
180                  * delivered
181                  */
182                 
183                 _parser->set_timestamp (AudioEngine::instance()->sample_time() + timestamp);
184                 for (size_t n = 0; n < msglen; ++n) {
185                         _parser->scanner (msg[n]);
186                 }
187
188                 Glib::Threads::Mutex::Lock lm (output_fifo_lock);
189                 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
190                 
191                 output_fifo.get_write_vector (&vec);
192
193                 if (vec.len[0] + vec.len[1] < 1) {
194                         error << "no space in FIFO for non-process thread MIDI write" << endmsg;
195                         return 0;
196                 }
197
198                 if (vec.len[0]) {
199                         if (!vec.buf[0]->owns_buffer()) {
200                                 vec.buf[0]->set_buffer (0, 0, true);
201                         }
202                         vec.buf[0]->set (msg, msglen, timestamp);
203                 } else {
204                         if (!vec.buf[1]->owns_buffer()) {
205                                 vec.buf[1]->set_buffer (0, 0, true);
206                         }
207                         vec.buf[1]->set (msg, msglen, timestamp);
208                 }
209
210                 output_fifo.increment_write_idx (1);
211                 
212                 ret = msglen;
213
214         } else {
215
216                 _parser->set_timestamp (AudioEngine::instance()->sample_time_at_cycle_start() + timestamp);
217                 for (size_t n = 0; n < msglen; ++n) {
218                         _parser->scanner (msg[n]);
219                 }
220
221                 if (timestamp >= _cycle_nframes) {
222                         std::cerr << "attempting to write MIDI event of " << msglen << " MIDI::bytes at time "
223                                   << timestamp << " of " << _cycle_nframes
224                                   << " (this will not work - needs a code fix)"
225                                   << std::endl;
226                 }
227
228                 /* This is the process thread, which makes checking
229                  * _currently_in_cycle atomic and safe, since it is only
230                  * set from cycle_start() and cycle_end(), also called
231                  * only from the process thread.
232                  */
233
234                 if (_currently_in_cycle) {
235
236                         MidiBuffer& mb (get_midi_buffer (_cycle_nframes));
237                         
238                         if (timestamp == 0) {
239                                 timestamp = _last_write_timestamp;
240                         } 
241                         
242                         if (mb.push_back (timestamp, msglen, msg)) {
243                                 ret = msglen;
244                                 _last_write_timestamp = timestamp;
245
246                         } else {
247                                 cerr << "AsyncMIDIPort (" << ARDOUR::Port::name() << "): write of " << msglen << " @ " << timestamp << " failed\n" << endl;
248                                 PBD::stacktrace (cerr, 20);
249                                 ret = 0;
250                         }
251                 } else {
252                         cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
253                         PBD::stacktrace (cerr, 20);
254                 }
255         }
256
257         return ret;
258 }
259
260
261 int
262 AsyncMIDIPort::read (MIDI::byte *, size_t)
263 {
264         if (!ARDOUR::Port::receives_input()) {
265                 return 0;
266         }
267         
268         timestamp_t time;
269         Evoral::EventType type;
270         uint32_t size;
271         MIDI::byte buffer[input_fifo.capacity()];
272
273         while (input_fifo.read (&time, &type, &size, buffer)) {
274                 _parser->set_timestamp (time);
275                 for (uint32_t i = 0; i < size; ++i) {
276                         _parser->scanner (buffer[i]);
277                 }
278         }
279
280         return 0;
281 }
282
283 void
284 AsyncMIDIPort::parse (framecnt_t)
285 {
286         MIDI::byte buf[1];
287
288         /* see ::read() to realize why buf is not used */
289         read (buf, sizeof (buf));
290 }
291
292 void
293 AsyncMIDIPort::set_process_thread (pthread_t thr)
294 {
295         _process_thread = thr;
296 }
297
298 bool
299 AsyncMIDIPort::is_process_thread()
300 {
301         return pthread_equal (pthread_self(), _process_thread);
302 }
303