1 /*-
2  * Copyright (c) 2006-2019 Hans Petter Selasky. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/uio.h>
27 #include <sys/file.h>
28 #include <sys/time.h>
29 
30 #include <stdio.h>
31 #include <time.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 
39 #ifdef __APPLE__
40 #include <mach/mach_time.h>
41 #include <sched.h>
42 static mach_timebase_info_data_t umidi20_timebase_info;
43 #endif
44 
45 #include "umidi20.h"
46 
47 #ifdef HAVE_DEBUG
48 #define	DPRINTF(fmt, ...) \
49     printf("%s:%d: " fmt, __FUNCTION__, __LINE__,## __VA_ARGS__)
50 #else
51 #define	DPRINTF(fmt, ...) do { } while (0)
52 #endif
53 
54 #define	PTHREAD_NULL ((pthread_t)-1L)
55 
56 #define	STRLCPY(a,b,c) do { \
57     strncpy(a,b,c); ((char *)(a))[(c)-1] = 0; \
58 } while (0)
59 
60 /* prototypes */
61 
62 static void *umidi20_watchdog_alloc(void *arg);
63 static void *umidi20_watchdog_play_rec(void *arg);
64 static void umidi20_watchdog_record_sub(struct umidi20_device *dev, struct umidi20_device *play_dev, uint32_t position);
65 static void umidi20_watchdog_play_sub(struct umidi20_device *dev, uint32_t position);
66 static void *umidi20_watchdog_files(void *arg);
67 static void umidi20_stop_thread(pthread_t *p_td, pthread_mutex_t *mtx);
68 static void *umidi20_watchdog_song(void *arg);
69 static void umidi20_exec_timer(uint32_t pos);
70 
71 /* structures */
72 
73 struct umidi20_root_device root_dev;
74 
75 struct umidi20_timer_entry {
76 	TAILQ_ENTRY(umidi20_timer_entry) entry;
77 	umidi20_timer_callback_t *fn;
78 	void   *arg;
79 	uint32_t ms_interval;
80 	uint32_t timeout_pos;
81 	uint8_t	pending;
82 };
83 
84 /* functions */
85 
86 uint32_t
umidi20_get_curr_position(void)87 umidi20_get_curr_position(void)
88 {
89 	uint32_t position;
90 
91 	pthread_mutex_lock(&root_dev.mutex);
92 	position = root_dev.curr_position;
93 	pthread_mutex_unlock(&root_dev.mutex);
94 
95 	return (position);
96 }
97 
98 void
umidi20_set_record_event_callback(uint8_t device_no,umidi20_event_callback_t * func,void * arg)99 umidi20_set_record_event_callback(uint8_t device_no, umidi20_event_callback_t *func, void *arg)
100 {
101 	if (device_no >= UMIDI20_N_DEVICES)
102 		return;
103 
104 	root_dev.rec[device_no].event_callback_func = func;
105 	root_dev.rec[device_no].event_callback_arg = arg;
106 }
107 
108 void
umidi20_set_play_event_callback(uint8_t device_no,umidi20_event_callback_t * func,void * arg)109 umidi20_set_play_event_callback(uint8_t device_no, umidi20_event_callback_t *func, void *arg)
110 {
111 	if (device_no >= UMIDI20_N_DEVICES)
112 		return;
113 
114 	root_dev.play[device_no].event_callback_func = func;
115 	root_dev.play[device_no].event_callback_arg = arg;
116 }
117 
118 void
umidi20_init(void)119 umidi20_init(void)
120 {
121 	uint32_t x;
122 
123 	umidi20_mutex_init(&root_dev.mutex);
124 
125 	pthread_cond_init(&root_dev.cond, NULL);
126 
127 #ifdef __APPLE__
128 	mach_timebase_info(&umidi20_timebase_info);
129 #endif
130 	umidi20_gettime(&(root_dev.curr_time));
131 
132 	root_dev.start_time = root_dev.curr_time;
133 	root_dev.curr_position = 0;
134 
135 	TAILQ_INIT(&root_dev.timers);
136 
137 	for (x = 0; x < UMIDI20_N_DEVICES; x++) {
138 		root_dev.rec[x].file_no = -1;
139 		root_dev.rec[x].device_no = x;
140 		root_dev.rec[x].update = 1;
141 		snprintf(root_dev.rec[x].fname,
142 		    sizeof(root_dev.rec[x].fname),
143 		    "/dev/umidi0.%x", x);
144 
145 		root_dev.play[x].file_no = -1;
146 		root_dev.play[x].device_no = x;
147 		root_dev.play[x].update = 1;
148 		snprintf(root_dev.play[x].fname,
149 		    sizeof(root_dev.play[x].fname),
150 		    "/dev/umidi0.%x", x);
151 	}
152 
153 	if (pthread_create(&(root_dev.thread_alloc), NULL,
154 	    &umidi20_watchdog_alloc, NULL)) {
155 		root_dev.thread_alloc = PTHREAD_NULL;
156 	}
157 	if (pthread_create(&(root_dev.thread_play_rec), NULL,
158 	    &umidi20_watchdog_play_rec, NULL)) {
159 		root_dev.thread_play_rec = PTHREAD_NULL;
160 	}
161 	if (pthread_create(&(root_dev.thread_files), NULL,
162 	    &umidi20_watchdog_files, NULL)) {
163 		root_dev.thread_files = PTHREAD_NULL;
164 	}
165 }
166 
167 void
umidi20_uninit(void)168 umidi20_uninit(void)
169 {
170 	pthread_mutex_lock(&root_dev.mutex);
171 
172 	umidi20_stop_thread(&(root_dev.thread_alloc),
173 	    &root_dev.mutex);
174 
175 	umidi20_stop_thread(&(root_dev.thread_play_rec),
176 	    &root_dev.mutex);
177 
178 	pthread_mutex_unlock(&root_dev.mutex);
179 }
180 
181 static void
umidi20_stop_thread(pthread_t * p_td,pthread_mutex_t * p_mtx)182 umidi20_stop_thread(pthread_t *p_td, pthread_mutex_t *p_mtx)
183 {
184 	pthread_t td;
185 	uint8_t recurse = 0;
186 
187 	pthread_mutex_assert(p_mtx, MA_OWNED);
188 
189 	td = *p_td;
190 	*p_td = PTHREAD_NULL;
191 
192 	if (td != PTHREAD_NULL) {
193 		while (pthread_mutex_unlock(p_mtx) == 0)
194 			recurse++;
195 
196 		pthread_kill(td, SIGURG);
197 		pthread_join(td, NULL);
198 
199 		while (recurse--)
200 			pthread_mutex_lock(p_mtx);
201 	}
202 }
203 
204 static void *
umidi20_watchdog_alloc(void * arg)205 umidi20_watchdog_alloc(void *arg)
206 {
207 	struct umidi20_event *event;
208 
209 	pthread_mutex_lock(&root_dev.mutex);
210 
211 	while (root_dev.thread_alloc != PTHREAD_NULL) {
212 
213 		while (UMIDI20_IF_QLEN(&(root_dev.free_queue)) < UMIDI20_BUF_EVENTS) {
214 			pthread_mutex_unlock(&root_dev.mutex);
215 			event = umidi20_event_alloc(NULL, 0);
216 			pthread_mutex_lock(&root_dev.mutex);
217 			if (event) {
218 				UMIDI20_IF_ENQUEUE_LAST(&(root_dev.free_queue), event);
219 			} else {
220 				break;
221 			}
222 		}
223 		pthread_mutex_unlock(&root_dev.mutex);
224 
225 		usleep(100000);
226 
227 		pthread_mutex_lock(&root_dev.mutex);
228 	}
229 
230 	pthread_mutex_unlock(&root_dev.mutex);
231 
232 	return NULL;
233 }
234 
235 static void *
umidi20_watchdog_play_rec(void * arg)236 umidi20_watchdog_play_rec(void *arg)
237 {
238 	struct timespec ts = {0, 0};
239 	uint32_t position;
240 	uint32_t x;
241 
242 	pthread_mutex_lock(&root_dev.mutex);
243 
244 	while (root_dev.thread_play_rec != PTHREAD_NULL) {
245 
246 		umidi20_gettime(&ts);
247 
248 		root_dev.curr_time = ts;
249 
250 		position = umidi20_difftime
251 		    (&(root_dev.curr_time), &(root_dev.start_time));
252 
253 		root_dev.curr_position = position;
254 
255 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
256 			umidi20_watchdog_record_sub(&(root_dev.rec[x]), &(root_dev.play[x]),
257 			    position);
258 		}
259 
260 		umidi20_exec_timer(position);
261 
262 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
263 			umidi20_watchdog_play_sub(&(root_dev.play[x]), position);
264 		}
265 
266 		pthread_mutex_unlock(&root_dev.mutex);
267 
268 		usleep(1000);
269 
270 		pthread_mutex_lock(&root_dev.mutex);
271 	}
272 
273 	pthread_mutex_unlock(&root_dev.mutex);
274 
275 	return NULL;
276 }
277 
278 static void
umidi20_exec_timer(uint32_t pos)279 umidi20_exec_timer(uint32_t pos)
280 {
281 	struct umidi20_timer_entry *entry;
282 	int32_t delta;
283 
284 restart:
285 
286 	TAILQ_FOREACH(entry, &root_dev.timers, entry) {
287 		delta = entry->timeout_pos - pos;
288 		if ((delta < 0) || ((uint32_t)delta > entry->ms_interval)) {
289 
290 			/* check if next timeout is valid, else reset */
291 
292 			if (delta < -1000 || (uint32_t)delta > entry->ms_interval) {
293 				/* reset */
294 				entry->timeout_pos = pos;
295 			} else if (delta < 0) {
296 				/* try to stay sync */
297 				while (delta < 0) {
298 					/* try to stay sync */
299 					entry->timeout_pos += entry->ms_interval;
300 					delta += entry->ms_interval;
301 				}
302 				entry->timeout_pos -= entry->ms_interval;
303 			}
304 			entry->pending = 1;
305 			pthread_mutex_unlock(&root_dev.mutex);
306 			(entry->fn) (entry->arg);
307 			pthread_mutex_lock(&root_dev.mutex);
308 			entry->pending = 0;
309 			pthread_cond_broadcast(&root_dev.cond);
310 			/* allow callback to update the interval */
311 			entry->timeout_pos += entry->ms_interval;
312 			goto restart;
313 		}
314 	}
315 }
316 
317 void
umidi20_update_timer(umidi20_timer_callback_t * fn,void * arg,uint32_t ms_interval,uint8_t do_sync)318 umidi20_update_timer(umidi20_timer_callback_t *fn, void *arg, uint32_t ms_interval, uint8_t do_sync)
319 {
320 	struct umidi20_timer_entry *entry;
321 
322 	/* check for invalid interval */
323 	if (ms_interval == 0)
324 		return;
325 	/* check for too big interval */
326 	if (ms_interval > 65535)
327 		ms_interval = 65535;
328 
329 	pthread_mutex_lock(&root_dev.mutex);
330 
331 	TAILQ_FOREACH(entry, &root_dev.timers, entry) {
332 		if ((entry->fn == fn) && (entry->arg == arg)) {
333 			break;
334 		}
335 	}
336 	if (entry != NULL) {
337 		entry->ms_interval = ms_interval;
338 		if (do_sync)
339 			entry->timeout_pos = root_dev.curr_position;
340 	}
341 	pthread_mutex_unlock(&root_dev.mutex);
342 }
343 
344 void
umidi20_set_timer(umidi20_timer_callback_t * fn,void * arg,uint32_t ms_interval)345 umidi20_set_timer(umidi20_timer_callback_t *fn, void *arg, uint32_t ms_interval)
346 {
347 	struct umidi20_timer_entry *entry;
348 	struct umidi20_timer_entry *new_entry;
349 
350 	if (ms_interval == 0) {
351 		umidi20_unset_timer(fn, arg);
352 		return;
353 	}
354 	if (ms_interval > 65535)
355 		ms_interval = 65535;
356 
357 	new_entry = malloc(sizeof(*new_entry));
358 	if (new_entry == NULL)
359 		return;
360 
361 	pthread_mutex_lock(&root_dev.mutex);
362 
363 	TAILQ_FOREACH(entry, &root_dev.timers, entry) {
364 		if ((entry->fn == fn) && (entry->arg == arg)) {
365 			break;
366 		}
367 	}
368 
369 	if (entry != NULL) {
370 		/* first timeout ASAP */
371 		entry->ms_interval = ms_interval;
372 		entry->timeout_pos = root_dev.curr_position;
373 
374 		pthread_mutex_unlock(&root_dev.mutex);
375 		free(new_entry);
376 		return;
377 	}
378 	new_entry->fn = fn;
379 	new_entry->arg = arg;
380 	new_entry->ms_interval = ms_interval;
381 	new_entry->timeout_pos = root_dev.curr_position + ms_interval;
382 	new_entry->pending = 0;
383 
384 	TAILQ_INSERT_TAIL(&root_dev.timers, new_entry, entry);
385 
386 	pthread_mutex_unlock(&root_dev.mutex);
387 }
388 
389 void
umidi20_unset_timer(umidi20_timer_callback_t * fn,void * arg)390 umidi20_unset_timer(umidi20_timer_callback_t *fn, void *arg)
391 {
392 	struct umidi20_timer_entry *entry;
393 
394 	pthread_mutex_lock(&root_dev.mutex);
395 	TAILQ_FOREACH(entry, &root_dev.timers, entry) {
396 		if ((entry->fn == fn) && (entry->arg == arg)) {
397 			TAILQ_REMOVE(&root_dev.timers, entry, entry);
398 			while (entry->pending != 0)
399 				pthread_cond_wait(&root_dev.cond, &root_dev.mutex);
400 			pthread_mutex_unlock(&root_dev.mutex);
401 			free(entry);
402 			return;
403 		}
404 	}
405 	pthread_mutex_unlock(&root_dev.mutex);
406 }
407 
408 static void
umidi20_watchdog_record_sub(struct umidi20_device * dev,struct umidi20_device * play_dev,uint32_t curr_position)409 umidi20_watchdog_record_sub(struct umidi20_device *dev,
410     struct umidi20_device *play_dev,
411     uint32_t curr_position)
412 {
413 	struct umidi20_event *event;
414 	int len;
415 	uint8_t cmd[16];
416 	uint8_t drop;
417 	uint8_t x;
418 
419 	curr_position -= dev->start_position;
420 
421 	if (curr_position >= dev->end_offset) {
422 		/* time overflow */
423 		if (dev->enabled_usr) {
424 			DPRINTF("time overflow\n");
425 			dev->enabled_usr = 0;
426 		}
427 	}
428 	/* record */
429 
430 	if (dev->file_no < 0)
431 		return;
432 
433 	/*
434 	 * Read data regularly so that the buffer-size is kept
435 	 * low, even if not recording. A length of zero
436 	 * usually means end of file.
437 	 */
438 	if ((len = read(dev->file_no, cmd, sizeof(cmd))) <= 0) {
439 		if (len == 0)
440 			dev->update = 1;
441 		else if (errno != EWOULDBLOCK)
442 			dev->update = 1;
443 		return;
444 	}
445 	if (dev->enabled_usr == 0)
446 		return;
447 
448 	for (x = 0; x != (uint8_t)len; x++) {
449 
450 		event = umidi20_convert_to_event(&(dev->conv), cmd[x], 1);
451 
452 		if (event == NULL)
453 			continue;
454 
455 		DPRINTF("pos = %d\n", curr_position);
456 
457 		event->device_no = dev->device_no;
458 		event->position = curr_position;
459 
460 		drop = 0;
461 
462 		if (dev->event_callback_func != NULL) {
463 
464 			pthread_mutex_unlock(&root_dev.mutex);
465 
466 			(dev->event_callback_func) (dev->device_no,
467 			    dev->event_callback_arg, event, &drop);
468 
469 			pthread_mutex_lock(&root_dev.mutex);
470 		}
471 		if (drop) {
472 			umidi20_event_free(event);
473 		} else {
474 			umidi20_event_queue_insert
475 			    (&(dev->queue), event, UMIDI20_CACHE_INPUT);
476 		}
477 	}
478 }
479 
480 static void
umidi20_watchdog_play_sub(struct umidi20_device * dev,uint32_t curr_position)481 umidi20_watchdog_play_sub(struct umidi20_device *dev,
482     uint32_t curr_position)
483 {
484 	struct umidi20_event *event;
485 	struct umidi20_event *event_root;
486 	uint32_t delta_position;
487 	int err;
488 	uint8_t len;
489 	uint8_t drop;
490 
491 	/* playback */
492 
493 	curr_position -= dev->start_position;
494 
495 	if (curr_position >= dev->end_offset) {
496 		/* time overflow */
497 		if (dev->enabled_usr) {
498 			DPRINTF("time overflow\n");
499 			dev->enabled_usr = 0;
500 		}
501 		return;
502 	}
503 	while (1) {
504 
505 		UMIDI20_IF_POLL_HEAD(&(dev->queue), event_root);
506 		event = event_root;
507 
508 		if (event == NULL) {
509 			break;
510 		}
511 		delta_position = (event->position - curr_position);
512 
513 		if (delta_position >= 0x80000000) {
514 
515 			drop = 0;
516 
517 			if (dev->event_callback_func != NULL) {
518 
519 				pthread_mutex_unlock(&root_dev.mutex);
520 
521 				(dev->event_callback_func) (dev->device_no,
522 				    dev->event_callback_arg, event, &drop);
523 
524 				pthread_mutex_lock(&root_dev.mutex);
525 			}
526 			if ((dev->file_no >= 0) &&
527 			    (dev->enabled_usr) &&
528 			    (event->cmd[1] != 0xFF) &&
529 			    (!drop)) {
530 
531 				/* only write non-meta/reset commands */
532 
533 				do {
534 					len = umidi20_command_to_len[event->cmd[0] & 0xF];
535 
536 					if (umidi20_event_is_key_start(event))
537 						dev->any_key_start = 1;
538 
539 					/* try to write data */
540 
541 					err = write(dev->file_no, event->cmd + 1, len);
542 					if ((err <= 0) && (errno != EWOULDBLOCK)) {
543 						/* try to re-open the device */
544 						dev->update = 1;
545 						break;
546 					} else if (err != len) {
547 						/*
548 						 * we are done - the queue
549 						 * is full
550 						 */
551 						break;
552 					}
553 				} while ((event = event->p_next));
554 			}
555 			UMIDI20_IF_REMOVE(&(dev->queue), event_root);
556 
557 			umidi20_event_free(event_root);
558 		} else {
559 			break;
560 		}
561 	}
562 }
563 
564 static void *
umidi20_watchdog_files(void * arg)565 umidi20_watchdog_files(void *arg)
566 {
567 	struct umidi20_device *dev;
568 	uint32_t x;
569 	int file_no;
570 
571 	pthread_mutex_lock(&root_dev.mutex);
572 
573 	while (root_dev.thread_files != PTHREAD_NULL) {
574 
575 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
576 
577 			dev = &(root_dev.play[x]);
578 
579 			if (dev->update) {
580 
581 				file_no = dev->file_no;
582 				dev->file_no = -1;
583 
584 				if (file_no > 2) {
585 					switch (dev->enabled_cfg_last) {
586 					case UMIDI20_ENABLED_CFG_DEV:
587 						close(file_no);
588 						break;
589 					case UMIDI20_ENABLED_CFG_JACK:
590 						umidi20_jack_tx_close(x);
591 						break;
592 					case UMIDI20_ENABLED_CFG_COREMIDI:
593 						umidi20_coremidi_tx_close(x);
594 						break;
595 					case UMIDI20_ENABLED_CFG_ANDROID:
596 						umidi20_android_tx_close(x);
597 						break;
598 					default:
599 						break;
600 					}
601 				}
602 				switch (dev->enabled_cfg) {
603 				case UMIDI20_ENABLED_CFG_DEV:
604 					file_no = open(dev->fname, O_WRONLY | O_NONBLOCK);
605 					break;
606 				case UMIDI20_ENABLED_CFG_JACK:
607 					file_no = umidi20_jack_tx_open(x, dev->fname);
608 					break;
609 				case UMIDI20_ENABLED_CFG_COREMIDI:
610 					file_no = umidi20_coremidi_tx_open(x, dev->fname);
611 					break;
612 				case UMIDI20_ENABLED_CFG_ANDROID:
613 					file_no = umidi20_android_tx_open(x, dev->fname);
614 					break;
615 				default:
616 					file_no = -1;
617 					break;
618 				}
619 				if (file_no >= 0) {
620 					dev->enabled_cfg_last = dev->enabled_cfg;
621 					dev->update = 0;
622 					dev->file_no = file_no;
623 				} else {
624 					dev->enabled_cfg_last = UMIDI20_DISABLE_CFG;
625 				}
626 			}
627 			dev = &(root_dev.rec[x]);
628 
629 			if (dev->update) {
630 
631 				file_no = dev->file_no;
632 				dev->file_no = -1;
633 
634 				if (file_no > 2) {
635 					switch (dev->enabled_cfg_last) {
636 					case UMIDI20_ENABLED_CFG_DEV:
637 						close(file_no);
638 						break;
639 					case UMIDI20_ENABLED_CFG_JACK:
640 						umidi20_jack_rx_close(x);
641 						break;
642 					case UMIDI20_ENABLED_CFG_COREMIDI:
643 						umidi20_coremidi_rx_close(x);
644 						break;
645 					case UMIDI20_ENABLED_CFG_ANDROID:
646 						umidi20_android_rx_close(x);
647 						break;
648 					default:
649 						break;
650 					}
651 				}
652 				switch (dev->enabled_cfg) {
653 				case UMIDI20_ENABLED_CFG_DEV:
654 					file_no = open(dev->fname, O_RDONLY | O_NONBLOCK);
655 					break;
656 				case UMIDI20_ENABLED_CFG_JACK:
657 					file_no = umidi20_jack_rx_open(x, dev->fname);
658 					break;
659 				case UMIDI20_ENABLED_CFG_COREMIDI:
660 					file_no = umidi20_coremidi_rx_open(x, dev->fname);
661 					break;
662 				case UMIDI20_ENABLED_CFG_ANDROID:
663 					file_no = umidi20_android_rx_open(x, dev->fname);
664 					break;
665 				default:
666 					file_no = -1;
667 					break;
668 				}
669 				if (file_no >= 0) {
670 
671 					/* set non-blocking I/O */
672 					fcntl(file_no, F_SETFL, (int)O_NONBLOCK);
673 
674 					dev->enabled_cfg_last = dev->enabled_cfg;
675 					dev->update = 0;
676 					dev->file_no = file_no;
677 				} else {
678 					dev->enabled_cfg_last = UMIDI20_DISABLE_CFG;
679 				}
680 			}
681 		}
682 
683 		pthread_mutex_unlock(&root_dev.mutex);
684 		usleep(100000);
685 		pthread_mutex_lock(&root_dev.mutex);
686 	}
687 	pthread_mutex_unlock(&root_dev.mutex);
688 	return NULL;
689 }
690 
691 /*
692  * flag: 0 - default
693  *       1 - use cache
694  */
695 struct umidi20_event *
umidi20_event_alloc(struct umidi20_event *** ppp_next,uint8_t flag)696 umidi20_event_alloc(struct umidi20_event ***ppp_next, uint8_t flag)
697 {
698 	struct umidi20_event *event = NULL;
699 
700 	if (flag == 1) {
701 		pthread_mutex_lock(&root_dev.mutex);
702 		UMIDI20_IF_DEQUEUE(&(root_dev.free_queue), event);
703 		pthread_mutex_unlock(&root_dev.mutex);
704 	}
705 	if (event == NULL) {
706 		event = malloc(sizeof(*event));
707 	}
708 	if (event) {
709 		memset(event, 0, sizeof(*event));
710 		if (ppp_next) {
711 			**ppp_next = event;
712 			*ppp_next = &(event->p_next);
713 		}
714 	}
715 	return event;
716 }
717 
718 void
umidi20_event_free(struct umidi20_event * event)719 umidi20_event_free(struct umidi20_event *event)
720 {
721 	struct umidi20_event *p_next;
722 
723 	while (event) {
724 		p_next = event->p_next;
725 		free(event);
726 		event = p_next;
727 	}
728 }
729 
730 struct umidi20_event *
umidi20_event_copy(struct umidi20_event * event,uint8_t flag)731 umidi20_event_copy(struct umidi20_event *event, uint8_t flag)
732 {
733 	struct umidi20_event *p_curr;
734 	struct umidi20_event *p_next = NULL;
735 	struct umidi20_event **pp_next = &p_next;
736 
737 	while (event) {
738 
739 		p_curr = umidi20_event_alloc(&pp_next, flag);
740 
741 		if (p_curr == NULL) {
742 			goto fail;
743 		}
744 		/* copy data */
745 
746 		p_curr->position = event->position;
747 		p_curr->revision = event->revision;
748 		p_curr->tick = event->tick;
749 		p_curr->device_no = event->device_no;
750 		memcpy(p_curr->cmd, event->cmd, UMIDI20_COMMAND_LEN);
751 
752 		/* get next event */
753 		event = event->p_next;
754 	}
755 	return p_next;
756 
757 fail:
758 	umidi20_event_free(p_next);
759 	return NULL;
760 }
761 
762 struct umidi20_event *
umidi20_event_from_data(const uint8_t * data_ptr,uint32_t data_len,uint8_t flag)763 umidi20_event_from_data(const uint8_t *data_ptr,
764     uint32_t data_len, uint8_t flag)
765 {
766 	struct umidi20_event *p_curr = NULL;
767 	struct umidi20_event *p_next = NULL;
768 	struct umidi20_event **pp_next = &p_next;
769 	uint8_t i;
770 	uint8_t cont = 0;
771 	static const uint8_t p0 = 0;
772 	static const uint8_t s0 = 0;
773 
774 	if (data_len == 0) {
775 		goto fail;
776 	}
777 	p_curr = umidi20_event_alloc(&pp_next, flag);
778 	if (p_curr == NULL) {
779 		goto fail;
780 	}
781 	i = 1;
782 	while (1) {
783 
784 		if (data_len == 0) {
785 			p_curr->cmd[0] = (p0 | s0 | (i - 1));
786 			break;
787 		}
788 		if (i == 8) {
789 			p_curr->cmd[0] = (cont ?
790 			    (p0 | s0 | 0x8) :
791 			    (p0 | s0 | 0x0));
792 			i = 1;
793 			cont = 1;
794 
795 			p_curr = umidi20_event_alloc(&pp_next, flag);
796 			if (p_curr == NULL) {
797 				goto fail;
798 			}
799 		}
800 		p_curr->cmd[i] = *data_ptr;
801 		i++;
802 		data_ptr++;
803 		data_len--;
804 	}
805 	return p_next;
806 
807 fail:
808 	umidi20_event_free(p_next);
809 	return NULL;
810 }
811 
812 uint8_t *
umidi20_event_pointer(struct umidi20_event * event,uint32_t offset)813 umidi20_event_pointer(struct umidi20_event *event, uint32_t offset)
814 {
815 	while (1) {
816 		uint32_t len = umidi20_event_get_length_first(event);
817 		if (offset >= len) {
818 			offset -= len;
819 			event = event->p_next;
820 		} else {
821 			return (&event->cmd[1 + offset]);
822 		}
823 	}
824 }
825 
826 uint32_t
umidi20_event_get_what(struct umidi20_event * event)827 umidi20_event_get_what(struct umidi20_event *event)
828 {
829 	if (event == NULL)
830 		return 0;
831 
832 	switch (event->cmd[1] >> 4) {
833 	case 0x8:
834 	case 0x9:
835 		return (UMIDI20_WHAT_CHANNEL |
836 		    UMIDI20_WHAT_KEY |
837 		    UMIDI20_WHAT_VELOCITY);
838 	case 0xA:
839 		return (UMIDI20_WHAT_CHANNEL |
840 		    UMIDI20_WHAT_KEY |
841 		    UMIDI20_WHAT_KEY_PRESSURE);
842 	case 0xB:
843 		return (UMIDI20_WHAT_CHANNEL |
844 		    UMIDI20_WHAT_CONTROL_VALUE |
845 		    UMIDI20_WHAT_CONTROL_ADDRESS);
846 	case 0xC:
847 		return (UMIDI20_WHAT_CHANNEL |
848 		    UMIDI20_WHAT_PROGRAM_VALUE);
849 	case 0xD:
850 		return (UMIDI20_WHAT_CHANNEL |
851 		    UMIDI20_WHAT_CHANNEL_PRESSURE);
852 	case 0xE:
853 		return (UMIDI20_WHAT_CHANNEL |
854 		    UMIDI20_WHAT_PITCH_BEND);
855 	case 0xF:
856 		switch (event->cmd[1]) {
857 		case 0xF8:
858 			return (UMIDI20_WHAT_BEAT_EVENT);
859 		case 0xF1:
860 		case 0xF2:
861 		case 0xF3:
862 		case 0xFA:
863 		case 0xFB:
864 		case 0xFC:
865 			return (UMIDI20_WHAT_SONG_EVENT);
866 		case 0xF0:	/* SYSEX */
867 			if (umidi20_event_get_length(event) >= 11 &&
868 			    umidi20_event_pointer(event, 1)[0] == 0x0A &&
869 			    umidi20_event_pointer(event, 2)[0] == 0x55 &&
870 			    (umidi20_event_pointer(event, 3)[0] & 0xF0) == 0x00) {
871 				return (UMIDI20_WHAT_CHANNEL |
872 					UMIDI20_WHAT_KEY |
873 					UMIDI20_WHAT_VELOCITY |
874 					UMIDI20_WHAT_EXTENDED_KEY);
875 			}
876 			break;
877 		default:
878 			break;
879 		}
880 		break;
881 	default:
882 		break;
883 	}
884 	return 0;
885 }
886 
887 uint8_t
umidi20_event_is_meta(struct umidi20_event * event)888 umidi20_event_is_meta(struct umidi20_event *event)
889 {
890 	return ((umidi20_event_get_length_first(event) > 1) &&
891 	    (event->cmd[1] == 0xFF));
892 }
893 
894 uint8_t
umidi20_event_is_pitch_bend(struct umidi20_event * event)895 umidi20_event_is_pitch_bend(struct umidi20_event *event)
896 {
897 	if (event == NULL)
898 		return 0;
899 	return ((event->cmd[1] & 0xF0) == 0xE0);
900 }
901 
902 uint8_t
umidi20_event_is_key_start(struct umidi20_event * event)903 umidi20_event_is_key_start(struct umidi20_event *event)
904 {
905 	uint32_t what = umidi20_event_get_what(event);
906 
907 	if (what & UMIDI20_WHAT_KEY) {
908 		if ((event->cmd[1] & 0xF0) == 0x80)
909 			return (0);
910 		if (what & UMIDI20_WHAT_VELOCITY) {
911 			if (umidi20_event_get_velocity(event) != 0)
912 				return (1);
913 		}
914 	}
915 	return (0);
916 }
917 
918 uint8_t
umidi20_event_is_key_end(struct umidi20_event * event)919 umidi20_event_is_key_end(struct umidi20_event *event)
920 {
921   	uint32_t what = umidi20_event_get_what(event);
922 
923 	if (what & UMIDI20_WHAT_KEY) {
924 		if ((event->cmd[1] & 0xF0) == 0x80)
925 			return (1);
926 		if (what & UMIDI20_WHAT_VELOCITY) {
927 			if (umidi20_event_get_velocity(event) == 0)
928 				return (1);
929 		}
930 	}
931 	return (0);
932 }
933 
934 uint8_t
umidi20_event_is_tempo(struct umidi20_event * event)935 umidi20_event_is_tempo(struct umidi20_event *event)
936 {
937 	if (event == NULL)
938 		return 0;
939 	return ((event->cmd[1] == 0xFF) &&
940 	    (event->cmd[2] == 0x51));
941 }
942 
943 uint8_t
umidi20_event_is_voice(struct umidi20_event * event)944 umidi20_event_is_voice(struct umidi20_event *event)
945 {
946 	if (event == NULL)
947 		return 0;
948 	return ((event->cmd[1] >= 0x80) &&
949 	    (event->cmd[1] <= 0xEF));
950 }
951 
952 uint8_t
umidi20_event_is_sysex(struct umidi20_event * event)953 umidi20_event_is_sysex(struct umidi20_event *event)
954 {
955 	if (event == NULL)
956 		return 0;
957 	return (event->cmd[1] == 0xF0);
958 }
959 
960 uint8_t
umidi20_event_get_channel(struct umidi20_event * event)961 umidi20_event_get_channel(struct umidi20_event *event)
962 {
963 	uint32_t what = umidi20_event_get_what(event);
964 
965 	if (what & UMIDI20_WHAT_EXTENDED_KEY)
966 		return (umidi20_event_pointer(event, 3)[0] & 0x0F);
967 	else if (what & UMIDI20_WHAT_CHANNEL)
968 		return (event->cmd[1] & 0x0F);
969 	else
970 		return (0);
971 }
972 
973 void
umidi20_event_set_channel(struct umidi20_event * event,uint8_t c)974 umidi20_event_set_channel(struct umidi20_event *event, uint8_t c)
975 {
976 	uint32_t what = umidi20_event_get_what(event);
977 
978 	if (what & UMIDI20_WHAT_EXTENDED_KEY) {
979 		umidi20_event_pointer(event, 3)[0] &= 0xF0;
980 		umidi20_event_pointer(event, 3)[0] |= (c & 0x0F);
981 	} else if (what & UMIDI20_WHAT_CHANNEL) {
982 		event->cmd[1] &= 0xF0;
983 		event->cmd[1] |= (c & 0x0F);
984 	}
985 }
986 
987 uint8_t
umidi20_event_get_key(struct umidi20_event * event)988 umidi20_event_get_key(struct umidi20_event *event)
989 {
990 	uint32_t what = umidi20_event_get_what(event);
991 
992 	if (what & UMIDI20_WHAT_EXTENDED_KEY)
993 		return (umidi20_event_pointer(event, 4)[0]);
994 	else if (what & UMIDI20_WHAT_KEY)
995 		return (event->cmd[2]);
996 	else
997 		return (0);
998 }
999 
1000 void
umidi20_event_set_key(struct umidi20_event * event,uint8_t k)1001 umidi20_event_set_key(struct umidi20_event *event, uint8_t k)
1002 {
1003 	uint32_t what = umidi20_event_get_what(event);
1004 
1005 	if (what & UMIDI20_WHAT_EXTENDED_KEY)
1006 		umidi20_event_pointer(event, 4)[0] = k & 0x7F;
1007 	else if (what & UMIDI20_WHAT_KEY)
1008 		event->cmd[2] = k & 0x7F;
1009 }
1010 
1011 uint32_t
umidi20_event_get_extended_key(struct umidi20_event * event)1012 umidi20_event_get_extended_key(struct umidi20_event *event)
1013 {
1014 	uint32_t what = umidi20_event_get_what(event);
1015 
1016 	if (what & UMIDI20_WHAT_EXTENDED_KEY) {
1017 		uint32_t retval = 0;
1018 		retval |= umidi20_event_pointer(event, 6)[0] & 0x7F;
1019 		retval <<= 7;
1020 		retval |= umidi20_event_pointer(event, 7)[0] & 0x7F;
1021 		retval <<= 7;
1022 		retval |= umidi20_event_pointer(event, 8)[0] & 0x7F;
1023 		retval <<= 7;
1024 		retval |= umidi20_event_pointer(event, 9)[0] & 0x7F;
1025 
1026 		return (retval);
1027 	} else {
1028 		return (-1U);
1029 	}
1030 }
1031 
1032 void
umidi20_event_set_extended_key(struct umidi20_event * event,uint32_t freq)1033 umidi20_event_set_extended_key(struct umidi20_event *event, uint32_t freq)
1034 {
1035 	uint32_t what = umidi20_event_get_what(event);
1036 
1037 	if (what & UMIDI20_WHAT_EXTENDED_KEY) {
1038 		umidi20_event_pointer(event, 9)[0] = freq & 0x7F;
1039 		freq >>= 7;
1040 		umidi20_event_pointer(event, 8)[0] = freq & 0x7F;
1041 		freq >>= 7;
1042 		umidi20_event_pointer(event, 7)[0] = freq & 0x7F;
1043 		freq >>= 7;
1044 		umidi20_event_pointer(event, 6)[0] = freq & 0x7F;
1045 	}
1046 }
1047 
1048 uint8_t
umidi20_event_get_velocity(struct umidi20_event * event)1049 umidi20_event_get_velocity(struct umidi20_event *event)
1050 {
1051 	uint32_t what = umidi20_event_get_what(event);
1052 
1053 	if (what & UMIDI20_WHAT_EXTENDED_KEY)
1054 		return (umidi20_event_pointer(event, 5)[0]);
1055 	else if (what & UMIDI20_WHAT_VELOCITY)
1056 		return (event->cmd[3]);
1057 	else
1058 		return (0);
1059 }
1060 
1061 void
umidi20_event_set_velocity(struct umidi20_event * event,uint8_t k)1062 umidi20_event_set_velocity(struct umidi20_event *event, uint8_t k)
1063 {
1064 	uint32_t what = umidi20_event_get_what(event);
1065 
1066 	if (what & UMIDI20_WHAT_EXTENDED_KEY)
1067 		umidi20_event_pointer(event, 5)[0] = k & 0x7F;
1068 	else if (what & UMIDI20_WHAT_VELOCITY)
1069 		event->cmd[3] = k & 0x7F;
1070 }
1071 
1072 uint8_t
umidi20_event_get_pressure(struct umidi20_event * event)1073 umidi20_event_get_pressure(struct umidi20_event *event)
1074 {
1075 	uint32_t what = umidi20_event_get_what(event);
1076 
1077 	if (what & UMIDI20_WHAT_CHANNEL_PRESSURE) {
1078 		return event->cmd[2];
1079 	}
1080 	if (what & UMIDI20_WHAT_KEY_PRESSURE) {
1081 		return event->cmd[3];
1082 	}
1083 	return (0);
1084 }
1085 
1086 void
umidi20_event_set_pressure(struct umidi20_event * event,uint8_t p)1087 umidi20_event_set_pressure(struct umidi20_event *event, uint8_t p)
1088 {
1089 	uint32_t what = umidi20_event_get_what(event);
1090 
1091 	if (what & UMIDI20_WHAT_CHANNEL_PRESSURE) {
1092 		event->cmd[2] = p & 0x7F;
1093 	}
1094 	if (what & UMIDI20_WHAT_KEY_PRESSURE) {
1095 		event->cmd[3] = p & 0x7F;
1096 	}
1097 }
1098 
1099 uint8_t
umidi20_event_get_control_address(struct umidi20_event * event)1100 umidi20_event_get_control_address(struct umidi20_event *event)
1101 {
1102 	uint32_t what = umidi20_event_get_what(event);
1103 
1104 	return ((what & UMIDI20_WHAT_CONTROL_ADDRESS) ?
1105 	    event->cmd[2] : 0);
1106 }
1107 
1108 void
umidi20_event_set_control_address(struct umidi20_event * event,uint8_t a)1109 umidi20_event_set_control_address(struct umidi20_event *event, uint8_t a)
1110 {
1111 	uint32_t what = umidi20_event_get_what(event);
1112 
1113 	if (what & UMIDI20_WHAT_CONTROL_ADDRESS) {
1114 		event->cmd[2] = a & 0x7F;
1115 	}
1116 }
1117 
1118 uint8_t
umidi20_event_get_control_value(struct umidi20_event * event)1119 umidi20_event_get_control_value(struct umidi20_event *event)
1120 {
1121 	uint32_t what = umidi20_event_get_what(event);
1122 
1123 	return ((what & UMIDI20_WHAT_CONTROL_VALUE) ?
1124 	    event->cmd[3] : 0);
1125 }
1126 
1127 void
umidi20_event_set_control_value(struct umidi20_event * event,uint8_t a)1128 umidi20_event_set_control_value(struct umidi20_event *event, uint8_t a)
1129 {
1130 	uint32_t what = umidi20_event_get_what(event);
1131 
1132 	if (what & UMIDI20_WHAT_CONTROL_VALUE) {
1133 		event->cmd[3] = a & 0x7F;
1134 	}
1135 }
1136 
1137 uint8_t
umidi20_event_get_program_number(struct umidi20_event * event)1138 umidi20_event_get_program_number(struct umidi20_event *event)
1139 {
1140 	uint32_t what = umidi20_event_get_what(event);
1141 
1142 	return ((what & UMIDI20_WHAT_PROGRAM_VALUE) ?
1143 	    event->cmd[2] : 0);
1144 }
1145 
1146 void
umidi20_event_set_program_number(struct umidi20_event * event,uint8_t n)1147 umidi20_event_set_program_number(struct umidi20_event *event, uint8_t n)
1148 {
1149 	uint32_t what = umidi20_event_get_what(event);
1150 
1151 	if (what & UMIDI20_WHAT_PROGRAM_VALUE) {
1152 		event->cmd[2] = n & 0x7F;
1153 	}
1154 }
1155 
1156 uint16_t
umidi20_event_get_pitch_value(struct umidi20_event * event)1157 umidi20_event_get_pitch_value(struct umidi20_event *event)
1158 {
1159 	uint32_t what = umidi20_event_get_what(event);
1160 
1161 	return ((what & UMIDI20_WHAT_PITCH_BEND) ?
1162 	    (event->cmd[2] | (event->cmd[3] << 7)) : 0);
1163 }
1164 
1165 void
umidi20_event_set_pitch_value(struct umidi20_event * event,uint16_t n)1166 umidi20_event_set_pitch_value(struct umidi20_event *event, uint16_t n)
1167 {
1168 	uint32_t what = umidi20_event_get_what(event);
1169 
1170 	if (what & UMIDI20_WHAT_PITCH_BEND) {
1171 		event->cmd[2] = n & 0x7F;
1172 		event->cmd[3] = (n >> 7) & 0x7F;
1173 	}
1174 }
1175 
1176 uint32_t
umidi20_event_get_length_first(struct umidi20_event * event)1177 umidi20_event_get_length_first(struct umidi20_event *event)
1178 {
1179 	uint32_t len;
1180 
1181 	if (event) {
1182 		len = umidi20_command_to_len[event->cmd[0] & 0xF];
1183 	} else {
1184 		len = 0;
1185 	}
1186 	return len;
1187 }
1188 
1189 uint32_t
umidi20_event_get_length(struct umidi20_event * event)1190 umidi20_event_get_length(struct umidi20_event *event)
1191 {
1192 	uint32_t len = 0;
1193 
1194 	while (event) {
1195 		len += umidi20_command_to_len[event->cmd[0] & 0xF];
1196 		event = event->p_next;
1197 	}
1198 	return len;
1199 }
1200 
1201 void
umidi20_event_copy_out(struct umidi20_event * event,uint8_t * dst,uint32_t offset,uint32_t len)1202 umidi20_event_copy_out(struct umidi20_event *event, uint8_t *dst,
1203     uint32_t offset, uint32_t len)
1204 {
1205 	uint32_t part_len;
1206 
1207 	while (offset > 0) {
1208 		part_len = umidi20_command_to_len[event->cmd[0] & 0xF];
1209 
1210 		if (offset < part_len) {
1211 			break;
1212 		}
1213 		offset -= part_len;
1214 		event = event->p_next;
1215 	}
1216 
1217 	while (len > 0) {
1218 
1219 		part_len = umidi20_command_to_len[event->cmd[0] & 0xF];
1220 		part_len -= offset;
1221 
1222 		if (part_len > len) {
1223 			part_len = len;
1224 		}
1225 		memcpy(dst, event->cmd + 1 + offset, part_len);
1226 
1227 		dst += part_len;
1228 		len -= part_len;
1229 		offset = 0;
1230 		event = event->p_next;
1231 	}
1232 }
1233 
1234 uint8_t
umidi20_event_get_meta_number(struct umidi20_event * event)1235 umidi20_event_get_meta_number(struct umidi20_event *event)
1236 {
1237 	return (umidi20_event_is_meta(event) ?
1238 	    event->cmd[2] : 0);
1239 }
1240 
1241 void
umidi20_event_set_meta_number(struct umidi20_event * event,uint8_t n)1242 umidi20_event_set_meta_number(struct umidi20_event *event, uint8_t n)
1243 {
1244 	if (umidi20_event_is_meta(event)) {
1245 		event->cmd[2] = n & 0x7F;
1246 	}
1247 }
1248 
1249 uint32_t
umidi20_event_get_tempo(struct umidi20_event * event)1250 umidi20_event_get_tempo(struct umidi20_event *event)
1251 {
1252 	uint32_t tempo;
1253 
1254 	if (!umidi20_event_is_tempo(event)) {
1255 		tempo = 1;
1256 	} else {
1257 		tempo = (event->cmd[3] << 16) | (event->cmd[4] << 8) | event->cmd[5];
1258 		if (tempo == 0) {
1259 			tempo = 1;
1260 		}
1261 		tempo = 60000000 / tempo;
1262 		if (tempo == 0) {
1263 			tempo = 1;
1264 		}
1265 		if (tempo > 65535) {
1266 			tempo = 65535;
1267 		}
1268 	}
1269 	return tempo;
1270 }
1271 
1272 void
umidi20_event_set_tempo(struct umidi20_event * event,uint32_t tempo)1273 umidi20_event_set_tempo(struct umidi20_event *event,
1274     uint32_t tempo)
1275 {
1276 	if (!umidi20_event_is_tempo(event)) {
1277 		return;
1278 	}
1279 	if (tempo < 3) {
1280 		tempo = 3;
1281 	}
1282 	if (tempo > 65535) {
1283 		tempo = 65535;
1284 	}
1285 	tempo = (60000000 + (tempo / 2) - 1) / tempo;
1286 
1287 	event->cmd[3] = (tempo >> 16) & 0xFF;
1288 	event->cmd[4] = (tempo >> 8) & 0xFF;
1289 	event->cmd[5] = (tempo & 0xFF);
1290 	event->cmd[0] = 6;		/* bytes */
1291 }
1292 
1293 struct umidi20_event *
umidi20_event_queue_search(struct umidi20_event_queue * queue,uint32_t position,uint8_t cache_no)1294 umidi20_event_queue_search(struct umidi20_event_queue *queue,
1295     uint32_t position, uint8_t cache_no)
1296 {
1297 	struct umidi20_event *event = queue->ifq_cache[cache_no];
1298 
1299 	if (event == NULL) {
1300 		UMIDI20_IF_POLL_HEAD(queue, event);
1301 		if (event == NULL) {
1302 			goto done;
1303 		}
1304 	}
1305 	while (1) {
1306 		if (event->position < position) {
1307 			break;
1308 		}
1309 		if (event->p_prevpkt == NULL) {
1310 			break;
1311 		}
1312 		event = event->p_prevpkt;
1313 	}
1314 
1315 	while (1) {
1316 		if (event->position >= position) {
1317 			queue->ifq_cache[cache_no] = event;
1318 			goto done;
1319 		}
1320 		if (event->p_nextpkt == NULL) {
1321 			queue->ifq_cache[cache_no] = event;
1322 			event = NULL;
1323 			goto done;
1324 		}
1325 		event = event->p_nextpkt;
1326 	}
1327 done:
1328 	return event;
1329 }
1330 
1331 void
umidi20_event_queue_copy(struct umidi20_event_queue * src,struct umidi20_event_queue * dst,uint32_t pos_a,uint32_t pos_b,uint16_t rev_a,uint16_t rev_b,uint8_t cache_no,uint8_t flag)1332 umidi20_event_queue_copy(struct umidi20_event_queue *src,
1333     struct umidi20_event_queue *dst,
1334     uint32_t pos_a, uint32_t pos_b,
1335     uint16_t rev_a, uint16_t rev_b,
1336     uint8_t cache_no, uint8_t flag)
1337 {
1338 	struct umidi20_event *event_a;
1339 	struct umidi20_event *event_b;
1340 	struct umidi20_event *event_n;
1341 
1342 	if (pos_b < pos_a) {
1343 		pos_b = -1;
1344 	}
1345 	event_a = umidi20_event_queue_search(src, pos_a, cache_no);
1346 	event_b = umidi20_event_queue_search(src, pos_b, cache_no);
1347 
1348 	while (event_a != event_b) {
1349 
1350 		if ((event_a->revision >= rev_a) &&
1351 		    (event_a->revision < rev_b)) {
1352 
1353 			event_n = umidi20_event_copy(event_a, flag);
1354 
1355 			if (event_n) {
1356 				umidi20_event_queue_insert(dst, event_n, cache_no);
1357 			} else {
1358 				/* XXX do what */
1359 			}
1360 		}
1361 		event_a = event_a->p_nextpkt;
1362 	}
1363 }
1364 
1365 void
umidi20_event_queue_move(struct umidi20_event_queue * src,struct umidi20_event_queue * dst,uint32_t pos_a,uint32_t pos_b,uint16_t rev_a,uint16_t rev_b,uint8_t cache_no)1366 umidi20_event_queue_move(struct umidi20_event_queue *src,
1367     struct umidi20_event_queue *dst,
1368     uint32_t pos_a, uint32_t pos_b,
1369     uint16_t rev_a, uint16_t rev_b,
1370     uint8_t cache_no)
1371 {
1372 	struct umidi20_event *event_a;
1373 	struct umidi20_event *event_b;
1374 	struct umidi20_event *event_n;
1375 
1376 	if (pos_b < pos_a) {
1377 		pos_b = -1;
1378 	}
1379 	event_a = umidi20_event_queue_search(src, pos_a, cache_no);
1380 	event_b = umidi20_event_queue_search(src, pos_b, cache_no);
1381 
1382 	while (event_a != event_b) {
1383 
1384 		event_n = event_a->p_nextpkt;
1385 
1386 		if ((event_a->revision >= rev_a) &&
1387 		    (event_a->revision < rev_b)) {
1388 
1389 			UMIDI20_IF_REMOVE(src, event_a);
1390 
1391 			if (dst) {
1392 				umidi20_event_queue_insert(dst, event_a, cache_no);
1393 			} else {
1394 				umidi20_event_free(event_a);
1395 			}
1396 		}
1397 		event_a = event_n;
1398 	}
1399 }
1400 
1401 void
umidi20_event_queue_insert(struct umidi20_event_queue * dst,struct umidi20_event * event_n,uint8_t cache_no)1402 umidi20_event_queue_insert(struct umidi20_event_queue *dst,
1403     struct umidi20_event *event_n,
1404     uint8_t cache_no)
1405 {
1406 	struct umidi20_event *event_a =
1407 	umidi20_event_queue_search(dst, event_n->position + 1, cache_no);
1408 
1409 	if (event_a == NULL) {
1410 		/* queue at end */
1411 		UMIDI20_IF_ENQUEUE_LAST(dst, event_n);
1412 	} else {
1413 		/* queue before event */
1414 		UMIDI20_IF_ENQUEUE_BEFORE(dst, event_a, event_n);
1415 	}
1416 }
1417 
1418 void
umidi20_event_queue_drain(struct umidi20_event_queue * src)1419 umidi20_event_queue_drain(struct umidi20_event_queue *src)
1420 {
1421 	struct umidi20_event *event;
1422 
1423 	while (1) {
1424 
1425 		UMIDI20_IF_DEQUEUE(src, event);
1426 
1427 		if (event == NULL) {
1428 			break;
1429 		}
1430 		umidi20_event_free(event);
1431 	}
1432 }
1433 
1434 /*
1435  * the following statemachine, that converts MIDI commands to
1436  * USB MIDI packets, derives from Linux's usbmidi.c, which
1437  * was written by "Clemens Ladisch":
1438  *
1439  * return values:
1440  *    0: No command
1441  * Else: Command is complete
1442  */
1443 uint8_t
umidi20_convert_to_command(struct umidi20_converter * conv,uint8_t b)1444 umidi20_convert_to_command(struct umidi20_converter *conv, uint8_t b)
1445 {
1446 	static const uint8_t p0 = 0x0;
1447 	static const uint8_t s0 = 0x0;
1448 
1449 	if (b >= 0xf8) {
1450 		conv->temp_0[0] = p0 | 0x01 | 0x8;
1451 		conv->temp_0[1] = b;
1452 		conv->temp_0[2] = 0;
1453 		conv->temp_0[3] = 0;
1454 		conv->temp_0[4] = 0;
1455 		conv->temp_0[5] = 0;
1456 		conv->temp_0[6] = 0;
1457 		conv->temp_0[7] = 0;
1458 		conv->temp_cmd = conv->temp_0;
1459 		return 1;
1460 
1461 	} else if (b >= 0xf0) {
1462 		switch (b) {
1463 		case 0xf0:		/* system exclusive begin */
1464 			conv->temp_1[1] = b;
1465 			conv->state = UMIDI20_ST_SYSEX_1;
1466 			break;
1467 		case 0xf1:		/* MIDI time code */
1468 		case 0xf3:		/* song select */
1469 			conv->temp_1[1] = b;
1470 			conv->state = UMIDI20_ST_1PARAM;
1471 			break;
1472 		case 0xf2:		/* song position pointer */
1473 			conv->temp_1[1] = b;
1474 			conv->state = UMIDI20_ST_2PARAM_1;
1475 			break;
1476 		case 0xf4:		/* unknown */
1477 		case 0xf5:		/* unknown */
1478 			conv->state = UMIDI20_ST_UNKNOWN;
1479 			break;
1480 		case 0xf6:		/* tune request */
1481 			conv->temp_1[0] = p0 | 0x01 | 0x8;
1482 			conv->temp_1[1] = 0xf6;
1483 			conv->temp_1[2] = 0;
1484 			conv->temp_1[3] = 0;
1485 			conv->temp_1[4] = 0;
1486 			conv->temp_1[5] = 0;
1487 			conv->temp_1[6] = 0;
1488 			conv->temp_1[7] = 0;
1489 			conv->temp_cmd = conv->temp_1;
1490 			conv->state = UMIDI20_ST_UNKNOWN;
1491 			return 1;
1492 
1493 		case 0xf7:		/* system exclusive end */
1494 			switch (conv->state) {
1495 			case UMIDI20_ST_SYSEX_0:
1496 				conv->temp_1[0] = p0 | 0x1 | s0;
1497 				conv->temp_1[1] = 0xf7;
1498 				conv->temp_1[2] = 0;
1499 				conv->temp_1[3] = 0;
1500 				conv->temp_1[4] = 0;
1501 				conv->temp_1[5] = 0;
1502 				conv->temp_1[6] = 0;
1503 				conv->temp_1[7] = 0;
1504 				conv->temp_cmd = conv->temp_1;
1505 				conv->state = UMIDI20_ST_UNKNOWN;
1506 				return 1;
1507 			case UMIDI20_ST_SYSEX_1:
1508 				conv->temp_1[0] = p0 | 0x2 | s0;
1509 				conv->temp_1[2] = 0xf7;
1510 				conv->temp_1[3] = 0;
1511 				conv->temp_1[4] = 0;
1512 				conv->temp_1[5] = 0;
1513 				conv->temp_1[6] = 0;
1514 				conv->temp_1[7] = 0;
1515 				conv->temp_cmd = conv->temp_1;
1516 				conv->state = UMIDI20_ST_UNKNOWN;
1517 				return 1;
1518 			case UMIDI20_ST_SYSEX_2:
1519 				conv->temp_1[0] = p0 | 0x3 | s0;
1520 				conv->temp_1[3] = 0xf7;
1521 				conv->temp_1[4] = 0;
1522 				conv->temp_1[5] = 0;
1523 				conv->temp_1[6] = 0;
1524 				conv->temp_1[7] = 0;
1525 				conv->temp_cmd = conv->temp_1;
1526 				conv->state = UMIDI20_ST_UNKNOWN;
1527 				return 1;
1528 			case UMIDI20_ST_SYSEX_3:
1529 				conv->temp_1[0] = p0 | 0x4 | s0;
1530 				conv->temp_1[4] = 0xf7;
1531 				conv->temp_1[5] = 0;
1532 				conv->temp_1[6] = 0;
1533 				conv->temp_1[7] = 0;
1534 				conv->temp_cmd = conv->temp_1;
1535 				conv->state = UMIDI20_ST_UNKNOWN;
1536 				return 1;
1537 			case UMIDI20_ST_SYSEX_4:
1538 				conv->temp_1[0] = p0 | 0x5 | s0;
1539 				conv->temp_1[5] = 0xf7;
1540 				conv->temp_1[6] = 0;
1541 				conv->temp_1[7] = 0;
1542 				conv->temp_cmd = conv->temp_1;
1543 				conv->state = UMIDI20_ST_UNKNOWN;
1544 				return 1;
1545 			case UMIDI20_ST_SYSEX_5:
1546 				conv->temp_1[0] = p0 | 0x6 | s0;
1547 				conv->temp_1[6] = 0xf7;
1548 				conv->temp_1[7] = 0;
1549 				conv->temp_cmd = conv->temp_1;
1550 				conv->state = UMIDI20_ST_UNKNOWN;
1551 				return 1;
1552 			case UMIDI20_ST_SYSEX_6:
1553 				conv->temp_1[0] = p0 | 0x7 | s0;
1554 				conv->temp_1[7] = 0xf7;
1555 				conv->temp_cmd = conv->temp_1;
1556 				conv->state = UMIDI20_ST_UNKNOWN;
1557 				return 1;
1558 			}
1559 			conv->state = UMIDI20_ST_UNKNOWN;
1560 			break;
1561 		}
1562 	} else if (b >= 0x80) {
1563 		conv->temp_1[1] = b;
1564 		if ((b >= 0xc0) && (b <= 0xdf)) {
1565 			conv->state = UMIDI20_ST_1PARAM;
1566 		} else {
1567 			conv->state = UMIDI20_ST_2PARAM_1;
1568 		}
1569 	} else {			/* b < 0x80 */
1570 		switch (conv->state) {
1571 		case UMIDI20_ST_1PARAM:
1572 			if (conv->temp_1[1] >= 0xf0) {
1573 				conv->state = UMIDI20_ST_UNKNOWN;
1574 			}
1575 			conv->temp_1[0] = p0 | 0x02 | 0x8;
1576 			conv->temp_1[2] = b;
1577 			conv->temp_1[3] = 0;
1578 			conv->temp_1[4] = 0;
1579 			conv->temp_1[5] = 0;
1580 			conv->temp_1[6] = 0;
1581 			conv->temp_1[7] = 0;
1582 			conv->temp_cmd = conv->temp_1;
1583 			return 1;
1584 		case UMIDI20_ST_2PARAM_1:
1585 			conv->temp_1[2] = b;
1586 			conv->state = UMIDI20_ST_2PARAM_2;
1587 			break;
1588 		case UMIDI20_ST_2PARAM_2:
1589 			if (conv->temp_1[1] < 0xf0) {
1590 				conv->state = UMIDI20_ST_2PARAM_1;
1591 			} else {
1592 				conv->state = UMIDI20_ST_UNKNOWN;
1593 			}
1594 			conv->temp_1[0] = p0 | 0x03 | 0x8;
1595 			conv->temp_1[3] = b;
1596 			conv->temp_1[4] = 0;
1597 			conv->temp_1[5] = 0;
1598 			conv->temp_1[6] = 0;
1599 			conv->temp_1[7] = 0;
1600 			conv->temp_cmd = conv->temp_1;
1601 			return 1;
1602 		case UMIDI20_ST_SYSEX_0:
1603 			conv->temp_1[1] = b;
1604 			conv->state = UMIDI20_ST_SYSEX_1;
1605 			break;
1606 		case UMIDI20_ST_SYSEX_1:
1607 			conv->temp_1[2] = b;
1608 			conv->state = UMIDI20_ST_SYSEX_2;
1609 			break;
1610 		case UMIDI20_ST_SYSEX_2:
1611 			conv->temp_1[3] = b;
1612 			conv->state = UMIDI20_ST_SYSEX_3;
1613 			break;
1614 		case UMIDI20_ST_SYSEX_3:
1615 			conv->temp_1[4] = b;
1616 			conv->state = UMIDI20_ST_SYSEX_4;
1617 			break;
1618 		case UMIDI20_ST_SYSEX_4:
1619 			conv->temp_1[5] = b;
1620 			conv->state = UMIDI20_ST_SYSEX_5;
1621 			break;
1622 		case UMIDI20_ST_SYSEX_5:
1623 			conv->temp_1[6] = b;
1624 			conv->state = UMIDI20_ST_SYSEX_6;
1625 			break;
1626 		case UMIDI20_ST_SYSEX_6:
1627 			if (conv->temp_1[1] == 0xF0) {
1628 				conv->temp_1[0] = p0 | 0x0 | s0;
1629 			} else {
1630 				conv->temp_1[0] = p0 | 0x8 | s0;
1631 			}
1632 			conv->temp_1[7] = b;
1633 			conv->temp_cmd = conv->temp_1;
1634 			conv->state = UMIDI20_ST_SYSEX_0;
1635 			return 1;
1636 		}
1637 	}
1638 	return 0;
1639 }
1640 
1641 struct umidi20_event *
umidi20_convert_to_event(struct umidi20_converter * conv,uint8_t b,uint8_t flag)1642 umidi20_convert_to_event(struct umidi20_converter *conv,
1643     uint8_t b, uint8_t flag)
1644 {
1645 	struct umidi20_event *event = NULL;
1646 
1647 	if (umidi20_convert_to_command(conv, b)) {
1648 
1649 		if (conv->temp_cmd[0] == 0x0) {
1650 			/* long command begins */
1651 			umidi20_event_free(conv->p_next);
1652 			conv->p_next = NULL;
1653 			conv->pp_next = NULL;
1654 		}
1655 		if (conv->temp_cmd[0] <= 0x8) {
1656 			/* accumulate system exclusive messages */
1657 			if (conv->pp_next == NULL)
1658 				conv->pp_next = &(conv->p_next);
1659 			event = umidi20_event_alloc(&(conv->pp_next), flag);
1660 		} else {
1661 			event = umidi20_event_alloc(NULL, flag);
1662 		}
1663 
1664 		memcpy(event->cmd, conv->temp_cmd, UMIDI20_COMMAND_LEN);
1665 
1666 		if ((conv->temp_cmd[0] == 0x8) ||
1667 		    (conv->temp_cmd[0] == 0x0)) {
1668 			event = NULL;
1669 		} else if (conv->temp_cmd[0] < 8) {
1670 			event = conv->p_next;
1671 			conv->p_next = NULL;
1672 			conv->pp_next = NULL;
1673 		} else {
1674 			/* short command */
1675 		}
1676 	}
1677 	return event;
1678 }
1679 
1680 void
umidi20_convert_reset(struct umidi20_converter * conv)1681 umidi20_convert_reset(struct umidi20_converter *conv)
1682 {
1683 	umidi20_event_free(conv->p_next);
1684 	memset(conv, 0, sizeof(*conv));
1685 }
1686 
1687 const
1688 uint8_t	umidi20_command_to_len[16] = {
1689 
1690 	/* Long MIDI commands */
1691 
1692 	[0x0] = 7,			/* bytes, long command begins */
1693 	[0x1] = 1,			/* bytes, long command ends */
1694 	[0x2] = 2,			/* bytes, long command ends */
1695 	[0x3] = 3,			/* bytes, long command ends */
1696 	[0x4] = 4,			/* bytes, long command ends */
1697 	[0x5] = 5,			/* bytes, long command ends */
1698 	[0x6] = 6,			/* bytes, long command ends */
1699 	[0x7] = 7,			/* bytes, long command ends */
1700 	[0x8] = 7,			/* bytes, long command continues */
1701 
1702 	/* Short MIDI commands */
1703 
1704 	[0x9] = 1,			/* bytes, short command ends */
1705 	[0xA] = 2,			/* bytes, short command ends */
1706 	[0xB] = 3,			/* bytes, short command ends */
1707 	[0xC] = 4,			/* bytes, short command ends */
1708 	[0xD] = 5,			/* bytes, short command ends */
1709 	[0xE] = 6,			/* bytes, short command ends */
1710 	[0xF] = 7,			/* bytes, short command ends */
1711 };
1712 
1713 void
umidi20_gettime(struct timespec * ts)1714 umidi20_gettime(struct timespec *ts)
1715 {
1716 #ifdef __APPLE__
1717 	uint64_t value = (mach_absolute_time() *
1718 	    umidi20_timebase_info.numer) / umidi20_timebase_info.denom;
1719 	ts->tv_nsec = value % 1000000000ULL;
1720 	ts->tv_sec = value / 1000000000ULL;
1721 #else
1722 	if (clock_gettime(CLOCK_MONOTONIC, ts) == -1) {
1723 		memset(ts, 0, sizeof(*ts));
1724 	}
1725 #endif
1726 }
1727 
1728 uint32_t
umidi20_difftime(struct timespec * a,struct timespec * b)1729 umidi20_difftime(struct timespec *a, struct timespec *b)
1730 {
1731 	struct timespec c;
1732 
1733 	c.tv_sec = a->tv_sec - b->tv_sec;
1734 	c.tv_nsec = a->tv_nsec - b->tv_nsec;
1735 
1736 	if (a->tv_nsec < b->tv_nsec) {
1737 		c.tv_sec -= 1;
1738 		c.tv_nsec += 1000000000;
1739 	}
1740 	return ((c.tv_sec * 1000) + (c.tv_nsec / 1000000));
1741 }
1742 
1743 int
umidi20_mutex_init(pthread_mutex_t * pmutex)1744 umidi20_mutex_init(pthread_mutex_t *pmutex)
1745 {
1746 	pthread_mutexattr_t attr;
1747 
1748 	pthread_mutexattr_init(&attr);
1749 	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1750 	return pthread_mutex_init(pmutex, &attr);
1751 }
1752 
1753 static void
umidi20_device_start(struct umidi20_device * dev,uint32_t start_position,uint32_t end_offset)1754 umidi20_device_start(struct umidi20_device *dev,
1755     uint32_t start_position,
1756     uint32_t end_offset)
1757 {
1758 	dev->start_position = start_position;
1759 	dev->end_offset = end_offset;
1760 	dev->enabled_usr = 1;
1761 }
1762 
1763 static void
umidi20_device_stop(struct umidi20_device * dev,int play_fd)1764 umidi20_device_stop(struct umidi20_device *dev, int play_fd)
1765 {
1766 	uint32_t y;
1767 	uint8_t buf[4];
1768 	uint8_t timeout = 16;
1769 
1770 	dev->enabled_usr = 0;
1771 	umidi20_convert_reset(&(dev->conv));
1772 	umidi20_event_queue_drain(&(dev->queue));
1773 
1774 	if (play_fd < 0)
1775 		return;
1776 
1777 	if (dev->any_key_start == 0)
1778 		return;
1779 
1780 	/* clear any key start */
1781 	dev->any_key_start = 0;
1782 
1783 	/* all sound off */
1784 	for (y = 0; y != 16; y++) {
1785 		buf[0] = 0xB0 | y;
1786 		buf[1] = 0x78;
1787 		buf[2] = 0;
1788 		while (write(play_fd, buf, 3) < 0 &&
1789 		    errno == EWOULDBLOCK && timeout != 0) {
1790 			usleep(10000);
1791 			timeout--;
1792 		}
1793 	}
1794 
1795 	/* turn pedal off */
1796 	for (y = 0; y != 16; y++) {
1797 		buf[0] = 0xB0 | y;
1798 		buf[1] = 0x40;
1799 		buf[2] = 0;
1800 		while (write(play_fd, buf, 3) < 0 &&
1801 		    errno == EWOULDBLOCK && timeout != 0) {
1802 			usleep(10000);
1803 			timeout--;
1804 		}
1805 	}
1806 }
1807 
1808 static void
umidi20_put_queue(uint8_t device_no,struct umidi20_event * event)1809 umidi20_put_queue(uint8_t device_no,
1810     struct umidi20_event *event)
1811 {
1812 	struct umidi20_device *dev;
1813 
1814 	if (device_no >= UMIDI20_N_DEVICES) {
1815 		umidi20_event_free(event);
1816 		return;
1817 	}
1818 	pthread_mutex_lock(&root_dev.mutex);
1819 
1820 	dev = &(root_dev.play[device_no]);
1821 
1822 	if (dev->enabled_usr &&
1823 	    dev->enabled_cfg) {
1824 		umidi20_event_queue_insert
1825 		    (&(dev->queue), event, UMIDI20_CACHE_INPUT);
1826 	} else {
1827 		umidi20_event_free(event);
1828 	}
1829 
1830 	pthread_mutex_unlock(&root_dev.mutex);
1831 }
1832 
1833 static struct umidi20_event *
umidi20_get_queue(uint8_t device_no)1834 umidi20_get_queue(uint8_t device_no)
1835 {
1836 	struct umidi20_device *dev;
1837 	struct umidi20_event *event;
1838 
1839 	if (device_no >= UMIDI20_N_DEVICES) {
1840 		return NULL;
1841 	}
1842 	pthread_mutex_lock(&root_dev.mutex);
1843 
1844 	dev = &(root_dev.rec[device_no]);
1845 
1846 	if (dev->enabled_usr &&
1847 	    dev->enabled_cfg) {
1848 		UMIDI20_IF_DEQUEUE(&(dev->queue), event);
1849 	} else {
1850 		event = NULL;
1851 	}
1852 
1853 	pthread_mutex_unlock(&root_dev.mutex);
1854 
1855 	return event;
1856 }
1857 
1858 void
umidi20_start(uint32_t start_offset,uint32_t end_offset,uint8_t flag)1859 umidi20_start(uint32_t start_offset, uint32_t end_offset, uint8_t flag)
1860 {
1861 	uint32_t x;
1862 	uint32_t start_position;
1863 
1864 	if (flag == 0) {
1865 		return;
1866 	}
1867 	pthread_mutex_lock(&root_dev.mutex);
1868 
1869 	umidi20_stop(flag);
1870 
1871 	/* sanity checking */
1872 
1873 	if ((end_offset <= start_offset) ||
1874 	    (start_offset > 0x80000000) ||
1875 	    (end_offset > 0x80000000)) {
1876 		goto done;
1877 	}
1878 	start_position = (root_dev.curr_position - start_offset);
1879 
1880 	if (flag & UMIDI20_FLAG_PLAY) {
1881 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
1882 			umidi20_device_start
1883 			    (&(root_dev.play[x]), start_position, end_offset);
1884 		}
1885 	}
1886 	if (flag & UMIDI20_FLAG_RECORD) {
1887 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
1888 			umidi20_device_start
1889 			    (&(root_dev.rec[x]), start_position, end_offset);
1890 		}
1891 	}
1892 done:
1893 	pthread_mutex_unlock(&root_dev.mutex);
1894 }
1895 
1896 void
umidi20_stop(uint8_t flag)1897 umidi20_stop(uint8_t flag)
1898 {
1899 	uint32_t x;
1900 
1901 	if (flag == 0)
1902 		return;
1903 
1904 	pthread_mutex_lock(&root_dev.mutex);
1905 	if (flag & UMIDI20_FLAG_PLAY) {
1906 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
1907 			umidi20_device_stop(&(root_dev.play[x]),
1908 			    root_dev.play[x].file_no);
1909 		}
1910 	}
1911 	if (flag & UMIDI20_FLAG_RECORD) {
1912 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
1913 			umidi20_device_stop(&(root_dev.rec[x]), -1);
1914 		}
1915 	}
1916 	pthread_mutex_unlock(&root_dev.mutex);
1917 }
1918 
1919 uint8_t
umidi20_all_dev_off(uint8_t flag)1920 umidi20_all_dev_off(uint8_t flag)
1921 {
1922 	uint32_t x;
1923 	uint8_t retval = 1;
1924 
1925 	if (flag == 0)
1926 		goto done;
1927 
1928 	pthread_mutex_lock(&root_dev.mutex);
1929 	if (flag & UMIDI20_FLAG_PLAY) {
1930 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
1931 			if (root_dev.play[x].enabled_cfg) {
1932 				retval = 0;
1933 				break;
1934 			}
1935 		}
1936 	}
1937 	if (flag & UMIDI20_FLAG_RECORD) {
1938 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
1939 			if (root_dev.rec[x].enabled_cfg) {
1940 				retval = 0;
1941 				break;
1942 			}
1943 		}
1944 	}
1945 	pthread_mutex_unlock(&root_dev.mutex);
1946 done:
1947 	return retval;
1948 }
1949 
1950 struct umidi20_song *
umidi20_song_alloc(pthread_mutex_t * p_mtx,uint16_t file_format,uint16_t resolution,uint8_t div_type)1951 umidi20_song_alloc(pthread_mutex_t *p_mtx, uint16_t file_format,
1952     uint16_t resolution, uint8_t div_type)
1953 {
1954 	struct umidi20_song *song = malloc(sizeof(*song));
1955 
1956 	if (song) {
1957 
1958 		memset(song, 0, sizeof(*song));
1959 
1960 		song->p_mtx = p_mtx;
1961 
1962 		if (pthread_create(&(song->thread_io), NULL,
1963 		    &umidi20_watchdog_song, song)) {
1964 			song->thread_io = PTHREAD_NULL;
1965 		}
1966 		song->midi_file_format = file_format;
1967 
1968 		if (resolution == 0) {
1969 			/* avoid division by zero */
1970 			resolution = 1;
1971 		}
1972 		song->midi_resolution = resolution;
1973 		song->midi_division_type = div_type;
1974 	}
1975 	return song;
1976 }
1977 
1978 void
umidi20_song_free(struct umidi20_song * song)1979 umidi20_song_free(struct umidi20_song *song)
1980 {
1981 	struct umidi20_track *track;
1982 
1983 	if (song == NULL) {
1984 		return;
1985 	}
1986 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
1987 
1988 	umidi20_stop_thread(&(song->thread_io), song->p_mtx);
1989 
1990 	umidi20_song_stop(song, UMIDI20_FLAG_PLAY | UMIDI20_FLAG_RECORD);
1991 
1992 	while (1) {
1993 
1994 		UMIDI20_IF_DEQUEUE(&(song->queue), track);
1995 
1996 		if (track == NULL) {
1997 			break;
1998 		}
1999 		umidi20_track_free(track);
2000 	}
2001 
2002 	free(song);
2003 }
2004 
2005 static void
umidi20_watchdog_song_sub(struct umidi20_song * song)2006 umidi20_watchdog_song_sub(struct umidi20_song *song)
2007 {
2008 	struct umidi20_track *track;
2009 	struct umidi20_event *event;
2010 	struct umidi20_event_queue queue;
2011 	uint32_t curr_position;
2012 	uint32_t position;
2013 	uint32_t x;
2014 
2015 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2016 
2017 	memset(&queue, 0, sizeof(queue));
2018 
2019 	pthread_mutex_lock(&root_dev.mutex);
2020 	curr_position = root_dev.curr_position;
2021 	pthread_mutex_unlock(&root_dev.mutex);
2022 
2023 	track = song->queue.ifq_cache[UMIDI20_CACHE_INPUT];
2024 
2025 	if (song->rec_enabled && track) {
2026 
2027 		for (x = 0; x < UMIDI20_N_DEVICES; x++) {
2028 
2029 			while (1) {
2030 
2031 				event = umidi20_get_queue(x);
2032 
2033 				if (event == NULL) {
2034 					break;
2035 				}
2036 				umidi20_event_queue_insert
2037 				    (&(track->queue), event,
2038 				    UMIDI20_CACHE_INPUT);
2039 			}
2040 		}
2041 	}
2042 	if (song->play_enabled) {
2043 
2044 		position = (curr_position - song->play_start_position);
2045 
2046 		position += (song->play_start_offset + 1500);
2047 
2048 		if (position >= song->play_end_offset) {
2049 			song->play_enabled = 0;
2050 			position = song->play_end_offset;
2051 		}
2052 		UMIDI20_QUEUE_FOREACH(track, &(song->queue)) {
2053 			if (!(track->mute_flag)) {
2054 				umidi20_event_queue_copy(&(track->queue), &queue,
2055 				    song->play_last_offset,
2056 				    position, 0, -1,
2057 				    UMIDI20_CACHE_OUTPUT, 0);
2058 			}
2059 		}
2060 
2061 		song->play_last_offset = position;
2062 
2063 		while (1) {
2064 
2065 			UMIDI20_IF_DEQUEUE(&queue, event);
2066 
2067 			if (event == NULL) {
2068 				break;
2069 			}
2070 			umidi20_put_queue(event->device_no, event);
2071 		}
2072 	}
2073 }
2074 
2075 
2076 static void *
umidi20_watchdog_song(void * arg)2077 umidi20_watchdog_song(void *arg)
2078 {
2079 	struct umidi20_song *song = arg;
2080 
2081 	pthread_mutex_lock(song->p_mtx);
2082 
2083 	while (song->thread_io != PTHREAD_NULL) {
2084 
2085 		umidi20_watchdog_song_sub(song);
2086 
2087 		pthread_mutex_unlock(song->p_mtx);
2088 
2089 		usleep(250000);
2090 
2091 		pthread_mutex_lock(song->p_mtx);
2092 	}
2093 
2094 	pthread_mutex_unlock(song->p_mtx);
2095 
2096 	return NULL;
2097 }
2098 
2099 struct umidi20_track *
umidi20_song_track_by_unit(struct umidi20_song * song,uint16_t unit)2100 umidi20_song_track_by_unit(struct umidi20_song *song, uint16_t unit)
2101 {
2102 	struct umidi20_track *track;
2103 
2104 	if (song == NULL) {
2105 		return NULL;
2106 	}
2107 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2108 
2109 	UMIDI20_IF_POLL_HEAD(&(song->queue), track);
2110 
2111 	while (track) {
2112 		if (!unit--) {
2113 			break;
2114 		}
2115 		track = track->p_nextpkt;
2116 	}
2117 	return track;
2118 }
2119 
2120 /*
2121  * if "track == NULL" then
2122  * recording is disabled
2123  */
2124 void
umidi20_song_set_record_track(struct umidi20_song * song,struct umidi20_track * track)2125 umidi20_song_set_record_track(struct umidi20_song *song,
2126     struct umidi20_track *track)
2127 {
2128 	if (song == NULL) {
2129 		return;
2130 	}
2131 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2132 	song->queue.ifq_cache[UMIDI20_CACHE_INPUT] = track;
2133 }
2134 
2135 /*
2136  * this function can be called
2137  * multiple times in a row:
2138  */
2139 void
umidi20_song_start(struct umidi20_song * song,uint32_t start_offset,uint32_t end_offset,uint8_t flags)2140 umidi20_song_start(struct umidi20_song *song, uint32_t start_offset,
2141     uint32_t end_offset,
2142     uint8_t flags)
2143 {
2144 	uint32_t curr_position;
2145 
2146 	if (song == NULL) {
2147 		goto done;
2148 	}
2149 	if (flags == 0) {
2150 		goto done;
2151 	}
2152 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2153 
2154 	umidi20_song_stop(song, flags);
2155 
2156 	/* sanity checking */
2157 
2158 	if ((end_offset <= start_offset) ||
2159 	    (start_offset > 0x80000000) ||
2160 	    (end_offset > 0x80000000)) {
2161 		goto done;
2162 	}
2163 	umidi20_start(start_offset, end_offset, flags);
2164 
2165 	pthread_mutex_lock(&root_dev.mutex);
2166 	curr_position = root_dev.curr_position;
2167 	pthread_mutex_unlock(&root_dev.mutex);
2168 
2169 	if (flags & UMIDI20_FLAG_PLAY) {
2170 		song->play_enabled = 1;
2171 		song->play_start_position = curr_position;
2172 		song->play_start_offset = start_offset;
2173 		song->play_last_offset = start_offset;
2174 		song->play_end_offset = end_offset;
2175 	}
2176 	if (flags & UMIDI20_FLAG_RECORD) {
2177 		song->rec_enabled = 1;
2178 	}
2179 	/* update buffering */
2180 
2181 	umidi20_watchdog_song_sub(song);
2182 
2183 	song->pc_flags |= flags;
2184 
2185 done:	;
2186 }
2187 
2188 void
umidi20_song_stop(struct umidi20_song * song,uint8_t flags)2189 umidi20_song_stop(struct umidi20_song *song, uint8_t flags)
2190 {
2191 	if (song == NULL) {
2192 		goto done;
2193 	}
2194 	if (flags == 0) {
2195 		goto done;
2196 	}
2197 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2198 
2199 	flags &= song->pc_flags;
2200 
2201 	if (flags & UMIDI20_FLAG_PLAY) {
2202 		song->play_enabled = 0;
2203 	}
2204 	if (flags & UMIDI20_FLAG_RECORD) {
2205 		song->rec_enabled = 0;
2206 	}
2207 	umidi20_stop(flags);
2208 
2209 	song->pc_flags &= ~flags;
2210 
2211 done:	;
2212 }
2213 
2214 void
umidi20_song_track_add(struct umidi20_song * song,struct umidi20_track * track_ref,struct umidi20_track * track_new,uint8_t is_before_ref)2215 umidi20_song_track_add(struct umidi20_song *song,
2216     struct umidi20_track *track_ref,
2217     struct umidi20_track *track_new,
2218     uint8_t is_before_ref)
2219 {
2220 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2221 
2222 	if (song == NULL) {
2223 		umidi20_track_free(track_new);
2224 		return;
2225 	}
2226 	if (track_ref == NULL) {
2227 		UMIDI20_IF_ENQUEUE_LAST(&(song->queue), track_new);
2228 	} else {
2229 		if (is_before_ref) {
2230 			UMIDI20_IF_ENQUEUE_BEFORE(&(song->queue), track_ref, track_new);
2231 		} else {
2232 			UMIDI20_IF_ENQUEUE_AFTER(&(song->queue), track_ref, track_new);
2233 		}
2234 	}
2235 }
2236 
2237 void
umidi20_song_track_remove(struct umidi20_song * song,struct umidi20_track * track)2238 umidi20_song_track_remove(struct umidi20_song *song,
2239     struct umidi20_track *track)
2240 {
2241 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2242 
2243 	if (song == NULL) {
2244 		return;			/* XXX should not happen */
2245 	}
2246 	if (track == NULL) {
2247 		return;
2248 	}
2249 	UMIDI20_IF_REMOVE(&(song->queue), track);
2250 
2251 	umidi20_track_free(track);
2252 }
2253 
2254 void
umidi20_song_recompute_position(struct umidi20_song * song)2255 umidi20_song_recompute_position(struct umidi20_song *song)
2256 {
2257 	struct umidi20_track *conductor_track;
2258 	struct umidi20_track *track;
2259 	struct umidi20_event *event;
2260 	struct umidi20_event *event_copy;
2261 
2262 	uint32_t tempo;
2263 	uint32_t last_tick;
2264 	uint32_t delta_tick;
2265 	uint32_t factor;
2266 	uint32_t position_curr;
2267 	uint32_t position_rem;
2268 	uint32_t divisor;
2269 
2270 	if (song == NULL) {
2271 		return;
2272 	}
2273 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2274 
2275 	UMIDI20_IF_POLL_HEAD(&(song->queue), conductor_track);
2276 
2277 	if (conductor_track == NULL) {
2278 		goto done;
2279 	}
2280 	/*
2281 	 * First copy the conductor track to
2282 	 * all the other tracks:
2283 	 */
2284 
2285 	UMIDI20_QUEUE_FOREACH(event, &(conductor_track->queue)) {
2286 
2287 		if (umidi20_event_is_tempo(event)) {
2288 
2289 			UMIDI20_QUEUE_FOREACH(track, &(song->queue)) {
2290 
2291 				if (track != conductor_track) {
2292 
2293 					event_copy = umidi20_event_copy(event, 0);
2294 					if (event_copy == NULL) {
2295 						goto fail;
2296 					}
2297 					umidi20_event_queue_insert(&(track->queue),
2298 					    event_copy,
2299 					    UMIDI20_CACHE_INPUT);
2300 				}
2301 			}
2302 		}
2303 	}
2304 
2305 	/*
2306 	 * Compute new position information:
2307 	 */
2308 	UMIDI20_QUEUE_FOREACH(track, &(song->queue)) {
2309 
2310 		tempo = 120;		/* BPM */
2311 		last_tick = 0;
2312 		position_curr = 0;
2313 		position_rem = 0;
2314 
2315 		switch (song->midi_division_type) {
2316 		case UMIDI20_FILE_DIVISION_TYPE_PPQ:
2317 			divisor = (tempo * song->midi_resolution);
2318 			break;
2319 		case UMIDI20_FILE_DIVISION_TYPE_SMPTE24:
2320 			divisor = (24 * song->midi_resolution);
2321 			break;
2322 		case UMIDI20_FILE_DIVISION_TYPE_SMPTE25:
2323 			divisor = (25 * song->midi_resolution);
2324 			break;
2325 		case UMIDI20_FILE_DIVISION_TYPE_SMPTE30DROP:
2326 			divisor = (29.97 * song->midi_resolution);
2327 			break;
2328 		case UMIDI20_FILE_DIVISION_TYPE_SMPTE30:
2329 			divisor = (30 * song->midi_resolution);
2330 			break;
2331 		default:
2332 			divisor = 120;
2333 			break;
2334 		}
2335 
2336 		if (song->midi_division_type == UMIDI20_FILE_DIVISION_TYPE_PPQ) {
2337 			factor = UMIDI20_BPM;
2338 		} else {
2339 			factor = (UMIDI20_BPM / 60);
2340 		}
2341 
2342 		DPRINTF("divisor=%d\n", divisor);
2343 
2344 		UMIDI20_QUEUE_FOREACH(event, &(track->queue)) {
2345 
2346 			delta_tick = (event->tick - last_tick);
2347 			last_tick = event->tick;
2348 
2349 			position_curr += (delta_tick / divisor) * factor;
2350 			position_rem += (delta_tick % divisor) * factor;
2351 
2352 			position_curr += (position_rem / divisor);
2353 			position_rem %= divisor;
2354 
2355 			DPRINTF("%d / %d, pos = %d, tick = %d\n", delta_tick,
2356 			    divisor, position_curr, event->tick);
2357 
2358 			/* update position */
2359 			event->position = position_curr;
2360 
2361 			if (umidi20_event_is_tempo(event) &&
2362 			    (song->midi_division_type == UMIDI20_FILE_DIVISION_TYPE_PPQ)) {
2363 				tempo = umidi20_event_get_tempo(event);
2364 				divisor = (tempo * song->midi_resolution);
2365 				position_rem = 0;
2366 			}
2367 		}
2368 	}
2369 
2370 fail:
2371 	/*
2372 	 * Remove all tempo information from
2373 	 * non-conductor tracks:
2374 	 */
2375 	UMIDI20_QUEUE_FOREACH(track, &(song->queue)) {
2376 
2377 		if (track != conductor_track) {
2378 
2379 			UMIDI20_QUEUE_FOREACH_SAFE(event, &(track->queue), event_copy) {
2380 
2381 				if (umidi20_event_is_tempo(event)) {
2382 
2383 					UMIDI20_IF_REMOVE(&(track->queue), event);
2384 
2385 					umidi20_event_free(event);
2386 				}
2387 			}
2388 		}
2389 	}
2390 done:	;
2391 }
2392 
2393 void
umidi20_song_recompute_tick(struct umidi20_song * song)2394 umidi20_song_recompute_tick(struct umidi20_song *song)
2395 {
2396 	struct umidi20_track *track;
2397 	struct umidi20_event *event;
2398 	struct umidi20_event *event_next;
2399 
2400 	if (song == NULL) {
2401 		return;
2402 	}
2403 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2404 
2405 	song->midi_division_type = UMIDI20_FILE_DIVISION_TYPE_PPQ;
2406 	song->midi_resolution = 500;
2407 
2408 	/*
2409 	 * First remove all tempo
2410 	 * information:
2411 	 */
2412 	UMIDI20_QUEUE_FOREACH(track, &(song->queue)) {
2413 
2414 		UMIDI20_QUEUE_FOREACH_SAFE(event, &(track->queue), event_next) {
2415 
2416 			event->tick = event->position;
2417 
2418 			if (umidi20_event_is_tempo(event)) {
2419 				UMIDI20_IF_REMOVE(&(track->queue), event);
2420 				umidi20_event_free(event);
2421 			}
2422 		}
2423 	}
2424 }
2425 
2426 void
umidi20_song_compute_max_min(struct umidi20_song * song)2427 umidi20_song_compute_max_min(struct umidi20_song *song)
2428 {
2429 	struct umidi20_track *track;
2430 
2431 	pthread_mutex_assert(song->p_mtx, MA_OWNED);
2432 
2433 	song->position_max = 0;
2434 	song->track_max = 0;
2435 	song->band_max = 0;
2436 
2437 	UMIDI20_QUEUE_FOREACH(track, &(song->queue)) {
2438 		umidi20_track_compute_max_min(track);
2439 
2440 		if (track->position_max > song->position_max) {
2441 			song->position_max = track->position_max;
2442 		}
2443 		song->band_max +=
2444 		    (track->band_max - track->band_min);
2445 	}
2446 
2447 	song->track_max = UMIDI20_IF_QLEN(&(song->queue));
2448 }
2449 
2450 void
umidi20_config_export(struct umidi20_config * cfg)2451 umidi20_config_export(struct umidi20_config *cfg)
2452 {
2453 	uint32_t x;
2454 
2455 	memset(cfg, 0, sizeof(*cfg));
2456 
2457 	pthread_mutex_lock(&root_dev.mutex);
2458 
2459 	for (x = 0; x < UMIDI20_N_DEVICES; x++) {
2460 
2461 		STRLCPY(cfg->cfg_dev[x].rec_fname,
2462 		    root_dev.rec[x].fname,
2463 		    sizeof(cfg->cfg_dev[x].rec_fname));
2464 
2465 		cfg->cfg_dev[x].rec_enabled_cfg =
2466 		    root_dev.rec[x].enabled_cfg;
2467 
2468 		STRLCPY(cfg->cfg_dev[x].play_fname,
2469 		    root_dev.play[x].fname,
2470 		    sizeof(cfg->cfg_dev[x].play_fname));
2471 
2472 		cfg->cfg_dev[x].play_enabled_cfg =
2473 		    root_dev.play[x].enabled_cfg;
2474 	}
2475 
2476 	pthread_mutex_unlock(&root_dev.mutex);
2477 }
2478 
2479 void
umidi20_config_import(struct umidi20_config * cfg)2480 umidi20_config_import(struct umidi20_config *cfg)
2481 {
2482 	uint32_t x;
2483 
2484 	pthread_mutex_lock(&root_dev.mutex);
2485 
2486 	for (x = 0; x < UMIDI20_N_DEVICES; x++) {
2487 
2488 		if (strcmp(root_dev.rec[x].fname,
2489 		    cfg->cfg_dev[x].rec_fname)) {
2490 			root_dev.rec[x].update = 1;
2491 			STRLCPY(root_dev.rec[x].fname,
2492 			    cfg->cfg_dev[x].rec_fname,
2493 			    sizeof(root_dev.rec[x].fname));
2494 		}
2495 		if (root_dev.rec[x].enabled_cfg !=
2496 		    cfg->cfg_dev[x].rec_enabled_cfg) {
2497 
2498 			root_dev.rec[x].update = 1;
2499 			root_dev.rec[x].enabled_cfg =
2500 			    cfg->cfg_dev[x].rec_enabled_cfg;
2501 		}
2502 		if (strcmp(root_dev.play[x].fname,
2503 		    cfg->cfg_dev[x].play_fname)) {
2504 
2505 			root_dev.play[x].update = 1;
2506 			STRLCPY(root_dev.play[x].fname,
2507 			    cfg->cfg_dev[x].play_fname,
2508 			    sizeof(root_dev.play[x].fname));
2509 		}
2510 		if (root_dev.play[x].enabled_cfg !=
2511 		    cfg->cfg_dev[x].play_enabled_cfg) {
2512 
2513 			root_dev.play[x].update = 1;
2514 			root_dev.play[x].enabled_cfg =
2515 			    cfg->cfg_dev[x].play_enabled_cfg;
2516 		}
2517 	}
2518 	pthread_mutex_unlock(&root_dev.mutex);
2519 }
2520 
2521 struct umidi20_track *
umidi20_track_alloc(void)2522 umidi20_track_alloc(void)
2523 {
2524 	struct umidi20_track *track;
2525 
2526 	track = malloc(sizeof(*track));
2527 	if (track)
2528 		memset(track, 0, sizeof(*track));
2529 	return (track);
2530 }
2531 
2532 void
umidi20_track_free(struct umidi20_track * track)2533 umidi20_track_free(struct umidi20_track *track)
2534 {
2535 	if (track == NULL)
2536 		return;
2537 
2538 	umidi20_event_queue_drain(&(track->queue));
2539 
2540 	free(track);
2541 }
2542 
2543 void
umidi20_track_compute_max_min(struct umidi20_track * track)2544 umidi20_track_compute_max_min(struct umidi20_track *track)
2545 {
2546 	struct umidi20_event *event;
2547 	struct umidi20_event *event_last;
2548 	struct umidi20_event *last_key_press[128];
2549 	uint32_t what;
2550 	uint8_t key;
2551 	uint8_t is_on;
2552 	uint8_t is_off;
2553 	uint8_t meta_num;
2554 
2555 	memset(&last_key_press, 0, sizeof(last_key_press));
2556 
2557 	track->key_max = 0x00;
2558 	track->key_min = 0xFF;
2559 
2560 	track->position_max = 0;
2561 
2562 	UMIDI20_QUEUE_FOREACH(event, &(track->queue)) {
2563 
2564 		what = umidi20_event_get_what(event);
2565 
2566 		if (what & UMIDI20_WHAT_KEY) {
2567 
2568 			is_on = umidi20_event_is_key_start(event);
2569 			is_off = umidi20_event_is_key_end(event);
2570 			key = umidi20_event_get_key(event) & 0x7F;
2571 
2572 			if (is_on || is_off) {
2573 
2574 				event_last = last_key_press[key];
2575 				last_key_press[key] = NULL;
2576 
2577 				/* update duration */
2578 
2579 				if (event_last) {
2580 					event_last->duration =
2581 					    (event->position - event_last->position);
2582 				}
2583 				if (is_on) {
2584 					last_key_press[key] = event;
2585 				}
2586 			}
2587 			if (key > track->key_max) {
2588 				track->key_max = key;
2589 			}
2590 			if (key < track->key_min) {
2591 				track->key_min = key;
2592 			}
2593 		}
2594 		if (umidi20_event_is_meta(event)) {
2595 			meta_num = umidi20_event_get_meta_number(event);
2596 			what = umidi20_event_get_length(event);
2597 
2598 			if (meta_num == 0x03) {
2599 				what -= 2;
2600 				if (what > (sizeof(track->name) - 1)) {
2601 					what = (sizeof(track->name) - 1);
2602 				}
2603 				umidi20_event_copy_out(event, track->name, 2, what);
2604 				track->name[what] = 0;
2605 			}
2606 			if (meta_num == 0x04) {
2607 				what -= 2;
2608 				if (what > (sizeof(track->instrument) - 1)) {
2609 					what = (sizeof(track->instrument) - 1);
2610 				}
2611 				umidi20_event_copy_out(event, track->instrument, 2, what);
2612 				track->instrument[what] = 0;
2613 			}
2614 		}
2615 	}
2616 	if ((track->key_max == 0x00) &&
2617 	    (track->key_min == 0xFF)) {
2618 		track->key_max = 0x3C;
2619 		track->key_min = 0x3C;
2620 	}
2621 	track->band_min =
2622 	    UMIDI20_KEY_TO_BAND_NUMBER(track->key_min);
2623 
2624 	track->band_max =
2625 	    UMIDI20_KEY_TO_BAND_NUMBER(track->key_max + UMIDI20_BAND_SIZE);
2626 
2627 	UMIDI20_IF_POLL_TAIL(&(track->queue), event);
2628 	if (event) {
2629 		track->position_max = event->position;
2630 	}
2631 	for (key = 0; key < 0x80; key++) {
2632 		event_last = last_key_press[key];
2633 		if (event_last) {
2634 			event_last->duration =
2635 			    (event->position - event_last->position);
2636 		}
2637 	}
2638 }
2639 
2640 int
umidi20_pipe(int fd[2])2641 umidi20_pipe(int fd[2])
2642 {
2643 	int retval = pipe(fd);
2644 
2645 	if (retval != 0) {
2646 		fd[0] = -1;
2647 		fd[1] = -1;
2648 	}
2649 	return (retval);
2650 }
2651