PortMidi 2.2.x
|
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