00001 #include "stdlib.h"
00002 #include "string.h"
00003 #include "portmidi.h"
00004 #include "porttime.h"
00005 #include "pmutil.h"
00006 #include "pminternal.h"
00007 #include <assert.h>
00008
00009 #define MIDI_CLOCK 0xf8
00010 #define MIDI_ACTIVE 0xfe
00011 #define MIDI_STATUS_MASK 0x80
00012 #define MIDI_SYSEX 0xf0
00013 #define MIDI_EOX 0xf7
00014 #define MIDI_START 0xFA
00015 #define MIDI_STOP 0xFC
00016 #define MIDI_CONTINUE 0xFB
00017 #define MIDI_F9 0xF9
00018 #define MIDI_FD 0xFD
00019 #define MIDI_RESET 0xFF
00020 #define MIDI_NOTE_ON 0x90
00021 #define MIDI_NOTE_OFF 0x80
00022 #define MIDI_CHANNEL_AT 0xD0
00023 #define MIDI_POLY_AT 0xA0
00024 #define MIDI_PROGRAM 0xC0
00025 #define MIDI_CONTROL 0xB0
00026 #define MIDI_PITCHBEND 0xE0
00027 #define MIDI_MTC 0xF1
00028 #define MIDI_SONGPOS 0xF2
00029 #define MIDI_SONGSEL 0xF3
00030 #define MIDI_TUNE 0xF6
00031
00032 #define is_empty(midi) ((midi)->tail == (midi)->head)
00033
00034
00035
00036
00037 int pm_initialized = FALSE;
00038
00039 int pm_hosterror;
00040 char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
00041
00042 #ifdef PM_CHECK_ERRORS
00043
00044 #include <stdio.h>
00045
00046 #define STRING_MAX 80
00047
00048 static void prompt_and_exit(void)
00049 {
00050 char line[STRING_MAX];
00051 printf("type ENTER...");
00052 fgets(line, STRING_MAX, stdin);
00053
00054 exit(-1);
00055 }
00056
00057
00058 static PmError pm_errmsg(PmError err)
00059 {
00060 if (err == pmHostError) {
00061
00062
00063
00064 printf("PortMidi found host error...\n %s\n", pm_hosterror_text);
00065 pm_hosterror = FALSE;
00066 pm_hosterror_text[0] = 0;
00067 prompt_and_exit();
00068 } else if (err < 0) {
00069 printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
00070 prompt_and_exit();
00071 }
00072 return err;
00073 }
00074 #else
00075 #define pm_errmsg(err) err
00076 #endif
00077
00078
00079
00080
00081
00082
00083
00084 int pm_descriptor_max = 0;
00085 int pm_descriptor_index = 0;
00086 descriptor_type descriptors = NULL;
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 PmError pm_add_device(char *interf, char *name, int input,
00098 void *descriptor, pm_fns_type dictionary) {
00099 if (pm_descriptor_index >= pm_descriptor_max) {
00100
00101 descriptor_type new_descriptors = (descriptor_type)
00102 pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
00103 if (!new_descriptors) return pmInsufficientMemory;
00104 if (descriptors) {
00105 memcpy(new_descriptors, descriptors,
00106 sizeof(descriptor_node) * pm_descriptor_max);
00107 free(descriptors);
00108 }
00109 pm_descriptor_max += 32;
00110 descriptors = new_descriptors;
00111 }
00112 descriptors[pm_descriptor_index].pub.interf = interf;
00113 descriptors[pm_descriptor_index].pub.name = name;
00114 descriptors[pm_descriptor_index].pub.input = input;
00115 descriptors[pm_descriptor_index].pub.output = !input;
00116
00117
00118 descriptors[pm_descriptor_index].pub.opened = FALSE;
00119
00120
00121 descriptors[pm_descriptor_index].descriptor = descriptor;
00122
00123
00124 descriptors[pm_descriptor_index].internalDescriptor = NULL;
00125
00126 descriptors[pm_descriptor_index].dictionary = dictionary;
00127
00128 pm_descriptor_index++;
00129
00130 return pmNoError;
00131 }
00132
00133
00134
00135
00136
00137 int pm_find_default_device(char *pattern, int is_input)
00138 {
00139 int id = pmNoDevice;
00140 int i;
00141
00142 char *interf_pref = "";
00143 char *name_pref = strstr(pattern, ", ");
00144
00145 if (name_pref) {
00146 interf_pref = pattern;
00147 name_pref[0] = 0;
00148 name_pref += 2;
00149 } else {
00150 name_pref = pattern;
00151 }
00152 for (i = 0; i < pm_descriptor_index; i++) {
00153 const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
00154 if (info->input == is_input &&
00155 strstr(info->name, name_pref) &&
00156 strstr(info->interf, interf_pref)) {
00157 id = i;
00158 break;
00159 }
00160 }
00161 return id;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171 int Pm_CountDevices( void ) {
00172 Pm_Initialize();
00173
00174 return pm_descriptor_index;
00175 }
00176
00177
00178 const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
00179 Pm_Initialize();
00180 if (id >= 0 && id < pm_descriptor_index) {
00181 return &descriptors[id].pub;
00182 }
00183 return NULL;
00184 }
00185
00186
00187 PmError pm_success_fn(PmInternal *midi) {
00188 return pmNoError;
00189 }
00190
00191
00192 PmError none_write_short(PmInternal *midi, PmEvent *buffer) {
00193 return pmBadPtr;
00194 }
00195
00196
00197 PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp) {
00198 return pmBadPtr;
00199 }
00200
00201 PmError none_write_byte(PmInternal *midi, unsigned char byte,
00202 PmTimestamp timestamp) {
00203 return pmBadPtr;
00204 }
00205
00206
00207 PmError pm_fail_fn(PmInternal *midi) {
00208 return pmBadPtr;
00209 }
00210
00211 static PmError none_open(PmInternal *midi, void *driverInfo) {
00212 return pmBadPtr;
00213 }
00214 static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) {
00215 strcpy(msg, "");
00216 }
00217 static unsigned int none_has_host_error(PmInternal * midi) {
00218 return FALSE;
00219 }
00220 PmTimestamp none_synchronize(PmInternal *midi) {
00221 return 0;
00222 }
00223
00224 #define none_abort pm_fail_fn
00225 #define none_close pm_fail_fn
00226
00227 pm_fns_node pm_none_dictionary = {
00228 none_write_short,
00229 none_sysex,
00230 none_sysex,
00231 none_write_byte,
00232 none_write_short,
00233 none_write_flush,
00234 none_synchronize,
00235 none_open,
00236 none_abort,
00237 none_close,
00238 none_poll,
00239 none_has_host_error,
00240 none_get_host_error
00241 };
00242
00243
00244 const char *Pm_GetErrorText( PmError errnum ) {
00245 const char *msg;
00246
00247 switch(errnum)
00248 {
00249 case pmNoError:
00250 msg = "";
00251 break;
00252 case pmHostError:
00253 msg = "PortMidi: `Host error'";
00254 break;
00255 case pmInvalidDeviceId:
00256 msg = "PortMidi: `Invalid device ID'";
00257 break;
00258 case pmInsufficientMemory:
00259 msg = "PortMidi: `Insufficient memory'";
00260 break;
00261 case pmBufferTooSmall:
00262 msg = "PortMidi: `Buffer too small'";
00263 break;
00264 case pmBadPtr:
00265 msg = "PortMidi: `Bad pointer'";
00266 break;
00267 case pmInternalError:
00268 msg = "PortMidi: `Internal PortMidi Error'";
00269 break;
00270 case pmBufferOverflow:
00271 msg = "PortMidi: `Buffer overflow'";
00272 break;
00273 case pmBadData:
00274 msg = "PortMidi: `Invalid MIDI message Data'";
00275 break;
00276 case pmBufferMaxSize:
00277 msg = "PortMidi: `Buffer cannot be made larger'";
00278 break;
00279 default:
00280 msg = "PortMidi: `Illegal error number'";
00281 break;
00282 }
00283 return msg;
00284 }
00285
00286
00287
00288
00289
00290 void Pm_GetHostErrorText(char * msg, unsigned int len) {
00291 assert(msg);
00292 assert(len > 0);
00293 if (pm_hosterror) {
00294 strncpy(msg, (char *) pm_hosterror_text, len);
00295 pm_hosterror = FALSE;
00296 pm_hosterror_text[0] = 0;
00297
00298 msg[len - 1] = 0;
00299 } else {
00300 msg[0] = 0;
00301 }
00302 }
00303
00304
00305 int Pm_HasHostError(PortMidiStream * stream) {
00306 if (pm_hosterror) return TRUE;
00307 if (stream) {
00308 PmInternal * midi = (PmInternal *) stream;
00309 pm_hosterror = (*midi->dictionary->has_host_error)(midi);
00310 if (pm_hosterror) {
00311 midi->dictionary->host_error(midi, pm_hosterror_text,
00312 PM_HOST_ERROR_MSG_LEN);
00313
00314 return TRUE;
00315 }
00316 }
00317 return FALSE;
00318 }
00319
00320
00321 PmError Pm_Initialize( void ) {
00322 if (!pm_initialized) {
00323 pm_hosterror = FALSE;
00324 pm_hosterror_text[0] = 0;
00325 pm_init();
00326 pm_initialized = TRUE;
00327 }
00328 return pmNoError;
00329 }
00330
00331
00332 PmError Pm_Terminate( void ) {
00333 if (pm_initialized) {
00334 pm_term();
00335
00336 if (descriptors != NULL) {
00337 free(descriptors);
00338 descriptors = NULL;
00339 }
00340 pm_descriptor_index = 0;
00341 pm_descriptor_max = 0;
00342 pm_initialized = FALSE;
00343 }
00344 return pmNoError;
00345 }
00346
00347
00348
00349
00350
00351
00352 int Pm_Read(PortMidiStream *stream, PmEvent *buffer, long length) {
00353 PmInternal *midi = (PmInternal *) stream;
00354 int n = 0;
00355 PmError err = pmNoError;
00356 pm_hosterror = FALSE;
00357
00358 if(midi == NULL)
00359 err = pmBadPtr;
00360 else if(!descriptors[midi->device_id].pub.opened)
00361 err = pmBadPtr;
00362 else if(!descriptors[midi->device_id].pub.input)
00363 err = pmBadPtr;
00364
00365
00366
00367
00368
00369 else err = (*(midi->dictionary->poll))(midi);
00370
00371 if (err != pmNoError) {
00372 if (err == pmHostError) {
00373 midi->dictionary->host_error(midi, pm_hosterror_text,
00374 PM_HOST_ERROR_MSG_LEN);
00375 pm_hosterror = TRUE;
00376 }
00377 return pm_errmsg(err);
00378 }
00379
00380 while (n < length) {
00381 PmError err = Pm_Dequeue(midi->queue, buffer++);
00382 if (err == pmBufferOverflow) {
00383
00384 return pm_errmsg(pmBufferOverflow);
00385 } else if (err == 0) {
00386 break;
00387 }
00388 n++;
00389 }
00390 return n;
00391 }
00392
00393 PmError Pm_Poll( PortMidiStream *stream )
00394 {
00395 PmInternal *midi = (PmInternal *) stream;
00396 PmError err;
00397
00398 pm_hosterror = FALSE;
00399
00400 if(midi == NULL)
00401 err = pmBadPtr;
00402 else if (!descriptors[midi->device_id].pub.opened)
00403 err = pmBadPtr;
00404 else if (!descriptors[midi->device_id].pub.input)
00405 err = pmBadPtr;
00406 else
00407 err = (*(midi->dictionary->poll))(midi);
00408
00409 if (err != pmNoError) {
00410 if (err == pmHostError) {
00411 midi->dictionary->host_error(midi, pm_hosterror_text,
00412 PM_HOST_ERROR_MSG_LEN);
00413 pm_hosterror = TRUE;
00414 }
00415 return pm_errmsg(err);
00416 }
00417
00418 return !Pm_QueueEmpty(midi->queue);
00419 }
00420
00421
00422
00423
00424
00425
00426 static PmError pm_end_sysex(PmInternal *midi)
00427 {
00428 PmError err = (*midi->dictionary->end_sysex)(midi, 0);
00429 midi->sysex_in_progress = FALSE;
00430 if (err == pmHostError) {
00431 midi->dictionary->host_error(midi, pm_hosterror_text,
00432 PM_HOST_ERROR_MSG_LEN);
00433 pm_hosterror = TRUE;
00434 }
00435 return err;
00436 }
00437
00438
00439
00440
00441
00442
00443 PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
00444 {
00445 PmInternal *midi = (PmInternal *) stream;
00446 PmError err = pmNoError;
00447 int i;
00448 int bits;
00449
00450 pm_hosterror = FALSE;
00451
00452 if(midi == NULL)
00453 err = pmBadPtr;
00454 else if(!descriptors[midi->device_id].pub.opened)
00455 err = pmBadPtr;
00456 else if(!descriptors[midi->device_id].pub.output)
00457 err = pmBadPtr;
00458 else
00459 err = pmNoError;
00460
00461 if (err != pmNoError) goto pm_write_error;
00462
00463 if (midi->latency == 0) {
00464 midi->now = 0;
00465 } else {
00466 midi->now = (*(midi->time_proc))(midi->time_info);
00467 if (midi->first_message || midi->sync_time + 100 < midi->now) {
00468
00469 midi->now = (*midi->dictionary->synchronize)(midi);
00470 midi->first_message = FALSE;
00471 }
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 for (i = 0; i < length; i++) {
00487 unsigned long msg = buffer[i].message;
00488 bits = 0;
00489
00490 if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
00491 if (midi->sysex_in_progress) {
00492
00493 midi->sysex_in_progress = FALSE;
00494 err = pmBadData;
00495 goto pm_write_error;
00496 }
00497 midi->sysex_in_progress = TRUE;
00498 if ((err = (*midi->dictionary->begin_sysex)(midi,
00499 buffer[i].timestamp)) != pmNoError)
00500 goto pm_write_error;
00501 if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
00502 buffer[i].timestamp)) != pmNoError)
00503 goto pm_write_error;
00504 bits = 8;
00505
00506 } else if ((msg & MIDI_STATUS_MASK) &&
00507 (Pm_MessageStatus(msg) != MIDI_EOX)) {
00508
00509 if (midi->sysex_in_progress) {
00510
00511 if (is_real_time(msg)) {
00512 if ((err = (*midi->dictionary->write_realtime)(midi,
00513 &(buffer[i]))) != pmNoError)
00514 goto pm_write_error;
00515 } else {
00516 midi->sysex_in_progress = FALSE;
00517 err = pmBadData;
00518
00519
00520 (*midi->dictionary->end_sysex)(midi, 0);
00521 goto pm_write_error;
00522 }
00523 } else {
00524 if ((err = (*midi->dictionary->write_short)(midi,
00525 &(buffer[i]))) != pmNoError)
00526 goto pm_write_error;
00527 continue;
00528 }
00529 }
00530 if (midi->sysex_in_progress) {
00531
00532 if (bits == 0 && midi->fill_base &&
00533 (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
00534 (msg & 0x80808080) == 0) {
00535
00536 unsigned char *ptr = midi->fill_base +
00537 *(midi->fill_offset_ptr);
00538 ptr[0] = msg; ptr[1] = msg >> 8;
00539 ptr[2] = msg >> 18; ptr[3] = msg >> 24;
00540 (*midi->fill_offset_ptr) += 4;
00541 continue;
00542 }
00543
00544 while (bits < 32) {
00545 unsigned char midi_byte = (unsigned char) (msg >> bits);
00546 if ((err = (*midi->dictionary->write_byte)(midi, midi_byte,
00547 buffer[i].timestamp)) != pmNoError)
00548 goto pm_write_error;
00549 if (midi_byte == MIDI_EOX) {
00550 err = pm_end_sysex(midi);
00551 if (err != pmNoError) goto error_exit;
00552 break;
00553 }
00554 bits += 8;
00555 }
00556 } else {
00557
00558 err = pmBadData;
00559 goto pm_write_error;
00560 }
00561 }
00562
00563 if (!midi->sysex_in_progress)
00564 err = (*midi->dictionary->write_flush)(midi, 0);
00565 pm_write_error:
00566 if (err == pmHostError) {
00567 midi->dictionary->host_error(midi, pm_hosterror_text,
00568 PM_HOST_ERROR_MSG_LEN);
00569 pm_hosterror = TRUE;
00570 }
00571 error_exit:
00572 return pm_errmsg(err);
00573 }
00574
00575
00576 PmError Pm_WriteShort(PortMidiStream *stream, long when, long msg)
00577 {
00578 PmEvent event;
00579
00580 event.timestamp = when;
00581 event.message = msg;
00582 return Pm_Write(stream, &event, 1);
00583 }
00584
00585
00586 PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
00587 unsigned char *msg)
00588 {
00589
00590
00591 #define BUFLEN (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage))
00592 PmEvent buffer[BUFLEN];
00593 int buffer_size = 1;
00594 PmInternal *midi = (PmInternal *) stream;
00595
00596
00597 int shift = 0;
00598 int bufx = 0;
00599 buffer[0].message = 0;
00600 buffer[0].timestamp = when;
00601
00602 while (1) {
00603
00604 buffer[bufx].message |= ((*msg) << shift);
00605 shift += 8;
00606 if (*msg++ == MIDI_EOX) break;
00607 if (shift == 32) {
00608 shift = 0;
00609 bufx++;
00610 if (bufx == buffer_size) {
00611 PmError err = Pm_Write(stream, buffer, buffer_size);
00612
00613 if (err) return err;
00614
00615 bufx = 0;
00616 buffer_size = BUFLEN;
00617
00618 if (midi->fill_base) {
00619 PmError err;
00620 while (*(midi->fill_offset_ptr) < midi->fill_length) {
00621 midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
00622 if (*msg++ == MIDI_EOX) {
00623 err = pm_end_sysex(midi);
00624 if (err != pmNoError) return pm_errmsg(err);
00625 goto end_of_sysex;
00626 }
00627 }
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 buffer_size = 1;
00643 }
00644 }
00645 buffer[bufx].message = 0;
00646 buffer[bufx].timestamp = when;
00647 }
00648
00649 }
00650 end_of_sysex:
00651
00652
00653
00654 if (shift != 0) bufx++;
00655 if (bufx) {
00656 PmError err = Pm_Write(stream, buffer, bufx);
00657 if (err) return err;
00658 }
00659 return pmNoError;
00660 }
00661
00662
00663
00664 PmError Pm_OpenInput(PortMidiStream** stream,
00665 PmDeviceID inputDevice,
00666 void *inputDriverInfo,
00667 long bufferSize,
00668 PmTimeProcPtr time_proc,
00669 void *time_info)
00670 {
00671 PmInternal *midi;
00672 PmError err = pmNoError;
00673 pm_hosterror = FALSE;
00674 *stream = NULL;
00675
00676
00677 if (inputDevice < 0 || inputDevice >= pm_descriptor_index)
00678 err = pmInvalidDeviceId;
00679 else if (!descriptors[inputDevice].pub.input)
00680 err = pmInvalidDeviceId;
00681 else if(descriptors[inputDevice].pub.opened)
00682 err = pmInvalidDeviceId;
00683
00684 if (err != pmNoError)
00685 goto error_return;
00686
00687
00688 midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
00689 *stream = midi;
00690 if (!midi) {
00691 err = pmInsufficientMemory;
00692 goto error_return;
00693 }
00694 midi->device_id = inputDevice;
00695 midi->write_flag = FALSE;
00696 midi->time_proc = time_proc;
00697 midi->time_info = time_info;
00698
00699
00700
00701
00702
00703 if (bufferSize <= 0) bufferSize = 256;
00704 midi->queue = Pm_QueueCreate(bufferSize, sizeof(PmEvent));
00705 if (!midi->queue) {
00706
00707 *stream = NULL;
00708 pm_free(midi);
00709 err = pmInsufficientMemory;
00710 goto error_return;
00711 }
00712 midi->buffer_len = bufferSize;
00713 midi->latency = 0;
00714 midi->sysex_in_progress = FALSE;
00715 midi->sysex_message = 0;
00716 midi->sysex_message_count = 0;
00717 midi->filters = PM_FILT_ACTIVE;
00718 midi->channel_mask = 0xFFFF;
00719 midi->sync_time = 0;
00720 midi->first_message = TRUE;
00721 midi->dictionary = descriptors[inputDevice].dictionary;
00722 midi->fill_base = NULL;
00723 midi->fill_offset_ptr = NULL;
00724 midi->fill_length = 0;
00725 descriptors[inputDevice].internalDescriptor = midi;
00726
00727 err = (*midi->dictionary->open)(midi, inputDriverInfo);
00728 if (err) {
00729 *stream = NULL;
00730 descriptors[inputDevice].internalDescriptor = NULL;
00731
00732 Pm_QueueDestroy(midi->queue);
00733 pm_free(midi);
00734 } else {
00735
00736 descriptors[inputDevice].pub.opened = TRUE;
00737 }
00738 error_return:
00739
00740
00741
00742
00743 return pm_errmsg(err);
00744 }
00745
00746
00747 PmError Pm_OpenOutput(PortMidiStream** stream,
00748 PmDeviceID outputDevice,
00749 void *outputDriverInfo,
00750 long bufferSize,
00751 PmTimeProcPtr time_proc,
00752 void *time_info,
00753 long latency )
00754 {
00755 PmInternal *midi;
00756 PmError err = pmNoError;
00757 pm_hosterror = FALSE;
00758 *stream = NULL;
00759
00760
00761 if (outputDevice < 0 || outputDevice >= pm_descriptor_index)
00762 err = pmInvalidDeviceId;
00763 else if (!descriptors[outputDevice].pub.output)
00764 err = pmInvalidDeviceId;
00765 else if (descriptors[outputDevice].pub.opened)
00766 err = pmInvalidDeviceId;
00767 if (err != pmNoError)
00768 goto error_return;
00769
00770
00771 midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
00772 *stream = midi;
00773 if (!midi) {
00774 err = pmInsufficientMemory;
00775 goto error_return;
00776 }
00777 midi->device_id = outputDevice;
00778 midi->write_flag = TRUE;
00779 midi->time_proc = time_proc;
00780
00781
00782 if (time_proc == NULL && latency != 0) {
00783 if (!Pt_Started())
00784 Pt_Start(1, 0, 0);
00785
00786 midi->time_proc = (PmTimeProcPtr) Pt_Time;
00787 }
00788 midi->time_info = time_info;
00789 midi->buffer_len = bufferSize;
00790 midi->queue = NULL;
00791
00792
00793 if (latency < 0) latency = 0;
00794 midi->latency = latency;
00795 midi->sysex_in_progress = FALSE;
00796 midi->sysex_message = 0;
00797 midi->sysex_message_count = 0;
00798 midi->filters = 0;
00799 midi->channel_mask = 0xFFFF;
00800 midi->sync_time = 0;
00801 midi->first_message = TRUE;
00802 midi->dictionary = descriptors[outputDevice].dictionary;
00803 midi->fill_base = NULL;
00804 midi->fill_offset_ptr = NULL;
00805 midi->fill_length = 0;
00806 descriptors[outputDevice].internalDescriptor = midi;
00807
00808 err = (*midi->dictionary->open)(midi, outputDriverInfo);
00809 if (err) {
00810 *stream = NULL;
00811 descriptors[outputDevice].internalDescriptor = NULL;
00812
00813 pm_free(midi);
00814 } else {
00815
00816 descriptors[outputDevice].pub.opened = TRUE;
00817 }
00818 error_return:
00819
00820
00821
00822 return pm_errmsg(err);
00823 }
00824
00825
00826 PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
00827 {
00828 PmInternal *midi = (PmInternal *) stream;
00829 PmError err = pmNoError;
00830
00831 if (midi == NULL)
00832 err = pmBadPtr;
00833 else
00834 midi->channel_mask = mask;
00835
00836 return pm_errmsg(err);
00837 }
00838
00839
00840 PmError Pm_SetFilter(PortMidiStream *stream, long filters) {
00841 PmInternal *midi = (PmInternal *) stream;
00842 PmError err = pmNoError;
00843
00844
00845 if (midi == NULL)
00846 err = pmBadPtr;
00847 else if (!descriptors[midi->device_id].pub.opened)
00848 err = pmBadPtr;
00849 else
00850 midi->filters = filters;
00851 return pm_errmsg(err);
00852 }
00853
00854
00855 PmError Pm_Close( PortMidiStream *stream ) {
00856 PmInternal *midi = (PmInternal *) stream;
00857 PmError err = pmNoError;
00858
00859 pm_hosterror = FALSE;
00860
00861 if (midi == NULL)
00862 err = pmBadPtr;
00863
00864 else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index)
00865 err = pmBadPtr;
00866
00867 else if (!descriptors[midi->device_id].pub.opened)
00868 err = pmBadPtr;
00869
00870 if (err != pmNoError)
00871 goto error_return;
00872
00873
00874 err = (*midi->dictionary->close)(midi);
00875
00876 descriptors[midi->device_id].internalDescriptor = NULL;
00877 descriptors[midi->device_id].pub.opened = FALSE;
00878 if (midi->queue) Pm_QueueDestroy(midi->queue);
00879 pm_free(midi);
00880 error_return:
00881
00882
00883
00884 return pm_errmsg(err);
00885 }
00886
00887
00888 PmError Pm_Abort( PortMidiStream* stream ) {
00889 PmInternal *midi = (PmInternal *) stream;
00890 PmError err;
00891
00892 if (midi == NULL)
00893 err = pmBadPtr;
00894 else if (!descriptors[midi->device_id].pub.output)
00895 err = pmBadPtr;
00896 else if (!descriptors[midi->device_id].pub.opened)
00897 err = pmBadPtr;
00898 else
00899 err = (*midi->dictionary->abort)(midi);
00900
00901 if (err == pmHostError) {
00902 midi->dictionary->host_error(midi, pm_hosterror_text,
00903 PM_HOST_ERROR_MSG_LEN);
00904 pm_hosterror = TRUE;
00905 }
00906 return pm_errmsg(err);
00907 }
00908
00909
00910
00911
00912 #define pm_channel_filtered(status, mask) \
00913 ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925 #define pm_realtime_filtered(status, filters) \
00926 ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949 #define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters))
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964 static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
00965 {
00966 PmEvent event;
00967
00968
00969 if (midi->sysex_message_count == 0) return;
00970
00971 event.message = midi->sysex_message;
00972 event.timestamp = timestamp;
00973
00974 if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
00975 midi->sysex_in_progress = FALSE;
00976 }
00977 midi->sysex_message_count = 0;
00978 midi->sysex_message = 0;
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997 void pm_read_short(PmInternal *midi, PmEvent *event)
00998 {
00999 int status;
01000
01001 assert(midi != NULL);
01002
01003 status = Pm_MessageStatus(event->message);
01004 if (!pm_status_filtered(status, midi->filters)
01005 && (!is_real_time(status) ||
01006 !pm_realtime_filtered(status, midi->filters))
01007 && !pm_channel_filtered(status, midi->channel_mask)) {
01008
01009
01010
01011
01012 if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
01013
01014
01015
01016
01017 if (is_real_time(status)) {
01018 midi->sysex_message |=
01019 (status << (8 * midi->sysex_message_count++));
01020 if (midi->sysex_message_count == 4) {
01021 pm_flush_sysex(midi, event->timestamp);
01022 }
01023 } else {
01024
01025 midi->sysex_in_progress = FALSE;
01026 }
01027 } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
01028 midi->sysex_in_progress = FALSE;
01029 }
01030 }
01031 }
01032
01033
01034
01035
01036
01037 unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data,
01038 int len, PmTimestamp timestamp)
01039 {
01040 int i = 0;
01041 PmEvent event;
01042 event.timestamp = timestamp;
01043 assert(midi);
01044
01045
01046
01047
01048
01049 if (len == 0) return 0;
01050 if (!midi->sysex_in_progress) {
01051 while (i < len) {
01052 unsigned char byte = data[i++];
01053 if (byte == MIDI_SYSEX &&
01054 !pm_realtime_filtered(byte, midi->filters)) {
01055 midi->sysex_in_progress = TRUE;
01056 i--;
01057 break;
01058 } else if (byte == MIDI_EOX) {
01059 midi->sysex_in_progress = FALSE;
01060 return i;
01061 } else if (byte & MIDI_STATUS_MASK) {
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 event.message = byte;
01072 pm_read_short(midi, &event);
01073 }
01074 }
01075 }
01076
01077
01078
01079
01080 while (i < len && midi->sysex_in_progress) {
01081 if (midi->sysex_message_count == 0 && i <= len - 4 &&
01082 ((event.message = (((long) data[i]) |
01083 (((long) data[i+1]) << 8) |
01084 (((long) data[i+2]) << 16) |
01085 (((long) data[i+3]) << 24))) &
01086 0x80808080) == 0) {
01087 if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
01088 midi->sysex_in_progress = FALSE;
01089 }
01090 i += 4;
01091 } else {
01092 while (i < len) {
01093
01094 unsigned char byte = data[i++];
01095 if (is_real_time(byte) &&
01096 pm_realtime_filtered(byte, midi->filters)) {
01097 continue;
01098 }
01099 midi->sysex_message |=
01100 (byte << (8 * midi->sysex_message_count++));
01101 if (byte == MIDI_EOX) {
01102 midi->sysex_in_progress = FALSE;
01103 pm_flush_sysex(midi, event.timestamp);
01104 return i;
01105 } else if (midi->sysex_message_count == 4) {
01106 pm_flush_sysex(midi, event.timestamp);
01107
01108
01109
01110
01111 break;
01112 }
01113 }
01114 }
01115 }
01116 return i;
01117 }
01118
01119