website/index.html: Extend Feedback section (codeberg.org)
[a2jmidid.git] / jack.c
bloba7a6803b224d08781bc538b8cb2968578e400b5c
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
6 * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdbool.h>
23 #include <time.h>
24 #include <alsa/asoundlib.h>
25 #include <jack/jack.h>
26 #include <jack/midiport.h>
27 #include <jack/ringbuffer.h>
29 #include "list.h"
30 #include "structs.h"
31 #include "jack.h"
32 #include "log.h"
33 #include "port_hash.h"
34 #include "port.h"
35 #include "a2jmidid.h"
36 #include "port_thread.h"
38 static bool g_freewheeling = false;
39 extern bool g_filter_note_on;
42 * =================== Input/output port handling =========================
45 void a2j_add_ports(struct a2j_stream * str)
47 struct a2j_port * port_ptr;
48 while (jack_ringbuffer_read(str->new_ports, (char *)&port_ptr, sizeof(port_ptr)))
50 a2j_debug("jack: inserted port %s", port_ptr->name);
51 a2j_port_insert(str->port_hash, port_ptr);
56 * ============================ Input ==============================
58 void
59 a2j_process_incoming (
60 struct a2j * self,
61 struct a2j_port * port,
62 jack_nframes_t nframes)
64 struct a2j_alsa_midi_event ev;
65 //jack_nframes_t now;
66 jack_nframes_t one_period;
67 char *ev_buf;
69 ((void)(nframes)); /* unreferenced parameter */
71 /* grab data queued by the ALSA input thread and write it into the JACK
72 port buffer. it will delivered during the JACK period that this
73 function is called from.
76 /* first clear the JACK port buffer in preparation for new data
79 // a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port));
81 jack_midi_clear_buffer (port->jack_buf);
83 /* now = */jack_frame_time (self->jack_client);
84 one_period = jack_get_buffer_size (self->jack_client);
86 while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
88 jack_midi_data_t* buf;
89 jack_nframes_t offset;
91 if (ev.time >= self->cycle_start) {
92 break;
95 //jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev));
96 ev_buf = (char *) alloca( sizeof(ev) + ev.size );
98 if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size)
99 break;
101 offset = self->cycle_start - ev.time;
102 if (offset > one_period) {
103 /* from a previous cycle, somehow. cram it in at the front */
104 offset = 0;
105 } else {
106 /* offset from start of the current cycle */
107 offset = one_period - offset;
110 a2j_debug ("event at %d offset %d", ev.time, offset);
112 /* make sure there is space for it */
114 buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size);
116 if (buf) {
117 /* grab the event */
118 memcpy( buf, ev_buf + sizeof(ev), ev.size );
119 } else {
120 /* throw it away (no space) */
121 a2j_error ("threw away MIDI event - not reserved at time %d", ev.time);
123 jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size);
125 a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time);
129 static
130 void
131 a2j_port_event(
132 struct a2j * self,
133 snd_seq_event_t * ev)
135 const snd_seq_addr_t addr = ev->data.addr;
137 if (addr.client == self->client_id)
138 return;
140 if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
141 if (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr)) {
142 a2j_debug("port_event: add/change %d:%d", addr.client, addr.port);
143 jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr));
144 } else {
145 a2j_error("dropping port_event: add/change %d:%d", addr.client, addr.port);
147 } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
148 a2j_debug("port_event: del %d:%d", addr.client, addr.port);
149 a2j_port_setdead(self->stream[A2J_PORT_CAPTURE].port_hash, addr);
150 a2j_port_setdead(self->stream[A2J_PORT_PLAYBACK].port_hash, addr);
154 static
155 void
156 a2j_input_event(
157 struct a2j * self,
158 snd_seq_event_t * alsa_event)
160 jack_midi_data_t data[MAX_EVENT_SIZE];
161 struct a2j_stream *str = &self->stream[A2J_PORT_CAPTURE];
162 long size;
163 struct a2j_port *port;
164 jack_nframes_t now;
166 now = jack_frame_time (self->jack_client);
168 if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) {
169 return;
173 * RPNs, NRPNs, Bank Change, etc. need special handling
174 * but seems, ALSA does it for us already.
176 snd_midi_event_reset_decode(str->codec);
177 if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) {
178 return;
181 // fixup NoteOn with vel 0
182 if (g_filter_note_on && (data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
183 data[0] = 0x80 + (data[0] & 0x0F);
184 data[2] = 0x40;
187 a2j_debug("input: %d bytes at event_frame=%u", (int)size, now);
189 if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) {
190 struct a2j_alsa_midi_event ev;
191 char *ev_charp = (char*) &ev;
192 size_t limit;
193 size_t to_write = sizeof(ev);
195 jack_ringbuffer_data_t vec[2];
196 jack_ringbuffer_get_write_vector( port->inbound_events, vec );
197 ev.time = now;
198 ev.size = size;
201 limit = (to_write > vec[0].len ? vec[0].len : to_write);
202 if( limit ) {
203 memcpy( vec[0].buf, ev_charp, limit );
204 to_write -= limit;
205 ev_charp += limit;
206 vec[0].buf += limit;
207 vec[0].len -= limit;
209 if( to_write ) {
210 memcpy( vec[1].buf, ev_charp, to_write );
211 vec[1].buf += to_write;
212 vec[1].len -= to_write;
215 to_write = size;
216 ev_charp = (char *)data;
217 limit = (to_write > vec[0].len ? vec[0].len : to_write);
218 if( limit )
219 memcpy( vec[0].buf, ev_charp, limit );
220 to_write -= limit;
221 ev_charp += limit;
222 if( to_write )
223 memcpy( vec[1].buf, ev_charp, to_write );
225 jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size );
226 } else {
227 a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size);
233 * ============================ Output ==============================
237 a2j_process_outgoing (
238 struct a2j * self,
239 struct a2j_port * port)
241 /* collect data from JACK port buffer and queue it for later delivery by ALSA output thread */
243 int nevents;
244 jack_ringbuffer_data_t vec[2];
245 int i;
246 size_t written = 0;
247 size_t limit;
248 struct a2j_delivery_event* dev;
249 size_t gap = 0;
251 jack_ringbuffer_get_write_vector (self->outbound_events, vec);
253 dev = (struct a2j_delivery_event*) vec[0].buf;
254 limit = vec[0].len / sizeof (struct a2j_delivery_event);
255 nevents = jack_midi_get_event_count (port->jack_buf);
257 for (i = 0; (i < nevents) && (written < limit); ++i) {
259 jack_midi_event_get (&dev->jack_event, port->jack_buf, i);
260 if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE)
262 dev->time = dev->jack_event.time;
263 dev->port = port;
264 memcpy( dev->midistring, dev->jack_event.buffer, dev->jack_event.size );
265 written++;
266 ++dev;
270 /* anything left? use the second part of the vector, as much as possible */
272 if (i < nevents)
274 if (vec[0].len)
276 gap = vec[0].len - written * sizeof(struct a2j_delivery_event);
279 dev = (struct a2j_delivery_event*) vec[1].buf;
281 limit += (vec[1].len / sizeof (struct a2j_delivery_event));
283 while ((i < nevents) && (written < limit))
285 jack_midi_event_get(&dev->jack_event, port->jack_buf, i);
286 if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE)
288 dev->time = dev->jack_event.time;
289 dev->port = port;
290 memcpy(dev->midistring, dev->jack_event.buffer, dev->jack_event.size);
291 written++;
292 ++dev;
294 ++i;
298 a2j_debug( "done pushing events: %d ... gap: %d ", (int)written, (int)gap );
299 /* clear JACK port buffer; advance ring buffer ptr */
301 jack_ringbuffer_write_advance (self->outbound_events, written * sizeof (struct a2j_delivery_event) + gap);
303 return nevents;
306 static int
307 time_sorter (struct a2j_delivery_event * a, struct a2j_delivery_event * b)
309 if (a->time < b->time) {
310 return -1;
311 } else if (a->time > b->time) {
312 return 1;
314 return 0;
317 void * a2j_alsa_output_thread(void * arg)
319 struct a2j * self = (struct a2j*) arg;
320 struct a2j_stream *str = &self->stream[A2J_PORT_PLAYBACK];
321 int i;
322 struct list_head evlist;
323 struct list_head * node_ptr;
324 jack_ringbuffer_data_t vec[2];
325 snd_seq_event_t alsa_event;
326 struct a2j_delivery_event* ev;
327 float sr;
328 jack_nframes_t now;
329 //int err;
330 int limit;
332 while (g_keep_alsa_walking) {
333 /* first, make a list of all events in the outbound_events FIFO */
335 INIT_LIST_HEAD(&evlist);
337 jack_ringbuffer_get_read_vector (self->outbound_events, vec);
339 a2j_debug ("output thread: got %d+%d events",
340 (vec[0].len / sizeof (struct a2j_delivery_event)),
341 (vec[1].len / sizeof (struct a2j_delivery_event)));
343 ev = (struct a2j_delivery_event*) vec[0].buf;
344 limit = vec[0].len / sizeof (struct a2j_delivery_event);
345 for (i = 0; i < limit; ++i) {
346 list_add_tail(&ev->siblings, &evlist);
347 ev++;
350 ev = (struct a2j_delivery_event*) vec[1].buf;
351 limit = vec[1].len / sizeof (struct a2j_delivery_event);
352 for (i = 0; i < limit; ++i) {
353 list_add_tail(&ev->siblings, &evlist);
354 ev++;
357 if (vec[0].len < sizeof(struct a2j_delivery_event) && (vec[1].len == 0)) {
358 /* no events: wait for some */
359 a2j_debug ("output thread: wait for events");
360 sem_wait (&self->io_semaphore);
361 a2j_debug ("output thread: AWAKE ... loop back for events");
362 continue;
365 /* now sort this list by time */
367 list_sort(&evlist, struct a2j_delivery_event, siblings, time_sorter);
369 /* now deliver */
371 sr = jack_get_sample_rate (self->jack_client);
373 list_for_each(node_ptr, &evlist)
375 ev = list_entry(node_ptr, struct a2j_delivery_event, siblings);
377 snd_seq_ev_clear(&alsa_event);
378 snd_midi_event_reset_encode(str->codec);
379 if (!snd_midi_event_encode(str->codec, (const unsigned char *)ev->midistring, ev->jack_event.size, &alsa_event))
381 continue; // invalid event
384 snd_seq_ev_set_source(&alsa_event, self->port_id);
385 snd_seq_ev_set_dest(&alsa_event, ev->port->remote.client, ev->port->remote.port);
386 snd_seq_ev_set_direct (&alsa_event);
388 now = jack_frame_time (self->jack_client);
390 ev->time += self->cycle_start;
392 a2j_debug ("@ %d, next event @ %d", now, ev->time);
394 /* do we need to wait a while before delivering? */
396 if (ev->time > now) {
397 struct timespec nanoseconds;
398 jack_nframes_t sleep_frames = ev->time - now;
399 float seconds = sleep_frames / sr;
401 /* if the gap is long enough, sleep */
403 if (seconds > 0.001) {
404 nanoseconds.tv_sec = (time_t) seconds;
405 nanoseconds.tv_nsec = (long) NSEC_PER_SEC * (seconds - nanoseconds.tv_sec);
407 a2j_debug ("output thread sleeps for %.2f msec", ((double) nanoseconds.tv_nsec / NSEC_PER_SEC) * 1000.0);
409 if (nanosleep (&nanoseconds, NULL) < 0) {
410 fprintf (stderr, "BAD SLEEP\n");
411 /* do something ? */
416 /* its time to deliver */
417 /* err = */snd_seq_event_output(self->seq, &alsa_event);
418 snd_seq_drain_output (self->seq);
419 now = jack_frame_time (self->jack_client);
420 a2j_debug("alsa_out: written %d bytes to %s at %d, DELTA = %d", ev->jack_event.size, ev->port->name, now,
421 (int32_t) (now - ev->time));
424 /* free up space in the FIFO */
426 jack_ringbuffer_read_advance (self->outbound_events, vec[0].len + vec[1].len);
428 /* and head back for more */
431 return (void*) 0;
434 #define a2j_ptr ((struct a2j *)arg)
436 /* ALSA */
438 void * a2j_alsa_input_thread(void * arg)
440 struct a2j * self = arg;
441 int npfd;
442 struct pollfd * pfd;
443 snd_seq_addr_t addr;
444 snd_seq_client_info_t * client_info;
445 snd_seq_port_info_t * port_info;
446 bool initial;
447 snd_seq_event_t * event;
448 int ret;
450 npfd = snd_seq_poll_descriptors_count(self->seq, POLLIN);
451 pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
452 snd_seq_poll_descriptors(self->seq, pfd, npfd, POLLIN);
454 initial = true;
455 while (g_keep_alsa_walking)
457 if ((ret = poll(pfd, npfd, 1000)) > 0)
460 while (snd_seq_event_input (self->seq, &event) > 0)
462 if (initial)
464 snd_seq_client_info_alloca(&client_info);
465 snd_seq_port_info_alloca(&port_info);
466 snd_seq_client_info_set_client(client_info, -1);
467 while (snd_seq_query_next_client(self->seq, client_info) >= 0)
469 addr.client = snd_seq_client_info_get_client(client_info);
470 if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id)
471 continue;
472 snd_seq_port_info_set_client(port_info, addr.client);
473 snd_seq_port_info_set_port(port_info, -1);
474 while (snd_seq_query_next_port(self->seq, port_info) >= 0)
476 addr.port = snd_seq_port_info_get_port(port_info);
477 a2j_update_port(self, addr, port_info);
481 initial = false;
484 if (event->source.client == SND_SEQ_CLIENT_SYSTEM)
486 a2j_port_event(a2j_ptr, event);
488 else
490 a2j_input_event(a2j_ptr, event);
493 snd_seq_free_event (event);
498 return (void*) 0;
502 /* JACK */
504 static
505 void
506 a2j_jack_process_internal(
507 struct a2j * self,
508 int dir,
509 jack_nframes_t nframes)
511 struct a2j_stream * stream_ptr;
512 int i;
513 struct a2j_port ** port_ptr_ptr;
514 struct a2j_port * port_ptr;
515 int nevents = 0;
517 stream_ptr = &self->stream[dir];
518 a2j_add_ports(stream_ptr);
520 // process ports
521 for (i = 0 ; i < PORT_HASH_SIZE ; i++)
523 port_ptr_ptr = &stream_ptr->port_hash[i];
524 while (*port_ptr_ptr != NULL)
526 port_ptr = *port_ptr_ptr;
528 if (!port_ptr->is_dead)
530 port_ptr->jack_buf = jack_port_get_buffer(port_ptr->jack_port, nframes);
532 if (dir == A2J_PORT_CAPTURE) {
533 a2j_process_incoming (self, port_ptr, nframes);
534 } else {
535 nevents += a2j_process_outgoing (self, port_ptr);
538 } else if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) {
540 a2j_debug("jack: removed port %s", port_ptr->name);
541 *port_ptr_ptr = port_ptr->next;
542 jack_ringbuffer_write(self->port_del, (char*)&port_ptr, sizeof(port_ptr));
543 continue;
547 port_ptr_ptr = &port_ptr->next;
551 /* if we queued up anything for output, tell the output thread in
552 case its waiting for us.
555 if (nevents > 0) {
556 int sv;
557 sem_getvalue (&self->io_semaphore, &sv);
558 sem_post (&self->io_semaphore);
562 static
564 a2j_jack_process(
565 jack_nframes_t nframes,
566 void * arg)
568 struct a2j* self = (struct a2j *) arg;
570 if (g_freewheeling)
571 return 0;
573 self->cycle_start = jack_last_frame_time (self->jack_client);
575 a2j_jack_process_internal (self, A2J_PORT_CAPTURE, nframes);
576 a2j_jack_process_internal (self, A2J_PORT_PLAYBACK, nframes);
578 return 0;
581 static
582 void
583 a2j_jack_freewheel(
584 int starting,
585 void * arg)
587 ((void)(arg)); /* unreferenced parameter */
588 g_freewheeling = starting;
591 static
592 void
593 a2j_jack_shutdown(
594 void * arg)
596 ((void)(arg)); /* unreferenced parameter */
597 a2j_warning("JACK server shutdown notification received.");
598 g_stop_request = true;
601 #undef a2j_ptr
603 jack_client_t *
604 a2j_jack_client_create(
605 struct a2j * a2j_ptr,
606 const char * client_name,
607 const char * server_name)
609 jack_status_t status;
610 jack_client_t * jack_client;
612 if (server_name != NULL)
614 jack_client = jack_client_open(client_name, JackServerName|JackNoStartServer|JackUseExactName, &status, server_name);
616 else
618 jack_client = jack_client_open(client_name, JackNoStartServer|JackUseExactName, &status);
621 if (!jack_client)
623 a2j_error("Cannot create jack client");
624 return NULL;
627 jack_set_process_callback(jack_client, a2j_jack_process, a2j_ptr);
628 jack_set_freewheel_callback(jack_client, a2j_jack_freewheel, NULL);
629 jack_on_shutdown(jack_client, a2j_jack_shutdown, NULL);
631 return jack_client;