jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

875 lines
22KB

  1. /*
  2. * ALSA SEQ < - > JACK MIDI bridge
  3. *
  4. * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
  5. *
  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.
  10. *
  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.
  15. *
  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
  19. */
  20. /*
  21. * alsa_seqmidi_read:
  22. * add new ports
  23. * reads queued snd_seq_event's
  24. * if PORT_EXIT: mark port as dead
  25. * if PORT_ADD, PORT_CHANGE: send addr to port_thread (it also may mark port as dead)
  26. * else process input event
  27. * remove dead ports and send them to port_thread
  28. *
  29. * alsa_seqmidi_write:
  30. * remove dead ports and send them to port_thread
  31. * add new ports
  32. * queue output events
  33. *
  34. * port_thread:
  35. * wait for port_sem
  36. * free deleted ports
  37. * create new ports or mark existing as dead
  38. */
  39. #if defined(HAVE_CONFIG_H)
  40. #include "config.h"
  41. #endif
  42. #include <alsa/asoundlib.h>
  43. #include <jack/midiport.h>
  44. #include <jack/ringbuffer.h>
  45. #include <stdlib.h>
  46. #include <stdio.h>
  47. #include <signal.h>
  48. #include <semaphore.h>
  49. #include <pthread.h>
  50. #include <time.h>
  51. #include <ctype.h>
  52. #include "alsa_midi_impl.h"
  53. #include "JackError.h"
  54. #define NSEC_PER_SEC ((int64_t)1000*1000*1000)
  55. enum {
  56. MAX_PORTS = 64,
  57. MAX_EVENT_SIZE = 1024,
  58. };
  59. typedef struct port_t port_t;
  60. enum {
  61. PORT_HASH_BITS = 4,
  62. PORT_HASH_SIZE = 1 << PORT_HASH_BITS
  63. };
  64. typedef port_t* port_hash_t[PORT_HASH_SIZE];
  65. struct port_t {
  66. port_t *next;
  67. int is_dead;
  68. char name[64];
  69. snd_seq_addr_t remote;
  70. jack_port_t *jack_port;
  71. jack_ringbuffer_t *early_events; // alsa_midi_event_t + data
  72. int64_t last_out_time;
  73. void *jack_buf;
  74. };
  75. typedef struct {
  76. snd_midi_event_t *codec;
  77. jack_ringbuffer_t *new_ports;
  78. port_t *ports[MAX_PORTS];
  79. } stream_t;
  80. typedef struct alsa_seqmidi {
  81. alsa_midi_t ops;
  82. jack_client_t *jack;
  83. snd_seq_t *seq;
  84. int client_id;
  85. int port_id;
  86. int queue;
  87. int keep_walking;
  88. pthread_t port_thread;
  89. sem_t port_sem;
  90. jack_ringbuffer_t *port_add; // snd_seq_addr_t
  91. jack_ringbuffer_t *port_del; // port_t*
  92. stream_t stream[2];
  93. char alsa_name[32];
  94. int midi_in_cnt;
  95. int midi_out_cnt;
  96. } alsa_seqmidi_t;
  97. struct alsa_midi_event {
  98. int64_t time;
  99. int size;
  100. };
  101. typedef struct alsa_midi_event alsa_midi_event_t;
  102. struct process_info {
  103. int dir;
  104. int64_t nframes;
  105. int64_t period_start;
  106. uint32_t sample_rate;
  107. int64_t cur_frames;
  108. int64_t alsa_time;
  109. };
  110. enum PortType { PORT_INPUT = 0, PORT_OUTPUT = 1 };
  111. typedef void (*port_jack_func)(alsa_seqmidi_t *self, port_t *port,struct process_info* info);
  112. static void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info* info);
  113. static void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info);
  114. typedef struct {
  115. int alsa_mask;
  116. int jack_caps;
  117. char name[4];
  118. port_jack_func jack_func;
  119. } port_type_t;
  120. static port_type_t port_type[2] = {
  121. {
  122. SND_SEQ_PORT_CAP_SUBS_READ,
  123. JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal,
  124. "in",
  125. do_jack_input
  126. },
  127. {
  128. SND_SEQ_PORT_CAP_SUBS_WRITE,
  129. JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal,
  130. "out",
  131. do_jack_output
  132. }
  133. };
  134. static void alsa_seqmidi_delete(alsa_midi_t *m);
  135. static int alsa_seqmidi_attach(alsa_midi_t *m);
  136. static int alsa_seqmidi_detach(alsa_midi_t *m);
  137. static int alsa_seqmidi_start(alsa_midi_t *m);
  138. static int alsa_seqmidi_stop(alsa_midi_t *m);
  139. static void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes);
  140. static void alsa_seqmidi_write(alsa_midi_t *m, jack_nframes_t nframes);
  141. static
  142. void stream_init(alsa_seqmidi_t *self, int dir)
  143. {
  144. stream_t *str = &self->stream[dir];
  145. str->new_ports = jack_ringbuffer_create(MAX_PORTS*sizeof(port_t*));
  146. snd_midi_event_new(MAX_EVENT_SIZE, &str->codec);
  147. }
  148. static void port_free(alsa_seqmidi_t *self, port_t *port);
  149. static void free_ports(alsa_seqmidi_t *self, jack_ringbuffer_t *ports);
  150. static
  151. void stream_attach(alsa_seqmidi_t *self, int dir)
  152. {
  153. }
  154. static
  155. void stream_detach(alsa_seqmidi_t *self, int dir)
  156. {
  157. stream_t *str = &self->stream[dir];
  158. int i;
  159. free_ports(self, str->new_ports);
  160. // delete all ports from hash
  161. for (i=0; i<PORT_HASH_SIZE; ++i) {
  162. port_t *port = str->ports[i];
  163. while (port) {
  164. port_t *next = port->next;
  165. port_free(self, port);
  166. port = next;
  167. }
  168. str->ports[i] = NULL;
  169. }
  170. }
  171. static
  172. void stream_close(alsa_seqmidi_t *self, int dir)
  173. {
  174. stream_t *str = &self->stream[dir];
  175. if (str->codec)
  176. snd_midi_event_free(str->codec);
  177. if (str->new_ports)
  178. jack_ringbuffer_free(str->new_ports);
  179. }
  180. alsa_midi_t* alsa_seqmidi_new(jack_client_t *client, const char* alsa_name)
  181. {
  182. alsa_seqmidi_t *self = calloc(1, sizeof(alsa_seqmidi_t));
  183. debug_log("midi: new");
  184. if (!self)
  185. return NULL;
  186. self->jack = client;
  187. if (!alsa_name)
  188. alsa_name = "jack_midi";
  189. snprintf(self->alsa_name, sizeof(self->alsa_name), "%s", alsa_name);
  190. self->port_add = jack_ringbuffer_create(2*MAX_PORTS*sizeof(snd_seq_addr_t));
  191. self->port_del = jack_ringbuffer_create(2*MAX_PORTS*sizeof(port_t*));
  192. sem_init(&self->port_sem, 0, 0);
  193. stream_init(self, PORT_INPUT);
  194. stream_init(self, PORT_OUTPUT);
  195. self->midi_in_cnt = 0;
  196. self->midi_out_cnt = 0;
  197. self->ops.destroy = alsa_seqmidi_delete;
  198. self->ops.attach = alsa_seqmidi_attach;
  199. self->ops.detach = alsa_seqmidi_detach;
  200. self->ops.start = alsa_seqmidi_start;
  201. self->ops.stop = alsa_seqmidi_stop;
  202. self->ops.read = alsa_seqmidi_read;
  203. self->ops.write = alsa_seqmidi_write;
  204. return &self->ops;
  205. }
  206. static
  207. void alsa_seqmidi_delete(alsa_midi_t *m)
  208. {
  209. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  210. debug_log("midi: delete");
  211. alsa_seqmidi_detach(m);
  212. stream_close(self, PORT_OUTPUT);
  213. stream_close(self, PORT_INPUT);
  214. jack_ringbuffer_free(self->port_add);
  215. jack_ringbuffer_free(self->port_del);
  216. sem_close(&self->port_sem);
  217. free(self);
  218. }
  219. static
  220. int alsa_seqmidi_attach(alsa_midi_t *m)
  221. {
  222. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  223. int err;
  224. debug_log("midi: attach");
  225. if (self->seq)
  226. return -EALREADY;
  227. if ((err = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
  228. error_log("failed to open alsa seq");
  229. return err;
  230. }
  231. snd_seq_set_client_name(self->seq, self->alsa_name);
  232. self->port_id = snd_seq_create_simple_port(self->seq, "port",
  233. SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
  234. #ifndef DEBUG
  235. |SND_SEQ_PORT_CAP_NO_EXPORT
  236. #endif
  237. ,SND_SEQ_PORT_TYPE_APPLICATION);
  238. self->client_id = snd_seq_client_id(self->seq);
  239. self->queue = snd_seq_alloc_queue(self->seq);
  240. snd_seq_start_queue(self->seq, self->queue, 0);
  241. stream_attach(self, PORT_INPUT);
  242. stream_attach(self, PORT_OUTPUT);
  243. snd_seq_nonblock(self->seq, 1);
  244. return 0;
  245. }
  246. static
  247. int alsa_seqmidi_detach(alsa_midi_t *m)
  248. {
  249. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  250. debug_log("midi: detach");
  251. if (!self->seq)
  252. return -EALREADY;
  253. alsa_seqmidi_stop(m);
  254. jack_ringbuffer_reset(self->port_add);
  255. free_ports(self, self->port_del);
  256. stream_detach(self, PORT_INPUT);
  257. stream_detach(self, PORT_OUTPUT);
  258. snd_seq_close(self->seq);
  259. self->seq = NULL;
  260. return 0;
  261. }
  262. static void* port_thread(void *);
  263. static void add_existing_ports(alsa_seqmidi_t *self);
  264. static void update_ports(alsa_seqmidi_t *self);
  265. static void add_ports(stream_t *str);
  266. static
  267. int alsa_seqmidi_start(alsa_midi_t *m)
  268. {
  269. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  270. int err;
  271. debug_log("midi: start");
  272. if (!self->seq)
  273. return -EBADF;
  274. if (self->keep_walking)
  275. return -EALREADY;
  276. snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
  277. snd_seq_drop_input(self->seq);
  278. add_existing_ports(self);
  279. update_ports(self);
  280. add_ports(&self->stream[PORT_INPUT]);
  281. add_ports(&self->stream[PORT_OUTPUT]);
  282. self->keep_walking = 1;
  283. if ((err = pthread_create(&self->port_thread, NULL, port_thread, self))) {
  284. self->keep_walking = 0;
  285. return -errno;
  286. }
  287. return 0;
  288. }
  289. static
  290. int alsa_seqmidi_stop(alsa_midi_t *m)
  291. {
  292. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  293. debug_log("midi: stop");
  294. if (!self->keep_walking)
  295. return -EALREADY;
  296. snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
  297. self->keep_walking = 0;
  298. sem_post(&self->port_sem);
  299. pthread_join(self->port_thread, NULL);
  300. self->port_thread = 0;
  301. return 0;
  302. }
  303. static
  304. int alsa_connect_from(alsa_seqmidi_t *self, int client, int port)
  305. {
  306. snd_seq_port_subscribe_t* sub;
  307. snd_seq_addr_t seq_addr;
  308. int err;
  309. snd_seq_port_subscribe_alloca(&sub);
  310. seq_addr.client = client;
  311. seq_addr.port = port;
  312. snd_seq_port_subscribe_set_sender(sub, &seq_addr);
  313. seq_addr.client = self->client_id;
  314. seq_addr.port = self->port_id;
  315. snd_seq_port_subscribe_set_dest(sub, &seq_addr);
  316. snd_seq_port_subscribe_set_time_update(sub, 1);
  317. snd_seq_port_subscribe_set_queue(sub, self->queue);
  318. snd_seq_port_subscribe_set_time_real(sub, 1);
  319. if ((err=snd_seq_subscribe_port(self->seq, sub)))
  320. error_log("can't subscribe to %d:%d - %s", client, port, snd_strerror(err));
  321. return err;
  322. }
  323. /*
  324. * ==================== Port routines =============================
  325. */
  326. static inline
  327. int port_hash(snd_seq_addr_t addr)
  328. {
  329. return (addr.client + addr.port) % PORT_HASH_SIZE;
  330. }
  331. static
  332. port_t* port_get(port_hash_t hash, snd_seq_addr_t addr)
  333. {
  334. port_t **pport = &hash[port_hash(addr)];
  335. while (*pport) {
  336. port_t *port = *pport;
  337. if (port->remote.client == addr.client && port->remote.port == addr.port)
  338. return port;
  339. pport = &port->next;
  340. }
  341. return NULL;
  342. }
  343. static
  344. void port_insert(port_hash_t hash, port_t *port)
  345. {
  346. port_t **pport = &hash[port_hash(port->remote)];
  347. port->next = *pport;
  348. *pport = port;
  349. }
  350. static
  351. void port_setdead(port_hash_t hash, snd_seq_addr_t addr)
  352. {
  353. port_t *port = port_get(hash, addr);
  354. if (port)
  355. port->is_dead = 1; // see jack_process
  356. else
  357. debug_log("port_setdead: not found (%d:%d)", addr.client, addr.port);
  358. }
  359. static
  360. void port_free(alsa_seqmidi_t *self, port_t *port)
  361. {
  362. //snd_seq_disconnect_from(self->seq, self->port_id, port->remote.client, port->remote.port);
  363. //snd_seq_disconnect_to(self->seq, self->port_id, port->remote.client, port->remote.port);
  364. if (port->early_events)
  365. jack_ringbuffer_free(port->early_events);
  366. if (port->jack_port)
  367. jack_port_unregister(self->jack, port->jack_port);
  368. info_log("port deleted: %s", port->name);
  369. free(port);
  370. }
  371. static
  372. port_t* port_create(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, const snd_seq_port_info_t *info)
  373. {
  374. port_t *port;
  375. char *c;
  376. int err;
  377. char name[64];
  378. port = calloc(1, sizeof(port_t));
  379. if (!port)
  380. return NULL;
  381. port->remote = addr;
  382. if (port_type[type].jack_caps & JackPortIsOutput)
  383. snprintf(name, sizeof(name) - 1, "system:midi_capture_%d", ++self->midi_in_cnt);
  384. else
  385. snprintf(name, sizeof(name) - 1, "system:midi_playback_%d", ++self->midi_out_cnt);
  386. snprintf(port->name, sizeof(port->name), "%s-%d-%d-%s",
  387. port_type[type].name, addr.client, addr.port, snd_seq_port_info_get_name(info));
  388. // replace all offending characters by -
  389. for (c = port->name; *c; ++c)
  390. if (!isalnum(*c))
  391. *c = '-';
  392. port->jack_port = jack_port_register(self->jack,
  393. name, JACK_DEFAULT_MIDI_TYPE, port_type[type].jack_caps, 0);
  394. if (!port->jack_port)
  395. goto failed;
  396. jack_port_set_alias(port->jack_port, port->name);
  397. if (type == PORT_INPUT)
  398. err = alsa_connect_from(self, port->remote.client, port->remote.port);
  399. else
  400. err = snd_seq_connect_to(self->seq, self->port_id, port->remote.client, port->remote.port);
  401. if (err)
  402. goto failed;
  403. port->early_events = jack_ringbuffer_create(MAX_EVENT_SIZE*16);
  404. info_log("port created: %s", port->name);
  405. return port;
  406. failed:
  407. port_free(self, port);
  408. return NULL;
  409. }
  410. /*
  411. * ==================== Port add/del handling thread ==============================
  412. */
  413. static
  414. void update_port_type(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, int caps, const snd_seq_port_info_t *info)
  415. {
  416. stream_t *str = &self->stream[type];
  417. int alsa_mask = port_type[type].alsa_mask;
  418. port_t *port = port_get(str->ports, addr);
  419. debug_log("update_port_type(%d:%d)", addr.client, addr.port);
  420. if (port && (caps & alsa_mask)!=alsa_mask) {
  421. debug_log("setdead: %s", port->name);
  422. port->is_dead = 1;
  423. }
  424. if (!port && (caps & alsa_mask)==alsa_mask) {
  425. assert (jack_ringbuffer_write_space(str->new_ports) >= sizeof(port));
  426. port = port_create(self, type, addr, info);
  427. if (port)
  428. jack_ringbuffer_write(str->new_ports, (char*)&port, sizeof(port));
  429. }
  430. }
  431. static
  432. void update_port(alsa_seqmidi_t *self, snd_seq_addr_t addr, const snd_seq_port_info_t *info)
  433. {
  434. unsigned int port_caps = snd_seq_port_info_get_capability(info);
  435. if (port_caps & SND_SEQ_PORT_CAP_NO_EXPORT)
  436. return;
  437. update_port_type(self, PORT_INPUT, addr, port_caps, info);
  438. update_port_type(self, PORT_OUTPUT, addr, port_caps, info);
  439. }
  440. static
  441. void free_ports(alsa_seqmidi_t *self, jack_ringbuffer_t *ports)
  442. {
  443. port_t *port;
  444. int sz;
  445. while ((sz = jack_ringbuffer_read(ports, (char*)&port, sizeof(port)))) {
  446. assert (sz == sizeof(port));
  447. port_free(self, port);
  448. }
  449. }
  450. static
  451. void update_ports(alsa_seqmidi_t *self)
  452. {
  453. snd_seq_addr_t addr;
  454. int size;
  455. while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) {
  456. snd_seq_port_info_t *info;
  457. int err;
  458. snd_seq_port_info_alloca(&info);
  459. assert (size == sizeof(addr));
  460. assert (addr.client != self->client_id);
  461. if ((err=snd_seq_get_any_port_info(self->seq, addr.client, addr.port, info))>=0) {
  462. update_port(self, addr, info);
  463. } else {
  464. //port_setdead(self->stream[PORT_INPUT].ports, addr);
  465. //port_setdead(self->stream[PORT_OUTPUT].ports, addr);
  466. }
  467. }
  468. }
  469. static
  470. void* port_thread(void *arg)
  471. {
  472. alsa_seqmidi_t *self = arg;
  473. while (self->keep_walking) {
  474. sem_wait(&self->port_sem);
  475. free_ports(self, self->port_del);
  476. update_ports(self);
  477. }
  478. debug_log("port_thread exited");
  479. return NULL;
  480. }
  481. static
  482. void add_existing_ports(alsa_seqmidi_t *self)
  483. {
  484. snd_seq_addr_t addr;
  485. snd_seq_client_info_t *client_info;
  486. snd_seq_port_info_t *port_info;
  487. snd_seq_client_info_alloca(&client_info);
  488. snd_seq_port_info_alloca(&port_info);
  489. snd_seq_client_info_set_client(client_info, -1);
  490. while (snd_seq_query_next_client(self->seq, client_info) >= 0)
  491. {
  492. addr.client = snd_seq_client_info_get_client(client_info);
  493. if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id)
  494. continue;
  495. snd_seq_port_info_set_client(port_info, addr.client);
  496. snd_seq_port_info_set_port(port_info, -1);
  497. while (snd_seq_query_next_port(self->seq, port_info) >= 0)
  498. {
  499. addr.port = snd_seq_port_info_get_port(port_info);
  500. update_port(self, addr, port_info);
  501. }
  502. }
  503. }
  504. /*
  505. * =================== Input/output port handling =========================
  506. */
  507. static
  508. void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, jack_nframes_t nframes)
  509. {
  510. const snd_seq_real_time_t* alsa_time;
  511. snd_seq_queue_status_t *status;
  512. snd_seq_queue_status_alloca(&status);
  513. info->dir = dir;
  514. info->period_start = jack_last_frame_time(self->jack);
  515. info->nframes = nframes;
  516. info->sample_rate = jack_get_sample_rate(self->jack);
  517. info->cur_frames = jack_frame_time(self->jack);
  518. // immediately get alsa'a real time (uhh, why everybody has their own 'real' time)
  519. snd_seq_get_queue_status(self->seq, self->queue, status);
  520. alsa_time = snd_seq_queue_status_get_real_time(status);
  521. info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec;
  522. }
  523. static
  524. void add_ports(stream_t *str)
  525. {
  526. port_t *port;
  527. while (jack_ringbuffer_read(str->new_ports, (char*)&port, sizeof(port))) {
  528. debug_log("jack: inserted port %s", port->name);
  529. port_insert(str->ports, port);
  530. }
  531. }
  532. static
  533. void jack_process(alsa_seqmidi_t *self, struct process_info *info)
  534. {
  535. stream_t *str = &self->stream[info->dir];
  536. port_jack_func process = port_type[info->dir].jack_func;
  537. int i, del=0;
  538. add_ports(str);
  539. // process ports
  540. for (i=0; i<PORT_HASH_SIZE; ++i) {
  541. port_t **pport = &str->ports[i];
  542. while (*pport) {
  543. port_t *port = *pport;
  544. port->jack_buf = jack_port_get_buffer(port->jack_port, info->nframes);
  545. if (info->dir == PORT_INPUT)
  546. jack_midi_clear_buffer(port->jack_buf);
  547. if (!port->is_dead)
  548. (*process)(self, port, info);
  549. else if (jack_ringbuffer_write_space(self->port_del) >= sizeof(port)) {
  550. debug_log("jack: removed port %s", port->name);
  551. *pport = port->next;
  552. jack_ringbuffer_write(self->port_del, (char*)&port, sizeof(port));
  553. del++;
  554. continue;
  555. }
  556. pport = &port->next;
  557. }
  558. }
  559. if (del)
  560. sem_post(&self->port_sem);
  561. }
  562. /*
  563. * ============================ Input ==============================
  564. */
  565. static
  566. void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info *info)
  567. {
  568. // process port->early_events
  569. alsa_midi_event_t ev;
  570. while (jack_ringbuffer_read(port->early_events, (char*)&ev, sizeof(ev))) {
  571. jack_midi_data_t* buf;
  572. int64_t time = ev.time - info->period_start;
  573. if (time < 0)
  574. time = 0;
  575. else if (time >= info->nframes)
  576. time = info->nframes - 1;
  577. buf = jack_midi_event_reserve(port->jack_buf, (jack_nframes_t)time, ev.size);
  578. if (buf)
  579. jack_ringbuffer_read(port->early_events, (char*)buf, ev.size);
  580. else
  581. jack_ringbuffer_read_advance(port->early_events, ev.size);
  582. debug_log("input: it's time for %d bytes at %lld", ev.size, time);
  583. }
  584. }
  585. static
  586. void port_event(alsa_seqmidi_t *self, snd_seq_event_t *ev)
  587. {
  588. const snd_seq_addr_t addr = ev->data.addr;
  589. if (addr.client == self->client_id)
  590. return;
  591. if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
  592. assert (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr));
  593. debug_log("port_event: add/change %d:%d", addr.client, addr.port);
  594. jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr));
  595. sem_post(&self->port_sem);
  596. } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
  597. debug_log("port_event: del %d:%d", addr.client, addr.port);
  598. port_setdead(self->stream[PORT_INPUT].ports, addr);
  599. port_setdead(self->stream[PORT_OUTPUT].ports, addr);
  600. }
  601. }
  602. static
  603. void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct process_info* info)
  604. {
  605. jack_midi_data_t data[MAX_EVENT_SIZE];
  606. stream_t *str = &self->stream[PORT_INPUT];
  607. long size;
  608. int64_t alsa_time, time_offset;
  609. int64_t frame_offset, event_frame;
  610. port_t *port;
  611. port = port_get(str->ports, alsa_event->source);
  612. if (!port)
  613. return;
  614. /*
  615. * RPNs, NRPNs, Bank Change, etc. need special handling
  616. * but seems, ALSA does it for us already.
  617. */
  618. snd_midi_event_reset_decode(str->codec);
  619. if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0)
  620. return;
  621. // fixup NoteOn with vel 0
  622. if (data[0] == 0x90 && data[2] == 0x00) {
  623. data[0] = 0x80;
  624. data[2] = 0x40;
  625. }
  626. alsa_time = alsa_event->time.time.tv_sec * NSEC_PER_SEC + alsa_event->time.time.tv_nsec;
  627. time_offset = info->alsa_time - alsa_time;
  628. frame_offset = (info->sample_rate * time_offset) / NSEC_PER_SEC;
  629. event_frame = info->cur_frames - info->period_start - frame_offset + info->nframes;
  630. debug_log("input: %d bytes at event_frame = %d", (int)size, (int)event_frame);
  631. if (event_frame >= info->nframes &&
  632. jack_ringbuffer_write_space(port->early_events) >= (sizeof(alsa_midi_event_t) + size)) {
  633. alsa_midi_event_t ev;
  634. ev.time = event_frame + info->period_start;
  635. ev.size = size;
  636. jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev));
  637. jack_ringbuffer_write(port->early_events, (char*)data, size);
  638. debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes));
  639. return;
  640. }
  641. if (event_frame < 0)
  642. event_frame = 0;
  643. else if (event_frame >= info->nframes)
  644. event_frame = info->nframes - 1;
  645. jack_midi_event_write(port->jack_buf, event_frame, data, size);
  646. }
  647. static
  648. void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes)
  649. {
  650. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  651. int res;
  652. snd_seq_event_t *event;
  653. struct process_info info;
  654. if (!self->keep_walking)
  655. return;
  656. set_process_info(&info, self, PORT_INPUT, nframes);
  657. jack_process(self, &info);
  658. while ((res = snd_seq_event_input(self->seq, &event))>0) {
  659. if (event->source.client == SND_SEQ_CLIENT_SYSTEM)
  660. port_event(self, event);
  661. else
  662. input_event(self, event, &info);
  663. }
  664. }
  665. /*
  666. * ============================ Output ==============================
  667. */
  668. static
  669. void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info)
  670. {
  671. stream_t *str = &self->stream[info->dir];
  672. int nevents = jack_midi_get_event_count(port->jack_buf);
  673. int i;
  674. for (i=0; i<nevents; ++i) {
  675. jack_midi_event_t jack_event;
  676. snd_seq_event_t alsa_event;
  677. int64_t frame_offset;
  678. int64_t out_time;
  679. snd_seq_real_time_t out_rt;
  680. int err;
  681. jack_midi_event_get(&jack_event, port->jack_buf, i);
  682. snd_seq_ev_clear(&alsa_event);
  683. snd_midi_event_reset_encode(str->codec);
  684. if (!snd_midi_event_encode(str->codec, jack_event.buffer, jack_event.size, &alsa_event))
  685. continue; // invalid event
  686. snd_seq_ev_set_source(&alsa_event, self->port_id);
  687. snd_seq_ev_set_dest(&alsa_event, port->remote.client, port->remote.port);
  688. frame_offset = jack_event.time + info->period_start + info->nframes - info->cur_frames;
  689. out_time = info->alsa_time + (frame_offset * NSEC_PER_SEC) / info->sample_rate;
  690. debug_log("alsa_out: frame_offset = %lld, info->alsa_time = %lld, out_time = %lld, port->last_out_time = %lld",
  691. frame_offset, info->alsa_time, out_time, port->last_out_time);
  692. // we should use absolute time to prevent reordering caused by rounding errors
  693. if (out_time < port->last_out_time)
  694. out_time = port->last_out_time;
  695. else
  696. port->last_out_time = out_time;
  697. out_rt.tv_nsec = out_time % NSEC_PER_SEC;
  698. out_rt.tv_sec = out_time / NSEC_PER_SEC;
  699. snd_seq_ev_schedule_real(&alsa_event, self->queue, 0, &out_rt);
  700. err = snd_seq_event_output(self->seq, &alsa_event);
  701. 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);
  702. }
  703. }
  704. static
  705. void alsa_seqmidi_write(alsa_midi_t *m, jack_nframes_t nframes)
  706. {
  707. alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
  708. struct process_info info;
  709. if (!self->keep_walking)
  710. return;
  711. set_process_info(&info, self, PORT_OUTPUT, nframes);
  712. jack_process(self, &info);
  713. snd_seq_drain_output(self->seq);
  714. }