Winmme driver compiles again.
[jack2.git] / linux / alsa / alsa_seqmidi.c
blobc3d8239f76e504ee1293f9733e781a3dfb02f82b
1 /*
2 * ALSA SEQ < - > JACK MIDI bridge
4 * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * alsa_seqmidi_read:
23 * add new ports
24 * reads queued snd_seq_event's
25 * if PORT_EXIT: mark port as dead
26 * if PORT_ADD, PORT_CHANGE: send addr to port_thread (it also may mark port as dead)
27 * else process input event
28 * remove dead ports and send them to port_thread
30 * alsa_seqmidi_write:
31 * remove dead ports and send them to port_thread
32 * add new ports
33 * queue output events
35 * port_thread:
36 * wait for port_sem
37 * free deleted ports
38 * create new ports or mark existing as dead
41 #include <alsa/asoundlib.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <signal.h>
46 #include <semaphore.h>
47 #include <pthread.h>
48 #include <time.h>
49 #include <ctype.h>
51 #include "midiport.h"
52 #include "ringbuffer.h"
53 #include "alsa_midi_impl.h"
54 #include "JackError.h"
56 #define NSEC_PER_SEC ((int64_t)1000*1000*1000)
58 enum {
59 MAX_PORTS = 64,
60 MAX_EVENT_SIZE = 1024,
63 typedef struct port_t port_t;
65 enum {
66 PORT_HASH_BITS = 4,
67 PORT_HASH_SIZE = 1 << PORT_HASH_BITS
70 typedef port_t* port_hash_t[PORT_HASH_SIZE];
72 struct port_t {
73 port_t *next;
74 int is_dead;
75 char name[64];
76 snd_seq_addr_t remote;
77 jack_port_t *jack_port;
79 jack_ringbuffer_t *early_events; // alsa_midi_event_t + data
80 int64_t last_out_time;
82 void *jack_buf;
85 typedef struct {
86 snd_midi_event_t *codec;
88 jack_ringbuffer_t *new_ports;
90 port_t *ports[MAX_PORTS];
91 } stream_t;
93 typedef struct alsa_seqmidi {
94 alsa_midi_t ops;
95 jack_client_t *jack;
97 snd_seq_t *seq;
98 int client_id;
99 int port_id;
100 int queue;
102 int keep_walking;
104 pthread_t port_thread;
105 sem_t port_sem;
106 jack_ringbuffer_t *port_add; // snd_seq_addr_t
107 jack_ringbuffer_t *port_del; // port_t*
109 stream_t stream[2];
111 char alsa_name[32];
112 int midi_in_cnt;
113 int midi_out_cnt;
114 } alsa_seqmidi_t;
116 struct alsa_midi_event {
117 int64_t time;
118 int size;
120 typedef struct alsa_midi_event alsa_midi_event_t;
122 struct process_info {
123 int dir;
124 jack_nframes_t nframes;
125 jack_nframes_t period_start;
126 jack_nframes_t sample_rate;
127 jack_nframes_t cur_frames;
128 int64_t alsa_time;
131 enum PortType { PORT_INPUT = 0, PORT_OUTPUT = 1 };
133 typedef void (*port_jack_func)(alsa_seqmidi_t *self, port_t *port,struct process_info* info);
134 static void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info* info);
135 static void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info);
137 typedef struct {
138 int alsa_mask;
139 int jack_caps;
140 char name[9];
141 port_jack_func jack_func;
142 } port_type_t;
144 static port_type_t port_type[2] = {
146 SND_SEQ_PORT_CAP_SUBS_READ,
147 JackPortIsOutput,
148 "playback",
149 do_jack_input
152 SND_SEQ_PORT_CAP_SUBS_WRITE,
153 JackPortIsInput,
154 "capture",
155 do_jack_output
159 static void alsa_seqmidi_delete(alsa_midi_t *m);
160 static int alsa_seqmidi_attach(alsa_midi_t *m);
161 static int alsa_seqmidi_detach(alsa_midi_t *m);
162 static int alsa_seqmidi_start(alsa_midi_t *m);
163 static int alsa_seqmidi_stop(alsa_midi_t *m);
164 static void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes);
165 static void alsa_seqmidi_write(alsa_midi_t *m, jack_nframes_t nframes);
167 static
168 void stream_init(alsa_seqmidi_t *self, int dir)
170 stream_t *str = &self->stream[dir];
172 str->new_ports = jack_ringbuffer_create(MAX_PORTS*sizeof(port_t*));
173 snd_midi_event_new(MAX_EVENT_SIZE, &str->codec);
176 static void port_free(alsa_seqmidi_t *self, port_t *port);
177 static void free_ports(alsa_seqmidi_t *self, jack_ringbuffer_t *ports);
179 static
180 void stream_attach(alsa_seqmidi_t *self, int dir)
184 static
185 void stream_detach(alsa_seqmidi_t *self, int dir)
187 stream_t *str = &self->stream[dir];
188 int i;
190 free_ports(self, str->new_ports);
192 // delete all ports from hash
193 for (i=0; i<PORT_HASH_SIZE; ++i) {
194 port_t *port = str->ports[i];
195 while (port) {
196 port_t *next = port->next;
197 port_free(self, port);
198 port = next;
200 str->ports[i] = NULL;
204 static
205 void stream_close(alsa_seqmidi_t *self, int dir)
207 stream_t *str = &self->stream[dir];
209 if (str->codec)
210 snd_midi_event_free(str->codec);
211 if (str->new_ports)
212 jack_ringbuffer_free(str->new_ports);
215 alsa_midi_t* alsa_seqmidi_new(jack_client_t *client, const char* alsa_name)
217 alsa_seqmidi_t *self = calloc(1, sizeof(alsa_seqmidi_t));
218 debug_log("midi: new");
219 if (!self)
220 return NULL;
221 self->jack = client;
222 if (!alsa_name)
223 alsa_name = "jack_midi";
224 snprintf(self->alsa_name, sizeof(self->alsa_name), "%s", alsa_name);
226 self->port_add = jack_ringbuffer_create(2*MAX_PORTS*sizeof(snd_seq_addr_t));
227 self->port_del = jack_ringbuffer_create(2*MAX_PORTS*sizeof(port_t*));
228 sem_init(&self->port_sem, 0, 0);
230 stream_init(self, PORT_INPUT);
231 stream_init(self, PORT_OUTPUT);
233 self->midi_in_cnt = 0;
234 self->midi_out_cnt = 0;
235 self->ops.destroy = alsa_seqmidi_delete;
236 self->ops.attach = alsa_seqmidi_attach;
237 self->ops.detach = alsa_seqmidi_detach;
238 self->ops.start = alsa_seqmidi_start;
239 self->ops.stop = alsa_seqmidi_stop;
240 self->ops.read = alsa_seqmidi_read;
241 self->ops.write = alsa_seqmidi_write;
242 return &self->ops;
245 static
246 void alsa_seqmidi_delete(alsa_midi_t *m)
248 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
250 debug_log("midi: delete");
251 alsa_seqmidi_detach(m);
253 stream_close(self, PORT_OUTPUT);
254 stream_close(self, PORT_INPUT);
256 jack_ringbuffer_free(self->port_add);
257 jack_ringbuffer_free(self->port_del);
258 sem_close(&self->port_sem);
260 free(self);
263 static
264 int alsa_seqmidi_attach(alsa_midi_t *m)
266 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
267 int err;
269 debug_log("midi: attach");
271 if (self->seq)
272 return -EALREADY;
274 if ((err = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
275 error_log("failed to open alsa seq");
276 return err;
278 snd_seq_set_client_name(self->seq, self->alsa_name);
279 self->port_id = snd_seq_create_simple_port(self->seq, "port",
280 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
281 #ifndef JACK_MIDI_DEBUG
282 |SND_SEQ_PORT_CAP_NO_EXPORT
283 #endif
284 ,SND_SEQ_PORT_TYPE_APPLICATION);
285 self->client_id = snd_seq_client_id(self->seq);
287 self->queue = snd_seq_alloc_queue(self->seq);
288 snd_seq_start_queue(self->seq, self->queue, 0);
290 stream_attach(self, PORT_INPUT);
291 stream_attach(self, PORT_OUTPUT);
293 snd_seq_nonblock(self->seq, 1);
295 return 0;
298 static
299 int alsa_seqmidi_detach(alsa_midi_t *m)
301 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
303 debug_log("midi: detach");
305 if (!self->seq)
306 return -EALREADY;
308 alsa_seqmidi_stop(m);
310 jack_ringbuffer_reset(self->port_add);
311 free_ports(self, self->port_del);
313 stream_detach(self, PORT_INPUT);
314 stream_detach(self, PORT_OUTPUT);
316 snd_seq_close(self->seq);
317 self->seq = NULL;
319 return 0;
322 static void* port_thread(void *);
324 static void add_existing_ports(alsa_seqmidi_t *self);
325 static void update_ports(alsa_seqmidi_t *self);
326 static void add_ports(stream_t *str);
328 static
329 int alsa_seqmidi_start(alsa_midi_t *m)
331 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
332 int err;
334 debug_log("midi: start");
336 if (!self->seq)
337 return -EBADF;
339 if (self->keep_walking)
340 return -EALREADY;
342 snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
343 snd_seq_drop_input(self->seq);
345 add_existing_ports(self);
346 update_ports(self);
347 add_ports(&self->stream[PORT_INPUT]);
348 add_ports(&self->stream[PORT_OUTPUT]);
350 self->keep_walking = 1;
352 if ((err = pthread_create(&self->port_thread, NULL, port_thread, self))) {
353 self->keep_walking = 0;
354 return -errno;
357 return 0;
360 static
361 int alsa_seqmidi_stop(alsa_midi_t *m)
363 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
365 debug_log("midi: stop");
367 if (!self->keep_walking)
368 return -EALREADY;
370 snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
372 self->keep_walking = 0;
374 sem_post(&self->port_sem);
375 pthread_join(self->port_thread, NULL);
376 self->port_thread = 0;
378 return 0;
381 static
382 int alsa_connect_from(alsa_seqmidi_t *self, int client, int port)
384 snd_seq_port_subscribe_t* sub;
385 snd_seq_addr_t seq_addr;
386 int err;
388 snd_seq_port_subscribe_alloca(&sub);
389 seq_addr.client = client;
390 seq_addr.port = port;
391 snd_seq_port_subscribe_set_sender(sub, &seq_addr);
392 seq_addr.client = self->client_id;
393 seq_addr.port = self->port_id;
394 snd_seq_port_subscribe_set_dest(sub, &seq_addr);
396 snd_seq_port_subscribe_set_time_update(sub, 1);
397 snd_seq_port_subscribe_set_queue(sub, self->queue);
398 snd_seq_port_subscribe_set_time_real(sub, 1);
400 if ((err=snd_seq_subscribe_port(self->seq, sub)))
401 error_log("can't subscribe to %d:%d - %s", client, port, snd_strerror(err));
402 return err;
406 * ==================== Port routines =============================
408 static inline
409 int port_hash(snd_seq_addr_t addr)
411 return (addr.client + addr.port) % PORT_HASH_SIZE;
414 static
415 port_t* port_get(port_hash_t hash, snd_seq_addr_t addr)
417 port_t **pport = &hash[port_hash(addr)];
418 while (*pport) {
419 port_t *port = *pport;
420 if (port->remote.client == addr.client && port->remote.port == addr.port)
421 return port;
422 pport = &port->next;
424 return NULL;
427 static
428 void port_insert(port_hash_t hash, port_t *port)
430 port_t **pport = &hash[port_hash(port->remote)];
431 port->next = *pport;
432 *pport = port;
435 static
436 void port_setdead(port_hash_t hash, snd_seq_addr_t addr)
438 port_t *port = port_get(hash, addr);
439 if (port)
440 port->is_dead = 1; // see jack_process
441 else
442 debug_log("port_setdead: not found (%d:%d)", addr.client, addr.port);
445 static
446 void port_free(alsa_seqmidi_t *self, port_t *port)
448 //snd_seq_disconnect_from(self->seq, self->port_id, port->remote.client, port->remote.port);
449 //snd_seq_disconnect_to(self->seq, self->port_id, port->remote.client, port->remote.port);
450 if (port->early_events)
451 jack_ringbuffer_free(port->early_events);
452 if (port->jack_port)
453 jack_port_unregister(self->jack, port->jack_port);
454 info_log("port deleted: %s", port->name);
456 free(port);
459 static
460 port_t* port_create(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, const snd_seq_port_info_t *info)
462 snd_seq_client_info_t* client_info;
463 port_t *port;
464 char *c;
465 int err;
466 int jack_caps;
467 char name[128];
469 port = calloc(1, sizeof(port_t));
470 if (!port)
471 return NULL;
473 port->remote = addr;
475 snd_seq_client_info_alloca (&client_info);
476 snd_seq_get_any_client_info (self->seq, addr.client, client_info);
478 snprintf(port->name, sizeof(port->name), "alsa_pcm:%s/midi_%s_%d",
479 snd_seq_client_info_get_name(client_info), port_type[type].name, addr.port+1);
481 // replace all offending characters by -
482 for (c = port->name; *c; ++c)
483 if (!isalnum(*c) && *c != '/' && *c != '_' && *c != ':' && *c != '(' && *c != ')')
484 *c = '-';
486 jack_caps = port_type[type].jack_caps;
488 /* mark anything that looks like a hardware port as physical&terminal */
490 if (snd_seq_port_info_get_type (info) & (SND_SEQ_PORT_TYPE_HARDWARE|SND_SEQ_PORT_TYPE_PORT|SND_SEQ_PORT_TYPE_SPECIFIC)) {
491 jack_caps |= (JackPortIsPhysical | JackPortIsTerminal);
494 if (jack_caps & JackPortIsOutput)
495 snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt);
496 else
497 snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt);
499 port->jack_port = jack_port_register(self->jack,
500 name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0);
501 if (!port->jack_port)
502 goto failed;
504 jack_port_set_alias (port->jack_port, port->name);
506 /* generate an alias */
508 snprintf(port->name, sizeof(port->name), "%s:midi/%s_%d",
509 snd_seq_client_info_get_name (client_info), port_type[type].name, addr.port+1);
511 // replace all offending characters by -
512 for (c = port->name; *c; ++c)
513 if (!isalnum(*c) && *c != '/' && *c != '_' && *c != ':' && *c != '(' && *c != ')')
514 *c = '-';
516 jack_port_set_alias (port->jack_port, port->name);
518 if (type == PORT_INPUT)
519 err = alsa_connect_from(self, port->remote.client, port->remote.port);
520 else
521 err = snd_seq_connect_to(self->seq, self->port_id, port->remote.client, port->remote.port);
522 if (err)
523 goto failed;
525 port->early_events = jack_ringbuffer_create(MAX_EVENT_SIZE*16);
527 info_log("port created: %s", port->name);
528 return port;
530 failed:
531 port_free(self, port);
532 return NULL;
536 * ==================== Port add/del handling thread ==============================
538 static
539 void update_port_type(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, int caps, const snd_seq_port_info_t *info)
541 stream_t *str = &self->stream[type];
542 int alsa_mask = port_type[type].alsa_mask;
543 port_t *port = port_get(str->ports, addr);
545 debug_log("update_port_type(%d:%d)", addr.client, addr.port);
547 if (port && (caps & alsa_mask)!=alsa_mask) {
548 debug_log("setdead: %s", port->name);
549 port->is_dead = 1;
552 if (!port && (caps & alsa_mask)==alsa_mask) {
553 assert (jack_ringbuffer_write_space(str->new_ports) >= sizeof(port));
554 port = port_create(self, type, addr, info);
555 if (port)
556 jack_ringbuffer_write(str->new_ports, (char*)&port, sizeof(port));
560 static
561 void update_port(alsa_seqmidi_t *self, snd_seq_addr_t addr, const snd_seq_port_info_t *info)
563 unsigned int port_caps = snd_seq_port_info_get_capability(info);
564 if (port_caps & SND_SEQ_PORT_CAP_NO_EXPORT)
565 return;
566 update_port_type(self, PORT_INPUT, addr, port_caps, info);
567 update_port_type(self, PORT_OUTPUT,addr, port_caps, info);
570 static
571 void free_ports(alsa_seqmidi_t *self, jack_ringbuffer_t *ports)
573 port_t *port;
574 int sz;
575 while ((sz = jack_ringbuffer_read(ports, (char*)&port, sizeof(port)))) {
576 assert (sz == sizeof(port));
577 port_free(self, port);
581 static
582 void update_ports(alsa_seqmidi_t *self)
584 snd_seq_addr_t addr;
585 snd_seq_port_info_t *info;
586 int size;
588 snd_seq_port_info_alloca(&info);
590 while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) {
592 int err;
594 assert (size == sizeof(addr));
595 assert (addr.client != self->client_id);
596 if ((err=snd_seq_get_any_port_info(self->seq, addr.client, addr.port, info))>=0) {
597 update_port(self, addr, info);
598 } else {
599 //port_setdead(self->stream[PORT_INPUT].ports, addr);
600 //port_setdead(self->stream[PORT_OUTPUT].ports, addr);
605 static
606 void* port_thread(void *arg)
608 alsa_seqmidi_t *self = arg;
610 while (self->keep_walking) {
611 sem_wait(&self->port_sem);
612 free_ports(self, self->port_del);
613 update_ports(self);
615 debug_log("port_thread exited");
616 return NULL;
619 static
620 void add_existing_ports(alsa_seqmidi_t *self)
622 snd_seq_addr_t addr;
623 snd_seq_client_info_t *client_info;
624 snd_seq_port_info_t *port_info;
626 snd_seq_client_info_alloca(&client_info);
627 snd_seq_port_info_alloca(&port_info);
628 snd_seq_client_info_set_client(client_info, -1);
629 while (snd_seq_query_next_client(self->seq, client_info) >= 0)
631 addr.client = snd_seq_client_info_get_client(client_info);
632 if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id)
633 continue;
634 snd_seq_port_info_set_client(port_info, addr.client);
635 snd_seq_port_info_set_port(port_info, -1);
636 while (snd_seq_query_next_port(self->seq, port_info) >= 0)
638 addr.port = snd_seq_port_info_get_port(port_info);
639 update_port(self, addr, port_info);
645 * =================== Input/output port handling =========================
647 static
648 void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, jack_nframes_t nframes)
650 const snd_seq_real_time_t* alsa_time;
651 snd_seq_queue_status_t *status;
653 snd_seq_queue_status_alloca(&status);
655 info->dir = dir;
657 info->period_start = jack_last_frame_time(self->jack);
658 info->nframes = nframes;
659 info->sample_rate = jack_get_sample_rate(self->jack);
661 info->cur_frames = jack_frame_time(self->jack);
663 // immediately get alsa'a real time (uhh, why everybody has their own 'real' time)
664 snd_seq_get_queue_status(self->seq, self->queue, status);
665 alsa_time = snd_seq_queue_status_get_real_time(status);
666 info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec;
668 if (info->period_start + info->nframes < info->cur_frames) {
669 int periods_lost = (info->cur_frames - info->period_start) / info->nframes;
670 info->period_start += periods_lost * info->nframes;
671 debug_log("xrun detected: %d periods lost\n", periods_lost);
675 static
676 void add_ports(stream_t *str)
678 port_t *port;
679 while (jack_ringbuffer_read(str->new_ports, (char*)&port, sizeof(port))) {
680 debug_log("jack: inserted port %s\n", port->name);
681 port_insert(str->ports, port);
685 static
686 void jack_process(alsa_seqmidi_t *self, struct process_info *info)
688 stream_t *str = &self->stream[info->dir];
689 port_jack_func process = port_type[info->dir].jack_func;
690 int i, del=0;
692 add_ports(str);
694 // process ports
695 for (i=0; i<PORT_HASH_SIZE; ++i) {
696 port_t **pport = &str->ports[i];
697 while (*pport) {
698 port_t *port = *pport;
699 port->jack_buf = jack_port_get_buffer(port->jack_port, info->nframes);
700 if (info->dir == PORT_INPUT)
701 jack_midi_clear_buffer(port->jack_buf);
703 if (!port->is_dead)
704 (*process)(self, port, info);
705 else if (jack_ringbuffer_write_space(self->port_del) >= sizeof(port)) {
706 debug_log("jack: removed port %s", port->name);
707 *pport = port->next;
708 jack_ringbuffer_write(self->port_del, (char*)&port, sizeof(port));
709 del++;
710 continue;
713 pport = &port->next;
717 if (del)
718 sem_post(&self->port_sem);
722 * ============================ Input ==============================
724 static
725 void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info *info)
727 // process port->early_events
728 alsa_midi_event_t ev;
729 while (jack_ringbuffer_read(port->early_events, (char*)&ev, sizeof(ev))) {
730 jack_midi_data_t* buf;
731 jack_nframes_t time = ev.time - info->period_start;
732 if (time < 0)
733 time = 0;
734 else if (time >= info->nframes)
735 time = info->nframes - 1;
736 buf = jack_midi_event_reserve(port->jack_buf, (jack_nframes_t)time, ev.size);
737 if (buf)
738 jack_ringbuffer_read(port->early_events, (char*)buf, ev.size);
739 else
740 jack_ringbuffer_read_advance(port->early_events, ev.size);
741 debug_log("input: it's time for %d bytes at %lld", ev.size, time);
745 static
746 void port_event(alsa_seqmidi_t *self, snd_seq_event_t *ev)
748 const snd_seq_addr_t addr = ev->data.addr;
750 if (addr.client == self->client_id)
751 return;
753 if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
754 assert (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr));
756 debug_log("port_event: add/change %d:%d", addr.client, addr.port);
757 jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr));
758 sem_post(&self->port_sem);
759 } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
760 debug_log("port_event: del %d:%d", addr.client, addr.port);
761 port_setdead(self->stream[PORT_INPUT].ports, addr);
762 port_setdead(self->stream[PORT_OUTPUT].ports, addr);
766 static
767 void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct process_info* info)
769 jack_midi_data_t data[MAX_EVENT_SIZE];
770 stream_t *str = &self->stream[PORT_INPUT];
771 long size;
772 int64_t alsa_time, time_offset;
773 int64_t frame_offset, event_frame;
774 port_t *port;
776 port = port_get(str->ports, alsa_event->source);
777 if (!port)
778 return;
781 * RPNs, NRPNs, Bank Change, etc. need special handling
782 * but seems, ALSA does it for us already.
784 snd_midi_event_reset_decode(str->codec);
785 if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0)
786 return;
788 // fixup NoteOn with vel 0
789 if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
790 data[0] = 0x80 + (data[0] & 0x0F);
791 data[2] = 0x40;
794 alsa_time = alsa_event->time.time.tv_sec * NSEC_PER_SEC + alsa_event->time.time.tv_nsec;
795 time_offset = info->alsa_time - alsa_time;
796 frame_offset = (info->sample_rate * time_offset) / NSEC_PER_SEC;
797 event_frame = (int64_t)info->cur_frames - info->period_start - frame_offset + info->nframes;
799 debug_log("input: %d bytes at event_frame = %d", (int)size, (int)event_frame);
801 if (event_frame >= info->nframes &&
802 jack_ringbuffer_write_space(port->early_events) >= (sizeof(alsa_midi_event_t) + size)) {
803 alsa_midi_event_t ev;
804 ev.time = event_frame + info->period_start;
805 ev.size = size;
806 jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev));
807 jack_ringbuffer_write(port->early_events, (char*)data, size);
808 debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes));
809 return;
812 if (event_frame < 0)
813 event_frame = 0;
814 else if (event_frame >= info->nframes)
815 event_frame = info->nframes - 1;
817 jack_midi_event_write(port->jack_buf, event_frame, data, size);
820 static
821 void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes)
823 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
824 int res;
825 snd_seq_event_t *event;
826 struct process_info info;
828 if (!self->keep_walking)
829 return;
831 set_process_info(&info, self, PORT_INPUT, nframes);
832 jack_process(self, &info);
834 while ((res = snd_seq_event_input(self->seq, &event))>0) {
835 if (event->source.client == SND_SEQ_CLIENT_SYSTEM)
836 port_event(self, event);
837 else
838 input_event(self, event, &info);
843 * ============================ Output ==============================
846 static
847 void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info)
849 stream_t *str = &self->stream[info->dir];
850 int nevents = jack_midi_get_event_count(port->jack_buf);
851 int i;
852 for (i=0; i<nevents; ++i) {
853 jack_midi_event_t jack_event;
854 snd_seq_event_t alsa_event;
855 int64_t frame_offset;
856 int64_t out_time;
857 snd_seq_real_time_t out_rt;
858 int err;
860 jack_midi_event_get(&jack_event, port->jack_buf, i);
862 snd_seq_ev_clear(&alsa_event);
863 snd_midi_event_reset_encode(str->codec);
864 if (!snd_midi_event_encode(str->codec, jack_event.buffer, jack_event.size, &alsa_event))
865 continue; // invalid event
867 snd_seq_ev_set_source(&alsa_event, self->port_id);
868 snd_seq_ev_set_dest(&alsa_event, port->remote.client, port->remote.port);
870 /* NOTE: in case of xrun it could become negative, so it is essential to use signed type! */
871 frame_offset = (int64_t)jack_event.time + info->period_start + info->nframes - info->cur_frames;
872 if (frame_offset < 0) {
873 frame_offset = info->nframes + jack_event.time;
874 error_log("internal xrun detected: frame_offset = %"PRId64"\n", frame_offset);
876 /* Ken Ellinwood reported problems with this assert.
877 * Seems, magic 2 should be replaced with nperiods. */
878 //FIXME: assert (frame_offset < info->nframes*2);
879 //if (frame_offset < info->nframes * info->nperiods)
880 // debug_log("alsa_out: BLAH-BLAH-BLAH");
882 out_time = info->alsa_time + (frame_offset * NSEC_PER_SEC) / info->sample_rate;
884 debug_log("alsa_out: frame_offset = %lld, info->alsa_time = %lld, out_time = %lld, port->last_out_time = %lld",
885 frame_offset, info->alsa_time, out_time, port->last_out_time);
887 // we should use absolute time to prevent reordering caused by rounding errors
888 if (out_time < port->last_out_time) {
889 debug_log("alsa_out: limiting out_time %lld at %lld", out_time, port->last_out_time);
890 out_time = port->last_out_time;
891 } else
892 port->last_out_time = out_time;
894 out_rt.tv_nsec = out_time % NSEC_PER_SEC;
895 out_rt.tv_sec = out_time / NSEC_PER_SEC;
896 snd_seq_ev_schedule_real(&alsa_event, self->queue, 0, &out_rt);
898 err = snd_seq_event_output(self->seq, &alsa_event);
899 debug_log("alsa_out: written %d bytes to %s at %+d (%lld): %d", (int)jack_event.size, port->name, (int)frame_offset, out_time, err);
903 static
904 void alsa_seqmidi_write(alsa_midi_t *m, jack_nframes_t nframes)
906 alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
907 struct process_info info;
909 if (!self->keep_walking)
910 return;
912 set_process_info(&info, self, PORT_OUTPUT, nframes);
913 jack_process(self, &info);
914 snd_seq_drain_output(self->seq);