gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

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 }