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
00040
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
00059 exit(-1);
00060 }
00061
00062
00063 static PmError pm_errmsg(PmError err)
00064 {
00065 if (err == pmHostError) {
00066
00067
00068
00069 printf("PortMidi found host error...\n %s\n", pm_hosterror_text);
00070 pm_hosterror = FALSE;
00071 pm_hosterror_text[0] = 0;
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
00086
00087
00088
00089 int pm_descriptor_max = 0;
00090 int pm_descriptor_index = 0;
00091 descriptor_type descriptors = NULL;
00092
00093
00094
00095
00096
00097
00098
00099
00100
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
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
00123 descriptors[pm_descriptor_index].pub.opened = FALSE;
00124
00125
00126 descriptors[pm_descriptor_index].descriptor = descriptor;
00127
00128
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
00140
00141
00142 int pm_find_default_device(char *pattern, int is_input)
00143 {
00144 int id = pmNoDevice;
00145 int i;
00146
00147 char *interf_pref = "";
00148 char *name_pref = strstr(pattern, ", ");
00149
00150 if (name_pref) {
00151 interf_pref = pattern;
00152 name_pref[0] = 0;
00153 name_pref += 2;
00154 } else {
00155 name_pref = 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
00173
00174
00175
00176 int Pm_CountDevices( void ) {
00177 Pm_Initialize();
00178
00179 return pm_descriptor_index;
00180 }
00181
00182
00183 const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
00184 Pm_Initialize();
00185 if (id >= 0 && id < pm_descriptor_index) {
00186 return &descriptors[id].pub;
00187 }
00188 return NULL;
00189 }
00190
00191
00192 PmError pm_success_fn(PmInternal *midi) {
00193 return pmNoError;
00194 }
00195
00196
00197 PmError none_write_short(PmInternal *midi, PmEvent *buffer) {
00198 return pmBadPtr;
00199 }
00200
00201
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
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;
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 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
00293
00294
00295 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;
00302
00303 msg[len - 1] = 0;
00304 } else {
00305 msg[0] = 0;
00306 }
00307 }
00308
00309
00310 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
00319 return TRUE;
00320 }
00321 }
00322 return FALSE;
00323 }
00324
00325
00326 PmError Pm_Initialize( void ) {
00327 if (!pm_initialized) {
00328 pm_hosterror = FALSE;
00329 pm_hosterror_text[0] = 0;
00330 pm_init();
00331 pm_initialized = TRUE;
00332 }
00333 return pmNoError;
00334 }
00335
00336
00337 PmError Pm_Terminate( void ) {
00338 if (pm_initialized) {
00339 pm_term();
00340
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
00354
00355
00356
00357 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
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
00370
00371
00372
00373
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
00389 return pm_errmsg(pmBufferOverflow);
00390 } else if (err == 0) {
00391 break;
00392 }
00393 n++;
00394 }
00395 return n;
00396 }
00397
00398 PmError Pm_Poll( PortMidiStream *stream )
00399 {
00400 PmInternal *midi = (PmInternal *) stream;
00401 PmError err;
00402
00403 pm_hosterror = FALSE;
00404
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
00428
00429
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
00445
00446
00447
00448 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
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 < midi->now) {
00473
00474 midi->now = (*midi->dictionary->synchronize)(midi);
00475 midi->first_message = FALSE;
00476 }
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 for (i = 0; i < length; i++) {
00492 uint32_t msg = buffer[i].message;
00493 bits = 0;
00494
00495 if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
00496 if (midi->sysex_in_progress) {
00497
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
00511 } else if ((msg & MIDI_STATUS_MASK) &&
00512 (Pm_MessageStatus(msg) != MIDI_EOX)) {
00513
00514 if (midi->sysex_in_progress) {
00515
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
00524
00525 (*midi->dictionary->end_sysex)(midi, 0);
00526 goto pm_write_error;
00527 }
00528 } else {
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) {
00536
00537 if (bits == 0 && midi->fill_base &&
00538 (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
00539 (msg & 0x80808080) == 0) {
00540
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
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;
00558 }
00559 bits += 8;
00560 }
00561 } else {
00562
00563 err = pmBadData;
00564 goto pm_write_error;
00565 }
00566 }
00567
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 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 PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
00592 unsigned char *msg)
00593 {
00594
00595
00596 #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)))
00597 PmEvent buffer[BUFLEN];
00598 int buffer_size = 1;
00599 PmInternal *midi = (PmInternal *) stream;
00600
00601
00602 int shift = 0;
00603 int bufx = 0;
00604 buffer[0].message = 0;
00605 buffer[0].timestamp = when;
00606
00607 while (1) {
00608
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
00618 if (err) return err;
00619
00620 bufx = 0;
00621 buffer_size = BUFLEN;
00622
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
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647 buffer_size = 1;
00648 }
00649 }
00650 buffer[bufx].message = 0;
00651 buffer[bufx].timestamp = when;
00652 }
00653
00654 }
00655 end_of_sysex:
00656
00657
00658
00659 if (shift != 0) bufx++;
00660 if (bufx) {
00661 PmError err = Pm_Write(stream, buffer, bufx);
00662 if (err) return err;
00663 }
00664 return pmNoError;
00665 }
00666
00667
00668
00669 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
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
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
00704
00705
00706
00707
00708 if (bufferSize <= 0) bufferSize = 256;
00709 midi->queue = Pm_QueueCreate(bufferSize, (int32_t) sizeof(PmEvent));
00710 if (!midi->queue) {
00711
00712 *stream = NULL;
00713 pm_free(midi);
00714 err = pmInsufficientMemory;
00715 goto error_return;
00716 }
00717 midi->buffer_len = bufferSize;
00718 midi->latency = 0;
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
00732 err = (*midi->dictionary->open)(midi, inputDriverInfo);
00733 if (err) {
00734 *stream = NULL;
00735 descriptors[inputDevice].internalDescriptor = NULL;
00736
00737 Pm_QueueDestroy(midi->queue);
00738 pm_free(midi);
00739 } else {
00740
00741 descriptors[inputDevice].pub.opened = TRUE;
00742 }
00743 error_return:
00744
00745
00746
00747
00748 return pm_errmsg(err);
00749 }
00750
00751
00752 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
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
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
00786
00787 if (time_proc == NULL && latency != 0) {
00788 if (!Pt_Started())
00789 Pt_Start(1, 0, 0);
00790
00791 midi->time_proc = (PmTimeProcPtr) Pt_Time;
00792 }
00793 midi->time_info = time_info;
00794 midi->buffer_len = bufferSize;
00795 midi->queue = NULL;
00796
00797
00798 if (latency < 0) latency = 0;
00799 midi->latency = latency;
00800 midi->sysex_in_progress = FALSE;
00801 midi->sysex_message = 0;
00802 midi->sysex_message_count = 0;
00803 midi->filters = 0;
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
00813 err = (*midi->dictionary->open)(midi, outputDriverInfo);
00814 if (err) {
00815 *stream = NULL;
00816 descriptors[outputDevice].internalDescriptor = NULL;
00817
00818 pm_free(midi);
00819 } else {
00820
00821 descriptors[outputDevice].pub.opened = TRUE;
00822 }
00823 error_return:
00824
00825
00826
00827 return pm_errmsg(err);
00828 }
00829
00830
00831 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 PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters) {
00846 PmInternal *midi = (PmInternal *) stream;
00847 PmError err = pmNoError;
00848
00849
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 PmError Pm_Close( PortMidiStream *stream ) {
00861 PmInternal *midi = (PmInternal *) stream;
00862 PmError err = pmNoError;
00863
00864 pm_hosterror = FALSE;
00865
00866 if (midi == NULL)
00867 err = pmBadPtr;
00868
00869 else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index)
00870 err = pmBadPtr;
00871
00872 else if (!descriptors[midi->device_id].pub.opened)
00873 err = pmBadPtr;
00874
00875 if (err != pmNoError)
00876 goto error_return;
00877
00878
00879 err = (*midi->dictionary->close)(midi);
00880
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
00887
00888
00889 return pm_errmsg(err);
00890 }
00891
00892
00893 PmError Pm_Abort( PortMidiStream* stream ) {
00894 PmInternal *midi = (PmInternal *) stream;
00895 PmError err;
00896
00897 if (midi == NULL)
00898 err = pmBadPtr;
00899 else if (!descriptors[midi->device_id].pub.output)
00900 err = pmBadPtr;
00901 else if (!descriptors[midi->device_id].pub.opened)
00902 err = pmBadPtr;
00903 else
00904 err = (*midi->dictionary->abort)(midi);
00905
00906 if (err == pmHostError) {
00907 midi->dictionary->host_error(midi, pm_hosterror_text,
00908 PM_HOST_ERROR_MSG_LEN);
00909 pm_hosterror = TRUE;
00910 }
00911 return pm_errmsg(err);
00912 }
00913
00914
00915
00916
00917 #define pm_channel_filtered(status, mask) \
00918 ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930 #define pm_realtime_filtered(status, filters) \
00931 ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 #define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters))
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969 static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
00970 {
00971 PmEvent event;
00972
00973
00974 if (midi->sysex_message_count == 0) return;
00975
00976 event.message = midi->sysex_message;
00977 event.timestamp = timestamp;
00978
00979 if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
00980 midi->sysex_in_progress = FALSE;
00981 }
00982 midi->sysex_message_count = 0;
00983 midi->sysex_message = 0;
00984 }
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002 void pm_read_short(PmInternal *midi, PmEvent *event)
01003 {
01004 int status;
01005
01006 assert(midi != NULL);
01007
01008 status = Pm_MessageStatus(event->message);
01009 if (!pm_status_filtered(status, midi->filters)
01010 && (!is_real_time(status) ||
01011 !pm_realtime_filtered(status, midi->filters))
01012 && !pm_channel_filtered(status, midi->channel_mask)) {
01013
01014
01015
01016
01017 if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
01018
01019
01020
01021
01022 if (is_real_time(status)) {
01023 midi->sysex_message |=
01024 (status << (8 * midi->sysex_message_count++));
01025 if (midi->sysex_message_count == 4) {
01026 pm_flush_sysex(midi, event->timestamp);
01027 }
01028 } else {
01029
01030 midi->sysex_in_progress = FALSE;
01031 }
01032 } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
01033 midi->sysex_in_progress = FALSE;
01034 }
01035 }
01036 }
01037
01038
01039
01040
01041
01042 unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data,
01043 int len, PmTimestamp timestamp)
01044 {
01045 int i = 0;
01046 PmEvent event;
01047 event.timestamp = timestamp;
01048 assert(midi);
01049
01050
01051
01052
01053
01054 if (len == 0) return 0;
01055 if (!midi->sysex_in_progress) {
01056 while (i < len) {
01057 unsigned char byte = data[i++];
01058 if (byte == MIDI_SYSEX &&
01059 !pm_realtime_filtered(byte, midi->filters)) {
01060 midi->sysex_in_progress = TRUE;
01061 i--;
01062 break;
01063 } else if (byte == MIDI_EOX) {
01064 midi->sysex_in_progress = FALSE;
01065 return i;
01066 } else if (byte & MIDI_STATUS_MASK) {
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076 event.message = byte;
01077 pm_read_short(midi, &event);
01078 }
01079 }
01080 }
01081
01082
01083
01084
01085 while (i < len && midi->sysex_in_progress) {
01086 if (midi->sysex_message_count == 0 && i <= len - 4 &&
01087 ((event.message = (((PmMessage) data[i]) |
01088 (((PmMessage) data[i+1]) << 8) |
01089 (((PmMessage) data[i+2]) << 16) |
01090 (((PmMessage) data[i+3]) << 24))) &
01091 0x80808080) == 0) {
01092 if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
01093 midi->sysex_in_progress = FALSE;
01094 }
01095 i += 4;
01096 } else {
01097 while (i < len) {
01098
01099 unsigned char byte = data[i++];
01100 if (is_real_time(byte) &&
01101 pm_realtime_filtered(byte, midi->filters)) {
01102 continue;
01103 }
01104 midi->sysex_message |=
01105 (byte << (8 * midi->sysex_message_count++));
01106 if (byte == MIDI_EOX) {
01107 midi->sysex_in_progress = FALSE;
01108 pm_flush_sysex(midi, event.timestamp);
01109 return i;
01110 } else if (midi->sysex_message_count == 4) {
01111 pm_flush_sysex(midi, event.timestamp);
01112
01113
01114
01115
01116 break;
01117 }
01118 }
01119 }
01120 }
01121 return i;
01122 }
01123
01124