PortMidi  2.2.x
portmidi.c
00001 #ifdef _MSC_VER
00002  #pragma warning(disable: 4244) // stop warnings about downsize typecasts
00003  #pragma warning(disable: 4018) // stop warnings about signed/unsigned
00004 #endif
00005 
00006 #include "stdlib.h"
00007 #include "string.h"
00008 #include "portmidi.h"
00009 #include "porttime.h"
00010 #include "pmutil.h"
00011 #include "pminternal.h"
00012 #include <assert.h>
00013 
00014 #define MIDI_CLOCK      0xf8
00015 #define MIDI_ACTIVE     0xfe
00016 #define MIDI_STATUS_MASK 0x80
00017 #define MIDI_SYSEX      0xf0
00018 #define MIDI_EOX        0xf7
00019 #define MIDI_START      0xFA
00020 #define MIDI_STOP       0xFC
00021 #define MIDI_CONTINUE   0xFB
00022 #define MIDI_F9         0xF9
00023 #define MIDI_FD         0xFD
00024 #define MIDI_RESET      0xFF
00025 #define MIDI_NOTE_ON    0x90
00026 #define MIDI_NOTE_OFF   0x80
00027 #define MIDI_CHANNEL_AT 0xD0
00028 #define MIDI_POLY_AT    0xA0
00029 #define MIDI_PROGRAM    0xC0
00030 #define MIDI_CONTROL    0xB0
00031 #define MIDI_PITCHBEND  0xE0
00032 #define MIDI_MTC        0xF1
00033 #define MIDI_SONGPOS    0xF2
00034 #define MIDI_SONGSEL    0xF3
00035 #define MIDI_TUNE       0xF6
00036 
00037 #define is_empty(midi) ((midi)->tail == (midi)->head)
00038 
00039 /* this is not static so that pm_init can set it directly if
00040  *   (see pmmac.c:pm_init())
00041  */
00042 int pm_initialized = FALSE;
00043 
00044 int pm_hosterror;
00045 char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
00046 
00047 #ifdef PM_CHECK_ERRORS
00048 
00049 #include <stdio.h>
00050 
00051 #define STRING_MAX 80
00052 
00053 static void prompt_and_exit(void)
00054 {
00055     char line[STRING_MAX];
00056     printf("type ENTER...");
00057     fgets(line, STRING_MAX, stdin);
00058     /* this will clean up open ports: */
00059     exit(-1);
00060 }
00061 
00062 
00063 static PmError pm_errmsg(PmError err)
00064 {
00065     if (err == pmHostError) {
00066         /* it seems pointless to allocate memory and copy the string,
00067          * so I will do the work of Pm_GetHostErrorText directly
00068          */
00069         printf("PortMidi found host error...\n  %s\n", pm_hosterror_text);
00070         pm_hosterror = FALSE;
00071         pm_hosterror_text[0] = 0; /* clear the message */
00072         prompt_and_exit();
00073     } else if (err < 0) {
00074         printf("PortMidi call failed...\n  %s\n", Pm_GetErrorText(err));
00075         prompt_and_exit();
00076     }
00077     return err;
00078 }
00079 #else
00080 #define pm_errmsg(err) err
00081 #endif
00082 
00083 /*
00084 ====================================================================
00085 system implementation of portmidi interface
00086 ====================================================================
00087 */
00088 
00089 int pm_descriptor_max = 0;
00090 int pm_descriptor_index = 0;
00091 descriptor_type descriptors = NULL;
00092 
00093 /* pm_add_device -- describe interface/device pair to library 
00094  *
00095  * This is called at intialization time, once for each 
00096  * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1)
00097  * The strings are retained but NOT COPIED, so do not destroy them!
00098  *
00099  * returns pmInvalidDeviceId if device memory is exceeded
00100  * otherwise returns pmNoError
00101  */
00102 PmError pm_add_device(char *interf, char *name, int input, 
00103                       void *descriptor, pm_fns_type dictionary) {
00104     if (pm_descriptor_index >= pm_descriptor_max) {
00105         // expand descriptors
00106         descriptor_type new_descriptors = (descriptor_type) 
00107             pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
00108         if (!new_descriptors) return pmInsufficientMemory;
00109         if (descriptors) {
00110             memcpy(new_descriptors, descriptors, 
00111                    sizeof(descriptor_node) * pm_descriptor_max);
00112             free(descriptors);
00113         }
00114         pm_descriptor_max += 32;
00115         descriptors = new_descriptors;
00116     }
00117     descriptors[pm_descriptor_index].pub.interf = interf;
00118     descriptors[pm_descriptor_index].pub.name = name;
00119     descriptors[pm_descriptor_index].pub.input = input;
00120     descriptors[pm_descriptor_index].pub.output = !input;
00121 
00122     /* default state: nothing to close (for automatic device closing) */
00123     descriptors[pm_descriptor_index].pub.opened = FALSE;
00124 
00125     /* ID number passed to win32 multimedia API open */
00126     descriptors[pm_descriptor_index].descriptor = descriptor;
00127     
00128     /* points to PmInternal, allows automatic device closing */
00129     descriptors[pm_descriptor_index].internalDescriptor = NULL;
00130 
00131     descriptors[pm_descriptor_index].dictionary = dictionary;
00132     
00133     pm_descriptor_index++;
00134     
00135     return pmNoError;
00136 }
00137 
00138 
00139 /* utility to look up device, given a pattern, 
00140    note: pattern is modified
00141  */
00142 int pm_find_default_device(char *pattern, int is_input)
00143 {
00144     int id = pmNoDevice;
00145     int i;
00146     /* first parse pattern into name, interf parts */
00147     char *interf_pref = ""; /* initially assume it is not there */
00148     char *name_pref = strstr(pattern, ", ");
00149 
00150     if (name_pref) { /* found separator, adjust the pointer */
00151         interf_pref = pattern;
00152         name_pref[0] = 0;
00153         name_pref += 2;
00154     } else {
00155         name_pref = pattern; /* whole string is the name pattern */
00156     }
00157     for (i = 0; i < pm_descriptor_index; i++) {
00158         const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
00159         if (info->input == is_input &&
00160             strstr(info->name, name_pref) &&
00161             strstr(info->interf, interf_pref)) {
00162             id = i;
00163             break;
00164         }
00165     }    
00166     return id;
00167 }
00168 
00169 
00170 /*
00171 ====================================================================
00172 portmidi implementation
00173 ====================================================================
00174 */
00175 
00176 PMEXPORT int Pm_CountDevices( void ) {
00177     Pm_Initialize();
00178     /* no error checking -- Pm_Initialize() does not fail */
00179     return pm_descriptor_index;
00180 }
00181 
00182 
00183 PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
00184     Pm_Initialize(); /* no error check needed */
00185     if (id >= 0 && id < pm_descriptor_index) {
00186         return &descriptors[id].pub;
00187     }
00188     return NULL;
00189 }
00190 
00191 /* pm_success_fn -- "noop" function pointer */
00192 PmError pm_success_fn(PmInternal *midi) {
00193     return pmNoError;
00194 }
00195 
00196 /* none_write -- returns an error if called */
00197 PmError none_write_short(PmInternal *midi, PmEvent *buffer) {
00198     return pmBadPtr;
00199 }
00200 
00201 /* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */
00202 PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp) {
00203     return pmBadPtr;
00204 }
00205 
00206 PmError none_write_byte(PmInternal *midi, unsigned char byte, 
00207                         PmTimestamp timestamp) {
00208     return pmBadPtr;
00209 }
00210 
00211 /* pm_fail_fn -- generic function, returns error if called */
00212 PmError pm_fail_fn(PmInternal *midi) {
00213     return pmBadPtr;
00214 }
00215 
00216 static PmError none_open(PmInternal *midi, void *driverInfo) {
00217     return pmBadPtr;
00218 }
00219 static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) {
00220     *msg = 0; // empty string
00221 }
00222 static unsigned int none_has_host_error(PmInternal * midi) {
00223     return FALSE;
00224 }
00225 PmTimestamp none_synchronize(PmInternal *midi) {
00226     return 0;
00227 }
00228 
00229 #define none_abort pm_fail_fn
00230 #define none_close pm_fail_fn
00231 
00232 pm_fns_node pm_none_dictionary = {
00233     none_write_short,
00234     none_sysex,
00235     none_sysex,
00236     none_write_byte,
00237     none_write_short,
00238     none_write_flush,
00239     none_synchronize,
00240     none_open,
00241     none_abort, 
00242     none_close,
00243     none_poll,
00244     none_has_host_error,
00245     none_get_host_error 
00246 };
00247 
00248 
00249 PMEXPORT const char *Pm_GetErrorText( PmError errnum ) {
00250     const char *msg;
00251 
00252     switch(errnum)
00253     {
00254     case pmNoError:                  
00255         msg = ""; 
00256         break;
00257     case pmHostError:                
00258         msg = "PortMidi: `Host error'"; 
00259         break;
00260     case pmInvalidDeviceId:          
00261         msg = "PortMidi: `Invalid device ID'"; 
00262         break;
00263     case pmInsufficientMemory:       
00264         msg = "PortMidi: `Insufficient memory'"; 
00265         break;
00266     case pmBufferTooSmall:           
00267         msg = "PortMidi: `Buffer too small'"; 
00268         break;
00269     case pmBadPtr:                   
00270         msg = "PortMidi: `Bad pointer'"; 
00271         break;
00272     case pmInternalError:            
00273         msg = "PortMidi: `Internal PortMidi Error'"; 
00274         break;
00275     case pmBufferOverflow:
00276         msg = "PortMidi: `Buffer overflow'";
00277         break;
00278     case pmBadData:
00279         msg = "PortMidi: `Invalid MIDI message Data'";
00280         break;
00281     case pmBufferMaxSize:
00282         msg = "PortMidi: `Buffer cannot be made larger'";
00283         break;
00284     default:                         
00285         msg = "PortMidi: `Illegal error number'"; 
00286         break;
00287     }
00288     return msg;
00289 }
00290 
00291 
00292 /* This can be called whenever you get a pmHostError return value.
00293  * The error will always be in the global pm_hosterror_text.
00294  */
00295 PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len) {
00296     assert(msg);
00297     assert(len > 0);
00298     if (pm_hosterror) {
00299         strncpy(msg, (char *) pm_hosterror_text, len);
00300         pm_hosterror = FALSE;
00301         pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it
00302                                      might help with debugging */
00303         msg[len - 1] = 0; /* make sure string is terminated */
00304     } else {
00305         msg[0] = 0; /* no string to return */
00306     }
00307 }
00308 
00309 
00310 PMEXPORT int Pm_HasHostError(PortMidiStream * stream) {
00311     if (pm_hosterror) return TRUE;
00312     if (stream) {
00313         PmInternal * midi = (PmInternal *) stream;
00314         pm_hosterror = (*midi->dictionary->has_host_error)(midi);
00315         if (pm_hosterror) {
00316             midi->dictionary->host_error(midi, pm_hosterror_text, 
00317                                          PM_HOST_ERROR_MSG_LEN);
00318             /* now error message is global */
00319             return TRUE;
00320         }
00321     }
00322     return FALSE;
00323 }
00324 
00325 
00326 PMEXPORT PmError Pm_Initialize( void ) {
00327     if (!pm_initialized) {
00328         pm_hosterror = FALSE;
00329         pm_hosterror_text[0] = 0; /* the null string */
00330         pm_init();
00331         pm_initialized = TRUE;
00332     }
00333     return pmNoError;
00334 }
00335 
00336 
00337 PMEXPORT PmError Pm_Terminate( void ) {
00338     if (pm_initialized) {
00339         pm_term();
00340         // if there are no devices, descriptors might still be NULL
00341         if (descriptors != NULL) {
00342             free(descriptors);
00343             descriptors = NULL;
00344         }
00345         pm_descriptor_index = 0;
00346         pm_descriptor_max = 0;
00347         pm_initialized = FALSE;
00348     }
00349     return pmNoError;
00350 }
00351 
00352 
00353 /* Pm_Read -- read up to length messages from source into buffer */
00354 /*
00355  * returns number of messages actually read, or error code
00356  */
00357 PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length) {
00358     PmInternal *midi = (PmInternal *) stream;
00359     int n = 0;
00360     PmError err = pmNoError;
00361     pm_hosterror = FALSE;
00362     /* arg checking */
00363     if(midi == NULL)
00364         err = pmBadPtr;
00365     else if(!descriptors[midi->device_id].pub.opened)
00366         err = pmBadPtr;
00367     else if(!descriptors[midi->device_id].pub.input)
00368         err = pmBadPtr;    
00369     /* First poll for data in the buffer...
00370      * This either simply checks for data, or attempts first to fill the buffer
00371      * with data from the MIDI hardware; this depends on the implementation.
00372      * We could call Pm_Poll here, but that would redo a lot of redundant
00373      * parameter checking, so I copied some code from Pm_Poll to here: */
00374     else err = (*(midi->dictionary->poll))(midi);
00375 
00376     if (err != pmNoError) {
00377         if (err == pmHostError) {
00378             midi->dictionary->host_error(midi, pm_hosterror_text, 
00379                                          PM_HOST_ERROR_MSG_LEN);
00380           pm_hosterror = TRUE;
00381         }
00382         return pm_errmsg(err);
00383     }
00384 
00385     while (n < length) {
00386         PmError err = Pm_Dequeue(midi->queue, buffer++);
00387         if (err == pmBufferOverflow) {
00388             /* ignore the data we have retreived so far */
00389             return pm_errmsg(pmBufferOverflow);
00390         } else if (err == 0) { /* empty queue */
00391             break;
00392         }
00393         n++;
00394     }
00395     return n;
00396 }
00397 
00398 PMEXPORT PmError Pm_Poll( PortMidiStream *stream )
00399 {
00400     PmInternal *midi = (PmInternal *) stream;
00401     PmError err;
00402 
00403     pm_hosterror = FALSE;
00404     /* arg checking */
00405     if(midi == NULL)
00406         err = pmBadPtr;
00407     else if (!descriptors[midi->device_id].pub.opened)
00408         err = pmBadPtr;
00409     else if (!descriptors[midi->device_id].pub.input)
00410         err = pmBadPtr;
00411     else
00412         err = (*(midi->dictionary->poll))(midi);
00413 
00414     if (err != pmNoError) {
00415         if (err == pmHostError) {
00416             midi->dictionary->host_error(midi, pm_hosterror_text, 
00417                                          PM_HOST_ERROR_MSG_LEN);
00418            pm_hosterror = TRUE;
00419         }
00420         return pm_errmsg(err);
00421     }
00422 
00423     return !Pm_QueueEmpty(midi->queue);
00424 }
00425 
00426 
00427 /* this is called from Pm_Write and Pm_WriteSysEx to issue a
00428  * call to the system-dependent end_sysex function and handle 
00429  * the error return
00430  */
00431 static PmError pm_end_sysex(PmInternal *midi)
00432 {
00433     PmError err = (*midi->dictionary->end_sysex)(midi, 0);
00434     midi->sysex_in_progress = FALSE;
00435     if (err == pmHostError) {
00436         midi->dictionary->host_error(midi, pm_hosterror_text, 
00437                                      PM_HOST_ERROR_MSG_LEN);
00438         pm_hosterror = TRUE;
00439     }
00440     return err;
00441 }
00442 
00443 
00444 /* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and
00445    Pm_WriteSysEx all operate a state machine that "outputs" calls to
00446    write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
00447 
00448 PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length)
00449 {
00450     PmInternal *midi = (PmInternal *) stream;
00451     PmError err = pmNoError;
00452     int i;
00453     int bits;
00454     
00455     pm_hosterror = FALSE;
00456     /* arg checking */
00457     if(midi == NULL)
00458         err = pmBadPtr;
00459     else if(!descriptors[midi->device_id].pub.opened)
00460         err = pmBadPtr;
00461     else if(!descriptors[midi->device_id].pub.output)
00462         err = pmBadPtr;
00463     else
00464         err = pmNoError;
00465     
00466     if (err != pmNoError) goto pm_write_error;
00467     
00468     if (midi->latency == 0) {
00469         midi->now = 0;
00470     } else {
00471         midi->now = (*(midi->time_proc))(midi->time_info);
00472         if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) {
00473             /* time to resync */
00474             midi->now = (*midi->dictionary->synchronize)(midi);
00475             midi->first_message = FALSE;
00476         }
00477     }
00478     /* error recovery: when a sysex is detected, we call
00479      *   dictionary->begin_sysex() followed by calls to
00480      *   dictionary->write_byte() and dictionary->write_realtime()
00481      *   until an end-of-sysex is detected, when we call
00482      *   dictionary->end_sysex(). After an error occurs, 
00483      *   Pm_Write() continues to call functions. For example,
00484      *   it will continue to call write_byte() even after
00485      *   an error sending a sysex message, and end_sysex() will be
00486      *   called when an EOX or non-real-time status is found.
00487      * When errors are detected, Pm_Write() returns immediately, 
00488      *   so it is possible that this will drop data and leave
00489      *   sysex messages in a partially transmitted state.
00490      */
00491     for (i = 0; i < length; i++) {
00492         uint32_t msg = buffer[i].message;
00493         bits = 0;
00494         /* is this a sysex message? */
00495         if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
00496             if (midi->sysex_in_progress) {
00497                 /* error: previous sysex was not terminated by EOX */
00498                 midi->sysex_in_progress = FALSE;
00499                 err = pmBadData;
00500                 goto pm_write_error;
00501             }
00502             midi->sysex_in_progress = TRUE;
00503             if ((err = (*midi->dictionary->begin_sysex)(midi, 
00504                                buffer[i].timestamp)) != pmNoError)
00505                 goto pm_write_error;
00506             if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
00507                                buffer[i].timestamp)) != pmNoError) 
00508                 goto pm_write_error;
00509             bits = 8;
00510             /* fall through to continue sysex processing */
00511         } else if ((msg & MIDI_STATUS_MASK) && 
00512                    (Pm_MessageStatus(msg) != MIDI_EOX)) {
00513             /* a non-sysex message */
00514             if (midi->sysex_in_progress) {
00515                 /* this should be a realtime message */
00516                 if (is_real_time(msg)) {
00517                     if ((err = (*midi->dictionary->write_realtime)(midi, 
00518                                        &(buffer[i]))) != pmNoError)
00519                         goto pm_write_error;
00520                 } else {
00521                     midi->sysex_in_progress = FALSE;
00522                     err = pmBadData;
00523                     /* ignore any error from this, because we already have one */
00524                     /* pass 0 as timestamp -- it's ignored */
00525                     (*midi->dictionary->end_sysex)(midi, 0);
00526                     goto pm_write_error;
00527                 }
00528             } else { /* regular short midi message */
00529                 if ((err = (*midi->dictionary->write_short)(midi, 
00530                                    &(buffer[i]))) != pmNoError)
00531                     goto pm_write_error;
00532                 continue;
00533             }
00534         }
00535         if (midi->sysex_in_progress) { /* send sysex bytes until EOX */
00536             /* see if we can accelerate data transfer */
00537             if (bits == 0 && midi->fill_base && /* 4 bytes to copy */
00538                 (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
00539                 (msg & 0x80808080) == 0) { /* all data */
00540                     /* copy 4 bytes from msg to fill_base + fill_offset */
00541                     unsigned char *ptr = midi->fill_base + 
00542                                          *(midi->fill_offset_ptr);
00543                     ptr[0] = msg; ptr[1] = msg >> 8; 
00544                     ptr[2] = msg >> 16; ptr[3] = msg >> 24;
00545                     (*midi->fill_offset_ptr) += 4;
00546                      continue;
00547             }
00548             /* no acceleration, so do byte-by-byte copying */
00549             while (bits < 32) {
00550                 unsigned char midi_byte = (unsigned char) (msg >> bits);
00551                 if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, 
00552                                    buffer[i].timestamp)) != pmNoError)
00553                     goto pm_write_error;
00554                 if (midi_byte == MIDI_EOX) {
00555                     err = pm_end_sysex(midi);
00556                     if (err != pmNoError) goto error_exit;
00557                     break; /* from while loop */
00558                 }
00559                 bits += 8;
00560             }
00561         } else {
00562             /* not in sysex mode, but message did not start with status */
00563             err = pmBadData;
00564             goto pm_write_error;
00565         }
00566     }
00567     /* after all messages are processed, send the data */
00568     if (!midi->sysex_in_progress)
00569         err = (*midi->dictionary->write_flush)(midi, 0);
00570 pm_write_error:
00571     if (err == pmHostError) {
00572         midi->dictionary->host_error(midi, pm_hosterror_text, 
00573                                      PM_HOST_ERROR_MSG_LEN);
00574         pm_hosterror = TRUE;
00575     }
00576 error_exit:
00577     return pm_errmsg(err);
00578 }
00579 
00580 
00581 PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when, PmMessage msg)
00582 {
00583     PmEvent event;
00584     
00585     event.timestamp = when;
00586     event.message = msg;
00587     return Pm_Write(stream, &event, 1);
00588 }
00589 
00590 
00591 PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when, 
00592                       unsigned char *msg)
00593 {
00594     /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */
00595     /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */
00596     #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)))
00597     PmEvent buffer[BUFLEN];
00598     int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */
00599     PmInternal *midi = (PmInternal *) stream;
00600     /* the next byte in the buffer is represented by an index, bufx, and
00601        a shift in bits */
00602     int shift = 0;
00603     int bufx = 0;
00604     buffer[0].message = 0;
00605     buffer[0].timestamp = when;
00606 
00607     while (1) {
00608         /* insert next byte into buffer */
00609         buffer[bufx].message |= ((*msg) << shift);
00610         shift += 8;
00611         if (*msg++ == MIDI_EOX) break;
00612         if (shift == 32) {
00613             shift = 0;
00614             bufx++;
00615             if (bufx == buffer_size) {
00616                 PmError err = Pm_Write(stream, buffer, buffer_size);
00617                 /* note: Pm_Write has already called errmsg() */
00618                 if (err) return err;
00619                 /* prepare to fill another buffer */
00620                 bufx = 0;
00621                 buffer_size = BUFLEN;
00622                 /* optimization: maybe we can just copy bytes */
00623                 if (midi->fill_base) {
00624                     PmError err;
00625                     while (*(midi->fill_offset_ptr) < midi->fill_length) {
00626                         midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
00627                         if (*msg++ == MIDI_EOX) {
00628                             err = pm_end_sysex(midi);
00629                             if (err != pmNoError) return pm_errmsg(err);
00630                             goto end_of_sysex;
00631                         }
00632                     }
00633                     /* I thought that I could do a pm_Write here and
00634                      * change this if to a loop, avoiding calls in Pm_Write
00635                      * to the slower write_byte, but since 
00636                      * sysex_in_progress is true, this will not flush
00637                      * the buffer, and we'll infinite loop: */
00638                     /* err = Pm_Write(stream, buffer, 0);
00639                        if (err) return err; */
00640                     /* instead, the way this works is that Pm_Write calls
00641                      * write_byte on 4 bytes. The first, since the buffer
00642                      * is full, will flush the buffer and allocate a new
00643                      * one. This primes the buffer so
00644                      * that we can return to the loop above and fill it
00645                      * efficiently without a lot of function calls.
00646                      */
00647                     buffer_size = 1; /* get another message started */
00648                 }
00649             }
00650             buffer[bufx].message = 0;
00651             buffer[bufx].timestamp = when;
00652         } 
00653         /* keep inserting bytes until you find MIDI_EOX */
00654     }
00655 end_of_sysex:
00656     /* we're finished sending full buffers, but there may
00657      * be a partial one left.
00658      */
00659     if (shift != 0) bufx++; /* add partial message to buffer len */
00660     if (bufx) { /* bufx is number of PmEvents to send from buffer */
00661         PmError err = Pm_Write(stream, buffer, bufx);
00662         if (err) return err;
00663     }
00664     return pmNoError;
00665 }
00666 
00667 
00668 
00669 PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
00670                      PmDeviceID inputDevice,
00671                      void *inputDriverInfo,
00672                      int32_t bufferSize,
00673                      PmTimeProcPtr time_proc,
00674                      void *time_info)
00675 {
00676     PmInternal *midi;
00677     PmError err = pmNoError;
00678     pm_hosterror = FALSE;
00679     *stream = NULL;
00680     
00681     /* arg checking */
00682     if (inputDevice < 0 || inputDevice >= pm_descriptor_index) 
00683         err = pmInvalidDeviceId;
00684     else if (!descriptors[inputDevice].pub.input) 
00685         err =  pmInvalidDeviceId;
00686     else if(descriptors[inputDevice].pub.opened)
00687         err =  pmInvalidDeviceId;
00688     
00689     if (err != pmNoError) 
00690         goto error_return;
00691 
00692     /* create portMidi internal data */
00693     midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); 
00694     *stream = midi;
00695     if (!midi) {
00696         err = pmInsufficientMemory;
00697         goto error_return;
00698     }
00699     midi->device_id = inputDevice;
00700     midi->write_flag = FALSE;
00701     midi->time_proc = time_proc;
00702     midi->time_info = time_info;
00703     /* windows adds timestamps in the driver and these are more accurate than
00704        using a time_proc, so do not automatically provide a time proc. Non-win
00705        implementations may want to provide a default time_proc in their
00706        system-specific midi_out_open() method.
00707      */
00708     if (bufferSize <= 0) bufferSize = 256; /* default buffer size */
00709     midi->queue = Pm_QueueCreate(bufferSize, (int32_t) sizeof(PmEvent));
00710     if (!midi->queue) {
00711         /* free portMidi data */
00712         *stream = NULL;
00713         pm_free(midi); 
00714         err = pmInsufficientMemory;
00715         goto error_return;
00716     }
00717     midi->buffer_len = bufferSize; /* portMidi input storage */
00718     midi->latency = 0; /* not used */
00719     midi->sysex_in_progress = FALSE;
00720     midi->sysex_message = 0; 
00721     midi->sysex_message_count = 0; 
00722     midi->filters = PM_FILT_ACTIVE;
00723     midi->channel_mask = 0xFFFF;
00724     midi->sync_time = 0;
00725     midi->first_message = TRUE;
00726     midi->dictionary = descriptors[inputDevice].dictionary;
00727     midi->fill_base = NULL;
00728     midi->fill_offset_ptr = NULL;
00729     midi->fill_length = 0;
00730     descriptors[inputDevice].internalDescriptor = midi;
00731     /* open system dependent input device */
00732     err = (*midi->dictionary->open)(midi, inputDriverInfo);
00733     if (err) {
00734         *stream = NULL;
00735         descriptors[inputDevice].internalDescriptor = NULL;
00736         /* free portMidi data */
00737         Pm_QueueDestroy(midi->queue);
00738         pm_free(midi);
00739     } else {
00740         /* portMidi input open successful */
00741         descriptors[inputDevice].pub.opened = TRUE;
00742     }
00743 error_return:
00744     /* note: if there is a pmHostError, it is the responsibility
00745      * of the system-dependent code (*midi->dictionary->open)()
00746      * to set pm_hosterror and pm_hosterror_text
00747      */
00748     return pm_errmsg(err);
00749 }
00750 
00751 
00752 PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
00753                       PmDeviceID outputDevice,
00754                       void *outputDriverInfo,
00755                       int32_t bufferSize,
00756                       PmTimeProcPtr time_proc,
00757                       void *time_info,
00758                       int32_t latency ) 
00759 {
00760     PmInternal *midi;
00761     PmError err = pmNoError;
00762     pm_hosterror = FALSE;
00763     *stream =  NULL;
00764     
00765     /* arg checking */
00766     if (outputDevice < 0 || outputDevice >= pm_descriptor_index)
00767         err = pmInvalidDeviceId;
00768     else if (!descriptors[outputDevice].pub.output) 
00769         err = pmInvalidDeviceId;
00770     else if (descriptors[outputDevice].pub.opened)
00771         err = pmInvalidDeviceId;
00772     if (err != pmNoError) 
00773         goto error_return;
00774 
00775     /* create portMidi internal data */
00776     midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); 
00777     *stream = midi;                 
00778     if (!midi) {
00779         err = pmInsufficientMemory;
00780         goto error_return;
00781     }
00782     midi->device_id = outputDevice;
00783     midi->write_flag = TRUE;
00784     midi->time_proc = time_proc;
00785     /* if latency > 0, we need a time reference. If none is provided,
00786        use PortTime library */
00787     if (time_proc == NULL && latency != 0) {
00788         if (!Pt_Started()) 
00789             Pt_Start(1, 0, 0);
00790         /* time_get does not take a parameter, so coerce */
00791         midi->time_proc = (PmTimeProcPtr) Pt_Time;
00792     }
00793     midi->time_info = time_info;
00794     midi->buffer_len = bufferSize;
00795     midi->queue = NULL; /* unused by output */
00796     /* if latency zero, output immediate (timestamps ignored) */
00797     /* if latency < 0, use 0 but don't return an error */
00798     if (latency < 0) latency = 0;
00799     midi->latency = latency;
00800     midi->sysex_in_progress = FALSE;
00801     midi->sysex_message = 0; /* unused by output */
00802     midi->sysex_message_count = 0; /* unused by output */
00803     midi->filters = 0; /* not used for output */
00804     midi->channel_mask = 0xFFFF;
00805     midi->sync_time = 0;
00806     midi->first_message = TRUE;
00807     midi->dictionary = descriptors[outputDevice].dictionary;
00808     midi->fill_base = NULL;
00809     midi->fill_offset_ptr = NULL;
00810     midi->fill_length = 0;
00811     descriptors[outputDevice].internalDescriptor = midi;
00812     /* open system dependent output device */
00813     err = (*midi->dictionary->open)(midi, outputDriverInfo);
00814     if (err) {
00815         *stream = NULL;
00816         descriptors[outputDevice].internalDescriptor = NULL;
00817         /* free portMidi data */
00818         pm_free(midi); 
00819     } else {
00820         /* portMidi input open successful */
00821         descriptors[outputDevice].pub.opened = TRUE;
00822     }
00823 error_return:
00824     /* note: system-dependent code must set pm_hosterror and
00825      * pm_hosterror_text if a pmHostError occurs
00826      */
00827     return pm_errmsg(err);
00828 }
00829 
00830 
00831 PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
00832 {
00833     PmInternal *midi = (PmInternal *) stream;
00834     PmError err = pmNoError;
00835 
00836     if (midi == NULL)
00837         err = pmBadPtr;
00838     else
00839         midi->channel_mask = mask;
00840 
00841     return pm_errmsg(err);
00842 }
00843 
00844 
00845 PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters) {
00846     PmInternal *midi = (PmInternal *) stream;
00847     PmError err = pmNoError;
00848 
00849     /* arg checking */
00850     if (midi == NULL)
00851         err = pmBadPtr;
00852     else if (!descriptors[midi->device_id].pub.opened)
00853         err = pmBadPtr;
00854     else
00855         midi->filters = filters;
00856     return pm_errmsg(err);
00857 }
00858 
00859 
00860 PMEXPORT PmError Pm_Close( PortMidiStream *stream ) {
00861     PmInternal *midi = (PmInternal *) stream;
00862     PmError err = pmNoError;
00863 
00864     pm_hosterror = FALSE;
00865     /* arg checking */
00866     if (midi == NULL) /* midi must point to something */
00867         err = pmBadPtr;
00868     /* if it is an open device, the device_id will be valid */
00869     else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index)
00870         err = pmBadPtr;
00871     /* and the device should be in the opened state */
00872     else if (!descriptors[midi->device_id].pub.opened)
00873         err = pmBadPtr;
00874     
00875     if (err != pmNoError) 
00876         goto error_return;
00877 
00878     /* close the device */
00879     err = (*midi->dictionary->close)(midi);
00880     /* even if an error occurred, continue with cleanup */
00881     descriptors[midi->device_id].internalDescriptor = NULL;
00882     descriptors[midi->device_id].pub.opened = FALSE;
00883     if (midi->queue) Pm_QueueDestroy(midi->queue);
00884     pm_free(midi); 
00885 error_return:
00886     /* system dependent code must set pm_hosterror and
00887      * pm_hosterror_text if a pmHostError occurs.
00888      */
00889     return pm_errmsg(err);
00890 }
00891 
00892 PmError Pm_Synchronize( PortMidiStream* stream ) {
00893     PmInternal *midi = (PmInternal *) stream;
00894     PmError err = pmNoError;
00895     if (midi == NULL)
00896         err = pmBadPtr;
00897     else if (!descriptors[midi->device_id].pub.output)
00898         err = pmBadPtr;
00899     else if (!descriptors[midi->device_id].pub.opened)
00900         err = pmBadPtr;
00901     else
00902         midi->first_message = TRUE;
00903     return err;
00904 }
00905 
00906 PMEXPORT PmError Pm_Abort( PortMidiStream* stream ) {
00907     PmInternal *midi = (PmInternal *) stream;
00908     PmError err;
00909     /* arg checking */
00910     if (midi == NULL)
00911         err = pmBadPtr;
00912     else if (!descriptors[midi->device_id].pub.output)
00913         err = pmBadPtr;
00914     else if (!descriptors[midi->device_id].pub.opened)
00915         err = pmBadPtr;
00916     else
00917         err = (*midi->dictionary->abort)(midi);
00918 
00919     if (err == pmHostError) {
00920         midi->dictionary->host_error(midi, pm_hosterror_text, 
00921                                      PM_HOST_ERROR_MSG_LEN);
00922         pm_hosterror = TRUE;
00923     }
00924     return pm_errmsg(err);
00925 }
00926 
00927 
00928 
00929 /* pm_channel_filtered returns non-zero if the channel mask is blocking the current channel */
00930 #define pm_channel_filtered(status, mask) \
00931     ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
00932 
00933 
00934 /* The following two functions will checks to see if a MIDI message matches
00935    the filtering criteria.  Since the sysex routines only want to filter realtime messages,
00936    we need to have separate routines.
00937  */
00938 
00939 
00940 /* pm_realtime_filtered returns non-zero if the filter will kill the current message.
00941    Note that only realtime messages are checked here.
00942  */
00943 #define pm_realtime_filtered(status, filters) \
00944     ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
00945 
00946 /*
00947     return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE))
00948             ||  ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK))
00949             ||  ((status == MIDI_START) && (filters & PM_FILT_PLAY))
00950             ||  ((status == MIDI_STOP) && (filters & PM_FILT_PLAY))
00951             ||  ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY))
00952             ||  ((status == MIDI_F9) && (filters & PM_FILT_F9))
00953             ||  ((status == MIDI_FD) && (filters & PM_FILT_FD))
00954             ||  ((status == MIDI_RESET) && (filters & PM_FILT_RESET))
00955             ||  ((status == MIDI_MTC) && (filters & PM_FILT_MTC))
00956             ||  ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION))
00957             ||  ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT))
00958             ||  ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE));
00959 }*/
00960 
00961 
00962 /* pm_status_filtered returns non-zero if a filter will kill the current message, based on status.
00963    Note that sysex and real time are not checked.  It is up to the subsystem (winmm, core midi, alsa)
00964    to filter sysex, as it is handled more easily and efficiently at that level.
00965    Realtime message are filtered in pm_realtime_filtered.
00966  */
00967 #define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters))
00968 
00969 
00970 /*
00971     return  ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE))
00972             ||  ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE))
00973             ||  ((status == MIDI_CHANNEL_AT) && (filters & PM_FILT_CHANNEL_AFTERTOUCH))
00974             ||  ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH))
00975             ||  ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM))
00976             ||  ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL))
00977             ||  ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND));
00978 
00979 }
00980 */
00981 
00982 static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
00983 {
00984     PmEvent event;
00985     
00986     /* there may be nothing in the buffer */
00987     if (midi->sysex_message_count == 0) return; /* nothing to flush */
00988     
00989     event.message = midi->sysex_message;
00990     event.timestamp = timestamp;
00991     /* copied from pm_read_short, avoids filtering */
00992     if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
00993         midi->sysex_in_progress = FALSE;
00994     }
00995     midi->sysex_message_count = 0;
00996     midi->sysex_message = 0;
00997 }
00998 
00999 
01000 /* pm_read_short and pm_read_bytes
01001    are the interface between system-dependent MIDI input handlers
01002    and the system-independent PortMIDI code.
01003    The input handler MUST obey these rules:
01004    1) all short input messages must be sent to pm_read_short, which
01005       enqueues them to a FIFO for the application.
01006    2) each buffer of sysex bytes should be reported by calling pm_read_bytes
01007       (which sets midi->sysex_in_progress). After the eox byte, 
01008       pm_read_bytes will clear sysex_in_progress
01009  */
01010 
01011 /* pm_read_short is the place where all input messages arrive from 
01012    system-dependent code such as pmwinmm.c. Here, the messages
01013    are entered into the PortMidi input buffer. 
01014  */
01015 void pm_read_short(PmInternal *midi, PmEvent *event)
01016 { 
01017     int status;
01018     /* arg checking */
01019     assert(midi != NULL);
01020     /* midi filtering is applied here */
01021     status = Pm_MessageStatus(event->message);
01022     if (!pm_status_filtered(status, midi->filters)
01023         && (!is_real_time(status) || 
01024             !pm_realtime_filtered(status, midi->filters))
01025         && !pm_channel_filtered(status, midi->channel_mask)) {
01026         /* if sysex is in progress and we get a status byte, it had
01027            better be a realtime message or the starting SYSEX byte;
01028            otherwise, we exit the sysex_in_progress state
01029          */
01030         if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
01031             /* two choices: real-time or not. If it's real-time, then
01032              * this should be delivered as a sysex byte because it is
01033              * embedded in a sysex message
01034              */
01035             if (is_real_time(status)) {
01036                 midi->sysex_message |= 
01037                         (status << (8 * midi->sysex_message_count++));
01038                 if (midi->sysex_message_count == 4) {
01039                     pm_flush_sysex(midi, event->timestamp);
01040                 }
01041             } else { /* otherwise, it's not real-time. This interrupts
01042                       * a sysex message in progress */
01043                 midi->sysex_in_progress = FALSE;
01044             }
01045         } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
01046             midi->sysex_in_progress = FALSE;
01047         }
01048     }
01049 }
01050 
01051 /* pm_read_bytes -- read one (partial) sysex msg from MIDI data */
01052 /*
01053  * returns how many bytes processed
01054  */
01055 unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data, 
01056                     int len, PmTimestamp timestamp)
01057 {
01058     int i = 0; /* index into data, must not be unsigned (!) */
01059     PmEvent event;
01060     event.timestamp = timestamp;
01061     assert(midi);
01062     /* note that since buffers may not have multiples of 4 bytes,
01063      * pm_read_bytes may be called in the middle of an outgoing
01064      * 4-byte PortMidi message. sysex_in_progress indicates that
01065      * a sysex has been sent but no eox.
01066      */
01067     if (len == 0) return 0; /* sanity check */
01068     if (!midi->sysex_in_progress) {
01069         while (i < len) { /* process all data */
01070             unsigned char byte = data[i++];
01071             if (byte == MIDI_SYSEX &&
01072                 !pm_realtime_filtered(byte, midi->filters)) {
01073                 midi->sysex_in_progress = TRUE;
01074                 i--; /* back up so code below will get SYSEX byte */
01075                 break; /* continue looping below to process msg */
01076             } else if (byte == MIDI_EOX) {
01077                 midi->sysex_in_progress = FALSE;
01078                 return i; /* done with one message */
01079             } else if (byte & MIDI_STATUS_MASK) {
01080                 /* We're getting MIDI but no sysex in progress.
01081                  * Either the SYSEX status byte was dropped or
01082                  * the message was filtered. Drop the data, but
01083                  * send any embedded realtime bytes.
01084                  */
01085                 /* assume that this is a real-time message:
01086                  * it is an error to pass non-real-time messages
01087                  * to pm_read_bytes
01088                  */
01089                 event.message = byte;
01090                 pm_read_short(midi, &event);
01091             }
01092         } /* all bytes in the buffer are processed */
01093     }
01094     /* Now, i<len implies sysex_in_progress. If sysex_in_progress
01095      * becomes false in the loop, there must have been an overflow
01096      * and we can just drop all remaining bytes 
01097      */
01098     while (i < len && midi->sysex_in_progress) {
01099         if (midi->sysex_message_count == 0 && i <= len - 4 &&
01100             ((event.message = (((PmMessage) data[i]) | 
01101                              (((PmMessage) data[i+1]) << 8) |
01102                              (((PmMessage) data[i+2]) << 16) |
01103                              (((PmMessage) data[i+3]) << 24))) &
01104              0x80808080) == 0) { /* all data, no status */ 
01105             if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
01106                 midi->sysex_in_progress = FALSE;
01107             }
01108             i += 4;
01109         } else {
01110             while (i < len) {
01111                 /* send one byte at a time */
01112                 unsigned char byte = data[i++];
01113                 if (is_real_time(byte) && 
01114                     pm_realtime_filtered(byte, midi->filters)) {
01115                     continue; /* real-time data is filtered, so omit */
01116                 }
01117                 midi->sysex_message |= 
01118                     (byte << (8 * midi->sysex_message_count++));
01119                 if (byte == MIDI_EOX) {
01120                     midi->sysex_in_progress = FALSE;
01121                     pm_flush_sysex(midi, event.timestamp);
01122                     return i;
01123                 } else if (midi->sysex_message_count == 4) {
01124                     pm_flush_sysex(midi, event.timestamp);
01125                     /* after handling at least one non-data byte
01126                      * and reaching a 4-byte message boundary,
01127                      * resume trying to send 4 at a time in outer loop
01128                      */
01129                     break;
01130                 }
01131             }
01132         }
01133     }
01134     return i;
01135 }
01136 
01137