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
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
31 * remove dead ports and send them to port_thread
38 * create new ports or mark existing as dead
41 #include <alsa/asoundlib.h>
46 #include <semaphore.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)
60 MAX_EVENT_SIZE
= 1024,
63 typedef struct port_t port_t
;
67 PORT_HASH_SIZE
= 1 << PORT_HASH_BITS
70 typedef port_t
* port_hash_t
[PORT_HASH_SIZE
];
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
;
86 snd_midi_event_t
*codec
;
88 jack_ringbuffer_t
*new_ports
;
90 port_t
*ports
[MAX_PORTS
];
93 typedef struct alsa_seqmidi
{
104 pthread_t port_thread
;
106 jack_ringbuffer_t
*port_add
; // snd_seq_addr_t
107 jack_ringbuffer_t
*port_del
; // port_t*
116 struct alsa_midi_event
{
120 typedef struct alsa_midi_event alsa_midi_event_t
;
122 struct process_info
{
124 jack_nframes_t nframes
;
125 jack_nframes_t period_start
;
126 jack_nframes_t sample_rate
;
127 jack_nframes_t cur_frames
;
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
);
141 port_jack_func jack_func
;
144 static port_type_t port_type
[2] = {
146 SND_SEQ_PORT_CAP_SUBS_READ
,
152 SND_SEQ_PORT_CAP_SUBS_WRITE
,
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
);
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
);
180 void stream_attach(alsa_seqmidi_t
*self
, int dir
)
185 void stream_detach(alsa_seqmidi_t
*self
, int dir
)
187 stream_t
*str
= &self
->stream
[dir
];
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
];
196 port_t
*next
= port
->next
;
197 port_free(self
, port
);
200 str
->ports
[i
] = NULL
;
205 void stream_close(alsa_seqmidi_t
*self
, int dir
)
207 stream_t
*str
= &self
->stream
[dir
];
210 snd_midi_event_free(str
->codec
);
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");
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
;
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
);
264 int alsa_seqmidi_attach(alsa_midi_t
*m
)
266 alsa_seqmidi_t
*self
= (alsa_seqmidi_t
*) m
;
269 debug_log("midi: attach");
274 if ((err
= snd_seq_open(&self
->seq
, "hw", SND_SEQ_OPEN_DUPLEX
, 0)) < 0) {
275 error_log("failed to open alsa seq");
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
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);
299 int alsa_seqmidi_detach(alsa_midi_t
*m
)
301 alsa_seqmidi_t
*self
= (alsa_seqmidi_t
*) m
;
303 debug_log("midi: detach");
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
);
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
);
329 int alsa_seqmidi_start(alsa_midi_t
*m
)
331 alsa_seqmidi_t
*self
= (alsa_seqmidi_t
*) m
;
334 debug_log("midi: start");
339 if (self
->keep_walking
)
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
);
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;
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
)
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;
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
;
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
));
406 * ==================== Port routines =============================
409 int port_hash(snd_seq_addr_t addr
)
411 return (addr
.client
+ addr
.port
) % PORT_HASH_SIZE
;
415 port_t
* port_get(port_hash_t hash
, snd_seq_addr_t addr
)
417 port_t
**pport
= &hash
[port_hash(addr
)];
419 port_t
*port
= *pport
;
420 if (port
->remote
.client
== addr
.client
&& port
->remote
.port
== addr
.port
)
428 void port_insert(port_hash_t hash
, port_t
*port
)
430 port_t
**pport
= &hash
[port_hash(port
->remote
)];
436 void port_setdead(port_hash_t hash
, snd_seq_addr_t addr
)
438 port_t
*port
= port_get(hash
, addr
);
440 port
->is_dead
= 1; // see jack_process
442 debug_log("port_setdead: not found (%d:%d)", addr
.client
, addr
.port
);
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
);
453 jack_port_unregister(self
->jack
, port
->jack_port
);
454 info_log("port deleted: %s", port
->name
);
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
;
469 port
= calloc(1, sizeof(port_t
));
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
!= ')')
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
);
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
)
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
!= ')')
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
);
521 err
= snd_seq_connect_to(self
->seq
, self
->port_id
, port
->remote
.client
, port
->remote
.port
);
525 port
->early_events
= jack_ringbuffer_create(MAX_EVENT_SIZE
*16);
527 info_log("port created: %s", port
->name
);
531 port_free(self
, port
);
536 * ==================== Port add/del handling thread ==============================
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
);
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
);
556 jack_ringbuffer_write(str
->new_ports
, (char*)&port
, sizeof(port
));
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
)
566 update_port_type(self
, PORT_INPUT
, addr
, port_caps
, info
);
567 update_port_type(self
, PORT_OUTPUT
,addr
, port_caps
, info
);
571 void free_ports(alsa_seqmidi_t
*self
, jack_ringbuffer_t
*ports
)
575 while ((sz
= jack_ringbuffer_read(ports
, (char*)&port
, sizeof(port
)))) {
576 assert (sz
== sizeof(port
));
577 port_free(self
, port
);
582 void update_ports(alsa_seqmidi_t
*self
)
585 snd_seq_port_info_t
*info
;
588 snd_seq_port_info_alloca(&info
);
590 while ((size
= jack_ringbuffer_read(self
->port_add
, (char*)&addr
, sizeof(addr
)))) {
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
);
599 //port_setdead(self->stream[PORT_INPUT].ports, addr);
600 //port_setdead(self->stream[PORT_OUTPUT].ports, addr);
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
);
615 debug_log("port_thread exited");
620 void add_existing_ports(alsa_seqmidi_t
*self
)
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
)
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 =========================
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
);
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
);
676 void add_ports(stream_t
*str
)
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
);
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
;
695 for (i
=0; i
<PORT_HASH_SIZE
; ++i
) {
696 port_t
**pport
= &str
->ports
[i
];
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
);
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
);
708 jack_ringbuffer_write(self
->port_del
, (char*)&port
, sizeof(port
));
718 sem_post(&self
->port_sem
);
722 * ============================ Input ==============================
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
;
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
);
738 jack_ringbuffer_read(port
->early_events
, (char*)buf
, ev
.size
);
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
);
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
)
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
);
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
];
772 int64_t alsa_time
, time_offset
;
773 int64_t frame_offset
, event_frame
;
776 port
= port_get(str
->ports
, alsa_event
->source
);
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)
788 // fixup NoteOn with vel 0
789 if ((data
[0] & 0xF0) == 0x90 && data
[2] == 0x00) {
790 data
[0] = 0x80 + (data
[0] & 0x0F);
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
;
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
));
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
);
821 void alsa_seqmidi_read(alsa_midi_t
*m
, jack_nframes_t nframes
)
823 alsa_seqmidi_t
*self
= (alsa_seqmidi_t
*) m
;
825 snd_seq_event_t
*event
;
826 struct process_info info
;
828 if (!self
->keep_walking
)
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
);
838 input_event(self
, event
, &info
);
843 * ============================ Output ==============================
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
);
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
;
857 snd_seq_real_time_t out_rt
;
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
;
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
);
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
)
912 set_process_info(&info
, self
, PORT_OUTPUT
, nframes
);
913 jack_process(self
, &info
);
914 snd_seq_drain_output(self
->seq
);