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