pmlinuxalsa.c (27552B)
1 /* 2 * pmlinuxalsa.c -- system specific definitions 3 * 4 * written by: 5 * Roger Dannenberg (port to Alsa 0.9.x) 6 * Clemens Ladisch (provided code examples and invaluable consulting) 7 * Jason Cohen, Rico Colon, Matt Filippone (Alsa 0.5.x implementation) 8 */ 9 10 #include "stdlib.h" 11 #include "portmidi.h" 12 #include "pmutil.h" 13 #include "pminternal.h" 14 #include "pmlinuxalsa.h" 15 #include "string.h" 16 #include "porttime.h" 17 #include "pmlinux.h" 18 19 #include <alsa/asoundlib.h> 20 21 /* I used many print statements to debug this code. I left them in the 22 * source, and you can turn them on by changing false to true below: 23 */ 24 #define VERBOSE_ON 0 25 #define VERBOSE if (VERBOSE_ON) 26 27 #define MIDI_SYSEX 0xf0 28 #define MIDI_EOX 0xf7 29 30 #if SND_LIB_MAJOR == 0 && SND_LIB_MINOR < 9 31 #error needs ALSA 0.9.0 or later 32 #endif 33 34 /* to store client/port in the device descriptor */ 35 #define MAKE_DESCRIPTOR(client, port) ((void*)(((client) << 8) | (port))) 36 #define GET_DESCRIPTOR_CLIENT(info) ((((int)(info)) >> 8) & 0xff) 37 #define GET_DESCRIPTOR_PORT(info) (((int)(info)) & 0xff) 38 39 #define BYTE unsigned char 40 41 extern pm_fns_node pm_linuxalsa_in_dictionary; 42 extern pm_fns_node pm_linuxalsa_out_dictionary; 43 44 static snd_seq_t *seq = NULL; // all input comes here, 45 // output queue allocated on seq 46 static int queue, queue_used; /* one for all ports, reference counted */ 47 48 typedef struct alsa_descriptor_struct { 49 int client; 50 int port; 51 int this_port; 52 int in_sysex; 53 snd_midi_event_t *parser; 54 int error; /* host error code */ 55 } alsa_descriptor_node, *alsa_descriptor_type; 56 57 58 /* get_alsa_error_text -- copy error text to potentially short string */ 59 /**/ 60 static void get_alsa_error_text(char *msg, int len, int err) 61 { 62 int errlen = strlen(snd_strerror(err)); 63 if (errlen < len) { 64 strcpy(msg, snd_strerror(err)); 65 } else if (len > 20) { 66 sprintf(msg, "Alsa error %d", err); 67 } else if (len > 4) { 68 strcpy(msg, "Alsa"); 69 } else { 70 msg[0] = 0; 71 } 72 } 73 74 75 /* queue is shared by both input and output, reference counted */ 76 static PmError alsa_use_queue(void) 77 { 78 if (queue_used == 0) { 79 snd_seq_queue_tempo_t *tempo; 80 81 queue = snd_seq_alloc_queue(seq); 82 if (queue < 0) { 83 pm_hosterror = queue; 84 return pmHostError; 85 } 86 snd_seq_queue_tempo_alloca(&tempo); 87 snd_seq_queue_tempo_set_tempo(tempo, 480000); 88 snd_seq_queue_tempo_set_ppq(tempo, 480); 89 pm_hosterror = snd_seq_set_queue_tempo(seq, queue, tempo); 90 if (pm_hosterror < 0) 91 return pmHostError; 92 93 snd_seq_start_queue(seq, queue, NULL); 94 snd_seq_drain_output(seq); 95 } 96 ++queue_used; 97 return pmNoError; 98 } 99 100 101 static void alsa_unuse_queue(void) 102 { 103 if (--queue_used == 0) { 104 snd_seq_stop_queue(seq, queue, NULL); 105 snd_seq_drain_output(seq); 106 snd_seq_free_queue(seq, queue); 107 VERBOSE printf("queue freed\n"); 108 } 109 } 110 111 112 /* midi_message_length -- how many bytes in a message? */ 113 static int midi_message_length(PmMessage message) 114 { 115 message &= 0xff; 116 if (message < 0x80) { 117 return 0; 118 } else if (message < 0xf0) { 119 static const int length[] = {3, 3, 3, 3, 2, 2, 3}; 120 return length[(message - 0x80) >> 4]; 121 } else { 122 static const int length[] = { 123 -1, 2, 3, 2, 0, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1, 1}; 124 return length[message - 0xf0]; 125 } 126 } 127 128 129 static PmError alsa_out_open(PmInternal *midi, void *driverInfo) 130 { 131 void *client_port = descriptors[midi->device_id].descriptor; 132 alsa_descriptor_type desc = (alsa_descriptor_type) 133 pm_alloc(sizeof(alsa_descriptor_node)); 134 snd_seq_port_info_t *info; 135 int err; 136 137 if (!desc) return pmInsufficientMemory; 138 139 snd_seq_port_info_alloca(&info); 140 snd_seq_port_info_set_port(info, midi->device_id); 141 snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | 142 SND_SEQ_PORT_CAP_READ); 143 snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | 144 SND_SEQ_PORT_TYPE_APPLICATION); 145 snd_seq_port_info_set_port_specified(info, 1); 146 err = snd_seq_create_port(seq, info); 147 if (err < 0) goto free_desc; 148 149 /* fill in fields of desc, which is passed to pm_write routines */ 150 midi->descriptor = desc; 151 desc->client = GET_DESCRIPTOR_CLIENT(client_port); 152 desc->port = GET_DESCRIPTOR_PORT(client_port); 153 desc->this_port = midi->device_id; 154 desc->in_sysex = 0; 155 156 desc->error = 0; 157 158 err = snd_midi_event_new(PM_DEFAULT_SYSEX_BUFFER_SIZE, &desc->parser); 159 if (err < 0) goto free_this_port; 160 161 if (midi->latency > 0) { /* must delay output using a queue */ 162 err = alsa_use_queue(); 163 if (err < 0) goto free_parser; 164 165 err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); 166 if (err < 0) goto unuse_queue; /* clean up and return on error */ 167 } else { 168 err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); 169 if (err < 0) goto free_parser; /* clean up and return on error */ 170 } 171 return pmNoError; 172 173 unuse_queue: 174 alsa_unuse_queue(); 175 free_parser: 176 snd_midi_event_free(desc->parser); 177 free_this_port: 178 snd_seq_delete_port(seq, desc->this_port); 179 free_desc: 180 pm_free(desc); 181 pm_hosterror = err; 182 if (err < 0) { 183 get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); 184 } 185 return pmHostError; 186 } 187 188 189 static PmError alsa_write_byte(PmInternal *midi, unsigned char byte, 190 PmTimestamp timestamp) 191 { 192 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 193 snd_seq_event_t ev; 194 int err; 195 196 snd_seq_ev_clear(&ev); 197 if (snd_midi_event_encode_byte(desc->parser, byte, &ev) == 1) { 198 snd_seq_ev_set_dest(&ev, desc->client, desc->port); 199 snd_seq_ev_set_source(&ev, desc->this_port); 200 if (midi->latency > 0) { 201 /* compute relative time of event = timestamp - now + latency */ 202 PmTimestamp now = (midi->time_proc ? 203 midi->time_proc(midi->time_info) : 204 Pt_Time(NULL)); 205 int when = timestamp; 206 /* if timestamp is zero, send immediately */ 207 /* otherwise compute time delay and use delay if positive */ 208 if (when == 0) when = now; 209 when = (when - now) + midi->latency; 210 if (when < 0) when = 0; 211 VERBOSE printf("timestamp %d now %d latency %d, ", 212 (int) timestamp, (int) now, midi->latency); 213 VERBOSE printf("scheduling event after %d\n", when); 214 /* message is sent in relative ticks, where 1 tick = 1 ms */ 215 snd_seq_ev_schedule_tick(&ev, queue, 1, when); 216 /* NOTE: for cases where the user does not supply a time function, 217 we could optimize the code by not starting Pt_Time and using 218 the alsa tick time instead. I didn't do this because it would 219 entail changing the queue management to start the queue tick 220 count when PortMidi is initialized and keep it running until 221 PortMidi is terminated. (This should be simple, but it's not 222 how the code works now.) -RBD */ 223 } else { /* send event out without queueing */ 224 VERBOSE printf("direct\n"); 225 /* ev.queue = SND_SEQ_QUEUE_DIRECT; 226 ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; */ 227 snd_seq_ev_set_direct(&ev); 228 } 229 VERBOSE printf("sending event\n"); 230 err = snd_seq_event_output(seq, &ev); 231 if (err < 0) { 232 desc->error = err; 233 return pmHostError; 234 } 235 } 236 return pmNoError; 237 } 238 239 240 static PmError alsa_out_close(PmInternal *midi) 241 { 242 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 243 if (!desc) return pmBadPtr; 244 245 if (pm_hosterror = snd_seq_disconnect_to(seq, desc->this_port, 246 desc->client, desc->port)) { 247 // if there's an error, try to delete the port anyway, but don't 248 // change the pm_hosterror value so we retain the first error 249 snd_seq_delete_port(seq, desc->this_port); 250 } else { // if there's no error, delete the port and retain any error 251 pm_hosterror = snd_seq_delete_port(seq, desc->this_port); 252 } 253 if (midi->latency > 0) alsa_unuse_queue(); 254 snd_midi_event_free(desc->parser); 255 midi->descriptor = NULL; /* destroy the pointer to signify "closed" */ 256 pm_free(desc); 257 if (pm_hosterror) { 258 get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, 259 pm_hosterror); 260 return pmHostError; 261 } 262 return pmNoError; 263 } 264 265 266 static PmError alsa_in_open(PmInternal *midi, void *driverInfo) 267 { 268 void *client_port = descriptors[midi->device_id].descriptor; 269 alsa_descriptor_type desc = (alsa_descriptor_type) 270 pm_alloc(sizeof(alsa_descriptor_node)); 271 snd_seq_port_info_t *info; 272 snd_seq_port_subscribe_t *sub; 273 snd_seq_addr_t addr; 274 int err; 275 276 if (!desc) return pmInsufficientMemory; 277 278 err = alsa_use_queue(); 279 if (err < 0) goto free_desc; 280 281 snd_seq_port_info_alloca(&info); 282 snd_seq_port_info_set_port(info, midi->device_id); 283 snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | 284 SND_SEQ_PORT_CAP_READ); 285 snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | 286 SND_SEQ_PORT_TYPE_APPLICATION); 287 snd_seq_port_info_set_port_specified(info, 1); 288 err = snd_seq_create_port(seq, info); 289 if (err < 0) goto free_queue; 290 291 /* fill in fields of desc, which is passed to pm_write routines */ 292 midi->descriptor = desc; 293 desc->client = GET_DESCRIPTOR_CLIENT(client_port); 294 desc->port = GET_DESCRIPTOR_PORT(client_port); 295 desc->this_port = midi->device_id; 296 desc->in_sysex = 0; 297 298 desc->error = 0; 299 300 VERBOSE printf("snd_seq_connect_from: %d %d %d\n", 301 desc->this_port, desc->client, desc->port); 302 snd_seq_port_subscribe_alloca(&sub); 303 addr.client = snd_seq_client_id(seq); 304 addr.port = desc->this_port; 305 snd_seq_port_subscribe_set_dest(sub, &addr); 306 addr.client = desc->client; 307 addr.port = desc->port; 308 snd_seq_port_subscribe_set_sender(sub, &addr); 309 snd_seq_port_subscribe_set_time_update(sub, 1); 310 /* this doesn't seem to work: messages come in with real timestamps */ 311 snd_seq_port_subscribe_set_time_real(sub, 0); 312 err = snd_seq_subscribe_port(seq, sub); 313 /* err = 314 snd_seq_connect_from(seq, desc->this_port, desc->client, desc->port); */ 315 if (err < 0) goto free_this_port; /* clean up and return on error */ 316 return pmNoError; 317 318 free_this_port: 319 snd_seq_delete_port(seq, desc->this_port); 320 free_queue: 321 alsa_unuse_queue(); 322 free_desc: 323 pm_free(desc); 324 pm_hosterror = err; 325 if (err < 0) { 326 get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); 327 } 328 return pmHostError; 329 } 330 331 static PmError alsa_in_close(PmInternal *midi) 332 { 333 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 334 if (!desc) return pmBadPtr; 335 if (pm_hosterror = snd_seq_disconnect_from(seq, desc->this_port, 336 desc->client, desc->port)) { 337 snd_seq_delete_port(seq, desc->this_port); /* try to close port */ 338 } else { 339 pm_hosterror = snd_seq_delete_port(seq, desc->this_port); 340 } 341 alsa_unuse_queue(); 342 pm_free(desc); 343 if (pm_hosterror) { 344 get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, 345 pm_hosterror); 346 return pmHostError; 347 } 348 return pmNoError; 349 } 350 351 352 static PmError alsa_abort(PmInternal *midi) 353 { 354 /* NOTE: ALSA documentation is vague. This is supposed to 355 * remove any pending output messages. If you can test and 356 * confirm this code is correct, please update this comment. -RBD 357 */ 358 /* Unfortunately, I can't even compile it -- my ALSA version 359 * does not implement snd_seq_remove_events_t, so this does 360 * not compile. I'll try again, but it looks like I'll need to 361 * upgrade my entire Linux OS -RBD 362 */ 363 /* 364 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 365 snd_seq_remove_events_t info; 366 snd_seq_addr_t addr; 367 addr.client = desc->client; 368 addr.port = desc->port; 369 snd_seq_remove_events_set_dest(&info, &addr); 370 snd_seq_remove_events_set_condition(&info, SND_SEQ_REMOVE_DEST); 371 pm_hosterror = snd_seq_remove_events(seq, &info); 372 if (pm_hosterror) { 373 get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, 374 pm_hosterror); 375 return pmHostError; 376 } 377 */ 378 printf("WARNING: alsa_abort not implemented\n"); 379 return pmNoError; 380 } 381 382 383 #ifdef GARBAGE 384 This is old code here temporarily for reference 385 static PmError alsa_write(PmInternal *midi, PmEvent *buffer, int32_t length) 386 { 387 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 388 int i, bytes; 389 unsigned char byte; 390 PmMessage msg; 391 392 desc->error = 0; 393 for (; length > 0; length--, buffer++) { 394 VERBOSE printf("message 0x%x\n", buffer->message); 395 if (Pm_MessageStatus(buffer->message) == MIDI_SYSEX) 396 desc->in_sysex = TRUE; 397 if (desc->in_sysex) { 398 msg = buffer->message; 399 for (i = 0; i < 4; i++) { 400 byte = msg; /* extract next byte to send */ 401 alsa_write_byte(midi, byte, buffer->timestamp); 402 if (byte == MIDI_EOX) { 403 desc->in_sysex = FALSE; 404 break; 405 } 406 if (desc->error < 0) break; 407 msg >>= 8; /* shift next byte into position */ 408 } 409 } else { 410 bytes = midi_message_length(buffer->message); 411 msg = buffer->message; 412 for (i = 0; i < bytes; i++) { 413 byte = msg; /* extract next byte to send */ 414 VERBOSE printf("sending 0x%x\n", byte); 415 alsa_write_byte(midi, byte, buffer->timestamp); 416 if (desc->error < 0) break; 417 msg >>= 8; /* shift next byte into position */ 418 } 419 } 420 } 421 if (desc->error < 0) return pmHostError; 422 423 VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); 424 desc->error = snd_seq_drain_output(seq); 425 if (desc->error < 0) return pmHostError; 426 427 desc->error = pmNoError; 428 return pmNoError; 429 } 430 #endif 431 432 433 static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp) 434 { 435 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 436 VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); 437 desc->error = snd_seq_drain_output(seq); 438 if (desc->error < 0) return pmHostError; 439 440 desc->error = pmNoError; 441 return pmNoError; 442 } 443 444 445 static PmError alsa_write_short(PmInternal *midi, PmEvent *event) 446 { 447 int bytes = midi_message_length(event->message); 448 PmMessage msg = event->message; 449 int i; 450 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 451 for (i = 0; i < bytes; i++) { 452 unsigned char byte = msg; 453 VERBOSE printf("sending 0x%x\n", byte); 454 alsa_write_byte(midi, byte, event->timestamp); 455 if (desc->error < 0) break; 456 msg >>= 8; /* shift next byte into position */ 457 } 458 if (desc->error < 0) return pmHostError; 459 desc->error = pmNoError; 460 return pmNoError; 461 } 462 463 464 /* alsa_sysex -- implements begin_sysex and end_sysex */ 465 PmError alsa_sysex(PmInternal *midi, PmTimestamp timestamp) { 466 return pmNoError; 467 } 468 469 470 static PmTimestamp alsa_synchronize(PmInternal *midi) 471 { 472 return 0; /* linux implementation does not use this synchronize function */ 473 /* Apparently, Alsa data is relative to the time you send it, and there 474 is no reference. If this is true, this is a serious shortcoming of 475 Alsa. If not true, then PortMidi has a serious shortcoming -- it 476 should be scheduling relative to Alsa's time reference. */ 477 } 478 479 480 static void handle_event(snd_seq_event_t *ev) 481 { 482 int device_id = ev->dest.port; 483 PmInternal *midi = descriptors[device_id].internalDescriptor; 484 PmEvent pm_ev; 485 PmTimeProcPtr time_proc = midi->time_proc; 486 PmTimestamp timestamp; 487 488 /* time stamp should be in ticks, using our queue where 1 tick = 1ms */ 489 assert((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_TICK); 490 491 /* if no time_proc, just return "native" ticks (ms) */ 492 if (time_proc == NULL) { 493 timestamp = ev->time.tick; 494 } else { /* translate time to time_proc basis */ 495 snd_seq_queue_status_t *queue_status; 496 snd_seq_queue_status_alloca(&queue_status); 497 snd_seq_get_queue_status(seq, queue, queue_status); 498 /* return (now - alsa_now) + alsa_timestamp */ 499 timestamp = (*time_proc)(midi->time_info) + ev->time.tick - 500 snd_seq_queue_status_get_tick_time(queue_status); 501 } 502 pm_ev.timestamp = timestamp; 503 switch (ev->type) { 504 case SND_SEQ_EVENT_NOTEON: 505 pm_ev.message = Pm_Message(0x90 | ev->data.note.channel, 506 ev->data.note.note & 0x7f, 507 ev->data.note.velocity & 0x7f); 508 pm_read_short(midi, &pm_ev); 509 break; 510 case SND_SEQ_EVENT_NOTEOFF: 511 pm_ev.message = Pm_Message(0x80 | ev->data.note.channel, 512 ev->data.note.note & 0x7f, 513 ev->data.note.velocity & 0x7f); 514 pm_read_short(midi, &pm_ev); 515 break; 516 case SND_SEQ_EVENT_KEYPRESS: 517 pm_ev.message = Pm_Message(0xa0 | ev->data.note.channel, 518 ev->data.note.note & 0x7f, 519 ev->data.note.velocity & 0x7f); 520 pm_read_short(midi, &pm_ev); 521 break; 522 case SND_SEQ_EVENT_CONTROLLER: 523 pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, 524 ev->data.control.param & 0x7f, 525 ev->data.control.value & 0x7f); 526 pm_read_short(midi, &pm_ev); 527 break; 528 case SND_SEQ_EVENT_PGMCHANGE: 529 pm_ev.message = Pm_Message(0xc0 | ev->data.note.channel, 530 ev->data.control.value & 0x7f, 0); 531 pm_read_short(midi, &pm_ev); 532 break; 533 case SND_SEQ_EVENT_CHANPRESS: 534 pm_ev.message = Pm_Message(0xd0 | ev->data.note.channel, 535 ev->data.control.value & 0x7f, 0); 536 pm_read_short(midi, &pm_ev); 537 break; 538 case SND_SEQ_EVENT_PITCHBEND: 539 pm_ev.message = Pm_Message(0xe0 | ev->data.note.channel, 540 (ev->data.control.value + 0x2000) & 0x7f, 541 ((ev->data.control.value + 0x2000) >> 7) & 0x7f); 542 pm_read_short(midi, &pm_ev); 543 break; 544 case SND_SEQ_EVENT_CONTROL14: 545 if (ev->data.control.param < 0x20) { 546 pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, 547 ev->data.control.param, 548 (ev->data.control.value >> 7) & 0x7f); 549 pm_read_short(midi, &pm_ev); 550 pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, 551 ev->data.control.param + 0x20, 552 ev->data.control.value & 0x7f); 553 pm_read_short(midi, &pm_ev); 554 } else { 555 pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, 556 ev->data.control.param & 0x7f, 557 ev->data.control.value & 0x7f); 558 559 pm_read_short(midi, &pm_ev); 560 } 561 break; 562 case SND_SEQ_EVENT_SONGPOS: 563 pm_ev.message = Pm_Message(0xf2, 564 ev->data.control.value & 0x7f, 565 (ev->data.control.value >> 7) & 0x7f); 566 pm_read_short(midi, &pm_ev); 567 break; 568 case SND_SEQ_EVENT_SONGSEL: 569 pm_ev.message = Pm_Message(0xf3, 570 ev->data.control.value & 0x7f, 0); 571 pm_read_short(midi, &pm_ev); 572 break; 573 case SND_SEQ_EVENT_QFRAME: 574 pm_ev.message = Pm_Message(0xf1, 575 ev->data.control.value & 0x7f, 0); 576 pm_read_short(midi, &pm_ev); 577 break; 578 case SND_SEQ_EVENT_START: 579 pm_ev.message = Pm_Message(0xfa, 0, 0); 580 pm_read_short(midi, &pm_ev); 581 break; 582 case SND_SEQ_EVENT_CONTINUE: 583 pm_ev.message = Pm_Message(0xfb, 0, 0); 584 pm_read_short(midi, &pm_ev); 585 break; 586 case SND_SEQ_EVENT_STOP: 587 pm_ev.message = Pm_Message(0xfc, 0, 0); 588 pm_read_short(midi, &pm_ev); 589 break; 590 case SND_SEQ_EVENT_CLOCK: 591 pm_ev.message = Pm_Message(0xf8, 0, 0); 592 pm_read_short(midi, &pm_ev); 593 break; 594 case SND_SEQ_EVENT_TUNE_REQUEST: 595 pm_ev.message = Pm_Message(0xf6, 0, 0); 596 pm_read_short(midi, &pm_ev); 597 break; 598 case SND_SEQ_EVENT_RESET: 599 pm_ev.message = Pm_Message(0xff, 0, 0); 600 pm_read_short(midi, &pm_ev); 601 break; 602 case SND_SEQ_EVENT_SENSING: 603 pm_ev.message = Pm_Message(0xfe, 0, 0); 604 pm_read_short(midi, &pm_ev); 605 break; 606 case SND_SEQ_EVENT_SYSEX: { 607 const BYTE *ptr = (const BYTE *) ev->data.ext.ptr; 608 /* assume there is one sysex byte to process */ 609 pm_read_bytes(midi, ptr, ev->data.ext.len, timestamp); 610 break; 611 } 612 } 613 } 614 615 616 static PmError alsa_poll(PmInternal *midi) 617 { 618 snd_seq_event_t *ev; 619 /* expensive check for input data, gets data from device: */ 620 while (snd_seq_event_input_pending(seq, TRUE) > 0) { 621 /* cheap check on local input buffer */ 622 while (snd_seq_event_input_pending(seq, FALSE) > 0) { 623 /* check for and ignore errors, e.g. input overflow */ 624 /* note: if there's overflow, this should be reported 625 * all the way through to client. Since input from all 626 * devices is merged, we need to find all input devices 627 * and set all to the overflow state. 628 * NOTE: this assumes every input is ALSA based. 629 */ 630 int rslt = snd_seq_event_input(seq, &ev); 631 if (rslt >= 0) { 632 handle_event(ev); 633 } else if (rslt == -ENOSPC) { 634 int i; 635 for (i = 0; i < pm_descriptor_index; i++) { 636 if (descriptors[i].pub.input) { 637 PmInternal *midi = (PmInternal *) 638 descriptors[i].internalDescriptor; 639 /* careful, device may not be open! */ 640 if (midi) Pm_SetOverflow(midi->queue); 641 } 642 } 643 } 644 } 645 } 646 return pmNoError; 647 } 648 649 650 static unsigned int alsa_has_host_error(PmInternal *midi) 651 { 652 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 653 return desc->error; 654 } 655 656 657 static void alsa_get_host_error(PmInternal *midi, char *msg, unsigned int len) 658 { 659 alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; 660 int err = (pm_hosterror || desc->error); 661 get_alsa_error_text(msg, len, err); 662 } 663 664 665 pm_fns_node pm_linuxalsa_in_dictionary = { 666 none_write_short, 667 none_sysex, 668 none_sysex, 669 none_write_byte, 670 none_write_short, 671 none_write_flush, 672 alsa_synchronize, 673 alsa_in_open, 674 alsa_abort, 675 alsa_in_close, 676 alsa_poll, 677 alsa_has_host_error, 678 alsa_get_host_error 679 }; 680 681 pm_fns_node pm_linuxalsa_out_dictionary = { 682 alsa_write_short, 683 alsa_sysex, 684 alsa_sysex, 685 alsa_write_byte, 686 alsa_write_short, /* short realtime message */ 687 alsa_write_flush, 688 alsa_synchronize, 689 alsa_out_open, 690 alsa_abort, 691 alsa_out_close, 692 none_poll, 693 alsa_has_host_error, 694 alsa_get_host_error 695 }; 696 697 698 /* pm_strdup -- copy a string to the heap. Use this rather than strdup so 699 * that we call pm_alloc, not malloc. This allows portmidi to avoid 700 * malloc which might cause priority inversion. Probably ALSA is going 701 * to call malloc anyway, so this extra work here may be pointless. 702 */ 703 char *pm_strdup(const char *s) 704 { 705 int len = strlen(s); 706 char *dup = (char *) pm_alloc(len + 1); 707 strcpy(dup, s); 708 return dup; 709 } 710 711 712 PmError pm_linuxalsa_init( void ) 713 { 714 int err; 715 snd_seq_client_info_t *cinfo; 716 snd_seq_port_info_t *pinfo; 717 unsigned int caps; 718 719 /* Previously, the last parameter was SND_SEQ_NONBLOCK, but this 720 * would cause messages to be dropped if the ALSA buffer fills up. 721 * The correct behavior is for writes to block until there is 722 * room to send all the data. The client should normally allocate 723 * a large enough buffer to avoid blocking on output. 724 * Now that blocking is enabled, the seq_event_input() will block 725 * if there is no input data. This is not what we want, so must 726 * call seq_event_input_pending() to avoid blocking. 727 */ 728 err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0); 729 if (err < 0) return err; 730 731 snd_seq_client_info_alloca(&cinfo); 732 snd_seq_port_info_alloca(&pinfo); 733 734 snd_seq_client_info_set_client(cinfo, -1); 735 while (snd_seq_query_next_client(seq, cinfo) == 0) { 736 snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); 737 snd_seq_port_info_set_port(pinfo, -1); 738 while (snd_seq_query_next_port(seq, pinfo) == 0) { 739 if (snd_seq_port_info_get_client(pinfo) == SND_SEQ_CLIENT_SYSTEM) 740 continue; /* ignore Timer and Announce ports on client 0 */ 741 caps = snd_seq_port_info_get_capability(pinfo); 742 if (!(caps & (SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE))) 743 continue; /* ignore if you cannot read or write port */ 744 if (caps & SND_SEQ_PORT_CAP_SUBS_WRITE) { 745 if (pm_default_output_device_id == -1) 746 pm_default_output_device_id = pm_descriptor_index; 747 pm_add_device("ALSA", 748 pm_strdup(snd_seq_port_info_get_name(pinfo)), 749 FALSE, 750 MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), 751 snd_seq_port_info_get_port(pinfo)), 752 &pm_linuxalsa_out_dictionary); 753 } 754 if (caps & SND_SEQ_PORT_CAP_SUBS_READ) { 755 if (pm_default_input_device_id == -1) 756 pm_default_input_device_id = pm_descriptor_index; 757 pm_add_device("ALSA", 758 pm_strdup(snd_seq_port_info_get_name(pinfo)), 759 TRUE, 760 MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), 761 snd_seq_port_info_get_port(pinfo)), 762 &pm_linuxalsa_in_dictionary); 763 } 764 } 765 } 766 return pmNoError; 767 } 768 769 770 void pm_linuxalsa_term(void) 771 { 772 if (seq) { 773 snd_seq_close(seq); 774 pm_free(descriptors); 775 descriptors = NULL; 776 pm_descriptor_index = 0; 777 pm_descriptor_max = 0; 778 } 779 }