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