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.

916 lines
24KB

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