portmidi/0000755000000000000000000000000011453601074011404 5ustar rootrootportmidi/pm_test/0000755000000000000000000000000011453601074013057 5ustar rootrootportmidi/pm_test/qtest.vcproj0000755000000000000000000001125711274243554015463 0ustar rootroot portmidi/pm_test/midithread.c0000755000000000000000000002673411254141714015353 0ustar rootroot/* midithread.c -- example program showing how to do midi processing in a preemptive thread Notes: if you handle midi I/O from your main program, there will be some delay before handling midi messages whenever the program is doing something like file I/O, graphical interface updates, etc. To handle midi with minimal delay, you should do all midi processing in a separate, high priority thread. A convenient way to get a high priority thread in windows is to use the timer callback provided by the PortTime library. That is what we show here. If the high priority thread writes to a file, prints to the console, or does just about anything other than midi processing, this may create delays, so all this processing should be off-loaded to the "main" process or thread. Communication between threads can be tricky. If one thread is writing at the same time the other is reading, very tricky race conditions can arise, causing programs to behave incorrectly, but only under certain timing conditions -- a terrible thing to debug. Advanced programmers know this as a synchronization problem. See any operating systems textbook for the complete story. To avoid synchronization problems, a simple, reliable approach is to communicate via messages. PortMidi offers a message queue as a datatype, and operations to insert and remove messages. Use two queues as follows: midi_to_main transfers messages from the midi thread to the main thread, and main_to_midi transfers messages from the main thread to the midi thread. Queues are safe for use between threads as long as ONE thread writes and ONE thread reads. You must NEVER allow two threads to write to the same queue. This program transposes incoming midi data by an amount controlled by the main program. To change the transposition, type an integer followed by return. The main program sends this via a message queue to the midi thread. To quit, type 'q' followed by return. The midi thread can also send a pitch to the main program on request. Type 'm' followed by return to wait for the next midi message and print the pitch. This program illustrates: Midi processing in a high-priority thread. Communication with a main process via message queues. */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "assert.h" #include "portmidi.h" #include "pmutil.h" #include "porttime.h" /* if INPUT_BUFFER_SIZE is 0, PortMidi uses a default value */ #define INPUT_BUFFER_SIZE 0 #define OUTPUT_BUFFER_SIZE 100 #define DRIVER_INFO NULL #define TIME_PROC NULL #define TIME_INFO NULL /* use zero latency because we want output to be immediate */ #define LATENCY 0 #define STRING_MAX 80 /**********************************/ /* DATA USED ONLY BY process_midi */ /* (except during initialization) */ /**********************************/ int active = FALSE; int monitor = FALSE; int midi_thru = TRUE; int transpose; PmStream *midi_in; PmStream *midi_out; /****************************/ /* END OF process_midi DATA */ /****************************/ /* shared queues */ PmQueue *midi_to_main; PmQueue *main_to_midi; #define QUIT_MSG 1000 #define MONITOR_MSG 1001 #define THRU_MSG 1002 /* timer interrupt for processing midi data */ void process_midi(PtTimestamp timestamp, void *userData) { PmError result; PmEvent buffer; /* just one message at a time */ int32_t msg; /* do nothing until initialization completes */ if (!active) return; /* check for messages */ do { result = Pm_Dequeue(main_to_midi, &msg); if (result) { if (msg >= -127 && msg <= 127) transpose = msg; else if (msg == QUIT_MSG) { /* acknowledge receipt of quit message */ Pm_Enqueue(midi_to_main, &msg); active = FALSE; return; } else if (msg == MONITOR_MSG) { /* main has requested a pitch. monitor is a flag that * records the request: */ monitor = TRUE; } else if (msg == THRU_MSG) { /* toggle Thru on or off */ midi_thru = !midi_thru; } } } while (result); /* see if there is any midi input to process */ do { result = Pm_Poll(midi_in); if (result) { int status, data1, data2; if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) continue; if (midi_thru) Pm_Write(midi_out, &buffer, 1); /* unless there was overflow, we should have a message now */ status = Pm_MessageStatus(buffer.message); data1 = Pm_MessageData1(buffer.message); data2 = Pm_MessageData2(buffer.message); if ((status & 0xF0) == 0x90 || (status & 0xF0) == 0x80) { /* this is a note-on or note-off, so transpose and send */ data1 += transpose; /* keep within midi pitch range, keep proper pitch class */ while (data1 > 127) data1 -= 12; while (data1 < 0) data1 += 12; /* send the message */ buffer.message = Pm_Message(status, data1, data2); Pm_Write(midi_out, &buffer, 1); /* if monitor is set, send the pitch to the main thread */ if (monitor) { Pm_Enqueue(midi_to_main, &data1); monitor = FALSE; /* only send one pitch per request */ } } } } while (result); } void exit_with_message(char *msg) { char line[STRING_MAX]; printf("%s\n", msg); fgets(line, STRING_MAX, stdin); exit(1); } int main() { int id; int32_t n; const PmDeviceInfo *info; char line[STRING_MAX]; int spin; int done = FALSE; /* determine what type of test to run */ printf("begin PortMidi multithread test...\n"); /* note that it is safe to call PortMidi from the main thread for initialization and opening devices. You should not make any calls to PortMidi from this thread once the midi thread begins. to make PortMidi calls. */ /* make the message queues */ /* messages can be of any size and any type, but all messages in * a given queue must have the same size. We'll just use int32_t's * for our messages in this simple example */ midi_to_main = Pm_QueueCreate(32, sizeof(int32_t)); assert(midi_to_main != NULL); main_to_midi = Pm_QueueCreate(32, sizeof(int32_t)); assert(main_to_midi != NULL); /* a little test of enqueue and dequeue operations. Ordinarily, * you would call Pm_Enqueue from one thread and Pm_Dequeue from * the other. Since the midi thread is not running, this is safe. */ n = 1234567890; Pm_Enqueue(midi_to_main, &n); n = 987654321; Pm_Enqueue(midi_to_main, &n); Pm_Dequeue(midi_to_main, &n); if (n != 1234567890) { exit_with_message("Pm_Dequeue produced unexpected result."); } Pm_Dequeue(midi_to_main, &n); if(n != 987654321) { exit_with_message("Pm_Dequeue produced unexpected result."); } /* always start the timer before you start midi */ Pt_Start(1, &process_midi, 0); /* start a timer with millisecond accuracy */ /* the timer will call our function, process_midi() every millisecond */ Pm_Initialize(); id = Pm_GetDefaultOutputDeviceID(); info = Pm_GetDeviceInfo(id); if (info == NULL) { printf("Could not open default output device (%d).", id); exit_with_message(""); } printf("Opening output device %s %s\n", info->interf, info->name); /* use zero latency because we want output to be immediate */ Pm_OpenOutput(&midi_out, id, DRIVER_INFO, OUTPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO, LATENCY); id = Pm_GetDefaultInputDeviceID(); info = Pm_GetDeviceInfo(id); if (info == NULL) { printf("Could not open default input device (%d).", id); exit_with_message(""); } printf("Opening input device %s %s\n", info->interf, info->name); Pm_OpenInput(&midi_in, id, DRIVER_INFO, INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO); active = TRUE; /* enable processing in the midi thread -- yes, this is a shared variable without synchronization, but this simple assignment is safe */ printf("Enter midi input; it will be transformed as specified by...\n"); printf("%s\n%s\n%s\n", "Type 'q' to quit, 'm' to monitor next pitch, t to toggle thru or", "type a number to specify transposition.", "Must terminate with [ENTER]"); while (!done) { int32_t msg; int input; int len; fgets(line, STRING_MAX, stdin); /* remove the newline: */ len = strlen(line); if (len > 0) line[len - 1] = 0; /* overwrite the newline char */ if (strcmp(line, "q") == 0) { msg = QUIT_MSG; Pm_Enqueue(main_to_midi, &msg); /* wait for acknowlegement */ do { spin = Pm_Dequeue(midi_to_main, &msg); } while (spin == 0); /* spin */ ; done = TRUE; /* leave the command loop and wrap up */ } else if (strcmp(line, "m") == 0) { msg = MONITOR_MSG; Pm_Enqueue(main_to_midi, &msg); printf("Waiting for note...\n"); do { spin = Pm_Dequeue(midi_to_main, &msg); } while (spin == 0); /* spin */ ; // convert int32_t to long for safe printing printf("... pitch is %ld\n", (long) msg); } else if (strcmp(line, "t") == 0) { /* reading midi_thru asynchronously could give incorrect results, e.g. if you type "t" twice before the midi thread responds to the first one, but we'll do it this way anyway. Perhaps a more correct way would be to wait for an acknowledgement message containing the new state. */ printf("Setting THRU %s\n", (midi_thru ? "off" : "on")); msg = THRU_MSG; Pm_Enqueue(main_to_midi, &msg); } else if (sscanf(line, "%d", &input) == 1) { if (input >= -127 && input <= 127) { /* send transposition value, make sur */ printf("Transposing by %d\n", input); msg = (int32_t) input; Pm_Enqueue(main_to_midi, &msg); } else { printf("Transposition must be within -127...127\n"); } } else { printf("%s\n%s\n", "Type 'q[ENTER]' to quit, 'm[ENTER]' to monitor next pitch, or", "enter a number to specify transposition."); } } /* at this point, midi thread is inactive and we need to shut down * the midi input and output */ Pt_Stop(); /* stop the timer */ Pm_QueueDestroy(midi_to_main); Pm_QueueDestroy(main_to_midi); /* Belinda! if close fails here, some memory is deleted, right??? */ Pm_Close(midi_in); Pm_Close(midi_out); printf("finished portMidi multithread test...enter any character to quit [RETURN]..."); fgets(line, STRING_MAX, stdin); return 0; } portmidi/pm_test/midithru.vcproj0000755000000000000000000001132311274243554016142 0ustar rootroot portmidi/pm_test/mm.c0000755000000000000000000004565311452617306013660 0ustar rootroot/* mm.c -- midi monitor */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 7-Apr-86 | Created changelog * 31-Jan-90 | GWL : use new cmdline * 5-Apr-91 | JDW : Further changes * 16-Feb-92 | GWL : eliminate label mmexit:; add error recovery * 18-May-92 | GWL : continuous clocks, etc. * 17-Jan-94 | GWL : option to display notes * 20-Nov-06 | RBD : port mm.c from CMU Midi Toolkit to PortMidi * | mm.c -- revealing MIDI secrets for over 20 years! *****************************************************************************/ #include "stdlib.h" #include "ctype.h" #include "string.h" #include "stdio.h" #include "porttime.h" #include "portmidi.h" #define STRING_MAX 80 #define MIDI_CODE_MASK 0xf0 #define MIDI_CHN_MASK 0x0f /*#define MIDI_REALTIME 0xf8 #define MIDI_CHAN_MODE 0xfa */ #define MIDI_OFF_NOTE 0x80 #define MIDI_ON_NOTE 0x90 #define MIDI_POLY_TOUCH 0xa0 #define MIDI_CTRL 0xb0 #define MIDI_CH_PROGRAM 0xc0 #define MIDI_TOUCH 0xd0 #define MIDI_BEND 0xe0 #define MIDI_SYSEX 0xf0 #define MIDI_Q_FRAME 0xf1 #define MIDI_SONG_POINTER 0xf2 #define MIDI_SONG_SELECT 0xf3 #define MIDI_TUNE_REQ 0xf6 #define MIDI_EOX 0xf7 #define MIDI_TIME_CLOCK 0xf8 #define MIDI_START 0xfa #define MIDI_CONTINUE 0xfb #define MIDI_STOP 0xfc #define MIDI_ACTIVE_SENSING 0xfe #define MIDI_SYS_RESET 0xff #define MIDI_ALL_SOUND_OFF 0x78 #define MIDI_RESET_CONTROLLERS 0x79 #define MIDI_LOCAL 0x7a #define MIDI_ALL_OFF 0x7b #define MIDI_OMNI_OFF 0x7c #define MIDI_OMNI_ON 0x7d #define MIDI_MONO_ON 0x7e #define MIDI_POLY_ON 0x7f #define private static #ifndef false #define false 0 #define true 1 #endif typedef int boolean; int debug = false; /* never set, but referenced by userio.c */ PmStream *midi_in; /* midi input */ boolean active = false; /* set when midi_in is ready for reading */ boolean in_sysex = false; /* we are reading a sysex message */ boolean inited = false; /* suppress printing during command line parsing */ boolean done = false; /* when true, exit */ boolean notes = true; /* show notes? */ boolean controls = true; /* show continuous controllers */ boolean bender = true; /* record pitch bend etc.? */ boolean excldata = true; /* record system exclusive data? */ boolean verbose = true; /* show text representation? */ boolean realdata = true; /* record real time messages? */ boolean clksencnt = true; /* clock and active sense count on */ boolean chmode = true; /* show channel mode messages */ boolean pgchanges = true; /* show program changes */ boolean flush = false; /* flush all pending MIDI data */ uint32_t filter = 0; /* remember state of midi filter */ uint32_t clockcount = 0; /* count of clocks */ uint32_t actsensecount = 0; /* cout of active sensing bytes */ uint32_t notescount = 0; /* #notes since last request */ uint32_t notestotal = 0; /* total #notes */ char val_format[] = " Val %d\n"; /***************************************************************************** * Imported variables *****************************************************************************/ extern int abort_flag; /***************************************************************************** * Routines local to this module *****************************************************************************/ private void mmexit(int code); private void output(PmMessage data); private int put_pitch(int p); private void showhelp(); private void showbytes(PmMessage data, int len, boolean newline); private void showstatus(boolean flag); private void doascii(char c); private int get_number(char *prompt); /* read a number from console */ /**/ int get_number(char *prompt) { char line[STRING_MAX]; int n = 0, i; printf(prompt); while (n != 1) { n = scanf("%d", &i); fgets(line, STRING_MAX, stdin); } return i; } void receive_poll(PtTimestamp timestamp, void *userData) { PmEvent event; int count; if (!active) return; while ((count = Pm_Read(midi_in, &event, 1))) { if (count == 1) output(event.message); else printf(Pm_GetErrorText(count)); } } /**************************************************************************** * main * Effect: prompts for parameters, starts monitor ****************************************************************************/ int main(int argc, char **argv) { char *argument; int inp; PmError err; int i; if (argc > 1) { /* first arg can change defaults */ argument = argv[1]; while (*argument) doascii(*argument++); } showhelp(); /* use porttime callback to empty midi queue and print */ Pt_Start(1, receive_poll, 0); /* list device information */ printf("MIDI input devices:\n"); for (i = 0; i < Pm_CountDevices(); i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (info->input) printf("%d: %s, %s\n", i, info->interf, info->name); } inp = get_number("Type input device number: "); err = Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL); if (err) { printf(Pm_GetErrorText(err)); Pt_Stop(); mmexit(1); } Pm_SetFilter(midi_in, filter); inited = true; /* now can document changes, set filter */ printf("Midi Monitor ready.\n"); active = true; while (!done) { char s[100]; if (fgets(s, 100, stdin)) { doascii(s[0]); } } active = false; Pm_Close(midi_in); Pt_Stop(); Pm_Terminate(); mmexit(0); return 0; // make the compiler happy be returning a value } /**************************************************************************** * doascii * Inputs: * char c: input character * Effect: interpret to revise flags ****************************************************************************/ private void doascii(char c) { if (isupper(c)) c = tolower(c); if (c == 'q') done = true; else if (c == 'b') { bender = !bender; filter ^= PM_FILT_PITCHBEND; if (inited) printf("Pitch Bend, etc. %s\n", (bender ? "ON" : "OFF")); } else if (c == 'c') { controls = !controls; filter ^= PM_FILT_CONTROL; if (inited) printf("Control Change %s\n", (controls ? "ON" : "OFF")); } else if (c == 'h') { pgchanges = !pgchanges; filter ^= PM_FILT_PROGRAM; if (inited) printf("Program Changes %s\n", (pgchanges ? "ON" : "OFF")); } else if (c == 'n') { notes = !notes; filter ^= PM_FILT_NOTE; if (inited) printf("Notes %s\n", (notes ? "ON" : "OFF")); } else if (c == 'x') { excldata = !excldata; filter ^= PM_FILT_SYSEX; if (inited) printf("System Exclusive data %s\n", (excldata ? "ON" : "OFF")); } else if (c == 'r') { realdata = !realdata; filter ^= (PM_FILT_PLAY | PM_FILT_RESET | PM_FILT_TICK | PM_FILT_UNDEFINED); if (inited) printf("Real Time messages %s\n", (realdata ? "ON" : "OFF")); } else if (c == 'k') { clksencnt = !clksencnt; filter ^= PM_FILT_CLOCK; if (inited) printf("Clock and Active Sense Counting %s\n", (clksencnt ? "ON" : "OFF")); if (!clksencnt) clockcount = actsensecount = 0; } else if (c == 's') { if (clksencnt) { if (inited) printf("Clock Count %ld\nActive Sense Count %ld\n", (long) clockcount, (long) actsensecount); } else if (inited) { printf("Clock Counting not on\n"); } } else if (c == 't') { notestotal+=notescount; if (inited) printf("This Note Count %ld\nTotal Note Count %ld\n", (long) notescount, (long) notestotal); notescount=0; } else if (c == 'v') { verbose = !verbose; if (inited) printf("Verbose %s\n", (verbose ? "ON" : "OFF")); } else if (c == 'm') { chmode = !chmode; if (inited) printf("Channel Mode Messages %s", (chmode ? "ON" : "OFF")); } else { if (inited) { if (c == ' ') { PmEvent event; while (Pm_Read(midi_in, &event, 1)) ; /* flush midi input */ printf("...FLUSHED MIDI INPUT\n\n"); } else showhelp(); } } if (inited) Pm_SetFilter(midi_in, filter); } private void mmexit(int code) { /* if this is not being run from a console, maybe we should wait for * the user to read error messages before exiting */ exit(code); } /**************************************************************************** * output * Inputs: * data: midi message buffer holding one command or 4 bytes of sysex msg * Effect: format and print midi data ****************************************************************************/ char vel_format[] = " Vel %d\n"; private void output(PmMessage data) { int command; /* the current command */ int chan; /* the midi channel of the current event */ int len; /* used to get constant field width */ /* printf("output data %8x; ", data); */ command = Pm_MessageStatus(data) & MIDI_CODE_MASK; chan = Pm_MessageStatus(data) & MIDI_CHN_MASK; if (in_sysex || Pm_MessageStatus(data) == MIDI_SYSEX) { #define sysex_max 16 int i; PmMessage data_copy = data; in_sysex = true; /* look for MIDI_EOX in first 3 bytes * if realtime messages are embedded in sysex message, they will * be printed as if they are part of the sysex message */ for (i = 0; (i < 4) && ((data_copy & 0xFF) != MIDI_EOX); i++) data_copy >>= 8; if (i < 4) { in_sysex = false; i++; /* include the EOX byte in output */ } showbytes(data, i, verbose); if (verbose) printf("System Exclusive\n"); } else if (command == MIDI_ON_NOTE && Pm_MessageData2(data) != 0) { notescount++; if (notes) { showbytes(data, 3, verbose); if (verbose) { printf("NoteOn Chan %2d Key %3d ", chan, Pm_MessageData1(data)); len = put_pitch(Pm_MessageData1(data)); printf(vel_format + len, Pm_MessageData2(data)); } } } else if ((command == MIDI_ON_NOTE /* && Pm_MessageData2(data) == 0 */ || command == MIDI_OFF_NOTE) && notes) { showbytes(data, 3, verbose); if (verbose) { printf("NoteOff Chan %2d Key %3d ", chan, Pm_MessageData1(data)); len = put_pitch(Pm_MessageData1(data)); printf(vel_format + len, Pm_MessageData2(data)); } } else if (command == MIDI_CH_PROGRAM && pgchanges) { showbytes(data, 2, verbose); if (verbose) { printf(" ProgChg Chan %2d Prog %2d\n", chan, Pm_MessageData1(data) + 1); } } else if (command == MIDI_CTRL) { /* controls 121 (MIDI_RESET_CONTROLLER) to 127 are channel * mode messages. */ if (Pm_MessageData1(data) < MIDI_ALL_SOUND_OFF) { showbytes(data, 3, verbose); if (verbose) { printf("CtrlChg Chan %2d Ctrl %2d Val %2d\n", chan, Pm_MessageData1(data), Pm_MessageData2(data)); } } else /* channel mode */ if (chmode) { showbytes(data, 3, verbose); if (verbose) { switch (Pm_MessageData1(data)) { case MIDI_ALL_SOUND_OFF: printf("All Sound Off, Chan %2d\n", chan); break; case MIDI_RESET_CONTROLLERS: printf("Reset All Controllers, Chan %2d\n", chan); break; case MIDI_LOCAL: printf("LocCtrl Chan %2d %s\n", chan, Pm_MessageData2(data) ? "On" : "Off"); break; case MIDI_ALL_OFF: printf("All Off Chan %2d\n", chan); break; case MIDI_OMNI_OFF: printf("OmniOff Chan %2d\n", chan); break; case MIDI_OMNI_ON: printf("Omni On Chan %2d\n", chan); break; case MIDI_MONO_ON: printf("Mono On Chan %2d\n", chan); if (Pm_MessageData2(data)) printf(" to %d received channels\n", Pm_MessageData2(data)); else printf(" to all received channels\n"); break; case MIDI_POLY_ON: printf("Poly On Chan %2d\n", chan); break; } } } } else if (command == MIDI_POLY_TOUCH && bender) { showbytes(data, 3, verbose); if (verbose) { printf("P.Touch Chan %2d Key %2d ", chan, Pm_MessageData1(data)); len = put_pitch(Pm_MessageData1(data)); printf(val_format + len, Pm_MessageData2(data)); } } else if (command == MIDI_TOUCH && bender) { showbytes(data, 2, verbose); if (verbose) { printf(" A.Touch Chan %2d Val %2d\n", chan, Pm_MessageData1(data)); } } else if (command == MIDI_BEND && bender) { showbytes(data, 3, verbose); if (verbose) { printf("P.Bend Chan %2d Val %2d\n", chan, (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7))); } } else if (Pm_MessageStatus(data) == MIDI_SONG_POINTER) { showbytes(data, 3, verbose); if (verbose) { printf(" Song Position %d\n", (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7))); } } else if (Pm_MessageStatus(data) == MIDI_SONG_SELECT) { showbytes(data, 2, verbose); if (verbose) { printf(" Song Select %d\n", Pm_MessageData1(data)); } } else if (Pm_MessageStatus(data) == MIDI_TUNE_REQ) { showbytes(data, 1, verbose); if (verbose) { printf(" Tune Request\n"); } } else if (Pm_MessageStatus(data) == MIDI_Q_FRAME && realdata) { showbytes(data, 2, verbose); if (verbose) { printf(" Time Code Quarter Frame Type %d Values %d\n", (Pm_MessageData1(data) & 0x70) >> 4, Pm_MessageData1(data) & 0xf); } } else if (Pm_MessageStatus(data) == MIDI_START && realdata) { showbytes(data, 1, verbose); if (verbose) { printf(" Start\n"); } } else if (Pm_MessageStatus(data) == MIDI_CONTINUE && realdata) { showbytes(data, 1, verbose); if (verbose) { printf(" Continue\n"); } } else if (Pm_MessageStatus(data) == MIDI_STOP && realdata) { showbytes(data, 1, verbose); if (verbose) { printf(" Stop\n"); } } else if (Pm_MessageStatus(data) == MIDI_SYS_RESET && realdata) { showbytes(data, 1, verbose); if (verbose) { printf(" System Reset\n"); } } else if (Pm_MessageStatus(data) == MIDI_TIME_CLOCK) { if (clksencnt) clockcount++; else if (realdata) { showbytes(data, 1, verbose); if (verbose) { printf(" Clock\n"); } } } else if (Pm_MessageStatus(data) == MIDI_ACTIVE_SENSING) { if (clksencnt) actsensecount++; else if (realdata) { showbytes(data, 1, verbose); if (verbose) { printf(" Active Sensing\n"); } } } else showbytes(data, 3, verbose); fflush(stdout); } /**************************************************************************** * put_pitch * Inputs: * int p: pitch number * Effect: write out the pitch name for a given number ****************************************************************************/ private int put_pitch(int p) { char result[8]; static char *ptos[] = { "c", "cs", "d", "ef", "e", "f", "fs", "g", "gs", "a", "bf", "b" }; /* note octave correction below */ sprintf(result, "%s%d", ptos[p % 12], (p / 12) - 1); printf(result); return strlen(result); } /**************************************************************************** * showbytes * Effect: print hex data, precede with newline if asked ****************************************************************************/ char nib_to_hex[] = "0123456789ABCDEF"; private void showbytes(PmMessage data, int len, boolean newline) { int count = 0; int i; /* if (newline) { putchar('\n'); count++; } */ for (i = 0; i < len; i++) { putchar(nib_to_hex[(data >> 4) & 0xF]); putchar(nib_to_hex[data & 0xF]); count += 2; if (count > 72) { putchar('.'); putchar('.'); putchar('.'); break; } data >>= 8; } putchar(' '); } /**************************************************************************** * showhelp * Effect: print help text ****************************************************************************/ private void showhelp() { printf("\n"); printf(" Item Reported Range Item Reported Range\n"); printf(" ------------- ----- ------------- -----\n"); printf(" Channels 1 - 16 Programs 1 - 128\n"); printf(" Controllers 0 - 127 After Touch 0 - 127\n"); printf(" Loudness 0 - 127 Pitch Bend 0 - 16383, center = 8192\n"); printf(" Pitches 0 - 127, 60 = c4 = middle C\n"); printf(" \n"); printf("n toggles notes"); showstatus(notes); printf("t displays noteon count since last t\n"); printf("b toggles pitch bend, aftertouch"); showstatus(bender); printf("c toggles continuous control"); showstatus(controls); printf("h toggles program changes"); showstatus(pgchanges); printf("x toggles system exclusive"); showstatus(excldata); printf("k toggles clock and sense counting only"); showstatus(clksencnt); printf("r toggles other real time messages & SMPTE"); showstatus(realdata); printf("s displays clock and sense count since last k\n"); printf("m toggles channel mode messages"); showstatus(chmode); printf("v toggles verbose text"); showstatus(verbose); printf("q quits\n"); printf("\n"); } /**************************************************************************** * showstatus * Effect: print status of flag ****************************************************************************/ private void showstatus(boolean flag) { printf(", now %s\n", flag ? "ON" : "OFF" ); } portmidi/pm_test/sysex.vcproj0000755000000000000000000001125711274243554015476 0ustar rootroot portmidi/pm_test/qtest.c0000644000000000000000000001116011301353626014361 0ustar rootroot#include "portmidi.h" #include "pmutil.h" #include "stdlib.h" #include "stdio.h" /* make_msg -- make a psuedo-random message of length n whose content * is purely a function of i */ void make_msg(long msg[], int n, int i) { int j; for (j = 0; j < n; j++) { msg[j] = i % (j + 5); } } /* print_msg -- print the content of msg of length n to stdout */ /**/ void print_msg(long msg[], int n) { int i; for (i = 0; i < n; i++) { printf(" %li", msg[i]); } } /* cmp_msg -- compare two messages of length n */ /**/ int cmp_msg(long msg[], long msg2[], int n, int i) { int j; for (j = 0; j < n; j++) { if (msg[j] != msg2[j]) { printf("Received message %d doesn't match sent message\n", i); printf("in: "); print_msg(msg, n); printf("\n"); printf("out:"); print_msg(msg2, n); printf("\n"); return FALSE; } } return TRUE; } int main() { int msg_len; for (msg_len = 4; msg_len < 100; msg_len += 5) { PmQueue *queue = Pm_QueueCreate(100, msg_len * sizeof(long)); int i; long msg[100]; long msg2[100]; printf("msg_len = %d\n", msg_len); if (!queue) { printf("Could not allocate queue\n"); return 1; } /* insert/remove 1000 messages */ printf("test 1\n"); for (i = 0; i < 1357; i++) { make_msg(msg, msg_len, i); if (Pm_Enqueue(queue, msg)) { printf("Pm_Enqueue error\n"); return 1; } if (Pm_Dequeue(queue, msg2) != 1) { printf("Pm_Dequeue error\n"); return 1; } if (!cmp_msg(msg, msg2, msg_len, i)) { return 1; } } /* make full */ printf("test 2\n"); for (i = 0; i < 100; i++) { make_msg(msg, msg_len, i); if (Pm_Enqueue(queue, msg)) { printf("Pm_Enqueue error\n"); return 1; } } /* alternately remove and insert */ for (i = 100; i < 1234; i++) { make_msg(msg, msg_len, i - 100); /* what we expect */ if (Pm_Dequeue(queue, msg2) != 1) { printf("Pm_Dequeue error\n"); return 1; } if (!cmp_msg(msg, msg2, msg_len, i)) { return 1; } make_msg(msg, msg_len, i); if (Pm_Enqueue(queue, msg)) { printf("Pm_Enqueue error\n"); return 1; } } /* remove all */ while (!Pm_QueueEmpty(queue)) { make_msg(msg, msg_len, i - 100); /* what we expect */ if (Pm_Dequeue(queue, msg2) != 1) { printf("Pm_Dequeue error\n"); return 1; } if (!cmp_msg(msg, msg2, msg_len, i)) { return 1; } i++; } if (i != 1334) { printf("Message count error\n"); return 1; } /* now test overflow */ printf("test 3\n"); for (i = 0; i < 110; i++) { make_msg(msg, msg_len, i); if (Pm_Enqueue(queue, msg) == pmBufferOverflow) { break; /* this is supposed to execute after 100 messages */ } } for (i = 0; i < 100; i++) { make_msg(msg, msg_len, i); if (Pm_Dequeue(queue, msg2) != 1) { printf("Pm_Dequeue error\n"); return 1; } if (!cmp_msg(msg, msg2, msg_len, i)) { return 1; } } /* we should detect overflow after removing 100 messages */ if (Pm_Dequeue(queue, msg2) != pmBufferOverflow) { printf("Pm_Dequeue overflow expected\n"); return 1; } /* after overflow is detected (and cleared), sender can * send again */ /* see if function is restored, also test peek */ printf("test 4\n"); for (i = 0; i < 1357; i++) { long *peek; make_msg(msg, msg_len, i); if (Pm_Enqueue(queue, msg)) { printf("Pm_Enqueue error\n"); return 1; } peek = (long *) Pm_QueuePeek(queue); if (!cmp_msg(msg, peek, msg_len, i)) { return 1; } if (Pm_Dequeue(queue, msg2) != 1) { printf("Pm_Dequeue error\n"); return 1; } if (!cmp_msg(msg, msg2, msg_len, i)) { return 1; } } Pm_QueueDestroy(queue); } return 0; } portmidi/pm_test/sysex.c0000755000000000000000000003717711445664134014427 0ustar rootroot/* sysex.c -- example program showing how to send and receive sysex messages Messages are stored in a file using 2-digit hexadecimal numbers, one per byte, separated by blanks, with up to 32 numbers per line: F0 14 A7 4B ... */ #include "stdio.h" #include "stdlib.h" #include "assert.h" #include "portmidi.h" #include "porttime.h" #include "string.h" #ifdef WIN32 // need to get declaration for Sleep() #include "windows.h" #else #include #define Sleep(n) usleep(n * 1000) #endif #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 #define STRING_MAX 80 #ifndef true #define true 1 #define false 0 #endif int latency = 0; /* read a number from console */ /**/ int get_number(char *prompt) { char line[STRING_MAX]; int n = 0, i; printf(prompt); while (n != 1) { n = scanf("%d", &i); fgets(line, STRING_MAX, stdin); } return i; } /* loopback test -- send/rcv from 2 to 1000 bytes of random midi data */ /**/ void loopback_test() { int outp; int inp; PmStream *midi_in; PmStream *midi_out; unsigned char msg[1024]; char line[80]; int32_t len; int i; int data; PmEvent event; int shift; long total_bytes = 0; int32_t begin_time; Pt_Start(1, 0, 0); printf("Connect a midi cable from an output port to an input port.\n"); printf("This test will send random data via sysex message from output\n"); printf("to input and check that the correct data was received.\n"); outp = get_number("Type output device number: "); /* Open output with 1ms latency -- when latency is non-zero, the Win32 implementation supports sending sysex messages incrementally in a series of buffers. This is nicer than allocating a big buffer for the message, and it also seems to work better. Either way works. */ while ((latency = get_number( "Latency in milliseconds (0 to send data immediatedly,\n" " >0 to send timestamped messages): ")) < 0); Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency); inp = get_number("Type input device number: "); /* since we are going to send and then receive, make sure the input buffer is large enough for the entire message */ Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL); srand((unsigned int) Pt_Time()); /* seed for random numbers */ begin_time = Pt_Time(); while (1) { PmError count; int32_t start_time; int error_position = -1; /* 0; -1; -1 for continuous */ int expected = 0; int actual = 0; /* this modification will run until an error is detected */ /* set error_position above to 0 for interactive, -1 for */ /* continuous */ if (error_position >= 0) { printf("Type return to send message, q to quit: "); fgets(line, STRING_MAX, stdin); if (line[0] == 'q') goto cleanup; } /* compose the message */ len = rand() % 998 + 2; /* len only counts data bytes */ msg[0] = (char) MIDI_SYSEX; /* start of SYSEX message */ /* data bytes go from 1 to len */ for (i = 0; i < len; i++) { /* pick whether data is sequential or random... (docs say random) */ #define DATA_EXPR (i+1) // #define DATA_EXPR rand() msg[i + 1] = DATA_EXPR & 0x7f; /* MIDI data */ } /* final EOX goes in len+1, total of len+2 bytes in msg */ msg[len + 1] = (char) MIDI_EOX; /* sanity check: before we send, there should be no queued data */ count = Pm_Read(midi_in, &event, 1); if (count != 0) { printf("Before sending anything, a MIDI message was found in\n"); printf("the input buffer. Please try again.\n"); break; } /* send the message */ printf("Sending %d byte sysex message.\n", len + 2); Pm_WriteSysEx(midi_out, 0, msg); /* receive the message and compare to msg[] */ data = 0; shift = 0; i = 0; start_time = Pt_Time(); error_position = -1; /* allow up to 2 seconds for transmission */ while (data != MIDI_EOX && start_time + 2000 > Pt_Time()) { count = Pm_Read(midi_in, &event, 1); if (count == 0) { Sleep(1); /* be nice: give some CPU time to the system */ continue; /* continue polling for input */ } /* printf("read %lx ", event.message); fflush(stdout); */ /* compare 4 bytes of data until you reach an eox */ for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) { data = (event.message >> shift) & 0xFF; if (data != msg[i] && error_position < 0) { error_position = i; expected = msg[i]; actual = data; } i++; } } if (error_position >= 0) { printf("Error at byte %d: sent %x recd %x.\n", error_position, expected, actual); break; } else if (i != len + 2) { printf("Error: byte %d not received.\n", i); break; } else { int seconds = (Pt_Time() - begin_time) / 1000; if (seconds == 0) seconds = 1; printf("Correctly received %d byte sysex message.\n", i); total_bytes += i; printf("Cummulative bytes/sec: %d\n", total_bytes / seconds); } } cleanup: Pm_Close(midi_out); Pm_Close(midi_in); return; } /* send_multiple test -- send many sysex messages */ /**/ void send_multiple_test() { int outp; int length; int num_msgs; PmStream *midi_out; unsigned char msg[1024]; int i; PtTimestamp start_time; PtTimestamp stop_time; Pt_Start(1, 0, 0); printf("This is for performance testing. You should be sending to this\n"); printf("program running the receive multiple test. Do NOT send to\n"); printf("a synthesizer or you risk reprogramming it\n"); outp = get_number("Type output device number: "); while ((latency = get_number( "Latency in milliseconds (0 to send data immediatedly,\n" " >0 to send timestamped messages): ")) < 0); Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency); while ((length = get_number("Message length (7 - 1024): ")) < 7 || length > 1024) ; while ((num_msgs = get_number("Number of messages: ")) < 1); /* latency, length, and num_msgs should now all be valid */ /* compose the message except for sequence number in first 5 bytes */ msg[0] = (char) MIDI_SYSEX; for (i = 6; i < length - 1; i++) { msg[i] = i % 128; /* this is just filler */ } msg[length - 1] = (char) MIDI_EOX; start_time = Pt_Time(); /* send the messages */ for (i = num_msgs; i > 0; i--) { /* insert sequence number into first 5 data bytes */ /* sequence counts down to zero */ int j; int count = i; /* 7 bits of message count i goes into each data byte */ for (j = 1; j <= 5; j++) { msg[j] = count & 127; count >>= 7; } /* send the message */ Pm_WriteSysEx(midi_out, 0, msg); } stop_time = Pt_Time(); Pm_Close(midi_out); return; } #define MAX_MSG_LEN 1024 static unsigned char receive_msg[MAX_MSG_LEN]; static int receive_msg_index; static int receive_msg_length; static int receive_msg_count; static int receive_msg_error; static int receive_msg_messages; static PmStream *receive_msg_midi_in; static int receive_poll_running; /* receive_poll -- callback function to check for midi input */ /**/ void receive_poll(PtTimestamp timestamp, void *userData) { PmError count; PmEvent event; int shift; int data = 0; int i; if (!receive_poll_running) return; /* wait until midi device is opened */ shift = 0; while (data != MIDI_EOX) { count = Pm_Read(receive_msg_midi_in, &event, 1); if (count == 0) return; /* compare 4 bytes of data until you reach an eox */ for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) { receive_msg[receive_msg_index++] = data = (event.message >> shift) & 0xFF; if (receive_msg_index >= MAX_MSG_LEN) { printf("error: incoming sysex too long\n"); goto error; } } } /* check the message */ if (receive_msg_length == 0) { receive_msg_length = receive_msg_index; } if (receive_msg_length != receive_msg_index) { printf("error: incoming sysex wrong length\n"); goto error; } if (receive_msg[0] != MIDI_SYSEX) { printf("error: incoming sysex missing status byte\n"); goto error; } /* get and check the count */ count = 0; for (i = 0; i < 5; i++) { count += receive_msg[i + 1] << (7 * i); } if (receive_msg_count == -1) { receive_msg_count = count; receive_msg_messages = count; } if (receive_msg_count != count) { printf("error: incoming sysex has wrong count\n"); goto error; } for (i = 6; i < receive_msg_index - 1; i++) { if (receive_msg[i] != i % 128) { printf("error: incoming sysex has bad data\n"); goto error; } } if (receive_msg[receive_msg_length - 1] != MIDI_EOX) goto error; receive_msg_index = 0; /* get ready for next message */ receive_msg_count--; return; error: receive_msg_error = 1; return; } /* receive_multiple_test -- send/rcv from 2 to 1000 bytes of random midi data */ /**/ void receive_multiple_test() { PmError err; int inp; printf("This test expects to receive data sent by the send_multiple test\n"); printf("The test will check that correct data is received.\n"); /* Important: start PortTime first -- if it is not started first, it will be started by PortMidi, and then our attempt to open again will fail */ receive_poll_running = false; if ((err = Pt_Start(1, receive_poll, 0))) { printf("PortTime error code: %d\n", err); goto cleanup; } inp = get_number("Type input device number: "); Pm_OpenInput(&receive_msg_midi_in, inp, NULL, 512, NULL, NULL); receive_msg_index = 0; receive_msg_length = 0; receive_msg_count = -1; receive_msg_error = 0; receive_poll_running = true; while ((!receive_msg_error) && (receive_msg_count != 0)) { #ifdef WIN32 Sleep(1000); #else sleep(1); /* block and wait */ #endif } if (receive_msg_error) { printf("Receive_multiple test encountered an error\n"); } else { printf("Receive_multiple test successfully received %d sysex messages\n", receive_msg_messages); } cleanup: receive_poll_running = false; Pm_Close(receive_msg_midi_in); Pt_Stop(); return; } #define is_real_time_msg(msg) ((0xF0 & Pm_MessageStatus(msg)) == 0xF8) void receive_sysex() { char line[80]; FILE *f; PmStream *midi; int shift = 0; int data = 0; int bytes_on_line = 0; PmEvent msg; /* determine which output device to use */ int i = get_number("Type input device number: "); /* open input device */ Pm_OpenInput(&midi, i, NULL, 512, NULL, NULL); printf("Midi Input opened, type file for sysex data: "); /* open file */ fgets(line, STRING_MAX, stdin); /* remove the newline character */ if (strlen(line) > 0) line[strlen(line) - 1] = 0; f = fopen(line, "w"); if (!f) { printf("Could not open %s\n", line); Pm_Close(midi); return; } printf("Ready to receive a sysex message\n"); /* read data and write to file */ while (data != MIDI_EOX) { PmError count; count = Pm_Read(midi, &msg, 1); /* CAUTION: this causes busy waiting. It would be better to be in a polling loop to avoid being compute bound. PortMidi does not support a blocking read since this is so seldom useful. */ if (count == 0) continue; /* ignore real-time messages */ if (is_real_time_msg(Pm_MessageStatus(msg.message))) continue; /* write 4 bytes of data until you reach an eox */ for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) { data = (msg.message >> shift) & 0xFF; /* if this is a status byte that's not MIDI_EOX, the sysex message is incomplete and there is no more sysex data */ if (data & 0x80 && data != MIDI_EOX) break; fprintf(f, "%2x ", data); if (++bytes_on_line >= 16) { fprintf(f, "\n"); bytes_on_line = 0; } } } fclose(f); Pm_Close(midi); } void send_sysex() { char line[80]; FILE *f; PmStream *midi; int data; int shift = 0; PmEvent msg; /* determine which output device to use */ int i = get_number("Type output device number: "); while ((latency = get_number( "Latency in milliseconds (0 to send data immediatedly,\n" " >0 to send timestamped messages): ")) < 0); msg.timestamp = 0; /* no need for timestamp */ /* open output device */ Pm_OpenOutput(&midi, i, NULL, 0, NULL, NULL, latency); printf("Midi Output opened, type file with sysex data: "); /* open file */ fgets(line, STRING_MAX, stdin); /* remove the newline character */ if (strlen(line) > 0) line[strlen(line) - 1] = 0; f = fopen(line, "r"); if (!f) { printf("Could not open %s\n", line); Pm_Close(midi); return; } /* read file and send data */ msg.message = 0; while (1) { /* get next byte from file */ if (fscanf(f, "%x", &data) == 1) { /* printf("read %x, ", data); */ /* OR byte into message at proper offset */ msg.message |= (data << shift); shift += 8; } /* send the message if it's full (shift == 32) or if we are at end */ if (shift == 32 || data == MIDI_EOX) { /* this will send sysex data 4 bytes at a time -- it would be much more efficient to send multiple PmEvents at once but this method is simpler. See Pm_WriteSysEx for a more efficient code example. */ Pm_Write(midi, &msg, 1); msg.message = 0; shift = 0; } if (data == MIDI_EOX) { /* end of message */ fclose(f); Pm_Close(midi); return; } } } int main() { int i; char line[80]; /* list device information */ for (i = 0; i < Pm_CountDevices(); i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); printf("%d: %s, %s", i, info->interf, info->name); if (info->input) printf(" (input)"); if (info->output) printf(" (output)"); printf("\n"); } while (1) { printf("Type r to receive sysex, s to send," " l for loopback test, m to send multiple," " n to receive multiple, q to quit: "); fgets(line, STRING_MAX, stdin); switch (line[0]) { case 'r': receive_sysex(); break; case 's': send_sysex(); break; case 'l': loopback_test(); break; case 'm': send_multiple_test(); break; case 'n': receive_multiple_test(); break; case 'q': exit(0); default: break; } } return 0; } portmidi/pm_test/mm.vcproj0000755000000000000000000001121311274243554014724 0ustar rootroot portmidi/pm_test/test.c0000755000000000000000000003661411254141714014216 0ustar rootroot#include "portmidi.h" #include "porttime.h" #include "stdlib.h" #include "stdio.h" #include "string.h" #include "assert.h" #define INPUT_BUFFER_SIZE 100 #define OUTPUT_BUFFER_SIZE 0 #define DRIVER_INFO NULL #define TIME_PROC ((int32_t (*)(void *)) Pt_Time) #define TIME_INFO NULL #define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ #define STRING_MAX 80 /* used for console input */ int32_t latency = 0; /* crash the program to test whether midi ports are closed */ /**/ void doSomethingReallyStupid() { int * tmp = NULL; *tmp = 5; } /* exit the program without any explicit cleanup */ /**/ void doSomethingStupid() { assert(0); } /* read a number from console */ /**/ int get_number(char *prompt) { char line[STRING_MAX]; int n = 0, i; printf(prompt); while (n != 1) { n = scanf("%d", &i); fgets(line, STRING_MAX, stdin); } return i; } /* * the somethingStupid parameter can be set to simulate a program crash. * We want PortMidi to close Midi ports automatically in the event of a * crash because Windows does not (and this may cause an OS crash) */ void main_test_input(unsigned int somethingStupid) { PmStream * midi; PmError status, length; PmEvent buffer[1]; int num = 10; int i = get_number("Type input number: "); /* It is recommended to start timer before Midi; otherwise, PortMidi may start the timer with its (default) parameters */ TIME_START; /* open input device */ Pm_OpenInput(&midi, i, DRIVER_INFO, INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO); printf("Midi Input opened. Reading %d Midi messages...\n", num); Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX); /* empty the buffer after setting filter, just in case anything got through */ while (Pm_Poll(midi)) { Pm_Read(midi, buffer, 1); } /* now start paying attention to messages */ i = 0; /* count messages as they arrive */ while (i < num) { status = Pm_Poll(midi); if (status == TRUE) { length = Pm_Read(midi,buffer, 1); if (length > 0) { printf("Got message %d: time %ld, %2lx %2lx %2lx\n", i, (long) buffer[0].timestamp, (long) Pm_MessageStatus(buffer[0].message), (long) Pm_MessageData1(buffer[0].message), (long) Pm_MessageData2(buffer[0].message)); i++; } else { assert(0); } } /* simulate crash if somethingStupid is 1 or 2 */ if ((i > (num/2)) && (somethingStupid == 1)) { doSomethingStupid(); } else if ((i > (num/2)) && (somethingStupid == 2)) { doSomethingReallyStupid(); } } /* close device (this not explicitly needed in most implementations) */ printf("ready to close..."); Pm_Close(midi); printf("done closing..."); } void main_test_output() { PmStream * midi; char line[80]; int32_t off_time; int chord[] = { 60, 67, 76, 83, 90 }; #define chord_size 5 PmEvent buffer[chord_size]; PmTimestamp timestamp; /* determine which output device to use */ int i = get_number("Type output number: "); /* It is recommended to start timer before PortMidi */ TIME_START; /* open output device -- since PortMidi avoids opening a timer when latency is zero, we will pass in a NULL timer pointer for that case. If PortMidi tries to access the time_proc, we will crash, so this test will tell us something. */ Pm_OpenOutput(&midi, i, DRIVER_INFO, OUTPUT_BUFFER_SIZE, (latency == 0 ? NULL : TIME_PROC), (latency == 0 ? NULL : TIME_INFO), latency); printf("Midi Output opened with %ld ms latency.\n", (long) latency); /* output note on/off w/latency offset; hold until user prompts */ printf("ready to send program 1 change... (type RETURN):"); fgets(line, STRING_MAX, stdin); /* if we were writing midi for immediate output, we could always use timestamps of zero, but since we may be writing with latency, we will explicitly set the timestamp to "now" by getting the time. The source of timestamps should always correspond to the TIME_PROC and TIME_INFO parameters used in Pm_OpenOutput(). */ buffer[0].timestamp = TIME_PROC(TIME_INFO); /* Send a program change to increase the chances we will hear notes */ /* Program 0 is usually a piano, but you can change it here: */ #define PROGRAM 0 buffer[0].message = Pm_Message(0xC0, PROGRAM, 0); Pm_Write(midi, buffer, 1); printf("ready to note-on... (type RETURN):"); fgets(line, STRING_MAX, stdin); buffer[0].timestamp = TIME_PROC(TIME_INFO); buffer[0].message = Pm_Message(0x90, 60, 100); Pm_Write(midi, buffer, 1); printf("ready to note-off... (type RETURN):"); fgets(line, STRING_MAX, stdin); buffer[0].timestamp = TIME_PROC(TIME_INFO); buffer[0].message = Pm_Message(0x90, 60, 0); Pm_Write(midi, buffer, 1); /* output short note on/off w/latency offset; hold until user prompts */ printf("ready to note-on (short form)... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_WriteShort(midi, TIME_PROC(TIME_INFO), Pm_Message(0x90, 60, 100)); printf("ready to note-off (short form)... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_WriteShort(midi, TIME_PROC(TIME_INFO), Pm_Message(0x90, 60, 0)); /* output several note on/offs to test timing. Should be 1s between notes */ printf("chord will arpeggiate if latency > 0\n"); printf("ready to chord-on/chord-off... (type RETURN):"); fgets(line, STRING_MAX, stdin); timestamp = TIME_PROC(TIME_INFO); for (i = 0; i < chord_size; i++) { buffer[i].timestamp = timestamp + 1000 * i; buffer[i].message = Pm_Message(0x90, chord[i], 100); } Pm_Write(midi, buffer, chord_size); off_time = timestamp + 1000 + chord_size * 1000; while (TIME_PROC(TIME_INFO) < off_time) /* busy wait */; for (i = 0; i < chord_size; i++) { buffer[i].timestamp = timestamp + 1000 * i; buffer[i].message = Pm_Message(0x90, chord[i], 0); } Pm_Write(midi, buffer, chord_size); /* close device (this not explicitly needed in most implementations) */ printf("ready to close and terminate... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_Close(midi); Pm_Terminate(); printf("done closing and terminating...\n"); } void main_test_both() { int i = 0; int in, out; PmStream * midi, * midiOut; PmEvent buffer[1]; PmError status, length; int num = 10; in = get_number("Type input number: "); out = get_number("Type output number: "); /* In is recommended to start timer before PortMidi */ TIME_START; Pm_OpenOutput(&midiOut, out, DRIVER_INFO, OUTPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO, latency); printf("Midi Output opened with %ld ms latency.\n", (long) latency); /* open input device */ Pm_OpenInput(&midi, in, DRIVER_INFO, INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO); printf("Midi Input opened. Reading %d Midi messages...\n",num); Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK); /* empty the buffer after setting filter, just in case anything got through */ while (Pm_Poll(midi)) { Pm_Read(midi, buffer, 1); } i = 0; while (i < num) { status = Pm_Poll(midi); if (status == TRUE) { length = Pm_Read(midi,buffer,1); if (length > 0) { Pm_Write(midiOut, buffer, 1); printf("Got message %d: time %ld, %2lx %2lx %2lx\n", i, (long) buffer[0].timestamp, (long) Pm_MessageStatus(buffer[0].message), (long) Pm_MessageData1(buffer[0].message), (long) Pm_MessageData2(buffer[0].message)); i++; } else { assert(0); } } } /* close midi devices */ Pm_Close(midi); Pm_Close(midiOut); Pm_Terminate(); } /* main_test_stream exercises windows winmm API's stream mode */ /* The winmm stream mode is used for latency>0, and sends timestamped messages. The timestamps are relative (delta) times, whereas PortMidi times are absolute. Since peculiar things happen when messages are not always sent in advance, this function allows us to exercise the system and test it. */ void main_test_stream() { PmStream * midi; char line[80]; PmEvent buffer[16]; /* determine which output device to use */ int i = get_number("Type output number: "); latency = 500; /* ignore LATENCY for this test and fix the latency at 500ms */ /* It is recommended to start timer before PortMidi */ TIME_START; /* open output device */ Pm_OpenOutput(&midi, i, DRIVER_INFO, OUTPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO, latency); printf("Midi Output opened with %ld ms latency.\n", (long) latency); /* output note on/off w/latency offset; hold until user prompts */ printf("ready to send output... (type RETURN):"); fgets(line, STRING_MAX, stdin); /* if we were writing midi for immediate output, we could always use timestamps of zero, but since we may be writing with latency, we will explicitly set the timestamp to "now" by getting the time. The source of timestamps should always correspond to the TIME_PROC and TIME_INFO parameters used in Pm_OpenOutput(). */ buffer[0].timestamp = TIME_PROC(TIME_INFO); buffer[0].message = Pm_Message(0xC0, 0, 0); buffer[1].timestamp = buffer[0].timestamp; buffer[1].message = Pm_Message(0x90, 60, 100); buffer[2].timestamp = buffer[0].timestamp + 1000; buffer[2].message = Pm_Message(0x90, 62, 100); buffer[3].timestamp = buffer[0].timestamp + 2000; buffer[3].message = Pm_Message(0x90, 64, 100); buffer[4].timestamp = buffer[0].timestamp + 3000; buffer[4].message = Pm_Message(0x90, 66, 100); buffer[5].timestamp = buffer[0].timestamp + 4000; buffer[5].message = Pm_Message(0x90, 60, 0); buffer[6].timestamp = buffer[0].timestamp + 4000; buffer[6].message = Pm_Message(0x90, 62, 0); buffer[7].timestamp = buffer[0].timestamp + 4000; buffer[7].message = Pm_Message(0x90, 64, 0); buffer[8].timestamp = buffer[0].timestamp + 4000; buffer[8].message = Pm_Message(0x90, 66, 0); Pm_Write(midi, buffer, 9); #ifdef SEND8 /* Now, we're ready for the real test. Play 4 notes at now, now+500, now+1000, and now+1500 Then wait until now+2000. Play 4 more notes as before. We should hear 8 evenly spaced notes. */ now = TIME_PROC(TIME_INFO); for (i = 0; i < 4; i++) { buffer[i * 2].timestamp = now + (i * 500); buffer[i * 2].message = Pm_Message(0x90, 60, 100); buffer[i * 2 + 1].timestamp = now + 250 + (i * 500); buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0); } Pm_Write(midi, buffer, 8); while (Pt_Time() < now + 2500) /* busy wait */; /* now we are 500 ms behind schedule, but since the latency is 500, the delay should not be audible */ now += 2000; for (i = 0; i < 4; i++) { buffer[i * 2].timestamp = now + (i * 500); buffer[i * 2].message = Pm_Message(0x90, 60, 100); buffer[i * 2 + 1].timestamp = now + 250 + (i * 500); buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0); } Pm_Write(midi, buffer, 8); #endif /* close device (this not explicitly needed in most implementations) */ printf("ready to close and terminate... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_Close(midi); Pm_Terminate(); printf("done closing and terminating...\n"); } void show_usage() { printf("Usage: test [-h] [-l latency-in-ms]\n"); exit(0); } int main(int argc, char *argv[]) { int default_in; int default_out; int i = 0, n = 0; char line[STRING_MAX]; int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0; int stream_test = 0; int latency_valid = FALSE; if (sizeof(void *) == 8) printf("Apparently this is a 64-bit machine.\n"); else if (sizeof(void *) == 4) printf ("Apparently this is a 32-bit machine.\n"); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0) { show_usage(); } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) { i = i + 1; latency = atoi(argv[i]); printf("Latency will be %ld\n", (long) latency); latency_valid = TRUE; } else { show_usage(); } } while (!latency_valid) { int lat; // declared int to match "%d" printf("Latency in ms: "); if (scanf("%d", &lat) == 1) { latency = (int32_t) lat; // coerce from "%d" to known size latency_valid = TRUE; } } /* determine what type of test to run */ printf("begin portMidi test...\n"); printf("%s%s%s%s%s", "enter your choice...\n 1: test input\n", " 2: test input (fail w/assert)\n", " 3: test input (fail w/NULL assign)\n", " 4: test output\n 5: test both\n", " 6: stream test\n"); while (n != 1) { n = scanf("%d", &i); fgets(line, STRING_MAX, stdin); switch(i) { case 1: test_input = 1; break; case 2: test_input = 1; somethingStupid = 1; break; case 3: test_input = 1; somethingStupid = 2; break; case 4: test_output = 1; break; case 5: test_both = 1; break; case 6: stream_test = 1; break; default: printf("got %d (invalid input)\n", n); break; } } /* list device information */ default_in = Pm_GetDefaultInputDeviceID(); default_out = Pm_GetDefaultOutputDeviceID(); for (i = 0; i < Pm_CountDevices(); i++) { char *deflt; const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (((test_input | test_both) & info->input) | ((test_output | test_both | stream_test) & info->output)) { printf("%d: %s, %s", i, info->interf, info->name); if (info->input) { deflt = (i == default_in ? "default " : ""); printf(" (%sinput)", deflt); } if (info->output) { deflt = (i == default_out ? "default " : ""); printf(" (%soutput)", deflt); } printf("\n"); } } /* run test */ if (stream_test) { main_test_stream(); } else if (test_input) { main_test_input(somethingStupid); } else if (test_output) { main_test_output(); } else if (test_both) { main_test_both(); } printf("finished portMidi test...type ENTER to quit..."); fgets(line, STRING_MAX, stdin); return 0; } portmidi/pm_test/midithread.vcproj0000755000000000000000000001135311274243554016432 0ustar rootroot portmidi/pm_test/test.vcproj0000755000000000000000000001124311274243554015275 0ustar rootroot portmidi/pm_test/midiclock.vcproj0000644000000000000000000001133711274243554016255 0ustar rootroot portmidi/pm_test/txdata.syx0000755000000000000000000003041410463413276015123 0ustar rootroot20 0 1d 4 c 6 0 34 1 4d 4 d 1f 7 3 6 c 5e 4 4d d b 18 5 3 6 0 3d 1 4a 16 18 1f 8 3 6 d 0 1 63 4 13 3a 23 0 0 0 2 c 2 4 0 63 32 0 0 0 32 0 47 72 61 6e 64 50 69 61 6e 6f 63 63 63 32 32 32 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 9 9 f c 27 2 35 37 10 1f 4 3 4 d 19 4 56 5 16 1f f 8 d c 0 43 60 4 e 1f c 3 7 e 0 43 63 5 10 3c 14 8 2 1b 56 5 2 4 0 63 32 0 0 0 32 0 4c 6f 54 69 6e 65 38 31 5a 20 63 63 63 32 32 32 0 7f 0 1 0 18 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f e f e 9 0 3 43 2d e 1f f 5 7 f 16 43 5a 0 0 1f 12 6 8 d 0 3 63 4 0 1f 12 6 8 f 0 2 63 4 6 34 14 0 1 2 4e 18 2 4 0 63 32 0 32 0 32 0 44 79 6e 6f 6d 69 74 65 45 50 63 63 63 32 32 32 0 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f b 1 b 8 18 40 5f a e 1f 1f 0 a f 0 40 5f 4 0 1f 1f 0 a f 0 40 63 5 6 1f 1f 0 a f 0 40 5f 0 8 1f 20 0 3 0 5a 18 4 4 0 63 32 32 0 0 32 0 50 65 72 63 4f 72 67 61 6e 20 63 63 63 32 32 32 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f b 7 f 9 0 4 49 13 13 1f 8 7 5 e 0 2 58 0 c 1f 6 4 6 f 23 3 46 10 a 1f 7 8 c d 0 2 63 8 b 2 1c 0 0 0 52 18 4 4 0 63 32 0 32 0 32 0 54 68 69 6e 20 43 6c 61 76 20 63 63 63 32 32 32 0 70 0 20 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f c 0 6 1 a 4 50 20 e 1f c 0 6 1 a 4 50 1f 8 1f b 9 5 e 0 2 63 5 e 1f b 9 5 e 0 3 63 4 8 4 1a 0 0 0 52 1d 2 4 0 63 32 0 32 0 32 0 42 72 69 74 65 43 65 6c 73 74 63 63 63 32 32 32 0 20 0 26 0 1 0 8 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 f 1f 4 8 f 0 3a 51 4 b e 1f 0 8 f 0 22 4b 4 3 f 1a b 8 d 0 3b 36 9 3 12 1f 0 8 f 0 22 5d 4 b 3a 1e 19 5 0 52 18 4 4 0 63 32 0 0 0 32 0 54 72 75 6d 70 65 74 38 31 5a 63 63 63 32 32 32 0 0 0 50 0 51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 c 5 0 8 0 0 2 4a 4 b f 1f 0 8 f 0 2 3f 4 3 1f f 0 8 0 23 3 44 b 3 10 1f 0 9 f 0 2 5e 4 c 3a 1f 19 7 0 52 18 4 4 0 63 32 0 0 0 32 0 46 6c 75 67 65 6c 68 6f 72 6e 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 1f 0 8 f 0 42 4a 0 3 11 1f 0 8 f a 43 51 0 3 11 9 0 8 d 0 42 2b 16 6 10 1f 0 9 f 0 42 63 4 b 3a 1e 9 9 0 5a 24 4 4 0 63 32 31 0 0 32 0 52 61 73 70 41 6c 74 6f 20 20 63 63 63 32 32 32 0 10 0 20 0 54 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 9 2 6 d 0 41 3e 4 15 c b 2 3 e 0 41 4f 4 12 c e 2 8 d 0 42 4b a 1c d b 1 9 e 0 3 63 a 14 0 23 f 2 1b 5e 18 4 5 0 63 28 50 32 0 32 0 48 61 72 6d 6f 6e 69 63 61 20 63 63 63 32 32 32 0 50 10 50 0 50 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1c 2 0 4 e 63 0 4e 4 3 d 5 0 6 e 63 1 56 a 8 12 7 0 6 9 63 2 47 1b e a a 0 5 f 0 1 63 4 b 32 1a 8 d 0 52 c 4 4 0 63 32 0 0 0 32 0 44 6f 75 62 6c 65 42 61 73 73 63 63 63 32 32 32 0 10 0 0 0 3 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 b 4 0 4 f 14 2 49 9 6 a 7 0 4 f 14 2 51 a 0 8 1f 0 5 f 0 1 63 9 6 a 1f 0 5 f 0 1 63 a 0 3c 1f 6 9 0 52 5 4 4 0 63 32 0 0 0 32 0 48 69 53 74 72 69 6e 67 20 31 63 63 63 32 32 32 0 2 0 30 0 32 0 10 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 13 f 4 a 0 3 3b 14 14 1f e 8 7 9 0 2 42 5 e 18 13 d 9 c 0 2 3c 13 8 1f 11 7 4 f 0 42 63 4 10 3a 1b 0 0 0 52 1d 4 4 0 63 32 0 0 0 32 0 48 61 72 70 20 20 20 20 20 20 63 63 63 32 32 32 8 0 0 21 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 6 6 4 f 0 40 48 5 0 c 8 7 5 f 5 0 52 4 0 f 7 3 7 e 8 3 63 4 6 f 8 4 5 f 0 3 63 4 6 7c 1f 0 6 0 4a 11 2 4 0 63 32 0 0 0 32 0 46 61 6e 66 61 72 54 70 74 73 63 63 63 32 32 32 6 1 0 38 0 8 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 d b 0 1 c 0 2 2c 3d 3 d 7 0 1 c 0 2 1f 3c 3 d 1f 0 5 f 0 2 63 5 6 d 1f 0 5 f 0 2 63 4 0 3c 63 0 2f 0 53 11 4 4 0 63 32 0 0 0 32 0 42 72 65 61 74 68 4f 72 67 6e 63 63 63 32 32 32 4 30 5 50 0 11 0 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 9 0 6 0 27 2 51 19 b 1c 6 0 8 0 37 2 47 a 3 1f a 0 9 0 3d 2 4d a e 1f 12 8 8 f 0 3 61 4 b 28 1f 0 3 0 52 c 3 4 0 63 32 1 32 0 32 0 4e 79 6c 6f 6e 47 75 69 74 20 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f e e f f 0 3 48 2d 6 1f f 4 f f 25 3 5b 0 0 1f 12 6 c e 1c 3 55 0 10 1f 13 7 8 e 6 4 62 4 e 3b 14 0 0 0 42 18 2 4 0 63 32 0 32 0 32 0 47 75 69 74 61 72 20 23 31 20 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 19 8 a 3 0 3 63 10 18 1f c 5 b 5 0 3 52 0 b 1f 19 6 b 5 0 3 63 a 16 1f f 11 9 7 0 4 63 4 3 3a 14 0 0 0 42 18 2 4 0 63 32 0 32 0 32 0 46 75 6e 6b 79 20 50 69 63 6b 63 63 63 32 32 32 0 30 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 1 0 8 4 0 3 3d a 1e 1f 1 0 8 0 0 0 43 0 10 1f 9 6 8 c 1b 7 46 1c 1e 1f 9 0 9 9 0 1 63 4 3 3a 1c 0 0 0 52 c 4 5 0 63 4b 0 0 0 32 0 45 6c 65 63 42 61 73 73 20 31 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f f f e 9 0 3 46 1d 16 1f f 5 e e d 3 63 0 b 1f 13 6 5 d 1c 3 63 0 0 1f 13 6 8 f 0 4 63 4 6 3b 1f 0 0 0 42 c 4 4 0 63 32 0 32 0 32 0 53 79 6e 46 75 6e 6b 42 61 73 63 63 63 32 32 32 d 6c 0 0 0 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 10 7 8 3 0 3 4f 4 3 1f 9 0 8 0 0 1 4a 0 b 1f 11 0 8 0 0 1 47 4 8 1f 9 0 8 0 0 0 63 0 b 39 19 0 7 0 52 c 2 4 0 63 32 0 32 0 32 0 4c 61 74 65 6c 79 42 61 73 73 63 63 63 32 32 32 2 0 0 0 0 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 12 0 9 d 22 0 51 0 b 1f 14 0 5 8 24 40 5c 0 3 1f 11 0 6 c 2c 0 53 9 0 10 1f 0 b f 0 0 5c a e 3a 22 11 e 1e 5e 18 7 4 0 63 32 0 32 0 32 0 53 79 6e 63 20 4c 65 61 64 20 63 63 63 32 32 32 0 70 0 40 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1e 0 9 e 0 0 63 3f b 1f 14 0 5 e 24 1 51 4 3 1f 14 0 f 1 0 41 4d 8 3 f 1f 0 b f 0 2 63 4 b 3b 20 11 12 33 56 18 4 4 0 63 37 e 0 0 32 0 4a 61 7a 7a 20 46 6c 75 74 65 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 13 d 3 d 1e 2 50 18 e 15 14 9 4 c 1e 2 56 11 8 1b 1f f 7 f 0 1 63 4 6 1a 1f e 6 f 0 2 63 4 0 7c b 0 8 0 62 18 4 4 0 63 32 0 0 0 32 0 4a 61 76 61 20 4a 69 76 65 20 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 0 0 4 f 0 40 63 3c 0 b 8 7 7 f 5 0 63 4 6 f 5 3 7 f 8 0 3b 5 6 e 8 4 5 f 0 3 63 3 0 7e 1d 6 f 0 4a 11 0 4 0 63 32 0 0 0 32 0 42 61 61 64 42 72 65 61 74 68 63 63 63 32 32 32 6 30 0 38 0 1 0 46 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 0 0 4 f 0 40 47 2f 0 e 8 7 7 f 5 0 4c 0 6 13 1c d c 6 8 0 63 5 6 14 11 d b 0 0 3 63 4 0 7a 10 0 51 0 68 17 0 4 0 63 32 0 0 0 32 0 56 6f 63 61 6c 4e 75 74 73 20 63 63 63 32 32 32 6 30 0 30 0 1 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 1f 0 5 f 0 0 41 32 3 1f 14 10 5 5 1 2 63 7 3 1f b 12 8 f 0 1 63 c 3 1f 1f f 8 f 0 1 63 4 3 39 23 0 0 0 62 18 7 4 0 63 32 0 0 0 32 0 57 61 74 65 72 47 6c 61 73 73 63 63 63 32 32 32 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 2 0 4 6 9 1 4f 8 0 19 e 1 4 0 20 1 43 19 0 1f 12 10 6 7 0 0 54 3d 3 16 d 6 6 2 1e 3 61 8 e 3a 20 1 14 0 42 c 2 4 2 63 63 63 0 0 32 0 46 75 7a 7a 79 20 4b 6f 74 6f 63 63 63 32 32 32 0 0 0 0 b 50 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1c 8 0 3 e 0 1 55 12 3 1c 7 0 1 e 2e 1 58 27 b e 4 0 2 a 0 2 63 4 a d 9 0 2 c 1 2 63 10 b 4 54 0 47 0 53 18 7 4 0 63 32 0 0 0 32 0 42 72 74 68 62 65 6c 6c 73 20 63 63 63 32 32 32 0 4 0 40 0 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1a 4 1 1 b 16 0 47 5 3 15 e 0 1 d 0 0 4c 5 16 1c 6 4 2 7 0 0 63 4 16 18 18 3 1 e 0 0 5e 4 10 24 7 0 4 0 62 24 4 4 0 63 32 0 0 0 32 0 54 75 62 65 20 42 65 6c 6c 73 63 63 63 32 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 1f 13 3 0 0 0 5f 3d 6 1f 12 13 2 0 0 1 52 5 2 1f 14 13 3 0 0 1 56 28 5 1e b 13 f 9 0 0 63 6 3 3b 63 0 63 0 73 23 7 4 0 63 32 0 0 0 32 0 4e 6f 69 73 65 20 53 68 6f 74 63 63 63 32 32 32 8 0 0 0 8 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1f 16 0 3 7 0 1 50 0 3 1f 18 3 3 3 22 0 63 0 14 1d 7 6 3 6 0 1 3c 8 3 1f 5 7 3 0 0 1 63 4 1b 39 23 0 8 0 42 18 4 4 0 63 32 0 0 0 32 0 48 61 6e 64 20 44 72 75 6d 20 63 63 63 32 32 32 0 1 0 3 0 1 0 1 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7d f7 portmidi/pm_test/latency.c0000755000000000000000000002326411254141714014673 0ustar rootroot/* latency.c -- measure latency of OS */ #include "porttime.h" #include "portmidi.h" #include "stdlib.h" #include "stdio.h" #include "string.h" #include "assert.h" /* Latency is defined here to mean the time starting when a process becomes ready to run, and ending when the process actually runs. Latency is due to contention for the processor, usually due to other processes, OS activity including device drivers handling interrupts, and waiting for the scheduler to suspend the currently running process and activate the one that is waiting. Latency can affect PortMidi applications: if a process fails to wake up promptly, MIDI input may sit in the input buffer waiting to be handled, and MIDI output may not be generated with accurate timing. Using the latency parameter when opening a MIDI output port allows the caller to defer timing to PortMidi, which in most implementations will pass the data on to the OS. By passing timestamps and data to the OS kernel, device driver, or even hardware, there are fewer sources of latency that can affect the ultimate timing of the data. On the other hand, the application must generate and deliver the data ahead of the timestamp. The amount by which data is computed early must be at least as large as the worst-case latency to avoid timing problems. Latency is even more important in audio applications. If an application lets an audio output buffer underflow, an audible pop or click is produced. Audio input buffers can overflow, causing data to be lost. In general the audio buffers must be large enough to buffer the worst-case latency that the application will encounter. This program measures latency by recording the difference between the scheduled callback time and the current real time. We do not really know the scheduled callback time, so we will record the differences between the real time of each callback and the real time of the previous callback. Differences that are larger than the scheduled difference are recorded. Smaller differences indicate the system is recovering from an earlier latency, so these are ignored. Since printing by the callback process can cause all sorts of delays, this program records latency observations in a histogram. When the program is stopped, the histogram is printed to the console. Optionally the system can be tested under a load of MIDI input, MIDI output, or both. If MIDI input is selected, the callback thread will read any waiting MIDI events each iteration. You must generate events on this interface for the test to actually put any appreciable load on PortMidi. If MIDI output is selected, alternating note on and note off events are sent each X iterations, where you specify X. For example, with a timer callback period of 2ms and X=1, a MIDI event is sent every 2ms. INTERPRETING RESULTS: Time is quantized to 1ms, so there is some uncertainty due to rounding. A microsecond latency that spans the time when the clock is incremented will be reported as a latency of 1. On the other hand, a latency of almost 1ms that falls between two clock ticks will be reported as zero. In general, if the highest nonzero bin is numbered N, then the maximum latency is N+1. CHANGE LOG 18-Jul-03 Mark Nelson -- Added code to generate MIDI or receive MIDI during test, and made period user-settable. */ #define HIST_LEN 21 /* how many 1ms bins in the histogram */ #define STRING_MAX 80 /* used for console input */ #define INPUT_BUFFER_SIZE 100 #define OUTPUT_BUFFER_SIZE 0 #ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef min #define min(a, b) ((a) <= (b) ? (a) : (b)) #endif int get_number(char *prompt); PtTimestamp previous_callback_time = 0; int period; /* milliseconds per callback */ int histogram[HIST_LEN]; int max_latency = 0; /* worst latency observed */ int out_of_range = 0; /* how many points outside of HIST_LEN? */ int test_in, test_out; /* test MIDI in and/or out? */ int output_period; /* output MIDI every __ iterations if test_out true */ int iteration = 0; PmStream *in, *out; int note_on = 0; /* is the note currently on? */ /* callback function for PortTime -- computes histogram */ void pt_callback(PtTimestamp timestamp, void *userData) { PtTimestamp difference = timestamp - previous_callback_time - period; previous_callback_time = timestamp; /* allow 5 seconds for the system to settle down */ if (timestamp < 5000) return; iteration++; /* send a note on/off if user requested it */ if (test_out && (iteration % output_period == 0)) { PmEvent buffer[1]; buffer[0].timestamp = Pt_Time(NULL); if (note_on) { /* note off */ buffer[0].message = Pm_Message(0x90, 60, 0); note_on = 0; } else { /* note on */ buffer[0].message = Pm_Message(0x90, 60, 100); note_on = 1; } Pm_Write(out, buffer, 1); iteration = 0; } /* read all waiting events (if user requested) */ if (test_in) { PmError status; PmEvent buffer[1]; do { status = Pm_Poll(in); if (status == TRUE) { Pm_Read(in,buffer,1); } } while (status == TRUE); } if (difference < 0) return; /* ignore when system is "catching up" */ /* update the histogram */ if (difference < HIST_LEN) { histogram[difference]++; } else { out_of_range++; } if (max_latency < difference) max_latency = difference; } int main() { char line[STRING_MAX]; int i; int len; int choice; PtTimestamp stop; printf("Latency histogram.\n"); period = 0; while (period < 1) { period = get_number("Choose timer period (in ms, >= 1): "); } printf("Benchmark with:\n\t%s\n\t%s\n\t%s\n\t%s\n", "1. No MIDI traffic", "2. MIDI input", "3. MIDI output", "4. MIDI input and output"); choice = get_number("? "); switch (choice) { case 1: test_in = 0; test_out = 0; break; case 2: test_in = 1; test_out = 0; break; case 3: test_in = 0; test_out = 1; break; case 4: test_in = 1; test_out = 1; break; default: assert(0); } if (test_in || test_out) { /* list device information */ for (i = 0; i < Pm_CountDevices(); i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if ((test_in && info->input) || (test_out && info->output)) { printf("%d: %s, %s", i, info->interf, info->name); if (info->input) printf(" (input)"); if (info->output) printf(" (output)"); printf("\n"); } } /* open stream(s) */ if (test_in) { int i = get_number("MIDI input device number: "); Pm_OpenInput(&in, i, NULL, INPUT_BUFFER_SIZE, (PmTimestamp (*)(void *)) Pt_Time, NULL); /* turn on filtering; otherwise, input might overflow in the 5-second period before timer callback starts reading midi */ Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK); } if (test_out) { int i = get_number("MIDI output device number: "); PmEvent buffer[1]; Pm_OpenOutput(&out, i, NULL, OUTPUT_BUFFER_SIZE, (PmTimestamp (*)(void *)) Pt_Time, NULL, 0); /* no latency scheduling */ /* send a program change to force a status byte -- this fixes a problem with a buggy linux MidiSport driver, and shouldn't hurt anything else */ buffer[0].timestamp = 0; buffer[0].message = Pm_Message(0xC0, 0, 0); /* program change */ Pm_Write(out, buffer, 1); output_period = get_number( "MIDI out should be sent every __ callback iterations: "); assert(output_period >= 1); } } printf("%s%s", "Latency measurements will start in 5 seconds. ", "Type return to stop: "); Pt_Start(period, &pt_callback, 0); fgets(line, STRING_MAX, stdin); stop = Pt_Time(); Pt_Stop(); /* courteously turn off the last note, if necessary */ if (note_on) { PmEvent buffer[1]; buffer[0].timestamp = Pt_Time(NULL); buffer[0].message = Pm_Message(0x90, 60, 0); Pm_Write(out, buffer, 1); } /* print the histogram */ printf("Duration of test: %g seconds\n\n", max(0, stop - 5000) * 0.001); printf("Latency(ms) Number of occurrences\n"); /* avoid printing beyond last non-zero histogram entry */ len = min(HIST_LEN, max_latency + 1); for (i = 0; i < len; i++) { printf("%2d %10d\n", i, histogram[i]); } printf("Number of points greater than %dms: %d\n", HIST_LEN - 1, out_of_range); printf("Maximum latency: %d milliseconds\n", max_latency); printf("\nNote that due to rounding, actual latency can be 1ms higher\n"); printf("than the numbers reported here.\n"); printf("Type return to exit..."); fgets(line, STRING_MAX, stdin); if(choice == 2) Pm_Close(in); else if(choice == 3) Pm_Close(out); else if(choice == 4) { Pm_Close(in); Pm_Close(out); } return 0; } /* read a number from console */ int get_number(char *prompt) { char line[STRING_MAX]; int n = 0, i; printf(prompt); while (n != 1) { n = scanf("%d", &i); fgets(line, STRING_MAX, stdin); } return i; } portmidi/pm_test/midiclock.c0000644000000000000000000002132411262124064015160 0ustar rootroot/* miditime.c -- a test program that sends midi clock and MTC */ #include "portmidi.h" #include "porttime.h" #include #include #include #include #include #ifndef false #define false 0 #define true 1 #endif #define private static typedef int boolean; #define MIDI_TIME_CLOCK 0xf8 #define MIDI_START 0xfa #define MIDI_CONTINUE 0xfb #define MIDI_STOP 0xfc #define MIDI_Q_FRAME 0xf1 #define OUTPUT_BUFFER_SIZE 0 #define DRIVER_INFO NULL #define TIME_PROC ((int32_t (*)(void *)) Pt_Time) #define TIME_INFO NULL #define LATENCY 0 #define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ #define STRING_MAX 80 /* used for console input */ /* to determine ms per clock: * time per beat in seconds = 60 / tempo * multiply by 1000 to get time per beat in ms: 60000 / tempo * divide by 24 CLOCKs per beat: (60000/24) / tempo * simplify: 2500 / tempo */ #define TEMPO_TO_CLOCK 2500.0 boolean done = false; PmStream *midi; /* shared flags to control callback output generation: */ boolean clock_running = false; boolean send_start_stop = false; boolean time_code_running = false; boolean active = false; /* tells callback to do its thing */ float tempo = 60.0F; /* protocol for handing off portmidi to callback thread: main owns portmidi main sets active = true: ownership transfers to callback main sets active = false: main requests ownership callback sees active == false, yields ownership back to main main waits 2ms to make sure callback has a chance to yield (stop making PortMidi calls), then assumes it can close PortMidi */ /* timer_poll -- the timer callback function */ /* * All MIDI sends take place here */ void timer_poll(PtTimestamp timestamp, void *userData) { static int callback_owns_portmidi = false; static PmTimestamp clock_start_time = 0; static double next_clock_time = 0; /* SMPTE time */ static int frames = 0; static int seconds = 0; static int minutes = 0; static int hours = 0; static int mtc_count = 0; /* where are we in quarter frame sequence? */ static int smpte_start_time = 0; static double next_smpte_time = 0; #define QUARTER_FRAME_PERIOD (1.0 / 120.0) /* 30fps, 1/4 frame */ if (callback_owns_portmidi && !active) { /* main is requesting (by setting active to false) that we shut down */ callback_owns_portmidi = false; return; } if (!active) return; /* main still getting ready or it's closing down */ callback_owns_portmidi = true; /* main is ready, we have portmidi */ if (send_start_stop) { if (clock_running) { Pm_WriteShort(midi, 0, MIDI_STOP); } else { Pm_WriteShort(midi, 0, MIDI_START); clock_start_time = timestamp; next_clock_time = TEMPO_TO_CLOCK / tempo; } clock_running = !clock_running; send_start_stop = false; /* until main sets it again */ /* note that there's a slight race condition here: main could set send_start_stop asynchronously, but we assume user is typing slower than the clock rate */ } if (clock_running) { if ((timestamp - clock_start_time) > next_clock_time) { Pm_WriteShort(midi, 0, MIDI_TIME_CLOCK); next_clock_time += TEMPO_TO_CLOCK / tempo; } } if (time_code_running) { int data = 0; // initialization avoids compiler warning if ((timestamp - smpte_start_time) < next_smpte_time) return; switch (mtc_count) { case 0: /* frames low nibble */ data = frames; break; case 1: /* frames high nibble */ data = frames >> 4; break; case 2: /* frames seconds low nibble */ data = seconds; break; case 3: /* frames seconds high nibble */ data = seconds >> 4; break; case 4: /* frames minutes low nibble */ data = minutes; break; case 5: /* frames minutes high nibble */ data = minutes >> 4; break; case 6: /* hours low nibble */ data = hours; break; case 7: /* hours high nibble */ data = hours >> 4; break; } data &= 0xF; /* take only 4 bits */ Pm_WriteShort(midi, 0, Pm_Message(MIDI_Q_FRAME, (mtc_count << 4) + data, 0)); mtc_count = (mtc_count + 1) & 7; /* wrap around */ if (mtc_count == 0) { /* update time by two frames */ frames += 2; if (frames >= 30) { frames = 0; seconds++; if (seconds >= 60) { seconds = 0; minutes++; if (minutes >= 60) { minutes = 0; hours++; /* just let hours wrap if it gets that far */ } } } } next_smpte_time += QUARTER_FRAME_PERIOD; } else { /* time_code_running is false */ smpte_start_time = timestamp; /* so that when it finally starts, we'll be in sync */ } } /* read a number from console */ /**/ int get_number(char *prompt) { char line[STRING_MAX]; int n = 0, i; printf(prompt); while (n != 1) { n = scanf("%d", &i); fgets(line, STRING_MAX, stdin); } return i; } /**************************************************************************** * showhelp * Effect: print help text ****************************************************************************/ private void showhelp() { printf("\n"); printf("t toggles sending MIDI Time Code (MTC)\n"); printf("c toggles sending MIDI CLOCK (initially on)\n"); printf("m to set tempo (from 1bpm to 300bpm)\n"); printf("q quits\n"); printf("\n"); } /**************************************************************************** * doascii * Inputs: * char c: input character * Effect: interpret to control output ****************************************************************************/ private void doascii(char c) { if (isupper(c)) c = tolower(c); if (c == 'q') done = true; else if (c == 'c') { printf("%s MIDI CLOCKs\n", (clock_running ? "Stopping" : "Starting")); send_start_stop = true; } else if (c == 't') { printf("%s MIDI Time Code\n", (time_code_running ? "Stopping" : "Starting")); time_code_running = !time_code_running; } else if (c == 'm') { int input_tempo = get_number("Enter new tempo (bpm): "); if (input_tempo >= 1 && input_tempo <= 300) { printf("Changing tempo to %d\n", input_tempo); tempo = (float) input_tempo; } else { printf("Tempo range is 1 to 300, current tempo is %g bpm\n", tempo); } } else { showhelp(); } } /* main - prompt for parameters, start processing */ /* * Prompt user to type return. * Then send START and MIDI CLOCK for 60 beats/min. * Commands: * t - toggle sending MIDI Time Code (MTC) * c - toggle sending MIDI CLOCK * m - set tempo * q - quit */ int main(int argc, char **argv) { char s[STRING_MAX]; /* console input */ int outp; PmError err; int i; if (argc > 1) { printf("Warning: command line arguments ignored\n"); } showhelp(); /* use porttime callback to send midi */ Pt_Start(1, timer_poll, 0); /* list device information */ printf("MIDI output devices:\n"); for (i = 0; i < Pm_CountDevices(); i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (info->output) printf("%d: %s, %s\n", i, info->interf, info->name); } outp = get_number("Type output device number: "); err = Pm_OpenOutput(&midi, outp, DRIVER_INFO, OUTPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO, LATENCY); if (err) { printf(Pm_GetErrorText(err)); goto error_exit_no_device; } active = true; printf("Type RETURN to start MIDI CLOCK:\n"); if (!fgets(s, STRING_MAX, stdin)) goto error_exit; send_start_stop = true; /* send START and then CLOCKs */ while (!done) { if (fgets(s, STRING_MAX, stdin)) { doascii(s[0]); } } error_exit: active = false; Pt_Sleep(2); /* this is to allow callback to complete -- it's real time, so it's either ok and it runs on time, or there's no point to synchronizing with it */ /* now we "own" portmidi again */ Pm_Close(midi); error_exit_no_device: Pt_Stop(); Pm_Terminate(); exit(0); } portmidi/pm_test/CMakeLists.txt0000644000000000000000000000113411445664134015625 0ustar rootroot# pm_test # set the build directory to be in portmidi, not in portmidi/pm_test # this is required for Xcode: if(APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) endif(APPLE) if(WIN32) include(../pm_win/static.cmake) endif(WIN32) macro(make_a_test name) add_executable(${name} ${name}.c) target_link_libraries(${name} portmidi-static ${PM_NEEDED_LIBS}) add_dependencies(${name} portmidi-static) endmacro(make_a_test) make_a_test(test) make_a_test(midithread) make_a_test(midithru) make_a_test(sysex) make_a_test(latency) make_a_test(mm) make_a_test(midiclock) make_a_test(qtest) portmidi/pm_test/midithru.c0000755000000000000000000003302111252403336015050 0ustar rootroot/* midithru.c -- example program implementing background thru processing */ /* suppose you want low-latency midi-thru processing, but your application wants to take advantage of the input buffer and timestamped data so that it does not have to operate with very low latency. This program illustrates how to use a timer callback from PortTime to implement a low-latency process that handles midi thru, including correctly merging midi data from the application with midi data from the input port. The main application, which runs in the main program thread, will use an interface similar to that of PortMidi, but since PortMidi does not allow concurrent threads to share access to a stream, the application will call private methods that transfer MIDI messages to and from the timer thread. All PortMidi API calls are made from the timer thread. */ /* DESIGN All setup will be done by the main thread. Then, all direct access to PortMidi will be handed off to the timer callback thread. After this hand-off, the main thread will get/send messages via a queue. The goal is to send incoming messages to the midi output while merging any midi data generated by the application. Sysex is a problem here because you cannot insert (merge) a midi message while a sysex is in progress. There are at least three ways to implement midi thru with sysex messages: 1) Turn them off. If your application does not need them, turn them off with Pm_SetFilter(midi_in, PM_FILT_ACTIVE | PM_FILT_SYSEX). You will not receive sysex (or active sensing messages), so you will not have to handle them. 2) Make them atomic. As you receive sysex messages, copy the data into a (big) buffer. Ideally, expand the buffer as needed -- sysex messages do not have any maximum length. Even more ideally, use a list structure and real-time memory allocation to avoid latency in the timer thread. When a full sysex message is received, send it to the midi output all at once. 3) Process sysex incrementally. Send sysex data to midi output as it arrives. Block any non-real-time messages from the application until the sysex message completes. There is the risk that an incomplete sysex message will block messages forever, so implement a 5-second timeout: if no sysex data is seen for 5 seconds, release the block, possibly losing the rest of the sysex message. Application messages must be processed similarly: once started, a sysex message will block MIDI THRU processing. We will assume that the application will not abort a sysex message, so timeouts are not necessary here. This code implements (3). Latency is also an issue. PortMidi requires timestamps to be in non-decreasing order. Since we'll be operating with a low-latency timer thread, we can just set the latency to zero meaning timestamps are ignored by PortMidi. This will allow thru to go through with minimal latency. The application, however, needs to use timestamps because we assume it is high latency (the whole purpose of this example is to illustrate how to get low-latency thru with a high-latency application.) So the callback thread will implement midi timing by observing timestamps. The current timestamp will be available in the global variable current_timestamp. */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "assert.h" #include "portmidi.h" #include "pmutil.h" #include "porttime.h" #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 /* active is set true when midi processing should start */ int active = FALSE; /* process_midi_exit_flag is set when the timer thread shuts down */ int process_midi_exit_flag; PmStream *midi_in; PmStream *midi_out; /* shared queues */ #define IN_QUEUE_SIZE 1024 #define OUT_QUEUE_SIZE 1024 PmQueue *in_queue; PmQueue *out_queue; PmTimestamp current_timestamp = 0; int thru_sysex_in_progress = FALSE; int app_sysex_in_progress = FALSE; PmTimestamp last_timestamp = 0; /* time proc parameter for Pm_MidiOpen */ PmTimestamp midithru_time_proc(void *info) { return current_timestamp; } /* timer interrupt for processing midi data. Incoming data is delivered to main program via in_queue. Outgoing data from main program is delivered via out_queue. Incoming data from midi_in is copied with low latency to midi_out. Sysex messages from either source block messages from the other. */ void process_midi(PtTimestamp timestamp, void *userData) { PmError result; PmEvent buffer; /* just one message at a time */ current_timestamp++; /* update every millisecond */ /* if (current_timestamp % 1000 == 0) printf("time %d\n", current_timestamp); */ /* do nothing until initialization completes */ if (!active) { /* this flag signals that no more midi processing will be done */ process_midi_exit_flag = TRUE; return; } /* see if there is any midi input to process */ if (!app_sysex_in_progress) { do { result = Pm_Poll(midi_in); if (result) { int status; PmError rslt = Pm_Read(midi_in, &buffer, 1); if (rslt == pmBufferOverflow) continue; assert(rslt == 1); /* record timestamp of most recent data */ last_timestamp = current_timestamp; /* the data might be the end of a sysex message that has timed out, in which case we must ignore it. It's a continuation of a sysex message if status is actually a data byte (high-order bit is zero). */ status = Pm_MessageStatus(buffer.message); if (((status & 0x80) == 0) && !thru_sysex_in_progress) { continue; /* ignore this data */ } /* implement midi thru */ /* note that you could output to multiple ports or do other processing here if you wanted */ /* printf("thru: %x\n", buffer.message); */ Pm_Write(midi_out, &buffer, 1); /* send the message to the application */ /* you might want to filter clock or active sense messages here to avoid sending a bunch of junk to the application even if you want to send it to MIDI THRU */ Pm_Enqueue(in_queue, &buffer); /* sysex processing */ if (status == MIDI_SYSEX) thru_sysex_in_progress = TRUE; else if ((status & 0xF8) != 0xF8) { /* not MIDI_SYSEX and not real-time, so */ thru_sysex_in_progress = FALSE; } if (thru_sysex_in_progress && /* look for EOX */ (((buffer.message & 0xFF) == MIDI_EOX) || (((buffer.message >> 8) & 0xFF) == MIDI_EOX) || (((buffer.message >> 16) & 0xFF) == MIDI_EOX) || (((buffer.message >> 24) & 0xFF) == MIDI_EOX))) { thru_sysex_in_progress = FALSE; } } } while (result); } /* see if there is application midi data to process */ while (!Pm_QueueEmpty(out_queue)) { /* see if it is time to output the next message */ PmEvent *next = (PmEvent *) Pm_QueuePeek(out_queue); assert(next); /* must be non-null because queue is not empty */ if (next->timestamp <= current_timestamp) { /* time to send a message, first make sure it's not blocked */ int status = Pm_MessageStatus(next->message); if ((status & 0xF8) == 0xF8) { ; /* real-time messages are not blocked */ } else if (thru_sysex_in_progress) { /* maybe sysex has timed out (output becomes unblocked) */ if (last_timestamp + 5000 < current_timestamp) { thru_sysex_in_progress = FALSE; } else break; /* output is blocked, so exit loop */ } Pm_Dequeue(out_queue, &buffer); Pm_Write(midi_out, &buffer, 1); /* inspect message to update app_sysex_in_progress */ if (status == MIDI_SYSEX) app_sysex_in_progress = TRUE; else if ((status & 0xF8) != 0xF8) { /* not MIDI_SYSEX and not real-time, so */ app_sysex_in_progress = FALSE; } if (app_sysex_in_progress && /* look for EOX */ (((buffer.message & 0xFF) == MIDI_EOX) || (((buffer.message >> 8) & 0xFF) == MIDI_EOX) || (((buffer.message >> 16) & 0xFF) == MIDI_EOX) || (((buffer.message >> 24) & 0xFF) == MIDI_EOX))) { app_sysex_in_progress = FALSE; } } else break; /* wait until indicated timestamp */ } } void exit_with_message(char *msg) { #define STRING_MAX 80 char line[STRING_MAX]; printf("%s\nType ENTER...", msg); fgets(line, STRING_MAX, stdin); exit(1); } void initialize() /* set up midi processing thread and open midi streams */ { /* note that it is safe to call PortMidi from the main thread for initialization and opening devices. You should not make any calls to PortMidi from this thread once the midi thread begins. to make PortMidi calls. */ /* note that this routine provides minimal error checking. If you use the PortMidi library compiled with PM_CHECK_ERRORS, then error messages will be printed and the program will exit if an error is encountered. Otherwise, you should add some error checking to this code. */ const PmDeviceInfo *info; int id; /* make the message queues */ in_queue = Pm_QueueCreate(IN_QUEUE_SIZE, sizeof(PmEvent)); assert(in_queue != NULL); out_queue = Pm_QueueCreate(OUT_QUEUE_SIZE, sizeof(PmEvent)); assert(out_queue != NULL); /* always start the timer before you start midi */ Pt_Start(1, &process_midi, 0); /* start a timer with millisecond accuracy */ /* the timer will call our function, process_midi() every millisecond */ Pm_Initialize(); id = Pm_GetDefaultOutputDeviceID(); info = Pm_GetDeviceInfo(id); if (info == NULL) { printf("Could not open default output device (%d).", id); exit_with_message(""); } printf("Opening output device %s %s\n", info->interf, info->name); /* use zero latency because we want output to be immediate */ Pm_OpenOutput(&midi_out, id, NULL /* driver info */, OUT_QUEUE_SIZE, &midithru_time_proc, NULL /* time info */, 0 /* Latency */); id = Pm_GetDefaultInputDeviceID(); info = Pm_GetDeviceInfo(id); if (info == NULL) { printf("Could not open default input device (%d).", id); exit_with_message(""); } printf("Opening input device %s %s\n", info->interf, info->name); Pm_OpenInput(&midi_in, id, NULL /* driver info */, 0 /* use default input size */, &midithru_time_proc, NULL /* time info */); /* Note: if you set a filter here, then this will filter what goes to the MIDI THRU port. You may not want to do this. */ Pm_SetFilter(midi_in, PM_FILT_ACTIVE | PM_FILT_CLOCK); active = TRUE; /* enable processing in the midi thread -- yes, this is a shared variable without synchronization, but this simple assignment is safe */ } void finalize() { /* the timer thread could be in the middle of accessing PortMidi stuff */ /* to detect that it is done, we first clear process_midi_exit_flag and then wait for the timer thread to set it */ process_midi_exit_flag = FALSE; active = FALSE; /* busy wait for flag from timer thread that it is done */ while (!process_midi_exit_flag) ; /* at this point, midi thread is inactive and we need to shut down * the midi input and output */ Pt_Stop(); /* stop the timer */ Pm_QueueDestroy(in_queue); Pm_QueueDestroy(out_queue); Pm_Close(midi_in); Pm_Close(midi_out); Pm_Terminate(); } int main(int argc, char *argv[]) { PmTimestamp last_time = 0; PmEvent buffer; /* determine what type of test to run */ printf("begin PortMidi midithru program...\n"); initialize(); /* set up and start midi processing */ printf("%s\n%s\n", "This program will run for 60 seconds, or until you play middle C,", "echoing all input with a 2 second delay."); while (current_timestamp < 60000) { /* just to make the point that this is not a low-latency process, spin until half a second has elapsed */ last_time = last_time + 500; while (last_time > current_timestamp) ; /* now read data and send it after changing timestamps */ while (Pm_Dequeue(in_queue, &buffer) == 1) { /* printf("timestamp %d\n", buffer.timestamp); */ /* printf("message %x\n", buffer.message); */ buffer.timestamp = buffer.timestamp + 2000; /* delay */ Pm_Enqueue(out_queue, &buffer); /* play middle C to break out of loop */ if (Pm_MessageStatus(buffer.message) == 0x90 && Pm_MessageData1(buffer.message) == 60) { goto quit_now; } } } quit_now: finalize(); exit_with_message("finished PortMidi midithru program."); return 0; /* never executed, but keeps the compiler happy */ } portmidi/pm_test/latency.vcproj0000755000000000000000000001130711274243554015756 0ustar rootroot portmidi/ZERO_CHECK.vcproj0000644000000000000000000000673011274243554014321 0ustar rootroot portmidi/pm_java/0000755000000000000000000000000011453601074013021 5ustar rootrootportmidi/pm_java/pmdefaults-setup-script.iss0000644000000000000000000000416011453600330020340 0ustar rootroot; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! [Setup] ; NOTE: The value of AppId uniquely identifies this application. ; Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{5094958B-3CD7-4780-A883-69C9E5B95AEF} AppName=PmDefaults AppVerName=PmDefaults AppPublisher=Roger Dannenberg - Carnegie Mellon University AppPublisherURL=http://portmedia.sourceforge.net/ AppSupportURL=http://portmedia.sourceforge.net/ AppUpdatesURL=http://portmedia.sourceforge.net/ DefaultDirName={pf}\PmDefaults DefaultGroupName=PmDefaults LicenseFile=C:\Users\rbd\portmedia\portmidi\pm_java\win32\license.txt OutputBaseFilename=setup SetupIconFile=C:\Users\rbd\portmedia\portmidi\pm_java\pmdefaults\pmdefaults.ico Compression=lzma SolidCompression=yes [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\pmdefaults.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\pmdefaults.jar"; DestDir: "{app}"; Flags: ignoreversion Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\pmjni.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\license.txt"; DestDir: "{app}"; Flags: ignoreversion ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\PmDefaults"; Filename: "{app}\pmdefaults.exe" Name: "{commondesktop}\PmDefaults"; Filename: "{app}\pmdefaults.exe"; Tasks: desktopicon Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\PmDefaults"; Filename: "{app}\pmdefaults.exe"; Tasks: quicklaunchicon [Run] Filename: "{app}\pmdefaults.exe"; Description: "{cm:LaunchProgram,PmDefaults}"; Flags: nowait postinstall skipifsilent portmidi/pm_java/UpdateRsrcJavaExe.exe0000644000000000000000000031000011127373026017037 0ustar rootrootMZ@ !L!This program cannot be run in DOS mode. $ q-hX@V7u jhP@Vi uL$QV'jhH@VB uT$ RVpjh@@V uD$$PVLjh8@V uL$(QV(jh0@Vָ uT$,RVt$D$C;^D$(L$$T$ PD$ QL$ RT$ PQR_][YÐD$VjPpL$T$QD$RL$PD$4T$,QRPML$8Qa%T$(RW%D$0P L$8Q T$@R 4^t>D$uD$uD$ u D"D$u uFF< t|$l$t WVjՃ ΄tC<"t4u3:D$$u-D$ tF> uFF< t>tWVQՃ NFFu_^][ÐD$L$ T$j PD$ QRPeÐD$VWPmt$jVh@WQ'tT$ jRh@Wt$_^ÐS\$uA[ÊUt39-@~jP/(@ȊJtCCù;tLVW3It;v09-@~jP'@JtN;wF_^][ÐVt$WtG3D$ILQ&Ѓt$3+ȋƒ_^_3^ÐD$hPgL$Q ÐS\$Ul$VWA3j\+Sȃ't-x3+ыʃ-t3+ȃf l@f uRj\hAi'tx3+ыA3+ȃj.U'tAth`@U}&t_^]A[ÐVt$t4=@~jP%@ȊJtFFũ=@~hP%@fJ%t ~:u~\tjhp@VF t3^ø^ÐD$tL$jQPp@3҃VtPt@^ĈÐD$P8@|L$#;u3ÐD$jPS\$VWh@S.%Ѓt4z3h@+Rȃ$Ѓuh|@S$Ѓt4z3h|@+Rȃ$Ѓuhx@S$Ѓt4z3hx@+Rȃj$Ѓu_^[Ð U$ VWu _^3] ù3$󫋄$ tD$jPi(/3T$+ȃUEu _^3] Sj;Ul$!؃U=uZ|$+$O̓󤿈@+O͋l$UV3$+j;O͍$󤿄@+O͍kU;l$ ؃ }UJuV|$+$ًO˃󤿈@+ًO˃Ug3+$ًO˃󤍄$PB[_^] ÐUl$Vt$W|$ U t$D$S\$jPS#SUjQ"[3_^]ÐD$HPQHRP D$ QRPÐD$HP@QL$RPjQTËD$Vt$ PjjV%"3f>BM^ÐHD$LS\$XUl$XVW|$hh@PE#u_^][HÍL$ QVD$dVjT$pjR!jjVx"$<(u,VjD$8j(Ps!L$DD$NT$HM%D< u8VjL$j QC!T$$D$&L$*%UD$dV"D$h_^][HÐQD$SUVWP33 ;h@V"؃;SjL$jQ f9l$SjT$jR f|$SjD$ jP-Aq D$( @Q3;ţAtxT$RSD$ PjWA. f9l$~2NjVSPQPQ@ A zEf;l$|S[!_^][YV]SA!_^][Y_^]3[YÐD$SVP ؃h@S|!L$WQV@uSV _^[3ҋD$ AL$AAfD$AAhAAVfAT$ AAfAVf _^[^3[ÐD$VP5 tdh@P tPWjjVV jjV~OQ`VjWPA~VA4:_^3^ÐL!SVW3|$ |$X󫋼$d+T$X$h3S|$\Ih@L aQ$l t&3+$XȃƄ$X$\$XD$($lL$T$XD$ LT$D$,\$H _^[u P uH uP u@T$L$,RD$8(*uLÍ$LP[LÐD$L$T$Vt$PQRVt9tj\V`t@ƋL$T$QL$ RT$QjPjRV^Ð SAU-AVl$Ƅ$WCD$uD$P@D$S   PT$CPQRjjvD$(L$4Ph@Q|$@3$+$уOʃMol$_$ tj\VMt@Ƌ$ $QUjPjRD$$B^][ ÐVt$ tj\Vt@Ƌ AT$QjPjR^ÐVt$W=4@hV׃t hV׃u'hV׃t0hV׃t#hV׃t3PjV8@P @_^øPPV8@P @_^ÐS\$UVt$W|$$WSV,@D$(tL$3PQV0@3҅‹WS8@VӋ- @PՋD$WPVPՋD$ |WPVPV _^][ÐD$HP QL$PhhhQVÐD$HPQL$PhhhQ&ÐD$HPQL$PhhhQÐD$HQL$PjhhQÐD$HPQL$PjhhQÐD$L$ S\$ Ul$ VW|$(WPQRUtD$,t VЃt WU3T$,_^][ÐVt$ W|$ VWVWVWVWZVW#(_^ÐD$L$VPQt(D$t VЃtV؏T$^3^ÐVt$ W|$ F h@Ph@WNh@ ȉNNQh@WvVNh@R h@WNXNh`7@ ȋPh@WN:N@ h`7@NNQh@WN _N^Ð$SUV3VVjP@$jQ@;ދ~VuW3|$T$󫋄$hRVP@L$UQF;|Nj$_UR?E^][ÐSVt$ WjV3@D$-^Ht$-"HD$PV$_^[D$%=9==tjH4@hVӅuO hVӅuWhVӅu GhVӅuhVӅuWSV(@_^[=p=eV_^[-t!HCGQV^_^[WPV4_^[O h@Whp$@h(@h@QVG_^[$P*@W PVh_^[Oh@Wh$@h@h @QV_^[Wh@Wh$@h@h@RV_^[h`7@Wh%@h@h@PV_^[Oh`7@Wh0%@h@h@QVe_^[_^3[|$WVjjV8@P @WjV$@_^@[)@V)@)@)@<)@D$(L$$T$,D$ D$L$L$ T$D$L$D$ T$$Rjh'@%jPj@ÐD$VWjPWy$+ȃ󤋼$L$Wh,@Q,T$$RPsЃu$WQ\ЃtN|$3+ȃ󤍌$Qt$RJ_^Ā_3^ĀË_^ĀÐD$h@PÐD$h@PÐD$h@PÐD$h@PÐD$h@PaÐVt$j.VtL$ QPAu^3^Ð3$VW$ j.+ȃ󤍌$ QNt$t+>u&$D$Rh`@PDL$Q̈$t+>u&$D$RhX@PL$Q薈$t+>u&$D$RhP@PL$Q`$t+>u&$D$RhH@PL$Q*$ t+>u&$D$Rh8@PlL$Q_^ÐVt$ W>"uF3ID1L1"uj.VЃt'S\$3IQSR辛 [uD$0_^ÐS\$Ul$VWUu53t/\$3IQVj.PEuЃtV5tN;uIt$3IQRj.P>Ѓt3+ȃ_^][ÐQL$SUVW3ҋ< ut<"uFFu>tFQkVl$ _|$$D$WUh@t$4VUh@{\$DSUh@kl$TD$DUPh@WL$dT$PQRh@CD$TDWPh@0L$VQh@ T$(SRh@D$4UPh@L$\T$@QRh@D$hPh@Vh@GLUh@Vh@3Sh@Vh@"L$LQh@Wh@ Uh@Wh@@Sh@Wh@T$ ߋ}K;Mr.}t 3u+PSv$ t6t7)EV#Yt(FCME}vE_^[ÃN N 3+Eu Vt$WF to|$t tu]$F u VD$Y3V-*F Yt$F tt uFWt$v() 3ɃI A_^Vt$WF @t:t4V)V;+v* }Ft PfYǃf _^,uPt$t$t$+j@t$ t$ U SVW}3ۋw9_u}_jSVZ( ;ÉE|[W fu+GO+]t)֋`9ADt(;s": uEB€uA}uEG Wu!U+‰E`9ADtjjju' ;EuGM;s 8 uE@G 4juuf' 9Ew O ttGEDtEE)EEM_^[Q=L$r-=s+ȋą@PT-A,øs@LA p@HAPAp@TAo@XAnp@\AU}fE fEm}mEŨ$T$D$ ÍT$ 5P<$f<$to5T$5L$a5u=A5 @5=A5 @y4ZÍT$5D$uA3D$u33% D$uÍT$4D$ %=u T$uutQ$\$q5Yat4BD$ % D$؋D$t=xl$D$t-`At4y4% D$ue4^4-Aٱu @ٛuU EVuEEEu EBEP MxE EPjYY^UQVutZ:AuVYVt6PYY:u&EPEPV tPuuG Vj5:A@^UjhX@h@dPd%XSVWe@3ҊԉAȁ Aʉ AA3VpYujYu'x@:A8:A7#7uЍEP@6EEtEj XPuVV@P[EPE MPQ4YYËeu=Au<t$<h@YYÃ=Au<t$<Yh@áAtt$ЅYtjX3Vt$j&@f8MZuHj,PY;Yt0@8t9;uA8uj SP< tttEP}Y[3j9D$hP@:At6:Au h$Y uhu5:A@3jXh@j5:A@:AuËL$%:A%:Aj|:A :At:AXá:A :A ;sT$+P r3UMSVu AW+y iDMIM11UVUU] u~J?vj?ZK;KuL sL!\D u(M!!JL! uM!YM] MS[MZU MZRSJ?vj?Z]]+u]j?u K^;vMщMJ;v;tcM q;qu@ s!tDLu&M!1K!LuM!qM qINM qINu ]}u;M\ щ^NqNqN;Nu`L MLs%}uM DD )}uJM YJꍄ ED0E:A x:A5@H h@SQ֋ x:A:A P:A x:A@:A@HC:AHyCu `:AxuiSjp ֡:Apj5:A@:A:Aȡ:A+ȍLQHQP&;E :A;:Avm:A|:AE=x:A:A_^[U:A:ASVWu;:AuM; x:Au%:AMB_^[á:A t:AVW3;u0DPP5:AW5:A@;tat:A:A:A :AhAj5:A4@;ljFt*jh hW@;ljF uvW5:A@3N>~:AF_^UQMSVWqA3ۅ|Cj?iZ0DE@@Jujy hhW@up;wtƍ4;sCu0jX^;uCF;sN;Euq )u 9U }ƍ4;urq;s~;Esvu@j^X;u%C@;]s +q aq16;s)E 9U r4맍;]s +‰A aAFk+3_^[Ujh@h@dPd%SVWeA3;u>EPj^Vh@V@tEPVh@VS@jXAu$E;uTAuuu uP@9]udAESSuu E @Pu@E;tc]<ǃ$euWSVd2 jXËe33M;t)uVuu ju@;tuPVu@3e̋Md _^[̋L$tAt@u~Ѓ3ƒtAt2t$tt͍AL$+ÍAL$+ÍAL$+ÍAL$+á@th@h@h@h@jjt$  jjt$  Wj_9=(Aut$@P@|$ S\$=$A Au+HNIN~WPS!4 E 3tË`9A@A@ t jjSV FMjE_WPS3 E 9} _tN E% F ^[]UHSVW} 3Gۉuu} M3Mu39U |xÊ@3Ƭ@E$Cb@MỦU؉UUUUxà t;t-tHHtYMPMGM>M5M,*u#EPYEM؉EEˍDAU*uEPYEMˍDAЉEIt.ht ltwMMM ?6u4uGGM} lUЋ @UDAtEPuP G} EPuPf %ÃgeXxCHHtpHHtl fE0uMuuEPfEYȉMu 4AMENf8@@E M@;ʉ}EfE0uMfEEPt;0PP3 E}2E)Zt2 tHYEEEPYt3Ht,EtMEEeM0AEPu guEEũEuHM@EPPEPHAut}uPTAYguuPLAY-u M}WiYiHHtQHHE'<+u 0AMNt8t@+EEEEt]EE0QEEHEEt;M5EPE Yt fMfME#M@E Et EPYAE t!E@EPt Y%YE@EPtYY3E@t|s؃ڀMEu}} Ee ueEEEM t;ERPWVEU1uċ؃0uWV19~]ԋEM뵍E+EEEEtM90uu M@M0E}]@t&tE-tE+ t E Eu+u+u uEPuVj EPEuuP2tuEPuVj0}tA}~;E]xfCPEPC/YY~2MQuPEPOuEPuuuEtEPuVj q} Gۉ} E_^[\@[@[@[@5\@=\@r\@]@UM IxE QuYYEu]]VW|$O~!t$Vt$t$ >tO_^S\$ KVW~&|$t$WFt$Pu ?tK_^[ËD$@ËD$AQËD$f@Vt$F @t F f F u V-YFvvv FtltgV ‚u4NWt<`9A<@AO_ႀu V ~uN t uFHFA^ F f^U SVuW;5`:Aƃ`9A`9AƊPe} }tgubHt@< tMOED0 EjPuQ40@u:@jY;uA A>mu35P.Y&UUL0D0t ? u $E ME;ME<< t GEI9MsE@8 uE^ GEsEjPEEjP40@u @uG}tAD0HtE< t GD1);} u } u jju } t GM9MGt0@u +} }E%AA _^[UWVu M};v;xur)$Hg@Ǻr $`f@$Xg@$f@pf@f@f@#ъFGFGr$Hg@I#ъFGr$Hg@#ъFGr$Hg@I?g@,g@$g@g@g@ g@g@f@DDDDDDDDDDDDDD$Hg@Xg@`g@lg@g@E^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $h@$h@IǺr +$g@$h@g@h@@h@F#шGNOr$h@IF#шGFGr$h@F#шGFGFGZ$h@Ih@h@h@h@h@h@h@h@DDDDDDDDD D DDDD$h@h@h@i@i@E^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_ËD$S;`:AVWssȋ<`9AD1tVPk+Yu A Ot$jt$P@؃u@3t P@)Y d0D0%AA _^[Vt$u VY^V#Yt^F @tv+Y^3^SVt$ 3WF ȃu7ft1F>+~&WPv$ ;uF t$F N Ff_^[jYSVW33395 7A~M'At8H t0|$uP.YtC|$utPYu F;5 7A||$t_^[SUVW|$;=`:ANj`9AD0tiW)Yt<tuj)j)Y;YtW)YPt@u @3W(Yd0t Uv'Y3%AA _^][Vt$F ttvff 3YFF^UQQSV5xAW} 3ۉ]]uN@u NNC|5`:A@_^][Dhh(YYU0@](@]EuMm]E @vjX3hT@@th8@P@tjVt$P)eYt,F=@~jPOYY @AuԊ @FFu^ËD$@t :tH@u@t*t etEt@H80t8uH@A҈uËD$`@rjX3UQQ}utEPE-E YYMMHÍEPW-E YYMU=0ASVt'],A3ɋQ3Ƀ8-M QYY8EQQ$.]VU CP3>-3ɅQ.>-E u-@~HWx @_3hh@8 0AQ,}YYtEF A80t<^Ky-Ad|jd^ÙA |j ^ÙYE ^[]À=0ASUl$VWt*4A\$5,A;uG3Ƀ>-͋0`0D$QQ$-\$$VFP3>-P->-uE-}FjWY0YG~AjWv@YvGY}(=0At;|SWISj0W_^][USVW}QQ$,,AHI] 4A3Ƀ8-PSM VN,,AHI9 4A 8A@H4A|!;}t Fu FSu WA uSu W_^[]t$0At$t$t$g%0At$ 0At$ t$ H%0A U}et2}Et,}fuuu u ]uuu uuuu u]W|$ tVt$ V@PVVU^_ƅp uK ƅp2;at=Atm4@u tF t2t>-`Aƅpݽ`aAuƅp-jA uS uN uu tƅp-`Au t Xݽ`au-`A tƅp-`Aƅp u-`A-~Aٛݽ`aAuݽ`aݽ`ٛu Aٛt øVtV$$vft^t̀zuf\?f?f^٭^A剕lݽ`ƅpa$؃#zuf\?f?f^٭^A剕lݽ`ƅpɊaݽ`ɊaŊ$׊$ ؃#۽bۭbi@tƅpƅpA۽bۭbi@t ƅpƅp۽bۭbi@t ۽bۭbi@t ƅpƅp-Apƅp tUEEEEE UE]MEMEMEMPQR+6 Ef}tmËT$fT$l$étp@ËB%=tËB D$B  D$ $,$ BËD$%=tËD$f<$t,$Zf$f=tf tf t Z,$ZÃ$D$%$D$%t==t_f$f=t*f u!f ttZmZ,$Z@@s @@@v @UQQE`@EV33s]9Eu49UuWE @weE @rmAEj^9Mu#9UuE @wBE @s9E u19UE`@vAwE`@sge9M ue9Uu`EQQ$XE`@YYvAu]E'E`@suA]EE^UQQEQQ$c5YYuIEQQ$>5]E]YYu,E5P@QQ]E$5]YYujjX3USu5Y Xu `jX  <AMM <AH xA|AV;}4I+э4A& Ju5A=u Ap=u A]=u AJ=u A7=u A$=u A=u A5AjY5AY^`QYE<A u @[]ËT$ A9AVAt4I4A ;s9u I^ A;s9t3Ã=h:AuV5:A<"u%FF<"ttP3YtF>"u F < vF> wt< v^S39h:AVWuM5A3:t<=tGVYtPY;5Auj Y=A8t9UWYE?=t"U˾;Yuj YW6h YY8u]5A?YA_^d:A[UQQS39h:AVWu@AhVS|@:A5A8tEPEPSSWMEMP+;ujYEPEPEPVWEH5A_^A[UMESV!uW} Et7} 8"uDP@"t)t%A8At tF@tՊFt&F8"uF@CtF@A8At tF@ t t ūuHtfe8 t u@8t7} UE3ۀ8\u@C8"u,u%39}t x"Pu}} 39U‰UKtCt\FKutJ}u t? t:}t.tA8AtF@FA8At@@Xt&Ft'E_^[]QQDASU-@VW333;u3Ջ;t DA(@;DA;u Ջ;f9t@@f9u@@f9u+Ƌ=@SS@SSPVSSD$4׋;t2U蘻;YD$t#SSUPt$$VSSׅut$Y\$\$V@SuL;u @;t<8t @8u@8u+@U1Y;u3 UWV W@3_^][YYUSVWUjjh@uH]_^[]ËL$AtD$T$SVWD$Pjh@d5d%D$ Xp t.;t$$t(4v L$H |uhD@Td _^[3d y@uQ R 9QuSQA SQAMKCk Y[VC20XC00USVWU] E@EEEECs {ta v|tEVUkT]^] t3x<{SkVS vjDaC T{ v4롸UkjS]]_^[]UL$)APAPy]At u*=@u!hHAYthYUU3ɸA;t A=(A|V;AAu =@\hPj|@u\h@P'YY\WP\b@Yt }w u,9Ev'EA"tMMȉMtEEtE؉EE E t83_^[UWVSM&ً}3ˋu F3:GwtIIы[^_UWVu M};v;xur)$@Ǻr $@$@$,@@@@#ъFGFGr$@I#ъFGr$@#ъFGr$@I@|@t@l@d@\@T@L@DDDDDDDDDDDDDD$@@@@Ј@E^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $0@$@IǺr +$8@$0@H@h@@F#шGNOr$0@IF#шGFGr$0@F#шGFGFGZ$0@I@@@@@ @@'@DDDDDDDDD D DDDD$0@@@H@X@l@E^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_̋T$ L$tG3D$Wr-كt+шGIuʃttGJuD$_ËD$USVWuY;5$7Auj3;V3Ҹ8A90tr0B=(A|EPVh@$j@3Y@8A}5$7A󫪉D9A}MA;A8A@j@3Y@8A4R]HA;t,Qt%;wU0AA8A@;vAA9uE}rE<7AP$7A<A07AYD9AUAAyHjXA8A@=rVYD9A<7A<7A307A 9pAt3_^[ËD$%pAupA%`@upA%d@udApAËD$-t"t t Ht3øøøøWj@Y3@8A307A$7A<7AD9A_UEVP5$7Ah@3@;rEƅ t7SWU ;w+ȍA ˃BBBu_[j5D9A5$7APVPjrj5$7AVPVPV5D9A%j5$7AVPVPh5D9A%\3ftA8A@7AtA8A 〠@7A@AA;rI3ArZwA8AȀ @7AarzwA8A Ȁ @7A@;r^Ã=h:Auj,Yh:AUMS; `:AVWy`9AD0W39}}}u3W t jWQ @E 9}E}M+M ;Ms)ME uE @@ȍ+ʁ|̋+EjPWP40l@tCEE;| E+E ;Er3E;9}t_jX9EuLA A@EǍMWQuu 0l@t E}E@EuY=D0@t E 8A=A+E%AA _^[tAhYL$At I AI AAAAaËD$;`:Ar3Ëȃ `9AD@á 7AVj^u;}ƣ 7AjP%Y'AYu!jV5 7A%Y'AYuj\Y3ɸ(A'A =A|3ҹ8A‹`9Atu BA|^= At>%UEu]Ã=TAufM fw9jX]ÍMeQj5@PE jPh 5dA@t}t A*]SVD$ uL$D$3؋D$ Aȋ\$T$D$ ud$ȋD$r;T$wr;D$ vN3ҋ^[SD$ uL$D$ 3D$3Pȋ\$T$ D$ ud$d$r;T$ wr;D$v+D$T$+D$T$ ؃[L$3҉ AA;t B=A|r$wA ËմAAÁrAv ASVW33`9At7;s@t+Ƌ؃uTG `:A|CVYt3`:A `9A;s`@ _^[ËD$V;`:AWsRȋ<`9A<1u6=@S\$utHtHuSjSjSj\@03[%AA _^ËL$V; `:AWsU<`9A@t78t2=@u3+tItIuPjPjPj\@ 03%AA _^ËD$;`:Asȃ `9ADtÃ%AA ËD$;`:As=ȋ `9ADt%PYPX@u@3tAA UM S3VWE ]t ]E eEu@u9AtMj^#+t-Ht!HtAA%EE@EEt& t0t @uuE E]#ʿ;5t.;t*;tt<nE7E.u)tt ;t>EEE t A#Muj^@t Mt t ti؃;u%AA>jVuEPuuuT@;tV@uVt@@PYuM@ uMVSYEY E <`9Ae HD1uxttE tnjjS Eu=AtM?eEjPS? u}uuSQYYtjjSH u SY} uE t L0 D0_^[UQV}u:E #E#E VYE Ym ^ËD$%Pt$YYS\$3UWtjXt t t  t t VѾ #ֽttt;u  #^t ;u  _][t S\$3VtjXt t t t t ˺#ʾtt;t ;u ˁt u  ^[tUQ=TASVWuEAZ ]j;^}%95@~ VSnYY @X#ƅue@DJte jE] X e ]VjMjQPEPW5TA} t;uE EM _^[ËD$Vj YjD$YD$+ʃ҅uF}8uF|jX^3^ËD$SVWj \$YD$1uBW@PWV_^[]U VEWPEPOYuYhAjj f AAA_AAAAA^UQU SVWfB%#ωE Bپ%ۉut;t<(!3;u;uEXfXK<] ȋE M Huɋ ٍ XߋM fH_^[jťYl$l$D$5tPAuËD$ %tg=t`|$D$ ?%D$ l$ D$%t `A `Al$ dA dAl$ËD$ D$uËD$ %u|$D$ ?%D$ l$ D$%t=t2D$s*D$r hA|$l$ɛl$l$Ã,?$A,Ã,,Ã,,,,,|$ <$|$ l$ Ƀ,Ã,<$|$ l$ Ƀ,Ã,|$ <$|$ ^l$ ,<$|$ J,|$ <$:l$ ,|$ <$&,|$ <$|$ l$ ʃ,Ã,<$|$ l$ ʃ,Ã,|$ <$|$ l$ ,<$|$ Ƀ,|$ <$l$ ,|$ <$Ƀ,|$ <$|$ jl$ ˃,Ã,<$|$ Kl$ ˃,Ã,|$ <$|$ $l$ ,<$|$ ʃ,|$ <$l$ ,|$ <$ʃ,|$ <$|$ l$ ̃,Ã,<$|$ l$ ̃,Ã,|$ <$|$ l$ ,<$|$ h˃,|$ <$Tl$ ,|$ <$<˃,|$ <$|$ "l$ ̓,Ã,<$|$ l$ ̓,Ã,|$ <$|$ l$ ,<$|$ ̃,|$ <$l$ ,|$ <$̃,|$ <$|$ ~l$ ΃,Ã,<$|$ _l$ ΃,Ã,|$ <$|$ 8l$ ,<$|$ ̓,|$ <$ l$ ,|$ <$̓,|$ <$|$ l$ σ,Ã,<$|$ l$ σ,Ã,|$ <$|$ l$ ,<$|$ |΃,|$ <$hl$ ,|$ <$P΃,Ã,<$|$ ;,Ã,|$ <$(,PD$%=t3%8t D$XɃ <$D$,$Ƀ Xt$XPD$ %=t3%8t D$kXɃ <$D$V,$Ƀ Xt$XP%8t D$/XɃ <$D$,$Ƀ XP%8t D$XɃ <$D$,$Ƀ XPD$%=t3%8t D$XɃ <$D$,$Ƀ X|$XPD$ %=t3%8t D$~XɃ <$D$i,$Ƀ X|$XP%8t D$BXɃ <$D$-,$Ƀ XP%8t D$XɃ <$D$,$Ƀ XP,<$|$ ,XP,|$ <$,XPSQD$5 lApD$%=\D$.%M=BD$,6D$*D$%?\$0+w^D$% \$0+l$(D$\$0+؃+ˋ؁ ˉL$l$D$|$(ul$|$|$4D$4 ?D$8l$8D$%\$0+؃? ˋD$\$0% ؉\$l$l$(%u AɃu\$0|$(l$-Al$(l$4t l$l$(tV|$<t|$4D$4 D$8l$8 Al$4D$YYt=Au VOYu6Y_^[UQQEMEf] fEEU3ҁ} u 9Uuj<} u 9Uuj*M#f;ujfuE u9UtjX]3]UQQE`@Vu 3]3fEueE u9MtWE`@sjX3Eue E tM eNfe;tMEQQQ$] 'EQQQ$E ]f%EE0^UQQE]EUE#f;u,EQQ$YHYtHt HtjX]jj]%fҋuE u}t$]E`@u $@]$]jjt$  D$L$ A8Au|$tE@#D$3ujXS39AVWuBh@@;tg5@h@WօAtPh@Wh@WA֣AAtЋ؅tAtSЋt$t$t$SA_^[3̋L$ WtzVSًt$|$uuo!FGIt%t)uuQt FGt/KuD$[^_tGIuulGKu[^D$_ÉIt~Ѓ3‹tބt,tt uƉ3҉3It 3IuuD$[^_UQ=TASuEaz ]}(=@~ jSYY @Xuk@DJte E] j e ]jXMjjjQPEPh5TA" tuE EM [Ujh@h@dPd%SVWe39=AuFWWj[Sh@VWL@tA"WWSh@VWP@"A9}~uuYYEAuuuuuu uP@9} udAE WWuuE$@Pu @؉];}$deĉE܃MjXËe3}܃M]9}tfSuuuju @tMWWSuu uL@u;t2E t@9};uuuSuu uL@3eȋMd _^[E6$谌e܉]MjXËe33ۃMu;tVSuuu uL@t9}WWuWWuuVSh u @;qlT$D$VJt 8t@Iu8^u+D$ËVt$tV舢@P}YYt VP$YY^3^UVuu Wuw uj^3wX:AuE;:Aw.PYuLu;5,AwP脝Yu?Vj5:A@u$=AtV#YtujW _^]V3VWj3^95 7A~D'At/@ t P1YtG|'A4'AY$F;5 7A|_^U֊S]V3;`:AË`9ADjVSñ EjVS諱 W} +~ohVPhSDE ;}PPS t+~׃=Au A u SYY@}>ju SSPH@NuA @AjuS۰ _ A ^[ËT$Vt$ 3 2;r;sjXT$^ Vt$W|$V76 tFPj0 tFFPw0 tFFPw0 _^ËD$VW0x04? H׉p _H^ËD$VWPH ΉH _P^UE S]3;VEN@SSvQWE}SpSjEPSSZEeeEEPSEMu3_9Su(KC EsӾsuSEYfE^fC [U\SVW}EjE3ZE؉UEEE܉EEԉEЉEEE} t t t uGj^G w$@1| 9j:@ujFÃ+tHHtjEX맃ejX란1U|9~:@+t1-t,0tRCE~c{erjOj 1| 9V:@Y0U9@~VPہYYjZ @ÊA#ƅt}sEE0EEG:@ug}UUu 0uMG9@~VPjYYjZ @ÊA#ƅt}sEE0EMG빀+ -9@U~VP YYjZ @ÊA#ƅWO1M|9~DÃ+ttHHtdjeU0uG19 1|9 j XO0uD} t*ÍO+MtHHMjXjXj OX o}E3=@~jPYY @ÊAtˍtAЁPG뾾Qu=@~jPYY @ÊAtGOE }8jX9Ev}|EEEHEE}H8uMEEPEuPjE3Ƀ 9M}E9MuE9Mu+E=P~0E]uEU}t`3۸3E^=} EuPEP> U]‹uƋEʃ 33333333E}t3333EM E_qYfA E^f[~@ͺ@$@N@@ @V@@@@@@UES]VȾ#fWEEEEEEEEEEEE?EtC-C } fuu9}uf#C CC0f;uzf;u}t@uh@Fftu }u.h@;u#}uh@CPuYCYenh@CPXYCY‹ϋiMfej NfUkM} EEPEPa f}?rEFPEP(YYEf3t}}~j_u?feEEP]MYu}ށ~ EPnNYuOCɉE~PMu}EPEPEPEPEPEMe0EMuEHHH5K|0;r89u0H;s@f*,CdE_^[;r 80uH;sf#C C0cjXUM3SVAMWjAM[A Mt EE XtEEHtEEHtEEHtEEHu EjP#˃ _HEыP ʉHEыP ʉHEыP#σ ʉHEыP#˃ ʉHtMI tMI tMI tM y tE X  #t4=t=t ;u(E E E ˉE #t =t ;u"E E EEM ʉE X EH ωH EEXE XPEHP ϋ}HPEX@EPSjuD@E@t&@t&@t&@t&Xt&ߋt%ItIt IuN !tItIu!#ʀ#ʀ@@_^[]U ESWj[t]tS^YtEtjDYEj"Y M#tXt(;M `@Aw]EnM `@vAA]EFM `@vAA]EM `@Aw]EEV3tE ]E`@EEPQQ$E ]} ]TE`@s3ҊE fE;}+]tum]tMmHutE]EE ^tjYEtE t j xY3_[ËD$t~A"A!3UQ}EUQ}EUQ}E #E#M ȉM m EUQQMt -A]t-A]t -A]t ؛ t]ËD$V;`:AsZȃ `9ATLt>%9t$ u |$ @uɀ f%^A A ^U$S] VufK 3WEE܉EEfF 3##ʁf=Ufff?w3:fuEVu39Fu 9uo3f;uESu9Cu9u FFkEEEE E} ~IƍKEE MEEM MQP1 tEfEmMuȃEEM } Ef}~%EuEP:EYf}f}9Ef}}+EEEtEEP'KYu}tMf}wE%=u5}u,e}uef}u EfEfEEEދEf=sfM fMNMNfF ff&~_^[U SA3Ƀ`9M tc}E 8A؉E `9MuEf9M tAVWE T} ;t'@f<4r }MuVurYY39M u_^[%@UWVSM u} LAxuCAZ I& t! tFG8r8w8r8w8u Iu38tKrD@33ۋ t# tFGQPS؃Y;u Iu3;t rً[^_UWVSu }LAxu; t.F'G8t,A<ɀ A,A<ɀ A8t43ۋ t'FG8tPS4؃*8t[^_t$t$j US]tRSYuAA 3[ÍEe PPE@hP]E :E .<@Ph@@t@=wM u!;EEPwpYȅu A ;E~A"sPQYYaUEt$e @EEPE :E \@t tjX]3] 0@R`rtdXNB6".BTbp 2FZfx*.~p^@R @nF@F@__GLOBAL_HEAP_SELECTED__MSVCRT_HEAP_SELECT1X@5X@EEE50P (8PX700WP `h````ppxxxx(null)(null)?~PAGAIsProcessorFeaturePresentKERNEL32e+000?5h!>@@runtime error TLOSS error SING error DOMAIN error R6028 - unable to initialize heap R6027 - not enough space for lowio initialization R6026 - not enough space for stdio initialization R6025 - pure virtual function call R6024 - not enough space for _onexit/atexit table R6019 - unable to open console device R6018 - unexpected heap error R6017 - unexpected multithread lock error R6016 - not enough space for thread data abnormal program termination R6009 - not enough space for environment R6008 - not enough space for arguments R6002 - floating point not loaded Microsoft Visual C++ Runtime Library Runtime Error! Program: ...GetLastActivePopupGetActiveWindowMessageBoxAuser32.dll@@n@r@1#QNAN1#INF1#IND1#SNAN_yn_y1_y0frexpfmod_hypot_cabsldexpmodffabsfloorceiltancossinsqrtatan2atanacosasintanhcoshsinhlog10logpowexpTT@LD 0@R`rtdXNB6".BTbp 2FZfx*.~p^@R GetCurrentThreadId!GetLongPathNameA$GetModuleFileNameAGetCommandLineACloseHandleOpenFile GetFileAttributesA>GetProcAddressLoadLibraryAGetLastErrorFormatMessageAFreeLibraryLoadLibraryExAdEndUpdateResourceAUpdateResourceA BeginUpdateResourceAqEnumResourceNamesAKERNEL32.dllEnableWindowGetDlgItemIsDlgButtonChecked3CheckDlgButton,SetDlgItemTextAVGetWindowLongAXSetWindowLongAEndDialogDialogBoxParamAMessageBoxALoadStringAUSER32.dll GetOpenFileNameAcomdlg32.dllDragQueryFileASHELL32.dll[RegCloseKey{RegQueryValueExAqRegOpenKeyAADVAPI32.dllHeapAllocHeapFree&GetModuleHandleAPGetStartupInfoAtGetVersion}ExitProcess GetEnvironmentVariableAuGetVersionExAHeapDestroyHeapCreateVirtualFreeVirtualAllocHeapReAllocMultiByteToWideCharSGetStringTypeAVGetStringTypeWWideCharToMultiByteTerminateProcessGetCurrentProcessReadFilejSetFilePointermSetHandleCountRGetStdHandleGetFileTypeUnhandledExceptionFilterFreeEnvironmentStringsAFreeEnvironmentStringsWGetEnvironmentStringsGetEnvironmentStringsW/RtlUnwindWriteFileGetCPInfoGetACP1GetOEMCP|SetStdHandleFlushFileBuffers4CreateFileALCMapStringALCMapStringWaSetEndOfFile RaiseExceptionGetCurrentDirectoryAGetFullPathNameAGetDriveTypeA@ߐ@@-prp=-bmp=-ico=-cpl=-exe=-run_console.http://\=\:\\;\rb*.%s %s .cpl.exe.properties.ico.bmpControl PanelcplExecutableexePropertiespropertiesIconicoImage Bitmapbmp_console%s%s.properties%s.bmp%s.ico%s.cpl%s.exeJavaExeProtector_console.exeJavaExeProtector.exeJavaExe_console.exeJavaExe.exeJavaExe.cpl8@@@@@@t@\@@@@@@X@@@@@t@T@@@@@h@H@$@@d@,@@@@@@@@T@ @@@x@4@ @@@@@h@D@@@@@(@@@@@@@@@@@@@@@@A@@@@@@@@@@@@@@@@@@@@|@|@|@|@@@A@@@@@@@@@@@Windows ServiceCan't continueUpdateRsrcJavaExeJavaExe.PROPERTIES.BMPService WindowsJVM.EXE.ICOJava Runtime Environment (JRE)Impossible de continuerYou must rename JavaExe with the same name of your main .CLASS or .JAR Please consult the documentation at http://devwizard.free.fr/JavaExe.htmlThis file is already open : %sSource files not specifiedTarget files not specifiedThis image has the format : %dx%d (%d bits)This executable file is not JavaExeThis file contains the properties : %sIntegration of image %s to %s as startup screen"%s" isn't a BMP fileThe icon file %s was not foundThis file contains %d icon(s) : %s%dx%d (%d colors)The ControlPanel has already installed. Do you want to delete it ?Do you want to install this program as ControlPanel ?You don't have privileges to install a serviceThe service has already installed. Do you want to delete it ?The service has created, do you want to start it ?Do you want to install this program as Windows service ?Can't find main methodCan't find class "%s"Can't find main class "%s"Can't run the JVM"%s" isn't an icon file.EXE file not foundIcon not foundJava %s isn't installed ! Do you want to install it ?This executable file is not completVous devez renommer JavaExe selon le nom de votre .CLASS ou .JAR principal. Veuillez consulter la documentation http://devwizard.free.fr/JavaExe.htmlCe fichier est dj ouvert : %sFichiers sources non spcifisFichiers destinations non spcifisCette image a le format : %dx%d (%d bits)Ce fichier excutable n'est pas JavaExe.Ce fichier contient les properties : %sIntgration de l'image %s vers %s en tant qu'cran de dmarrage"%s" n'est pas un fichier BMPLe fichier d'icone %s est introuvableCe fichier contient %d icone(s) : %s%dx%d (%d couleurs)Le ControlPanel est dj install. Voulez-vous le supprimer ?Voulez-vous installer l'application en tant que ControlPanel ?Vous n'avez pas les droits pour installer un serviceLe service est dj install. Voulez-vous le supprimer ?Le service est cr, voulez-vous le lancer ?Voulez-vous installer l'application en tant que service Windows ?Mthode "main" introuvableClasse "%s" introuvableClasse principale "%s" introuvableImpossible de lancer la JVM"%s" n'est pas une iconeFichier .EXE introuvableIcone introuvableJava %s n'est pas install ! Voulez-vous l'installer ?Ce fichier excutable est incomplet.System33Control Panel\InternationaliCountry_console.exeBIN@@ ((((( H .us?B@VB@VB@?powIY@@@ @ @@@@ @@@@@@ܧ׹fq @ @6C ??exp!t@-w@2w@au@5h!??    @@ @ @p@@@@@@@X@ @@x@y@z@@@`y!@~ڣ @ڣ AϢ[@~QQ^ _j21~ 'A 'A        ! 5A CPR S WY l m pr   )    5 @  p??_ ?C;??@@@@ @@@@"@>@C@Y@^@z@@@@΢@Ӣ@@@@&@>@R@r@w@@@@ʣ@@@@@5@:@Z@n@@@@@٤@ޤ@@@*@>@^@c@}@@@@Υ@@@@!@&@F@Z@r@@@@@@@!@@ @@@x@t@p@ l@ d@ \@T@L@D@<@4@,@$@" @#@$@&D0@@@@ @P@$@@ @4@N@ p+ŝi@]%O@qוC)@D@<զIx@oGAkU'9p|Bݎ~QCv)/&D(DJzEeǑF e uuvHMXB䧓9;5SM]=];Z] T7aZ%]g']݀nLɛ R`%u?q= ףp= ף?Zd;On?,eX?#GGŧ?@il7?3=BzՔ?aw̫?/L[Mľ?S;uD?g9Eϔ?$#⼺;1az?aUY~S|_?/D?$?9'*?}d|FU>c{#Tw=:zc%C11/?32M2K3G4H5H6J7K9Z9L:M:M;[;N<O=R@i@SB^BnBUCVE[EWFhFXGZHZIaImI[J]L`LsL]M^MbPePaQbRkRqReUwUfVfViVdXhYq^Zh]u^|^t`lbqbrb{bteofxffpgvhxjyktlzl|nćn}p~qqrstvǍvxyz{|}ǐ}ʒ}ʓ~‹ÌÍÎĎÏĐőΙƓǔǕǖȗҟɞ˛˜˝͠զĢ΢ΣϣϥЦѨ٭ҩҪԮհְԲܵصصٶٸڸ༱B?ܼܽܽݾ»ýſƿ1.ͺ$!%"(%" -+1-31526397=:A?QMNLRORPWTXU\Z_]kivt|{{qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxX>((D_qqq>!>XpxkX6qqqqqqkpedzqqq>dqqqNqqqqqqp6(!!!((6>qqq]Xkqqqqqqd6e]_X]hniqqqNXʩqqqqqqqqqqqqqqqׯqqqѯqqqqqqqqqqqqqqqqqqqqqEqqqEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq( @Z/U0Z?4G4H6J7L:V:aAyTEXGpGZI\K]LaQbQqQbRfRcSwTfVdXrYj[l]n_o`~`rcse~fgwiÅkzlzm{mpqrrsǍvw}‹̕ÎĎőƓǔǖў˝̞֧͠ΣϣЦѨӬڱֲ׳״صٶ໰ڸڹںݿ¼ý$!2/4274B?EBNLSPRPVShfqnusVWjm33333333333333333333333333333333WWWWWWWWWWWWWWWWWWWWWWWWWWWWW33W3||||||||||||||||||||||||||W33W3||||||<$ )|||||||||W33W3||||0 4FO\ifaWND|||||||||W33W3||||TF||||||||||||||||||W33W3||||||<   &|||||||||||W33W3||||||||HUffi^\|||||||||||W33W3||||||||I2)9N|||||||||||W33W3|||||||YNWiWN,|||||||||||W33W3|||||||\BBBBB@||||||||||W33W3||||||$$$00B|||||||||W33W3|||||||TT|zj||||||||||W33W3|||||||||{gz|||||t||||W33W3|||||||||og|||||||ti||||W33W3|||||||||jc|||||||tt|||W33W3|||||||||q|||||||||ti|||W33W3|||||||||||||||||||tt||W33W3||||||||||||||||||||ti||W33W3||||||||||||||||||||||W33W3||||||||||||||||||||``|W33W3|||||||||||||||||||||```|W33W3|||||||||||||||||||||```|W33W333333333333333333333333333W33WWWWWWWWWWWWWWWWWWWWWWWWWWWWW33W33WWWWWWW33WWWWWWW33W33WWWWWWWWWWWWWWWWWWWWWWWWWWWWW33333333333333333333333333333333( @pn~װge8Ά<                   (0`tfeUWFP>G4G4G4G4G4G4G4H5M;VEbQȯUCK8G4G4XFk\xjy¡ykoabRH6H6yäiZpa¡̻{myl{¡þŦ[JG4G4G4G4G4G4G4n`ʩdTũĿ˸ũʶseTBP>L:K8L:O=O=SBXGgWiY¼n`Ũ|ƪĦĦǮͻϾ˸_OP>l]uk\n_gWk\ydnmy`xjYHaQyyլȰǮ͵O[[alx@@*'сbg$!ѮX\$!ccc( @ k\ZIRAH6J7G4G4I6I6P>ZIYHG4VEiY|̹οä~qR@r̻ǭͽϲylG4I6H5I6G4_OƫɳֺoaZISBgWvh¡Q?ȯħ~qǫɯʶRAP>wƢśǷyFO<@߮]d=<HJ54( @ǮG4G4ĥG4װ~qG4G4װؑ;ؑ;ؑ;e8G4Ά<Ά JavaExe 4VS_VERSION_INFO?StringFileInfo040c04b0BCommentsInsre un .ICO multi-format et/ou un BMP dans un .EXE de mme nom$CompanyName LFileDescriptionUpdateRsrcJavaExe(FileVersion2.0DInternalNameUpdateRsrcJavaExej#LegalCopyrightCopyright 2002-2007 by DevWizard`LegalTrademarksCopyright 2002-2007 by DevWizard email : DevWizard@free.fr @ : http://DevWizard.free.fr TOriginalFilenameUpdateRsrcJavaExe.exe PrivateBuildHProductName UpdateRsrcJavaExe,ProductVersion2.0 SpecialBuildDVarFileInfo$Translation Ȁ.JavaExe : Files IntegrationMS Sans SerifP2OKP2CancelPM Integration of .BMPP<I Integration of .ICOPdk Integration of .PROPERTIESPSources FilesP_Targets FilesP- into .EXEP- into .CPLDP#DP##DP#KDP#sDP#Pi< ?Pd ?P ...Pd ...P< ...PP ...PO ...Pi ?Ȁ.JavaExe : Intgration des fichiersMS Sans SerifP2OKP2AnnulerPc Intgration du fichier .BMPP<` Intgration du fichier .ICOPd Intgration du fichier .PROPERTIESPFichiers SourcesP_Fichiers DestinationsP7 vers le .EXEP6 vers le .CPLDP#DP##DP#KDP#sDP#Pw< ?Pd ?P ...Pd ...P< ...PP ...PO ...Px ?portmidi/pm_java/mac-make.sh0000644000000000000000000000155511322627742015043 0ustar rootroot# script to build a jar file to run PmDefaults from the command line on OS X # (This is for debugging. Normally, you would use XCode to build PmDefaults.app.) # Compile the java Portidi interface classes. javac jportmidi/*.java # Compile the pmdefaults application. javac -classpath . pmdefaults/*.java # Temporarily copy the portmusic_logo.png file here to add to the jar file. cp pmdefaults/portmusic_logo.png . # Create a directory to hold the distribution. mkdir mac-osx # Copy the interface DLL to the distribution directory. cp ../Release/libpmjni.dylib mac-osx # Create a java archive (jar) file of the distribution. jar cmf pmdefaults/manifest.txt mac-osx/pmdefaults.jar pmdefaults/*.class portmusic_logo.png jportmidi/*.class # Clean up the temporary image file now that it is in the jar file. rm portmusic_logo.png echo "You now have a jar file in mac-osx" portmidi/pm_java/README.txt0000644000000000000000000000355611215774554014542 0ustar rootrootREADME.txt Roger B. Dannenberg 16 Jun 2009 This directory was created to implement PmDefaults, a program to set default input and output devices for PortMidi applications. There are three main sub-projects here: 1) pmjni -- a JNI (Java Native Interface) to access PortMidi 2) jportmidi -- a Java class to access PortMidi (uses pmjni) 3) pmdefaults -- the PmDefaults application (uses jportmidi) For Mac OS X, you should build the PmDefaults application in Xcode. For Win32, an installer for PmDefaults is included in setup/. To build from sources, you should first build everything including the portmidi dll (that will be used by the Java application) using Visual C++ and a provided .sln file in the portmidi home directory. Then, run make.bat in this directory. The subdirectory win32 will be created with the application pmdefaults.exe. You can run this application in the normal way. To move the application, you need to copy *everything* in win32. To build setup/pmdefaults-setup.exe, I have used both Setup Generator from Gentee software and Inno Setup from jrsoftware.org. A script for Inno Setup is included in this directory, but since paths seem to be absolute, you will have to adjust the paths in the script before you use it. ---- implementation notes ---- For windows, we use the free software JavaExe.exe. The copy here was downloaded from http://software.techrepublic.com.com/abstract.aspx?kw=javaexe&docid=767485 I found this page by visiting http://software.techrepublic.com.com and searching in the "Software" category for "JavaExe" JavaExe works by placing the JavaExe.exe file in the directory with the Java application jar file and then *renaming* JavaExe.exe to the name of the jar file, but keeping the .exe extension. (See make.bat for this step.) Documentation for JavaExe can be obtained by downloading the whole program from the URL(s) above. portmidi/pm_java/jportmidi/0000755000000000000000000000000011453601074015022 5ustar rootrootportmidi/pm_java/jportmidi/JPortMidiException.java0000644000000000000000000000037711030706332021406 0ustar rootroot// JPortMidiException -- thrown by JPortMidi methods package jportmidi; public class JPortMidiException extends Exception { public int error = 0; public JPortMidiException(int err, String msg) { super(msg); error = err; } } portmidi/pm_java/jportmidi/JPortMidi.java0000644000000000000000000004455411030706332017534 0ustar rootrootpackage jportmidi; /* PortMidi is a general class intended for any Java program using the PortMidi library. It encapsulates JPortMidiApi with a more object-oriented interface. A single PortMidi object can manage up to one input stream and one output stream. This class is not safely callable from multiple threads. It is the client's responsibility to periodically call the Poll method which checks for midi input and handles it. */ import jportmidi.*; import jportmidi.JPortMidiApi.*; public class JPortMidi { // timecode to send message immediately public final int NOW = 0; // midi codes public final int MIDI_NOTE_OFF = 0x80; public final int MIDI_NOTE_ON = 0x90; public final int CTRL_ALL_OFF = 123; public final int MIDI_PITCH_BEND = 0xE0; public final int MIDI_CLOCK = 0xF8; public final int MIDI_CONTROL = 0xB0; public final int MIDI_PROGRAM = 0xC0; public final int MIDI_START = 0xFA; public final int MIDI_STOP = 0xFC; public final int MIDI_POLY_TOUCH = 0xA0; public final int MIDI_TOUCH = 0xD0; // error code -- cannot refresh device list while stream is open: public final int pmStreamOpen = -5000; public final int pmOutputNotOpen = -4999; // access to JPortMidiApi is through a single, global instance private static JPortMidiApi pm; // a reference count tracks how many objects have it open private static int pmRefCount = 0; private static int openCount = 0; public int error; // user can check here for error codes private PortMidiStream input; private PortMidiStream output; private PmEvent buffer; protected int timestamp; // remember timestamp from incoming messages protected boolean trace = false; // used to print midi msgs for debugging public JPortMidi() throws JPortMidiException { if (pmRefCount == 0) { pm = new JPortMidiApi(); pmRefCount++; System.out.println("Calling Pm_Initialize"); checkError(pm.Pm_Initialize()); System.out.println("Called Pm_Initialize"); } buffer = new PmEvent(); } public boolean getTrace() { return trace; } // set the trace flag and return previous value public boolean setTrace(boolean flag) { boolean previous = trace; trace = flag; return previous; } // WARNING: you must not call this if any devices are open public void refreshDeviceLists() throws JPortMidiException { if (openCount > 0) { throw new JPortMidiException(pmStreamOpen, "RefreshDeviceLists called while stream is open"); } checkError(pm.Pm_Terminate()); checkError(pm.Pm_Initialize()); } // there is no control over when/whether this is called, but it seems // to be a good idea to close things when this object is collected public void finalize() { if (input != null) { error = pm.Pm_Close(input); } if (input != null) { int rslt = pm.Pm_Close(output); // we may lose an error code from closing output, but don't // lose any real error from closing input... if (error == pm.pmNoError) error = rslt; } pmRefCount--; if (pmRefCount == 0) { error = pm.Pm_Terminate(); } } int checkError(int err) throws JPortMidiException { // note that Pm_Read and Pm_Write return positive result values // which are not errors, so compare with >= if (err >= pm.pmNoError) return err; if (err == pm.pmHostError) { throw new JPortMidiException(err, pm.Pm_GetHostErrorText()); } else { throw new JPortMidiException(err, pm.Pm_GetErrorText(err)); } } // ******** ACCESS TO TIME *********** public void timeStart(int resolution) throws JPortMidiException { checkError(pm.Pt_TimeStart(resolution)); } public void timeStop() throws JPortMidiException { checkError(pm.Pt_TimeStop()); } public int timeGet() { return pm.Pt_Time(); } public boolean timeStarted() { return pm.Pt_TimeStarted(); } // ******* QUERY DEVICE INFORMATION ********* public int countDevices() throws JPortMidiException { return checkError(pm.Pm_CountDevices()); } public int getDefaultInputDeviceID() throws JPortMidiException { return checkError(pm.Pm_GetDefaultInputDeviceID()); } public int getDefaultOutputDeviceID() throws JPortMidiException { return checkError(pm.Pm_GetDefaultOutputDeviceID()); } public String getDeviceInterf(int i) { return pm.Pm_GetDeviceInterf(i); } public String getDeviceName(int i) { return pm.Pm_GetDeviceName(i); } public boolean getDeviceInput(int i) { return pm.Pm_GetDeviceInput(i); } public boolean getDeviceOutput(int i) { return pm.Pm_GetDeviceOutput(i); } // ********** MIDI INTERFACE ************ public boolean isOpenInput() { return input != null; } public void openInput(int inputDevice, int bufferSize) throws JPortMidiException { openInput(inputDevice, "", bufferSize); } public void openInput(int inputDevice, String inputDriverInfo, int bufferSize) throws JPortMidiException { if (isOpenInput()) pm.Pm_Close(input); else input = new PortMidiStream(); if (trace) { System.out.println("openInput " + getDeviceName(inputDevice)); } checkError(pm.Pm_OpenInput(input, inputDevice, inputDriverInfo, bufferSize)); // if no exception, then increase count of open streams openCount++; } public boolean isOpenOutput() { return output != null; } public void openOutput(int outputDevice, int bufferSize, int latency) throws JPortMidiException { openOutput(outputDevice, "", bufferSize, latency); } public void openOutput(int outputDevice, String outputDriverInfo, int bufferSize, int latency) throws JPortMidiException { if (isOpenOutput()) pm.Pm_Close(output); else output = new PortMidiStream(); if (trace) { System.out.println("openOutput " + getDeviceName(outputDevice)); } checkError(pm.Pm_OpenOutput(output, outputDevice, outputDriverInfo, bufferSize, latency)); // if no exception, then increase count of open streams openCount++; } public void setFilter(int filters) throws JPortMidiException { if (input == null) return; // no effect if input not open checkError(pm.Pm_SetFilter(input, filters)); } public void setChannelMask(int mask) throws JPortMidiException { if (input == null) return; // no effect if input not open checkError(pm.Pm_SetChannelMask(input, mask)); } public void abort() throws JPortMidiException { if (output == null) return; // no effect if output not open checkError(pm.Pm_Abort(output)); } // In keeping with the idea that this class represents an input and output, // there are separate Close methods for input and output streams, avoiding // the need for clients to ever deal directly with a stream object public void closeInput() throws JPortMidiException { if (input == null) return; // no effect if input not open checkError(pm.Pm_Close(input)); input = null; openCount--; } public void closeOutput() throws JPortMidiException { if (output == null) return; // no effect if output not open checkError(pm.Pm_Close(output)); output = null; openCount--; } // Poll should be called by client to process input messages (if any) public void poll() throws JPortMidiException { if (input == null) return; // does nothing until input is opened while (true) { int rslt = pm.Pm_Read(input, buffer); checkError(rslt); if (rslt == 0) return; // no more messages handleMidiIn(buffer); } } public void writeShort(int when, int msg) throws JPortMidiException { if (output == null) throw new JPortMidiException(pmOutputNotOpen, "Output stream not open"); if (trace) { System.out.println("writeShort: " + Integer.toHexString(msg)); } checkError(pm.Pm_WriteShort(output, when, msg)); } public void writeSysEx(int when, byte msg[]) throws JPortMidiException { if (output == null) throw new JPortMidiException(pmOutputNotOpen, "Output stream not open"); if (trace) { System.out.print("writeSysEx: "); for (int i = 0; i < msg.length; i++) { System.out.print(Integer.toHexString(msg[i])); } System.out.print("\n"); } checkError(pm.Pm_WriteSysEx(output, when, msg)); } public int midiChanMessage(int chan, int status, int data1, int data2) { return (((data2 << 16) & 0xFF0000) | ((data1 << 8) & 0xFF00) | (status & 0xF0) | (chan & 0xF)); } public int midiMessage(int status, int data1, int data2) { return ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF)); } public void midiAllOff(int channel) throws JPortMidiException { midiAllOff(channel, NOW); } public void midiAllOff(int chan, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_CONTROL, CTRL_ALL_OFF, 0)); } public void midiPitchBend(int chan, int value) throws JPortMidiException { midiPitchBend(chan, value, NOW); } public void midiPitchBend(int chan, int value, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_PITCH_BEND, value, value >> 7)); } public void midiClock() throws JPortMidiException { midiClock(NOW); } public void midiClock(int when) throws JPortMidiException { writeShort(when, midiMessage(MIDI_CLOCK, 0, 0)); } public void midiControl(int chan, int control, int value) throws JPortMidiException { midiControl(chan, control, value, NOW); } public void midiControl(int chan, int control, int value, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_CONTROL, control, value)); } public void midiNote(int chan, int pitch, int vel) throws JPortMidiException { midiNote(chan, pitch, vel, NOW); } public void midiNote(int chan, int pitch, int vel, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_NOTE_ON, pitch, vel)); } public void midiProgram(int chan, int program) throws JPortMidiException { midiProgram(chan, program, NOW); } public void midiProgram(int chan, int program, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_PROGRAM, program, 0)); } public void midiStart() throws JPortMidiException { midiStart(NOW); } public void midiStart(int when) throws JPortMidiException { writeShort(when, midiMessage(MIDI_START, 0, 0)); } public void midiStop() throws JPortMidiException { midiStop(NOW); } public void midiStop(int when) throws JPortMidiException { writeShort(when, midiMessage(MIDI_STOP, 0, 0)); } public void midiPolyTouch(int chan, int key, int value) throws JPortMidiException { midiPolyTouch(chan, key, value, NOW); } public void midiPolyTouch(int chan, int key, int value, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_POLY_TOUCH, key, value)); } public void midiTouch(int chan, int value) throws JPortMidiException { midiTouch(chan, value, NOW); } public void midiTouch(int chan, int value, int when) throws JPortMidiException { writeShort(when, midiChanMessage(chan, MIDI_TOUCH, value, 0)); } // ****** now we implement the message handlers ****** // an array for incoming sysex messages that can grow. // The downside is that after getting a message, we private byte sysexBuffer[] = null; private int sysexBufferIndex = 0; void sysexBufferReset() { sysexBufferIndex = 0; if (sysexBuffer == null) sysexBuffer = new byte[256]; } void sysexBufferCheck() { if (sysexBuffer.length < sysexBufferIndex + 4) { byte bigger[] = new byte[sysexBuffer.length * 2]; for (int i = 0; i < sysexBufferIndex; i++) { bigger[i] = sysexBuffer[i]; } sysexBuffer = bigger; } // now we have space to write some bytes } // call this to insert Sysex and EOX status bytes // call sysexBufferAppendBytes to insert anything else void sysexBufferAppendStatus(byte status) { sysexBuffer[sysexBufferIndex++] = status; } void sysexBufferAppendBytes(int msg, int len) { for (int i = 0; i < len; i++) { byte b = (byte) msg; if ((msg & 0x80) != 0) { if (b == 0xF7) { // end of sysex sysexBufferAppendStatus(b); sysex(sysexBuffer, sysexBufferIndex); return; } // recursively handle embedded real-time messages PmEvent buffer = new PmEvent(); buffer.timestamp = timestamp; buffer.message = b; handleMidiIn(buffer); } else { sysexBuffer[sysexBufferIndex++] = b; } msg = msg >> 8; } } void sysexBegin(int msg) { sysexBufferReset(); // start from 0, we have at least 256 bytes now sysexBufferAppendStatus((byte) (msg & 0xFF)); // first byte is special sysexBufferAppendBytes(msg >> 8, 3); // process remaining bytes } public void handleMidiIn(PmEvent buffer) { if (trace) { System.out.println("handleMidiIn: " + Integer.toHexString(buffer.message)); } // rather than pass timestamps to every handler, where typically // timestamps are ignored, just save the timestamp as a member // variable where methods can access it if they want it timestamp = buffer.timestamp; int status = buffer.message & 0xFF; if (status < 0x80) { sysexBufferCheck(); // make enough space sysexBufferAppendBytes(buffer.message, 4); // process 4 bytes return; } int command = status & 0xF0; int channel = status & 0x0F; int data1 = (buffer.message >> 8) & 0xFF; int data2 = (buffer.message >> 16) & 0xFF; switch (command) { case MIDI_NOTE_OFF: noteOff(channel, data1, data2); break; case MIDI_NOTE_ON: if (data2 > 0) { noteOn(channel, data1, data2); break; } else { noteOff(channel, data1); } break; case MIDI_CONTROL: control(channel, data1, data2); break; case MIDI_POLY_TOUCH: polyTouch(channel, data1, data2); break; case MIDI_TOUCH: touch(channel, data1); break; case MIDI_PITCH_BEND: pitchBend(channel, (data1 + (data2 << 7)) - 8192); break; case MIDI_PROGRAM: program(channel, data1); break; case 0xF0: switch (channel) { case 0: sysexBegin(buffer.message); break; case 1: mtcQuarterFrame(data1); case 2: songPosition(data1 + (data2 << 7)); break; case 3: songSelect(data1); break; case 4: /* unused */ break; case 5: /* unused */ break; case 6: tuneRequest(); break; case 7: sysexBufferAppendBytes(buffer.message, buffer.message); break; case 8: clock(); break; case 9: tick(); break; case 0xA: clockStart(); break; case 0xB: clockContinue(); break; case 0xC: clockStop(); break; case 0xD: /* unused */ break; case 0xE: activeSense(); break; case 0xF: reset(); break; } } } // the value ranges from +8181 to -8192. The interpretation is // synthesizer dependent. Often the range is +/- one whole step // (two semitones), but the range is usually adjustable within // the synthesizer. void pitchBend(int channel, int value) { return; } void control(int channel, int control, int value) { return; } void noteOn(int channel, int pitch, int velocity) { return; } // you can handle velocity in note-off if you want, but the default // is to drop the velocity and call the simpler NoteOff handler void noteOff(int channel, int pitch, int velocity) { noteOff(channel, pitch); } // if the subclass wants to implement NoteOff with velocity, it // should override the following to make sure all NoteOffs are handled void noteOff(int channel, int pitch) { return; } void program(int channel, int program) { return; } // the byte array may be bigger than the message, length tells how // many bytes in the array are part of the message void sysex(byte[] msg, int length) { return; } void polyTouch(int channel, int key, int value) { return; } void touch(int channel, int value) { return; } void mtcQuarterFrame(int value) { return; } // the value is a 14-bit integer representing 16th notes void songPosition(int value) { return; } void songSelect(int value) { return; } void tuneRequest() { return; } void clock() { return; } // represents 1/24th of a quarter note void tick() { return; } // represents 10ms void clockStart() { return; } void clockStop() { return; } void clockContinue() { return; } void activeSense() { return; } void reset() { return; } } portmidi/pm_java/jportmidi/JPortMidiApi.java0000644000000000000000000001263311254141714020164 0ustar rootrootpackage jportmidi; public class JPortMidiApi { public static class PortMidiStream { private long address; } public static class PmEvent { public int message; public int timestamp; } // PmError bindings public final int pmNoError = 0; public final int pmNoData = 0; public final int pmGotData = -1; public final int pmHostError = -10000; public final int pmInvalidDeviceId = -9999; public final int pmInsufficientMemory = -9998; public final int pmBufferTooSmall = -9997; public final int pmBufferOverflow = -9996; public final int pmBadPtr = -9995; public final int pmBadData = -9994; public final int pmInternalError = -9993; public final int pmBufferMaxSize = -9992; static public native int Pm_Initialize(); static public native int Pm_Terminate(); static public native int Pm_HasHostError(PortMidiStream stream); static public native String Pm_GetErrorText(int errnum); static public native String Pm_GetHostErrorText(); final int pmNoDevice = -1; static public native int Pm_CountDevices(); static public native int Pm_GetDefaultInputDeviceID(); static public native int Pm_GetDefaultOutputDeviceID(); static public native String Pm_GetDeviceInterf(int i); static public native String Pm_GetDeviceName(int i); static public native boolean Pm_GetDeviceInput(int i); static public native boolean Pm_GetDeviceOutput(int i); static public native int Pm_OpenInput(PortMidiStream stream, int inputDevice, String inputDriverInfo, int bufferSize); static public native int Pm_OpenOutput(PortMidiStream stream, int outputDevice, String outnputDriverInfo, int bufferSize, int latency); final static public int PM_FILT_ACTIVE = (1 << 0x0E); final static public int PM_FILT_SYSEX = (1 << 0x00); final static public int PM_FILT_CLOCK = (1 << 0x08); final static public int PM_FILT_PLAY = (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B); final static public int PM_FILT_TICK = (1 << 0x09); final static public int PM_FILT_FD = (1 << 0x0D); final static public int PM_FILT_UNDEFINED = PM_FILT_FD; final static public int PM_FILT_RESET = (1 << 0x0F); final static public int PM_FILT_REALTIME = PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK; final static public int PM_FILT_NOTE = (1 << 0x19) | (1 << 0x18); final static public int PM_FILT_CHANNEL_AFTERTOUCH = (1 << 0x1D); final static public int PM_FILT_POLY_AFTERTOUCH = (1 << 0x1A); final static public int PM_FILT_AFTERTOUCH = (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH); final static public int PM_FILT_PROGRAM = (1 << 0x1C); final static public int PM_FILT_CONTROL = (1 << 0x1B); final static public int PM_FILT_PITCHBEND = (1 << 0x1E); final static public int PM_FILT_MTC = (1 << 0x01); final static public int PM_FILT_SONG_POSITION = (1 << 0x02); final static public int PM_FILT_SONG_SELECT = (1 << 0x03); final static public int PM_FILT_TUNE = (1 << 0x06); final static public int PM_FILT_SYSTEMCOMMON = (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE); static public native int Pm_SetFilter(PortMidiStream stream, int filters); static public int Pm_Channel(int channel) { return 1 << channel; } final static public native int Pm_SetChannelMask(PortMidiStream stream, int mask); final static public native int Pm_Abort(PortMidiStream stream); final static public native int Pm_Close(PortMidiStream stream); static public int Pm_Message(int status, int data1, int data2) { return (((data2 << 16) & 0xFF0000) | ((data1 << 8) & 0xFF00) | (status & 0xFF)); } static public int Pm_MessageStatus(int msg) { return msg & 0xFF; } static public int Pm_MessageData1(int msg) { return (msg >> 8) & 0xFF; } static public int Pm_MessageData2(int msg) { return (msg >> 16) & 0xFF; } // only supports reading one buffer at a time static public native int Pm_Read(PortMidiStream stream, PmEvent buffer); static public native int Pm_Poll(PortMidiStream stream); // only supports writing one buffer at a time static public native int Pm_Write(PortMidiStream stream, PmEvent buffer); static public native int Pm_WriteShort(PortMidiStream stream, int when, int msg); static public native int Pm_WriteSysEx(PortMidiStream stream, int when, byte msg[]); public final int ptNoError = 0; public final int ptAlreadyStarted = -10000; public final int ptAlreadyStopped = -9999; public final int PtInsufficientMemory = -9998; static public native int Pt_TimeStart(int resolution); static public native int Pt_TimeStop(); static public native int Pt_Time(); static public native boolean Pt_TimeStarted(); static { System.out.println("Loading pmjni"); System.loadLibrary("pmjni"); System.out.println("done loading pmjni"); } } portmidi/pm_java/make.bat0000644000000000000000000000302111261603452014421 0ustar rootroot@echo off rem Compile the java PortMidi interface classes. javac jportmidi/*.java rem Compile the pmdefaults application. javac -classpath . pmdefaults/*.java rem Temporarily copy the portmusic_logo.png file here to add to the jar file. copy pmdefaults\portmusic_logo.png . > nul rem Create a directory to hold the distribution. mkdir win32 rem Attempt to copy the interface DLL to the distribution directory. if exist "..\release\pmjni.dll" goto have-dll echo "ERROR: pmjni.dll not found!" exit /b 1 :have-dll copy "..\release\pmjni.dll" win32\pmjni.dll > nul rem Create a java archive (jar) file of the distribution. jar cmf pmdefaults\manifest.txt win32\pmdefaults.jar pmdefaults\*.class portmusic_logo.png jportmidi\*.class rem Clean up the temporary image file now that it is in the jar file. del portmusic_logo.png rem Copy the java execution code obtained from rem http://devwizard.free.fr/html/en/JavaExe.html to the distribution rem directory. The copy also renames the file to our desired executable rem name. copy JavaExe.exe win32\pmdefaults.exe > nul rem Integrate the icon into the executable using UpdateRsrcJavaExe from rem http://devwizard.free.fr UpdateRsrcJavaExe -run -exe=win32\pmdefaults.exe -ico=pmdefaults\pmdefaults.ico rem Copy the 32-bit windows read me file to the distribution directory. copy pmdefaults\readme-win32.txt win32\README.txt > nul rem Copy the license file to the distribution directory. copy pmdefaults\pmdefaults-license.txt win32\license.txt > nul echo "You can run pmdefaults.exe in win32" portmidi/pm_java/setup/0000755000000000000000000000000011453601074014161 5ustar rootrootportmidi/pm_java/setup/pmdefaults-setup.exe0000644000000000000000000166322511453600330020177 0ustar rootrootMZP@ !L!This program must be run under Win32 $7PEL^B* X@@P ؜CODEt `DATAL@BSSH.idataP @.tls.rdata@P.reloc@P.rsrc؜@P@@P string<@m@)@(@(@)@ $)@Free0)@ InitInstanceL)@CleanupInstanceh(@ ClassTypel(@ ClassName(@ ClassNameIs(@ ClassParent)@ ClassInfo(@ InstanceSize)@ InheritsFrom)@Dispatch)@ MethodAddress<*@ MethodNamex*@ FieldAddress)@DefaultHandler(@ NewInstance(@ FreeInstanceTObject@Í@% @%@%@%@%@% @%@%(@%@%@%@%@%@%@%@%@%@%@%@%@%@%@@%<@%8@%4@%0@%@%@%@%@%@%@%@%@SV8@>u:hDjȅu3^[á4@ 4@3ҋDBdu^[Ð@ËSVu3^[ËPVP XB^[ËP Q8@8@SVWUQ$]$PV;CS ;uCC FV;u C F;u‹֋Uu3Z]_^[Í@SVWU؋2C;rlJk ;w^;uBCB)C { uD5; r΋{ ;u)s & J $+|$+ЉS ԋu3 ;u3YZ]_^[ÐSVWڋ} sjh Vj;t#Ӹ<@luhjP3_^[ÐSVWUًCjh hU;usjh VU;t#Ӹ<@uhjPb3]_^[ÐSVWUL$$D$3҉T$ $ʼnD$<@Q;s;wFC ;D$w;;t$st$C ;D$ vD$ hjVu @߁<@uD$3҉|$ tD$T$D$ +D$T$B]_^[SVWUL$$Ћ$T$D$(D$+ŋT$B5<@<^~ ;v;|$v|$;vjh+WS&u D$3҉ 6<@u ]_^[ËSVWUQ؋4$$+$A5<@8^~ ;$s$;s;vh@+WSu @6<@uZ]_^[Í@SVWUL@?]3;{ ,΋׋C>tPFCF)C { u>5;uɋ֋>t!̋֋<$űV3YZ]_^[ËSVWU $L@?];t;su;suW;{ L$+S CC |$t3L$ T$]|$ uL$ T$D$%$3҉L$׋|$t4L$ T$|$ fL$ T$D$$3҉Hk;u:;{ 5 $׋q$8t($@C$@)C { u$3҉]_^[ÐSVW$?4$;s[ϋ+ӋL$׸L@]\$tL$ T$&D$ D$D$D$|$tT$L@3_^[U3Uh@d2d"h@9=2@t h@.<@L@x@xhjt@=t@t/t@3ɉL@=u\@@h@@3ZYYdh@=2@t h@)@]US=@3Uh@d2d"=2@t h@f@t@P43t@<@hjCP%<@u<@L@x@u4@t4@P4@udh@=2@t h@h@C[]ËS;h@u Ph@PH*;ut@3҉Tt@TP[ËP[Ðx@J;rJ ;rx@u@3ҋÐSʃ|[Ã| ʁ [@Ѓ@Ë |Ã| ʁƒ SVЃʁt @ځ+Ë3t @t Ѓ r+;pt @ދ^[Í@SVW3t %؋uhF؃#_^[SVWU؋kC Ѝ 7+у ++Ń }̋+S׋̋׃F,$u30+֋pD$SS ;s 7+ԋYZ]_^[SVW߉sƃ p0t@Dut@\[:CZ,<| ֋ uh@h@CZ_^[Ë=l@~@=l@ } @+l@p@p@3p@3l@ËSVW<$L$׸x@<\$u3R;s )GGt$ ;sGG;u op@Gl@_^[Í@S؋ԍCp<$t Wu3YZ[ÐSV؋̍V<$t &u3YZ^[Í@3=wt@Tu@=uÍ@SVWUh@l@`@;sC;~{s[;sB;tc ؅uNu3;u)u} }u3Ep@5p@փ@5@L6S+ƃ | ֒`;uCƃ Ëփ@5@]_^[USVW؀=@u+u 3ET3UhH!@d6d&=2@t h@X } Åyt@Ttyʋà B;uÅy5t@3|&y=t@D2uuFu0RE@@;l@J)l@=l@ } l@3l@p@p@ӃE@@92E3ZYYdhO!@=2@t h@5 E_^[YY]Í@UQSVW3@=@uu@Ea3Uh"@d1d!=2@t h@u@ @%)@tEƃ P |t@ +;Pt@ ڋË;=p@u,)p@l@=l@<~3E t} @ 7)ǃxt 8tx } @ PӋ;@E3ZYYdh"@=2@t h@ E_^[Y]ËSVWU } }Nj;+։$;p@u8$)p@$l@=l@ L$p@$)l@3u ËP$0<$ |ދ$Ã+ljD$;p@ugl@;D$|SD$)l@D$p@=l@ }l@p@5l@3l@+@E% uUuMӋ‹H $ $;L$s$ڋ$)D$,fD$)$<$ |Ƌ$:4$ރ#.t!%Ë؋T$t  3+@E% uYZ]_^[ÐUQSVW؀=@u/u 3E3Uh%@d2d"=2@t h@\֋t]7Ã%;}ƅtȋ׋-}3ZYYdh%@=2@t h@uE_^[Y]Ët @ tðjÐt @ uðRÐt2tP @Y tð.@ uðtP@Y tÍ@ @tZH=&@y " ËPRQ YZXu1Í@P Í@VWƉ׉9t/x*_^Ít|x_^UEPEkN8tfOu@u\2 uIuF_^[ËSVW11ɋp܅tf;VtfIu@u߈ 1ɊA_^[SVW11Pp؅tf>N8ttOu@uZN\2 uIuZ_^[RQSP1ҍL$diA*@A d [YZD$,@ &ËRË=@vjjjhË=@tPPRTjjhyXTjjheXÀ=@v PsÐ=@vPSÍ@tA9t 9u AAË=@vPRQQTjjhYYZXË=@vRTjjhZÐ=@vPRTjjhZXÍ@D$@8PHt/0 @҅T$ ‹D$H HS1VWUdSPRQT$(jPhy,@RS|$(o_G,@RA_ÐD$@8tr@҅u @T$SVWUJYq ŋt=9t7H;Ou@W1Ɋ: u @BtuԃKu]_^[D$8PHt @T$‹D$H 1dSPRQT$(HVjPh-@R$[|$(oG-@D$c#vA0ËD$T$@tJB,.@SVWUj~]_^[ËU1hd.@dudetx N,NUy/11GD$T$@uHjPh.@R@D$Pu@@ 1dedE]Í@ZTUWVSPRTjjhRÍ@D$0@/@t B `8t B1dY]_^[Í@+ BZd$,1YdX]{1ҋL$D$d Ë$Í@UU=,t\=tW-t\-t=HtN`q?r6t0R=t=-t.HtHt$:-t/=t&,*&" %R X]D$@uk2T$jPh<0@R\$;SCt @҅S x @tыL$Q$ 1Ð1ҍEd d@0@h@Ë1ҋ@d 9udË t9uÍ@j@@@ 4.@Í@S=@} ! hj@ ؅u  S@P@[Ë 0@@u(d,@PtË@PztÐtJI| JuBSVÉ֋tJI| JuBNu^[Ët#JAPRBXXRH|ZXJtJI| JuBÍ@t JA~JtJI| JuBZÐ~P 3ZP@1ÐSVWÉ։ωDžt ‰;_^[ËRZÐ1Ɋ BÐ1Ʌt!R: t:Jt:Jt :JtBBBZ)Í@t@Åt?SVWÉ֋yV9tNT_^[Åta;t\;tPQZXSVWӉPCFlj‰؋KNSXtOG_^[É@Ku=1@ujh2@h@j@@18@@ =@u5 @@ @@=@5 @@-@ 0123456789ABCDEF33҉(@3(@SVڋVt waƉ^Vt^[øf뾺뷺VWxu.xx P+P ;P +PQPu3YXH _^=@uQRPXZYxtixqYX͋ʺ8@@~!@PQ@z-u YXՅ`YX3Ɋ BRS3ۊ+~ PRZX[B5x@&%xuH ;H} H@ PRPu'ZX=@uRPXZxtɸiZXRQ1ԹZ3VWQIZ+ыQYƋ_^|HtE=Ѓ,U@@t$Ѓt ,UA@t ,EB@=}BЃ,U@@tЃt ,UA@tȍ,EB@-@@?@@@@ @P@$@@ @(k@ @@C#@&@*焑*@ -@1_0@4@.7@@v:k :@#NJ>@bxA@z&D@n2xH@W ?hK@N@@aQYR@ȥoU@: 'X@ x9?\@ 6_@Ngb@"E@|oe@p+ŝi@զIx@=AGA+BkU'9p|B09FǑF uuvHM䧓9;5S]=];Z T7aZ%]g']݀n R`%uYnb5{USVW3UhC@d0d @@3 @3$@3(@13҉3,@3@4@5@f@f@8@C@@C@3ZYYdhC@m_^[]%X@%T@%P@%L@%H@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%@%|@%x@%t@%p@%l@%h@%d@%`@%8@%<@%4@%0@%,@%(@%$@% @%@%@%@%@E@E@ <@)@(@(@)@@ ExceptionF@ E@)@(@(@)@EAbort3҉YZ[SڋJtJr T@Ũ@HBGSY[Í@=,tY=tS-tU-tt@@ٰ0B t tࠛ@f t0 t33+%@fM Ip+Mr3ɰE]UJ u3 }- tĪP35l\@0CI u K;uXUrM 0(3ۀ}t HCIt Ku@ t@ 0Jt AuJu3ۊ@}t @:vݍ^@<@tQS<$t<*t N[YCV5@tN^$*@@@*$@@@$ *@@* $@@($*)@-$*@@$-*@@$*-@@(*$)@-*$@@*-$@@*$-@@-* $@-$ *@* $-@$ *-@$ -*@*- $@($ *)(* $)U@WVSEٹt GtOG  GtOtLE'}u +EиPRE׋ffEf=tf=tu f=~}ujjjE׋!}ut;utI[^_]u<'t$<"t t<;u t<;u u t<;Ê:t uSu33EUU<#t&<0t%<.t,<,t3<'t5<"t10trS]U+U*[눋+EÃ}t| Mu E؋E;E~AC u KE;E~10}u ࠛ@f}tE܃~u@MUWVS؋t [^_]fF%t=uf~t@3C.-?iM@E+Ex-|\@ٛ}fEAt 5l\@Eu{ Df00fJu2}}y3;} r} s'|;5r%D;Ox D;|;9wfC1ED;Ox|;0tEfVffSËV  y؃3ɋ} }3|A-dڳ sIdҳ EUm׸+t4h\@u{ u D u$uIu90 D 0$0IuǍL+O?0tV33҈CfSUWVSٛ}-\@>+t-uF3Ҋ:@uFm;tJ$u.€u-ut??f u3m[^_]ì t< tN33Ҭ,: s l\@EEBN33Ҋ+t-uF,: sFk Ёr-uUSVW3UhNe@d0d 3ZYYdhUe@_^[]Ë%D@ËH;Jw r; wr1@Ã1ÐPÐSV؅t",/t,-tƹe@^[ËƋc^[\SV؊D3Pt;}^[ø^[ÐUSVW3ۉ]M3Uh|f@d0d ؅uEϋ EPIUE3ZYYdhf@E{_^[YY]ËSVWUQ$W|Y,/t,-uOF,/t,-uD3;|4D,/t,-uE}"C;|D,/t,-t Ӌ;}̋H^|,/t,-u<$tB3>~8C;|%|:u<$t;~,/t,-uC3Z]_^[Í@SVWU$|$n_;|3D,/t,-u<$t|$CӋ#؋HD$;}͋YZ]_^[ÐSVWPTD$Ph%PGÅ~}T$Njh Nj_^[Í@SVWU3"C;||.uC Ӌz;}]_^[ÐSVWزWV_^[ËS؅u3[ËNPSt[ËSVWU&K;}PVC,/t,-t;u ŋ-U˺D]_^[Í@UjSVW3Uh`i@d0d UzEP3ZYYdhgi@E9_^[Y]Ðtu3ðS؋@[SVWڋúIFP^PVPXu ËLt_^[UQSVWU3҉3"u}t }@t  u_^[Y]ËUSVW3ɉM3Uhj@d0d M3ҋEM3EЍMk؋ƋUcCH, r3ZYYdhj@ER_^[YY]Í@UjSVW3Uhj@d0d 7UOЋ3ZYYdhk@E_^[Y]Í@UjSVW3UhWk@d0d U3 CU8u3ZYYdh^k@EB_^[Y]ËUSVW3ɉM3Uhk@d0d u$hPjȍ-T8u EU]tKƋUL3ZYYdhk@E_^[]ShD$PpӋ [Í@UjjSVW3Uhl@d0d Ӹm@>;t uHӸ m@";t u,=|@uӸm@;t uVUEUU_3ZYYdhl@E_^[YY]TMPTEMP USERPROFILESVW;ËNj_^[ËUSVW3ۉ]M3Uhmn@d0d 33EEPjEPjWV3E;E t E;E}uEEM3EPEMPEPjWV=tukE;E t E;Eu[M}t EU|t}u }tEEU}u}tEUDEU3ZYYdhtn@E,銿_^[]jjËUVu <uEPVEPQR^] 3ɉcËUSRE3Uh6o@d0d }3Uho@d0d PE3ZYYdho@m߾3ZYYdh=o@EPE[]Í@USVW3EE3UhMp@d0d h`p@h|p@P؅t Ӌ=|@u8jjEPp@3uQMp@EEP6jjEPp@3uMp@EEPp@EEUEU菷؃}t33ZYYdhTp@ETEL骽_^[]GetUserDefaultUILanguagekernel32.dll.DEFAULT\Control Panel\InternationalLocaleControl Panel\Desktop\ResourceLocale$SVڋË);t8.v ú,q@^[.SV؅uƺq@.úE@ t ֋Cԋԋ7^[[ExceptObject=nil]SjhT$RjPjh2(H~T!r tԋˑ[ÐuC ^[Í@SVW؋ԹCSt C3ɺP蕩jD$ PD$PL$ CP t |$ v t$t$ ;sdt'"jhVj{`u}sdK`L$CS`h C _^[ÐUSVW3ۉ]3Uh%@d0d { u E(}@]VEPύUC%؋Ãr2t "EP]EU3ɸ<@EVE;t 3ZYYdh,@EtҮ_^[]LzmaDecode failed (%d)@ @ Í@SVQ;Cu'̋sӋC  $K<$u CZ^[ÐS3VC3҉3ɉSK C3K 3 FS |^[ÐSVWUQ$$3X$p t0;w+s$D3 ֋OuЋ $Y$p Z]_^[SS ;S v;S+f{s%S  ‰C c3[)S)S f){sK 3 щS c[SVWUQ$4$t_VNÅu $PZ+Z]_^[ÐSVWU33L$$;4$}D]T$ ؋ F;4$|YZ]_^[SVW^ Ë؁|_^[ÐSVWUQ $,$Ӄҋ$$‹ ;t"}"^q Ë؁||Z]_^[ÐSVW؋֋>uNjÃBCuNjκi_^[ÐSV}^[Ê r^[3ۀ-Xr @Ӏ-s3ۀ Xr @ s33BH 2CBp |x u@ 3^[ÐU|SVWMUEE3ɋPUMEHJUEHJUEU܋EMp4EYDP8U؋MA@E芝Eb_^[]Í@UjSVW3Uh@d0d F@u jl@PEE苟Pjð3ZYYdh@EP_^[Y]UjjSVW3Uh@d0d ;؅U~@E虶t'EP ECE@ru 4@>EPEEȕ@Buh@EFKo3ZYYdh@E-k_^[YY]/SP- /SPAWNWND=/Lang=SV؅|@;@}8;8@t0@D0P@D0Z8@^[ÐSVWU=@t<=@O|1G3Ƌ@@?u tFOuҠ@,rt  3f=@O|8G3Ƌ@;C(u{,t D;C,u \FOuˋ=@O|FG3Ƌ@C(%f;u{,t ;C,u FOu3]_^[ÐUE 3ҋȃtIt%}'u H@-}'u$E<@URURPEP@P薭Ћ]S S֭S蘭jjjjS貭u[ÐUĨSVW3ۉ]3Uh@d0d h@Sh@VE轛E3ɺDvEDEPEPjjjjjjEPj諫ubXEPFhjjEPjHt*WEP贫EPK3ZYYdh@E h_^[]"" =@t @E@ ܕù@E@ŕGThe setup files are corrupted. Please obtain a new copy of the program.1 ËSVWUļt$(D$PjVS被}~u`FuZ3ۋFtt t uTj@F PPYt3 l$;n rtTD$PF PP'F jVSt F;xD]_^[Sj hg+j٩؅uSj辪,tSjl؅uuSc؅ud[USVW3EEnuu3Uh @d0d 3UhԠ@d2d"@U3U@jjj @r@@3Uh@d2d" @@x uH@(@;B(u.U@Q}u U@QE@;Bsb@P @x@@@<@@@|t!3Uh`@d0d h4|@ @w@HD@3UhO@d0d j@.D@<@@@p@@K|'C3j Ƌ@йAD@FKu3ZYYdhV@D@֌騑3ZYYdgv@q@B詒@uJ=4@uAj$@vPM@E]Pj蕨t@@EU@Uܡ@rE܍M(@EPUܡ@yUܸ@Y@@诔@P@3Uh@d2d"3@@jjj @r@@3Uhݞ@d0d @@@@@@3ɋ@Rlj3Uh*@d0d h4|@ @w@*D@3Uh@d0d ӡ@HD@3ZYYdh @D@ ޏ3ZYYd靎v@;@xߐj@@3ɋ@RË@R@;Bt9@P@O@)3ҡ@9ӡ@H@S3ZYYdh@@@چ@H3ZYYd&ٍr@@@ Pԥa@j@Pjjjjjjjh0@hD@jD@h0@jD@P@EPD@EE@@ EE@@$EEUĹT@CE@MEp@@EPEUX+U@@@=<@t <@3ZYYdh@@=@tj2h @3=@t@ғPt=D@t D@Pؤ=@t&@ @@@(3@km=H@t+u"h0l@]Pd@RPj芤3ZYYd/jA@@C3ZYYdh@E薐E莐_^[].tmpInnoSetupLdrWindowSTATIC/SL5="$%x,%d,%d," @@\!@$@2Runtime error at 00000000Error dejI@G@@G@G@H@DH@H@H@HI@I@J@J@XJ@J@J@J@J@J@J@ K@@Inno Setup Setup Data (5.2.3)Inno Setup Messages (5.1.11)@0123456789ABCDEFGHIJKLMNOPQRSTUV@@T:(T0H*`(D*Lbz"0FZj|,Fbx8DTft 0BZj*@Vp4HZj8kernel32.dllDeleteCriticalSectionLeaveCriticalSectionEnterCriticalSectionInitializeCriticalSectionVirtualFreeVirtualAllocLocalFreeLocalAllocWideCharToMultiByteTlsSetValueTlsGetValueMultiByteToWideCharGetModuleHandleAGetLastErrorGetCommandLineAWriteFileSetFilePointerSetEndOfFileRtlUnwindReadFileRaiseExceptionGetStdHandleGetFileSizeGetSystemTimeGetFileTypeExitProcessCreateFileACloseHandleuser32.dllMessageBoxAoleaut32.dllVariantChangeTypeExVariantCopyIndVariantClearSysStringLenSysAllocStringLenadvapi32.dllRegQueryValueExARegOpenKeyExARegCloseKeyOpenProcessTokenLookupPrivilegeValueAkernel32.dllWriteFileVirtualQueryVirtualProtectVirtualFreeVirtualAllocSleepSizeofResourceSetLastErrorSetFilePointerSetErrorModeSetEndOfFileRemoveDirectoryAReadFileLockResourceLoadResourceLoadLibraryAIsDBCSLeadByteGetWindowsDirectoryAGetVersionExAGetUserDefaultLangIDGetSystemInfoGetSystemDefaultLCIDGetProcAddressGetModuleHandleAGetModuleFileNameAGetLocaleInfoAGetLastErrorGetFullPathNameAGetFileSizeGetFileAttributesAGetExitCodeProcessGetEnvironmentVariableAGetCurrentProcessGetCommandLineAGetACPInterlockedExchangeFormatMessageAFindResourceADeleteFileACreateProcessACreateFileACreateDirectoryACloseHandleuser32.dllTranslateMessageSetWindowLongAPeekMessageAMsgWaitForMultipleObjectsMessageBoxALoadStringAExitWindowsExDispatchMessageADestroyWindowCreateWindowExACallWindowProcACharPrevAcomctl32.dllInitCommonControlsadvapi32.dllAdjustTokenPrivileges@@@@@x 0H`xg+ p8Ph      0 @ P `h(%.B12%_$\#B1<,t, \D]E]E]E]E]EZC\D]E]E\DV@[D\D]EZC]E]E]E]E]E]E]E]EU?]E]E+!J8]E]E]E]E]E]E]E]E]E]EZC}$;,H7-"]E]E]E]E]E]E]E]E]E]E]E]E\E=.( YB]E]E]E]E]E]E]E]E]E]E]E]E\D;-BR=]E]E]E]E]E]E]E]E]E]E]E]E]E]E(YC8*]E]E]E]E]E]E]E]E]E]E]E]E]Ex']E/$]E]E]E]E]E]E]E]E]E]E]E]E]E{(]E/"[F]E]E]E]E]E]E]E]E]E]E]E]EI&w%\E]E]E]E]E]E\D\D\D\D]E]E\DM:\D\D[C\D\D\D]E]E3&F4k(:+~0#8)d&}/#7(j(f'>.0$e&]E]E;+:+E3K77(?/I6;,C2M9QZBYBU?U?Y"9** M9R=A0XAP;o*;,\D]E]E]E]E]E]E]E]E]E]E]E\DU?YB]G]E]E]E]E\D[E[DYB]EXA\DYB]E]EXAYB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EG5\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK9.{Q=]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EH7R<]E]E]E]E0&,"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EUSA]E]E]E]ERG5]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ET>lXPq6*1(-YC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EI6a) ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0%N9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[D-".  G3]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\FI9%J6]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXC#VBV@!]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ8.\E]E\ Q>]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED30]E]E.$/%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E<-B]E]EI8W]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0#_]E]E\E<[G]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E}*#w*"]E]EXB2YG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EdTM>F5\L\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EM:-_N:]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6)G6]E\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D\D]E\D[C[C]E[C]E]E]E]E\DYB]E[D]EZB[D]EZCYB[D\D[C[CZC\D]E]E]E]E=-<-]EL80$`$S=a$h'Z"FR=Z"2%E3X!3&y."9?/W!88*F4O5'r+ I]E]E]E]E;,Eu, E3t, Y!L9]#`$Q<>.4'20$9*QF44&<5'F4Q7)D3QQ$ R=\D\D1$Mo*CN:+ \D\Dy."H:++ G4D2% U?DD3?c%X!2S> [D]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]ER= E3R=ZC3J7XA$ D2' [C]Ei'4'O;( }/#v-!# T>@>. V@H60 S=[C\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]ER=H0 NM4'G4! K7 A0N:]#x-!N:' ?2%;# T>@B1 D32%0 S=[C]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\DR=! Q2%N:@/X!{."0 W@j(\D]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]ET> A, P[C]E]D\D]E]D\D]Eq+ 8)Q<L]EMV@y."M9]E\ES=2V@["\D\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]EU?RM;\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]D\DQ>%\D]E]D\D]E]D\DA5/F7]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]E]E]E\E]E]E{"(#\E\E]E]E\E]E]Es!T ZE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\D]E]E\D\D]EQ=5= 3'H9P>VA\E]EYGDc [D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]DT>*"z"K$+G t"y}*q*"\E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]E]E]E\E]E]E\E]E[ED05*6 9 E7]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\D]E]E\D\D]E]E\D]E]E\DWDJ? YA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]D\D]E]D\D]E\Ew# ?-\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]E]E]E\E]E]E\E]E]E\E]EYDz"!  <+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\D]E]E\D\D]E]E\D]E]E\D]E]E\DL<1*`'=+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]D\D]E]D\D]E]D\D]E]D\D]E,'B1\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\D[Ds*"P?]DP:!Q>\E]E]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E\Ei*XE]E[DE3(]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\E[EX 2\E\D]E}!_\E]E\D]E]E\D]E]E\D]E]E\D]E]E\D]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\D\EB :]E]D\EA26K9]E]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\EXB, P]E]E]ES?4.&]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\EQ<"f ]E\D]E[EYi]E\D]E]E\D]E]E\D]E]E\D]E]E\D]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\DH4%]E]D\E]E,#9[G]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\ED5 6-]E]E]E]E5%'WH]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\E=3@3]E\D]E]E|&+XH\D]E]E\D]E]E\D]E]E\D]E]E\D]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\D,$@5[G[DWD4,T\E]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E#[d= $@0]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\Ee! : G 49qB1\E]E\D]E]E\D]E]E\D]E]E\D]E]E\D]E]E]E\E]D\E\D]D]E]E]D]E]E\E]E\E\E]E\E\E]E\E\E]E\E+!WR>]E[D\D]E\D\D]E\D\D]E\D\D]E\D\D]E\D\D]E\D\D]E]E\E]E]E]E]D]E]E]D]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EYC\D]E]E\E]E]E\E]E]EX@]E]E\E]E]E\E]E]E\E]E]E\E]D]D]E]EYB]D]D\D\DYB\DYB]D[C[D]D\D\D]D\D\D]DYBYB]E\DZC]EYBZB[D[C]EXA\DYB]EYB]E\DV@\DZCW@]E]E\D]E]E]E\ET?( T>]D]EE3HXA& V@i'8)=-) % ;,\Ez."EG6(L8:L8$ c%=4'8) N' P;1\Dk(/ ~0#5W!N]E\D\D]E]E\ER= M9YB\DA0?W@ T>`$4'7(JYBC1 S>9*>.?.J70 J76@/?=-Y!7)N:N:( [DK@/P;?.r+ + ]E]E\E]D]D]ER=1 0 2%A03T> M9Z"5'7(M\DXA J6<-0$HJ70 V@7)@0* >.X!;+R= N:( \DJ@/C20 7(A0]E\D]E]E]E\DR=! R=K7 ?.?HAU 1 J77(M]ER= P;7)JAE3Z"7(TW!<R;,;+D2YB]D]E]D]D]E[C=-;+[C]E]E]E]E]E]E]EYB@/]EL9W@]E]E]E]E]E]E]E]E]E\E]E]E]E]D]E\D]D]E\D]E\E\D]E\E\D]E\E\D]E\E\D\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\D]E]E\D]E]E\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E(@ B]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZBZB]E]E]E]E]E[DS=[C]E]EXA[D]E]E]EZCR=\DYB[C]EV@\D]EW@]E]EW@]E]EYBV@]EWA]E]EW@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EU S]E]E]E]EC2 @/]E92%]E]E\D$ ^$C{."Q<3%N:U?E3 \D<-Z"W@E3 \D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EDA]E]E]E\Dy-"]E3%ZB+ v-!]E]EU?D2]E5m)6(>I6Q<@/ZBq+ ]Eo*S>@/[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED3I6L8ZCS=G5]EL9N:+ q+ ]E]ET>F4]E5m)S! F4Q<@/Q<F4]EE3S>@/[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED  F4 7)]E<-XA+ E]E\DT>F4]E5l)9*2%Q<@/XA6(]E3&S>@/[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EDA]EYB" O6( C 3&]E2  >\#+ M95ET>?FQB1[D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EDA]EXA! P]ER=C2Q<]E]EN:V@F4U?K8:+[D5 , ]E0$ Q<[CG4]E]EK8G4M9S>[CG4]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQI6]E]E]E]E]E]E]E]E]E]EXAL8]E@s+ ]EK7T?G5\D]E]E]EP<U?G5\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYBN:N:P;[C]E]E]E]E]E]E]E]E]E]E]E]EXA]E]EXAO:[C]E]ER]E\DP;]E]E]E]E]EJ7]E\DP;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E^G^J^G\D]E]E]E]E]E]E]EYA]H\F]E]F]E]E]E]E]E]E]E]E\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[G#>-YF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E?3.@M9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4("K0%%@1]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZCYB]E]E]E]E]E]E]E]E]E]E[ (O>]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\Gu 5$]E]E]E]E]E]E]E]E]ESH3PZE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E1)BUH]E]E]E]E]E]E]E]E]E4---#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[FW>5]E]E]E]E]E]E]E]E]Ea $6&]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E=*?9W v ,%1%I:ZF]E]ETLQT@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[D=0.%('N! .G YKW(!WE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZEA,+!g'$$!ZG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQD. $]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK>*'M8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\Ge1#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWCh 0"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E>2r9"3"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYJ@/.%#2#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYJ2!;,]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVF !I;]E]EK5*"C7]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EO>#*TD]E]EU@Fi]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E>1$6ZG]E]E]Ef;UE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E3&?\E]E]E]E0%/6+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E.#H]E]E]E]ETC7_ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E' ^]E]E]E]E]EO 1QB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ep"u&]E]E]E]E]E*#!.%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZ ,%]E]E]E]E]EA3#y$ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG/$]E]E]E]E]EYG1J ZG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[F>=2]E]E]E]E]E]EF/XK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXH.!RC]E]E]E]E]E]EH (TH]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EPD#"VD]E]E]E]E]EL; 8WJ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E=3!^M]E]E]EWCRBL `\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0'#T75D:8),%9 :+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E.'* +}$\F]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E}+$X^F?L @.]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E%lYE]E]EZD]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[EWEO<]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EU=]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZBZB]E]E]E]E\DW@]E]EW@]E]EW@]E]E]E]E]E]E]E]E]E]E\DS=ZB]E]E[CYB]E]ET>[C]EXA]E]EWAYB\DWA]EXA[D]E]EU?W@]E\DS=YB]E]E]E]E]E]E]E]E]E]EU S]E]E]E]E>.]EK7U?T?L8Q< r+ \D]EF4 / 4']Ep*O\DC6^#]E4&V $ ]E;1%]E;,<, 3{."]E]E]E]E]E]E]E]E]EDA]E]E]E]E8*]EE3Q]EL9A0K8]E]EM9W@]EXBL8]E- t,![CR3S>]ES=C1N:]E]E]E]E]E]E]E]E]E]EQI6]E]E]E]E]E]E]E]E]EN:MYB]E]E]E]E]E]E]E5'GM9]E]E]E]E]E]E]E]E]E]E]E4{."]Er+ N]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYBN:N:P;[C]E]E]E]E]E]E]E]E]E]E]ER=N:O:V@]E]E]E]E]E]E]E]E]E]EI6F4[D]E]E]E]E]E]E]E]E]E]E]EP;W@]E[CZB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E( ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQ]E]E]E]EL8XA]E]E]E]E]EM9I6XA]E]EQ]E]E]E]EL8XA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ7J7]E]E]E]E]E]E]E]E]ES>QGP;]E]E]E5(0]E]E]E]E]E]E]E3& F4<- \D]EU?J]E]EI6 V@]E]E7), ]E]E]EF4" v-!O: WA]E]E7), ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(3&]E]E]E]E]E]E]E]ET> , 2N:]E]EZ"[D]E]E]E]E]EZC& A0n*T>]E5'S=]E7)G4]E]E^$ZC]EM9   % K7]E]E^$ZC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]EU ?/]E]EG4=]E]EW!ZC]E]E]E]E]EO:g']E]E]Ek(S=]EJ;,]E6(F4]E]E[#YB]EJ7)]E]E6(J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]EYBH]E]E]E]Ed&Q<]EW!ZC]E]E]E]E]EL8~0#]E]E]Ek(S=\D]#]E6(F4]E]E[#YBYB?]E]E]E]E:J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]EK71$]E]E]E]E;,A0]EW!YB]E]E]E]E]EK8~0#]E]E]Ek(S=K7  ]E6(F4]E]E[#YBL9{/#]E]E]E]Es, J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'K6(6(8)?/S=]E]EH63&]E]E]E]E>.>.]EW!T>]E]E]E]E]EK8~0#]E]E]Ek(S=3&y."R=6(F4]E]E[#YBI62%]E]E]E]E{/#J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'MU?S>d&]E]E]E]E0$J7]EW!F4]E]E]E]E]EK8~0#]E]E]Ek(S=J) P;:+6(F4]E]E[#YBQ<_$]E]E]E]EU J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4' 97$ 5]E+ T?]E]EYB!  \D]EW!^$]E]E[D]E]EK8~0#]E]E]Ek(R=k(]E [#6(F4]E]E[#YB]E  S>]E]EO;J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EM9 E3B1 2%4'* ;,]E]EX"222%J7Z"7x."Q<]Ek(A0A0]E^$ 6(F4]E]E[#YB]E2% 1%{/#J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Et,!4']E:+  5']E]E]Ep+ & Ss, U m)]Ek(m)XA]E<-n*F4]E]Ep+ \D]E\DZ" x."J7]E]Ep+ \D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Es, 4&]E]EV@9*n*n*7)T?]E]E]E]EU?q+ F4ZC5'n*?/]EU?2%Q>.WA]Ek(/ 8]E]EU?0F4]E]EU?r+ C2]E]E]E]EG5y."o*9*YB@/J7]E]EU?r+ C2]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EI6F4]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK8~0#]E]E]Ek(y."]E]E]E+ F4]E]E]ET>[C]E]E]E]E]E]E]E]E]E@/J7]E]E]ET>[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E5'" 9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EM91%]E]E]El)G5]E]E]En*F4]E]E7), ]E]E]E]E]E]E]E]E]E@0J7]E]E7), ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG5NV@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYBE3]E]E]E9* \D]E]E]EI6S>]E]Eu,! \D]E]E]E]E]E]E]E]EI6Q<]E]Eu,! \D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EN:A0@/@/@/A0F4U?]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EV@Q<]E]E]E]E]EK8@0B1U?]E]E]E]E]EM9A0B1T>]E]E]EZC:+L8]E]E]E]E]E]E]E]E]E]E6(:+]E]E]EZC:+L8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EcP^OaQcN[D[D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EO6]E`QYK]E]E]E]E^L]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[B[D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EA9F@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVOdJ\ 6'SEWL]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESF0+@'"6E`--MO]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E: '4B\]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ep/,?IQPhTB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[LF"#G D7^HWNMEG:P?]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E;.540)]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQ?O;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ej">UJZC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E>5gpV@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVQ]YRG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[PZL|]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESGID</"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ETJsEGMC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQHx' 0%IOI]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ETLP6HXSUE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ERLG,3[]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EB;67EB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E/-17h QB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVJW T NG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E# 1)TB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E.!V 4c  82KAUJYLXL]E]E]E]E]E]E]E]E]E]EFM )H3]F]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E Y3(++#!#+4AQ^l #ICTL]E]E]E]E]E]EP\~ $+SAYF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUBB3_H^ O)&+5?Ia*&81|3;p -VF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQHQK]EJEPR7;a 5"3OF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ERF<-Y7/")~*%OK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EX=]E[GM?OGMIA   8SM]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EKIC    Ah]G]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[GA>> ..]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESK2+= NS>]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK@>   3(\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYM[ '  'eWB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EKBT %     +YXD]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG?O-  )U]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUOV<+   "U]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED;P9. "Y ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESJMF,+p H;0%'b]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ETNWP:1m T@ -b]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EROU0g [E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESO\2s WG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYOC 3$]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWCZL5  55+TD]E]E]E]E]E]EREPC\Q]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVDTG25F9XE]E]E]E]E]ErZ]RI]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EI>18OBYD]E]E]E]E]E@3\4;:2]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E;21=SGWC]E]E]E]E]E]Ec%%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0)0 GVJ]E]E]E]E]E]E]Ex % hSL]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUEv2VXJ]E]E]E]E]E]E]EE;<'?H@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWEm 0_\G]E]E]E]E]E]E]EQGJ.0u&WF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ea+ e]E]E]E]E]E]E]E]E]El 7*FYL]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ET" m ]E]E]E]E]E]E]E]E]E=4F#2<3]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZIF| ]E]E]E]E]E]E]E]E]EZPS!(q ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESD:&]E]E]E]E]E]E]E]E]E]EgRRJ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK=1  ;.]E]E]E]E]E]E]E]E]E]E&"E95]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG8+$I=]E]E]E]E]E]E]E]E]E]EOE+0l NC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EC6$)PB]E]E]E]E]E]E]E]E]E]ERED'H]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'  0VH]E]E]E]E]E]E]E]E]E]ETFg%7SK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E">\M]E]E]E]E]E]E]E]E]E]E]E905)=8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EyK]E]E]E]E]E]E]E]E]E]E]E]ERFE ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]El  #[ VE]E]E]E]E]E]E]E]E]E]E]E[MTeTN]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ed +tSA]E]E]E]E]E]E]E]E]E]E]E]EeOVR]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXJ^030UC]E]E]E]E]E]E]E]E]E]E]E]E|CQQ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWKU3EA]E]E]E]E]E]E]E]E]E]E]E]E]E@KJ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ERK:0KB]E]E]E]E]E]E]E]E]E]E]E]E]Ej CNM]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\FMG40QD]E]E]E]E]E]E]E]E]E]E]E]EZMGORP]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWI@:77ZIPA]E]E]E]E]E]E]E]E]E]E]Em" dPP]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUG/)51dS]E]E]E]E]E]E]E]E]E]E]E?@, #ZG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUFx/ -`QYN]E]E]E]E]E]E]EF>]E397 +<5]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVGi 0 XXR_YSLWKYDS;\GWIKGs9N SE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXJd6  ,E,0;<&/%VS'B0"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[N[1 !3<A2-){\K]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXMP   %7JzZK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESH4 ,'!'8Mk =/]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYJ%B#A992rdbhqz0'RE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK;+ ,#OF]E]E]E]E]ERB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EE4O.1E>-]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVHWJMC2&S@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ5Q7]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQP;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZCK8G5Q<]E]E]E]E]E]EU?O;]E]E]E]E]EM9I6U?]E]E]EO;WA]E]E]E]EYBK8O;]E]E\DJ7[C]E]E]EL8XA]E]E]E]E]ET?G5J7YB]E]E]EYBK8H5O;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ7J7]E]E]E]E]E]E]E]E]Ep+ @]E]E]EC2V@]E]EU? F4]E]ES=& =9*\D]E]E]E]E]EV@Z"$ =-]E]E]EXAF4]E]EL9% @L8=- ]E]E]E2% " F4y."^$]E]E7)* ]E]E]E]E3& F4V@W!}/#\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(3&]E]E]E]E]E]E]E]E]E9 ]E]E]E~0#G5]E]ED31%]E]E9*@ZC]E]E]EWA% Rl). 9*]E]EK82%]E\D! V!o*+   ]E]EB1  ! 3]E]E^$ZC]E]EZC& @06W!x."I}/#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]E]E5]E]E]Ez."F4]E]EC2~0#]E]E6(V!@/@/>.x."\#]E]E]Em)B1]E]E]E1$/ ]E]EJ71%]EN:^$]E]E\DW!V!]E]Eb%0$]EYBS1]E]E[#YB]E]EO:g']E]ER=A0]E]E]EE ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]E]E5]E]E]Ez."F4]E]EC2~0#]E]E6(~0#]E]E]E]EL9 N:]E]E8]E]E]E]E]ED2I6]E]EJ71%]ET>R]E]E]EM9p+ ]E]EKV@]E]EXA1]E]E[#YB]E]EL8~0#]E]E\Do*5']E]E]EL9 ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]E]E5]E]E]Ez."F4]E]EC2~0#]E]E6(~0#]E]E]E]E]Eh'|/#]EV@. ~0#~0#~0#~0#0$6(Q<]E]EJ71%]E]Eg'6z."C2R=o*]E]EH]E]E]E]E 1]E]E[#YB]E]EK8~0#]E]E]E]E]EG5n*+ q+ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'K6(6(8)?/S=]E]E]E]E5]E]E]Ez."E3]E]EC2~0#]E]E6(~0#]E]E]E]E]EB1L]ET> ]E]EJ71%]E]E]E=-N m)]E]EH]E]E]E]E! 1]E]E[#YB]E]EK8~0#]E]E]EP<2 5(\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'MU?]E]E5V@]E]Et,!>.]E]EA00$]E]E6(~0#]E]E]E]E]EM96]E[DJZCZCZCZCW!]E]EJ71%]E]EXAE3\D]ET>>.^$m)]E]EH]E]E]E]E" 1]E]E[#YB]E]EK8~0#]E]E]E* 91$I6]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4' 97$ 5]E]E5;,]E]ET U ]E]E5'4&]E]E6(~0#]E]E]E]E]EP<1]E]EF W@]E]EZC :]E]EJ71%]E]EY"1$]E]E]EM9|/#]E]EH]E]E]E]E" 1]E]E[#YB]E]EK8~0#]E]EZCn*]E]E]Ek(% K8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EM9 E3]E5 h'h'Gq+ D2]E]E6(~0#]E]E]E]E]EJ7A]E]EI63@/A0=B1]E5(V 9s, M9s, r+ E3B1?D2]E]EH]E]E]E]E" 1]E]E[#YB]EJ7Z"7x."Q<]E( 8J7N:b%=-]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Et,!4']EGCS|/#r+ M]E]E]E6(~0#]E]E]E]E]E7)j(]E]E]E>.7)]ES=i(YBEP]E]E]E\# ]E]E]E]E8E]E]E[#YB]EU m)]EJ7Z"\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Es, 4&]EM9o*O:]ED2t,!t,!F4]E]EJ7y."s, @0]E]E]E]E6(~0#]E]E]E]EZC( C2]E]E]E]EWA:+m)f'4'S=]E]E]EH5~0#T ?/XA]E]EH60$d&e&|/#F4]E]E]E]ER=o*G4]E]E]E]EL9o*N:]E]E[#YB]EU?2%Q>.WA]E]EXA:+o*j(3&L9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EI6F4]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(~0#]E]EXAF4>/ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK8v-!]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[#YB]E]EK8~0#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E5'" 9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(N:]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EV@! 9*3&Q<]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\#YB]E]EM91%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG5NV@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EH6LR=]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[#r+ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Et,!]E]E]EYBE3]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EN:A0@/@/@/A0F4U?]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EN:A0@/@/@/B1H6XA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E@/v-!n*5(XA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EW@{/#E3]E]E]E]EV@Q<]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E!'%s' is not a valid integer value('%s' is not a valid floating point value'%s' is not a valid date'%s' is not a valid time!'%s' is not a valid date and timeInvalid argument to time encodeInvalid argument to date encode Out of memory I/O error %dFile not foundInvalid filenameToo many open filesFile access deniedRead beyond end of file Disk fullInvalid numeric inputPADivision by zeroRange check errorInteger overflow Invalid floating point operationFloating point division by zeroFloating point overflowFloating point underflowInvalid pointer operationInvalid class typecast0Access violation at address %p. %s of address %pStack overflow Control-C hitPrivileged instructionOperation aborted%Exception %s in module %s at %p. %s%sApplication Error1Format '%s' invalid or incompatible with argumentNo argument for format '%s'Invalid variant type conversionInvalid variant operation"Variant method calls not supportedReadWrite)Format result longer than 4096 charactersFormat string too longError creating variant arrayVariant is not an array!Variant array index out of boundsExternal exception %xPAJanFebMarAprMayJunJulAugSepOctNovDecJanuaryFebruaryMarchAprilMayJuneJulyAugust SeptemberOctoberNovemberDecemberSunMonTueWedThuFriSatSundayMondayTuesday WednesdayThursdayFridaySaturdayPArDlPtS{ *f sJէDy , h 00 %@@ (B (4VS_VERSION_INFO?StringFileInfo000004b0r-CommentsThis installation was built with Inno Setup.=CompanyNameRoger Dannenberg - Carnegie Mellon University =FileDescriptionPmDefaults Setup JFileVersion eLegalCopyright =ProductNamePmDefaults NProductVersion DVarFileInfo$Translation Inno Setup true PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXzlb]&p/D|)1/AqkLx#t8Kps_gr=N`9? Ogp07yay3N 53h3p1̔-0}IƘx#i2QxސJ~ qQxڲ ܲ%a"xJW~h\,b\\^BMDt[%Ƒ0V|{)~5]H%gcnMƒم=B^@*׊⭛_E¹ jOi^gj6XG#eHhxח||`6 )TCq {F0.I(cRmS-Fl虁<,i%$aO 8lۯaVh|:UpQ;NU a>;8ǒ3݄~v ۨ(q2$TDKyK.&SmBX5u૪?tq;)3vQYA<2u\>݁OP\*IdY~7kU,7_BOrr+<)P2 Ngӱؐ%n0v74 k^3w %h#ڭA^zޢeEm9fC6ްA c Y{+@rsQ0Sv+d{ վ6) WNhꖷ&`3fMj&cc@ZugL+NBYUnG5E!᫡ӭ4M-j+ue4T5#`7_xLJc޼zmyIOte+xLb:bHJ01zT>E+䰏w)( V m㓚HI{.^qryhr !yHkp!vY"R/i􊚦zxDe7&.g|7EVԤhJ EL@#Z!#4B l#k\syUknŊA/K$͑e- w3ڔ 6̚g:93AtȥÞ`~iTg˸̉{s 'Ϗu(wT;d}?IuD'[%8OYS>y>|Xrd|^P=F24#DrXF 5K匹I}GUd%}aR"fO_\CSyE-%wCϟ Qw8¤+(S8 yUvm7C%Aymc}\N\NZ^}|04Wx惎zZu&E ҉K'jpڏ7$̙ś Zڱ-Wn!ãRO䤻!=F`]љXee(wcJR/i~0&{\H52I0܏_SYaAs.6=?$/ OqROg4qxY{`bEJO17+(ٟO|No ! Y>K66x,>=f$s2{asTga iW!]hGbġn&H;lHD IFV fuTu\ȏmu$z!#%H +9Ty4q`\#zb X][d;Z65L9K Þobɪ]Xh<nWu M*bj eVe9\JIy`V~]a9Jnw> *&R rvm>Jx-w ^垥 Z'd6ɡ٪}ҴBUv A (iuL6DNX(&B68М!1_q@T72'1Y۝aWɎ{ZDP3[cT9{MVMfsx)K#4S-CVzsR}[nn ~\Xl_Qv,EOzb:mW ~IBI~0uۄGa `m- 97d OlB7DRGx9*ZݙQpy{5fӈsw2*ם~kzM=cB~雋!HvWL1[r>Foe" ʇԌ5Ǝe=Ug5{>nﴼ 2;t5!Ό+(868u&)Z!D ɇ Ŝ kOT0 Ws %Z;R3qH&#Ub JNVsLդ 1V֩BBJv˘T" VE/\FfިUXɗE;!I]Kf.u=pTv . i?}F6BI1atPm S:&pݗAXRt?J̐:D^ bݜ9]s$h1yc ܣ,NM>39n9ohF-3=YnaSs`mpJ_\wWFktFug> + :d8܏̏JK &ɩl'msS8#m&%_`y1{i`ɄTTі=\$md]K2:Ȉ,?\j"C#wTMg$-GsBgt$ OcwtIƼjTq玅!FjUFSؑUa&E\!id_Vk僎>UrlnWp% QA`yPmͩk\FxyM#El\}ErïYuW,ae連_e.˙q+n%#(~JԎ>Ù&4\ZW,4̂e!Lvr~ ԇu?CR^O`XZwf\0=xݨ$|.)9m#O[L,4w4Ծ02C]UTY2 a$:pD|&t),1!Yr I|FYRmLol(=< Di*㣪%Dr,tZ) ǡ D \q1ϲ\4&Gۋ70+}wt`Ba,STjQ}{6=0`u/N9Q/͞Fu\9NNFCUf/F,h`0h’j씑vbvcԘ[gcgM*>ӄz83O_3^؟E |<:{;[6DUF ϹI6u!)"~mz-*؆-,(yYR7b(dTZ4,Gp)z @Ӧ]=:̨M>ۂTͷMu6u^QQT#TqhT,FB=A䢁zX305ݒHѤyad'R]+Ϣy]LcsdޥsX6~(?ʉ7Ġ4"#|S(7p|#%WϰjŪ2 =b ݚ ?(˕`06kLh89In1ֈ>1mOEAK-Bf!W)!$ajNɾN75,%%Z8KWO'5h!]! 7%n1GfJ9^m B8V~ՐȷICK9YP^Va;=VryUe=KOu^o5W#dIaqNbIЮ M?Yُo:ک1fTb`W񺳼 2|@ \ [273ѝi.UH13&ޑMKܺՂzZdug?1CzCZ!&w I`zYH}:';["-tD ؊Js~# tXک@4֠g{>I=(lomrr5DgOi@7,3ŵweo\Ix%pMgF&-l18qkGͤ*Z̊d@<j1 _ݭPǩޜJ5l_M+虜62y&=mG};UUfrMuA)NPj1oLf|^_i?q9OEBɣ;0u_qH>x;Ӈse#0Zkf?KqZ5ud?,uYwK!`j2`NQUMD!ފ#B3U*G*"B8gP4?@e~s.\+Ų}iTGa/x6sAh7 R]33? 6ǡ’q qRpLtȸC0FxZ]2e:qYmbݝ`F&[\NړPo'\Kߖ*N"1hU(Lh 9WqfR~2{ji!E ʃug>ԔІch{Jݥa6Xԩ*tE҅RS|D#]^9GNߣkQq=Rrک 誸(NN"!/$}nn1ߊo\3UDUJM{2/D?(x@TEP}UQ`RK oY C85= C ^ڥ4*@݌z?H=I=pcꃮ}Lnn#iぱPIa(lj}f'7oV`L^$|@E/ޫ1FA2t~TJ֋Oݩ SLF4{T3:M Iw?qԀr^tHCBۓd$uג1A@3pHёѾPB!Y%\d9!4t -n7ZZ\^1΀iASy}aReNE_m8:somVc,}mE7B&NernսlL wSNxxÖ}Qͯ*>\e{KYa;/K ,Fq;HW$]K0" r"01^DR]KO%_1NC/:oS37`Z!rVKVc/jXcgp&ĄfpٝZ6_+ h?9߰W =uuͷ"ب ѾFH 쟠֫2[Fs!r{#_YyeOG:U}W(w A2_c7ܰ.%د,.-TzzF7q ;pO*F*  BO6SE*]j64WFf3ܙHH]NJ+rûg4MxG&lLK͘Kf눃-0f;%GwʨD3$6# @QDhA+a<! R;Gūݧ^ v1~gk׵؇Fp/J}H j)S$/U鷖,Yb@ŕ*h^x$b30í-.s]l+{$~PO OzBft[Lh 'ЍQ*@Кp,^G3i-b!Vד@JHQz P -]BHf ۡE(BƯg6˔&chX_t۠6*qjrpp3i5r701',i. ډ  α҅\%q=&*ASp{)N69,ǦQy'L }>_k^qCq9}kh7z[w"mxԌ}\l)+_M6,r%Շ$@>K>g8µ[afdE}>y @)dB:=7PuD(\bSkDʭ{\0ϗK~%K0Q"J/+x9Baܑ͈2p"LlҊ>vV뀈2qkQ!۝ 0a).`A.7AK}Pwv[o^BY nԥ*?ʏ#C/ge2r.C2 xf2կWT.q\-sKx\~7˰h /m؞qvI}Y]bY*)׸{@y.yS%G(p$aʔVpJs:cDL!N%ӹ>a\ĉo"%÷c ;bJ::V,ʕj}&eTS 3TۋZY\%SCl?c0ه^SytNv'q[>s\\3 ⓩbJG y-h-VAB3Jh^&y sp%z^2, ͌9݅k΁MV_b M(Qj@ }bfؗ4A%OKZP 1ca"cUV$w^vBD8W{i/ڗk>ōl=:Rl(a@4vlfN7т'Z-m 0䙵COH-#Zf%VO>8;t~pԲd񓶫S|N7c ߪdEeh8Ʒ߈,n# d\;z:FȼKK aEXz7ґI̛pƀӫ~7s57-+{s}=ƢyP{KwƝ`НWúڕZƘOm{1&hdH!~49dCXd.k1&3vfp#hilnpÑ,gȝGBn>Q6&r TG[fr[k:Y!q]a`$X*fa% |39p5:ݲ߀۫j*2ikk4XʼQFFOa3}2#1NtYy=3*Ǜu XwCw&,SQK=Ƀlūu>{, XO +nF.TSXb϶k~T' i]4}GT̪} /Hp32Z({G:dKasAR(pm} BY1gUKʃ.POM"pa]eePkp{G4ɘ-MoN2@E yqao/| '!Xtj@Aј*9 qxt{sh~Yh~(TKR X NKC2ÏPЅ+S-wuaE~:)qò{45$p7K[CRMv.7]x6xuE>; ('TCM ( L`!9TKGEY-@'i% pP[+_[VfJiy&gol l/{WV%7L>iX, h 9jlUCG4]M_NEp;46* ?K 7VWq-^v=߬88?w:5_if^ ,,;[%c?Ppr(uoP:j@MvDmGCcF_qr")S.WhD7bP+vݐ÷Kݱnű+D 㖘^pdqi?WZitGvNrnYp"F5ua$fQF-̤֑r4]1ƱŌ3Пo`Q3K tZײ)O;.J!_;<_5^yd pD:#h`ػ a $,`LMgs&Mk~I4N3+"qzz_55QKTZb! r"˿VICZx嫀H@VqK6pA~o:FRog#yYQYvn ^qdn}ъdH0SgCjSmT#xnhčf>sanS%`XsN{.%-4{N8Ӊo.D,$Á5bR^;x浢y_r6\nRDw|oYXYBc:&Ov4xo+&^Nj%@E@_gJ<8KS83R>|;0C]=,?sCs}&um|[-e87 gɘR2cleE0Q<<$ڕ$1U1JAnzZ' +h^KGDu勤J%im:j)0RiLŗ&#k̀?މA%.ō@fԕQCzeFX|7wMtm1+ks8h[?ֽ :)t;q(*ҏXrmUZc%X "0%osw-N?c<QSwAj^uV2 I٩UIgqE~eXNb,b s{g,P.Tи,Nաt(q 3}ss2">v,;^́PY"}2|=mKNLM1Qa23 cR9p°جx&!s%|`6{q?l)O@Z3AFң!Ҳ$+&*9}8ildY ).Bdr OV=fAH"Ĝ~[Iw>1ݳޜ-NدoWGnnS6y؊ (,Y4+:љTPsݩ=DJWjQ^,.)n!kD,.d8L͞0Kꤵg )p56~sn#E@BAꧮ!9[@ܐ~َ -u[{GtL3&][ 0+m.۞D~YI}̤CxV.%cw*oAl nPqrF Jg&$GƧ0Ԏ)DҼNz/J{mͺI),"Y`xFt$xWiz+gzbP?}u.pD֡7*i \s+hݗ_36;wLǃZN]!\ &IJ:sFpѩ<=[<!cKk2-F£crŠTXar8; [9E0-% iST&>eK[chJ5-W'si2@!O8i^A/-ڄ/BVlCancCʆkFS !l(S)Ro-_#NNe BǰE`R O2x)f-s ŘJޠo,* ab<^z%FQڔPJOv%K>+M[_9j.G@ +WN0w},m*BTP&HfuEZro5p hvWq&ԾθE@MIhYfu^ t;/gۊ=ђpX;Ef8ekӳ@m<^kU*R}ܸO[2X9[zhNdR;"pH/3N B#k9:dqMޱTXX"bi@p +O7'#~t[B>>:]>O-9U~\G0m >L*0~h?c&!`3׫yM1HKIoUGZF0H^&΋C#d=CdfG`8X: ^`+=Yr@n`ߏdC°) |cTqH<SDGx_ u "Z3׻ V "QCn\kjz7D#7u]F2s0}E`/O9=ii_?:>xl`m Eh}N)D$}T <,.7 y= }FK W0#| ]ɘw/`V|aID1*;,Ϯ9@LwZqm~hۿ|rȿ`T(^d1gbcΟ jHHOeק|GQf>E "Rbk`lv%n)7m,QKH/RPOTn擪s` ,F4v0uǜFX+08Hm6KE*? Q%bv?xes_78lIdʘVn1Qj+F^0$p?1Lax嚰 f>zgԦP4]Tiig]IlE%[. ^4QߐZF$![UDU}RKo.,w'үhG= yR3Y{b-UL0V6^OFWi-ub;%_>ҥ@Ŋ  7cfd)L¯Èm=Es"h%Ӓ|$.c|<¡Ҷ42MmlkezMKuyGzÛȾ( {ki杛B #l1 `TfԞ_VXAv/.Q?"p=k}k=\˰y;,g ̽ߦ}z<@!b"(-qF},/; 1yI f'oZMxc6),y~gߕ.`WԆbgHHΑjӦ @S}&FE-yY R Yڎ{@c2>PץmTl^`n"ImbFܲEkƒ+v*uk`e^:]D,NozykE1K!z"5QTqehm9R+s) U'Ҭ]G=AGIGTeX] Q?mԓAyxZk?9q#!+)Y '_ 9M( ɣ'BWa'/ivF*D1X-i(WF^-D|ĝ.?g';4 ۄ_cg>DX k wd yvw؜9•Z72׀[vUy {6$'^+lw}, = W sN"/#> &R*av=a=>vtl1,/D+ºif1I,?–;u@P/s ϼ3`Kf9 Q,dO' {p*H#2ۮoӱL{6 D~Y8K)Vwȭ~ɾbp?b!!=^#K)+ADI$Jks}Ղ6)ӀS+r9eZ&[l;BGggADma jvX<|ضLzw#w쳒ָO6kWɢw|lgQjOVaPKeh<8D/y(j~Q1Yae`R{(j޼+H $jʹ$9.K 'PޛAb!I Uy)Uo2Vd(W7oENWtQ|m|w2oY"8۪DF!]o8M khI~<xSjIG,u,''!!""f}<^\lQRqziP DOx8"Z)RN[0C6S2UGܼKVF5EUy$`!sGKՆƁU9[UfدCϩ[=;n9,Px"5/@,ul&4ßz6lf#)_7gb@V3-RRb^KЊH)_jv& 'p"US0`I蓳?'p .rYaA Zh Qaw% 1# )8gFӝ_Mi=YF3bӰף<$J7`p+Zr`'ˋ5KR BI(e=A"ϞE$%\I%?k+qd!8~*(1QjoSfBHҗXʚU2Ueb/i@FgfйÜ,> ]l䐶 O@T_H1\_T|M%jl|[KNtSct? Zst,7BzzkѤjɥ =xX6odu7S$k*Y%r%yk67Ew\ {d2mgW >KW ;n! z;2(GH7w:Gyj^("*k,ߥFryLd ƢXd\PbƸQ(5C.D۲RPʿƔTX%8X\Ix"kf?mKf[9y요H\oZ#Q t[ [=Ц5w#G1l7aְNԵ0qs3ɵߪ/luQ뮫؝#nvUIrxNw, Dr"=:MqAmEJ(ʘ`QzKIu "ެ4u뇨xL]r2xnJ, $2g|ʣ٧]Mwȗ1?`'F&jㄳ77l]sau@ZqcA_o*-DPc*d{ uy·xJ+E?D>y+oFNiReAK Oμ^if0sv8II軻bo ntZ]@s\C2ϸ ~/ZьdM4 }.fڮw* r6ճ?">6PP!El.=eq cf Hp7*s jF4{Xae-Zej[VBL|fM9~#p aqא=ËƊ_e*"ͅ䯰ƺۘϳ 2q2" ;zOY_ՙv5< B~c\/b{֯kԮ4"ɷ?ɗ?=#?c=_ج=׹++jR*Mkk- bu nLq6k=y!Lc:U\\.=Nj?z,n;ܤ[eJy@lj iERғfv74v<(RS f #AR7Pݲ'BKU%$An^%\Xc-:0ϱH5F:K8Gp.72,^i(=<.ȒdӘW_Wl>%X22bullK;zM{8~ ˟G Ɯ1t+Z(=dP1ЉD@q'un=и _'Ԩ!fyla'#Dm5% 9`ű\XR`'1S"u!^GyE%6s-^ BB.&T2/f4@:նpPam cAJE]RI6m __w sK:POx{Q6nJt`jf=j+, .qH'VQJ^u#HF?a8;)\+t.qTer630fkBQ{X?kU~%[2ewU.{JsSfNޫيJU3湉Яo'!{,`e񶽉UGoi~7r- Pȣw)kP%~$!N@/*v}}ve)"k%0nJ 4IϩlMkEZzG+l3e?EʽPQUEwFFÛC(Q3Iw;L'=~ǖp<PsJ^]eZvl""MEM_ڜFoEQ=V쭟=XN)Y=E8ie[פG#i"jwM?*pd~ƴ㚀1lDym.wPG0^n; UJ]0鉕f-?%c r;؟W9+]kY)/,n>ǥ8onN7;X.'{zZ0ϯO>yI;Y# 4w M?״Y/<")Gv=Pw3eng/U9]t:8:hGK~$f vŔφ `-IRכ 7~5AT&78TRS*|< ݞG_X+Y8iLk`lܬRNLP^޶OdGaGӢdk@z%Eӝ-8oth/db2fj;/(SU>;(;h>;纱E20!l0|Fj 8v5TJɜzeQ¬pPRE쐵SdAswZz'R94=3 }Hj3!ڡjPNyRyUswՁ:䮕ti vS|` 0uTYR7*ix 2eD,iXN.yj'l5i"¯GY!w)Sh8Y"u~P/\ 40;)xGh-yd'hߜ*FpP}A{OBe.ݼhBʬC~;WA{L|/Wl?VѮ ^Xu.BNX@vIY4jT %@ag׸-'Ƌ~@e8-q5,@["oH\c4Ni؎OAZ(̀?ġ|tM핽Ȕ͖랭C r@jb(9*uln%ifhq%{%z0aF83#l$36P*^vb",G{oMH;kxٜD5pH ø8OaCc r11^\5k{Id5=xCku~fЪHEX3)|GBNV},y<nH Te<[Dd%Y=mdX诺V{r9Ƙ~wM%mע|ܮ-I;qo%)LX>7c٘D{P/THc'Eam!ܿ]Vr@K>[84QeO}FU-lguMv(2=*C6 \vZuNȾpSOI JE3S5`z t{=M#~'"g!N켯V'[xSҖ5)caxj!_QҺ%H^ߏnn^UrjdKpӵjFqMy8̶ܷ6UBSwڵ3I_|R9F&W=5NE AuP%Læzٸ'd<ܝ +a|I|]`'9VlD!xguӎB}>')_Ԣ^6Xp^_nBəĘr0[ JEw@bʲa r`s bn[s?*h: MYN%xv*!'"CWз8ܺe\pT"}|]+xpyh]cdXˤ OX@MurNƚ7J륀xz3[B*kr7>5-5`\>P}J-DOC U ʈя  eqJȑ} WB֙.C5v1>Ć]C/YSb;^ސmCok,,׷/,Қ䠀]Y,&|%r"3Ev^p$eCޜW$pcO kFET&?R|ys95TYZV1SWh~M{/x ]u3wmS|<"^MJj},z8cưLf [ήG@{??k7Alꩼ&e "ݹj\kT!iXEMKs3smTEM%Ώbx^Is}"2W`y)F/Fyqn)hA )aDVіzO-4+AxYQ,סܴ tۉ{wgk'[O{%n=`/ZY)~vsUQ(~\jf(|/C&o2ncHd;K}n׿JЕ`@k-(|..٘ga\gzjvO1t5cɄ!ϸѹoMsѽ9:VOi.*yMVڃӵ1悃(alNeZfog0 -T߬΁5J#Ca4&~*vA7Mdd3EP^ce6oz| ]{ CR{A󯏨ӯHC;(ka]N=*ZU1JMO 0-!m~9!3K l"CwsTR;P)ZZn?L!+JBqΠ-YV-'N |q5ND[쮐ٟ/9 utŎ؊ZӰ*1! @y'HGݴ:S)oV^(U/#(zbN6mf(Taǽ9! oWL_MC q \>O0_S.Zdzd];P9Wof:'E}3<֛1joJCD;uš 4 `椈7cqgQBĺL DŤ&F,nU|ٹ*_0cf<׎ݫZ!| *͉[ 6fp)ɪ0íX "d/_un?Ҷrj/))˱ny>A>:x{gTu/y*Lj `5`|ןZE}ʹW)u\_ecQlQIBOTX(iuղ!y1(0lxqSHw&2PаʯN7OyC 4A=A5\. it5d:v}Gbgê1X!7VP31X|6y)>93ƾVxan U,P~:-v|kh7``5 <}lM"cŲQ:{ PhUBt(d] >aO !WMVz3L.Z5HKSMnhoC/g hm4@X<=.dJ-YV TQhۮNc7 %lĨR?a7CDROiC=KStmG<~ Pp^?eת"Ɖ O0fCU!A6X!COe~ *iFgD5@eS kAlyIFpFBūO Cj߼rDc4PʂkBL>ƥ+[C1⢪26<@< bZ| k״^uA& 97"02)H[Lީj<%M6]gljfbl»E!YeV1 / k+4J1'ΘͰb~a\NI7 et* ń[!)6gIu͏ܖfSŅ/"32d sc"בW6r 4s5چ$sx|e&I-s.)G=(~Mvs\9cPyjם+yV.oMn2 g@'tfsdO=(U&ƴuL/4dYd~XD(Ȑ-Q]/Eſ,%z VLgw0o'kvj;*`ͳJh\`gZ P&iЕ8fZL"W^*Yz-[u<hcO}ʌ.``RHt}](H !{f_+@H\#}@ 1L o\yMFyJJi_^'LyӦ6h~XRDbUdK)ț8#:|as;tM kEEP`T?E Ck( w>V974 ao\^ϪFWQ˖t ꈉ0vD~g4ϓl,chH5QYVGp!sO%Sm`dN\̄|.#  ;3|>PXDCv[W#@dztsu_B- R/W;ͥnS$'ﬓ&sn>,۫?T5ya2 x߻]C/Rh3nLu#D6_]VܸrGUd3ͲȪʤL55| wߓH`P GߝTXKv}*MIQ$Iw K]A: :b_W NBoz!!kF+߼M#.p/ s&Ae?5OM֫W>^H?ٿVMb$>5!y/͌22AGfeXN4Ñ5zh{O(b憙%knek@~K\a| L TA冹  D߾/5Z<X!-SPc W2ed6J t)|"+u1Cb5~1LŠ][Ty >ZzyuQ݉qmGU{o&=KMʭN@aAtT~7BVQ-wDe{t{jv#2࿼立1H} OIeS1]gšR{l%)+qSE,܅?8C'N˟ޫT2h(U9:x;N- Vz8O~ `T)^p(#"ypО3y1G? ?.Gk-åSBE,[Ėg'Ÿ烞˜d0 b̙Բq!#25T0Gfp hQQ1Dq3*f%;3jyCvw,J$4e{%[QS/0ހMި!MA'UQhuT%e%jyϲHׄ 屯:Ga& |߆Xϰ֊ӧ9<)8#NI ou1Vm$T#~ʂF>ZqR}z7e.uE!Yz\k%xVHAw5"Z 89XU|5OA^i朧ꌗD$CW_JP(#Sb!Y2 Wm\ |J}P/IPw\3\;鹩qځnmKѴa|o?} 265GCйߨ䈑0{Kn$u宥N|ɚ ]zH AMux:ϡ]vF1FbI? Y̢MEځQ(6 nYr,T <ۿFwľ?h>J|AHu2~Q37)Nh*u RfAj.]kv_5ngz1RUHyq\2#;9jTArvX8qHj)ſS}f'/D><ثIF7_{%vaJ`6O]JJ6\bK,{*8EcJ>- K}rifj镳3Ԝ ɚź{4W4lqEt37XpsfʩLA:ѐ`7oLܜoX4*w:5y/0A\A:&ݰMXyIvu[`f 7/>giwh%1כJj0xP N>]=klkns‚dYu ;d#hIR<͒N+ϣ{) '`Ce^ :ץ;H`EXaKɄBEV)4zfk2 14~,vӀڽjѣ_wA5(y7j.>!|/'"hw.Buq| ޴Anbl nb:烘~G/iRHqv%"*D5:ma jRS4bB׊ۅF-ڶ&2- A ^O(l?z\DP{Lpl6ĆJKG7BP5 PeWΆΓ Mg(k?sJ(?Û-׉dN8/>7JH,Gc)8hSb˖~! ;l:ght}+ ,dz3w޿Tw5 Ip3WTw)h:1*ޒr,삜T?~xJɫ+Mٿ XV5mVf[ :bKQ Ǡ|YL+t _L ޯ+3'Mp4MQ S YSiN5~+' /YY^>& _¨Oiʕj1 jbsOωrÑW# "=w E+jw)āt d!M˩a9|y ۖR|[m槨f#=2Se7sfHS.;gwjnf!ɵ= rfV^PCTUٱOvyh2A)%VmkO#{|S=+#;gdgK1%tat+t2T:N816<2S)C>q]?վM'g=VAܜ Y\Erw J< {QLs~U꽏Vux:R_dHF"QN|.p.!tr/=qtB7hM;1B>^zI!N=Ol_If0Df=0>XJ/B[Xmm ˔K=Fr O-գH. DQHhٹٱ8șHǧ,ԅ1C8L9s.*d "v!8mhx-e)5#=L|pa9,]xg9 k*<=6?f?"mm)` cz~-dG9݁~1CaӚw]SFL 1o-R%!V]8Zu ۻX^=#]\csxnO}&fƨ.db >AA:&o$R MXG@fljOl#ya)o})򄻒EDYh^W.XR,]7I͉]dߊ\i*+$JAZt ,0$zlkZUarf! 'S#蜧DOv:q|L}gɟKJ FX5āN%Ϯ Ly7YǺgo=z]itIcE>`YCr\Lbʤj lXZ3AW Sh6a@m\j}yEU@ mOې6P#b؁~5(//mb7 LuI!MCQ ZGqf+Zk/c'~ҪV(ǁcB"(=I'dB58kvtV$B?#Wzs_}S)ԎW|&d\"{Rp%챑_-E*@kMW?*~Iѭ0Gƍq4xI,jXCjKzPylUk 3} &Eܣ)#&$8mSg-IWpboPVg 2I.^3&v?u*[< d̂ W Bڮ$^+Ofxxt`Yx,]´G\PdǙ9Նݕ-)05,ȝjxlRcMy{l';ep0d`Č7F~9wo#YXqE|zGb: _ApGCdnWSh [ýy0 0[iinZMEaUیj[ҙ%D kzPnPb@GA2\ͯ  bU[E#]#ǡ3˹v Z-BiM EW?:R-f5?vNi-0ER03 3 5Zu_i/ڥyIMMp'4~Q2GRk I|ow"Dm/kGT »8}{?~uiPI}Y3@aMvy+#^.I'yUZ}k HMn;GjL$jIgfmUhNĆM`W2WLIdYMS[ÄL'g_Y޷ .5g[gݣak BTwXUXWz^2.2,y<-ZV$ LmIp~XYSVnbei4T;0{H=49)3GC$9K.]JS.6J8XԻ:v.\!&0ǯZcV _aOeQnvȼ"86C*T@z["vwU4Uq%pȦ֪,P-%kb]Ks?  d% T#1ya I|J\* x;u@,yy}x;wR(W`*Zc]m:OD{XX=R҉U&Bk!\$x{ЄyL\؃Y#}mT?~ L#wez] GNg7ZmZ=b>Q6L{3/b}ҬSL(YbӟaXC=+#s*.:NRs/k|K8 cAk&he66Oڨ>m;ý+]a8?S"((=s>!D$vz O|/qiawFG!B~~ :CtӹLyTeUϠ1$=Zq=+l';.dw) '$X;^C >Tms>rE~)^ b^oIU0 AVjmqq{j]50( 7b 7PѠpΑZ;8"1]3i첃@{HҞ5O{7~>Ts(}/SZ y TǮ]d@Pf4L_GT?ѓVG;hU\ՋU6tY l)<.j:Ȝ$V`,Pr^K^{aC#aF_%~P7MJPQ B {|A-QVZ-l6[ƭ@#m#D-j<5" t3=7Ṽg^o[9ݍiY8/TI&K'i!]r1J@cGjfѧgط_KApx*Yҏ t9zNtHV u)wRg\\zMʭUAz}6Ic9+U >הvڷ:E>q~fu$T 5$1y⪏) . 8ćs,:G]z&rW g$ R˰19g!Be+IlŒT kA bPz:ad[suM-2i܊zɢmraFԜLK-f3#'AvnA506Y$.h,%fQ<:D#o ?%}wKs\>_!ndR,n*5.0Is )lE@K; (;47bt-+EB*?DW{U z,*\>GLe|P|CV }S0Vn wG t`"1!sM;z;N40]?:F#8spYe-(0_?Z!Ko?X2Mq/+rRF~%9uKQ|}dswk|h #,z@+piFSH$xȷkR`QԂo &uMSxyY/!yR๔Dzv2<|n+ԺS̍ʗX!#Jha[fTbԗ}7-jaEs+ֿY>gBD PjUhjE<=6%%?elroε Ȯw؊rE1h'*}!jNogG"?@U7cOھ> !*Zǭɥǜ?z嬏",;ƯY4ّM9Y,=?fRf۴wP:E[. D‰>y?~7Fy'HCEy苮 I2=[87וjԑIQ`wgk&'w .k-,jt>q\J5gbAcQgk71O;HMskERPT+c/Q1@ lGbOy[ P^_yu@`a寉2>x:ޡKR\M̊Hѻ|f6 vf,37fn\ 6SǼr_,+$"kzd߫g%%X[\bDm=7[ތ9gx$ @;q\(M9+{?XvnMIoUr:'򤴔ULX2ե[ptlK ɶ@fi4ʅ/Zj s(Ema7+aJJHL^!*hw]fobUI!wLԑ 3$3y@JB%zFT۶ae]2d܈.ZE|iL'=LJW0wd.TǹZXM5xefOfD< h3{B%=QؤkӒMU7<H,61BkXSN+c6g\ymRe(wE0WՇ B߶7FC|J`7_Z6b+U#! ւ=R4"Ұ'mgԶnңyKW0L(MI!߳frP暊X9H%_ ?߮Se ^e{˼o-П$K5{ϥzVDӈjVp4tFE|foLj'7\ #Z˱;PcҲjLj_gFjD,ƳO6|rK"bVށtvݠؠ5Һ)SG] Z}ϿMų^$"m r[aBX룓/K2ץ37m‘"SeeQUy{Ò&&Z$W2+sӼN" k,Ot{4|+G|2ПpJ1'2p} 0VElE-CΝeZ*<0tZ=YV H !#?dbw"QyIs mؚc4>}eKT5BB+{%'\W LMl_H5FYra&P2XP^2|?~/dB_˕f"PS጑٘wrW@̺.BTuGi|sOY#5|O\ ԖuXXJU=Kg?=u6m[)nMF/4ɔ鴤yn#l*:[.0XwKZ tce5t [70Ϝ9L7/tEQ7Ȝ0ik:)J fW 䜄dK֝RLW?";$W7İf> |,[/PsZQxIOC5:نꯊ~0&".',YzRgmjI>=W~+5~'N(FIƒُi:J*9RT[E[u(=&a2EC!@ĉ9y ې:>R;ݓN!tLf)}T!25>1P5flXĂ*T~Ƭ_*9Bl]z=Ko#Gz)OutzG5pu?حarݕ=Dt}un!UZMj=9.0Əo:+Q:Cv!tv&\|M|9P,*f7 wPr6C<׋Sr9~ iZx,6e? ^OV֚Y܊߈gB,'GJ-O;%BW7QWw)WUȩ*ِ嗳\QIa]O%J*OF=U.4'm/d1F%Հ2d6{a>ђhnd3룳64JyU.)u w_p|{:]Yֆ}bOߍ ^@@`wDavWߓ ` Er2SMFoA y?TM_Y3#qӘ)O)*Pc$͎N^@xsCZGc+' A cf=rʂV'1yWXdr䣢:OqEz̬+ǝIglsL$LkxS# 9a\R^C?uS?|5def.V %]Ǫ> bl7`-Lwڴ<6mYH85b.h(K}#Qr2e1l#Ja}5dlxq2vrd&MF 5fAge^KHQ8 Bw9+u[AEqfbXQ\LC1 :7K )7 [{&H RADKjkd枍MAsJq.GIp5F3^H~yC\FU6,,Uh0QD&/my"^ʣuCj_4ٸ+#^=H;a'%Yҷm)|DR{Hc,#¨-ECa.4 qCki41z@VPIvD}@˔E@u^T۬ _Z_\Ge_+B$W҇ҩ(L;I>C'G;)1c z޽3GJ\ZۛdùVE "td%[bQ7?GK~ ]0R˞*~dRs ʀM#M*e8UPPO0h)x"+K J=iZh cXzK'C$P-3:-xֆ3qYmRI [v^oN**vۡCTMy~5AeV$ x)!: ʦ R*uh\ ? 1?N̮=j.=p,`biux.qEG&VM`:"Ŀ  2zZ}Ic'DUȥ-B) AW=&"qd50Pn\F_4eB1φ!Hs9n2A}B򶤯C&)`#*8 A !nnʟo/_혣9EWQ"r#Kdtt9x1[f3A$N愀p傅X=jP˵@g%D%͖?f]dm GV^S2J8aʶ/SEp(Z BB :*BZis8\ }ejjzγG茄ՔBqW.AaƩEt.&@+{5w9*a_Is݈.(-AVJ<bVDI J-& Nˈ'$|1YurOEE9LfXᦾmPk7POcNCt=D=HXdI'rc٨~? چFeR;$}.&(( 6p}-%G_ 5Pkp-!,,\f&AHd1k`ִ2A_ͱ! s*ph3>ri{^[Yeþ~BKuYX/Ŗ 4Үl 22&_aZG1˺Ь&)&6EK'ǡTeEcǬd^^N `3^B3e%Gwd[G1ɣ<:, /=N{'6mJ?_Mܻ47ǜIьIgyFzmfQo<16}e+m*(1 71A$Ϝ c8ґ-y/y%& nJ8Œ9#SKLtp/ 5݇]bHr^k󊲏S$ f_CϫLyeRpjO#5؎s.OxV> fdhɩ)|Y y/U8gfjox$7UUGc6RdxMqPL30uQ|HXŠK?*Hϓzzw={0jJ*;uyi:䣖!ȤLsp̆`L4lh^'m#r}; <3jITM G@ZJJ+0o~z,0K2 wY鳃]4PnSWY}{1 RcKw#ZoJ*7xHXy7YA43'U>3 y}˫hD5~XABaX']Tl0<7Py_SuMshwQ|$WK|HK-me0'_jL`̉t}Ll <|hڂOJu-0QS3M`°Yn[שœT GQH<֟ |P_Tl82f4vb;< ReH+b9qy4o1%4[@,Qq`zm (8Aj1 ztȉ˫ {(Z_yΪ6zE_]Tk5fh#aVl((9#v펲 w2rn?H*.#lm.:7jè4DCXRwڼNnB G HJRrK2U+NIb&"  R<"\p%?ɓӼք^h H '*P~ä=^XCw0f异_3}[&7ݧ]D\ H`/'/!KoKܗ)KS)m>MU~Dk:F$t&"[snnu_- > k{s3NAEh8T9숀Dٛd&>ߣ`.MZS;0B.o%ԍ3~5pJ,͞7.nOL)P|^T@9LfNk׶ԳG$GPv*!?oVT^{$x߁nT 9Pgv Y!Wn?n?omTi(մkឪFaP{ I~t}yF 9zw{37^'xI'jMKl9 2:?'p 0T;Aү`URga $VAe ;n17 7/4dUՂH2U MB?r;%'MD; +xlƩA+*5<0熀 Z{ ?:oʨ;@,\mPeV!0sa/fqdbDOp'2zݏf@"vgE~hK -V\Ԛk5֓yGn)> +ɫEyD?Pal\*Imr:m% FoUy~YK.TYXq& `Ks˜bJݯq0hkRW .ʼOŁ$L [C )4J|AA<h@D/EDŽy&)/l;@+-#M_G8:o-α]A e$RSI\T{/ѥf$3E01OWtUO&jQO?`sB>ZV+K*;>ɯIk kЭtTh ?.>.&6c#+J_=-k|1N;L"!A": 2 [| WvHcA[IV'0~i>N/9Y5֤:Rzn!E2[b0WOP = Dd #.Du+Rz Eylnr #^HU|j5`::XO>RO OMEޞKds૞N-Cr4 e+vz>$)ÕA%*ܰ2dNxjߔj:#iԪ]W?Gӟ@pޗMY /Ebq4\BL)8oòq6lg4ack 74Uw' G%ADzIܸ(qĩa 7+^^\;삯fO3RNlD1ijXK>~oU8B2s(݂r=HVٺwny&4CKfo#߽w>ki H-baiVU"W&Ρ-QojS[b`]^ъ`ws@l!RlY:9 o@%Z3h;+%"lTrs(vj}HnٝM2ʙCW9R<92ˊ]"-}r_0 }o]0P1hՈ~cEz3ͅ>tj%S㡗62YݾYVt,p3U@eQSAN#Np @Lv!ncQsZf1V;VyZFg $ 6.nK#Wik اƔ/!Hj Y"ܐ$[2ǹM-4L@Ô_j`ڑ)%8 %j,Ah3^OgUV/#֯ V֘]Z|aJq9".EoQ{2WS+i."W\y~=}_= 0(g%"~"ηPׄ'o7\p}0{<#EqaX߂H+1{ZǠT xqnߠBx`DMNeU []WߜOY>g,B@k dz~+̂gK}&5 I#hUړǴ9n\bY}Ydc53U7OcoR,3PYY9&{g͎{?qT1sgOm3pZ">4BV ϣi#Y9yx=aE˷/$v%U:PV%wf+,^]cY[SvMthG"Q"@FE gS@ 䊸}9*BF|m&ru"TBu ۑ WW/AL.z ў{w ԧ:Aϓ,{r Ψx݆*l⊍ٺFԚ) <`M˟TId ~?)KHa ]k'k?êyd|t~6Vtd0p 4\~JNRt8?mշG+\r>܄ |enJ2ry  4ˣYm ̑فZzc3}͗yxKpxņ$W:cdeb+im^TYdsZfcYf0f|i>vvQMF\6q,*5v4!嶂'n+2wݦ2CW??`wI|21[Q.d ;մB[ Z ҤJ}z5igs;k$оפ,,tRָ`0+ eIn )Ci6j ."6cVZo0?eV\rYzM[_@<  &'o1sCT'ZOA!'&>4v7]Gp5_/f5&Ղyî~RothQJ~1xq t3/JFݡ2ެ9ujLGFv'LQHBB!H:elZOECRw!s"A {V8ZIopؠjG_tgĚaq4G;:>-ou?Mm bX?u;#F$ dxk74~Һ`ynϵqlIx˂jieI`p-~WqmtvvJj3ND##jO9P8бIsRD\ Pdע34!!• < {#'եG KFPIxpf~荭G ը^ n&jW!CTIڤʮ.ЯQbuQ 73n uuIcP{ gFDb50|)3ozQk{[,A|xщC/ekD[I2B6=}#ɚ^E_%ں{x&Q=oq덲aK̨^_:RYV[~$PU W5B)}A5ȐFa=Ǩ f #F*w/.mrm )]BVT0.ԭ1Tp<$aF%dpx+ , n% .me$ڇU})hna4^%ǵHiO9>s]-}~I,|kc< T6 cPG0IIBaCh&P4}=@f$_0mhS=2:q=v[fi3 XltFЅ\^'&s#7b6L3  @Pm3,XVLZs2 D>>Æp(YUGC5 %(8iu־iݹP ruH ;£r*+w=P;ȓ6 ?DEVF(>vI*C gi[f7qnM ׽e"=~+{ψ8rvŝ :`P,xrΟݐ 6?dicg4PJf2cM3$0F&qN(!-T`O^jPerp]9q|@|7}Yh";ㆥ`UzT$BFql,pZ]gف1no,VzֵXҡW*LYT⫴ۦU=[aYDAb/e%LTRS+2]>dXr7mnG"t7`}JUKAVL+FpDxV$(b`~.iD:o&͎P֧,pgCUx i5tu8{H\U0@kO6 d$F%lH1qhI;3ܑLz7/.i$6{289WgDdP_"D`eL۞Dwcd`)ڱ\UEGH52wޡ?AKI+ls")`:4&*LqM.uclq&MK#p[3]1{[Ioigs޲俳Y|n9uH3+wj&8gϽ" \F+o<&ĥ2}6+9 cƊ:8QvvKfe)rj-y]:]Ğ0_BgpƂ;i rsloa\pȏuhf։0rU!\&\N׳:GXz7vpc!-}7f;V9p)!0l{Sup8Vdk{w/WZue۷<رY 1Ts[Fn  Wg] ɥqjv #ԑrZu'w9|0м[I-(tmc6 M 6ea B:e2pp[lZAB( K m4R]F$XʭZVbԕy8!=dKeW4\nАTǠnS 337{}:p%* R_X^I1)uB7CGJő0 wt =mv)!d('r(9^XG3}3-b -lxei3gR~F%g4„`"DF ޢ؄p [d!,u !zR7T BUܺՕ%T<<#+N 3#ta/]&J- q& ֒WՂ9ź]o)Oe;M~I7 H>H }e *+>b/7´j}+K]cЛS@z4AC q]Њf+ʫ ɐu. wl^HA@)ZhKp\Wu"c<*vXjT_ei_Qz?u) ttIR!hpE0Aot5|%7h%4~x|N[ }MZLPs6t7Lco3/ Х3tj.c36 Wl-R[ay<ǚĘ+bLM"Y^/f{36=}&JzMt}{4(G=E*z-d-1~ɢ4!ҥ!Z/b5lۜ4]QmlV*MI'  2AۜM7ܵ|_{|qKoiȅHE/Y8Ϝ }a<:@ЍmQMti9MN#EaF+ p=B* %!=ǘXs43'$.A(D^_X5%ݛ$:v.j$9G6yLrFړLs tVѵ, =B Hц1uO>Ga 5Y)BuۅLA@ w^~դuH(z<Дe(~Y|+c?c|b*K6 <XL YAxSR٤ʃl,jݝ"bjb"@K&4}IJv^ף{߈T9;mGY0GQgecf1.ӶmQ7R5)c qU1cXˡ#+Rm\>P{tsj[ق_i#$f} g$PW +P,kuЕtdbNA{5W]Z]K@.F*dA{ANW1qn|>a},T3kB^T/iuX]n8BT2u-*(cu{?`KAā +< F 駓ߔH@J )Yr`Z >0' O eX^l xlE1IyÌ`T2$+sfp7o4 $$)BVZyтVP7t>l:{RX~ oOG<QhAY(~TqDw5݋x 8:_fm"cz#rԁ}JF6oI*3l? '=7h=`]ÄdS}UeRw[YHg&;@!OЎxы }[,EF)b%nX@RM۹=>?E C1N`xD}=6ɱ)MAE};7sscZ ݂P3!tl7w^1uq% 4kXz{=>2'k@e0j6k_AO!E_ fkuTu IR@L#y(;8Jz(ѫ~'7zlo%]=,7 Y%O'f(PyYԦ5(M&tWH0[:#ҴIH})h9=K?ׁ p!7ݏқ=HZpc~sAtuW/Ѧ p9=m3b~g7w\4DW=*}ܫ[LIWBwr{4yyM\h 輞<`1'tdҿQ \A5,I!n?19QKjVuxwD2ISxum*6l DL|2KB}ZۑW& IAY* B~1G[b^˾$#clXG{?p_K4}oN׻,ULn\no*9=ǓsH8M|&U Ho9R?.sT`U jaB8_9E'< &~੆? x,I\`Fj1/%@ڙ%]/2ȫ:'w+bRXrRuT úq>LE 'M6$-i &i5XoR-Wfۗ8t}"tB*@r0!X$"ygA17 ]ݵt˔H4} )C!|A`H,}Y0/C ]}[9CSg_옙4O-iӸH|-bd_Q$ꪗSvL<ջh Oyy!Q>CI^bZ7O 1p h-O )"oC]Q:DB_6m_{Y9Mm߰qpf|VSNr?8|ަo i2z>sH5źG̯"#,=tE3$'$-70zD0lcڂ@e.•3Z9 hiHBr pK@ c6ybo&qpd>n>"+{5g0%oy9(+"9&DDK-^ ڌY!"{_ ܀:z$&y$wݝ9BDfGi &  pv*ہ=^D^Bb25t9GCYDuM2k)r6_'0N}0 K QɋFS[ Q3{P7Gjhu%ŦHGAU O>*6 d}ydv螚߄D0̶X0'G{ D5jޱ( b۩zs!ceѩ׸CS{(AHj EI/ ~_?ґg. ̳̏q?n nϺ\ +/u3)U|xYIʱVa^0xR 1EDR5o!iGϞ-Mzﬡ.l(, SnӐPEOj3lI))԰!%ր>՝ZdDV hz9h |"?1  H`ڝvl5]N|zMuN-'SC0Ӑ{{gBCeaHΞ-E-c@:b9﹪YrjXqQW3]+*~ *v)6j j /I+QxS簫qqh9mH|`U&Xvent\8(T:r7S`AR^YiBEZ8"K:imM<^U"sZ6^NF+Ⱦ0qJ}N3cuꯤ;$;2>ᓢEhw.ŋOBx΅D*ؿRRonu`TCiQ< */عAESEk? ^mKƸ ԜNou"*3գb-x'b7^>ɽRR1W@ ! Y1ŎD!tOoF3\%$ɨǖezX'Mхd$ \A|m_TrZ#8*Xx5$W@ϣH{FUFΞAvЇQEoDRjؙ"y;Iq TVw9cЪȯr(RaJAfɇ|R|EOOC P5Ѯڃ:tpgޙy\@4Ƶߨv tnƨǟn? Y;3Bstwy,@2)/%>!Y>i`3HhodU;N($] dؖ ^YWsŁ߶T3{Q^x/\T X)CsK zGٸњ,{9+NxpEIވ8kaHmN$"3mGw@y3+!ćfFUa>%J?koL݉aWyз!20,u89`ý^Ydf~2-C)0!dp w{ᏽQ{)aKy'8_C[d V㯒" b=ibcw!D}+DC֟VG9j.;$r? -9m>8Rlh-B0cyNtZK2u Ƙ>_MC>=oi1@L7jqdF {nI{rft_uБ8 _5 "H+UL < Ʃ>ߊ>s` cJü#(f\TN_TC)Ȩþh􇇈? C䞪?&R6LNwж*ڑr9 •[ڤ((^?,3u6Ć?Qu *l0t*K)ϑ:czrD@tLpZjm^ eC~:_Z,q ])Uѭ7&K(sMxyΐl@HQKCbK. xivuC VxE '(l1#Ȕ CUFIiefG^OVv[m(tY) )ĩH17U.CzlU]TPꔿߵuM;r#v\TsٙW0M XD?h"h?/r2"Ny ~4~ `GK}EvU(E@"I $Qc)⃓v,T~!fc#4 Є#j8/Z~iE0Z[u/%JƄ]="1#r 7>ߢQ!9S'tlQ4aK^B H實.AKw=ߘgq1VŸIXxⓊ9RaC?GE gOGF'LmYuݫ-\k# {!~G?Q??!v3 1jexmxjB dn.ObhW̓gJMBW }~ybyy$a6DC9tɛ(5GD FY(d}Ir@{!%wlݹw`@+x[?.`lHvZmѐR`rG:ܙ.MFDig0,>i&L5\-yg2iNkĒ1D>*+gAeC&/acjT/d& ?me%\hYIhEI{(^~G%`Tbsxj/\."Œuu'z;~o6nv {Su@9E_גpedn:Ljҥ;+ RALq-n Ҽ˟Ը?5Ao.&4j:7N}@}*qׄ{ljJoԪC?@N$ݼ_vߎRȄ;U(\M׫3o^a{Unc+gA9+DJH O6x"ŝ>.|LO9HoCA_c ɠyvm0QV x='6o{Ӻy4f|ZW*)VVv@v؎D7AHHrtnϟz a|!Z D:Ox-Qyfa2VDuJ|B8wa|i2zGE nTn lHcb*{}\q6c+}((vg" tU"!4!RYFAl'E r~˾~>{OҝG賻q^>*RL';>-ꐵX+y?`O\բU\f)G\6[qTpl1W8zW_˞_g%8.ǃ͋j` T2l^|=nT?uҹLmVaz}:}a.}CVMLpt_X!Tc&\iz2S1)&_j& 0Ë(m;0fו2yeggv-p\<# F BH &F(j._eG"Ri Z #b5ԋ ՃyP53 @TPkRtd`\XF|g~lʬJz$hoϯl;I.؆оݞ0HI7eatJ!R(*">\˧􁽂H*&c> > t@XD. BtgwǙ\,Dz#8i= M/h5w"HǡEHVt ]M 6@YSW4e+vE"  712oGM S%!ޣMv*Ћ8 ΂"TsdF*v;୅X_vXbtz9KE.E؝guq(\ Έ 4ػl-@~[5#髤I~<$G5$&*Eץ O B֔nwӞ ;XУu Fk~.[FJϧ!k 5o7K(IswJ؁Z5Sk_b2w+hL]:.%3OpWoD5~н83՟f~h,VtϡRFPJS\1U000HY(aTPߏkl[@v"99=mOQ1,o 9HbOM=c7xsAB^bPn6q'9;!$lB6D?lXRD/7ƛe1xv-,bt&ԽmI<)ȢW/q|˵ ]4V߶Mw+,w`SCĎ&`:_^0eGqeR *#gKs,j|H$ %>U {Q'O)5yIȪAx__:G;f{M`:Wv'AhvgK}wnᄈ0yDD '(2Rԇc\V]Qr7Qk}Wd܀=HQ7.-Η:"Vj  LmH$(.2g39_Zje h+F dR3}lm!Ohep7}@;Dgnk5|vS>|1ᶘ;ˁ@âp*!1҉йlf5_Io tEd<:vNu T~J R2JsLZUdV/ bK*~L5SM)*e:6kQ=O ^Lׯ>|'b[FpL-_),n+KRIkRCjP|k[Rh>h0p#NL+hH zmQܢ‡}H_=4߭զ9jܘCf)&wn8a'ބ }r=~aǁ5^R4;fPtYۆ1^R=KT~|g:ƗxH >i`~d% ZˬsoJX [E+^ D;Ś жTVl[rWs;=U 8BOZ:dM:󫆀f 5g-ڈxlڏ%E?OܒvTUq k i['Avv=]{cH|AqOctepS~_0@yϸ\0EIn&:lEجy(5B/Q*yvG,poc?RW3:%C}uIbC̺0`A_ޔ7]&L-Q)_ tiV"@%"Gk,t|} XADS!B54)\fS`[r(H #H3K9S|mIaG7i|H0UX6n[% vxo3rzӈ޶ ]F3n+9G/t@wJz,B!_D+~BTG:2(]i7!_^V"M(AnOF`58vSkW>ly`'EAdsexJM0NOcPQ뭳LcsۭK[n0 ,<O汅(щ~LܓʪE(LtMz~İCyzpj>̪(N+Kȡ-"R}[k 4~o:e/؇|fBb^~9CAyb2W&K}Vu%@;Z"TDq1i9]b8%UvtHJWd1yDح9*c.ܪ߂S`1g#ёi`sg*kN{ǧzu}İV'-4%Zy-ڴtAšR Eq+'PtOIR($z7XQ(w=7_=ԄOpwjd 7L]MQνw߄\,VeV~7L]>߄JC*ŋpHnQ-,K}s*.,QdIF~|#$P4]|AW|j /0Y~}-ŀ@/<^*Y|Sޝrwb^2/gI^rxg*2|6s)5(h&f/Yi}鄽PY>3hf/䖀 ՃOU۽xڪzB'(Eޮ 9~>WjPdžcpA]2[5dz;\GIj&onA:R ՖtswSW :O̿^ ei%]kn|mLj}(˂ ^x!:aƻ@Pcڥiߦ@0wM"L$C#3ҒF$rܻ#W qnJTč= Ij4 t_hQ`VèSϬa%I/C l7l˹'NB"fEݰC =f6Emzϋ /0x:ҡu*5jXdP@4n^q,hvNW&5 ف;ܩ4YMh{jx^.aW칚"9t&Q~-jފt"; 8Daݚr@ N.#9ZͣxD)$>/6%4fz_$Q7J+,>giZZ޵RlVyQknkg=nv@/iES^`p~;oujϫ7%UoyGB8#`wU6 n#pK`- n~#E do`:rx4U7+`Ϸ B΀JlX:3?³4M,6mKB>{4{oWg/2/GXW ^kz;ִ>ݹR /Ʉⴣ|7(wB!tK`@W8PO LGcK_\ \0o3I~L{0{PtFs#̙鈴`{@?7̚ Vuē8D| `Py [Q]IFo|sAS[ ɒ$`б hW1 5:#iOkzDy2TBWyiŤ#D%ޯ|n.y /cBРаp @!)Pn與)A-u夛k΢Br"w a xupYҠUɺBA8=@ֽuáPv d][hX;SҚ 8 FC|5%u3P՗cUٲzchLPdmq-7ՏtogEm1Fa[YݏULLdoo2)5Zsd/0{mP9xgf/YrM:^]$ZedhX{m-un *52$^Hlh!a{whD{= TIkSIb3CijPIYSN&Ѹ,CW #{Sr,p#@>cR6=jd{5;fKT6^AQg%=N L5`c-O˦! b0͊ ??D9VW͸`_ԧWF&|֜#e1m㧤W7y|MO(3{!]/z2هUѠOti \_M c űo -O#=.oS2qm!XUAY81EO< B~`&%+ 4Y j R0N=Q&c!5k)gG:*u6]06:Td6,= ڪ5Z\5l1oIٷl <}y %>j1 繳`2r'-/{E߇!i(*#7C(W[qxQ7m>'7IM ؾhH_YZc=YǣWڬUҟ Q^ T3< _ʖ"ԥtsikVٶ/<1Vۯ]'!Dฤ˞t>%r0 DEc=FiՐ=Ȭ ]D׹QvoZ#+Y K:0GEU)fy*V`b\l]8hT!.ACYade*;~m_Z39%ZK7$0*=ɄS)vzZq :{TZ4 \h%XF3)PDcD, M_ΠfQ|v˛wЖhƔcp{17zP6NJX\əs/\G)JR뮸N"@=[-lGu!{Ra+D`_[uUNPl;ҒhXEbݕ^t[;܆=x 1vI]EW}5c/4 >/9W'FIDW󨳺K8$^FV P!tKv.ב€lWsV6_^&"wy{ )8T@GNR4֝'dU_uvhݿT:;e{yHx?XA}H`Rc IU2IBZjрRFӑTh[g W<M11y EVPɭ z+?۰zWf|K<@2 Cz= gz(j o:W>W)AV|u$ExݸhpP(ǏPWL lL-b |e-V*@;j= ;א``Yd0,L5=Z_ycPbVXg#Im <c8o3-b|.c F˛sp$_//P6 1Oqosb?RjY6#$DuT3fv,?yᐳ;*0){vV9/OyNk{<3keGqò>uPAC?5:vt8r+z]ǶRY; -9F[|d|־28 +K{ˎgCZ O#l۬\`/S);_)BȞ]V &W6"ljRM!Al~бo^bP"9)_h)P_}TyJ})`Ci?yXrs*y誼H4IV&'J5 }neNR+lu3כ8F<`m/诧-63L3$zY׮WZK!2QGV+m7ž}Pp3-g)n-!1tЭ>3䈷j%yrWN,n5CM_t#ax{0@!O>V$D[E[*DYD7dtg9iVbD"۵hL*CM] #~-&hz8{=zIri5?4b !v(EIw4R%fY΃Va7×H$CzW46ԏ_N,!im]H%.P>GX '/0mį&y I&,8ĊjNyaKt~IDaX@nXJūt-S5/OP 3hxn: nrsYDZw!{*vF'10n8W^/)\: g.Xɧڥ1,}<}nXhcBzL}dh&&ɢ E8vSXVu [x͈ [fft=K$enhehoWrheǣ oNq{}TAd A{efcVx;HD\nSpb|I7<1NO {VܳI;Ia3E~5vi*[ MUL_iTgyl6CO>;>8沲(S26cRyzI7&}t1HV[r:3HXTH #9cy"7__x!h(Mj#A#Q̿yjPgoAZnpH(b6L5̶@u|7g~(TxfS`γ6jvoBXC!ʍj{v*az>Ί7C_Mw/2 6h ҚBJE*w;e"m^qfsS|ojnHئ-EC+p'Y<6V2pB:-)Q0Z7iՌ P#$Reb06=R AI =Cs܁yε z܍7vA8qi&3܍ځ­Bۮ,PXxw!y&.hxK xt2ra $!8ݛRTw *"B1vj:NJ%M:#U_cs)ٟ1pAJ4Zh"0P J%5<0<5FRμ ɍ"D[-F_T ];o h}+>QJ{$cd˾E>_4F-?J ,gCCѷ_SsY'eRnJqr% b;JkO [Ez9.O]&7^)pR;$/aU?ޞ /ܡ4jⵤ\7=֧%?uأNE?0J}+v8rt)dO;Ps_S;i QfyP</y^?Ih cxrr^EzM(OQȿMmH"J&;YH.!F܃I+-Urm"ZC8]4i7_A U^FK9tX}ܣl'UD># ey9ȫX)԰1)7 3MV'K2,VҶ1Ţ_$~ h}߿E|+ +ewފ<:4r?xSK!NztCVŹ3Ǖ2UzzG\JITX͋`TU3':6>gz/zURѲ[FϛUYůq9Z mQ-UbRַC/8Vmp*-+nw&yHwh ˯%*6FHo..WLe7v@h{ZW]aEBh#o"6`"ή>`"؎ߒ.;PO+G7G# y$q/s1X|#Y'Ra/C=7@j"J~X .s}Ep8=@ waD+dְF<(7N#DY!UKօ?n8zahyƅ(#c~Yl#b!)x* M*c2]_ zOhJS@|_#SPhd; l2.YHր,VS obzYO70W.zݴD:RgRĺϨM-;\)J^ U^a x E mRfz>R2RgFWd?mk u7o8W|q%cpl]sd`48% ^āid*B6цz:]0[ CAlҖ0:cuEƅxnnMwԧS$?ql#§-Ⳁ4F`y|,]4E_tB{LsXqFMwLDA@B geZ|0$v4socjMvki1"?%H8z2?M;iYOh iҧ[Ad︞hNYORJB٣Ydf0G=Vɺpq$nǹkmK~pw:bur/Ttղ%  ![FPc #*K8 ]SmJ.M{^vykٞh=KOB%bJ0\!tX_0't4@=g=M lH_K2jU&gRX Kv i S28zpIp4-bῄCP'Rmk7?N6P G5@_ uO,7;zkJC ?~`B23;(sR |\4x<5Ku% Ium"q;zrhNԪBs:kim>PzbOyO#H rX;&߾:רb?B'0w`1|d` .UwQmGW5O-cZZ=]SWL98eߟq!5qt# y,"Ҙ_B)HMtbCE66t6\oIR :=Cy-U䴭P0g`h}\v}aҭpoI9hg,FaEt4~u bUpB 3{ZL<|5C /+vD9C} q]6#v.f%"(CA,A W=ЮkNL(j"0v546\[ѭPC܆cgXpZ!43PlKtHTd|zneyyG1.B& @gz_)* kօIzGBC|j^˝${io)ݐ~oࣨ'lm|K<-r)fy݀˰a6c +6=:jP_0>py8I^vb-ASlSA^: # x5}21e>з"(?g$h"hOz\yn\Y> $6?q- :+7rA`*QgpFfHUаÁzoYB*iVTaΗ2[ o?t6ké[Qu + >>AW[(nO?TdOE1bu0s@++:fg"X4i98̑ NSw|? !5Khg:E% 茄P9DJa'<\D:rDS>f8o qedk+2YD.((ܷS&zGnӣr¿oitD!eX6}t]J@µ*Vkh!/20| Lj]Odl_Zuh~NܣHdo睺.gG̵;+Rcu&DZ9%"IIXH|rгt}?,cϩi=WQ`֤w) 2Z<)G +lIwΒ*/qsxDwJ>FXU*# (ce`U+RL~|kVPY_;27BIy_LXrYAgȃ.nh~=,A(&1{ ;==˟z9q^ZzbPȦPl̂!Yܽ4JT*h3e xpt9T3K^?iQÙ!+qq>W7'Hqڋab9TW@gi\jtC 2݀(p|eS_fgw*V(j t*+t3TQzW*wOŦOk?r8bQ"1kIS ,\tCG)>S\:B dIw `'@PX~)G44]N?MM gʚ@8lYCWJDO*bc@lK#*5:0'^g7 :bse/k ś 3*ɂו_pD 3DYM$j/Qm94},ɱZ`ᘕ D"TdL0wV` *0֘ݒ5ve JYfN'b$?JyM (7իˢ)WD;D2j`nsP;n-77D>/SK-E:`ꫢ@Di59W+Μ*n) Vwng6;=ëty;(~5F+z_jtykf5k{ei2 Y_$BG,X^e41z>+uutD/@f B!H*h4fcdѦXzNmÈLFApL{ѦMBgŕ"# "')j~A}eӶéYoccbUE<.Qf+fv A+˙/{=tXCMJ RXNۉjQ,yW>cZNw%4fk^zڰwΈCY5<Pdȩccyj ky}> 0*'-ХnW=j^5=` {jŗ:C>,B!}kZ0#ɚĪ+ 7y5m=lg0~$'8L>KwWDQF3J`_3qqnpJfr#ŞꏠYȺy]7![͗#9+a\=S%X Ӽ4հ :-1N2ۢV-K67K߀39{l]8B/Q'ieR@ú~8RS( ^EʼU=+7M[_nf3xˡѝP ]RЧqf 7N`_.%oQ7+hʮzxx H, ˲%+v^slz]y$ o4>y٢C/@-&灙UkmѬȨEܷPLf~#G'@0&֏^/3WI|ؐ2vx0&9%݂<1{MȨ(|`4.De =X& %x &^ww@U+|hBz~z`/QzKT0#0$a־Ï-(Yi2Yl" 6:aSPE.O_9\ ;QXh.|VC Jλ_pB\vV>)?%Qol|E${&h5JxE4ΐ!ɆSknhod'IǪ%֝Q;8d`wHu۸ݐq} >;)QU+6ƖES~fݻ~%pv%\쫃',f#^8M% Z9ɒ)Qu 'I<64jwݧȈV"BnuJ3xGA_uQW5|nAJ/LU/?-BV1%k3QEkq*WP`Dq@*CxyN;|'\Ws`!:+-#ۺ`8F4y\c܅|۱wjh/309LwP0KХٳ^&1ÄsኊK%\nmnA3KU+!7rSmN?0K]ɽ78󊞄f \w 0?[ij%!o uqhoE 6w&tg:7i%b#dQ`Oc]͉ .0Õ__bl㐮Wwd`Df8 lMR@N,H1vK:o(5 n63x+aS^!+lpN@1(=hBǗ`biCBgg _<4[;i#6۔qIDY] [F)3 cuYry܈765Y^l@AMrPBɢx8 % H֣_x0/D^X@k8͜SG:̸}hJ0Hs( qcAї:?qՐвyq -HNjOnrz}jCrFÁTQ,݂ =RVάT9U迯c<䳼. lzVFk.fA  )"]Њf_FϹƏCwwO'VI{1)N<橔3Eh$"]H*ϡ 4@j ݥ GfGk$6,Xt3v+ GYHfrh!n N2?Eki|]V;.5Ch!"hdtX Q&2F=ƕ.џ"_`OQ~/|&rw|ӈ׀ֽ_SM>.U> f6OF yiuMKGJw77ZED|WϮG < @f]At7;-nآQ()Uϒe`-@xJNާ>pVOELE(@SÓK?!NqszzvwV^XQF{v z J8;7%Q4vkg,a%ll=2wv֚zyCOCnu7x&fT_\i%_y1p|P݋v {K"E FһIZj2=vi%r<΅Bc{xz"yiveM]O)ѨI6 #vNj%n0?"[isx40QQf/)W A| ?d@d$ 7!OsBQ Iʧ(C5p³AxkX}ޒN"HTrpPΗgV Ab^@8buM2p`X#NؿL/JlSCR,f9 SOs)yvѢ% /GVa1ʁėi^uTJȖz*(@rwXZBT2IVyDWO0qpv}(R7,_G gǓwkmߤ` 9?Dd#h BpMCˤ:2/|2f!:(YD.Ij`q<>/ein`pL1>IAz=q?CkI}[%?+߷?eQy-6'F=w~bfÜJ1gr tpA>PCQµb3Rr~͇.߿z3/';f!Z,G gbшI{<:Qic{l5fl.t4mn+qsbBx]^[kDux߉s4v㽷p. yE+$}[ro}w_`׌D8r!龍,/e_=3,S(Z#mMJ^eX[t#$;=5K>#TOn(uۦ+ ; ;DDh#8:.uKVasZ# >luP9C#+kb_9-ke#&QA4X}:c%nkE}c*C)/X-j4ՀI1h`D=2̿,Kdwܛ>l`,1q3zW|5DXfěsBp?i}k %bu,B8Fi^`C6Tkֈ5#6h=cgr4CkXylQ~h%,՜+ҬsYr/ $s D P*2wМais}G7u0~!15rM\\bz5Yg]RPJ".>3װGU"^|ziMTJ2F |Q}#>eզ?, BF6դ6${gC3N.~/b#ۏgzn8t9JRߝRNyF#YGFr789G_c܊Y0Gp3nK8K*=(V,xptַd5i{uamk wPً8|^_}eڼw5bێ1j̛%Hmh tOY0j=e \9p6~ű[Ѕ>9Us,uWZ2 :)U':ιwI%;PT8J7IBEjKJàBv-;C'DBрA+2NF;6Q}ErIdB +'R+n觑) ==*lĺ/ i,:GMޙ͚8zEB.XاݚGZpUfe!})q#B؆>&O䐅ڕ!.?_ &Ƕ>b |-R!|ڳߏ 95<-p2^/N{lL7dI]p b`Jg($8*tIJFOi^;[MEEzE(/uAʡD E~*ag1-A1usLa!Le6cOvl\ꈣ 4Ƌ )/.g3 l')60jv5jvDYl\`Bi)i ȼ1+q1!O1d*XX񀧶5kxOC0ސ' mlb̊Y߳=}8U,\n{%T%WKT;võ@ Y̵U;V`IL4Ť,ًZ\L E&|7VO ɄU'PXː03]q JeS 5s.eGOᖋ-%$`b'Y 8&ķ `eXC'MAHxP4xkſ\ *(l L 5LOo{-,#Tl](p?s.S0$mm$.At R}U>4!F/͎qd@|(<2M.1ů64xS%d7NYaJDC8"CU9Q8F8jAATS{ I. @fPlƐ% )FG~MqTF`ڌ"DUBO)CJ"5!~g܌:R`#r2g}Pǹ5V!b$Ŭ ,N%3˙T0M~&fs F'oRd0tAz@֓;a8`rl`âq R"t;=6 = жTGc6´dcX^8۵0Y+6Cg<rEo>~{/.ݣSNbsbtC9RxVeMC<[򺎶ƠY?$ nx[̱$balDC03_\1 zP_i5Xh?} XjLedq0l'GEq2㧤"gVm`navd{ %חfُ^?0H~;+|S_=_-5$VJk]OkWו`O>?jSwMwW-ӢF$h~ vJ=W l F|ȼOnZ7~QfĐ'~&#\,4!, ѷ`xTڜ==mg)lR#x {u9{I#;Z^MjOMPTbZ`2pȟRHK<+~]..dܻȮ|)娊C^&r {dL\ W"YZ rˢ q_c4=o[M+(nt/BSaalX ~[OU=PDZgIVOweM5!)Ioݜ\F̐,4_U '{Όc-Lo߃M{Bn"q!=nrJ}r?~[(.R L#YcU%MQڢ!k$$yvJhg5U7[e #CmNdX@>̛N(\r%[jdh >&末?0)b7yJA:ҥsP(֌X$2r Di)ũJrc=SN&t :p1knd8K[1ڐt-%*W-):^/-hŅgY\`<F ߜE^ޡ-DiQj`?|+h'c` #3a ATc^Z򶲃okƴ|}ΰAS)b3RE28⿕J(*l.>3]/גsmc SWJ*l?3K~KrsqHH=! 1L'E-==@z} f満n8&sGFѭLǿxY"xP[v:><4q {W5Ӳ$3FY7 2ȩ.U%"'ĺ87KvdmZ|21d|:K%{bh -d bq9]7/|>HSf|>AE1m p6V{ %*i*EOSߥ >Hhs׭h==|@\^ᆪBDi[92n i~.{ષyN>ud!xYֿot"r݆CedƗB7/{|AiW}pY@xN_ůwڙqMU:Q̀ݮEnN0C5(ðFwyBp7<8R:0US,Bqo Sa4 I+wRF[ɕV'ang l4>k!fvt WH^}I}ÕD@T +5oVybQ(zѭg80(р-8!6!\%%>DsDzW6T;2,>>( s49[*ӑ|Z78i5,hM~H^Ka~Ry!KߧC{M}9{"ê"kM_YbF#KN9ه t 3nU}fǓ; QJc2Ep&Br).͚Ze>[Lň3 kv Sht#U7WY\@(yqWL#+'7%%H@|9B1!"Z 5T7V)aBsHY)^0xMJ}; CEP&a{3u-Տ۱zIlW?1a'N$CQ74Ad407/ӭrk@zQxCFŦ?inrv$1)<* e0xkR0|Fm"(Q/ lZS'PZTtΎπI^rbxWrqwd =C iiW>SP(BP=\Ю=N*rػCJYtp;$4VYrt$~"U;yE2BG@2?ǾFI\d~ȌnF.8gM9@U|k:#nЌD_28[a|U ې:G:WJ.) Yw1lHwքSξ`+Ȩ 'O{q{A<4˞#=u:Es.ΔzE:1>UA 4U1Զ )Le$O 99Eay9pZ47M눇e8gh^Kirnm+ҁD1tp;î/ml 0i'G=ET 3EθMݠ?L# t$jTl3\0WL>r HŎF@Ya2bdl`q~5+Œ: `lVdo3qlm' 5$S 9$61->BݻS0ާdX s;X`AUcP.pd=WV{&# qk~w{@gH4ECSkisir-tdm M"|"on9"L +ǟXjm{Zф(1}3yQ\y= P| P]$ &vK0&9r31(b{qk U]JZ>.m=pwj!>l 4Ap6㹑dp-*=N4N=TEv{}El\E+4 =_Jdz* X(ƹ4 k_^/ᴤT>Bb5՗wJIB); <N '󮹔H}P=gǤQh4MiyS Z.^ jbs 1uNQX׏^F E֥n9Q\_=5<'3vopYRuR^?8‚:pi"3\&jO;fkRmtX쓥LM}(oD~OR?WYn*#% >\P|i[9}텬DcO|x3W6yBE1\;CF;yKa1G6u-B pRg}p<֡p?zB`1xq ߅"@y׼(KPr12aħrJ[( ILt$#'/9Ө?yҗ0șcAMԂW%I 7rMD:k)TlZ1-CyP#O֒jZ6C!>۞7\$4m4h~c;`h姭K;>Ѫ$tV7^5s2ˀi$Goj ]j$Y21Q7C|`=!)UGx7gt!ׄ_XOKF#H(ИܟhJ0o3w@[ʡ~lmWRXڞ0!2a pRaC|;MiWͲ0Dˉ 8JM^y#t*RK !4!C&,*Q>Cþ4΄buv/M*bi23 3}ju.ә|7p![)ZE9QkRaF)lZIkFepk f ?籱_nY^XZx]B0Słgטƾ9QOr~GG̎lpüLwz%c6QZAPrqs̶bvtpaEЏQU|<_x9%<T9DrW\E:Qz}K=`? Id~xѐUÓۡ̾ ɌŁL))IaB":C BozN^[J4ΜpR:_TlDJ>N.DKj8uBE _4-, Qwܷ#Lfrl+,`ĸ6tGX74y@7i[(M9P$Ol,Hƛpl{& #WI蚹,&E^af̔b]KJRfM2E,bG U謹Բy#iϋZ(q"}4!||ˆ u+y7ę n:a 1`ӕ[Gl qҬR!gjC{YizdUM_fl$pدDeXI.'r`ʾF̳Fs?$,fZ:{{y5.H"4#GR8vGhTE,n>x]EoYZ0@d?zzt4nF7^Bxg3İSc TqT21w ڑ*Q !':RdhvP ^el#Bw% vFNrQbZTp߼2 泥Jm0<2hq֪ѱLw~ն"$_җ[jЪn&d-4cբcF>Wy29WE{rSQѰ#^ B/akBpg#DkdH`E~[X  {,C31zUZl\`N%,ѱ+EETtH+AZB =MU\T5Q o#:Z#aUh,c.Inno Setup Setup Data (5.2.3)$bzE] 5\)@Y}#}v4s6qCp5h5.Kkbp44cHpx8%$;b l0n|n+B݉-ǗM [?^~,Sz}zDHЭ̳X PBf zI %yq \Mʔt3M]$uO8G l̵G:JA[F=g.V^sD_YTBm*%h*^֞mi `{[ctN<䀘\`M@ [JYu։e% ]#JW36-`Z:'۴xBhP m9.E:L#"?l~5,+.̼6A&-FɴD0z=ZoGs GT9Xx(_ uci+Nh@8>5I/&\,vEwiws&qHY)mNj`*M+9~\#ur]gS_ĒlFyP׽1(Өod06ut2woY 2yk̯dZE3~fv81tϨaF{r)Gpʾ3Ѕ+Vۈz^4 ׻8qPINYu&!-xڽ8t?sPי *({ m*d_]NL?RxHFЌ62eF^ i)A׷P!%ɲ6: I#bhrX:p4PA_O-fFD2*O_\b>l.[iq(4><~|=ᆞ1=JfNtWBG:`d{TZtݶx[+o72&`!}/jgMw*HlKb͎'P7fA^(.uz1j)|PVa.j}y׻Q=$o\|fU)f02,bp&'fIM/8/|\i ͒B$H :=ۧW٤ c Hh9T&29Nddx! sROn4S0Vx|Qѳ{yyeG E$[G=g!,R2`B8l`,Z3X".M $_Ьoiec!?HĞݭv^<]*2ݓnXv"aDy~ T6]|SS-IW2/:xr68߱&;3ǸkJp,Tᅳ~1WQ,4l7Qz+r֒2;)bgL՝-cv^YZKT!5ĞjX3uR,< r m2Z|rd=E:W #3i!'Kc&:Aj ”,p]C#;4|ӄlՍ| /O._Xj$=HTC 3D|S8$$EaaᅶCdv CkxiZX a&~ae\Q*N%t 'a1M Dm=^+ U85]Ҟx }oZ_-$+݋o2== +*]Ƙ;'3m#v\[\,̕@_|Kq+2AsW4** ړ)nJS=coQ0Cو דjgJ|?eWߙܭ[tu3!ޅTâ QFVHDBemObfd'JMtF\@l%U$ |?DvP]LɠD^"ϔJAL:[2U<:e~l>ȏ`a$c˹$ĸ(xcP h΄ҐRaݟOV<+{`?fY~T!0%5!oG<4ڕb&TEVom=֢E^ 6;-_L[WԄi^yU donO+a$S[pɪ\cؐo?tVT.NQpa27OTYz#-K+2 vb0xs%1s9,:zU #+%5kЎĮeq4*Ѕ O-=,~}K81Y3"x_N5#q#X,9vKB|&V^˲Lz2kӳ}&Ava.߽_Pg"'m0AaTCfp[h~k֋]9Vh3q7[._Kzs1QC}R*`ՓL02*.׎C"S:)뤃y*!^ߘqHm hr07_!)ɘ]Y8|Rr7WtU@`"E(hx 1,@P>yR^9莰W!\wU2fמ.7]u%ؠ_耸սl0>?I ; xP9nb *y]^ttuu $oV>QJR5{d) Mv'nk^۔ąHKIK =u[:o٩-dBHLqA>C -$U;G+])ѱ 1ShV?)v3/*ְ^%'xP yFmִP,s|5y4{}J*a0 =MښS9(r<,T5m6Uft/ 9Sض_hCgbD)1 Ie.oqv{M_+O6BFؘn* VrdiZ!1CWT>Ε`Xlvh}YcQڴ-2 !xVf7/hԷsױL"9֐ MZ=@FS~X'@u3 $^KY7H-{\2A- q\b t= P9@%[* yDMNZ+ʟ65EC1,m+'Wb)| (L}SjܽPb >>jƁ WόAeA|oLEU[ûH*`ߠN!z Vp hGɬb9Do&NV9{ap :t` MtF |X+P ǯ!a]j:5 1 \(xw(oUDq{y!ҭIBk:\1bHOZZk0#v:?VZIT`MM:/;1zFг4s}Biri~8ܱtǭg;##rwkKA?jPkG;dtN}UX&W=4b O&fdR!b;=YF+&'glV`~i1&]N+AfC0t;G?Il/mZ2Υ#. ǮYmBɞ/MdsVB \9߆ }˯Xhqy.;*]b}..n~*GLabY?GƲ y9%}~7)E/1uϐ1 \:bpa\fDt)0O`4Q e&Rz&xNi3M!f Q{]J}9>Vk!JΪ-ɧ޵"|vQGM7ے.,l߻FgY<6BNT|1&0Pz\of/>=yPQ-ow3{a} 5E I Bl=QQ[]\'D͒n~<0SR#̇pɄq2Qbہ0{֙F+ <@ Ufwl3,oz ϼ3O-X:Vt [<%iȹmm(A`r'P~<ܝFNo|3nALZI>4Vvr=!(7'b&W|Iuɗy%k[ ,Kxbh$z~mNu``Ė!1Ϳι/ Fm/ɷaTZaփdWۙݹ+,SpMAڂX}hBv|f8ZО$;DGAD ;u3@R˄U (73UlW$UKΤŷ|׏#J?ĕ} gTLljKuj)#`b}؁ 0-/yVT])qBZ'csXw [M[4KG❲L*deDGob}"ա>yIJ ԇKR5-)T,y'a|kfb>)9GEP:eIyy.X"sd(e}_ G͝DtuD|30$Ap%xI&γF`rQsTg arq.Ƽ*YUש!KNBE+AurpUlRK?#9T/il@+g.֎IN}9M\4g׶ b>pDª ^Y 0ڣ=׍G˒؏ DMPVa25gó!PȜLݸc D뭯7WD@B sozwmnN&u\wi2" 㘤,"/(&0rlDZ>$pP:.0^G*4t \D؋7wQc;䐬8`/B@ʆf6 +oagMx?q`3qß>41^%G,acI\ ;B%͐SດU)w3Oi }nhy|d#wTDLA>H19?{m:,q{a fuJLv gXuoqGɴ =7"1i#z&\|\{JILNqC?*sX=O*tkB)FN8=Vj"q )rKwpKldޱfBɹ#9k9'a9`-:Qf'NC"ߦUw[l|([(:[L, [Y(-5NxP&FZS{yFt^/u9TOhS %  &2őrym 0W7 .+XEcI kD[[͆+r'LltS҂8zkͮb]3a8u 糡ĩ\Z zlcF?-_j[,q>˭w>t_m63": ɵ?Q0gֲ&/ev}Җ}3[t[vzO-l7Z6E'ߊ ĀP ͖&ҏ j &Ͼ$ Z2BnS+`R9?gA9`ƳOa<n6x!>+Y wPW%{ F XI@Oca%kF%:uqCD$o! h/5;7-v2Q*_8+&ˁx'ZifKV2 OMz N} igLID!i fҼId Z{'KNf8B/ Xd |-J rϱaP^bv}$m(Z}Yc}M@xqD 1N!f1Uy `)R΁ o̽:A\?BN˙CƏNEchl#Y(W1ˮNAQeT΋(wQxNy;9¥f-E^A4ygAh`D `@J=v~ zL*sM9/*_ﻖӡYDry<pBQ!`j1W_z+LQ *UT"!zBцd:rʱ1R1)AUSw6$۳rDڭmňz?wAd]4Më5A{,9ܙ BS .Q [Ǣ/ɌǞ~+-^hkBܺpI ˼]xr(SGGǯh 9Aus=7&r-w_)m<[I4ҁ2/Z9ܛe>Ǝ7Bd8vRjqL3ԨJ?Nz)kWjqgLCya"UC0l@Jo*ghBhrl}#PHBwxD.,qxW㲢QjyYj>*hbf0o{D`tKNsf|5Eh$)ܡtw)z榒/r3JҹOd5&Tϖ ޱ[MYaCW+~x>_: *lg8bkaԾU=_DJM-oW!*-_GKL`Ђp@+9pH 'R0+*Z{TyS%?y:q" a]>+Prܗ]fEUNji\Mi1d Tft2JvGߡ>3~\e& \ 0>BT "''BnBXԚ!g~D5Ƒ/"& :nMZlXJ4ⒼoFIv~HѪ,CI۝k$6.2j@9:P1vpm+r2+Je?jCXK<ۼl__%Ä mp#O3葶OYvˤT-[Lxfݎ.$5UztHjpe Bh2uB$/{"-{e#ĖYZB:"M- UO$U3c(ߓQ۹clip58RUta \Eeaxf .gX ;< ̺e\3aޕ uamoj ,C%n!ܦf+2쾟\+o}9偊4;#3yfIr&6Щ v{ʽ m* 9dhȊp pŮuQ-*Ng.*ʃn⋗!jIv~Ar%N F C_d`ނMO2=6Mb-}hHX?)m&巪J]ivXQil@.dN@cXҜW2YZX/t`e ]]?Q$2BU?ȗK7i*^G$v\|!CWJ}l/MӎZ S3@3/" opq#JkOz+y< L9 FSʳ1wX~<)n.ؽ8S)PpB׎&%S0>X 88.g'*ۡ {TлΖyO4z {l³UV~ۆ ޳V |EbJ,Ԍ&vTσ%UVL|a}Cty_;Eއh,^b=tC2/|t+γ¤*6H}s4ufnT*yHH;#O꽷"jh.X$̔Z&qmcٟ硘L{ugZWlqd$VudUh}V8ZkZΔ(^#xCg5GcR8W+nfkX'^ӻT`mܼ7RiHRY򗻶$ڜvHN1B|˄KO=[RU(34rӞj|hLc J`S">`vq GhF\6(&al fi$-y~וSgon?RpZkqQwiGhcl1 }ɹc˴Np|W\.z zULDQ `@ȉؾ ;ks^g]og[Cò eXm)AdÕN23U.{¢Ey(ŠM@PQ^ +q%%14R/[OlQdb7"dA¢Z56Y r:lY52ƥ75?Z8)؆ٞ[@cE迆ʖl!9e3.ry "t|uO.K#ђ3y"uڝX#v?;BL/SI Q5CHt\cބMcEQꐮ]WVR0)idc~]9.ƳpO}YO V gӡƈl#ۨ#8l YjXQ##MM^Wo D[t)7g}Ƕ<to@HZ=x'8VT@/;KO@I8,݌8N Vwdj[u 0~>;ߦ@?,D&B:'=0t_K1r,`"*Pl]ivۃ \fD]\eP,NX|UofV~+X} 6xzc}++[7agoÒcO>[v3E4/biv1SÌa'f`F82'HTZٙb Bơqʨ3U'HZ}MTaWܹ]>|ڎBި) T.%~:#r"&ճAf}uOs45˫*QдAE1kb:Pb_ 1󺈮eP)j2*HlRbL㈅ K+R޸1 '*pZܯs(u-fF0!7c^aNEh{GX22%s8< H'+GCuOǚ}d6kB塲@ԜDHra` k/ +c'Yhl#y_Ou-ćg%'@ϗо Ixk]"Mc-@zL%-H \k5DuѨe(Y߲8҇F>ӷ kO1T`gDK}kJnsE]8c?D)!z! Jٻ=gY&c8O櫰hv(rẼ[I/\V 6AvAޙ>H5hL-M3M4h(3Gxd0ٗNLO?@%s҃AU{vq!I M6,jZL*땕aa#Ik>rddשcc%TQl*[e ވo16 ^UyY\b?{Ï {[G*OO\n1zt*[E("fTRiQ98O:F&onzɏlg#r*1>zb6="wA *['3LH= >:f"p(U#`i-|K%8 _r hЪ5#8uFegLtvDZ;Y*(KbXqB\]1^M֎k $C1Pmh.'1@4uhPoXŶ1ʺ'Ubͩc/`4tǴ17{W:Fa1יh`OOW;&U[M_4_[$^qҝ v`m@EZ>*}=] 6S 1?Ӷ'fznS˓ ZrO0sv~{zʫb 31!^GI6^Ý$pVZGޥssY tLP`ux9}s%w0?Y=L9+v!QwNWiKt'w _@ .J\SrvCK "Zj”uER\*R[En94ڮedʨر)(TRDN~D +Se4Q #T:: o[Wp$K"9)LFzI*8E${ҌSw()\7EHmORAEW|Ɖ׀zO"t0_^O nZLad>">sw[`| TzlS-٘}I_Nml$eb"0AC{eSM${Ԑ`M@/oUtڕK(ʊ礗@̤a (x˗aJ2ݽ_Wbiwܫ"zMdCl$ )re3Zd*`i̅avO7Z"cs>}r;rOtfF_#1_&BI bE8גUA =dVo}<~b{fބ! $BI %)̸a0:eiFi+eOT`aJN/?KZ'mnMX~7d=eMO:$#mGmpK_ D,#(멵Nh$PZ6/wʐjXswɋ*NbkÍwst{[xƼ^YM^]~&K?%!],JN4ID*zCQfl d-2BL,4j]sXzau[)x gfv6hNJeҏbS,Na WZڤ} 4{J-.3NUq7U6+J^Hj61f _cX$w̱٠}X "Z@qfE ٞzS^)#~{^smz=/nȘN Wx>^ d$i;wz.<Lݩ8% 4>Ϝ(o3׎ bO7ma颂\\#6Rdz85?k_038Զ, Ų FvX2',^ ,g),{\)I]J? JKVk ś0#;|{gϥT>tvHw`uka7pu@)y"q|w'CIJFE~z 8CF8/RCXUnGJqY܂˲AF9v-g3$_ӫ1"<6e"_h)8!jR.Wr.$ۻ#̦,jiwzGXv,B")2eQ3+wTUF1$;" n@X+QhT. 'j_WWy(Uʐ,ߏ2̄qڮn߄J.rjRD[Z<|K!52tFj>MM:~U47?#v0CB7\/./8pg9` tQUi*r"\RDtD\d_"VJEI(Зy ѕS<3%|7Web^™o ˳,) ~6 ͤ. Z+As >jzz*?8ώqy{ BvOTT|]뺾~CiG\@2wD$.ohÕu//v >|AwC`RpYl_#' |U[nm nѤ6K}& EPՅQꝲ4za&]$zs^}[D 墐T'|rkh̛9Moa_-s˜rpYa)Y Csjϡ?< !#xCZO^Y@^_(ˮE |~KCr1g}O " N3i#n[G-Ր"ִ$؄Rb7i!3¤jt@8Md2޳#KGDa_re Ïϭy5t75形a# %COrf[pa힛Ϳcɂ |ǎƊ-\ Asf 76dnƠͳ'V79IvND "4Z,w8Jǹ)mN&m#i%c4 U6T5. S G{dz$˩1drNJ$:4\{*8C OTEབྷ/y|H-?:]<Dnֶ!{?cqKW|!a)st ͅj@DaVk0 +i?BW9)԰!C%I7B%ytȀ 8BTDOʜ. ҒI%>_ULh[9^@Rf[x ʽCtV9vy:uN9墳۽FqlJ$+)`zۭfTmG'KsԄkvo1 m9jG:ΈPoQu8)%EDgQ'¤>o;ˉڜWsO[20'Q;xPI'g}*3*VSM3OCgmE䫥6PI9HhSLojU*3,IJ'nj??3;@!bWw?,Qb'^®6(JF늺|vVRUk{1 Ȱ͢et-1{4p (Tnh)vS B3SC|b*)g}˿vwHvGrۛ Մ ?P;_HsY,HY`鬄sQ[XrH" f/O1d+-@s93k9>E}WPۛf\J׷J!RoKPy)\ G-ׄ Ġ.LX 1` oaM/BӺ5O/D(?x^5m>!(ͯ1$B8%;H3sĖ2&uMw#__f1R @q͜|0iAr8y a ӫx1>|.Oܤ[:4>q7kW\Bu9Һ5`DQ?dđCAF7]tUY5*.J-SU' nrU{!E>::)j#Y}FD6׹hXjXg*X6\NfNPpHT/i`asؤ6-ACCU"#tD\ tꏠپ ;lF gEhH/? 5vf~gL8 8ZWVNtFͣݙ,Il H59*GFVᾋ/g\Uu_k|c7>j3#!g t9峤l+NѠm=6[y oTd=@Rۛyl'D {h}*i/ jv,!ԈRVEs.( e: u&u\i4YV3 ,!m]<w͞Fb\} \B8'OّxusuZvF4ryQ##]/c#64(-]Uar- 7KbZ;N- XkOcK\cnV49]kHlnZZ)߬0Z;8 DyM6tWaS7j(e> B^.IBkQ5U s9x)lxO9 1"0lvCJ>OWWxk Zr3&&ǿx|ʑ9p;p-~KИ>B7[$LtnM+Q8~~ {*-hС_:Wxg;DCd,ʊot\֡ZL[ Q@^EI 7` *HJm}/+yޚ&NB5cu 5m$ N|^Ղ-eg%UhBirwj6Ϗ+o0c䱔q m3yo:-N̴iݴђNO<ɍ)޺fdV(Wc>gX ElFk0!ް}losZ&H#8`($3 cQAyw6s?w,сKpj|"Z 0t:dOt&g<[-m  21΄qx8 +/ OR`R/@ľQx޸6tk ܕebKʚX"ةyZ¦ "Jt\1G3:̣R*GщX`YcF:sO\RO{:!NZhKJά=mB Y^1>gP,j S ~kt޶Sӿ(lp g5|?Ne]'JLY.GC_Њjfw"ґʕ0)dyV\V 炐?IQ 5Kw>)~~P7%}}zgŠfޏ1s!㘛,B5!e ] #L!CU'hOQgӌxt\E.[`Sz 3xs°!4~ft?[]a H3Ӿ#'>ݕ @N9WeG ؚ̪m^v9'l@ c&mÊF* DN4õ/x1% F*\#+ dn\f;ܮt3}c|a|Q )Orr(0w*/^\>*sw"9]y,-Z8tUGR=H;k ;rvYk";jcE`j2a>m*7wNXpSRRJ7Vu3 ј'J+vOp'II.c'$UCDj!ҕ`:>.^^f4ȟzU9AЂΕx.ӪkGD4~fca3axl#v_ M݀dɻ)s; 3S hD^ \8b*GaIvwSH>/8A0P>5~$= Jp\NKT^<GN! YD\?b/X)dM{i#bG^Xмs'$Zt1A'E\ u'|+PJA$e.|%<.чQm2be'\"ҒS ޓ`>9I6Řk/V?܉nE~_<;}srS Fp)f8u5K^](FGDd GI`+sfoG#Mfq.Ugc2;TzBEyk蚲|waaDdnrW"D}dpYwzԻhh\N5D w4,CѶ`:M fH$_jle8&{LAX1e03_= !KxTwc?YdPY>WwKTE>g"<'C:IO6T T2Gt5C̡ $Lf g:y 3Ud Yls`J:GKx\;%`>$)V&QC!lCQWQob lIۅ "QٻFIs7X'8\\{PPpvnN rŘ[ ^["*$X}p";NwܨL=cEl ߩQ@ `Œ0mi/<[|O]ERL\Kġu s!dܱ9J C*1,QǸ;Jaf9M:gCHþB os!frGUs4i L,Ruoc֞YFNxb ^޲ڪ212dZgbtBge~. rCf3 8lK}pgnByݻ, Bb!c)S$2wr{(Òwp~Mk&,4((3Q~] G[h,p~C#,[Db,"Y]22'P¬\su-Y&+.-_Xᴔd]'弋)#@_4y γ'E6L@fT"`ltsB#nnٺj{XDH'!ϠeSG%3sdw )&:Fl~žNp<{ca@xF$^i@|{țAY u&\we *EƁZu+j|p/'RW OXD+ΑU!+,z:LSDQH އD |AdwcY ӂco$EX'h0)ny&zGLEx,9읔+8M?PnqהH:c]1PR_vM4e)q_s54h:Mj݅q|?6P!(͞C=R[ ~H}p쎓3q9dRu;YjRKZqRC:Bb5ȝ_XkvIjm~H-udJ!Ig˺bW/.4؆вBDt9jrng-2IТ2cD::m7ܫ 4O=yv+1-"pL`]+мP4 M ,3I a[ayn: 4 JMJ Is{*) : 1j$z 7]73j.GlG{ENފC] l/gssq'i8ALYO%Yeߑn@FLz̋|_5Ue 8HѼKpZ}I岮U7LAqAwtbTWW'|ܜP7zh96ɻjBb;{Y"R#[wsKi/2,/BWq??mqyX>@ܬSG{YI0d95x Lgc}CC]vkx\"n޽wtfh+>|%*/%'" 0}C ?SB Pwx#q# ~y$|2GMډKxM_VQ|F3 Z"~A.l cpdgہ"?5?ou~܆6^1II[}K&B8K"Єwd+If2jqt3.PMuM$(bX GYW|ӶC!aČ&OFzNnytaHNeVFżH,%0'UC7ou%êXrM9 TƚXKucEXR E>؅~Rg.f[?cN9,cDtݫrQwkfJ)I4ꑫq?r}Npc(/s}jOfB;R⭷}-:a/"Q+Yg%FN1ʞF{f8H62A0ja_*gW(Umy7Uek~tV ?ݏń+ieSՐ%дVim; #7`NУt.A 74#e Μ&drkx`Y V~Pi)O!(xl 㑑:]|YɮISeݣqB%k76~$: 430LL6/(0pwVa2D\j6Vp-)D2'˼5kӅ.9 S;sΩ)z k<Yv˛PVÉP7^*DM0 _0vWi7 ӁHj\XCH=*PrRۂ38PӿBC7O.HtRr 'uf%Z??ɍ^4)`]"w3`S^8&܅GT23i!CrJJ[~嵐+kpvPw&LC]3?~\j^BH)$ߗv&vXt~_Q>Iz_=AW(ƣ|V+6{'/b u#ǥxT vi}3G:ZƖvW#@B}cyKK諽u OZsaqR賞z )mkH pFO!=^(bR83"p "iQ\6&yFq`jO^ t14Ac둧bbU._-=+]y?Sh<soƦ.Aζ1(m+Frs|k$ZYMbi? U DtN :wWZ+cih/жܫ E0t7 X!UjJ#*3!Ն;kDXG j0̈́FW\7z$eHln `\},ZǾcLа*f+UZ0CWG{u(Dx@~ a!$|y~֓?"trBakVp\Bk^+!q^cwJH"auG=sׂ @Wr2ɉ -XYb[$7p:biIu>w-F8%CK-KRF*hǠD=W~ iD yޫ1Nd\.J0$&$Z@#'\"ձWwVHW=ucQMZr$L53/%d:{2 xj}n8xuL_կ1qdM85@O^@@YCєyL"-m8ی~ylX\}WוS6*xU-&{6;aaG8(w+-^Ąg":1e>mglz }@qVVm7r{#cK/6  V:;ڟx)lG k ::؛rjR YB=pβz[鉢CTހdѬP16`+x0%7wwM~0>6.BlK8R"nЫ{u,Imz%5~Ji6 2%g;y&d^k͉gT 5M 'Tk]Sh3gQ[q^UyμAAాVhu&, FK}w-,]㕫EIsᯆYdl虑] mTGz~ѣc=`l @ Kc"ǼRj[RםbLOs Ŝ'@ |&}pFJ/h^6lV;UV-D&5 Z.t$q6 }" 7<"Cm T/e{***La }֥ 8ñr_.i ,.pKxOa0B; #&G6ba*`B>b~_GwNTͶ*_&;)e@4X~+m{}aVk/njz"]#Wo#0NxI5D?LJbe:dvG2v}B'6ED7kq3lhGJݘ)P|a"C|>(;ϋLȌG:H~I=3v>&KԘ_4ȳ.c5nk6`Pzocg cE}zm GRFa+o羔U\ S!o:%.^ w5(Rb@/z^[q_dL,Arcڛl(* FuCil TO&ʠ9ٞ5PxWV{dzQX_Q I9 EVF ʜZo_ ({]t$ =܁ ;eg0'3R06~GV$^bM\@i|gO9?7+l %2ڹS˖ Z5zZV_Ux]?6!Q/*kq^͎?Bj ~%%D Q.}%?yYv}! 3'+Ut1p1f,0-K>ϕ"<>9K!o NDo9Lʐ7״'E_GK>X_à胀 ¨ e `*Yu֏#̤ous'?9i=+FKsT$/*l6bxXkmRlyٛ X2  ^)K^,PuǩbYI1 D[U)< rߠcݎWX-zCJN=r*tѝIOz}݊|2a5m N|:(rFYElz+? BSwUMMSpfJ`2)i]8kˮ05v&Zځ/ Hr?N @c Wh.qQF^6 1_9*e/kfmHͽGDB;ַz9KO]WohXpcO~mڃl6rw?Yxke|p d$'u^G`2' ؞ TO5WF]%gx(\O>KD)#xJ<"ʭ4fU3"9OP0O5I qU  0¨WLml-"*YԦKvVӄLY)4q4 )Lك2c>2ro_0:-đD9g1``Mf̸CT>gjbъ} Xz^O@Z.mk#o‘׈"IOP 1]kϙh.S\\{ O3 <5k3X{ܢ?'8xmUM+Tk8݅5TOUY9b>ۑX.(@VƏ uDHdTY#v1Yczw-VDVd; cxq=.jP,qG[vךW:x HˇsZҬgc|]:y޼6),)/m- DL,vNik278i,5[z-i1S";!8QE_dYL\vã}?Sj')N} @oߛ?X߶koaI(KTN|6Eh8& Mi̱Ķy%`l8'J)mo{6E7ˡ QVu9>zj>`+&MhCsgl8/'_0mncOZeJn46fhqia&Uy"1i%yrnKiimids_ncVm^F*=2n@%? &tH0un@E_,c2tl\M Oe#*~TxdBd:%ale:@ͺ Jc.iW7P5Z;$XISWןbyȏv4p7Ry~ Ʊt`~|@I7x.jݮ?.o{u5@*)78G LCY(HI-1;E t]aMu `bN~E @8h=|LJ!p1RhM֨3d_B[ /"V[Y̓ae1Re.&z5 "m^nj_k{HG(elCύ^p4[ f_( /ĵkbS)H >܈6x!6:3Zw> {𷴘x~[5W&âFrjyWqCs +$oq{cV*'`l_pG]dvV6t#AEcoIpET P >UH4zkZ2%AkmhQ_{ZNd7+|"zA`TDB*8{]OfyDai9waIAxJ:,įY}Кф]XS{#MywbM[lU:(_!Us^l}El'lS̢R?DCa8 ң/Ztʈʈ.zXMairjK'{ÎN^-> H79TtS;GV*ȱaHWP+7tf)A 'fukao-(҉Qk@iGrŇԚE nջD\kTRSwRXM8xmq}s?BWf 4{TG a趴5y;=6䱴}LڬP4@b|>뒠5DA5~tA㲹MO:|C |16ppfJ0z.$ZXߘ@]m 7@a/RVn-qs_WdH;5ڬk6s98`1e.8rE6n~[!p'KC'4s8vξQJG-Zbiɒ Kxcx]6A`kzs{ D',G0` E ՘ b % aPór-2/K6C? ;CܻOgP@r~4k%W[{Rñ0Am.,:)RЊkjk&y~8mqym[gnRq{KM|t#2FAOف+EWOw՛ڰs:*Yw B9X3 bg/?",;2q*#04C/*GɡP+V~%ؗ<#*{ [mZNv W;it)>rPk& p]m6ϊCb\/~f^Kc )d_im!qM"+[-3EMh'Sx*#& /|wɚ->r@~B> vT9pNӔM Ĭav:Tc1(M{Dtԡw%$3l0"#2l,NU0< m|hK~=H;(Zpns ^2_И؄j_Eph esWӒ*py+  !:滘ʝaf~ܞF5hѩ d(a7os ƥ86oZb ?F _GA|!Xh;i9>;mY0*q;buCU0B9%lG $cPiym +l0Zi?-b39:?f!CH+ʾeTLZWϠJ)%XN\cpWth9$kPZYS@#'v^ M< ֗ޒN5MT/`r?6 X7No6D['E & _=Ǥv[Jdyj,1Al)?}Yu]e&&@nt09ao|rӟоF^`RV6 zA~]07oɓ&+|I~Wӷ C#(}\-dck8`k/f[90NQXi2B3Gs({&->u׾*ףG<(nZvPԀ3|_bĶ u]5^&qlҭؑG69D[d w]sVbZ aŖyKgj()E~4cUU 9́|fRr fLRӀe謉 ]d'-zxyr~ܹV~R:OPU(iL2S_-ATKl87\[=:p;G)XR[FQYpϖ7P&ٿW>̒|{ Z*W {CVD9tvfgM=9P47[ },*H:/'UEZ(o-ZJD|x7CZa|EJz[ 联ί!sS͓r)M( ~yg7sRٚwnm ebP)tr832d- j>CoVOARS&߬~W{\gZG̦i$ơ6l_f( ͛ZTC MD2iWȯ-8omHc$T$,Z"ˁ=~P:$+DSs1&uFWPV!C `־6mpH?t NˈQepR`rf^i Oom{ziOH6Ltf9{!l~0P0FX諞hgU,FRB ]-=G/g}m8,*,6^8'Y$v)ĹGS-+}gx،*pbdB߹ydCS#P'v'ƛk?^~ѯ8.q+R`Ko_y7\F!MaF9j^j>cm4Yޑ p Dwְ5Cj݈PbZ"<CxV=OٺKbڠ\惟UD؀eLzCSe?6zmg oiOc[޹[K68"EdisV3:T1S!7e|ypR 7wfJaIc>VU8 O9\IY,FH8YpΎކ՗fȎln.*Pa ~lEm4zM_sY|83]e+kK?YL]Thn_+ibacLqg]Kq|2μz}Rk@>'%7DS蚱/ |Gz (2@#:Q //6BI~ jҌF*{?Bnp"Z 2ciDSl75(,(Se QuYGa̵Wx )__Tn'pVX]xw&{U2z \>fh;Rc~;3-po`1A2P/[">a'ź%U7Cpj4֚4Y;z=Wd$iN*9**ӳfj1(z\vrZm~ݺ3DSlq}G 'W^_0bS6!oXa 4rf ;",c7v9L u{A2sҗ<*)7O)PbI tAZt^cs,jr K󛂴r5ejJEB#[;->SuoquW0rȤX;/^pZ6 jȅ.NsBSA/+x<du(g;OmuWe9= 9vg[XqT*9Hh9Kt1Y OrBрЪVXΑׇ:o}1(Z=j$YDlQ;uB>!q3QUT2[h_W_b.d͡i\mͯ8]ϰ]ftG!HߢW iAmqMvu N/~I+Nb[w}LNqj#mE nئow.50B,o@H%mzXEg։ Dzݒ[&'е.JɩEX)ab$H^ְ& 4}Q?_E=4IwgKhXhi;кӘWx9R Ҏ.Va$J+62^ԧI5M~}6}ٜdMz1gT3t]f%[߫-S|ˉE')ӳ&L@dԁtG.$n)JJCwd]gs(kҮODCgoŇ^lХ%Mx-Bj_N3%=0(fMH2wyk#ȱ-YfRNin/8֙EqqAvjçk|7:3QN[+ӯ=JvLFiS r?ii9'~B)RB<&6Lém, RQCoY$:%{p7yp! P-eCI+P^ D >'!rnINpƋmt <^> 3Yk(b2 ե~P*ehҬ$ o EYl[)'%/y'O#SgM/@l&=UDrdD:%^2>~=5}YTw$%i~ŚYBEX3nBN1OeͼY uw'dф G ʌW-0GJcxIfpd OZWO9(>gZ8Ee@qnN£#*BfKEuu}1vRuK=m`84A nFYp8$7kOyM#$?#m"']!U'ʫI|_R#l~Qt͸X]wCS|u-ܽQg0DQi\ ll3μKϾF5+t 䚭< QPco֐a^^dy/?E:d҉%öi>yX,R26_ɞ`M)a&>.O*OkFYP<@FwוNd bRK]hVHo+vĸABzѿ'߼\>Y/eԀ\^}Iz~cV<#uw1Oe[q=#WcQjڋ/1,O]Rzt2(CkUrd]{lԎKj>j2&k'i릭˽ݪrNq5BVv2KDLȆ"۔Tl$BS6C{8Q@cı7'l+KL ]I8TwdBHwck<7"f Nw߆Lf͉ ary ǁW|7 [5 PUX3Ǫl3)֨08Q!ZDT$E}Iٹ̭6#\p}Ĩ*6Zž^G!-w΄ ܧŒRN ]Lܰrnt ^?K68Ա# y8 2 {}pp#0CI7!PDBj,Zq(zpn¢׉8pQ(ed>X2Г' <`ɝjNӮ:Cl=uM;e* ~qPv _mߏAV",-qYr'm:jCH]~R @ڽ~YAV-Ciaˑ^nHa'˹k쑋_,Ɉ߈g,])-~i|~o,9ʣo̢s2z)˜SDF$E i.ق{!ujD/fGKRhKd߶=!z;L 6ClTaӕ# NS\hOè |MibFd%/`}*g "2֬^=:%u&~,TQؕU23ļYHrB]smʏ ը!՞#^!yw Hm=Ϸv'%RuS];)>fz#}(%r}VD닩uyދH >J,, @x̭E 3nt!X%!z GQm"P"կ- y;EϹS"ߢ{Xi((݁c>%UTSrN \K))(=e=,I~I*P0ߣza 12<WKZkzhC>iTC 0 /\Tpޞ?ـ ~ @Lk FR<N=9o?\+$!ĥ}6$  ݲD2(V{mIy5 Rn g Fkn{0_S^=9<5W%n8m3zͱHi7 㤮Y8v,[h&1︴q7kl ET6]1@B`4)U;bS muݖN;9~p1<Z+m"c}kn6!(ݓD}WZ$OmSCJL55݄qy*, |̀D-V}fdqQ .EF*'';]g)gl؝%J=RYk("XhY@G1XD ο,Pb[qItJaARIV$/̍g_?ųs-is!8"M`EhMy8o/>Ac |H2_|$W96'ۯ*O3~n} ?ý| wccG^@-g^igɖXzf3 ,PU}VkIgRd #tTnݓ>ƍ5G(aqn f-l pyrGZX0Ǭ2 {5_'Bݫ0LqNiR8#g&kYY2`4%Qs|쬿B"AcGCV|M$^3@6^: ņZxYL3q!"vGPЩA<oE ?i:,NJ9: O%W=ze>kiѵVVP\#gҵ =Sz"V]J;O%ܭ̳7Jd}52wйdXY{Nt,1]UHMԃ&%+l69tWUARG!{mY>RsP:bvP&%([X5As߰3\["Ϋ#'c&,@jPFeL)pXӮҳET:CjDŽ|%:= )Qo4j/_ũEx1qd5,8&C@[ R)b"8eϮAm<?D 6 sqfI#u`C^#<6 VMWCźXM'ڨ>'VZI-?t"6.0 ?c+ ?j(F[ݶr+KT .SayQIHmhVp.N2g:ոWڔvbW$! w[}=e+tr!\ :<PتX{zA/'" ϩ*~$NYŸEIfinq iLXs76/A5X$3r<"ˎ8|G,5T1䚈H86 B&ႆ,ZjQ`!@'H`7CTa~WIDfg&WdgLŋQ= rKNzϾY>yC3;rHC[*[=MPA5FcQ Ͻyk@-4]gUg7y*(QH8<"Na}3q+"f#+m G9XFYOxoy.-Dim9NYpNg$KuU9^^VHG U[-!ڇ!-O)bC\W-Za5ݎJ;B?05iAS}AN it2M 7y@RK靮;{'%^ٱW<&b -#Bc{ ަ,U_tgKD1^Fp[Qhn%w\ԽS{5#ݏ.amm 4dX5[b-dlˈF[U7 =f%IRvg )&m_=|ݫ"Od[W0 i&N 2oչ-2vZJKߋYNNSqCODrBU$$ f&3He,0*qB?n:(ESN _LsYu]͟xgU>ʜY uÝ㼠e!HqShs:u1R-ayjoMw[r4@ԔQnQƨebzAX]q;SRQM*PнMГ8<4ӥ+Pt? pԃ&:sTwRJH*(v+9ʩXQ.}8Ǎ|gǰwQ3O– fbimJӗ 6[7y黍]W,Э,_<Ch~^m`L? Ė`o: ^-d߼Ni6v# $YT=n(ڮu=qqMS*+fʰQRK&I󗕣 fij+3TP6s@CDuޑs^p}K4X^#/3#ⷣwHrPl2]'A?uq9lq<&Cex,SvsUK;B@'a$@u5Ӫ:E/*@[=cr￴"٢q:lzB[@0T08ATHhLͣO&"F?ibsN/8D$yGt2?B~r4P>:7UI~oik߁/cQ%t5N1*FP%Lg,/uakx<#zjn HvêLƽK`7WaßYiqt$X4ydv^p}rn,{{EO\i$8~VIO;%*3T \64u0 .Pz'7abc!Yf'_x}]>)MVVCf*LF>A1ʵ`! Zd#EʹX`TXw:̢Y݅geHRnsCѣ]zLG,Ed>4_}y N>TWŊB[V!-""-cӬhUHFJ%ˣӟh_}{yhW8nݰJpe:-''<]=e.o6COYmo3?GDf3W9A)X2,sPtˢ-u´ͪ%Fw QYVႅuŞ!pZCWݰ#;߁yfQ+?+uQ3rz_ÚMmIu3VD(}dLAe7;k866??|ˤfh?7m 5,`{ȗZ9>Hr̲yHAOM׋&f ZrJ#pHq SJH(8D̯}"v_)\`-7YP6M5$DL"?+2{B>!C,Nӳ%mRQ;P'7w%'hF"|n1}|V·xPΌPx}ҦF^JWQTI_-1Y,¶n䊖u-cUS/&*4275ϻxH|zD?NYقn\i0$8Bvx8@_솶m%f?7'24Z|В \gu8\#< *]sGVZc[]n;gV6i,y\OH3+Be1dm}L¼< i}J1ߑ/qYU."#m{q'f[ dUpĐAqڽƇ0лAr@W9ohc^" bz8K] 1w9Pګ4+0G]wh}17XZ|p7gtZ ,>pEZ,fVUi펈{Ģ)v/a]bx.IN0G;S]7h6xkFr+LQʑIg+e֍W QK_V]|nЕeb"Љ`Ь 0w:㥵5n~f1$P/-(Ntlp10^vM7>xnCˤI/fVɌ7,P *ꤰuߙ mϢ&'2 `Izf?rsy+ &xD;4UP'zנҫѸ+^)5BeR@3 980mʑÓ.jP {7Q#Vk\s9dB%\;Os (:jȉI`W6?@\;<~q KL~p>{ں56[}xܣUEEܑ影"VԽɈkWyk]MxA?Q8 3ȋ$#݄j"m!w ` gJŘUQz RдkM{h3l;| y J@;]eeS\i\cp,c23ѳo$~賛)@BYMk/+ #~ծ=|,[ AʉLt>XMs<>0XЁ-DzO^l^c;e_iGqWNP-хw͂OV7) [hK=NourÒWY'mB}Ա6> ZBci}nέ.SӶv!FrJ!ͳZrlئz1Jfx^$8o0~w w_:PR̟Q $^MRxa6XqCwr'cC7_`K^%SuÚ's䡩.8g@89"EIf{Zn ? \O+7y8ݖ6) ʁ~fۄ9Ia f(O^Vz|x\3ևև%5aRqZnlM3;M&8t\QKZ|PazA%b \L5:KQ!E T6p]bqoљd$sJtl^'QZZ@ +>s $OF,v~w _Cn\Un Q ]p9Q"nH:^@[8T-.,NRE.A`/x9r]=>Gg$ *052|jnǑw5Up֜IY#z]-Hp0C^te:&o\\/m:04C6OCYMkm^Pqge\,0PRިA=K3,&"#`һ+_@o JLMkTdEuaFy;ˬrw9]Y}GOTqd"_լw^kE`/aPWM Ⱦ!:oLj7%(YSQ sm- 5 \@i*q[V>-zB?"o:VR ?jlNzңNy-\)ZWgv4)2|xa^ CU1ݬh0S;y <1X%r+]rJ/Yd 8l$ENud u0a \j)An1+Tbȑq19{'߳'<\&YyD3N0fk;<]g*o.Sħ }-a-o밷>\=ƞVhУ\3q5Tt,F8I YMhGsёՄf} 0 H9룯!IAJlFs ר-cSJᡇ5qxBR'ǁf$ݼDq-d3.'6j:B/Z7HX ;mSbh/kX܄͍\e_DShM^JpJJ88#t>(&35{c]Z+w 'C,!+g+ aAgMwL@ v`Bm: U(q4Jhcuk:f.ʮv-gM.H'#X)QZ|ySo-qL-^#}5Q3!BǫDx6S:DW{ sߜ`UًLfg=)Is>+ny$2$脀8S((djsQZLGu͑xbs^z"G|}gvX0'9ņVյ (]}A7y%;^J9Oj. f ^$QOLW؂`aEHTG 1QV <ش'ɝM+"Sr os()vz;+ÄP0P!&9BdGp:o^#/Au >h7߻Ci4`@.ØT!Y{D:V#to%Z Lqń-kU7/x[ˆK;v]2gK~i-=W%# kϞ7=_I-$O_!(n"{P-Zx#/%?r:aL|vtͼgX/0v̈R>Q!*jMƇ9JK=GV)~/}T1ϻgMCpS98*4{mvvL?z]}H/bL"iš>i@5]"gJo%s ?PkfZa[騿TC僚&g*'f96nv4*^Ne (Qlq2B%pΖ ziX!s[!W"xZ"縡8pԒfpm򆡯M)ʖ⨧S=fFTfvSf&~]l`sMAvy|t*Rۜ:X YCl]S=!6݉宫cd]W>RU};IW(t~/h&E\eDS!I_)S뚽| #2Gพo&Y Y2;/y?8b;(@ˈ=N)׹xY_%qE]VqG\d*f eUG5'OS6IBrMCƮ} |_k@i A>%~*d,`7 bۛ~2GcHgv]LՂg(t.}NJޚęF:VSֈp:nv^-P}Zt%O*&rnQv C4O}ԪoȈpc0>{5-? LDx:w}R㻇Tao.+ flc׏&Sn-[5.M-;^z7tpiip}!q[ h͓* kUۀ*簑t-EȜ;D"*A1nf.2RB8O""ܞp~̦flsZٳSo[IyP<'Ͱ;X`SI}~>{C̈́Lq̚^g `waҲTYO^))0qDeﰿB/yf`ଫׄ&Qާrth JVAjfXꫲ)]>V` b5'y-_; bWtY;N^K,BÁxȣ)r0+nm,A!ȹ#P]}/c38ϛ9 }6ةeL2yyN~ÉU )|cv/tpQ's6A0ح][!FS9F;O|4q 1> JOgb r~u L <=M:P94 TCۢ;Q/U–y@@; Zia59*d)ﮗaQ)X&N m$- 9D4|z6O6%n'%nA&l݉OW~%y-yƲ@IPoUz۝y3셕E>WD=ӨAݠi1kr,QQqMC`ͫ3e`[NλP6dӴ:@0LKx~}=Ec9S\pEtR47΁AsqFOvjfZLD |RE)P'^^B*d<^Pe6[pU`˷]D6R`~ʚO"O@w:E˿c v`H\Tiɤ;BtHp oHc-aK 7LP:yu|u/uQ ;LEV/8 e3Vxim15ؠ_tN9X]o9Ѓ>eƔTERrzcȀ͜x0CxOX;[c! 0.u;ăk NiF¶4s_J~Y~^x5r#{f6B ń!})A:' y{Ko-Ɲx޺R\~W}zH6cl!dWU8)}5yW3^E;lDX$d^Ӿ5s pȤ GϞ yPR8,EF[dMZx@R" aa^,ptJ{S~wŶe=.'k Ĥhtm%}nbrr^4_4`K4:2Rm@N@ib2*wuQQ2uRK՛N@}G-R:8a^$B]Ċ<㶓Ւ +@!J"K} *ͻ ݤBNeUFg45E@>Q]3UuE/sھ(?tm_˅SMTGruU XckM(cVm!GZ[ΐq--l14zbjbmTAoVY![ߝf0 )z\ Ez]6"8(KPIs@ r!8EdA2qX?3rhYW'8mdJ /8eN{MuM;F >#?_É01*_!=1hݤZ%Mm%/NbTbZj{_ XP=;Tf!짦VfBhy$:+IJKo:PTwm",5֐:6ՓAn]wJw7ⰫQNٔN&dkgWڼSp(vT8Lc?"ưk8/K}9cr*=P!Ï΋T3xԂ6a&f0\ *4&ps|hh#Z=,v=J8hb}.Bv Ad 49-rx^6O@&NXxēt}}Wg8! ^rݕKq5}f̭?V^!nCZV*nT\c@m^[ȴG55 YvTSsahř5>Ђsbg1MD.¢_G1I#]b̛wpj BH5|!B;3ldq~Zj7*95ԛUo y Oҟ4uzShxwaaSȗdFڼIW"$EdyFp[(~$ %lCHBfgFL h=73q/ew&bY:1F @r I%FpD9<`T^{IJr!Z31X k9-4KNu$z?\Y-ڶnOe?BOE%f(ՠ'}alU#0p}wN D_DIR<8k( xiZaц *xDY^"0F⥨/UؓhoS%DU"ˇjƒ,;,T_yd3GKZp,#mϲp"P!>Ks޴WP~fITe K`n\9>~LQsem\޴.Nq??ǧ0&k f8$nid1V:c^DBMxM.3?hkP֮۳N٩+: 5K=0 Ii X'۰5P+wQKg8p6g|M1(A4re oxP57J^$U?AwLɮ*DAq.LbҺ`8kcGLA>j "մ X <~g&оdظܙ_>?sr<0TpȷuUwbJ_Eg+%;WA+ Qg3Fw74HPl X˕G `h e t[kUdݽ=2Y,{`U\ zQPD;83D:bG*Hzz+NAvyTrE]B̬UUNpY@پ(]&b1r}"OLi"ՀPDѽi;˰UxvC`\!KNn*UyjN}RT/O?2+|3<<++ -g05T&k{KPTz_6c/u'9~2|Hg 2:~l*wUaWdT,qV=Ja|)S-3JUЁsE*F .}ZX$Gu.>8 зa[?pC]doh˨<= F$XxN3;j(QrRK\Gfz,rBvB\NάV`bNRLFh ~*ֿӊ=5@"#p΀hI2TvE1hAYT(x'1bTՀgxuyBk>>EXŽ03{a]0{u_ϬNptᶁ$X^c/z'Dkn$C4[1 9긾q]bOX|S6墩& yJTFL(6ƨ po*ܣ}y#i,9o\GsL&[T% -W)(j+Zi5^#T۝X8sa@\!^y80{Ae~:/(!khSD')-mB[l!?nfjZ7ɨJA=p4s:*yP7h">'; n߂TϿ%yB1aB2nV6~1kBVLeaLI VLEOO+яaJ-H@+oq#Rl=)l %Nƣmps{LLjX"!ss ?|S4òhy*w= ,r )SqPU&K@ul&CșID^ znG>@*vF 0M&cMiC2d3(y!^*F89ٳ!36EAHM=SmLA$JWDΰIv9Zl\C Q'JXfqzóz/*9x@ܼ c4E(|#N܌=v&+ 71-Ev,RWLiFxh},jT_rn.Q"{7 { <#N '"NM&=Qj|x 2&BYQnɳ8`5V~6 \̡e~_phLnN}'iiģ2M:zrN~?cC('Unk/kܝj`n^O0wߖfY#lNgw/A/eC5Gv<+Sk:_=A$#7<%HTMaPb1YNt/Q \ކ9# Yh XeoAջB];?arG!5 B߫iɛn&KV ]8XDE^8Al1SzօM&N1y3ՑX<oLQk#ܼx͊5i+({ǼўkXPg ˂pzyoV}IJj[]ܻ'UrH1jhVؠ~.eOfIuĬ$ކ̵bJ^zSddE#kH"xQ!-WN:, gH$w*+d0X̙U٢)(\+UFrYBSf;jN"mߢXҠsЏĵ |}oٚ$  *& oXUVЌq?kE VXjZb`Ձ;,Yo]Vm0C20OERMuC,kS6\ev=.|mHf%Wp7>C͚Mu)z\2j092'ookM&(llnwF I3 gCwMVj;0x8)D`-AeT5%0˅sWFg83Rk:BEk/p*Ñ*`Du}=`󃋆jfInMqS{\YBv{VA!IwrƦsi:"M{RH^ GSy8@!JQ5AhCzNEM ;.[8PA͕q|~ mz4b{ʸur ۱d{Y솅a*nϝu4+?ϪmY0@&j_K UHy%엑p2S@Ǖ-MbBL *] t](OQ|maԕ>X{}妤3j;gRڮf՝dw$c> Qg$>\5]y$Tjb;9t2G=%cn`|rv#/ߡe)>g#9w뗾@þ) P~r}=遼dSsb j+:RQa sƎ1ȭ {r{04`Fv’)Asi(ycRs/uˆiCuDV:DRWy2`k!ϿY9*xިwC9,@wvcXC}!%Jׂ>ֽv QIvݛ\[yr02Qg/$ MgU "h~CGr')☢5c*q5B|w-g{SIffں*IuI(׶:H л*?(#⭷bm<@4sŽMhuА"8ϹcRX;`+Fp=~zC %esNI(J%*3p/b櫾pM3tY@BqLOĒ1-=xF`ʫ߉7B'n9wq\/wjܪK;VQjH_XtDoJ..jhܴF)u>Xca4a?ߍ(zO8ND ,#yk8i44CzEBL0KP [;͟QȏBdyS l"i?mu|,`_v*yi\5zs:Q4@sJ~4wa:e|-KqL C6)M-"/:9EU" {l៶*A| gL6c+{{UC[cWTԙ-6`@c'?=螷E#s9qڙڝKdP ӿ2 dh X֊a}ZؚQR ,>#4 iʊ /TД}dy,HqNpc^oDfnUwU'ڤ/P]41s"kڷ,#ok4zCSv8(Ϸ%fʥWi8*LG!^˂?>f?ޔoI G%@UŰVN=Y#.uatOg1 ߔeS0u ${M S{XZqix<**%rțU?|a4`~Uܹ6yʐk_P^Iv.dD:^*h3c|e)eq-%s561h., ¼+7s> ùObARu`*Wecё[5Ej5nb4 5x~\s,u([ x7/7;3n -$~7L~x}{"LRԯ$9YGߏtclג,Uߙ~CΑިmwy7xBB@bHT 7q>2kˣݥ5dh2?}c V%JVl VfG rk}-p}XǜO  9јttXa^+sF̪!gp]$W0g &~DM *gKnь&2IeQ7$Ƿ:g%eSEWET^:M |d&_ʽFCoC,r 8?tצA+ds-p}Aa\;]0'-h4 d͢/*n@dJMTI[|s:]h/U?(gs93T"N)JU->f$n b필Jf3L]-h[?q+}{~E[qY1#V\>]؍9!peI({(,REdG Zhッ0Z L]oWߜf96q| XV ocDڜǢqC#_ 9i;BYlt70S@-=홓'r:V`BHK oiMxڏ$TLjneN#˸˿T\\K3>X.c2Њ{KHcė:mEueǟϖQ:7HDϺ:!puaHnwl1IN]f@MV|i'ʇ'HO|Qٛ^swYV:XtWfu){s}Z)w[FM^mD勱l #m4Q i&{uW+Y7h.] Y&G3FrXc]@=6.,|QŸfC(AM>>a; aNM|+{bΦ{(r'KU0&/$(B7Ue#?"0= v(S5MQi)}R1t<a>9R=l_mvGob^,GXUMּA7( O$uH0g}^"Vљ;.ml/yR,FL@}MKSǙJY5?0ԭuZ4ƭ!̨C- nhr"(Vx.!܀FrjYE=JHXqL \R>6UTĒdMXG8R=FgCW$QyzPT,^4;s7.tYtgxM,bȚ/`|H' >RՆ FM I f_hJwfƔFXGJ9e6 >-p ŭJ"&V_Wvb;<9&τg݇Imo5AO!q.U&6 @˚)c(S,,-Z##'1vJ[&[ba쀩$k0xb&JRMa`8!'J(ۨ8ѭJ'NWhZBMK9@,{ʟ e|'6ljbXCݕ'P7j_6UiA?1ph]מv 9ơ?NsGt]`e A=]$N>Q^_A)I\z܌&­kB}d,@%TtH.ߪ!0xҷ{6 ϓ~*~ xW|#(GI7xE3PĨ$w ,>GCGYh;BIHzJf櫠Z^},:"L +}"إrZq 5,N[NE=0JFpBMuu|(iˡj,!zUSyNUpl:\]~׋Y' QnJI2 ;PT@ -61g7*27UBuqd% 6'ouuA~r%pakLҽᤇxoڴrFĿwqd'ѹ橖yLgo_$UoT0^M7/Ј$e_KE v ~$dW+8-Y8`(uFn7;{Z82~:8x>~DMJzlkwZ0`.2YSՔ=I!&vZ{|S8סt3".{"ly~W65!+aL+K\q*=<Cu2ߏ)1*>OMJJ6 MZ.}N=`Srǁb%|Eb岯 [FU72hzZVbSk{$J*ht] @0v/aT_̲}.Dxc ){om9',7&C!e]~3!ိ_E,HWLUیwнC@]@P:%o@QgMj߼,P W+%$+B+G"0sMPmZ>5JGXvIø%wQx178N ޅBo.\ Zv`H8Ɍ)蕙"كco|ڏz3/I3)Ň%6\x\>wE>t Jqn$;L*R)峥ׇ< hՇYXF`LͲQN/hDvze[U79g'L=U Z3cA<ݲn91VJr{It bCMH|WɭdKNuU[ɓ#zsOg4`"uQPp GZ&SfVmpGCE'&1 P?p 9<Х'Jtךk/.Ksoy0̳?hNs\xmԭi{@˞\\PvGóS9jS uk\{/1\K6!:֜hF,u*~(=$"'tφh)t.38qĥȡ0CPbR's#{,r'FݩM7s&y<׌)sO8Uq,^"^D N̗x7tFn\dV.HA-br);j [!/3Ԇǽ̈SN-hTu e^mgM9Ms_6ON* 6U$K)H>d\-&wW|aɁ?bGJ^W$1Ok&\vYJԣ :N( XMqj$bk+ex2z~5 AdIQV>f#_nCћ+٦vyPYV1Yي[u {ٮy% F߹pHлDZϻaeg{IHujMV1w7o=M$ 8q+4f@֌@ y~^zrMrZ59;lNz#ڐ4w}4M$,)Q{s`MͥIeMƀʑ4$M^?$TA A1w#Hsa2Ȧ,<̞K띐<$R*aYB*V' up%="$b疊7j"v0< Ҹ b34JgYLdHM*}4 eaem e|ѯTmP# jyf[sA{ůe_d1D@&PwB`xhpW^`K3RQ1mtGqDx7d`5DUoL)4.O,'92ȨQ 9㬔 <4:IY!Ў|OmӶO?=zL"Xu \+9 M->l?G1JO˜|tv.gYƚ-p{YdtWc\^;96B.G:9%eQr̕7Go^?3nDKUi1K< pX1P 9ea[;SFǣz Rԫwwz 3q@^w~v̄-%w? OSGzGCX>lp`Z,j=ETHأ4W L<V<#$՟bX;\#%z07 a" -AcblCΘQE}ؘ*VҚlۘޝ4d]eKtu7K;gܽ:>FA֣'CmY.ǜC15m $+Kc@:%v23'B܏u SǼ4a:~b*)]}'Bךzkpn̅۶~NA"R`g%Zr lبHmC~JYCraϲr^p4&\h^BFdNV'$ĥѣCD#D ;MO9R~Bi OL^/8{vYoeKv?`h=ZXJ]O\ #u!/}01SA^ !4qЬT_9sꛒ*v+ZO\^ĽNt>ZQ|;]n6?0~E;zKD]!$gUu(ܨ9 j`ܚy 2&dWo+iKoE\`.iHSt?;*2XrDDxz*:IQ,uEcx6dLyd͸#/TUh-@LX (wc-{]dxgڤ @Fs V=TFm9 Mk̷҅y7匲TOuѷiR 6 [͘Ӫ œNܥ]L|z&߹*!hŰNRibQl+RMX"%opKN8MބдVa+i(0jBc{>p~4,$I)Xi5̛믏]xv᷀X4t)s\V!dpw`FqkF@5n`Ȍvy U:֍=u+WY  %8;QU{IWs 6~.Z[[yHMpওy]U&Ђ):fI%;, >K{BC3Uc Wv/J]" <_UX`&sI'`B j3ByElֿ~OXYMlɧW.oy"c^!ܿ"Ӷ i81a򈲶CfS9ٶ)h#B˜Zx31lTLƔ~'lqҬP97آ_c_w!l:]% U*ѽj7RRtBgwgw0E+d"g>ťG+3{ p庖йm2g17CW)0`ɘҗySHlop/jhlG!I`R~OA{W?ϋ6_ujqxd{5%``M6FG$7?5yNTm;vS}8F?,sz f5/b|“1#۫=3kwFMmNwN1*1|?] G}O& x{L폘DΟq(A|u@Uھv98K=FϽQ,">kZ<ق- HUz7xqxVfQ[uEÃ^d/ ƭ SxNE#~`jME%rRRoOL9-wøRbVsVm&{cIeq61N<ס9mX2EXIZBaPy(?!k0akn׍;desycYEtQ|]b!!fEx̃-sh)6MƇ5 hHwīU+ɵ .4ѣj:) _wd|ÇPÈ~^N>/G:ͬ+y/W5p,71{T74Tމl x:9!/*/7 QM^ aQ99;zꆔ!^|I+j7q3EK-bn]!Ut!D\ktxA,$O+ {7-<#/1$8Zg]\Ĥ.kRV:i1]~%m5JƓ,Nd^K?1.\-FHڄW3J&Κ]EPŸDI84\g|C:A­AWUB`0<4+R#cTDX#urs1&}/}56[\NQ!$,2:c.3[f#AEuQlڗeߦB %ms@x [Ą5MSd[0YV_PȜ<Y&c4hɗ2` v/NkSL#AR>!q o ~l?.j.;bn/idѼ?CvcrzGA{wk&@$Fg*XWJL+'H=o8VEW^nEt!n׎ݣ`"'&"K0GGSO,1:E^hJVb?y$ ySM\&44ZOuc1jaMK! >ܢd wWV)+,IlIʬ/I# :jp.NŪ+ןHUEfڜ X63_wZ{`>?roI˘}bcy'("H#LvذEfc)㍪w^ZbDڲY 優nŠrG2 F;TO ؤ*]˵h%U]'ʸ3$L|wG*,ls t6wk'`#ڲ Onͳ }ח2_ q"dM#xuc_hZJJ9PԶX ̗>!ezIE+ꨮ(si%T1pY~41HS_7@׵sgH`/4*7l]cr^'--M-x"dN:OzOOn²`N9rVcqj $0M_kXL8a"BbnZ!'Js W{9QQU< qtJ k)(#E؎pӜb3ṽ6]y'.7pPWu6Po:Z(W9)\mu"8ĤBXmXZGew'[<6 kF!"P&xP_ˑ}1\:v9ad&Xd v tr p:~Mk6(EOvI.G㹪r A(G/ vڳxz(*n8)k:ϩ6' \6e.-E[.f63NZhw܇:hq0l/p ;b׎teڍОirm0L\W7+p6+oΫ/>,ykSkQC|d(P ^yuR unId A}+]YeL)G'R52}*Hn@+ه&/O FΚY@yYȼSlPb0:8_ o8z~/+ӥ?Dzc ]Df_5-"?raS ռ]ɪ>?S+$y3\|h!p1At>Ayã!IDR=ު\fi5Ԣsqٸ/C#zH "44#M9Zc=#xa.&X^Jqg0I^z0ƚ8250^u E0;|y9y؜8,94xy8k NmĸKz2N+V =\aE*[7MW,D?Ky@AyKb(u Ø1=Dn83.!BEss_gE ^j>av2|hQHfe_PJW&0t7$s1VgQ߈y#z.2G=q ,+١DƓEgM0$5Llp lN/6lJЎIk^iy%)7Lfvb!;T۬`M얹y|T*‰ D VJbj1*WɽRƄv%Kկ*2ƉKI^ )N-IJ=iGz"V6Iē̆P~i(AL#SH.s/m ZO!킽~/޳Nއ4 ZN7}5Xdk}4<{m-h5R4WM~*g8?Rjz2Hz?_Ru>nih4hmU/~p: Ym~<轌EǪ !k;\s4+bNwmˀSZNdp& v,㧁,6'yFoݎvZ+3"ʘ#4^Yxrg||֞7x+h&b(IJm(ut7]IVREd2Sፈ#,c'G ?`5ܝ568FGdwy]Xۭ(R>ܔ d/6V ޟhBeo UT5D \ɹۍ$'E>. qHG xC.Est]2j-\/`bD wM#g o"!̲۟0L& dJ(l z1I2R!(U%FIWZ2S+A̽oj}23.vKmJ8I+K)P\)#]V1諱,RL)< l"}>c~}V\%v^ZY8VFb:t1岍6Zۨ8 H:Aؚ+ZnW"huԸyф%w ʼnÈScڪ#Y+(5ZpUҷ&q!$_Gj ig{72^iPBZ[XO HGDzfCEmLiL4lܚڕTɓ/-w"b3p@ rb"aSԘDw |!A RerBd%dhLiI,b猦]x#u6<8Lw`ƌ/5m_؉;кV3q ItS)Jh++;Wo^#ve{ ފSB['q[?`7:R XQ|9'A4gOd`pUh4a]LWF˄?0E|`贑e%l}$m[`J>GzgW&jD!5cNgZ35Ob^7@GŊkwΫDnؒ{pۿj=g5% g]qPzijyPH)A(>௭RPcĜ$j}D]aR18*eYʷ q]Fϔj{\, 2HN#X/夐At!>ng$UKv <- \c 徛 MmBM]%ˠ^¿g=o/@1׆%JK}puF 28|#\OS :1ȋ.i|o@@Ii@$-3gHk?ej4q<j*f "'s@4mx/"p$ƫ]=Sp{yr>$阬zBdeSx'QrP 3 Um޳$xj_!<uC-@OBl9|܅T[HAB/3Q D(5-WPRlkf /Pk 0v&aUca]*›ܾhd#J_h2Z'9wVm T%(6)Ȝuz\94JXu i .Gj%|Pi7!ihVn36>yo5z(d&ɺDfSiڃu^gqEC뵺rk@~ُi?NM[ZW\І,^ZwXb-.NE[Qp9O:K >:o5GJo o?v [A6AC:ܿNtv?W@r#AKC~0iSXLnYr7i!†9AIoYt}24 ?T1HkV:} $H*Tn{=AڒdP`H[E~dKEV>~LjHbn~M@)GH Em|KGe=fn ]ӕmuH:+摜i:]MY*FފqڼKZ8g:q{z󕅱q?{6T}j30҄մ#޽`z tO^ \4~w^J1z\S@/.t@첁u䏳 _3^V1}kUP,IYמ(ov8JlAߎۼȶ0囱唠PWyoۣqB;P_կR2!<@#`P䒟D3ƹNkȐR鱛;0M*nB==lc!A¡VʹPt+<0h%! Rr17>rK}sGKYm,p_l)A{b`#;nZ ~UM4Q}Rޭu F?;U^7 yJí'm݄ba O)ͧjq"ɼSgRZݞu3YBRSzV1g>n]Jd{#Mŝ2_|nFr$:f/1t/7SEͭ[C:{Tuď TRg:Рߵ*GGrzOpnuf`6U;4b7pwԋ4r9Ѐ8xlAq}77HnNn8ŵR~ oK>Bv$iiOJ6ӹnv#^ٖ?C/ӸC 7Y2]O,sv:eI. h`FVw/{ܫcGi.I` @ 0h]>$EC,JmJɭɰAcmeH3y^])~RD_d ƸfY9KKuZ X5!N#%-3 deyN@<b}+sJ2u}m`o>+w!~6Ob;8CP"@kX0n@;2lQ,'^4cEa cVxږzzM_O@l! nw<ٍB.*=axP_^͏&Y P`rqM 5KzWNbʻZp{1Z Kug §e  &KoOCk>^?;a&qr(}?A7 1P:u\j Xo/XĆE'sj\䑶FG15^D+U|r?d ó`s*ܺl?ʌK}1?͋FyQm<^)5..ͧ*ВDi_:j!q?^}Ⴤb.3fz2 T/0rx\Cnx+DtӾ,P<Qc1E7TA| -om~BLcKcB޸#m6Ĵ]k^L }|԰=)شĝoLgiWK {,&7EFo{Q~ǠNHO5zk(Aэ~;}yυW&r9w_H8#1j^>= )IqUU)''Q"uKhQl0{G9j%B:ӟ\!e e> ncM+ΥKR %&R}I8=%M" f)C qY%/[l`A hЗz])Hg j3I yj@N&2 PЂZW n tH1HT uJ&!?Du >LJj9I`Ņ|}Ƭ!`#{3 p16|155 Lh(Π*sHY OT%%Yq@}}c%f !LO#d=܄}v(jP|v1r4cYßO|ߣ:]b+5yjDQ䌍-LGU'1L0fk'a85qCr8{"\y qP$+OorOp퇙p7cukS (g;F;(RUHmj1_!\_ήnA'aQ*G|2q_2Þtl &Yodk̿AE,r W\t3i15!f*5um5nXJ7!꒢Rּd%ba|e.ⵉwqөo7 ivArE׸I.ENvġ(3SO"pcKHm/ēfG4b49 %81G"Cy<]}1#@EV]2$X.ʝ<[*z?#I`od8Vγ-rQ6u*"ש}ӐPaZzb4'fIJ[Zu2bi!L RV ;eaZylxBw?"kwoKr7춼ln(s:䴂]#S(料YVGg/*$ކނyOm֧? >HcME@AFa_de9qe< EePR`d?s"^NH ԣm7?c<Ƥ_9ːr8h>}ͭC{GSS?.Ŋ񉾐`=NI.Ӎ5a2R2`XYT,ߵXt\A7ƫB8@8}ONtȫm >/_;m5.{?ϒ!֓'TEќ\l`V>xt[ ؄F޳S0vsy[#cէC:tmnqe$<3FI L|XŤkD &w/hn,AK^i @R.V(lD"G|Y!,~V@_ tr轡Y!yd+lsgаr6{m8-}JO~yjw5jdƛ3缔G)$8demR) g12ɱ(itg1+yC{ʔCJ# z.Hݏls>`RAFyO_=ᗸjXמ$$yz:g `Jiu` tTC[C*Gx{ 9?=pV ~.O@[ga9{Ku^67>o'XaKLIXUjׅEЊTeχ iy U.Jj޶*O 2M/$z3KlnN,?Qlb'Ωp^3%m SAԦCP#tçyW[-7?gv>w̑n#zU/ޯr_Ȟ̲K't=T?mG;b|ԣpU('~u1;qeM>Il0Ō/9p0ѲREL+[!X3 _f'&Y`*? @owKYL͏pG@?%W["UR4.Ti\HUɼ+Ez֓d !d|"2(HZgʼnYiq:)`& Z?[Dj@doWG5UE%;J[F00qP̼lLⅴFJƌ 0vKTd$V.A+wi,7uok~g~1hہr$6J#&-NaVp3:q{ocRw9+#1"~Pq#讑 5d!q+ʊƏU&bO<*Ogrd= vpJ|gb =KK()wyPχ@4fw68@9\P-[iDI6Bz FX^x|˵%yþ-:o- m>p&!b%|{6{6!qI"얘 J9 K2,R@[M.0%8NqO84P׾(zTS5~+ ^#~I3] KOr/0pЅ#whvG'5ڒ&!_;j\c`6$wO1?:5Ъ}TwTw'Glbp ˩jD ȉOPD{H82y+1|p-)54yګQزt_l_N^`8@6&'v 7Ns&`N*lAܸ ðG1n G! D6hX-[ULhyO3 :vFRrM]69:hgȧ`jHu`ńY_xih'Ghi67VQCvҭKq@jl5c_^Cby5Fk|vX],5,G"3!i+5 6š!eiճppE /ѣ W忍V?E6l9lAJZ֐yoCױ (jBsRxnwtm c(s^֚suLtOCZGT8 a y~r$y0i B$cED42l>5fopC8MϚ2nkl,כJ"Yu¹HE*c/ʐ`1)ߺL;G?~aQALڰV c$?p'_:ʄcl= [+h aSVD|euXX*ķҜ\K,E~0y7@~qS?mªGw)*M(!iM҆7^5aU& !J&uv bI ilQ;˖c 1|z|ikʦmq7VzgoX%q~6>YpK:( X 1J5h8vq ᫮LꌽAɥ*D%,}|4{@9\˭"-ҋ4/0Pԥ[w%oUYDb4 ٳ 4b_Z:캨9#y)]Կ `,~snW0P>TbgG 1X;G%Cuk#$O%'nY ڛ'vgvrC l +9CȽ~syz^j-_ئʕCnxa$xU8ӈALûRI=BXHByM Mf 0mEc^G[Pe@91oQc[i{=ޖ>*fSGʷLh(+WDoH/n0W;I"W THEY߇萳 *zƐ kVCDA^S d(d -Gswt:, Ba^qذ|![LZ{F4{ݗ``?*|h+)a#4~\20A t0c>gǮK2z2[=1'x^|2;K%cL8* 8MŚ"C,d$X텼 T횲qOM[[qߊV&9ByI̠j܂7J΢e[2S!^WHug܂o]MXדBNQbE`ð3,,1Ғ#u@jyl^5 lu3f2k} 0N d4ES=ۜZU W*go9#+"{R8l70QTO^0L$=]-(GJo%j `RUm7}*g:{ȉ:;N<H}ؒiQtObB.]adEUD: n>XO4Ņv %lѪJUT\\^F:x(W Ȇ4Op {9N04$WC̶[Bhb%q.."YV{x5F!>W|݊òG0[4 ͜Ű6^윩P/?Dz6jbŋw38x* X(3)D3+G] C~_ &MGʪn u@BiEޕN"tM|[fst~6S9Vjvү=o!FDӴӁeb1,ð$ U}m "a So \m²8EkKM[D_ ^xqAgHNRR۝:5x' $ubNGN"zh +lD»yGzt0 z \|bM6ܫYc:K (qQܚ~g}{f&!נ#ǀYS6)=Њ'FnZ_u](Nէ5&O ;5 (.R3 +izo]FM$]%"wY[!0~~:mˆ]\}Tff{̜Kj5t3oCcR|KON J>|Ė휑 z\W,NV=Τ-JbDa1˅5۞߁f8$XC cR'mPNy5=&Is)=*$A[[쫏${B]~OV:/ㅱFF*2o/,6m ߍ!c@v#}DHnOo:>o#ǑY ˕%;O1>B|},摶/t]W'p| ;OpKn˶~J)'=(HT6$C~w k0FUľgFR;n҇y܍3W%]ܣMUPL%޸1DHF<>sUͮMBr`f}SCkar1 F${?*SDWJ)#" { |"F^7oX3_wZ2Oo+zsL5OfR/644r*|K@+f2ZlW%k9)W\2"평Ԑcr!JQ̲T&y!.KP !%-o$#{ª'g JU/8o" .N[«GѺV1l3\RD͗çѓ7đRMJw楤KouXVoo[w k1z) 2ڊZrJSKL;՝ hԤg7qe<@ZLxU`2˝Lje&Jwa6`(bPL [w :{( AfREbցc$~~2yB/<-ePt\ͱlK˱#<.ImP.f߅b*{ xNEn({2|otYWŘ?=ϮGL[l2H6a[Wdnàg\|4uLqs=LKO^^|r hEN3$)O*w أعsFPA},Б?[I6N2t Y\m'uv PkPON^4ł{Yؕ $fl2-笛 рYa.X1ܗ!M*L_jHĶ4ܑkUy dXidiRpok|fC%63JY=)^%QsDi=iޛII1(Y{Ǿ7Vu&j[ވBLnT뗀{u"-;#62; `Kŕt4̜//3Ys"E&mit-3# PPwW =.@DJ*kFMF=61dl@/P}b  cu7?,6NoGm` J@+eCc>S% u3v)DTPՑEQ%s)*Z{XGh;̯CRl^~:SR SdlįJTәr@&Fpgx_Ox/]Vɫj|M}\V'oBCަMI9XQ_8lPܯ$?։چay?&Na$1>h*7P~p?_١BZ[s9Ƌį%9a}<.BYU.T=Mbl,[\/aS's608VΌKȝQUK9̎lнxO_#U+G^ TcYgML|1(`"+ o9çиΐj;;EH_2!؞@ͬp}4[SeZu؉)m'FWDsЮ,.SCs!{yw Ɠ*?|0~R~y|(8ɀS.L?ߌЏzM+ÝW$54rW-4Y jW~t!p/2eGe S"( ' ^: 4IcϭwE'ljfь)8]b/R,&5/A\6&-aڄ:=6gMʞ$#x@v|n G,c'BhuYOrH7&9nxAcJA{/J.r!j`ۧ3)RX*uA0Vx)raY]8.+p SY%ă1KpuXp7Fs0}_2^ :C.u} TmڱRwAR~j~=8xg`7*4eCds3!>a,@r1? (ʢi=loIP|x L3 B&I*[ؾ :\7#P;Y*w3RRΝ3k?>:G]ijJ/!(!.c n#f1'"sKa-^b96\EŎq,A91oijI agqًkqkXJ~ӕ8 u|EIǼFfe*e{_ضll%g?ʌhs}J/RWF~I4wZCncd!# 9}J>^&ؚZo.|d _سP鵏6KM>k>yʬ:BtgCTڊ' ./kXs/}"Y&2V9v_;< wN@[*jzZYDK+j?HycBNXԟ9SZM&icϸ7+l CtOvx,*w[ACS׷7c gu=[mN](N!p N=g̀}3[C>D*ȜςbKipyl1X  z69Myd:wPob kp3 HB }58Kfk6!R %0%yjP)'~vX*Kb[!4!ay:S\ ;qr(e^?Q씙ma_ݎ~̾2 ]:64=q8P5`UJ%J)3qeMT 6#DV}Xؑ姘jJeIJ4ə2E jRI7mB]WnH5fwp{ _QubhZ#eTVDnğ#¾IwnC.AsZY%o.^ !\̊c!AXdۆ'7o #5-|Dt`lB76- i[;1ҺS][o) N&M@)*Mիc CH'cIYqcXؾ!:+,UބBQLJ|ӶRR{i-^̔}RIy\vΨO 1HaVc6韪DķANN_ ^ #&%M']#>@ZYV~N;ڸ SY@4"`£v)HT6wM&t\l-AY s-{g$dH deu!]_ŭpL}ɛ]ZDzeY*!z.P/x!gՊ fı0"_ It']f*ٍo:\h hbZ]DasVUcԓ4XY{R:e:Nk59|πU|#lUURϙ" vE8dmBf%|q|%۲'_ dQ]݁3Ib25g%zS>ؑ$$iCW Vԁd/D10>WK[?QFV d [:Cǘ4K1Ut(Cq M چsL!=tzSVIMIpdqwOXX ;"=rx0)(_#q07!VXD+6ZgX}D8HGe}bݐ!\g>^ 3.I2`\n L]>@t0c."ӈx3/nb{]a!~m,\31scL׷ث2|.$N]"B *X2dBla^ ZgjN nK|t]9Wr7Cً0,Y[PU[pP.SbX}Qk4sFRʌ,?uXMn&]H2 he`B Βc|m^E-h,g}š.E9bǍ;uHaih2 s&0]j+橋6-qC(cWܕchٛuېa@?/3H51|;y:?phh}3uZX.O/Tѻ">|iLׅ#<LZձBx7.^gꁁ0C.銢ڎkvq(z?[+F8EzģW w?R~Պ8.f%BŜm,fa>I87A@; TUצ3'IoYEY_Qafձ!-ܝu@QFM YuxC<pj$Nk#WPVd- v2D ;wip0ҶW2O~kN4Bx*FJ-,I?@:y/7*\dIx J͋hNuj!m)zSK SoV~VApdGI9,ж"d%ʇ,܎d]az VM]+pftqxgMKk؟'(bdHcwaؾ)ӻyp 2/ŴGE2F#ۆS/@"#F*&nFcgH7-jsʄ"Dë xDFow$QmHν^˜4n`m/ı2?=;FDrF7\q-E6cļDدt8;>IleIq"=o$%Zޏm^IZk xC>5N^Pp@ƭ)'34$ġvhЂv,6VMPh`}lOi ^m^bŶP N٧E (2 )jё|F,a^lqA86=!(4ic~b= eӑ =m+{L/##0祫 I룺gr!EiZ>*>C 66v9_Uf<_8 <'&rEf^ Jm'Du׆ Ԏ"`$o,7~8"d 4OaŖPɝc`zVp\y`i{]ܵbyj4X^b0 c^AR+䢵su]-ƌs > WqiDGf>q4C ģW`ȵzd|bZѶ?>Q5L0@NoՒ1>iIL;aEvyVl1=~nj1#.C.P$f#{ Y'Dbyf6$f#RBpf i0یgEt>#}Ed~znjBMunP1DZ#jfdWcORx'[w̙to[MP02!k Ԣ/J/VSoLTAC&LP85kJ̳$D )$˶㲭CK"s.6|ƀ<%$9eB$6<)`~?S ʱk9 "*Ҍ9[jjEHwMKS9t3CBMna(KdBc_ie4v{ 1:؅L -2b^.>VT,Z򬭻WLv.6;a [EO}SH֎K /?LDM.0 )Ȇ9aL y"͛69\1#؛=w𗩷y.$}1HW>g(o:Ba:/sй%SvEBp(>o +pFx&D GH6qCQ]WLD릳;`}9NcxB⻳"ͤ~n\83}A,|-ZD#4,aL]/-}?d%IoYj=I}-0G0^ru| GRTs#eG~2b+` W֬/JmqͲjHL00޼vSI**q՘BCCY)< =Af:Qf,kcluu-}>o٨"IDņIS|eʃ3J^l2QRh 젔ԗldLLp}[c{_ǎI=W0iWSDRדJ Ҧ|hu m>}kTԐ/ $+wy$ `$7| ^\8aJD2_Jy7l%;Oo<2$'G:#Y@q;qALF#.>j ^+ݻY(1ux ޑKԔ'E@Y‹4Rp8 kRRO a)r*ΑG] f_ӕT7$̔ (p%&!l v0SN#֧ eU*̤ ̦m3?o6,ڲ|bDp](Zdx+#w;E {ή}|+4S0O`pfS \6f>t`cSC2wb_zӉfVZNpb!irdj? D̺^~wJ=i ^csҧ?g—_V*asPo/rv(Tk 3K,=-| <)4_5kJn[f̋~qg/%$=."s7!A c͆5NHx#.SJ`\7=Z`,%i+T$#ijA=+ы4-*4q{=+öO1@x?$zIrdK^ Ldwp9ͻfZiK`xCѡ 9_{? ǃGlo6=.Y>Q[AR ,S!2h-ؚe,( j^^ق4Xy뵶=Du\@w"֗tܩZ-;dˡaw]a.EsIuה$B>V ~Y^&>`NuV9+Dm 2="-x9jeoEzw\} E0XKo&06=ON'3ס}4C((W]D_\87t)3fK޻Izʝ$uy] hf5i97x.xaTո<[2s C葿zZާҊyGe 7V~ "Mݙ9(+8fp=vяz U)%?Պ?\eJN5&ÈtFxxDA .%N`VW܅;p^ִy1DN-b~jÕHhMI/n Ȥ3mH U/}В- ;?eG҃s;59{k9˯C4Q~C97$P QkR+䠼\̘4 E'll۱EHcVyT lf=ҜvPDN>-S sA'kP1: ,Do]KDݵQ+_0JJf\!2mcRa*`|x ;ߝ0rnfIL>Z* !p>}R>>zȅ6E MZj!DXNȓ[wA;Ð]x bTkDJvzɿ-z4">sX@s*׎lcdxY֕ى+ip_ҞTTwU;oy`X>\ŎB" 푕>  l9wyM_ԺB*DsǾTCj.?ghf-?Mm\h= 9v@Cr4CD(|b$YXC-2mZoBOzE "c| W(T(ie6|~>NňJ cL\k*h\r,_& QQ1omW$Fz 1@o@aDfL䓶Tjv fcHƁWU(1k.<%#`J~luNka/:M< bVb:" `aAɵ:HG ?V ʵk|R2#rZ L+R/&eL,I`Ɨ4}Z>6ȫzLaƙ e6YSC,tD-?e@>hal\{P_ /$ыQ`xwse~R½\L9d[€|8L5ANR`@u{!rs.HE'h,RP[~St=/'L}U2`p˧}V.Ajzl;pd5A[@sDy? ?":@dk@q1dHv&D`@ڑz|pπs,WyyL8ӋX_[KzMSB54ɼS Y`Uk !bO,;_yys (;OL^T=> "N{m`y=fR7Q[Ov<}ON8˚<ڍM'TbH=}a#d8ĕ描aOŠ-9acH4HʐDUajRJaz֡b9\%ps \1x6 \k]ˮ_3ڠv9%w+n *Y*xkB6 2>(PUN0L΢ͫ9z}' y16Vkbη:py}sn/*y5wJa]i=Q I2`%cxdE(TA pE6w z3SXs`i6,i}{2we;NBNOGDus zi{$9#QId(bdso6V%ݚʏ4=gYL׿G7úMMk77I_|zM$zz]ݔ!ϡfvT' \AZF*uC:n,E_HM#$s`Fso)Bѫ.CW#Zf|dR!T6†^sT/r"Iq>_7?tsҠCYD4&o8wR2FLJXu i :.gaY%~|oL *Pg~_\oJXjqpGJ+ >DssR t`GN}*VDh5>o T6<9{STJ4 (fI A+?.7%Vfnc8[rb6Li3O!ˠ6R>&8džM#j$71m"9a= Ѫb육i}GWC$ɀ^ /5bL!in3Z{<{.YaJvlWaP|saĚT:HbZ1O/)` /a[.+6t9H8^U'W`4Heb[$ϴS%vs*Nknqy2n̪Q}4Z STMx2U݁Nd%uN7slvcfj.-S݊^\QwyGc[($7*"VH50+ej|"8Gf{Eu\ }3JŤ0n@Qo%\'1˩ڝ2Q?<#O}BbsaF_go?is H9Kba00=M=XH!SAS`yC޺ >EO>A'ҵ|:O!/_.Vj0ϸFEp?y0R)ܾEcZUG@/?hJ3HwzYo5$0&gc/ۄLu$餷_NA0v:.2*$UΫ:ZF ]*?ޛ=iNY:/>' IX .[#Zs u u~*<?n7&#&)c7HSh5g5GV}0#C>(5f&;ˠ.3Da O=d? 0}=UtMMğ@:ZwO`2/GHeOVMFYqs`UT 9ú,|^$Gh%!^ kp"K2ېo]۰kS~W G\?вAS'],_ѫh"/L6`™$ 4)@9TxB +LFnqCc_霁I8k,nI}åXⴡwhe9btLY6trVx;/jrZeDb2Ӳ M&|+"|px)8 DlUpGx?](\Jxadab^?e+L? ZT o݆{ Q'RTwJ VFuض²5s^6`yacyތ!o.%[8]D#CfbT񄢻a\a{[ DovwLY.{̼@ajJzZ22KGa?w a\'4B $Ԫ^"_TP1hap3P\wU?EsD)†46ħYg?4=cgUtox5byJAi06\ɰCi oc7/Zg+AjHզ㧻SD˘ꊘe}|V}ȿ1#0B+' t;) "@v Wg FU I{Ո@.N}71;˅ &Q:HܩC|3W{+B5ںgJbQS;O!˭djfWM{BK"ghL.[ڃqK|-ziua\t`OE!)*8F*b[::(WR 'gg~S!30z'MF&3wFuGͮlZCrVp$qyݚP.q_ގBM0xmD1G?$L\z/我gBq=y3d{enE==@ǃOn 0>N+n5M"rLacɬ/쫺 G6RV mCyHk*]A[.%EU 2gJS[r ݳ 4@f/Ue R|Kmb1-FzSj0&9?yeld|VcϱZUuy>O*XCm2J;#t֦,U߮.p5Y^&ncwQ맔 Y5|! hJ\G_-F阮kCN955:7:iFiLa>GnQϮ?4ZkkVw1g`W8 kކt߯]e+Ga٩Hy昩i^-+l{: J obAWV]%}O3 OvBgĊjA%sz$ᨖ4iV|{_>,- #' {B? Jy tW}_ch#h(!{;Z363mVop!W1@܄K\RS`Pu6넦H$) rRq(a};4bBNC8tgFtR ^&.O`7Hq\MfhYjUί}{k  ?5 W/S{Bᰊc3/-GPq 5W`ͫh@$sAu7H :IMٱ_Xs2XcB>lI0Rw{  ղTj->adIV[B-tM莐%=Cl!Ӿr6G @ͤ@0GK2YV5w\T -u9VFTDku+qMOe5?SWު#H?4ܸwQ&4wN'yI5K uMj[> w+ʯ?rxۘ>I&-ڑ YXuGfͶAҒL\;5`#G^}_5 s \z]v&49@禛ětRbndGSJY|>%oG(ʜg.ƺNnMAӒu([g۱xsO1'fa4Yc,qԞv.5] j'2L+RMA6 ! ,8͒RKqq)X݇{1H1f`VnhoB6dŶ~UЋU)&v͔` DIiFbn^[HL#":/}c`VMmrj.wPIEdFDH9fԺJ7X/L1[bHM-,)h:=<4sJpz E[rzBß*KV,2'JP.* b~+&uSxe 97ji^Hs̊#_h9څ}fJ !&xVpXU!-ғrE=M&$ QNa߾&zq np)l܃ؕm!pYgz<25PIWVÊHv HquJޢܬP*gVMI}WHX1r^m'Q"8o+Yh&:t.ekr 3FKͭ9m+GJ۰]B9z?mRZs =4u+$zLYН *H&ZD3@=&^Srsc Dpn[Lea7?|aDİdU06T߃fέSvH9Qg?`;lv /C84LڰѪ|8ӸT"# Hl,T+gi'Z)XAlƷ1*koM\Ĥip,G'o+WW M:β=˲Bp^.MtfTFiT]ﻐswcnEhF(kk+=wkوYnJJ'v{fFKg=!C? EFQqt3EB zP~[}Ӯi#e"Z^n$&}sE Q5jLGDR6k蕰oe4PZ%#A]~#}԰ͳcH䩕 8/[+01+K=0vs1X:cq%0u62>7݈k+1͎0{~uW#ζ9ڶm'm[zHwA~n2/^9F=HHQM f3daҪs2)LO]ep`iVpSV9gY{kQIͫ4@%u50I-8rlP<+2b74.OGH.k*P){[T] y/'"&{n)vGkS:flvG;?Q5 %HlP)QEkc6&gYϾ>jN%Ž2s?5L|q?5EenORPS`=4 rVηfBv8Q!ڝ#%=6r/b{h%d͗ -lts s)A *4g4݊ґMyX٤݌'/)deV@$/AF=ÄΩWkr<)ՠJBgk/=3h o>1BUeϯGQ׶kv`Z+ )}sVkD1Tln+8|M {vpֈ t[ ʧ:l-c8y#Y&rZ:q *^$,WA"&S ]/,>҆p}@[g/:YΞc@ k$YHC27Ģe۞M)V84&ᵉ+>9K?Hu?e@^f@{ !r˷~ƓE6SA͵<|8Hm.!"ԙ k,ІدD:P;􊞼3GAs ,B9}ΎJwIpwyًx沲q rߔGR{>~C9B#iIӪkXY =mф8GHBc-Ӹ=ThFWQʅ:2Pϋi =x LC`yQwxdg2t^pGӋ(/ ,NFp ծ9k^X!]gn$D|݋6B69+׈O! ZM\iP{չvI.G0W%:(%AIoRT(wZ<Τfq!/$ET?i4J.WHyAlVuŏn&jkqs&bg?'NL1q.a4 h$-#.S+zF}A$i0/$U?ST`RJ۹kl;!f;5]hLYΕRP\?s`5|31Bڹ N|>h'v/w\dTp>8thK_DtW93SS(8u`ʊS"Ϛvp"w1T2m1"(0RzT!4C@Jbr'y4:d.GbA5nco${Gqtov5UŠ./OmTm|ӊfų&dZ%36,`zɔY> 1 (0+,e,l Akv~]^˜c0m_Vq5Gd8^_bp^WS`1 > 1jl(tZejI \y7Ȑ'CΓ<+0:Y8{jn⣵W\eM(/ o68m#Er&(Gp7 &|L1ܚ, ӋRr,P4.7 4#97M9]^cr%"[T%R Gش75fxĒHdA0C?QU4}D7ҼnֵQ"<54*V ˷i tD$񂞏JNz |CQ0dC9SYkB5Lqʸ)6a`k$yK*tl3ʚb=+lJ 0&^cq J@d5Ү0znyJY_W~RݳipYcncw=p]q3OYj C.UPTfq\o6UXD  _ [k76+cOc)qB:x埃^8ͻVȊm`F-cjM;OɹTA=v+hiWy9ؒ%'$Ʒy Z*b#@~x|%|V0Sjvx?,tΥDw3]5vM9: EfdD8R2?{壇ytwe}vUXK4m[&~%n.m%OeL#٠ppumHsx2IJ4pC&3&~yy5ܴ]ybA dgYAW@X%qh6s5BlY^τj! Cm ~'I @tfA,h]%2{"ľt^63t,&h!필8cDy7(IkzEB)K,qeZY%"g/RHsZOaX܋P, }BB]PyI wx;J }AD΢`wZu"‚nxiD̮z>M((^z wf;@gƦi!gTbZQ vb? R73/HM n9xƱGueݳ &LV=R4kny ?3}#ʷCT4@4v}J$lI2ݏZ!C`AJEIOuUwa`_d}8HO&+zܹhʰIe쏹3\5&[ov٧z'i"'l[M.LxP .:}BKA|]⇉gM# fP6,wQAd0OQEƒ#N e};e#W#kfrnb.96,Z zL1-yfS9Y쀗䴱Q^Eo+Rۂ B"5@u|C1?|̛V5iW,qc!8\z{q+Cjp<+- qì)0\lB"C}(VصlY}?U zU+~-'cLlUrZ֪>w<\7^;"1L 1s*'idk8Vp89I6=e+N-:Kʬj*۔v2JpE%J:l=VTGO_ hD/i`A$i΍]mg =)h#.p-+$x?&ZR,=•בhCRszvi#jO$Cn5grc/gpPa#KR\s%@0-N¹ڞ;fei'`RHDIF2^6=ϒ rӎ8&23q"1;iFś:~PA#q}1ߖ,gSZY}$U81>@ =PHR9-::UV_Fa{2AdixLL'g7IB4Yq+T}CS/.1̓.gv+c?BSѦc\23g)FO3<F 2^ʖDph2Z=ԥF j=!p‰M 2U#gEqDXF:ICX 0:kt˨~?bHNoW~z܉kGl'6܁ZT-X$ʽ;Y\)^2m2d#l0@:<\xr cP㈙ k 3UYfQ|tnr:k[֢Q=/6]{gC o- @FX).C/,kKn0f]4h5ŶΛI5Ȯ`cPVqDTJpA6֕Y{4zq|g7 h`E=(,7Zhnk\Wᵲp &d_,\  kf=O`$v ({Mυ {mmhK>NmpQ\6:mHٓکŲD 'MtwrIABlCAtZ"pd39p`@[ZfP X2|cO c@0o §TN$I~oM p(5!KۛHB{VJjcO F5$2iؒvˈT*,q@}V"+~G1a$UuYQTJk4TችEP/o܎&4{Ԡa\kQz`>PϘFJ!M H Z*NX1F B1A+0e-k3|xL0M%0t]~ԞW5lܘoL!|f)ryI=ۡyhH=ư70Y$&/2Ȱ]n*HM9K+U1]e5swDʆ|:1~n[1h/h7vCBsPTrDIΰơnMq_ @Z<$ A."e \X֓Jo낽7X2,1Ek'SpC++dGф7^ \9ofA%.#hg̗*M_!@m.BpHa4i&Iݿj{M/噬ٸ/E/kn]3Z@Ү=Hmc ifVu7[ ![D18 z/uh/{4>73RU!8V5HwkoWDHF;@S!׎:MBvi"u1^\Q#MTBChR1yP-{Q2(:6먿С_n2:smIz/!2Q¦iT̄SW][u9;4FzlySOZUeO^{A~L(D|)^~"ENp"Iw`oJ?n\.T麃ݐ/uƔtNbӡ֖aTE^<%02S#z #e(bc(,@ǩO()7~3~_gnv1'P%}ahK*401L?y/Vi" 3^GاjcS 1[NC' RGdim"}+' N k\oE%IC72Ch.BGj#/M&:#1[y&}Ph6dzA̓t1z %5Na-zV.|9)="@hRv%ejк@r")r~ZL~lҏQu )_[W=D bppbt-DžA|Eڕi6 bl˄)Dc Y>4%.,n/NF %j&\5xR^d\ٔJ݁cevc,i^D(EA;e " lCǏn7*3_} QZrqP+C*g-y^iӱ5+>3N_Iy?R A"q{r8Dr9YG>AaxcZg9 ^3"5FG}b<șӱF'H25OU`W]Pm灣E:BRiK9M;{8H9 y>?pQ<74;Ac̾U<оԖȇW ɘnjM_o^RM82##D\I~bH# )~bB?(`Aʀ1'ԯQy-V00/;SJFTEP\5BugNP0KGBmUzm$Jc_/8TG=*wK.0"NeUCgzyZcοC9B'NJy٫ӝSJx78X05fش)9=ientҬAvFN+PҭYj^$nMˢTjIqe?sd,Y $שL4MZgN 8fpOc[G^`:bF*Ŵe_;P1^[[2hQĞ&Paop>.QbFV^EfPP:6̰Ejr"MG8D,'n|]mzm__0V~|g˖{au!/⽛!󃬩s達dx@V\wJIFl4;h{˘MbPyezVLIFl|slq59ȊojĕrItlk(F[`ׯEo'P'VvV\m!mtw) K5_%y+eo6Tjz4YWIiNTʿd2u9ƺS-Rm r->}v޵ٗQ~_$9=~?U0F5_3ܹuf'Wsȓ-j.z 1^R\..r`6j׷ToDtP8ȝ$ 5/ ڈ|3YVfX|F b";Ί6Y!/}\$lOHl3"cuLJ5:+65IaMW(u=^-0'H2(́{rق&QNAǪ\EC{]N_!6Bjw|(!y+=gi a._Lhv#S/ve>Ȧhql$LvEԀڵ6KܸXY "s<INQesЖ*FA:T]!Ofg,&@!҆-]k$VA4sȸq-؉ Bpk)0&-\RP4_huU'fT_kq>p,| ڂP=ZTW%Q 0.%ȊڲTqPu3SW 7 ĬVbv(ى.P]gLa``n_&`%@:Fۉ1iU5Ls6*s&ZLsb~2m:#PO~)^'wM9'e)LIo&-]=8gF"ժֵE\_P|B5Y{ZPLX@R_ gD΍jEF~?t! sSgl^a [i6<0Qe`ջ,Hܯ6%8H݇FG4C*'LOMʸX04T[5 b=5Ti\ `P2)Bwz/$~)DM80XSn"iUĉ!]_bŝ|RI[)tS蕍L?ݱ[*̒=7fICO>8;4O&dk~@ϑkb#ҷTgG==G^*E y<&||6ոWc&q-/yaGX|,@f|$JրSϻx Lf_ݬO оj?O!;` t9MD?ޕ^>&/+e8nFp}pw6:ۜ|tLNVx$4_e? t܏ߍ1R$ )BwM]I,+C0ADpy䥭 w-6+Wð1эMosrojz)>.jݰD5ca3'òt-hʻHRX T{D(ܔJduw#4YzzbqCtfIqhqhh[8*V> e seZ< /̫Ifp%d[;#ff&5vvuP6S7]GQ~ @􇵼ƙ~.  E\!J|Kx f82d@[Ej QiZKqA#G\R,嘠(vwfKf.jpbfvDGIObb.Qs!S$/t5 &6 @/`'4*b0@xڅ4B Tgl΢mh$rC] 9۱:/MEt< 3@#1hI^0-ƆVyO9zC`EꧩiQ##J# 3 :)R68kg'pJED;q.-҂S9 ;,1Ħs`)jVa0FJ3ԴP94)$B3 DnUqbwo 1(;hI5<2g@c+SAh5QՀC!հ)nh'/kfnʹc!!%^I@>侪AJBY#%qnùnP})Uٍ5:gk.mӇh[_^`'Vhan?HHpy])Yg&^)+l[Cpd4ХW cpO+""$nMN$FD⣿[Oc.WmXwssڗ۵˳h7AOv sfZ?V'I߯Bӛwx &K~<]l- Ңy22;sjK1U~[:d4>=zI&:ܷKk+?<ɾV#-V\!ݑyU#I󆡁?/x M%D!Қ==79˩Q=<5!*U3~U}ȋP^ ɉg5ziuPc[desN̢bJ wqPޠ0[^^ց`#?M,mt"Re]~g#[Q| ;AG_'(MܧZ(uJh-1όR#_#VbM > w׭Q3iތU"֢ʒ4݊h+3em~N]{X2>]η^ '-SEۀXb]N(`]e,1P{{Oɚck$Eň;*2k&hCT:}daS5AH`JWb78A)uG73.Y?:OR/b(F2D{[f*f(k!wH8vz.8;Å7h.hP]?eo4-x.q#[-!T `+0 3'Q Y Xy#f""ܘVI̔{1$%{H!Nfv7ٽ {e3.jfD.G#Q")ܽBSdVnOD}mZ!Gb`q~Qk`~_1-ȓJdgdkQEA3&HxTŠV]_e#b I(%}Pf'ҍ^Ḧ) NژEKl?JXZ Pš dp\L|#M";@ep8Kf[mWN4f3Y_z% 1e#ӤHdLD iNaV h m.6jU4u므>H1LG B6mbm?Br c%6ڃC$Ra.tԒaF;Iu;c 2[ ;tJ?@ĤjH씜;W; `iF_(͵L'ՙ5yGGSD]|?DԔHG(lѥ=.F(y: ryo0c`{Ne;<&X(< bz"ah|jtӀi7{0zˁe^a&g2Z;7e- -S4 _Fr! #%ϝ e?q$w{˔^n5to/ HW"JY87AQ5rˋJ^e~^mjLԂK{>f,"Cly݇ Px_v^PN ؤ'fI~ܷ݈(q=˘iC8#yU1~:\+ITV4nT m|ԃPxra*[W{gT\p{/02+,kAe!KƯx )EtW;Ëxxv%WKG3AA8$CW|A3>PjgvUׅxB{У(²vQ%ˁ[ɕ^R8c@qRjFXo_B#x4kv*K gO7Լ-LjܒlΌ`#IٟQ0ɵ%V1xu n Oku+IoQ\Ne7zwmyDp뎷d"<v'td3֟\OG Wn?*Q\Xq~9=eտv jb7W\ZDP< :5+o/[yyMI],Ub ~԰4} 7*ZN<-:*s%%ˑө}`$Ds0_ p:F=ꅦ&bHk L7VWƊpWVF}b Sʵuze:k\Ŷb a׫TGJiZL{uMoL̓,F@'+z ҝ ydCihNn+RS pAwGS-Jԍ@4<\[ +Ep5 nKh\)8 H_*SB󌙬8UVŴ'1L{&azQOW(ТOSܔ" V{6JТTU/RӠ+-bOWDw9ɱW5K܉KŇxJп}x6cg\,nGܮ\g%^bbco|<79K:=Z j8UP~u/sD6$+l@(QA=M~! d^Fu */?U=Ag +_boĵyu_ʘ>%EC;l{ahڿ6p(\:} $<}lTH+Q tM/XO<⮅!~OSt" /ZnzhʬNoC2gw#r݉FTY"z?A{ @+SMu!בS¥SoK/Mxow e7xu?I .z3cL4ss8wrxhJB][ ' KNJG!'5D/` sWf}ȴ}jAtz"B}Q-B8ӴXJ]zVL',ZK/,BNΠeM{j: 篩SO!|S)x8NYZ7C\·PI1&ik;W`"DtZvolukEE1*vGC1%HBW0hQ؃ʼna/CM7XӦהϖ"Rs)&^+G6/z pmh=w 3!%Y.w3{ ׂN5A#@l%T\hϳ?U'γ7cW(ן!ɜaq곇k0GxƵ &$L$jBa,NThmFx"&ALq[qBd &aW\`~J+xنUhr ȅQ_昼~fh'}HpV33/SJ ۪ !~}5U{h--HI˦QAx5ე\: mQ`8K=\ <ȕ͠Z"m+N$ÿcZfyivf :ŸRYb,PÀqۛgkِ>w"UpMu aGNdՃdÃ3Yxds*Co~^" I"f,kҟΗ9'ɺ(wcJ]Žil ՟P9|׺pϟ!]dф-mӈaQK'`NcAwKӬBW+8t:IWB؉EiuX\.BC )/+J iiӲ%hh5ㆭlvKI؊GRE03mg B.Ǭ">CC) sЯF[cU*̕KШi Xbd~e<mm!KJԬUwecn,w3f(oc!p{eV0{[䭇AqN.98jZd2؇{|]gr?558&'H*N CnJ7kQba([ 4]i_Qy Kp- Q3>@ae& ȘxG]ap PG.0K9@"GV/yU*Bb؏E~]ħnG#ynnrFK %9E%#6v` R\~1Xr+! 5jYdعCpey% 9yxY3mJ~i׼)5ӪS_Pa-;7Q!UVUPC.B"j tfcq_%y 3yݥS5J¬cJeY䕙@ݸzwtЧ)7lT7- "Z8,&;>wWbhS-.]R0VcoG|yx&tKC1N82$wyGڱ=: OFQSeG 75tDB{=H^,P'uXLX<7QI@+{ftl G8,Lbdhq$[?GUˊn!nf>$iMl'"Mu 1`.SN y4 9KѨ4:]QXiKu߽+ etpe".b荃-yJ &6ݟɴ=,ags[P#Tcb4Eo>/da[W$R@'Jj9`Wp9u[vX1ha5"9HoJbo m^Vh革?56C/}gPۮŗLJtNm -^o[.wf6~D$#:bAG,Q[b<oZZ TJ2ec4j/'V~5yq@Ge1JtnXRGY ĵ!cDiVH,@Rv1=R,Rt'K6"w}&/ĘrYh#CrT e tL@ߌ<>a%;rwE MdK 7Pv>+J-Yt4 JѷM3%/j㗔Jߧ;p+: O? dgOr > 5x⊣$qx6Y{b1պ͒/$ԡBo秴oy⽿c%b*Aͱ ϔ$?Sa(k>-R?UEA/H QpZ8n:3(}%)zDNfG9`i]^PuٶzC٣6QS<7 H>SwxZ_ג >4irjÖzQ{2BS i,qxs7׿ rÅ5 FF2"Rq$+CғB'8D:Vo;ݛ.]bI V^._v!OIeaǣb10U<+Vr1z9&`kL :O= Yܙ5!b ufM5s+mSdL zVM|iLfCeI i:,[NLKiQSKSa!iM 2ʰR3Dd=Eb#Km~Y_4%%Px*i!<)V݀T[ 10_/n6 9_QO:W6pIVlr". I[)U"x:|xYǻ.Bwrk(dAm0~ax}e0 ڈ#aB-z.wLsF9oL"=CT_,_V"T(g}kC(X{_ρhůe|%:t D!ROD<0CҔ七wʽ-gݡح%&Rwm6dĿiIA<P[P-q#AD1XلAD 1e[\h8ͱ=dQˆؿ yju\sLP >,.d17X6ڵXk}FVx4G>mM'lX%tj_e(S9=iK'`^Jr֕`$ $9'ӱ"3Fr: 3jC 'iP/4a\ݗ?$+vYJ}9eqJJ., '9nyTbB2ލhkr7NCCcݽD;@M{in}`EȐ6-U ْo=⠰A@;[D>=rie`e{=< r}_5 `tk4ys:Fu,s׌8蒫Ls_Aj"%*HMs?ybmr|0M$CI5p mܼXq eޘ_5y- B:Y8Zʁu_6]Ȭ-S7<}{os)OSܷ˦a/ΐzp'lNHH[^G%k5u :p]5JjYTVtՖr!)Qjˌ~d%y!{`H)/vƳKrB0uE mvIi3eF̳}t79ዮn&W6-THelh@B<l:l z(g%& u1GוWic3]Me;~ ;gwV}W2uagR<:HX@'zdJJ:e<ٔ%\HY8!{y^PZ_Cc\^ g-X@O)ø, bCv5RSt1E 3¼ED&l,t ,j&"XZ8St 4e9|SZG #z!Лx f#6X]~N'@)dpfɪNݎj"_[+ڥzTyV3A(] w7*1Wڈ_2+kOvNXB TmO2r )ށ{z]g:/a Dt A :k'Sc[_3>=4LF_bq#(EF7W[,V r_C, {?vne# .i:0E? JڙK׿ҏ)p6 Yw]{A%ŧ ihi3{ۜ.\p] fg*x&U qƯlϭ-ϕhiDm`af6b#ꩦ BqSw_ &wKpTTn,=o@w.qAKdc$¾M!ʴ6KĹcMK K&?.ۊ1$Zs߮ mS;]wCn>("Ktg(gkd'Xo+UՁ/7uWP/`<1  Y mQNai?˼¨@l?bkA,g"PuwO#7yg`f'4%}&8ӱN,*N4Au,K\8(rC>D/rx-rE+G^{c:6ȏʙ'?qf~1$HiuNz) IRh2l|b1߮}-OlvQ̟IyHu 9A?\a_M]YvrYWۥS-2dZ`jHnU6tPN:oDf!dʶlYt5@ƋIHG ךn!N2_X(_]Gl=  .cǪ|WLM_q5l_'I ] 5*SM )@!gc X L}}j$W7 Mv0w"3~jaC?Dq@R NjR/ uEt@(joX2,m A?(ADI!ACPo l j9o9vpMFZmp*:YɷwZg%0ϒz8AŬl9)$DhBE<񵄘VΨ>#Y~/zWNTG?ᙳx,)r/rQfql][y9uG< WoFʹx@'-VMU* X}RVjz *frbD\Ӻ^fxR7۾,a{ b 9FAzP]n[-`B]zgtǃ+x?L 1_TD{۸d&*VX6\ QRnT*1`ǑyK:I4;@/ږڈ#$A4jIDF1p̩kIC^ &9+hT$L[롬:H}G\94"6lzJ=w5~IcWKZ]45'~'v`6ևv(K3sK[}Q.H)P4Wo.~ugҳMbn*) ""FZ\}9 HP x.`>v)ĕᶅ#jL[+ ts1HNwRwAo;ڸJgaR&2+( 9wd VWq|13pߝO1zֹS bzHk}', `jhzʓKi2bJx1c&+ٚ.w?]A_8i rE،CHڇ8W%!etqof5BPk$9b X9B n25)w$t} x¬f>W[&nE6 k>:ů@5aP;|*&sZ$bc?|rd(N1K@WM>7,.2Xtbr%M@i7EmOݟ4HR~ a l %4B-G;h;;qPI}՘Sؖ>4ݻVR"WRc5̟ʹEPįOM2<@zv/gW7f g󴖇ԅ wJA1ӺjLQb-w%[!Nظ)#ߵ^KLN4,~,TbIڒ[L!ZTڎKDkiˤ*TNs|.ؼPy$/I%Rf4Bx3mL󌡆_EE&s:3%7s(C= s'#&8SeEQKnmTUes)7Ed{E{ÎV| 3Euk6v\;${<`S묣V8qq @W)v5҅Z6[~uv_b 'B4*A[*L,",ZjDc.(${Oqy!ūgL(9Kǜ9\1ͼ16_GHO qq@*_t) oB&CX޽?G&ڂGQbarDe/e $?=?ij{s]VkVoB'c0AGX8w̱5~{pgͷ+TWTpDqm5K]¾@ {&p|w\RP 6l}ܧAFj]bQӁ'Nw E"]+-kxƵ#kvZ=y7b@,&9cgc7,JcmI>l )_'>|Rt(- '*"ƔB0-C7f()|3<zlj/z$+$|<>@sN';ZR5PQC!J3,Nڱr}1NZb ϡ* Nm!n Ĥб-I-vaRP-E9IhoUW=]B~Ƚ>hEBƛ2`] L &|?E|UC>u /T3' 'lT%LtJfH 8itDpO$d)Ų*:}`BDC,s`xhNXP[#oQhXE0_VGL_]MlyNNKl?f+yITU: erc]TzSV]PUsni;K8- UBqC$Ս<GG` 7Γ0]~5ٮP% bC{Ӫ;AAQz;>GZut>6|l e۰@e[Ӿ[߈`HH],OagQ,h*!|B ksrq6j{avzScs(BBNp_MgÄ7e29/&r>Q9‴qTw1q/["sKsTL]@d>2£ٛ|IVW(Uϊ02]KbJYϢ4:Fszk[b~ri^шivPPBҙT zi 0]jުL׽M/Ooٞ"V^. cx)AOLZb`^B=zV<u#F` V>DY nOVpypͪV:O'Fc8JJY A!SZ'D,bj@p,ۋOaSTdD|bU2~YxiBVBt 0 %:fe^TNɬ?'Fڣ˶#Utp`qV: XoL$c}M? qdC?.CU _y]6a UytZo6IcBWܩVۮ$p N%h ?]_s/Z(i'WNOk?yfiw= k-Cer) ٿ pCP+zVk.4gDg <3߼S]fmadu~w{_mm|/㉧)JB(fD }fcLJj5i>Jy_E;#rU}#2dkz|co5MwvY /*EVaWIXh&h 5=V_ P2+h=;2!)Ev?Q5 F_S*g'cnN`Xpu}3]f4HJ2(H|art'*CAWM5ւH`m)% ql >n+UMæuuf^\۞#pͿ" }sլ)>Y K9jpRZ\R _njOjXx.jc\&V[w-Of@3 h$VZł'배hnLe!>MCTq yg,[K&b{lJpNT["r.Y4 2E2yJ{Ɣ.O:u7szxŃ- z7-ٜ1sQ['>ma'3G^إ~;$vxfCU`5/Kltr!RWlSJ%ДuDa|ӮF@x!roty[qcf&C}[kݲksE:ռ~B V׷ |h?Șrgx K&$TiYjv"]"ba":F!7gRSot Z{™!Hm%=2KFv[" D$(2 AU[?읉uAHQYXrv&b[YNWyʗLg_VR̯){,SF*,]fđ=1y|ΠaU y=goP̺YT,TYma.Y1>fZ~؏ݛ3hTI)'p&#H9Ó-藙͞z$'$T4s7u'XzPz4SSbZ3ۜ7Q UNnӹ[s{alv}O.FNzY .R#XI6 <&cحFf,!aQJ_EJO=Ct0Bx)^vB()nCu;\PmUt4  } Zn)q3Wyq?y)7C4bRxFzvR')ZI?̛0Й$"[p"tsu yl . <@@ ;rIy?o-;bZ2)\(!#nHg< kړϓ~.q*1xhw]c~dUyBGϻ!:"3cL#6Py pug񪈎Ulh)tA%_E9|Q1k<Ĝ :7h`G`Ӄ90`( F|eK}Z֣x} >g,߃g|.&[>ƹC{.0k\JB?MA/є"Lon\`0e.[XB`28})i ?_Pa OBDŽ~֢V;!!$?_UlhK"ҙ$8k)*Hӥ'wNG. /1(/}e9Q`ҹ!QHaHAuRu?͍yXx6)(.act[7AD܈Y:u’qhúS^8mJ}(-q r1k|I7cS͸GVt C.+<Rwèv{' V4c`“  =ST̋G=ֳh7hi<&"#@j])1wH,FsWR#$CYފ{ɬZ^'Y;N]b "hH,iLSN*- *4ֶ+o!z i;[^|UsĦwFo9M6]Ӳ(`8=n#eM;Z>|gvrCS~Ъ&—~ ? VToWn>ȍɇe Y<ٺv1mW@c̀0r+!*EPA*H}2[]edgiKm^PՉ_,^Ť5z`HMkf>Y;80X] Y^^B1dzW}^М{ MX-n[Jqv+K3f w6# ^0P,ɳ@q$=S,lO{E8bw7+x 9F|{>{RlJn z5+ Ckc GGE@%WL^<,1$eׂ'Y ISRІSD~&W9w1rg1ދKBU๴M NЉ9pr{[՗mfG>:Qs$9#EGe}lѨG!(o@~;b#"h~d,[LsmޕO39s,qtbSQqqid[]=zkhEHt@Υo7C^{|9shQ%A|?4D\|ܬ$gi+1O73 lj-7/K1~=(,$ؓf)=s9avby^]ج<=FZb WZnk6!MDuz`jT{K|#4پqGBF,ɯ; ;J5#@/B_&ħVҚ}^)3B^!ux0 \ZQ^&$ Qe]7hR͡G< T . *C'Q;J5q*mAj3|{I$iZ԰[hQ]eHwUF3U9HHz&MpEH0gG$Ӣ64EL9e\01no5`:/ZO7I>nL.9FDۡ(2WY08!WZ5dO# q)p,GSyKPc~ڸcpfHHg+Waop=>T.Nq^>u#~ ~#dw0N#IϥX\+ǞG5? F~oo?sa}۵Hc'zXɮ֔3R5=ã3j5, L>MspЭ77w>\go"($Yc /lpb(9#0)翑U<ޙå4Ƥ8t+KJ7-TGŴ9͜ou,`8!pr!P8~K/>98ܟr\t&LcKCğŖd9&|xGYA`\hH/7|+gZfKeIGg58\7Y9LZ @G4 ܒK%$᎕ f5_{񶭛}!#-O:ƛ#Öc `}4EHujυEdE"5WS1R#XIǍ;4,ވpt]^ŝMʌ&{~(X}aT'E^F`%/܋̈~1:H0ІiP=oT/dא#y䇶ecj$)~q9+@N)tȈ}ZB{S!t8)u<8aQ)ާEtEl^G ,]}v-Y3_utSOePmV:?NBhˆ4:@֒04ˇ1̷cx PQk#Z" lbzRL$k;赢ICvz)Q#v!W\>(zLw^.]нP}dt+  :Ml;7dqWe:(} N]$N˲(O{XӷN (Vky$qb9w?2Y+ [u4 Ξ=BQbz׹ 5YY֤#[BxoU o`κ*U 99@_y^)_cšK~.4bk5x!;gy˫g!-1HIW ?ƲCY,k ZK!/'ݬڧibD,:1Xqm/ŋ})9P;BbQ~'] O2}\ Sl9GMl:A#Ye]5 tBd>PD (#+^!j; !xJ-h;3`'HD*J6ХYG^f[0S ٝn`ơSLﳩ8sZkcgeLP,l՞|JBz @:rM>(4@wFw>`3s$.6UB)OC ;;##a|,{o^,fҍ#"3RԭW 5Rrg'sjNeK݈D`yq,r{E=L0XK ^1)5âA/1Yqap;j-eXLJМ*!=f]tM֎NA1`먭4fd+ lLVKW]T#64gau:)a^G8r)7rڙBXcG@ut1zT gEKe0mC1SRb}X@bbt}pniΉ16 ?!DzOVh}K序w1O vS*>%մ?\kf4)J]ݔ&CI#>,i2bWJ&7[ ߴ (Qp-d۳"Q!ww'U }ݍs\hհ~ WyD7hہ^0sʦ*y[A 2W!(E] LK%Mw>Ŵ8Rc%$crf+*K2׶qp}l-ofcϘEOS3uk@m(dlvAd$)Z]nv.YT$ЈOIm08{x(AXIɕ5Lግܤ?y}"RAZ,/'Ў_'=Ut5)߷?" F7 ؒ=Ҫ`<.( ԯ}k,x\KMw=i+]ط\Ip,Y۲԰D}kRy<;}-O? `'ōlyH gvip5brOE! ?zƼD>OXR<6ޕ@v)%WwL:K'1Vct gu`AM9 ꫽RƏ`8th i&8t(d &~O$Ƈp8@%*@]MmqPfˉs?4nOCɻK2sU(!f?Uj`f-mWB. ղz?I-e~XMxϿ4*D,Q mk6>Mzo =*q$%9() ثZ/GNd܊wWQ=pҢq$ġ`&hpw3Wq}'[GӸTVdӼLBb{O߹d^X31\ \eFb1_}UBhEw6iՆ> Wxe,yyq >TLNj!e&z<ԗC=x).|($Qo"`<-8ϫ4kVE2XsvdgᆬˀZ-=_\8>PBȯ[V_{i"W%1qxƉ@zOAv;6pF}.@HjL.L6#ڑk$/o}='ϽQ;Έqgv5P~.R D`)'U\?Wۜj"](p5TGcV0vo<!Ѧ/6Y1\2[˗ׅ};+[xw 謤(R0bFߠEAM]z\- f`ʸS8S)_B3L|Ћ JMk˵·e"P1;d:N,V?{mRP.}O8t92z+R;zݩ Bec D_KhsRՐMBߘ9nN(+dqGC֎ Utdd&x{,~~8nSDx/cDrBErJ"6?H?c )Kl#^M7Q9q9HNoe5*\"Ż:bLjS-xG. =cp35F'$cCn qC {vsϘr1-&Ƹ;3~k^xe;em*Ïܪ5J![rz'>rhՁTr$vFe$ F5kUҺi՘=Xe?/2ҋjyF Sw/0d 'sȷF -Z 5lc[G˔3W~KNO]O;Sbk{I@b0`IU.iD;%T \cB7: yyPt٨"wT.e+컗vnm-cȒ48w2Xa̻ -*K5(AY' \`Pp*.6:$ٿOh8uV/i/bzGE 㕳Q )*Ac6Ҭ$kפv`xFjd~ɰ!-!28EߕB+5d^$ QʓFѳ'g8t$BEbxU+݀2hw腇[bp+<-zЛ" mEX#) *ItcmDJYG!PtAQ,Xl4x^nzP\'LbRjo|rH>]me }ysY['pCRawIB_i1e_1 '?8e,0 pIUT1_X1_[91KV !QwÚVgY>݀- κj vϖc;!/#y2f zJA_q$8ISe&*#r3LnBN{B-hwLfNFw!wrcȄGB4T~.ԿTLOM2W 3mV콄 OM~;u`80q95W9Äa5{Rc b2eG*3@@#nOI;@]b,'{աN9rs)~)| }*+-ǹ+CP|+.GgE}”,<!.@OWntq7<^-AhHՍʿ MMx/Ҿ%/G^x 68[Zy*XmL[D0lL7lZgv 2M>u.51,DI nY@ٺ& ]uOZY*ǁPQ.;UAv\Ps!\HR{|,SY7e.ʹEUB!oߡ:p=-;μWh8S`oJ,Zi ZtMfdZ.d0Vz06 #Ywi{ K- .U }Jv׭LEʒ5%%iVs Cė@DYGlÇ3ӆ.}+]6/FDv&rspO UkMKCw @:?5*,s&k}"Á_` #iEgy) eS)ƷY{o50q<~QQ$XH,_c 'ՋF6{Tv9Aٯd"=٧0iAXH`AMq)uʭbmf~IY^0WLaNũ׶m(Ta%٢)2odMH̛"q^Iޓ}OIz5>Zm:a:nYt vc) Puyܳ]'CD9t[{97PF:Rۭa=wYML 5_ao:ԥ:`t|i$Y5;*)V":(OUwb& { OH5Yie˽`eʚEVN\b?j^͝cPa)v^E=Qޮ4e?]YhblPŧK3_jwkPBXe&)5ٽI Gd7稱%hAaԫ;9 lq6`͋sn_e:: 4Ӱw9rA} [0s`|*|ԏEڇ X۲I14*.;Nx';< x*O $$26fbXxkd B4qV`' Jz=LR>%ԈfϺ] { ;~# 5D*mQE3(O&ᗹ31ih8 QZQ Q?zx|^NÍ{XTPbB,L uL)T/bjĈ9}i({pG^$"٬  sn:)u64*Du=glٌ' D KJ!Nt,L܉o(ZΝPl| _4~$aMZC%V2zfn9}-d/DkҊ pX 8/s޻ P:/㌹1L{xS^OH=xEgh)L4yd>iBD?n.}j-1mؗHP0 )亷i4tԈpx$|W3<ұ/gT-=ζ/Rj0403X<,zcUR-7Ν\la~  %q&:\.\5Q2"u,m)Y;reL>9(ر&BaZ߻(RiSl#N-Q]qs:h׏gK~DHpBgc*ˆ.1ݱ.)]Ԣ'<#0M(;^e S ȉ%N3D 3Z. -A}Lj?S}U?b &΂ pKj{p[rϻv9ԡs\B7ha':t AػocE4 h={E{<.2륆Nxt }>? h<'u~uĕ'94+1̥aݳ(iJ`jfnQĦ\ߘ&"/-exq6kT9Hw xBKb.䂈"'u(ڎe2~bKPj,:o})ZULIږf [:lX\㵽AV2S1o74O>'lY:@hk-z)/u{7~x+$sX2ZUK&2斮{s|`5.x1Ch]JME`EUMAB+9/ڽOOCɈo+~W)W|wE}b3@&ma/~KdI"er H٫A9[|Ptl*n|'5goeŗ$s^F} tK~I|S33]gBbx:Wj;})JxDր?<8y\$nSrncIe @Gx52}_S¯NP}]ZڙMIC3A_t0ptkbĶq(XU+"vJZ"):f@D,(un}&'5Y:sMپѲ HV TbݡuKpi"} 3!TV ~rDl*? 6C ^0 Q񾡄]ӄ,WCݩza6@B_\RDxB a8 >!ٹ2KZRvq7 tue.~>n}VtE*G,  g5z^}>]SMPvxOn:fvRf[jD hOBh/͎1AQ6\ӶGK;XE ΑK>'bh 8eFj ٸ~arB7i7ԩGsSA߆;tP$ r Qt%^򄹯c?&I9h5m@)G2Y|%BNp@Dt$AgmI S*B g<`o̐RQd {iPlvXSo"K鼾VLJoqad>B k֩0r-uBT Tc3PБ/ ㌒ uo޵;`(ЙgצԺ՛UpklH(*rd /WNCo}yZZ$@:r;Zk; 0 Iõ[m8 'jmun RFDggD_SM?/k+XAVy L͋;M/Ev&rn #C2 L'_@XANAy8u$ygbK-m7%fD{3={S9W@<%9 ?yyМR*o֦;̈́synCy7Ldd=?. %R[50 XA= 6(SAA#*EL Rkxiҧ..dYp:ui1eG"kOܪ,5]{dkʫi`뢹=>f#k})S̺}}> > #ZG~U]4mg5$"3 ߌ$vtZs8nCzȡr*2T )a +lPٹO>Hq=QZiұ5pAp\w`nHYQ6ҳG7']N,3䔔@yeRD=;p"EhkV <6Q+N1fBbYߟii| gYIt.'\o)0;=t@˫%}\A$Cah @[ȧ=`"x基f--V$vc~ 3Ģ~Q:qi =Q2ӆZӻEo?{bŐho]]+YnW\ +f2H__b LSGo9"|;m@g(iEd QoO\6r}]"Zx]Ƽ?Ffa'dAcSB%Ko"4. j:@x96X%ހw>P{{>'0pAL~WѮʉ"Bgdp|WPGm QXK<FH8ΤB1R#ۿ|L۰u m"T"f|gߋr 𠒃iwg61vOU幊x3FSͷ5 __J3Δ/3 3[ig82t`4:6$4 V-! @&rB*f0'Apr"0 j]~s@[UUppJ桒7e:$ @O;ޢ3~ yM&,44k%/.~)T5Y[7φ^5~bGU`nQW &$ڰ`i&:hP 6l<dqDu{5YiSOȜ碜׳7RYZ%G- dPk5IK-PO`taS#!o{՜21wO4qr$1 ULo'E"{qA0phmeN-X, wЊU,7# QH] wzXBY*qg kAi# SVcP}EL)Pʖ`W*??=ʅKq쟪g{qjGf3D3K2?\5C>Pd`b07]r @~z1#ٰraa a~ ˆp=',@8#jpl"͢n #?(g7L}v(6'vlڰCقc٣.Hq]!`pXE@pl\Wn~ !a۳MpQYV=oK^ǒi`~'uB}|@g_y&EGD85$R4+ag;M]8xڦc,W UbPQRI|1Tw=f0Z$5ӵ ?bЋ'j^Y\ǒ]FEP. K͖d[9LJTA|243sFv <8Cn c*Q tK~ f1n\R#Η|a l;}YOTprϑZZ~‡? GV<5=X4cxr)ކ$unBdn2AyA.S.ׇJ)./t'z]DT&yEoWRgY1H #Ex=s(ݭ"E_̀5ND(Grn[-Kd[8#B#-~kΜf`<۩=Q,͛+>>z>&gsҀhhWv3t`1ʜ[)^DNHnsw#{ÀA^5^/tEMVs.  C8j^ٴoy3l<9]U_]B5NvQcST'y;"O+[W̶ SPkXf919?Īpi8h viwseO4UF5 靺/Ӷ#B03T/ǥtOUsXO XNIHYȊa5}W74}3%p33j[3hwsV7ߑ URd gɽG/EB&Ruc3'-y^\쏜rϟjf|ćؼQ-z ,īWV',p E-7L@Zw|/Lv[f&f¼뵥_a ˄qP-#ԥ gT̪}SG7C ٻUxLi *FuY[ 68CsiA˓p>I8[pt/ݹрIXlLm+ @/ߓA)lɭS1. oms\Qs%Or&jYW@Dx2 ](!O@|ˆT$s^qcyXhcs&;M[h.8eggV˚DUh8pyfY4J-@ V|h@rqԈԥ%#US_{ryfgJjvLINo5>VXg{gP)X1!D5.(sj{N*6f*rݗSfWv$(qzYE̕b;& BzS-7l"-Y/^5a27h|Q -IRǂih(w @u( 25SA$X(`&B| M$`E̢n%"/TYw-5fi4𴋚Mj{<顕%UVRD3kuJ1XcgeBY Wd,oY/`ǻl37mvYw$,=kyV3 W+ qa|[)[z^Q:qVd|RjIw jSk<}PeJK qG(Zq5_~sX3FηC ۍ;m›C/Ɉy%ڄ|Yt1Q<}TkDO|9AZJqB?7_ab/xO-9=]vBIo()E\Z4{pzYqv3>&cN N AaJ #kgRfԔnm/dPbՠ8?x1 |{pH֏jN8Nn3G8%b)r{)O( #r72!}"gC*,j,ɅXt@m&zv46P߭9aE2't%T' lw$Vӯ7.<Cã'j`<<"X+5ŭ%fdܝQ$D07Hb0JkFuɽU;tBWz'`24sH$\mf?)L$%R=_ɾ^>=LpVhG8%JZ(+JV|ri%ujL$]47;{;=ΘYn ƅN^\0nU./S, ]S|ը/j<+}3JPN=l `KPKwN o8|)V g; Nglv7֡wD !-V"! @*5lA56Nfaw05:3AyOf1N|u()DzI}DS 7ƻUt9 նa\p|ok<$]4IÂ7eةCƎ)yd3"2wP06S`95“, WXlm:3py [ٮ .⛒>_3A^D95vP58Δ@rp o8Xɠ OaDXX/Pc|1ZMn=# k1Рr=λmQбC SqSn;J2x\Ai<6rG$/Plo$Fc3; CHnfYJ5VCL! ^πF ^Lf,`6Oc0̚Ϣ6rVXp,x}:C&Ȼy:'.;tctxw6(`5_jvC41F|gg6,LZ4gYi7oAm pɨd]OE\=A8 q=*8=ꂑh駰J8E`&Eve<+H965 l41 2zMY'SbUiKPXT>5`{HW$]\P ݋YDAw_mPHos]Dc; JD6%^~ŧIGCnQ XgWkc>86MW\=.Æ((7s-؎prwS3[h2&DSM2"/ CUc3xYY@/6j>2;nEd>x 01Xq, ..Ѐ:il%E&5P!3ߺ vRpaYq[ .V' g Pރwwj!FG^f_x|%cz}+؝IZ32d ] *[)%jS{]y:zS:8* ~BתV-1:[P2d*,nTLkUXГ_ߠ1`F(k& ;ll3ދN Sct5.Q@-XGKV;I 4z_cde(QU?d BSvmԀ4d'pŲ:+x)m6WF<è`e#]BϿ_^ qukc(g rc)i'6JOXbvU\hK>˦ v|!MNu+((cXяZ!!(bT⊘@DkV7萅poe˘a 8xn)Tҳ{?^P\n~F/INJ6BmoP'3rX%-3859,ȵ'|0̯85r$8\O^kb~Ԯ3XE @}N$y2۱טOBa,u`o}0oMBl'X@r.W'^] PMF( ]48V uq6~w^*G\2-xV =TGٴN @X5H98Ձ`àdjxqLx#H.voU\qdHj{oa0٘g!ˋ]7⾲H-~6Ϫw)RA=vYfbFBǕT2!Qd*pr%JJf !A\"u񻎶\7B4-oa3Gx I!:ǸoZ$krEt s A3~=X") W$HkwG[ܫ@A",_:XIqs{3V/rjνKdԛNYSPŠ֦PcV }yCx! 1ׂZ-ں7^ÁiL)Xs º ]xYB˥aGDӜ%227a+H, /+|ٞYP&sB ؎Rj|R@;p`qЪ#OxYCgLG7 ݀xprO=Һ0(X~5)&Ng!ğ9%!7A5>cYW]sLFdjPjcEfQ΄Xiڽ韰#▝s5-TkkUQ'c5њ4#<(:%,~r&K-4^ex!VgbKbǦM풊@bЍTxFViqq'srqݣ}J 0a~8je3}c&: 8BG]qO'7}C.1|cx8]\D&qgcz@Lqų{} V\WZ(g˛*a+ͻD-:^G:kF28'Luz3XT@? =톄^pFt[~/ۊHn(Ս&plS$- TBsW$E~d#J8zm|4*w|0p63+S)~d@wts\-zoG qfy]P}z%Ιb Js N9iu(O@ 4h##b!-/g,-y(Ǖ4V;,I S7Bot 2FRCiAH'RC&/^I1Olv#R\"|%~|kQɹYzW0|juCn!mP MJ Q L5j%:< Thy ͫ|+1 + )A6=mٴ N e/&(Һ>Q.*1̤9||-IQuVp0pxL!$Qr}gBk ݼ,FI)ru,J*V#eu{,-&wO} tʼn6``_8L],)L4"0RwJ$`. fLയ<-̥!#)<\.F|IL1t/><iRxߑ}FzZLfWc7ٔ C s@#EL:̝\QE*>) Vܐ5.8D]^ -ƜR&Tk|P1j>}%i"ʚk| ̫Cg*Hxkw0%0|p'!4tlq2s)=CCQ.t||q..KWKՓC~6r?ȩAb7Qw 4U4J\}wE%!3'a%JfC_m%Ja僀"j?XY~kxq#궿9$-wt~RLΐd'\=89f6?Z(.h%Q<6A=+km!c񔦓ξ6Vy:/z D96O#$^YoH0  K$+l7ݹxt{wAcT!'ڷa.ޝ'׉shyJs㌠x聻$($sMf&j+.HޜJ;ZGV@`L~_C}뤌|נs8Zr0gm<5 Zl8AaI?穀)B>1: Ӝ滜cӮ(&w6c\0Eˈ(XYPqxceշjgw~2ؑǩ}[Ua]}Ld|&JKjywL upv2ҧwRP7zObCSf2zS+NjI&AO^+pU0Jޒ>T >+a7綯bK-NӴ&G3=IQ~׉-=HFo! Z~ (<.$;JxnP+ `%yUigժ7E'!}?CO r|N$U % [*N(3jj{ņB.H=ג]P>]jsE}|cx#C˞`\p  G-!\zp.F9վX3ތچNGp*7FEvNa!5v} T ;rKKѾS@bDjx=s۫6~^yO.wfca58j\Tl\[}uSQ]֮4Oڴ<{qYi>`OF7)U'(I 1ե7 GGVxBxgcUa4a:Sg>Vd-?vE] yd%qXl1xZNE2ZUmأgm[eNMa9 Qcff0KD.wE[Gi8gCʾHjRV?񌂫]YmVkFBэ" dC%mͥ s%'ix2I=&^հϿarMt}$OswgPPxϝޭVZ#-|(7-L?% qީB[w;rYXC[HmR\C`9;ҝ6wP Y,qKkJdžq"l,$g.e/ ÈE ^g[[N 4]zUvh pdaRM:A'9Tˆ$mjn؁iwjaꉣ(:[,wܡj-ܳr*?Y蝚P"vāV%[)kWJ߻!YD(k"UC܍ )]=1)J-;=1\Bۓ_BK_}TvVHxf6 {@n'"$y$>lHJypfh{L j\glhRƩ]x. I;“˺%)N:z؃:ygҜM~v fL|;g[Rͨjks::j`-Ymw=~ˁ>GC[p[kt@V:>C3NO* #NQ*׳2xf]'-s=Pۺ(ϳhX|S)Ȩytû{l"ojq Q q3dy˒ǥEᏞNC%-*['qbq/y=r<`;Ӛ_dI/|i9dh(Ґ9CxՐMtpHjRU/[d~"xx){+hB=d8U%iH\$iҶ~0ɐdf<8_]Gn/(5kQzue`p.KOlH{%7t x =8PNm෩צ_f Y7 Y9kH=7L o")o~f.[I$pɕ-KթW a$sSdJFV Od7ͬԺb Lipflhr3  5qByi\l-O0ht))T4&ZƜݍEg; yw~_iGoPpѡ)r7 +-C%_,i= G7D.UƤ۔_ լ`g7%iɄ/Υ,d'<;A)֪/ tsbpaT-;?nk43zqE N_ð588L&8t pS ~Qk KHbb_%'͹lx5^`|A't=[N)% 'dc>pMGgy%S~tBE9*Byq5HW$4v횎h8)trh} L+"i{bu(S12b2;0o)K:$`sm_N|͕t([eSS ϩVV7$w_ Ҋc A>VOk]֞FʸQ 6s=zݳ#V¬<@Bģ:4)L$N{sfaM:f0!QR qhPTJN&[.PW*ZoEaƆ^6s^!ӜEsOp-" '),e !჊y_mk7$Xxo:X&$L73l4e$<Ǹ9e[.{ :*mo;MX ]GKStz+A`o7Jfcl 㺨=7(O$JJϢ7BVL^[s[HX2GZ XItelɧXmq_?aa%+0Qy%u$.(Tw XH R7V)Ar-Vۄ`exKC܎5)"}| ΨwS}ѡkG`qOq Ε:|K%<&,ݜgڄ4 ٺ߀*S񃗼 exy8AA!M"hZㄔҮGE!|bg'(Ő|ojP^Z<0n}lG(&Mcb]F-0QThRٻCbHP fޝ,)Nu[ 8ʤ~m)Q=NAߍFEfrrեO0ܣ)OvFR}zʎQKmn)P1]}2i F'w0W|v?0 ^4;z4'SԦ/=+JHk,u*lsҾI4E߃!V6;ș`%1ͫҦ8M^f^A-JZZHLλn/1؇G a%`렐?G6 0qMmViͼ% F6iLDv{^KE2| 7W5CtClW.ͪ޿Fua<\=zP I0C|U^w (U@U?ׅVh3/q{J]W'yR}q.4/u"{A OKz=Ep{yo\LzâU:dcoIsy†Qʚ@QPu-Sv#knjf@iⴔ$LZ~/kzq7 N" qPdWGjTJ^s Zd_h!jz+wHWUֈ4W> ^H67hl^ vV\>dKGAJ8W8j_~Z(0B,'PAUI~pTPc(0|*JlHSw(ErSˀ (;^1f~<ڋTT`UOZLb?iHל-") ,hf#*gp>jIMZNѿU1.l&e#Ui(ސ_ WK֦BntMb#sQ޽Qh5q 4o'6A 1U`&\ &m_rB/QlNUJL&1>R=Q)cjΎ60)6.Ԋ_SwUjf6;)%8&SkouQ:HNStŏ[w8I NX5Ë -N$^esn:~.xн.j]5]Pݣr573hR?Ͱe+"5"}b9{udjdSXJy[4L~=o=a'=R^|6_s%nVc`,OIxPjcILsUyu>["r=_@ʹ:}aff7'k'R?[e)f/kZ(.4MBd 7wӑʑ<[%X$[g9g%SdȶcgKsYzB LV4(ރ Y71@s% nJ,Y@qiI1mԟ,xB,uկ{?o񀓯p70Hf>p`VVQ*Үn]VqV(r,E_g ᡍR  q"2}{lW"mD>ϬYDip@FCTAsZ'P&OEpNFlnp >"g3\v9\(9% 4 #dxXR,܅. O{f'N)mCyX j;pg2 1S&/|[d|r~Q/]35 jdf ~'Uo>sGèkOe2ӯ#LfK ot~zP7jRQ*dhD&km_cޜ2ߎ.IU[:FܝGv8>83ć6&o8W/U5XpdLl+̹qc%Foe% [b݄ph,iZR%FsL *;^8H]k);񧯼yWam˪k;IGm@J#*@՟qaD;Mnc'ޙ` xMf-J.2b#[>n8W? ||27D\ؗz RxKg=ujlL%R;Ch,I"Ā2L(:)NԔ/杍)ɥ%q}QHKdE4m&撸 9 ;(ą=N̅\_U4Q1pMH7v ;q5Fy"w#ɛefۉ +J(*u"Pq\)3/! ܠމm_~ 舐8} }4`ROu3yF?;N9ӿ!_J v &9k[/>Z0|xŹ6Ma6r2ɗQnʤu]GwՁ?^8Ds(#( ,~clx-+YOvQRdg>`y |5u/YXU6W徝MQW:D g @a#.a__yTa].G {&`b/jE/xHJPP\Ǫ7U4guW;J[π%:D(7M(v/P}{SƳڛ?^S᭤>on5VQqה6/hDW-,jg`5 Inށ/O/~0 9}ƕ4(Wllش ;ib Mչ8U"vxNl TY^Xg|. J*;MSx5up^JGQōu`lXaŪ2vòٻA8^g]a[yb |=;qv-NfIn c}˵7 0ao8O@SSTj/>_qnG!8- Ǎ]GB^ɖ/Z:s,@ , [T{Io`f_$G2J¸ZA-8;xlRGA}uAV8ͭ%W%G6cvΆHV'WcиҕzGl.];y~}O3os*,I t<ٷ`Ln<=b SE9<Ιu,{5g_a_y̩LĿ2W ߇yB/%Ld{ZV5C-Y^/籬)3$7rjEOitq<$.3q ־qوP"H _5KP#|֢o țF_K1bPfpP֯0cg璘XA͕4oz {J=JŇ74XH4m[9SY3"ti~lS Hdq:&ui7)ueLSM~г`D=~4'B+TS?!#v [G;Օ5 5|c6H~4,WURl>.MER? xHʐ͍"=`ӷ?xízlPp޳[Ps"p&YyEQ Ź$gVY!m gq pH6; F#n.0?m\!{Dm.ףEW,5lXrz?wS8N Ol;c2uijO(^%2E E(ӻ)n= mMrΔ1t^"Ml2E;(.P [=?(nXǓX=AoRuZmV̭¥}n);/xԲ=E|*"2:ZHj!?,V=Ig=4`,.stsC>Ѽe\d)jP7͸![kN(Q9R2Lxp9:Җt)uM?5i L^F'U's:$F:>'ei'ogKl՗WAb(w$ _i_r'%>?@$㊊`SvC5E ͫä.~xӈO=[@Em%?`{Ȣ1hAzW^]TGlSax%G':ӡL/'uB'S%| 6sF%k^)p쓷DĦښ5@V~jAo(8.MpH(.(l3XCErb34ڄ}Kf}\Y41Ȱ9 /; ܇zf4~L?K3Pbs~xsW"2/qE5TxKK#ƾbH;Uu> ]?=zB0-/M 0 uWD˅>5)62bX++;~ZVct`RE;X^lM zRa`mB)y;@/tܲϾH>+I$vo!nkΧp5e!G+ʒ:6Qi  _pAPYlj+INF+6qL:^YZ32IML1.yv*[Em.P+Or|u`nT]c YFمd}}[]p-]U[+R٨sl%6vrHSɸ˄N*?B \,&A1'7 3 + e(]͍ā_jn:A65=6*LJ 5 wubd],F5ERid97!l/}'{B*>4Ś"ԭ߄t 3-oYj~ē]{!R1W-rxW) >[)V_C3hnS/?dCx ل{9"q㻷%YPp '-hSAg)`{ I'{sAuΧB]LR[ eB= 9'5n>QT+3Q1tOxf!nfyv%R^X;-( Kva@TبT[vVY>O.CMӸ*LuvYdqU%|0{XH& _ZYP5?n}lUg,L;DH3|XH9" :nlr_lo&b>Zl[0o=&ݱiO-~#h;d~-aF"RSG؝W4+H6!Ǔ MQ۽v7\zX?LA)Xm4l]Emn=\QjqVD/}y,|ڲ$A`Džhі-lPuWW ՕP 6tKȊCy*NO\}1^![2cttxy/I+1~SіR ,06Qx}D#ڰM#{斏8C;^7WCL9*>X.3u}CX,;9ZE~q5PniF;Stki7RRylej6X`O^;Te^̼2h_O&?t>s#}Dxcg?69QښunN~k_^~&A"ߺ炐c*2":Swuqxa^\vV=q IC5-hZ}>~6f̍PNɩ'X_[Kp\,+&A#fB(NgWb)p-NgxF@XC咲CcFMե]24.8dǚ(}Gz*\YМUhܴ[*㏝,ԝ{xߋ[29[Z$)βDO Pe;A+!a ZF3[P ze8MF/Y{KꙬn4:zsuhW>!ΠXu:-"B;BaWʯT0:_Ѱy/>U;w@r'o{a P%NaHFa7㶅ԱǸ٭^R*kqR j\YS(w3& ~,.™}װp=28)ow^ʂ:STk t7=Y{" y*.Cb|*]^5J KkoFtYy.01CHW8 KpwY٨4PWSePw}HJCۡ5 8 ܮ.["]Vx*@1#Z4'd ㄵ𑠛$SZXkgY 9y2## `x%xֆb: nsKJ5:b7Rh7?U"M6!qDc)+hj$}w1 ]VHUpvU ]gѺHٱ/P4 Ñ8TOɫ ;J@f\j֥$Vfʗ 7-avm̈́l7ţCfvSJ@=u^혃@#ǐɠeYPALE ZPv=4spyI,p@Ġ{}EwrA|a}zĵhgGqC4V9QuSSo{yyb;4XQ\Ápe+^0cvvX 5j8(NU6483 + |KwlwHBtf 2m,Eb蒫4(+TUT%DJ)M㱚(4l~HPhD{M2:[E|TaNI _vڅl߬Cf"^qYݼ&5 M2z3'~}Y>gʐf˅LUvE}iمXA*ቓETxw?M,լIJ6J䠶\M3&M|i@Q"e )CDޏ釀{qxDxB_pH"'JJgŧ_dr٭o(h/CMG҉9m|U|M#wQ޳qE/QHDHeu%^ңZTvH{|AΟ?P]1WUWe]O\;3@#skMBkg2];8-ar,0S~<8 &F{Wu17y %9T[B#Z]`17Pc.d˃b閾ĺ;S z T('čAR*3@1 E6fLFORvW}+t]oR**W(ΈY~b!}CVJ*5.3V@jue=JpM?,]7< N?l_x+BiBG,iA*jl&O8M~/~z&K_̽d*=ywq{n4\,=>ucoJ%W@ߥ8=v"$25iΝb}9guU8`AIVwjtJhҥKXpXip㜩ǔ}@POu:1XT8fP,C7 D4+DZmH1f#]&'i[aBDGîmU7aRj,G$q6!م5aguv."LHXiUcQnwi-%Jvϯg1ZKrVp$S5ptEK,0Y5dky 팡Q4'@?u;du; :U"M1VLpv6|1z#̮ܺ?m4f~ʉmcZ T^Y耢hP -ŝsw`3 9tKMAP ];cf_(JkJyQ;FBb^5z&ZVX Mk؅Rr-)&v'zrMW!UpED,=$9Mti;)g bڵ>W]iȎ4 \ ?fN-4vHh@r9jʢk[`8ҷټ9c,]S:f1"jCl $,=.=m@^1$6L^}LJD{=cs_\&TΏMFKvo\P.Ed)c! Z? ƴN wIiYhX !aedŃ]'>~'F$)56t`g6 -t-W7{$az#[N鵊IgTU{~Xן@WRn{{72x:ްe?b0qc,hX=e ~ Od2$sjg9EKE8Swp`૤e~&2’R/)NDu璐.~ YmRQ~EdwztQeŴƙP2 wGmX)by m3SsGd%wჯM^0y>/s#Og/D2OE`?` l}E <-e HGXvyu8/Sv{^tSey~0ا$ (I`}EyZLpv{+H85|P]MLga-y6ʻW.h n嵴%nzldwVB) H6S ~/GG|TdK0ZWMo ʊ*fyQ<*ruEs)xua3WɎy`@a5ܣHyޖ8)G_0(vc>B&<cUDBCvrόƕ?bih* YxMJK+ KÏV d$.Bj<+kqK>`)0Ҳݚ#*&ϻXJO.-H){JHJ\rHƁB?|iUǚˁuÊzSR0gI*)P,Fُ 3NȃKTe _;bw/j5\}'EĈ& /? 4\fp1ǜyjr6t`venB.6~HvW.-GkcZLmPЍ8}LszJxf !9RZm%p ⃥E ς^jA( ;cg|䎙dPt@>!uVg0j!(x3:Eؾ2nZWtЭFͅ=l\' _אBdx/0@r 8ڶR;!ߍƾD|QK!/; p<]8BL@ӹ.8 e$SZKis9}KYS~;™baW"8vqGZc`wj`Ph*hOpA7$%D?$TNkȥxgWƭ!`nfb3#-/nt)zPfTjo8~@ \ \&0sg:wf<}{ďauN`0lc6_Rg3H&bw!=4Sٕ3hZDZkPCw)3enʥ*}\,N3s,iMjJDXo_/`~ȋKӫpCmd)kI'뇆rƢL$3&5=p#Z`cKYu3•hʹC>a6en]=(t4# 7̩Z^DK/H+P wz.c/O|w7d0 mQ,4&0#mX̯6O#yݑH/8ސS;.qin /-h0ܫfGU?ho:)x"i@ ֦[d!TB}oO / eeIIg1Xt)4P9~O"zoΡ A$tI?j.(65>0b+wP_$Qi̦Kl O=b]q.?'kp"2ݵxn[׼8׃O-qk&`#Lk%ً19!U|7˿:o?RVP3OYqHchq}mSѳ\"Qv97>[fTx]#fi) B(U h gq_m @NQ+5b &H)OR{Ǧ}=a:(/x* =^z2R}7WnF͆tb5Ҳ#>IL!&Pye^GJf^O]%^ƕ:_|}7J ip-6g?dhѯ,=B)W*آGYYEz7t//gu˄D{#R]W?#KcSiB8htakf4"-_UPTPe>dQFvl\J\vr}1o=3?أsZY79hC#dEDU^2}BURCy^m-Be20xH|Rq>mYn1ń]_ Cuj10tA(njJ6$}-w68m0Yu7 =6_ׂ}Qeh[QY^, 2d|%%w?\8g͇f)#wݙ<0-j,Ku~c`¶Pkz!o+M;^BҙЮ#+M#&;$ЦjԄ ]qQSme^\qʟi @C~Z]8h~ͱ3K&{W2E%yHƅY$Ѳ7>*Bd# $b,<\ulLo%2I"dB\gkɀpңY"sp&!]0qmH Ѵ?nwzw͉ >+6i& eũha6oJIESc\Z~ HGV҉ vOa]X p91X?/xN51z["* |e+tn6¥~=<~++C:+oGS@'gMcCl$G fNՊȿ&Rr!DLXm58XYo( at Фo:*={ e-/\: )En @HD2vDҠeO}5  ٠!,iL8UkF3e$:<,!C5׋o$] z 1sqg fExL=j~V;rkpE P.9 a-٘pUe9&&4z˷"̼R8Z,SEyo%[/eH}TrM[onn;|Čo#K ⥀n73G4 (K(^:nQH#5fFD.ڍ_^3)ZzOoG0ʰ(U3:=ln!ȂAE>F F 38ɒf5 (kW ZŸ< XBvxSL;7~ bIif{&$ R4t(MㅼiQ3l>}ܑ6j!G9o'Wh T-˧ 7%GqIlI:UJ*=Ȳ٠ 32W2+_fNPIi+mg\Yfd)iX 5_YR ofOwv }mV`$/S}0 ΃DqQ9>̚!16`Zw.WxP&Jf??#BuoU vc߁՝ifZ!Vܑzi ^aҀk8[M<U^R7]͇B܏UaQ@uТz.-F:w8QP/LmfRVITNn"05f V]Z)wW:i%9`a29[bs㤏Ea8g#^m :fM:"毸W_ӫdy[*[as=ɕϩi*'t>X\?3 } xIgYWOǺ":Ͱ&bUk)qPvjax:f~`'L_yVpz4E[R'A3xRQ@{&l=& vx(K҉H 4/d4EF#7;W d@3Sః:RރRf0+I^Ttѳm/PFO63QѭRn EU21yTzK\pd?CS%pG0z oD`nFj=bݞU'։KưKqv5Beắ p\*%Qew3T`N D/OK9& %q:2ZP$c3Xlr뉕q-m31Ye8|0^\^ݴ,îO:8孺bR2(KE,3VxIXL?ק@_ugf+g %}EܻFfd2Ybۭ-X_Zn{DּOH 6o~lNsQՙ')ȠAiz.7 ~֧g9t¯qZ"O5pP%-Ka/֮u @T ^W^o3C5F/>ƃ_qfŦ#?O|oz(g>&>XVÝW&k;`%_1X[#p& |s;*tN9ͅX1@XoL%xb$X\Ō-y YC_"0pŗx~뛻tTu*Z.$, zzk |^8Zkfo!4 Uq !?4zvJs#?lt` z2?Nߒ3LdB\-%CՂlgV9b)y2-;7q8k Ҧ"$6aV3Ek ƃ<@R1E$]Ki- jүXg$dzp[6ӂN\ʜfWtox){i18UzJ+{I,&N(ۖ{M< SGI]@T= ~ψ"s&$z=~rYxP2_rIқvETh!/O;-Ѽڵ $G9|: qBGNtŏ%֍)8WTѹj~fʋ`yMA0m y;\z"RX& 3IaTODkZ4ld`*.zwn_殯 叨ܻQ+W m)s.Fp,{`8vnu0Oou>]I484q  x Mz2H֕N2TQ`^ 1X uBpXӆ_$aW*NT6 0+;N2WI-}Uc[,5tnxxS3%&|sf4%K.(L1hrZ ◃:\`;1yk-3nB(Xo^l)^*Q ui'T/z"ah\'ϰڞ$[ztW)ZЋKqZdz1І׎>kq/D 9eI];ˁPW@ ȺBjH(|_0aٻWtT"mt24bk?LH6y, cAYlShq!aؠ4K'(.54b˾&:~%crJO5km"Z <)w6eZr60bR jh&94=G56c\wͭst*%c\:,C<.=!*%WAJԱg) }*."J{;=8KQ!?e U9U2H~{rRM#]dfchՂf ܕUd.^pI4"a,8;2بn7zpZgEG`KO@rưnI!+E>Si5UZaCg _)YWؕy1,v;.gqU~ݖߟtDݜrN])`rԬ 1k8MEMzb]@boƫkO/J։F3Q ל ˆ`q:5`/=w"Y1Wa/coO];rX,L~ZC_:^*YJvBfaBu,u9TU1*+ @͚fScFeE0Cm?(/;!76=鄼&tNAH ԳÁ++Z+d9&HFj1_JS2H*bH<&\L.9Z tD}5סJMz%tƴs6=d4Z lIKNr}n䁎0^ ux*3L.,f hC +gd=u. [DƺQx,7x_TF3z>H"JcC "ɓ`~dED uK6(ysuk=r'65b@gzF>Ulf=8(Y ܆U@1(xPsdDə wwFDK>-pQKJ heK>XJL:1Dcʚ3&}nw^KrD#$a(@}@/9c'O}?ֺŠo_LLoW=}DdND+u)!t<0f/6VV'h#v\İ4~@<i330(3wbŖܰ;77Ab!5QEiV"./r9M,ϷfH|U*v]!B>PХq%Onn-o[' ZYͼTn\'qZjDX;"/ M|6@ʌ|S*p=3ne8n9rJf{~ xeJ?.Y%] XWqǓ<1ŐʔFԸv~Qɬ9fy&q+giB+FAJ<\_zXjUmY}∆l(]RisIa;3amӜߧHX s#mC@$ì5JӇؤYm4=!=l`ŃK湠ZU[+NG3#,K2h$>|"Lc啰=yTϼ9B$B{6`i[B<ũk(jzJFR#Q3S(v2RrIJn!;#:'J043lHt1o&ӤPVgĿLqSם@FVݭ1[SkL?."bV2Tz$ E+mrF,da++AcGUܓtaO}]?uiH54JN1/ Ng$-]@J[ܗLŏDO3+#B, buGZGJl&!TG3.&] j 4yh-*y(ﴣ{d-(z= w2:LL%_X`kVhg.* Hs\  lWGO(EJMraz^)WQ#0 ]%+bR _$WWf 4lخ}AxN2p2DuKIFQ^3b5qZ a1"ٗ>s1+f4o0XQVĂ-^#` 2.Zρiws֬9nj 9dťﭝ-{&'Q1}8eH)4z&jjz,t|ǝ̬օQPm;2p4lC ٽ6O$jp^p% -0Blq]WN)j7'yANhz.ElY6ɽܡ Cmk32eYU@?e;ZT+vyecԤKIQ8TIXCL'p|'n!  4iqhnǽ 2"7.n,*"׏L_u X|_ +s[eO|zB; N6Ty F0mQF$ܟŝ~hqi_{k`\}M{tL*`'PX~q1'OD6'4vf;B]UpMYȡC>1''Px~A.a*,d:O]V|bi&WS753Hᴇߒ7-3=KZKvoMBhƌG(ҿ2Y}u+a oz]70PsL ȁQ@F1͂v" q{u3@w k`AwqK0G_1b^7oi1VR@ 8W:O"ȳϋ5KnU Ȱ:!;b$k~^~&A##񥽿&&L1-t|P/綡 wcHF_ۨ  );NG{#93!;cR :kBWɦe9=WiͣW`kzU2,0N]<'_5qeFFza;_ͫG<VV*ev5aB 9Eyf -*,`bn뢺+SV ̇Fs5GEɌA!(<}V8K$=7D] <;?=/36~tdedhI%F+9w7Ix1QDVއ|5z̓CMRAaE(gzi$P:`3m3r;uǏAUб1D$k3`r -y_2rYyŀUO |D:7JS52C~szxe.^U#8ܱ)Y7FB%+|_߶GٕE!lnC&I{UigZO1[g+zyY~%cEDcIh&$ͨp=I%y T<B$͋LYP2|Kf!U!g+ /CJuJɁS/Zީ6"2ʍLIuAl!D\ȴ@@A[:aՙ%1EhVp0˳nxB;ZBtQ<M ϔq8Tjժ6S"Gw,oΡ%|c.^hVD,x=IU(u͊ng*r )=Qu% ]6n f,=ϷZ_ ޵:?۩7m? ~ N0՛>, OiFQw!)U{b yF7F,Bސh}o^q1bShwhS U64!c>4."_W:Ehp&E5.ey}ᵀTuhIzZɬ4i{GƽwHTQDCVnTT%q3Kb+F4,=n&q1N^IzkeM(Z^\ ْh_vS[Z~>xPm!1!@iE{ mGXtDeԧ=*;1W帊x%@0+p*NGmB(Է @^ř$a5gB-5^8~1% Z@ڦBsL;?pMEl`F9W8~D]L$z/,&U L< QD33rpe2v a!l璐JP/5p:Cl -gΊKDF"qA5cjzSB)tqvq/vBǰ1VcRbLsb 9#L+NtHC[ G{O$dPk6vݠ&O;B.MgO@n7@zU efL6?--|Cm5c*))TlB|Ю΁(_ю]qug|߲s^Ve&ˎKH8Hđ;HIuODu W&k:.q_rJ};ߠy]xQh@c3t2РpvY 9E%x&yw5aOHЇV?巠 >FdEv fPMRq!&33)sBI !Pc[%Uɟ#:4]=V{,Y[>TDaV0פJ/l,o8? 0I'oF*]7:AN` iG7GnMv}Hr9_Y-J3?3c:& 2B*$_{6Hsk>O ]6''sx8n.&ؾC_X4\ ! A۾ؙ!c* 1zu/i6o)apI }y+L^F 5&"BF0PF=3`xDߠ)!p7β:MޙbJA 'ԪAt _bh%CGeV$i(\@ P͝ȝar"! X@׎Tn{!d=ʂ@Ƴ̨Kvz ̩IL^pADS+ q :|mz=^׷}B"Isz04PiO3{y7+-Xg}4Nxf 2/8Ύge w.l 0Jɢ)|kmUʜ-lÉ(lءFédo.{wSv ,ɞa.99yy#58߉{.ˀ< U%yٌoOg)EفvN#HE2ӱr I>ʇr"4'}+*<9Yt8#YٸJS]#zO Z7f^KxlBy}cQpz_ؙiXHHY98KnTWIl>y Po`DCpu∔޻lX]kḵ`DaSܧAsL Lǀ--FtخxǒAcrH+w>%0mQ]0܆f봻Z/K(Sj,LX]̱%OPC5Z'ljcM"8k=l5He3*5-Y]+d6\I"?ofg !4N_{)[),ىj>=6e+TI]o#-s<%7e1>MNs9) (\rj:ň7L9pG۴5{&]}hMҕ4NjTYpoICH@B%&2DWi;x"6r?e}Fº1AsU҉})rt#1[e9p:q+9vw,XwA kK rlyuf6R8g Ь_ t^tIǸva'j qhw6MVIźⓙX֜*.\gt0":>BqVq2/q})vϤR cHlK(r#ᘣΗz>5%609UCkrbNIP ).Ȣ vb[~"BwrXH1Rf6D4~>QkPGd6  }8]obK\>[4պVދ \KZ|EtCF4=rc=Wnn0M&D>2,5Uoyb!?W3jNIf r+m±}!De=FU3 z/ qT&a6Σl+H/}Ri]۵o()GaקD蛍ᔱ#?Y%. H?L}@ݫ8&zPQc#jJw{Y %(l _ޏt, ;iC'n({t#~jEUĠhz+'גYOJ_f1m ҌM ,F͔IK YvAٴBok/?᯾GoeLvK:"@ehFy+-kQcUtI'\Xhƀ4 L;pkJ|JGP|>ZIl12'`9Λ` 0IY61Vqmnd#t[գm=кa_f1Ա@jE]\O'/~3NvNp]92DT\pg4 p#vX6?M& U/onv/& Y]1 ^wX*8g:cVX+8^p"Ouj9T^x+( U^ \ߌ+RASaLIz#;N +wvb[5m趂-4Wrr}}al)*wo't#%(McFxckEM9܎kxi@B)S`u[S ,ӝpS|v׮yertYbBM[N3_\rkMM|(ժmkۘ_˥9oJnE;:vh[Z3M>B _%վo>(v->P $ngU#y'ݷ}ZeP=Ov*>b,QȚq ,.R찥ֆ22-]+ a 8O-/V{ wyGyQke*6![^ӡ{2#RUG@P[(Gp^ma q6[S%)p N97(F">IipjvuRP] lŗK:sT+s}>DAu CY8F4ͷ ?5KΤbVQo614 ]OxCKݢqK1x+B]ŷ5$ayG,+G[{%~ǰR2ĘWJq4&[jq=cl\j46!eK - Yś't O 4jlC#Ռl!ϫ`X8IHzb.2D.6U 4. 80fYm_[-<pٖh|b4-qI]@TMLe'],|r.:[{)J(';EE6iUQC 6um,ҏɒm+}+kOH[)u:.!}=֢ۡc oFR[2>=Fҋii8laQУ֓vг.1+^G!IpFA*=Xs|p''ht$WB>@g,+ګܝ-v ~B~MpkZyQwQC};83ޕ- ΐmRNga\2h*?N&e; W{-R1^/'FhɚpzDKJX}۪o}E "%9,xTQU"e7C-=d48l]n,=!Y҃z'OdE?pTRoւRKnc=CtXQ}QA3R, +rY|h* |IVrf:xGH^3] ,5d]샄- 1:8-חVo8* 7 O8N?h݂$G8qaa&w\*.}joâ =x+yFs7o@xQLi26Ȧmv-=C:, ; 8 i5}1IKKط\oeyS"C6??$ ل f8 dh(|XYgQ3^GF $ڼs3.~a!ѓ)Ϡ9iibcP1#&HR=F *e0Ԙu߲W [b|_=uRdNQ 1fRxD nRY?!+G)[.?E6Uk/ܤzx dOa\ÏjY륕5:M O vK`2Rn7kfשTr_ #MO7+YH04}Xt>FhlU*YO>*&p g S49CdLp=HgX"ɽ=͡+0;{ tpC(9u_~r([lan4' ^ 2T9j%e3-d}q`גJR"Q:'S[3_!sJav՚/13?Mm٭(Uvn?V!:Qn_%TV3$T!eIu<ܤ7u3Uv +=Ur>2 [d)N2ϺvR $O 24n2Xi6>]`$gR{݁$h{ˠ]eY K.,q6363ΆlI ᡸXO{b)?;(n+vT孤"R7^*S8¹ mw+_4neU'o(x*YXG{;5RivQȼ ďSr iGQÅ?R+ŕ؃ F%RzI6Rt5STLMi6QĎעnPn`$Q0.Iuj@~* !Mh ˭Ax]2f Z[ t_&Vy$,wf^ R6hwIΈAxD6Ħ@aݾF1;M^/y]UK&O7Hm3eߣhЅS\`,@w3bV9)ln73 CL\ +w8"n /u#st4MQHzMNšXo(J3AO62iJru 𑄜h-Ӂᬱt$FYt8)bwXl-Q(UvMr܂]Ïo݈f$UksV.SPƤ%I,tZzԗ 砥Tq*D~$D$ 0sƊ:漍%"1H+Ǽ_i?Ե][ MR^]u7u.\c<ί3339tՆ\V߿|?ɟ(g5B5o^H`ѭ%y?U  eJ 3; 2gfH RD~Z$ҩsDmsh(ob>M~ T3rP*~;/=U&ۻagW!DEPqTó/I71eghNC6+M W.d 7.lg C뉔ޖy2.>(+/s1dBZ{8I(5F;$)xiZ?ld)VX7$fsc?($mJ.z&6sH?A CdNwB,WHk!!׸ Ex>e^)۸Pf[GKFXuMi^e(9EqK6@7V~< 8z2I* ] L֑w0v+ Ң!X4do뛃,=@ȗsnӵnD3(hGM3J(sP>A: cUZZ3S"٢^ YfggGgprs + ?nV+p"fùDO]F8E>-w(昅8$XF㻸-(o FMI$KKF+jߧ\3< 3nK/Z]YAHC7G䍽D2~w ' {h@p{I`0?@ uya~Y/(bEC ܪU!/, 'hmTuυ%e+ Fk#͉ 0wu C@px;YV- AZ1īaZ8^'c!*1< +5*=Zʎ8rҟkhQ54j%9,c,\/w. LqaF@I6jܸ@ъ(}TZBsJ9Z1S }Q a=Y "?&k6S-ZpܬP ZF8+;pUA={z<%ކCj@iZ!|ǞhSl#}UCmBgo'IK05U_8|ƠA>:DtK0RTh}'EEo! 8 UFC[U1m@| SK" VXʚA>qq?'] .6@M@kڨ-wR78a;DUvN]Pr?vE%Q_ZvA5yb+;3],B=[=:D&#zT(F}!J.~~ŽRMY).: d!_ԳB֮B4 $)ɐ:\B%ׅ^ _S|qaHO-gGƒORؕ",]j+MOO)J+jA){Thʌ3tXV=qTo>`,(bb"C,`7/pj%4}/!5ѯ{tp壁/îؓ+"m6f@3ciX *Ig+-:5 Xޒ,6g)*W֮gPtQu ܹրwIeZ6gBoz'$sAIAɷ(wkwQ(Ȩ.ARB={eU%5ۙꄮHz`By5T ͕6 M,}($n VҗUcD6 eiQR3Q˕;`kiIˀ-Hb/=E+SDQt+ Ϩe^ }Z H&gQCvKMEU?zopUi}.Q{8j{}o*( YeL_p:3YBgҚr(~U } q=mgk懂~'z! GؼBV;GmI]^C-H}brrtVm`B^c,Y島Vp度.+T{ `l:{6f?ʬ.z"џoa`ֈ oA _i}C KG^-ۺe2QhZiYAkY3cl\{D;ӂrIA.8K0" ge hfm]0 A"^=IXjѓFV6FsID^ V{Q )yۨ or(@2^lB&0v"AXS]ܽmЍENqDu+pؒ/O+m-(U{Uw6,~lB7]]2{d֭(S>, W;X87KR783r }Y2݋AI QDo l*(? EjC0};gWA T/俘"o$'vNY }xyzFH A8݇E9,!S0ɖMbPcHg<(h8haI0n=5ఙĘ;eFdLw2!=JbSdjYT8i慛ol5gm\>KX3Gپ4qT:6tRջuv {w\ 眇Cdq%˵}AW㬹Mp(W؝ElDBo4u%# *}]Ff 3cbH8(bs>>uBt%Qp!SOj,/BHHZ[ y_ B"u%u7P 9ZiygؼJ:*6$U'OM8~Q~y N:O|nRP~rPdzx8SU;ۏP]KX|@/QWǽaA5m`4$NvV_ࡨBagQG*oB䆲/^p"“ۭ=1ﻵi3!޹iC4S(#( !z&-Z]m,5z-M:8U=~P=&AYjTDYيDO ʱeN`9*n9PIAYYxAVqg`G2ۥBDw /Z p/H۳uB^S"fʻx?RNd,'ld wN::S_/^ vML1طicwew^L?zQ]5f\~s$e~õbߡdZ` pt! 8}ޅ"$^xOy..^y)t>Jmj &ƣeΨ/;fUv&A8V)atmKgrbCra,3*\s(z#cc.qPǓ^ .Ƈ/-ۋp=Ea Rlہuw2 ];?&Y=)C D:.U?j ^iq$=:ٝ(, r3Oyz@Eg&h/OqU}GwM07x`тΚ!L 0wԋKAe* $3.2`Y&JFC{,1Q0uc)H7M0qG#M}Q[:.^ |pXT|,Id7F,\i\8+3kwAƚlc6.Y!rhK%ϖJ^a"q!73X@Wq[~{dT `U0eyJ-ï2a MN(S0܎VHgQH;.3?@]]vk܉Ƃ`\y"!P >|*z{f3aO=#J9Tc=#y q!ujh=M{48VKK"c4žoR_hWMoOϘo\O$0ZY:ݘ&x&2]NgtHiqf~Bҍ@½ ijl}ͮ[nT1TܻlWvd7"{qV3LUpJeb,&6Pa$h0gY'1 +Cyέ:S>'z_6yW'p9-x<)| TOt#uC$kp lb+~)[ b~nq;YA!fM}>g @鲺EVh{ڝ=V=@͖ɨj?:_B1eqlu3.QDt,4RRH:K:u, Dߪ8}dbޡ^k~%s[.}JT<kt`"JPnLm^u32W)z}YR $$ #u/}HG,P^$OKYqȃV!~5baW~ n:)W愛&Y^AI-lfþbd;UJB,9 x⤑p'|n̞4vL\}o}~7A{qVQ)|71 NTy3ʴ寚{2eI/:rVbWtF6<[ DEf\:yj``<%^G9Nr-s] hzd?^e&WF#ײi (xπ ěd$ x`(zjd'c|+bKDg}2h!G˛y׶$N'4(dK[Cs띮,8tW:2vLOí| j0~oi|fs.…%f[*S~h9 _ Yr6pX?*I~1>fA"JƥE9?. fZËjFjWXrrxR]riAEN?OԀlCpAE*]p7:jڽ9eR`ěW4IeƔ!wM,E\>#4=ſ'N=mwI v F~2YՒOKÔ7&L/қZpT21lTQ.g.! oyFt_);@4#_0+y]UzcPhW-MVBZy?VX2֯(V/w<)Q+){X kVdZ$wGj:N[պ?n8} T,@b?qс572ue6,,;Hc'S_2Lxb5$"f-R;b-Q3EY6\A ǐN,9ww V4!ed}x"K:fk`OE\P]k_$u('=hVy$mW~߇KQ(;`xa՛@" 3/l~i |%ܟ9Q{׃ZDmJ0]<;U ? 1oOnoP'8{\D}jHA.i9ȣǶž&04 31m$UD$vb2n7#ܝ6CV8Qp^j+N-Yrb%mBe4CZCuügl:nObJcOԱwzFF݌ Lj'CoS-Z8!u^0%R>g4ъf IMjq5P `-N2T2Q,44 H6f~3_yYsCPlerәpxF?pw1f3Xx@㻸AQbutEv[ JCEy+ViW=N9*ם!\RQʁdk(S1cկ BA0-1ݹʈ#R "LkDZOC RFcӬ\oq.xe#2lxL)(_V F˜޼97cyrQS-=yz:X%+]A9sI9?k5-; Bl^>M=)ǰռgqKmrsP=$WrnK㚹;F*&s@KRX$;hmǢ,|Q%UAvG>4Bܙ:z~!9Zy<\E> Sxߵ6&M a{qcDN4MkާXhL>%ǮRnӚ3]K؂HJ/-Gv*$nl&|9u&.N][ nU߲R17T`v/^yC0jvdUȹd״l_ޛs)Wb(Gޤk R}d`;$˙" Ղ\Xrfr,|/{:*&jEZiI3X2p5,J["mgpB؃}njo@p"F}eAHkl CGe%EA*I1a3kҞt4C]*& uH*9,:kl՚pNq`\G$`x,D9{]a%2_&aM'^Z@Y V|q;y[]Jg^`ԛFaHkG=-%pMicT0Q&4S\6nJ29j0l^Kh;4ՉHUJpXn"GC^ID@z#hުgwgI ,y64GLA<-›s5L %+x.PBRe `}k}HhU0zjL*>$")ע|bOo $ 6/A/8TFCcVw#foXAwO.](LU9?$3{7ʰ *: Щ+|u[Qϡd154ۻq/Whfd/P䪐s qYv-c4ܦ-'5=?]"<80; b~^t=Z1,^aGqL@BDf1Gy<;] ګ,<`2`O|'l/vo쏈7!7]g": m,?̴xqݴiMӝ@ӨyW]kd.S̫rZ<b]?|n`tkp %r!CXTdžܵP E:K) ^)DV MO|cS$FN<LpԖKn!zz016X38K]xUm|$ߊEs/ZI tԘ_~Y} |Dw=>880z.)=?]/<*0|&;BqJcyt|zF0J>Wa|4kNė-̓Ԋ2L&67'E,@ j/YzX;_TAQi/lvʢ}.k=]_X9*jX[ũpr.nu()}l:au-TQGr/&)Z^m iհ8+6uNȐ a_b#ĮV:ϺwDF,>+ȈEG~(_U3,q\ZPu#[ 5y%C=ӶATf^9dw̸ $-k1ҟɔ"8CL\.#EC9 ra"qt4Z+ɣ߆)jc ߻PeAQ@CyH1uE4q:5!.8Z-;CjrdyA-*^׉`Ž>Xfe[ʳ-nLcOhQ=%nmLF;K@3$-M%9:N5#{Y!nF-,rAkC\GfMиG!/: ;WV@A%6 *7vp)=zv+uE ~i{a) @Ӕ,2kHw aJ pDi>.)wWl[d:C`zaɔ U5Y-R͕`uԦ: 5U v8i6[=IΣ1K,X3cfJ0vCqo?L,F v{p`U?vEcR-弄4eOm=p3}1l+?Z+?q) Iɛ"[DOf?'trzd+<1Gw" QrU63OA_^Ľ{uHHLՍ $Rˤİ3D&B&5SyhGݵkf_~g@\̄(7@xQѲ>+>`\Ϸ1YH PSZ:\L'\DM˃M rKy?ƛeE4Vy),*ĈnXef6ŻqkÄŞ豽5/[NssG4/U#5bo^y>kܖ8-)p;&BAQގӫWsW[+y41Opd sӠ@WrNǯ/uDۍ :tGA!GEl/TQӶr m(W$ެ_X9K6)uve1m]ѣDEK 6F+ ci\\]ԘةPXE$A]{`MbQIX f!}{T.mSי+ *+ *H0 /:e"YZ=j5ִ$FH]Hqr 5+qE̢pn8yv8˄1׽=lfTQD^M١4N ՟;4Iib@xk]#gJNɍ";؛AWw=EA6F<@A39#{w"%oOeJiڡzºG-ZSwE +ީE~n/k @5Th3ȅ@![ZUOI$S S@Ar#3ZM5涱6$aYQ Q,u}Qex\‡*kktRԜ^y #6潥~I8H!3em!Eh 7YUHh٣mBzµ]f- $h2w+[>Eu7AJ zNJISǩjp565I=z(^"ΪهB/2VlNLPk,F\S4-Pl5MoP7&H!'5t9 dCW-տն/Wc^ Pt"Ў2KJ<]<Kj o"7O)QOoRkVi#Oys?Á. A7W2ixzkΏHz!PT_'mבl$]`7^OW{7Pm-/RmPu>bK4M{vA[lzZ4Sg\o?ޜݾL^MCe + 2t]GVWs |:xf)\77xT;K5ŖZKG_fvJP\9rqe[~/YfQgTK}5X!yQ9RT׳ Q^%w|l'~4]˴0Lϔk oEZwr"tGЗlOQr7v ^sY;s[,BO_YSuBWDefqHrD5 8F4khRM(hqx֝1Ͷk" toEɨJ갔y}V9~3&5=KZטD6+`LYϳ50 *?{''ռ=񧍹f;#EYOt,J~B-8Kkɗ]rst(.> V< zW_X?0#=7Zl]{DF" 5ngv*E-sGMU q515"f$੖5c!Ug"_=Moѳ%Glv3QJ۽x׵Dc%s"wM ;'u'J}Yl'av?!?ZY~']C\N.p\2Xشhw'4͝Zs_+({A_DS[坰{6C\7KhTO49nʯ.H=7@ANϳur+ %#F~aN=wekî.1D2CDC4ONL$Yd"f}>yWJ+g0]> .2N \<+A/&jFV= q9+y|z{zrB+ƶ/^wLT$- `^aozQcoQx(v1v3O|GpF?r<6IH}C+DL}.{lY8̔1cv/)'>AMpM^EP= , @:2>x{pk,Wݶwг/z*cdȡ)$3il2 =K2.Z9xl30 lOqdp>jTx楊( o`gvNB6u[l_LŘ+[6~ 8Zt#uAO6w'g7T[zV1f3j"^6B=35a_HXҵfgPqwvQSHƺ+k9" 5͂cFΈ$Lr ZSpîYnUyp3+NC};2T'FXn9ɒWcѿc;^={x=GI"C4dJwO@ĔxlI2 ()+&泙f:R=iffX&Ğ)[ O zCji!kw_C< {' z|>1Aǽw5Z_UġB\ -ډ뾏Rw=QЬ\wz)BcaΆ8M9c;Sw(J?jbp<ȟ"LptC=iC hu/MVҊ"ʾ{Dy$̇L7I LY}C7!5a,43ǥ}6=yo!y7h_+8Q` { O_W=x]w)`d4r@M!͕3P|!E8XXl+sOűSDe6uk/Dx\wVMg\!M84K`bB?W]ishL{xhsSŦ X (St1gxC%L`sAHCT Ӵ+9hYA\¦kl4R]Wx(Zf1Q#ij1NB4^4NfQuTXTfJz%~&;Hvqx!`~86-Zy_`U"i)R+=E_9+o !~Μ6`IшVh"r )7@ 53wɿ#F 3!zoq]oPu^3!bP9CE!3yi{y|kCֻȅ,8V/kryoz U-[t xjD-]}}*(ڿe#[&GiT@ڠ ji[~OC6 fħXh %}FQzuJc%*\B!(|\] ]oKFus|L usA_X%̕iS2rFSe | #j=lG?9҆QMY ^_xvcBrOEkʷHBgnn7] SǢ{P]lq s؉U ]kD?g1X]S[`.p֙J't{*)(=IӞ(T7*B!@2]Vbu1|}纷>4]ЗCّol?\ɩ))WY# ifL ݝ]ti>}ALY#DN <[ifyXJ3#>&Q`gLn'v&ybU*{D7 !7G}7NI+LRDd,9P'>Enb3^mm#o&#!y/Ils78EulJi:fR%_,]}9G}D- k0AASZaCIe(*LCXh *& % DϹ !fpW,YOӠæ$^D.pVP$6voB+qN4ڹ[;fL[WÑi3(.;ҼyB2LQMK,{[Z$%eSk'CE_e"ꧼ |J妗m#h}^W꟢7v)"109$Giu `h*;{$ylfR+8oIU"8ESg(syvDotR(E =H|Lu|Z#YYUBqOd+ʎ~0 b{KM !s%$?YѫOYVRst_WUu?fpvoZxmbW:I^Ǩ,"PעYܳ=xtd\.:^ii $rTlC (1oQzjS{ݺRc|ٌHbpӃ#ޠG !^Ay'+_w;Cxf p%'G'%xۉt5G7<"Zy9&\|]g9,ɚ6wu,iB4Yzk=I(;( -T4C;޴p"*MƳT3%^Ftnx +'EmS1# l}!2}R u>aCQ%ֽфR~>KDo5,<{𷅱}Rw!V7jB]p#Y?J%b{kF<90P_\/>!Ñ80vM@="&AQu&i,KګcG1l~ ?XK8X>.)ׯ:˰$Av C6s0ZX3\KeQxw,9GBf' nJ -+8NT!+j1ho֊ c6T|? ZDmm P|s ڰC#)!q">KbވagӖg?sK JI*/mQ]2ZSԙ0拾4'f V:q%rk kz{dBt0Uk'nO?dM 5 u:ǬʴY')f}ß䜰@VsƄ* %bs=HqxI*䏤dneD>*<`m&PsyWCY6(>U^d~NRfȈ/ԧ31-[C͞H4lr?.Վa՝E<ɟfUs Vb19uZ|Gx 7pB"*[gQ˸FVfq3Sk'-yǀ'Ʀ?'OKQQ^:E})CE8#J09Md6C``;^A5=孿XolK0N BQ|w*ARB& `6qrbџq4q#MNCݹ} vf,wqI!Z@ }~xaҀr2j:Ri80  F9a3eKSYi-ޫ avVv$!\Hq6κrؼ9\ `N0&`c9Tիygp2 bKMG&ZMryFY|Nټ=XL7O\$cmZ7-IuRQNJq[;߽Kh g0q(KQA#`ܧq#-i EyS zouUXOcBfpTE/QQ f:4%g(kfJi<5UmOn5eȿ6 !CL1H򣼇2 fn4`A/DvP &$H];GVZmVu . &-|P& ,F  mL={Svt< F7H % JhgiC|JLdc"j2XeMY% qTmL!]Gnˌ iTR^|!ޣ>ww΍Գ;t5U1,V÷L9!47<4#q;CQ X`=;?߰aMA%,Gee=|1.|LVBۛp) ˩DZ4䁓:z<ɷ{=28EEs4n.8M}N9@EH&{mjBR'F-+3y 0c' ѵeV!?HNhԥf2kz?oF c1=^4Uԗ4&]Fe7qKMMdzW*f=P7,g@&4 VN /nWA7-35l *I_XR>QݫeѸ·ڍIgj 9l^GrtZK7bu5/16̄w׼_r)n?w}9(yJc#egâmFq%ѴYwbG{ MzЭA3aC,?c;`nDN1rmPy۽,(N^l/Ϯ}MR<08tm^`T#B r.RGOp$1BF:CB4OLLOeJ/bg 65u3ŕˑcRǝ?ꌫ,$Q e\ð9 Oɷ}MM@?Ic3`l_#hn0(} F0pv6^Y /U+C T|)H)c0GK({k#!`Y \wFzka( .p9P ʂV̨MNP&Ft-;u*pumS0p+4$BW0-1xF_eE^IMa眇|R,rEEfחIX%"!@>c1+It sv% |1msX[gV`أu^|~F;p.f, ]VA`#ZB}>7eftdTJd9EGx¿>ϧ/,F-W?r.Igw6] Ͼh. vϴN7w.w/jBd#xʒۨA՟W\M!_7Nuor_<Ю )D;u){z*Td Y(.~nEͨ'1 ~Hu~s(%Cbp=Iq:H݂:K;sQ Ջķßm;ǀL˄-.0 GهsZ'$ o^J5mM@ X25sƋq靬O:Vr{9\%Goh4CQ SQ6!0xۜ<0Ȍ Im{FȺVD@KҊDH٠XC%?ka.M/3s4᳨\uRfmƗ21NF~s휬R9,Eb>90C64IJ".hl|L }&W=A0+f@WG!9ϰ6i{Ԩ{ݣlqYϔL_½dѹ$q$Z?WdWHC')c_dU d^?oӓ‰NTIY  0q[`MdIDEiS kpV*' 4 A\^?+~Fa^"cvC|.X]~870[>d=L?Tۖs%.Lńk3[<|wr+?ACdA`7y2Jgކ4eq5H` HHM⸟ts 8@(u9% L>B8qϓ˓vPw=t.Cޜҧ{]e*p9 nA xۇMj{\a=Pճ9cjA8x9 W7qlΑ9ݦC'0TzDF'dm$ c3~xINg(85PXYO5է-7= _-`s Apʅ&w_ .O9+Ak -5gV2 ̓EN JR^dNjd֧ E!kS󍜉?_z2)>l-rs5DU Z_\ wzɘ<@<U, nn"ӴpQnG?&%6δ W^GmcY4,W4\VA܅PC⟵Qh~0=@( j:mi,Pb };7Q"4FQI`X6hDA+e%@1d"#)dF}-82z|h0hM3 V Cv/Y&9R,|6*lh4 ;.aӛkjN0O-j|5 c"{tډYyXqg8zerPjGqי4Ok[>xc:?9H ,ID<$] OFkCZ}0Q?f;MKM,y?p->#Mi ӶNčVRgg O]N\d hrHV6vA *hNߣ}[E}'ЉPhnAW,^\MtBtRe|HӢ>T4 ˫1X9^= -=\G8Ccg; u|\xQN]vnԻEqd?㭪oZEr6FS-9ʞeRFHyĚv?zйf4' N0({\X)?՚nPH_Nau7Q8Lxi?<_9 Dҥ.JR$Vx !*3}`1}iÅb>b` Z݉ ,tmj-0 Pp ,zmsbuV[mA>~pZ"ZuywaUI/Fo{b^LK%d*'+Ub>4&c|I.{+ϡ!S+ Y\6틷.sQB+LFM>ZKP늉(Y;ѧg^H/ w7YVt]0#Zy<0)"{OZDb[PH@H(60.8xФ)fe̼N`{palt$| pQcH(e5߄k> Rg ;E6gWU1RwE;%| MH;mhUDtuB@%v L$Y,ut˱<9ar gtb'C8KJe@yd h>^m?ǎ1i%^Oy 7ĂCIp7_ ^7e]T'ƛfx/YOԋ27x_wn|$^j g吃I-J +CQ/b=,F.{v+.eEI,;x% =r N+GQ*' z@W-DQ:Qֹomkg<=[5"HaWE2[gL_*A)Raڄ),7#j:.cXDy&9 4^!,"-ri?MN80u+7'Z09il]?˥="c.*{ii^ΈKi}ʓ-z Px%l gDf "Yzs8m7"|1wJ A#XU*olV&j*>@-KCCM4mx {ҷ1G8i2Fc>LW|L㯿HMKF{@P,S8{cAbsjHO`&(?t[0@Chm+IejEO}u ݤ\f5lʜ*Pn_b[ ™>@h6'>v8E(eq\m0_u~a=yPYn'hD;2 o7$=sfS\x368`Gw9N\'򶜐B }Up=N3`زǸB/x]|4b,sJ%>(YW;+s%cΒ ewW Z26y6 \;v›g l+X&(G=Jpvb}fegY4kt[ ;k&[tk]JY#?K?I\}t3xPt2 %tp/ Ԏ`.a?z F Z\S߱Sџ̙w;\P/9H]} "/IHk,Q>3MٓC逷 bo3A@2p꧃ e5 i{S]kܐp\s+MO"NM} i/f[;4)>H@akL[=bà iͿU<3N\__G D!.!tTQw6KB'U1j'X4ϋ!8gF^Vw9Of꾅:Qߟ85CS, ;?>Vqzc\kW<[E?€eb೵.1if;3j޲{Ւ (![EVѠG&4y#ihḯwQy ?,W=$hfL|@`/@9*Xx+= j8{6u89eoU'(,M#hFp-`vȬ 1t,qo/'ϡHn-Op>d/O2}ɆRv"0hfgYޓCpA $4lY0'*.L+hxy!*Q [\:+ki&x,`NɁa$v1zy\K86Y-Z&%vveN??0!\5bPߴJ aye*bb6e%-# RP/ܚsy!Z.rJ%ш!Cbw'$sLPo;b2~{ntNhpRH.'~L:>Xxi\)qt"ȥP=-Q.c e[FB۶I2 !9 3$ DU!4 'I)d .`8m)g" "Aj p%Hҍl9uOzwE([TAQYуO#Gvf=%1CВPСVG҄Z|#Hst~RcFƜ鯦_M')' XAcEdžH=3o]GǤ~ a%mSc%^C:h-HwXAcbldso8ԉ\`H~*ݦ<$atC s U2!fZ iLAC6olNyS۱o#ecxzb.| AycC$󐜭&o"2\dşw.%*]WcGi﹕Lq0I//MqRu|fI˨j\[Ev Xvl}ӭa:$,>],>E}R \k$y)C@?1&cS"5x ?ܗ e]|%fГ%Yϸ/c75ՁIo|1w@0VKL rM[b<0rry3KĚ~jBEGm1Ko/WlKwa[ۑP%KW |/3r&c !IJ~/\OFl4AOQ[?s1`1{C{hg*oH4Rtmtl_gNdm@K]L#[s5/ r5}^F?#C/}D>ܓ*F o6fJ@zFr;PLwBg&P2 dVVE l&!BAQg^S: UcgBM.Ç~|VZ-bNxh-- *?4xp{ؔ-=5[dudD8/!B CY#%ș&OjMáHsP.*;|ڶ׺s6 =X^5/qMa+`}ڣTI*5.#/ ork/bgO+/a cmfc e.b['ni{Œ>*ƢWH2^*W;F,b/*44NW B.fiU΀ nʴ[cFOOh:m̚HeCvH,!Sb=MIRG c壉Xur:?u[\@w=FIMlHm8=zS d43Cɚ˛j#c i"??6g_P%vDC;pN"c`:/u7dS`A G]J{[?"/x(01;1mepKXYtF1uRR%Aʧ omc|sID:^r}\:!F\|®lkrRs׽2[lX|W{߫fp o4ӂoY`>qnDݯ{2<e CF6\FjgH/lR,vi&XWlS*?\Aٛ]GFJ]d<{3ٛ4=Lg nQs|.{4QLߧ^uIyHS .&1;+FRJ6_l>5-Jkx\M V,qoZ^q+EN:n1o̥JgXu?@ jM' &8#@Xvz3x8o<[ mymC!t'kpoxp_BhpZ$vюvOD]Zu:1)17AiuJbGXsק[k!:X噽"Sӂ,Cd.PtN'6Ud\"5=Ii& L]j0\#uub{fKe$=YW,ޓA̷֯F!mXA4vo[%k`` %߃ rP8 .gpBMCE$݂[]nNS< H[_¤"P0 xj:/dWEU>1%hB܊KgoB@`:;ӭQ(TO~ܨ͊.8(RHtg>)>jN90Sbw22 rWSĊ0D ;Gh`%ϟyw] ¶ʔj.8ޮ:I惴^%ҹ8@B_Z+_<"ƬŎm{GB-@'7XWg0.|.;p&GX䗰^}S3~ª鳎AJӈ0t`M7@5jKOWvW)(Z}E ƤA ,Tk8n៶^Z 5hkU* SrQp0oΠE =U- |z?C'n ,.ԷJԙE*%E6֤沱PFVx1ʌ{|sfxE#]Շ-'|UŝC19CO-IӅ0HW۰.эpTY^LS*`ȧ6o˛j y jH]=az|˚+ZRnE8=t~&6D9$_#hi{p-a4v-q[GtNhK"5Os}k0\La{Q C0]\vy{33]IFD {.($-V׵xP@ALyV[iI1_ٿ'CcCiq]0xVD|H\-쎠a^/DS6E&^GU-xGR }IajlR b-BNx`upo <5;& YWCal=}4{qY-nVQ/{6_=8Z _d2Q!DһvPwUnO@DfdR)#@uz[# K6GRSM/NH9Xy2qAFB^n0|'' %;.BUvr7/TYsF׷3rTRm90#QDyڇWI0 vV_Q2В[&Կ[}à8<hpU4H]/?m+.q8OOB5asB{Z&ve Kgڏ "WۜU"O;C}y%un(%U>Vx^TL2A-א`BGl~-Q--v'h19%xлfԢ _ʂ1#B|cjpw!>p-J`cj$}5 z?eQZ< j+&I,F(gSL{$4r\ >~gՔ3jupĴ^ .#AdY8)*ҳ@'\R~wY旅Zyed~Q(g¯fC;{SٴQ^qMꕀ/v?桝 >mO [G-^`$"&|;Er: 9GD۱o 'WRn":Ēqws,`k%'VQR,3('UBIJ^I k4IRcٻE%@Nm b۲2LIlt@: .dPJfD!xeOR-p%;v KfiJNy uH!^]QȌ>>to2Ozfk"T&G!dǚEG,B坣! mV~H ^!yJ)5*'{(-h8S3{"TWU#,J^!'84R ŒM=7/8Uh$^h&%? h EDC,V2z[zkҀ° Z"e CAҳ3z{_į),8 r8$*0M|Ke_mj2 zY䥠-w~}_K9G:k~,&;ҕ<.CSw;4B,q8uim` jWC**6ـgEo}Fwnd$ 7ذyIC w8Z~zpӹ-gqP3R gW)e/_Zjbgٷ)l+X_)؆Q9bsxtDz,łHb` Z1%Wx~ cȊ@lNi:l?TP5ݼRzmVxu*Ft%D] 0c0q6=n^=vP1*?p> ȩ.tFnR#~Ͷ-Jzyvt*SՅUS-pWj ,56Q'S%eֵ}痹o_wFh= q:=Bm~oO6 7!Fj u0OOft*c?[y4l-߽)x</Yz-PuS J=)6\'j}HIvr'U^Ӟ #=CQK3ETF1] a'YuĻxwRvL2ƞE!"'M0mj  6ܲ:0 b3UQnG gY$~vZeo]nnT9 ^˫%\oPj)pDF׼(},U>5JA9!]2bO3(GCm>IpܢRuV09m]A<`>=Tq/?W@'9oMp%*>GENWW-a`=ν 0MC`!]lQ _'0˜ YIs׵R o9-Ʒȕϝ*7 ryT4ikHdN6Ъg6$Ú!48`LEx-ac`\<_rTۥVC1|YYЫ?lb"akL.aE bD",gG/$C0g '|x-'27ͰnT0~'V%TL^-zRkذ.9f-j> !4ŎWq^W!?]:D^#k#t/t y3E$DtHd&:Nam?BKEV]I&kߒ&ɴ|D&ƚ@ W H-0sU)n8n_ ||Λ,Dm'piwI0CϺrz= $k6PqwnNj]?{bѻ8 >oP>mji.6ǪPvZWlzi] N-oAuiA5P3c^ZGvo7ƫ*h}Ċ#ʓrFQ恱b\E)>A(;p<+lě$)AOZ iT`=Tzˊ@?z/%R-fy}TbL5I6Mn8#sX>[0 qDZ m^py!1+kv_.81ސkR+@,ԜO!ޘzM^6:>3C]CU.kaC6g7mPRxf3=gNл WI_zRTY x &OD}HfE|To.ޟ̰`4U'<ɰs rtDF,$Nt/ Eqr!",I9UI=:=7mY¡uH iR+]YQY)/=vih,IHy_822UQe~T| 4˺m'S.dO¦d9.]J2L[Y`ux _1 @bl}QBd9g6*0&,Gcڵ~&Cw(tu'KJV5{NecݐRp=3Hy[:d)`;P|3BpvjtƬ P]m}`\ en6 3Jae"5)C~K: dF^IKMOIV*]P φ"V'*pdWAtx5c[r#ĭFIKyp:s7.9qQVBM8$(}yPBNC*S{"ZBuZDw'2+ţqraMNX(;,PdrWgvw#B׎"d4$p4ڎ-qJr\r'Ntng@8Fe8MM9p-*jix]ChTɘl+Lv96ꛨ-`T{Ҝc#!iu2 dO}́! .be_Rl zKcA[x4Q*ɐoU6ߊ75H޲s[>p):=y̭k8AR߼ rt~9͋KwHټN| AvmqVq"FaR< l,NJ@")dחeF';\h&ɴ]R2Bl^^~ 3aε5a<Ƥ̂;'^t?]jFم98ܛ&/:EO N䫼\P-P()`;\hcqbض}HG\)<=,0E ćm*eS;FuRf#d6@ז9dNznG0t5pX0>7DxYcTv!e$y| 9ƒ #q'L+G .1wዡDV?#3-\bͬ'1i㭌'Ur(St >E?83&Ut'M'.ޙ龁~ <].\7z c wA}9J_v; ݒMFnVߘ5]ڸ`ZlWj:]8;!&N;zܣ4*j$)J<pX̵cO4P:Su$FSbXfX,>2jjszM4-it\[HvT7;SxAuT?i,SPgG*ź[e߳ao,ψ^H E osJžp|} Ș?[əS ^WZ[^Ios! N~}0 t@ wz<@hJ"{S.\;l3>6rbY"qzJsq aP5p|Z/b53~3}z7&88^k A@Fj>v RaDQş><`JB$jB'[䯯ʴ3pE4 DfCrЃE*5dQp .{ڽ?wڵCfq"C}$>4iD\ =b g@K \OmIs2*U|V_I;S +gEr9Ba4 ~$oT[Xղ.x?}#Muxmxt>Hq0%O ti9STXϠ#y{sLN86`v?4$}|06x&fWi݊!XLDw4H>՘Yy66 P9V: 6x,vv .95Qwh} Go3DSjHϘȕ/@b?fPePm[Is{s`T~:gJY}35϶hs+X uNہSnt ErMKt\H |:֘`t WGq)V(5ƒoMſ2C}eK<* F; Ɖ'׀ ؏vJƉctgqރuG$bi*z k'J}lHz9=q51=^&/m iD l(.1iyptP%roAfngVӲ#kfZJEs-EifJo:1 U6Sx/aP2vr&n.h(9Uw2Ej(3bfPR@)D_|bEh}2=6oY!Zwͧ}=?N}p/ሠpbqHn9mve0+:dT1Wa*17/F#P9sE˾wy#c>:1bΦDdFd q%<4_}pf*` tvpZ -ڍ3z>΋v4.BNK,uZ Bw=k'F:IFF)9FT[$A|ࡏ7YF,1gλ$b a v摓$MFrV~{atj_ /sU^߼Xs!ǚ\dnSL/6{ke(H՛l*,uIFwE;^ y3_ 뤩9J ;y-yɦ7Tǃg9sjdBBD,gbxq]'@/#J;^HyK#;Ҿ`,9ln#AXsǘkݟV_"ͩ"[6ixJ FaJc d@$F$)hr1`Xި+ZT `ڢn~ұո~ zf;QFfD8_:m^(A:*ޙ4PMMZ݋ QFQrs!DLc@p3am0-yɟ(e䎘᳦Gɺbu ۦא ӟ*ru_ip8?TH!]`-*le9{MZbqS(p>@KqD;iYlm>@S_&Mx+3m=/RZc]DAUrXHxMCn#&ةv-IQҕL ƛdut'T;̢2\Mátm*4ޱar)_zݓV݋@,͟gportmidi/pm_java/pmdefaults/0000755000000000000000000000000011453601074015165 5ustar rootrootportmidi/pm_java/pmdefaults/PmDefaults.java0000644000000000000000000000041411030706332020065 0ustar rootroot// PmDefaults -- a small application to set PortMIDI default input/output package pmdefaults; public class PmDefaults { public static void main(String[] args) { System.out.println("starting main"); new PmDefaultsFrame("PortMIDI Setup"); } } portmidi/pm_java/pmdefaults/manifest.txt0000644000000000000000000000004211127373026017531 0ustar rootrootMain-Class: pmdefaults/PmDefaults portmidi/pm_java/pmdefaults/pmdefaults-icon.bmp0000644000000000000000000004207011127373026020763 0ustar rootrootBM8D6(@  !  &*/ %4: 59?0E@FKL  ZSR* H>Zbai jQF WteQ $ ^ _r Q Z T * p0+~  p }X 2y k lg_ 9 3 };B=Kz DM~uqOeV z q\ m_%Z# b%u&k('$!#/w%%m+')m)&&u, ~/x.$11*&2 / 0).)+2+,0+4$/#.#85&4&1.0/6'2'.27,9-='4838;091<)?*84;5=-@.>6;><9E(B2B3@3H3?4@<D=C>E.E9I8H1H9H:H<N*K5L7I6F@IFN>I@L8LGO0LMLCJDN<OIKKR3Q4N>UCEHQ?P?PGT?SFT7LJNJV:NRQQWCSDU;NMVDUKKVW=SFV=RM[>XLTNZFZLROWHXNUIXASQWUWJ[B\8ZJXQZD_PWU[MOXZNcG]I\I_PeNaQcL^[ضޯضaYL3!Y!B;!X'DS!k;xi'';ocVcq{[kYkYocq!ooWXoc{ж;k}kYcxЊ׉oiaoc{[;kocx;XX;RB;(ki~q!}3ko(!k 3EkLDkR{k3k'(!k};ic}x{x}(}xݩ݊c{DXXݩɩxX!;3!Xx''X]!('''''˲9%AБ "1^/ud 'Dgbbp$ 64648/ (_)&d޲d"$pg%$- /  Z)  AT )0KmG 1 &/ClI! dhhQ  %GIDATx̖ Ey%o&]STH&2c/5ӗ6~~6$=OuWivκ򎫪+u'㋔hZP0#:7lXd\`RȖغS0!  .:)oT'k ޺*vv0iVjOEri(Q}8CРBH1"Xcd8x+p & yrE1+':<]$FW5rXd?O`e*/cݬs[$84FćwR5 \tPx\7q KWp`!EN_c)+hI-lX|V'0I}IENDB`portmidi/pm_java/pmdefaults/pmdefaults.icns0000644000000000000000000010761711030706332020215 0ustar rootrooticnsis32_!EFGFEFFEFFEEFFEEF=2@B68D9=DB8?DEG2$%&#$"%'##/GF@C==8;::8:8=888@@>E G-!')'%")E F>A6;<5685:E FEGFFGGFGFEN]^_^]__]_^]^_^]]^RCWYIL[MR\YKT[]`C10023/0-25//?_^WZSRLPNMLOKRLQ^]^]^^__[",>a^_^][-Y/Y]^.V5]c3GD`]^]:P^]V8[^]\2DH4`] ^_[`a6N_^^] ^RJ\\SKLVVT] `=,475# 3.8] ^SXHOQGILGN]^^_^^_]Nٱ{~w{|i䟈G>ɝ ݂ u[Ty ռǻ s8mkil32EGGFEFGGEGFEFED41BG >/7FFGF7:HFG;A?FGFE]F<$823<% 1=2<.1;;@< -=1>FEEF<(#66%,  6 -*0GEEF;D@)- #-#1!#"" 3-"GEC;FD<>?<>18F=3C==5:>3:FEFEEFGFEFG4>HGIFGEFEGFGFEF  !BFEG2'HEH$KI5 EH GF:EH(GG.GEG0 CH)HEG5BB?FEF? @9!FEGC17GFED# 5GEJ*;FEFB0'GE B0+ @FEG1IH2HE F>>7C4>>H@<;EF7"#25>.-%- 354!*/EF7!("3**!$'EF6H2"!"0A$!) (EB>FE6;A@E7:?=>?@97@=EFEEGFEGFE]``^]^`_]__]^][FBX`S@J^_`_KOa_^^`PXT_`^]]^P0*KCDP2,&BRCQ?BOPWP+pWdkj~g\iZq`tmqeS]lr~pd\~t|nZwz`q`fxݯصؽ޴ȷF4_Q^<.yo~HfVLm?|?_7ݕ./S n_f@ w_ z? 몪шVw|ܤX3t>vbxmofBLOcv~llxtx]mBsoonnډl8mkih32 EFEFEFFEFEFE@89BFED;8=FE:8EB>EADE@HGFH1 #FGFFH: )FEGEFEEH0E=C749EFD22CB:E55;?B1:;A:F;1@33CEFE FEFEFFEGGFEGGHGFEGGF GFBEFEFGFGGEF)AGEEHFE H "FE BFGHEFBG=.GEH =G6AFE FHI$2GFHFEFG;(.HE FD.HE H1GE GJ BFE FHHE,'  (>FC/?'FEC3>+%?$2 5 =: ;EC  %A /6D#:<) A 7EC .CI)F- BI%;$&<)E$7ED6GG4<BH) &5 7>89E@DEEF@`L PJ%'P&A0#-Z3OP5?H.J(&L_])FA/"+@]]A7( =I.@ FEG?VH)4E_])0M[OZF2(@`O F /3:FM7CGF?[RL/3_])@b_OZF2*E )_&'+7GA7?(@^&(+#'`](NW]]ZL]NYTRZIFL]^[DD[YN]GHPTYBNPWO_OBVDDZ]_^]_]_^]_]`_`__]`__^^`^[^_]_`^_`^]^6"W_\]`_] `-Q_] `"  N_] `*;[ZP%#_] `;F`^__ Y^] `C;`]]b,X^] `G)`]]a# [^] _P$a]]["`] ^W_]_N6`] Z Z^a8R_][X^__]^U_R:a]`(O`J"T^] _aa)D`^`^]^_K0@`]^Y$?`] _&B`] ^`^Z^]^__Y>0 M_] ^V'+)$/b] ^V 7MTZ`bX ] a.a_^^]]_% Z^]^W.Y^]`BGc`]^_]^X AA]^9^]^MK]`]_``_^]^]ba]_`]_^]]^_]_]I;=R_]^]^^RU\BO`MD\FW^_UJXF]^[ $V]W_]\Z_(1R^T6T_Z? U5^]^ZES :2U0C HR'N+"P']^Z,2W? H['0OQ8W, I]^Z>[b8^<Yb'2P03Q7]1 J]^[I``G)QYa84H JSK$)M]W\]]_VP]]W]]\QWX]V]W]W]\QZY\W]^]^^]]^]^]^]^]^]]^]^]*L8E<H+~'QH+8zoiSФ9`fe^vӋK zje+<7HA$}[p9+7iT4y==I&lI+:}'?i: {DS)A@G1|A+<,@nR-ldfqH)%k>PGJ6djp[h*ﳳϭ⳴(r \[iS^  AI! ; u X? 3 zH nHv #X) ;E7 Q=lic0< mۉ ϗ`$ { { SP ꭄ2D iH'.R,uE/Ib ixP)@cŨn!` ɳ/T^*iI4 ߎS/RJKG88 3&'hpLDYf /2>tQ0e}6LPN87,sU1 -N3.g7691R3 E>JkC+Q$HM^EHkKh8mk it32,fEEEEEEEEE:0/04?E:0/16AE/!(AE@#3E@.EEE EEBEE8#E $6E'(()/=EE"3EE2#EE(#E1E>EE7%E -EEE EEBEE8#E<(DE'%EE"4EE2#EE(#E#E@ #$(E 9 EE@EEAEEBEE8#EED'E9E'%EE"4EE2#EE(//."E1E2$ EE7%E:EEDEE$EBEEBEE:EE=0EE(&EE #5EE3%EE*CEA  *EE8%ED  EE1 EECEEC 0"#E77E E 2@EE?4EE= *DE@ -EA4EE9 8- E % 4"EE) E&4@#DE<;EC85E95EG)SE@GEI:IAEPEFGDEMPEKBEMEKAEJEJ0CEQEAEREEMNEEFEME08E'HEFKE6BEE8=E CE=.E5EDEJEI EPEE43EE LE GEGFEJE;@E)JELE2GCEE>BDE32EDG9EIECL+DECQEOEO GEOENP1EJF+ E;EOE?EB DEM BE@EK+ >EG> EIGE=EG?GI MEF-%KEHKEER; FEB3&1; FECLE\ AFE!2AJLLEM3FEJGEBE;BE-BELSELEJCEH IEPEGDE5@EQGE?;EJCE.)EL7HNE:?EBEEF+-OEO'ELE9@EEEEPOQNDDE6EQKELEBDEE:0/04?E@EC+8E(+EC+8E5@EB3E*DE6>EE!DE 6CE/7E>CE'%E &EE@*)?E#? 4C'/E?%.AE EE?4EE? 2E 5"*B/7EE? 2E'%E!'E+'E  EAE-4EE DED "7EE DE'%E931 %' ,EE(%7"EE;7EEBE'?>E$7E4E8#E= ;+(4EEB<E 7EEBE'(()/=EE6&E..E>E8#E=&"=(4EEB6%E #7EEBE'%E7$E,0EBE8#E=7 E(4EEB9#E 7EEBE'%EBE :EEDE C 0>E'=E)4EECE9 7EECE77E>;E(E&4-DE?EE6@EE) E4 !:AEE) E<E8AE96AEE<>E8AEEEEEEEEEE]]]]]]]]]NA@AFU]NA@BHX]@-*5X]W/E]VQ]GV]HR]#+],]YE]5 ]6N]V 93Q] #Y]]M1]41]IF] 60]]XF]K-] #Y]]K0]41],4]M*O]D,,F]]J.,@]60]ZC]W:)'4S]H0 ?X]]H0&&/F]R*G]L*N]]#Y]U2>W]]X:*(3L]41],4]/+]60]7(]>7]S(Y]# ] ]]#Y] )]J"\]41] M E]'' +D]]60]&J]]I@AB]5 ,M,+EBD]]] ]]#Y]J".Q]JN%=]4  ]];]] ]]54]]60]P]]W]]Z ]]J1]]"1]M/]]] ]]#Y]]K0]]Z*](K]4U]]V]],>]]A0]]60]M][Z!]]J1]]XE\]T>$)]]] ]]#Y]]K0]1I]4668?S]].E]]C0]]60]B]T ]]J1] = )]]] ]]#Y]]K0]P 5\]41]].F]]C0]]60]'/]V06Q]]J1]]'.CR*]]] ]]#Y]]K0]G*+]41]].F]]C0]]60] LN]]] DI]]J1]T] M+]]V]]X]]#Y]]L0]]\*5]L ]41]].F]]C0]]6!@@>.#])B]21]]J1]N$]]\!!]]%0]Y]]#Y]]O']]RA] ]63]] 0G]]D1]]9Z]W)9]]K2]\ !* ]]B  ]]$Z]]Z@!./]JJ]+] CV]]UF]]S9\]V" =]XF]]LL= ] 2 F.$]]7]3FV!/\]QQ]\JY]NU]TP]ZKGQ]UO]MIU]OW]YKO]]\J[]LX]TGJY]YKHO]]]JQ]]VWM2S]E>]K#O]R]Y#A90R]S =]XZ][\]X,;&/0]VX_SWYS\WK S]U`Y]F]3<]U/d]?Z]W@ZP]P]\MQ]ZR]RK] N]WE]K]X3U]Q]S]V]  V][T]]R ]"\]9=]4V]TS]CP]R]GI]ON]K;]&9]S&]R]Z]Z ] ]=<]]Y]W\]Q&W]UX]EH]0V] S];SW]]IOY]@:]VTFX]R]WZ5T]RP\]Y$]SW]R []TW: ] SM, ]D ] U ]G]K X]Y W]K (\]S2S][A .]K]X][MOMS]R<*O]QQ]JP7O]UB *83V]  #IT]PSY]. 8KUYX]FH]V N])T]BE]/ Q]TXU]R]TM]Q'O][]SI"]>V]VR]QO]UZ];0] [ D^WMGP]T]]S0-M]V 6SW]AF]]]]c^ac[[]O]`Y]^][[]]NA@AFU]VQ]K@BU]MABT]Z:L]6:]Z:L]GV]YE]9 \]IS]],\] IQ]],\]5 ]M1])G]*F]]7]@J]]7]41]IF]K0](.]F]T[]@J]T[]41] ,4]]V9**7T]#U+FZ5*?]U2>W](]]UF]]U+C] G.*9Y@J]]U+C]41],4]:5]+, )]()X]<*F]]+\]\" .J]]+\]41]M EB 24;]]"(2J".Q](AA]$ 6F]]#Y]2 1/J]]#Y]4  ]T]]Y \]!$]][]]K0]&(R(] #6F]]#Y] S]]OJ]]#Y]4US&]0J]!F]K0](SP:6F]]#YQ$] J]]#Y]4668?S]]H3]>>]!T]K0](S3.R6F]]#YI2] /J]]#Y]41]K1];A]!Y]K0](SK ]6F]]#YL/] ,J]]#Y]41]Y]&Q]!Z]L0](S\#]6F]]#YY] J]]#Y]41] ?]]G]]!Z]O'](S];]6F]]#Y]7]]6J]]#Y]63]T N]]"[] ZA*T]5S]7G]]$Z]M K]]$Z]JJ]SP]5]3F< \]U]]IV]]7]F -OW]]7]QQ]XJIV]KX]TGJY]]MV]VI\]PT]LX]MIX]]QS]LX]]]]]]]]]]ϪߔΪvn{֜NL׎[r t" 9ό!Ԕ \ ~>/v [~sottys~(mfڀ~Tde|oo[QojɑtGCS|rM~jڃiEP\ 8E[UmZ 5 hh Gq~&A3=V9ssr?H"1[Z7x(8b"97$55TU~1F :Y|H"1[~nk%ƏM5t~6JWܤ^mH"1[~*9Kځ5z~~L݆ NmH!1[~25z~~h|.~g6zoH1[~n+q5z~~ 8 R pK1[~o5z~Vx\9m/^WVbS1[gE9 ~@%Rl.!Vo+  !3^& 6WxI}Æp@ &=Z$ %@ȡ "y^* W}և߁ђƼՃЁ̿߀޻ǽõO.1E+ ,؂%Brdbhqz4 ,'!'8MkP  %7Jz[1 !3݈5) 0Ӈg%7$)ʇD'H+$+0l1 "E:gRF|S!(qT" mF#2a+ el7*Fm0_J.0uv2VՄ<'?0 G„x% h1=ڃc%%18ق\4;޲25قrZ]ڻ5 5݃C 3\2sU0g ˟mT@ -b  pH;0%'bP9. "YV<+  "UO-  )UT%    +Y['  'e>  3ښ= N>  .C   AhȼA  8ʙY7/")~ͥa5"3ص_H^O)&+5?Ia|p-Y3(++#!#+4AQ^lۃ~$+ V 4cއ )W TЏ# 16717hP6HޏG,3[sEGx0%IZL|ۯ</gpݐ]Yʒj">54 F"#G p/,?IQPh : '4B\ ݖ@'"6E`dJ\͍ԁ܍Ϫߖւǩʪ܀ȇȯNu u " 9ln,,~ky+À snnށ#qnQk/80r yort  p&SsUmkmnp Z xp *X(22Z7xk^[{[$97$5+!W^~&kk[[ [MdW~kJ)[_ U[KW܂~kڇy׍[ {[W~k [{ s[HdW~k][? :[U=WgkJ[J[,2Z & n^ %^ÆQGр0 J ,"v ,։޻݁̿ہt8mk@portmidi/pm_java/pmdefaults/PmDefaultsFrame.java0000644000000000000000000003626711450424334021064 0ustar rootroot// PmDefaults -- a small application to set PortMIDI default input/output /* Implementation notes: This program uses PortMidi to enumerate input and output devices and also to send output messages to test output devices and to receive input messages to test input devices. */ package pmdefaults; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.lang.Math.*; import jportmidi.*; import jportmidi.JPortMidiApi.*; import java.util.ArrayList; import java.util.prefs.*; import java.net.*; public class PmDefaultsFrame extends JFrame implements ActionListener, ComponentListener { // This class extends JPortMidi in order to override midi input handling // In this case, midi input simply blinks the activity light public class JPM extends JPortMidi { ActivityLight light; PmDefaultsFrame frame; int lightTime; boolean lightState; int now; // current time in ms final int HALF_BLINK_PERIOD = 250; // ms public JPM(ActivityLight al, PmDefaultsFrame df) throws JPortMidiException { light = al; frame = df; lightTime = 0; lightState = false; // meaning "off" now = 0; } public void poll(int ms) throws JPortMidiException { // blink the light. lightState is initially false (off). // to blink the light, set lightState to true and lightTime // to now + 0.25s; turn on light // now > ligntTime && lightState => set lightTime = now + 0.25s; // set lightState = false // turn off light // light can be blinked again when now > lightTime && !lightState now = ms; if (now > lightTime && lightState) { lightTime = now + HALF_BLINK_PERIOD; lightState = false; light.setState(false); } super.poll(); } public void handleMidiIn(PmEvent buffer) { System.out.println("midi in: now " + now + " lightTime " + lightTime + " lightState " + lightState); if (now > lightTime && !lightState) { lightState = true; lightTime = now + HALF_BLINK_PERIOD; light.setState(true); } } } public class ActivityLight extends JPanel { Color color; final Color OFF_COLOR = Color.BLACK; final Color ON_COLOR = Color.GREEN; ActivityLight() { super(); Dimension size = new Dimension(50, 25); setMaximumSize(size); setPreferredSize(size); setMinimumSize(size); color = OFF_COLOR; System.out.println("ActivityLight " + getSize()); } public void setState(boolean on) { color = (on ? ON_COLOR : OFF_COLOR); repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); // paint background g.setColor(color); int x = (getWidth() / 2) - 5; int y = (getHeight() / 2) - 5; g.fillOval(x, y, 10, 10); g.setColor(OFF_COLOR); g.drawOval(x, y, 10, 10); } } private JLabel inputLabel; private JComboBox inputSelection; // inputIds maps from the index of an item in inputSelection to the // device ID. Used to open the selected device. private ArrayList inputIds; private ActivityLight inputActivity; private JLabel outputLabel; private JComboBox outputSelection; // analogous to inputIds, outputIds maps selection index to device ID private ArrayList outputIds; private JButton testButton; private JButton refreshButton; private JButton updateButton; private JButton closeButton; private JLabel logo; private JPM jpm; private Timer timer; public void componentResized(ComponentEvent e) { System.out.println(e); if (e.getComponent() == this) { Insets insets = getInsets(); Dimension dim = getSize(); layoutComponents(dim.width - insets.left - insets.right, dim.height - insets.top - insets.bottom); } } public void componentMoved(ComponentEvent e) { System.out.println(e); } public void componentHidden(ComponentEvent e) { System.out.println(e); } public void componentShown(ComponentEvent e) { System.out.println(e); } PmDefaultsFrame(String title) { super(title); initComponents(); System.out.println("initComponents returned\n"); pack(); // necessary before calling getInsets(); // initially, only width matters to layout: layoutComponents(550, 300); System.out.println("after layout, pref " + getPreferredSize()); // now, based on layout-computed preferredSize, set the Frame size Insets insets = getInsets(); Dimension dim = getPreferredSize(); dim.width += (insets.left + insets.right); dim.height += (insets.top + insets.bottom); setSize(dim); System.out.println("size" + getPreferredSize()); addComponentListener(this); timer = new Timer(50 /* ms */, this); timer.addActionListener(this); try { jpm = new JPM(inputActivity, this); jpm.setTrace(true); loadDeviceChoices(); timer.start(); // don't start timer if there's an error } catch(JPortMidiException e) { System.out.println(e); } } void openInputSelection() { int id = inputSelection.getSelectedIndex(); if (id < 0) return; // nothing selected id = (Integer) (inputIds.get(id)); // map to device ID // openInput will close any previously open input stream try { jpm.openInput(id, 100); // buffer size hopes to avoid overflow } catch(JPortMidiException e) { System.out.println(e); } } // make a string to put into preferences describing this device String makePrefName(int id) { String name = jpm.getDeviceName(id); String interf = jpm.getDeviceInterf(id); // the syntax requires comma-space separator (see portmidi.h) return interf + ", " + name; } public void savePreferences() { Preferences prefs = Preferences.userRoot().node("/PortMidi"); int id = outputSelection.getSelectedIndex(); if (id >= 0) { String prefName = makePrefName(outputIds.get(id)); System.out.println("output pref: " + prefName); prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName); } id = inputSelection.getSelectedIndex(); if (id >= 0) { String prefName = makePrefName(inputIds.get(id)); System.out.println("input pref: " + prefName); prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName); } try { prefs.flush(); } catch(BackingStoreException e) { System.out.println(e); } } public void actionPerformed(ActionEvent e) { Object source = e.getSource(); try { if (source == timer) { jpm.poll(jpm.timeGet()); } else if (source == refreshButton) { if (jpm.isOpenInput()) jpm.closeInput(); if (jpm.isOpenOutput()) jpm.closeOutput(); jpm.refreshDeviceLists(); loadDeviceChoices(); } else if (source == updateButton) { savePreferences(); } else if (source == closeButton) { if (jpm.isOpenInput()) jpm.closeInput(); if (jpm.isOpenOutput()) jpm.closeOutput(); } else if (source == testButton) { sendTestMessages(); } else if (source == inputSelection) { // close previous selection and open new one openInputSelection(); } else if (source == outputSelection) { jpm.closeOutput(); // remains closed until Test button reopens } } catch(JPortMidiException ex) { System.out.println(ex); } }; private void layoutComponents(int width, int height) { // I tried to do this with various layout managers, but failed // It seems pretty straightforward to just compute locations and // sizes. int gap = 2; // pixel separation between components int indent = 20; int y = gap; // inputLabel goes in upper left inputLabel.setLocation(0, y); inputLabel.setSize(inputLabel.getPreferredSize()); // inputSelection goes below and indented, width based on panel y += inputLabel.getHeight() + gap; inputSelection.setLocation(indent, y); // size of inputSelection must leave room at right for inputButton // (in fact, inputActivity goes there, but we'll make inputSelection // and outputSelection the same size, based on leaving room for // testButton, which is larger than inputActivity.) Dimension dim = inputSelection.getPreferredSize(); Dimension dimButton = testButton.getPreferredSize(); // make button and selection the same height so they align dim.height = dimButton.height = Math.max(dim.height, dimButton.height); // make selection width as wide as possible dim.width = width - indent - dimButton.width - gap; inputSelection.setSize(dim); // inputActivity goes to the right of inputSelection inputActivity.setLocation(indent + dim.width + gap, y); // square size to match the height of inputSelection inputActivity.setSize(dim.height, dim.height); // outputLabel goes below y += dim.height + gap; outputLabel.setLocation(0, y); outputLabel.setSize(outputLabel.getPreferredSize()); // outputSelection is like inputSelection y += outputLabel.getHeight() + gap; outputSelection.setLocation(indent, y); outputSelection.setSize(dim); // testButton is like inputActivity testButton.setLocation(indent + dim.width + gap, y); testButton.setSize(dimButton); System.out.println("button " + dimButton + " selection " + dim); // refreshButton is below y += dim.height + gap; dim = refreshButton.getPreferredSize(); refreshButton.setLocation(indent, y); refreshButton.setSize(dim); // updateButton to right of refreshButton int x = indent + dim.width + gap; updateButton.setLocation(x, y); dim = updateButton.getPreferredSize(); updateButton.setSize(dim); // closeButton to right of updateButton x += dim.width + gap; closeButton.setLocation(x, y); dim = closeButton.getPreferredSize(); closeButton.setSize(dim); // place logo centered at bottom y += dim.height + gap; logo.setLocation((width - logo.getWidth()) / 2, height - gap - logo.getHeight()); // set overall size y += logo.getHeight() + gap; System.out.println("computed best size " + width + ", " + y); setPreferredSize(new Dimension(width, y)); } private void initComponents() { Container wholePanel = getContentPane(); wholePanel.setLayout(null); setLayout(null); inputLabel = new JLabel(); inputLabel.setText("Default Input"); wholePanel.add(inputLabel); inputSelection = new JComboBox(); inputSelection.addActionListener(this); inputSelection.setLocation(20, 30); inputSelection.setSize(inputSelection.getPreferredSize()); System.out.println("Adding inputSelection to panel"); wholePanel.add(inputSelection); inputIds = new ArrayList(); inputActivity = new ActivityLight(); wholePanel.add(inputActivity); outputLabel = new JLabel(); outputLabel.setText("Default Output"); wholePanel.add(outputLabel); outputSelection = new JComboBox(); outputSelection.addActionListener(this); wholePanel.add(outputSelection); testButton = new JButton(); testButton.setText("Test"); testButton.addActionListener(this); wholePanel.add(testButton); outputIds = new ArrayList(); refreshButton = new JButton(); refreshButton.setText("Refresh Device Lists"); System.out.println("refresh " + refreshButton.getPreferredSize()); System.out.println(getLayout()); refreshButton.addActionListener(this); wholePanel.add(refreshButton); updateButton = new JButton(); updateButton.setText("Update Preferences"); updateButton.setSize(refreshButton.getPreferredSize()); updateButton.addActionListener(this); wholePanel.add(updateButton); closeButton = new JButton(); closeButton.setText("Close/Release Ports"); closeButton.setSize(refreshButton.getPreferredSize()); closeButton.addActionListener(this); wholePanel.add(closeButton); // load the logo from the jar file (on Linux and Windows) ClassLoader cldr = this.getClass().getClassLoader(); ImageIcon icon; URL logoURL = cldr.getResource("portmusic_logo.png"); if (logoURL == null) { // on Mac, load from bundle icon = new ImageIcon("portmusic_logo.png"); } else { icon = new ImageIcon(logoURL); } logo = new JLabel(icon); logo.setSize(logo.getPreferredSize()); wholePanel.add(logo); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } void loadDeviceChoices() throws JPortMidiException { // initialize and load combo boxes with device descriptions int n = jpm.countDevices(); inputSelection.removeAllItems(); inputIds.clear(); outputSelection.removeAllItems(); outputIds.clear(); for (int i = 0; i < n; i++) { String interf = jpm.getDeviceInterf(i); String name = jpm.getDeviceName(i); System.out.println("name " + name); String selection = name + " [" + interf + "]"; if (jpm.getDeviceInput(i)) { inputIds.add(i); inputSelection.addItem(selection); } else { outputIds.add(i); outputSelection.addItem(selection); } } } void sendTestMessages() { try { if (!jpm.isOpenOutput()) { int id = outputSelection.getSelectedIndex(); if (id < 0) return; // nothing selected id = (Integer) (outputIds.get(id)); System.out.println("calling openOutput"); jpm.openOutput(id, 10, 10); } jpm.midiNote(0, 67, 100); // send an A (440) jpm.midiNote(0, 67, 0, jpm.timeGet() + 500); } catch(JPortMidiException e) { System.out.println(e); } } } portmidi/pm_java/pmdefaults/pmdefaults-icon.xcf0000644000000000000000000004676511030706332020775 0ustar rootrootgimp xcf fileBB $gimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  r f     gimp-text-layer(text "") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.270588 0.364706 0.960784 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) Rfjf~E]DED]DD3 P PortMidi#1     c +gimp-text-layer(text "PortMidi") (font "Arial Rounded MT Bold,") (font-size 20.000000) (font-size-unit pixels) (hinting no) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) P fP `(NPPM? 0OJ-NK_/< Bd8n-x;?hpx7>0|@pxqbg?oRvV@Fpxp`oש Z@px+BJwp^˸u3Ƃ"NLl@ vp 0|l@ p{5@0|ؐ%_l@ "pllfQ9rUT0|rl@ 7px2z]M 0|2l@ .px  /|l@ pxQ=']l@ lr( Nni= ,34%mt?Z6h 561 <5 -6$/pppFl`_/8 O4hP4'h+8 !//( text1       4 P ` p @@p PmDefaults#1       -gimp-text-layer(text "PmDefaults") (font "Arial Rounded MT Bold,") (font-size 20.000000) (font-size-unit pixels) (hinting no) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) zp p  (NPPM?)NPPJ9P<9nj( cpx7>l|? 0pxq+'E?5Ol|Fap:|Qpxp~l|hUipx+BEl|57PLImćp\nql|# 4xpVL{l|,4xpllfQBH|l|K4xpx@H|l|~||{l"4xpx@H|l|.*E74xpx@H|lPPUJy4xlr|<Dxb d1u34F@bX ? 3 (% 1;!&PPPmA  B r" -x$ 0| 9{~@=.* vV_t.  5,CIE 3Ƃ"4)Xy-~ 0| 1 AT 0|y6X 0|#mǀH 0|<- /|o.){ 'NI O}./Wv@ht?}+8& 0&3/<5  0:&8 Background     d|M :0=?ENJHGGHGDDEGGHGEDDEGHDDBC>EENHEEHGGDDEGGFEEFGGFFDHEENHEEHGGDDEGFGGFGGNCGEENHEEHGGDDEGGH GHKEENHEEHGGDDEGHGGHFFOLEENHEEHGGDDEGHHGGHGDHIEENHEEHGGDDEGGHFEENHEEHGGDDEGFGGFGGECBGEENHEEHGGDDEGEEDCEENHEEHGGDDEGE EDCEENHEEHGGDDEGEED ENHEEHGGDDEGEEHEENHEEHGGDDEGEEDGJEENHEEHGGDDEGEEGMEENHEEHGGDDEGEEHELEENHEEHGGDDEGEEIEJEENHEEHGGDDEGEEFGKEENHEEHGGDDEGEEFIEENHEEHGGDDEGEEDGGEENHEEHGGDDEGEEIHEENHEEHGGDDEGEEJHEENHEEHGGDDEGEEDGFEENHEEHGGDDEGE1ENHEEHGGDDEGEEFE ENHEEHGGDDEGEEFHHEENHEEHGGDDEGEEHENHEEHGGDDEGEEHFFEENHEEHGGDDEGEEGDDEENHEEHGGDDEGEEGEDEENHEEHGGDDEGEEHFDEENHEEHGGDDEGEEGHCEENHEEHGGDDEGEEDJBEENHEEHGGDDEGEDEEG GHEENHEEHGGDDEGEDEEG GEFIFEENHEEHGGDDEGE EDECEENHEEHGGDDEGE EDCAABEENHEEHGGDDEGGEDC?@A]\]]\\[\^^]\\]\ZYY[\]YYZ[V]][]_]][\\^]]\\[ZZ[\\[[Y\`]][]_]][\\^]]\\[\\[\\`UY]][]_]][\\^]]\\] \VWZ]][]_]][\\^]]\\]\\][[^[T]][]_]][\\^]]\\]]\\]\VZW]][]_]][\\^]]\\_]V]][]_]][\\^]]\\[\\[\\]Z][]_]][\\^]]\\]]`]Z]][]_]][\\^]]\\]]_]Z]][]_]][\\^]]\\] ]\][]][]_]][\\^]]\\] ]\][]_]][\\^]]\\]]\^]][]_]][\\^]]\\]]\^]][]_]][\\^]]\\] ]\Y\]][]_]][\\^]]\\] ]\]Y\]][]_]][\\^]]\\]][]][]_]][\\^]]\\]][][]_]][\\^]]\\]]\Y]][]_]][\\^]]\\]]^Z]][]_]][\\^]]\\]]_[]][]_]][\\^]]\\]]\_[]][]_]][\\^]]\\]]Z]][]_]][\\^]]\\]]^]Z]][]_]][\\^]]\\]]\^]][]_]][\\^]]\\]]^]][]_]][\\^]]\\]]\^]][]_]][\\^]]\\]]\Y\]][]_]][\\^]]\\]]\Z\]][]_]][\\^]]\\]]^[]][]_]][\\^]]\\]]\`Z]][]_]][\\^]]\\]]\]\]Y_Z]][]_]][\\^]]\\^_\[YZ[\]]\[[\]]^Y]][]_]][\\^]]\\^^\[ZZ\\]]\\[[\]__Z]][]_]][\\^]]\\ ]\^Z]][]_]][\\^]]\[\\ ]\]]Z]][]_]][\\^]]\\[[\^]^[             EIGQMJECCHHNHCI@HICKFGEEDCA?B>57CEEJDINJFHGJMJIDEFBBCCGFHHGEDA@BICAAEEKHJC&@?P95OOLHIKFDAEEG)SGQAAL9AGLOH@MQMGIKFDAEEI:IANDC=9;ECGMRPPHDFIFDAEEJGDOSRJ?KHMEJG@MPMB@=FFDAEEJKBKHNGMCIHHKCIHMLAE;FFDAEEGKAIGCGHFEDMFKGBJMDDBHFDAEEFJ0CEDDGFDDMGJCCQLIEDIFDAEEGKADFDEGCGJFIAIRGJEGIFDAEEIKECFEEHBGFFICMNDEFGIFDAEEJHKCCEFGBGCEIHFKG@HEIFDAEEHCMBBEGFGGCEHH08KJ?GDIFDAEEJB'HEEIGFIEBDFFKIEAEFIFDAEEKB6BFHIFGIDADEETD<@DIKFDAEEDG8=@HGBHMEEBDE CAF@EGKFDAEEFE=.BHHDHJBDHB5KBA?DJIFDAEEFBDCGHFGHIBLLJIDCCIFDAEEGAI GHHIFFP@HPLECFFBFIFDAEEF@KLIGIFFNCG43NFAFGCGIFDAEEAHMIFHFJFLL LEFBJGGHIFDAEECE LHGHFJHMGF=DELIIDIFDAEEFHEJGGIFFPH;@EGFFGIDIFDCEENFJ)JEFICMMILJFCDEGGHECFEEMHJ2GCEFEHLLKKGCCDEGGFEDHEEIGF>BDGGJII32PJFCCDEGGEEDHEEFGDG9EIHMIIIMIFDCDDGGEEDHEEFCL+DIGMMBHECQJPIEDCDDGGEEHEE]\UYOOUYX\ZY_^_eZ`a[c[\\]^baTJQ]]^PPSSU__`]Y\Y`a[[]ZZ[\^`a_X\_]]VWM2SWUZ`YY\WZc^\__b[YZ[\]]^a]]E>X_]]Y[\WWXZ[``][Z[[\[ZZW[`[]]K#O^PNW\RQUQY\Xb^\[\]\[YY[\a_]]Y#A90RZeZ[[]]\[Z\[`a]]S =eZ[]__^^]\Y^^]]XZ[]__`^^]\_]][\\Ydb]\\[__]]X,;&/0ZY^\Z]\[__]]VX_SWYS\WK SZYXW[[_]U`YP\\^a][FQ35) 0g%7$)D'H+$+0l1 "E:gRF|S!(qT" mF#2a+ el7*Fm0_J.0uv2V<'?0 Gx% h1=c%%18\4;޲25rZ]ڻ5 5ENHEEHGGDDEGGE DABCEENHEEHGGDDEGGEDCDEFENHEEHGGDDEGGEDCDEGHHJJKJEENHEEHGGDDEGGEFEDDEFEHFMLKLNPEENHEEHGGDDEGGEEDEJLMNIJF+ EENHEEHGGDDEGEEDEGFLIW;ENHEEHGGDDEGEEDDEFMPIOEENHEEHGGDDEGEDDEFIJR?EENHEEHGGDDEDGJIBEENHEEHGGDDEDCCDDGJM EENHFGGHGEDDCDDGJL@EEMJIJJGGHCBD@@HGEEJNNK+EEKJIKKIGC=GG@D=GGJIHO>EEJGHJJGCJFG?FBA;AC?FNKIEEIEEHHCEEOFI@AG?=HG?GI EEIDDGGCIEFQIKOLIF-EGDDEGH@DQHKVER; EIDDEGEIB3 &1;EEIEDEGFGCLKN@HKK\EEJGEGHJA!2AJLLGHGHFGEHFVMEEKGFHHKGJGBBDFFGHFFGFEDCCJHNEEMHFHJEQD;BRJHEDDEFEHHFEDCCEFIEEMHFHJPFOLSECCDCCADFGEEDDC?JFEEKGFHHGLLJCOMMIGHHGFFGGEDCAGJEEKGEGGAIIJPGHJGFHIHHGEDCACJEEJEEGGHEEJP5@CGEDDAEGHHEDC=BEEKGEEF@IHEK?;CDEA@CFFCDEEDCABHEENHFEEDEGJHGEEDDCBALEENJFEEDCDDIIGEEDCDCE>LEENJFDEEDCDDGG EDED>J?EENHFDDGEDCDEGG EDABEENHEDDGEDDEGGEFCEENHEDEGGEDDEGGBL@EEMGDDEHHGEDEGGEGFAJEEMGDDEHJHHFEGGEEGEFB=EEMEDDGGRKIGI@HGBFBFCFCFGFG@IAEBE:EEMEDDGNCMIPJKGBDAHBCCECEBAHAJHIB?EEKDBDHPOQNDDLDDFIFHEJHFFJDIH6JQKNEE][]_]][\\^]]\\[]^^]^_\]][]_]][\\^]]\\]^]\]^Y]][]_]][\\^]]\\]^]\[Z[ZYYW]][]_]][\\^]]\\]]^_^__]YYU[YURTW]][]_]][\\^]]\\]^]]^^_^]_[ZYTSM, ]][]_]][\\^]]\\]]\\]ZVXP^D][]_]][\\^]]\\]\\Z]^QU ]][]_]][\\^]]\[[\]]\[XWV[G]][]_]][\\^]]\\[\]^]ZWWUK ]][]_]][\\^]]\\]^^\YZY ]][]^\\[\\]^^]\\]^^][YZK][]][[\`[\`\[^[[^YS2]]\]]ZZ]_[Uaa_bV^_]^XQUA]]^]ZZ\Zb^]X``b\`aWZZRK]^[_Z\Y_W^Y\b\Xa[MOM]]^_]][`YV]SXZTQR<]]_^_^^`XX`QQ^JP7]]^_^][^UB *83]]_^^]]\Z  #ITVYOUSJP]]^]^\\]Q. 8KUYXTTVX\]^V[F]]^][Z[WV NLNRVYZ[XXY[]^_`UL]]\]^ZYT_NBE^]]\]]^^]]^]^^_ZO]]\]^ZY_TYTXUXZ[\]\[]\]^]]^[cR]]^ZY\YTMZZ\[[]][\]]^]]^_aY]]^_\\V^ZW[TVZZ[]^]\]]^ ]_]a^[YY>V[``^_]Y[[\]][^\]]\^_^^_[b]RXQOZ^`]\^`^ZY[\]^]]^^\]][]^]]^__]ZYY\\]]\\]]\\]^_^^]Z[]][\^\\]^__^[XX[\\[\^^]]^_]^`X^]]Z[]]^][YY\]]\ ]\hW]][\]]\]\YZ\^^]\]^``]][]^^][\]]\[Z]]^]\\]\[[\]_\[]]\]^^][[]^]\[\]]\\^^]\\YcU]]^]_^]Z[]^_]\\]]\[[]][[^Yc] ]^[Z[^_]\\]]\\]\\Z[]][\_\Z]][\^_^X`XW[^V^_[^Z_\^[]^]^XaY]]e]]\]^_^_RZXb``]Z[W^Z\Y[[]YX`Ybab]^]]_^c^ac[[^WW[^[^]][\]b\aaOa`Y_]] pHP9.V<+ O-T% ['  > ښ= ߬> C  ȼA  ʙY7/"ͥa5"ص_H^O)&+5?Ia|Y3(++#!#+4AQ^lV 4cW T67P6HsEGZL|gpFHFOEKHKDGFKJIQFHEDCDDEGEEHEEIHKO GLKJEFIEGGPHGEDCDDEEDEEHEELJOOFHJFGADIIMFIGEDDEDEEDEFHEE1KDIEDCDEEGGEDEFEDIEEJBFJDCDDEEDEFEDHEEHA@IDD EDHEEJAAEEDD EDGEEIAGCEEDEGEDEDGEED@HCGGEDDEEGGHHGEEHEEBADEGGEDDEEGHJHHGEEFEHEEEFBKGGEDEEGHHGEEGFEFEE>DDCFGEEGEGIFDCEEDK?EIE EGIFDAEEND;DEAE EGIFDAEEMKAKCHBE EGIFDAEE%KOKKDEDEEGIFDAEEFNOEFJ>D@DE EGIFDAEE FO@UJALHADE EGIFDAEE AFLBHIG>GDE EGIFDAEE3HIAFKBGADE EGIFDAEEBJIHFCGAE EGIFDAEE-BFFBDFEEGIFDAEELQI@FEFCJE EGIFDAEEH INDFEGCIGE EGIFDAEEGDLGA>EGHGE EGIFDAEELQGD@>CIJGE EGIFDAEEDMJCGGCIKGEGEGEEGIFDAEENF.)KBGN@FHGHGHGGEGIFDAEEFGL7RNE:?EEHIHFGHGGEGIFDAEEGHJBGIGFGFEEGIFDAEEICGCAGFHEEGIFDAEEKHF+-OEHBDDFFEDEEGIFDAEEIJEO'ELMSSIDCCEECEEGIFDAEEA?NM9@PD=IIBDFDDCEEGIFDAEECEHQJIEEDCFEBCEEDDEGIFDAEE>BBKLNCFJ=AFHHDGDDEAFCAIDDKCFIFDAEE?CEHERE@CG@J@KFGGCKBOGDBLHFIKFDAEEAKRLLKIGHA@GKQAGPFCIBDDJIJAHEKFDAEE]WY$UZUYW^YZXT`V\]^_^_^]"]XUTSW\YZ\__YWU_Y\\^_^^]\\] ]WSVR VZ[Z`Z]_[_Y\[\]__]\\[]^]]: [X^\^^]\]\^]\^]]ZX\a_^]]\]^]\]] [XYc^][\]^]]\]^_]\\]]^YY^^]\\^^]\]]\\]^^]\\]\Y^[]^]^`_\\[\\[]\\]]XX_Z\]]^__\\[\\[\] ]WZ[\\]\]\\[[\^]](\`Y_[\\[\\]\\]]\\^]S^_[[\]]\\]\]\]\\[_^]].ZeZ]a] ]\][__]]\XT^]X\] ]\][__]]SYSb[`Z\] ]\][__]]*OWY]Z]]^] ]\][__]]OVZRX^U_[] ]\][__]]V_Oc[Tdc\] ]\][__]]SY^SZ]^Zb] ]\][__]]H\]UZb\b]^] ]\][__]])T^]]b[] ]\][__]]/ QX^_[\]\\] ]\][__]]RYVXa_^Y^\] ]\][__]]Q'OYXabaWZ[] ]\][__]]SI"T\_^aYV[] ]\][__]][VR[_^_[Y[] ]\][__]]STUZab[XZ[]\]\\]\]\][__]]\S;0[UU\OX[\\[\]\\]\][__]]UY[ D_WMGPVY\][Z[\\[\\]][__]]\WTX]_\[[\\[\]]^^][__]]_XTTY]_^]\\]^^]][__]]_\S0-MHWZ[^_`^\\]^^]]\\[__]]^]TV 6SWTV[\\[\_`^[]]^^]\\[\[__]]YT`XAFXUR^]VY^]\\]\[\[__]]a\[W\SUX]_^`^\]^][[]_]]\]]\[__]]a`\`]\R]eZ\]]`\^[Z[X^[Y`[Y`X[][__]]e[^[ZUbZY`dT\T`[\[Z`[e_XVa][^\[__]]V^d^]YXY__^[ZcT\eXX^[[\\_W^[\[__]]C 3\2sU0gmT@ -b;0%'b "Y "U  )U   +Y'e 3N. Ah 8 )~3p-~$+ ) # 1 17h G,3[ x0%I ۯ</ ]Y j">54F"#Gp/,?IQPh: '4B\ݖ@'"6E`dJ\@@portmidi/pm_java/pmdefaults/README.txt0000644000000000000000000000141611127373026016666 0ustar rootrootREADME.txt Roger B. Dannenberg 2 Jan 2009 PmDefaults is a program to set default input and output devices for PortMidi applications. After running the PmDefaults program and choosing devices, identifiers for these devices will be returned by Pm_GetDefaultInputDeviceID() and Pm_GetDefaultOutputDeviceID(). Included in this directory are: manifest.txt -- used in pmdefaults.jar pmdefaults-icon.* -- various icons for applications pmdefaults-license.txt -- a version of portmidi/license.txt formatted for the windows installer portmusic_logo.png -- a logo displayed by the pmdefaults application readme-win32.txt -- this becomes the readme file for the pmdefaults application. It is copied to win32/README.txt by make.bat TO BUILD THE APPLICATION: see ../README.txt portmidi/pm_java/pmdefaults/readme-win32.txt0000644000000000000000000000045111130155250020113 0ustar rootrootREADME.txt Roger B. Dannenberg 1 Jan 2009 This directory contains files that implement: pmdefaults -- a program to set PortMidi default input/output devices You can copy and rename this *whole directory* to move the application to a convenient place. The application to run is pmdefaults.exe. portmidi/pm_java/pmdefaults/pmdefaults-icon.png0000644000000000000000000001551211030706332020763 0ustar rootrootPNG  IHDRL\ pHYs  tIME 8IDATx}yt\՝wV$Ͷlۘs M!=ӝN&CfHLs2Mw 3MLgғ !, ccl,[lUEUڗ;yw[8!|y+7h2O[Lm0rD'@S^^n~]" =whp *$}YMnEםv`T`L{5:7- L֦or~El$45 ԰ H? @A84v|q#7|ؾ;\8:8|aO޼͝*dR|ym#n!ȥuF>mj6+6 LdupoiwHD?tynHz' PVs˳@"rdr5JegPA<[~{]:~*L-YA㡱SS')͛m- wii9^4_Ogї7 Uu\ܠ7@W檼x15=1Ks)'#/U,H}F_IN2-e;5Љz HźyAkіQXY{7xCʯ@zȋ=*>׶e.;G< ?_km׵?̪ۦU@N "8Ϟ*{{Xφ>30B^ ԰kID|O7W7au?&hbgթ _=`[U}O3t= {? +i*eމ1^vuSFz~8|7rVn|46~`9kU7=x?7t_VjHc#z3tQ.B3~.@ɇۼ '\V~EM:+^>9Og˽?$UrLr@geVmauzj\֟0kNT sbzb1 m/@Yw^ZPUk:[uLhYPӚo-ރlҼ͘c|4O'{MOpTlmjo Obo_ʥGsfhݟ,aRݥ'Ld]4iZ`Utly#~rVnzKc"/&#y<>\j_vt@Eme57 $WY iNˆ%d #Tݞgg{"hso}1>N\S |SMΊMʷ_\7wfra ^L͟y;:{%2';Nf.kŴ>Q}g~ r.f]s|=~ WL8YxRNG*Y:|Í3gh-_wV^>|;#ƥBc^ 87eԴ|hW7 6y({Cݏ}sn UƂ }/zBOL=14MM:c|8d|gGz~x-kt'@w3HAp-:Γ` ;-gGـ̶֥+e>MEc AHf{٭KNijdm,6&藌z`US /VOdu. qVp[37X+rFS3MH2Gic֥EiEDXd4kJEY@-W|(GL~̗i^4W-/{{a9uAR0aG|Hblvl5(̀O  ߉k9?@ $LkX"j$%GF4T0AfdUp*o+T7j ,8F(X 292@A,` u;*CT7Z('oA@9(H8c<`njJ7.ʥ!@ˍ#GyrPU2%B&h'T0k93`椪N\fopy)@a y 胘 c2N"8^]}R7(oCgOR'̠Fh yD')'`x4;jWU3?9u=mpGw￶cZn?a0ᓏM `7y  ([#/5G=7&]DkԿO+#=0|OOǘvWozf=Ȭ\˃T7Lq}o:|h`gL)ex:^RWN?5xs]=={1"> U7|e3Dɹ$_ْM }.BL~B8@ê*Y\W CQ[#?pWmW>@m>W7?w-T-PD.= O$X۽n?; xTX$KYr'窼@47#ph_8+6׭y(o6"T|%Ì &Ƃ|hϝMf8aB%Z쭺0ޛaMN:glQ!!B>tUOy[e5MߙivaїSw'9㟫żঞ )ٶV˽D.D,3D8a^~Og&ZqR2z1*JU/b,ohrj񾧣} ?!܌;B_HS0*Z/Glu3mD.(L@0G`|~ODnSnsm`w;H7{Hw>ƨ \*j?+{=! Z][]k8ذ&[<"DDt\a^lj$2~Ƙ"\MFLA~L,IpX =l0QS䀽l}qf`1ubr8SϳT씦&-lj$Y/D@ .D@J(D@J\z"pIENDB`portmidi/pm_java/pmdefaults/pmdefaults-icon.gif0000644000000000000000000001550011030706332020741 0ustar rootrootGIF89a!  &*/ %4: 59?0E@FKL  ZSR *H>Zbai jQ FWte Q $ ^_ r Q Z T *p0+ ~  p}X 2 y klg _ 93 };B=K zDM~uqOe V zq \m%_#Z %b&u(k'$!#/%%w+m')&)m& ,u/~$.x11&* 2 /)0).2+,++0$4#/#.8&5&4.1/0'6'22.,7-9'=84830;19)<*?485;-=.@6>>;9<(E2B3B3@3H4?<@=D>C.E9E8I1H9H:HN@I8LGL0OMLCLDJNCUHE?Q?PGP?TFS7TJLJN:VRNQQCWDS;UMNDVKUVK=WFS=VMR>[LXNTFZLZORHWNXIUAXQSUWJWB[8\JZQXDZP_UWM[XONZGcI]I\P_NeQaLc[^!Created with The GIMP, H*\ȰÇIHŋ3jȱǏ!IIޥ\%˗.cœ)&͛6sܩSf@ 'ϣF"]MPJuRϫVbݪ+ׯ^Â+,ٳf]ʶ-w&n]mݘΤkT8.e#IShؖr ecRlـtƁi}GN8:k㺴ґ!vGK-`(4ɻ(,r)4W.3`Ͱ Ľ@;U[!߁{4oR-WTpJXR;xp 6 oH2H)R>,\eЅ,># QN~4?aaSokr#,IOWqxP>9h8Olix6@ O*YBsY49l @`a@p7Jag}xo@|6aUU)[!*˩9/EY@D.b>Vb&2oRQK G)\kBU Vh h@ȋ3`!  OSxv@ > @eF3&p$ϩXdˬm[DPFs{?C-fU!?*i hH4*['VdΪaua< s \؄"곅,-#`1-vAӅYH"%@\hS ~Y>;<'̲DtqsA2Nb#Vbz> P!KG(􇨥5/x7/ 4)@ .@zթL/7ƒ^?zcȅ@L`tX^k9 q{0dg}I$5L+JQ[>dh<("+H(ܼ$+T`/B˕U>!i 0E'@ACZ)Ide8mu*K2@1 K>J{!9Ha!PM @}CӣL(+7@PQig9b0=,0@J 7#D#H(B4 |$ I,)֎U =s<}= 8V0ԍ1\gJ;at/ lQ @FvPA 0C~CibjB a3$4}b?6 &yz=JQ2B(-lAȃ\jVD頸ZU$L 3Zi2 W'ӬB﫚!aWTɤD3z",lb4.OkY0M΃Gghu= *V925hSa#תAoY)` 51KXV VmHkڔ"0amfX|XCDQ&Y_E0&MPݬJܨ>Q TxܠhGO[Pw7>xC7JӲDM"[ FW7l\#9 P 9x `Pt#}Z' cⵣLO9-Wr `8\ X@$|!te"VԭpX+a1awt,Q@-j8(0o^% w vLītX k=nf)<4@$p$@ ×aut<זgm-{.@$ Cbx. hA% |>oXGVhN 3;v z<N2+Lز8~5wX%B P ̣L2ށL h ۉvG $`G  Sw.W%nekj3M>;,WG+8`9Hm:voAjL uxb/2d~@!>7۸|j_(pz@5BOAz%dxDnVΡ9g[EO̰|hyTe:m 69}yF6J7xT/kyS ` Fߎ핻|Մ%m>rpjGpZzNvkD4`CytwNuԧzWrl2|F{%%w}hgW&00 $  &Wgp=|4}~2\^Igv-n! &PVGkBUEy7Yƃ[Hh~ b@l.Kjg!687fe[q`#gZ{%"IZq `|7rosx}6UrnxQf_\za P   _yeL88XSՆ8r(0G{ " \gr@Wuxz`[5l%Yp N7 @4 XGeƌ'ua@ X/0|w[ y7]7mcՆG\+@ZWp(Y5_G{1E'w= 8P{_ЕY!{TT|T`Xh< O`d ` P%GR]_Km* _k a8\\Trxw[2Mb?5NpFH w>XZT8f8{b"9 i #zH3|"9s5kG`sWF @h'GMv%oD[x8pqV0 P@8/zXhU' a=[gvfhyh۵␝SЂua5iRuWV7iZ"_`gYa #Ps@v Y҉؊cimV`bf10nivha7h}Nš5D9p;Lf9V)Ex{aixt H.0i 9p{)thoXP،1_u) !P0%1c7LI[֤ELk8( 7 @Y}* }٨D8z]UpʸG Gu")BKG# ]d}^5[FZ A`s}JipdAp@`m֕}ɑlUfr8te[99%SBiDi/gzri^^:[(=SaJaZtl^ sZtc() @,0*ʎW:hVe%)hekc  )A:l%5mGyg'Z HC=pBiO.H `9Wz mm!  rG6Hp ɦEgwxؑ2W z;9_ @H 0/d0c!sQxiUX .  p`ZٯQ vƌ7ti@!gLvv*ieB!r:=4dhJ i% l eP|^q} LwO*- (f/0l .paI 1K1f^_`|]gp0m 08: G'^tiʦٹG {f< ]&x^;E \ @` c~\? ` -+$C̝3z@['@7Ip t)|'`'pd@R'[VAVA'`6p(i`x,`d +~`ewƚA . f*2~P+Xp^.h==ܱ9b3 q ~ . ծ 2@@{вDƱ Pɐ :  6ܩe)2 aA˾a-aR?Z=@x@'V1K(&x|W=ɢ+1 E+*3LwAL@8Rb?0  =k3H.k@7"%N]{$X73%C#0R O=gd=?|S Q*3`kP p+(ÀdA:`)Nq<"5H65co V8^ ɮZc(; q  VQLurPcJ:Xcs9cP@K\"" o??PdqMΙ÷\d"N14%Q+!O߻|2` A}{Bp$% Oٚg> \Bw rFkj)ӦΜ/'|2C}c|1Bq2B@7 8ry&^%-o,l(`Ζ;gaܽ1gHP095 `)DLa u8Z- \Ԗ5 ˲USKKL\c]lIMl˜Xf7G `09+[*1` , Eq) aព` lK7o> 'v f>-'o^jf&#jaR^,* ;'/k(I+rI͛n &ӱI9's/$Rȗn-ͼrl'AԍGjF5 L )&Q7Ҵ3{3C G3u!сTyjU0U& M%4*KCNDd5Lem'iGnwڳ:TeUV3ϸQX/CC]X{S2?hK3]XvWG'.x5_WYi#F5ksS_U=N=NIG6d$ /dev/null portmidi/pm_java/pmdefaults/pmdefaults.ico0000644000000000000000000030253611127373026020037 0ustar rootroot hV 00 %f@@ (B; (6}(  @]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EB1N:7)D3B0;,o*C27(3%\D]E]E]E]E]Ey."n)>.B12%_$\#B1<,t, \D]E]E]E]E]EZC\D]E]E\DV@[D\D]EZC]E]E]E]E]E]E]E]EU?]E]E+!J8]E]E]E]E]E]E]E]E]E]EZC}$;,H7-"]E]E]E]E]E]E]E]E]E]E]E]E\E=.( YB]E]E]E]E]E]E]E]E]E]E]E]E\D;-BR=]E]E]E]E]E]E]E]E]E]E]E]E]E]E(YC8*]E]E]E]E]E]E]E]E]E]E]E]E]Ex']E/$]E]E]E]E]E]E]E]E]E]E]E]E]E{(]E/"[F]E]E]E]E]E]E]E]E]E]E]E]EI&w%\E]E]E]E]E]E\D\D\D\D]E]E\DM:\D\D[C\D\D\D]E]E3&F4k(:+~0#8)d&}/#7(j(f'>.0$e&]E]E;+:+E3K77(?/I6;,C2M9QZBYBU?U?Y"9** M9R=A0XAP;o*;,\D]E]E]E]E]E]E]E]E]E]E]E\DU?YB]G]E]E]E]E\D[E[DYB]EXA\DYB]E]EXAYB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EG5\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK9.{Q=]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EH7R<]E]E]E]E0&,"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EUSA]E]E]E]ERG5]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ET>lXPq6*1(-YC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EI6a) ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0%N9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[D-".  G3]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\FI9%J6]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXC#VBV@!]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ8.\E]E\ Q>]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED30]E]E.$/%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E<-B]E]EI8W]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0#_]E]E\E<[G]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E}*#w*"]E]EXB2YG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EdTM>F5\L\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EM:-_N:]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6)G6]E\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D\D]E\D[C[C]E[C]E]E]E]E\DYB]E[D]EZB[D]EZCYB[D\D[C[CZC\D]E]E]E]E=-<-]EL80$`$S=a$h'Z"FR=Z"2%E3X!3&y."9?/W!88*F4O5'r+ I]E]E]E]E;,Eu, E3t, Y!L9]#`$Q<>.4'20$9*QF44&<5'F4Q7)D3QQ$ R=\D\D1$Mo*CN:+ \D\Dy."H:++ G4D2% U?DD3?c%X!2S> [D]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]ER= E3R=ZC3J7XA$ D2' [C]Ei'4'O;( }/#v-!# T>@>. V@H60 S=[C\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]ER=H0 NM4'G4! K7 A0N:]#x-!N:' ?2%;# T>@B1 D32%0 S=[C]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\DR=! Q2%N:@/X!{."0 W@j(\D]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]ET> A, P[C]E]D\D]E]D\D]Eq+ 8)Q<L]EMV@y."M9]E\ES=2V@["\D\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]EU?RM;\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]D\DQ>%\D]E]D\D]E]D\DA5/F7]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]E]E]E\E]E]E{"(#\E\E]E]E\E]E]Es!T ZE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\D]E]E\D\D]EQ=5= 3'H9P>VA\E]EYGDc [D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]DT>*"z"K$+G t"y}*q*"\E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]E]E]E\E]E]E\E]E[ED05*6 9 E7]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\D]E]E\D\D]E]E\D]E]E\DWDJ? YA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]D\D]E]D\D]E\Ew# ?-\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E]E\D]E]E]E]E]E]E]E]E]E\E]E]E\E]E]E\E]EYDz"!  <+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]D\E]E]E]E\D]E]E\D\D]E]E\D]E]E\D]E]E\DL<1*`'=+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\E]E]E\E]E]E]D\D]E]D\D]E]D\D]E]D\D]E,'B1\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\D[Ds*"P?]DP:!Q>\E]E]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E\Ei*XE]E[DE3(]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\E[EX 2\E\D]E}!_\E]E\D]E]E\D]E]E\D]E]E\D]E]E\D]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\D\EB :]E]D\EA26K9]E]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\EXB, P]E]E]ES?4.&]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\EQ<"f ]E\D]E[EYi]E\D]E]E\D]E]E\D]E]E\D]E]E\D]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\DH4%]E]D\E]E,#9[G]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\ED5 6-]E]E]E]E5%'WH]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\E=3@3]E\D]E]E|&+XH\D]E]E\D]E]E\D]E]E\D]E]E\D]E\E]E]E]D\E]D]D]E]E]D]E]E\E]E\D\E]E\D\E]E\D\E]E\D,$@5[G[DWD4,T\E]D\E]E]D\E]E]D\E]E]D\E]E]D\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E]E]E\E#[d= $@0]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]D]E]E]E\D]D]E\E]E]E\E]E]E\E\E]E\E\E]E\E\E]E\E\Ee! : G 49qB1\E]E\D]E]E\D]E]E\D]E]E\D]E]E\D]E]E]E\E]D\E\D]D]E]E]D]E]E\E]E\E\E]E\E\E]E\E\E]E\E+!WR>]E[D\D]E\D\D]E\D\D]E\D\D]E\D\D]E\D\D]E\D\D]E]E\E]E]E]E]D]E]E]D]E]E]E]E]E]E]E]E]E]E]E]E]E]E\EYC\D]E]E\E]E]E\E]E]EX@]E]E\E]E]E\E]E]E\E]E]E\E]D]D]E]EYB]D]D\D\DYB\DYB]D[C[D]D\D\D]D\D\D]DYBYB]E\DZC]EYBZB[D[C]EXA\DYB]EYB]E\DV@\DZCW@]E]E\D]E]E]E\ET?( T>]D]EE3HXA& V@i'8)=-) % ;,\Ez."EG6(L8:L8$ c%=4'8) N' P;1\Dk(/ ~0#5W!N]E\D\D]E]E\ER= M9YB\DA0?W@ T>`$4'7(JYBC1 S>9*>.?.J70 J76@/?=-Y!7)N:N:( [DK@/P;?.r+ + ]E]E\E]D]D]ER=1 0 2%A03T> M9Z"5'7(M\DXA J6<-0$HJ70 V@7)@0* >.X!;+R= N:( \DJ@/C20 7(A0]E\D]E]E]E\DR=! R=K7 ?.?HAU 1 J77(M]ER= P;7)JAE3Z"7(TW!<R;,;+D2YB]D]E]D]D]E[C=-;+[C]E]E]E]E]E]E]EYB@/]EL9W@]E]E]E]E]E]E]E]E]E\E]E]E]E]D]E\D]D]E\D]E\E\D]E\E\D]E\E\D]E\E\D\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E\E]D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\D]E]E\D]E]E\D]E]E\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E(@ B]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZBZB]E]E]E]E]E[DS=[C]E]EXA[D]E]E]EZCR=\DYB[C]EV@\D]EW@]E]EW@]E]EYBV@]EWA]E]EW@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EU S]E]E]E]EC2 @/]E92%]E]E\D$ ^$C{."Q<3%N:U?E3 \D<-Z"W@E3 \D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EDA]E]E]E\Dy-"]E3%ZB+ v-!]E]EU?D2]E5m)6(>I6Q<@/ZBq+ ]Eo*S>@/[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED3I6L8ZCS=G5]EL9N:+ q+ ]E]ET>F4]E5m)S! F4Q<@/Q<F4]EE3S>@/[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED  F4 7)]E<-XA+ E]E\DT>F4]E5l)9*2%Q<@/XA6(]E3&S>@/[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EDA]EYB" O6( C 3&]E2  >\#+ M95ET>?FQB1[D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EDA]EXA! P]ER=C2Q<]E]EN:V@F4U?K8:+[D5 , ]E0$ Q<[CG4]E]EK8G4M9S>[CG4]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQI6]E]E]E]E]E]E]E]E]E]EXAL8]E@s+ ]EK7T?G5\D]E]E]EP<U?G5\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYBN:N:P;[C]E]E]E]E]E]E]E]E]E]E]E]EXA]E]EXAO:[C]E]ER]E\DP;]E]E]E]E]EJ7]E\DP;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E^G^J^G\D]E]E]E]E]E]E]EYA]H\F]E]F]E]E]E]E]E]E]E]E\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[G#>-YF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E?3.@M9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4("K0%%@1]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZCYB]E]E]E]E]E]E]E]E]E]E[ (O>]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\Gu 5$]E]E]E]E]E]E]E]E]ESH3PZE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E1)BUH]E]E]E]E]E]E]E]E]E4---#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[FW>5]E]E]E]E]E]E]E]E]Ea $6&]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E=*?9W v ,%1%I:ZF]E]ETLQT@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[D=0.%('N! .G YKW(!WE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZEA,+!g'$$!ZG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQD. $]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK>*'M8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\Ge1#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWCh 0"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E>2r9"3"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYJ@/.%#2#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYJ2!;,]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVF !I;]E]EK5*"C7]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EO>#*TD]E]EU@Fi]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E>1$6ZG]E]E]Ef;UE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E3&?\E]E]E]E0%/6+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E.#H]E]E]E]ETC7_ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E' ^]E]E]E]E]EO 1QB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ep"u&]E]E]E]E]E*#!.%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZ ,%]E]E]E]E]EA3#y$ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG/$]E]E]E]E]EYG1J ZG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[F>=2]E]E]E]E]E]EF/XK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXH.!RC]E]E]E]E]E]EH (TH]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EPD#"VD]E]E]E]E]EL; 8WJ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E=3!^M]E]E]EWCRBL `\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0'#T75D:8),%9 :+]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E.'* +}$\F]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E}+$X^F?L @.]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E%lYE]E]EZD]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[EWEO<]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EU=]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZBZB]E]E]E]E\DW@]E]EW@]E]EW@]E]E]E]E]E]E]E]E]E]E\DS=ZB]E]E[CYB]E]ET>[C]EXA]E]EWAYB\DWA]EXA[D]E]EU?W@]E\DS=YB]E]E]E]E]E]E]E]E]E]EU S]E]E]E]E>.]EK7U?T?L8Q< r+ \D]EF4 / 4']Ep*O\DC6^#]E4&V $ ]E;1%]E;,<, 3{."]E]E]E]E]E]E]E]E]EDA]E]E]E]E8*]EE3Q]EL9A0K8]E]EM9W@]EXBL8]E- t,![CR3S>]ES=C1N:]E]E]E]E]E]E]E]E]E]EQI6]E]E]E]E]E]E]E]E]EN:MYB]E]E]E]E]E]E]E5'GM9]E]E]E]E]E]E]E]E]E]E]E4{."]Er+ N]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYBN:N:P;[C]E]E]E]E]E]E]E]E]E]E]ER=N:O:V@]E]E]E]E]E]E]E]E]E]EI6F4[D]E]E]E]E]E]E]E]E]E]E]EP;W@]E[CZB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E( ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQ]E]E]E]EL8XA]E]E]E]E]EM9I6XA]E]EQ]E]E]E]EL8XA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ7J7]E]E]E]E]E]E]E]E]ES>QGP;]E]E]E5(0]E]E]E]E]E]E]E3& F4<- \D]EU?J]E]EI6 V@]E]E7), ]E]E]EF4" v-!O: WA]E]E7), ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(3&]E]E]E]E]E]E]E]ET> , 2N:]E]EZ"[D]E]E]E]E]EZC& A0n*T>]E5'S=]E7)G4]E]E^$ZC]EM9   % K7]E]E^$ZC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]EU ?/]E]EG4=]E]EW!ZC]E]E]E]E]EO:g']E]E]Ek(S=]EJ;,]E6(F4]E]E[#YB]EJ7)]E]E6(J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]EYBH]E]E]E]Ed&Q<]EW!ZC]E]E]E]E]EL8~0#]E]E]Ek(S=\D]#]E6(F4]E]E[#YBYB?]E]E]E]E:J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]EK71$]E]E]E]E;,A0]EW!YB]E]E]E]E]EK8~0#]E]E]Ek(S=K7  ]E6(F4]E]E[#YBL9{/#]E]E]E]Es, J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'K6(6(8)?/S=]E]EH63&]E]E]E]E>.>.]EW!T>]E]E]E]E]EK8~0#]E]E]Ek(S=3&y."R=6(F4]E]E[#YBI62%]E]E]E]E{/#J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'MU?S>d&]E]E]E]E0$J7]EW!F4]E]E]E]E]EK8~0#]E]E]Ek(S=J) P;:+6(F4]E]E[#YBQ<_$]E]E]E]EU J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4' 97$ 5]E+ T?]E]EYB!  \D]EW!^$]E]E[D]E]EK8~0#]E]E]Ek(R=k(]E [#6(F4]E]E[#YB]E  S>]E]EO;J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EM9 E3B1 2%4'* ;,]E]EX"222%J7Z"7x."Q<]Ek(A0A0]E^$ 6(F4]E]E[#YB]E2% 1%{/#J7]E]E[#YB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Et,!4']E:+  5']E]E]Ep+ & Ss, U m)]Ek(m)XA]E<-n*F4]E]Ep+ \D]E\DZ" x."J7]E]Ep+ \D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Es, 4&]E]EV@9*n*n*7)T?]E]E]E]EU?q+ F4ZC5'n*?/]EU?2%Q>.WA]Ek(/ 8]E]EU?0F4]E]EU?r+ C2]E]E]E]EG5y."o*9*YB@/J7]E]EU?r+ C2]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EI6F4]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK8~0#]E]E]Ek(y."]E]E]E+ F4]E]E]ET>[C]E]E]E]E]E]E]E]E]E@/J7]E]E]ET>[C]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E5'" 9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EM91%]E]E]El)G5]E]E]En*F4]E]E7), ]E]E]E]E]E]E]E]E]E@0J7]E]E7), ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG5NV@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYBE3]E]E]E9* \D]E]E]EI6S>]E]Eu,! \D]E]E]E]E]E]E]E]EI6Q<]E]Eu,! \D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EN:A0@/@/@/A0F4U?]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EV@Q<]E]E]E]E]EK8@0B1U?]E]E]E]E]EM9A0B1T>]E]E]EZC:+L8]E]E]E]E]E]E]E]E]E]E6(:+]E]E]EZC:+L8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EcP^OaQcN[D[D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EO6]E`QYK]E]E]E]E^L]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[B[D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EA9F@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVOdJ\ 6'SEWL]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESF0+@'"6E`--MO]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E: '4B\]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ep/,?IQPhTB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[LF"#G D7^HWNMEG:P?]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E;.540)]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQ?O;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ej">UJZC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E>5gpV@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVQ]YRG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[PZL|]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESGID</"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ETJsEGMC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQHx' 0%IOI]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ETLP6HXSUE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ERLG,3[]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EB;67EB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E/-17h QB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVJW T NG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E# 1)TB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E.!V 4c  82KAUJYLXL]E]E]E]E]E]E]E]E]E]EFM )H3]F]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E Y3(++#!#+4AQ^l #ICTL]E]E]E]E]E]EP\~ $+SAYF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUBB3_H^ O)&+5?Ia*&81|3;p -VF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQHQK]EJEPR7;a 5"3OF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ERF<-Y7/")~*%OK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EX=]E[GM?OGMIA   8SM]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EKIC    Ah]G]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[GA>> ..]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESK2+= NS>]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK@>   3(\E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYM[ '  'eWB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EKBT %     +YXD]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG?O-  )U]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUOV<+   "U]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ED;P9. "Y ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESJMF,+p H;0%'b]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ETNWP:1m T@ -b]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EROU0g [E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESO\2s WG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYOC 3$]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWCZL5  55+TD]E]E]E]E]E]EREPC\Q]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVDTG25F9XE]E]E]E]E]ErZ]RI]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EI>18OBYD]E]E]E]E]E@3\4;:2]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E;21=SGWC]E]E]E]E]E]Ec%%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E0)0 GVJ]E]E]E]E]E]E]Ex % hSL]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUEv2VXJ]E]E]E]E]E]E]EE;<'?H@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWEm 0_\G]E]E]E]E]E]E]EQGJ.0u&WF]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ea+ e]E]E]E]E]E]E]E]E]El 7*FYL]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ET" m ]E]E]E]E]E]E]E]E]E=4F#2<3]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZIF| ]E]E]E]E]E]E]E]E]EZPS!(q ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESD:&]E]E]E]E]E]E]E]E]E]EgRRJ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK=1  ;.]E]E]E]E]E]E]E]E]E]E&"E95]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG8+$I=]E]E]E]E]E]E]E]E]E]EOE+0l NC]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EC6$)PB]E]E]E]E]E]E]E]E]E]ERED'H]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'  0VH]E]E]E]E]E]E]E]E]E]ETFg%7SK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E">\M]E]E]E]E]E]E]E]E]E]E]E905)=8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EyK]E]E]E]E]E]E]E]E]E]E]E]ERFE ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]El  #[ VE]E]E]E]E]E]E]E]E]E]E]E[MTeTN]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Ed +tSA]E]E]E]E]E]E]E]E]E]E]E]EeOVR]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXJ^030UC]E]E]E]E]E]E]E]E]E]E]E]E|CQQ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWKU3EA]E]E]E]E]E]E]E]E]E]E]E]E]E@KJ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ERK:0KB]E]E]E]E]E]E]E]E]E]E]E]E]Ej CNM]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\FMG40QD]E]E]E]E]E]E]E]E]E]E]E]EZMGORP]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EWI@:77ZIPA]E]E]E]E]E]E]E]E]E]E]Em" dPP]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUG/)51dS]E]E]E]E]E]E]E]E]E]E]E?@, #ZG]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EUFx/ -`QYN]E]E]E]E]E]E]EF>]E397 +<5]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVGi 0 XXR_YSLWKYDS;\GWIKGs9N SE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXJd6  ,E,0;<&/%VS'B0"]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[N[1 !3<A2-){\K]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EXMP   %7JzZK]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]ESH4 ,'!'8Mk =/]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EYJ%B#A992rdbhqz0'RE]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK;+ ,#OF]E]E]E]E]ERB]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EE4O.1E>-]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EVHWJMC2&S@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ5Q7]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EQP;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EZCK8G5Q<]E]E]E]E]E]EU?O;]E]E]E]E]EM9I6U?]E]E]EO;WA]E]E]E]EYBK8O;]E]E\DJ7[C]E]E]EL8XA]E]E]E]E]ET?G5J7YB]E]E]EYBK8H5O;]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EJ7J7]E]E]E]E]E]E]E]E]Ep+ @]E]E]EC2V@]E]EU? F4]E]ES=& =9*\D]E]E]E]E]EV@Z"$ =-]E]E]EXAF4]E]EL9% @L8=- ]E]E]E2% " F4y."^$]E]E7)* ]E]E]E]E3& F4V@W!}/#\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(3&]E]E]E]E]E]E]E]E]E9 ]E]E]E~0#G5]E]ED31%]E]E9*@ZC]E]E]EWA% Rl). 9*]E]EK82%]E\D! V!o*+   ]E]EB1  ! 3]E]E^$ZC]E]EZC& @06W!x."I}/#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]E]E5]E]E]Ez."F4]E]EC2~0#]E]E6(V!@/@/>.x."\#]E]E]Em)B1]E]E]E1$/ ]E]EJ71%]EN:^$]E]E\DW!V!]E]Eb%0$]EYBS1]E]E[#YB]E]EO:g']E]ER=A0]E]E]EE ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]E]E5]E]E]Ez."F4]E]EC2~0#]E]E6(~0#]E]E]E]EL9 N:]E]E8]E]E]E]E]ED2I6]E]EJ71%]ET>R]E]E]EM9p+ ]E]EKV@]E]EXA1]E]E[#YB]E]EL8~0#]E]E\Do*5']E]E]EL9 ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]E]E]E]E]E]E5]E]E]Ez."F4]E]EC2~0#]E]E6(~0#]E]E]E]E]Eh'|/#]EV@. ~0#~0#~0#~0#0$6(Q<]E]EJ71%]E]Eg'6z."C2R=o*]E]EH]E]E]E]E 1]E]E[#YB]E]EK8~0#]E]E]E]E]EG5n*+ q+ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'K6(6(8)?/S=]E]E]E]E5]E]E]Ez."E3]E]EC2~0#]E]E6(~0#]E]E]E]E]EB1L]ET> ]E]EJ71%]E]E]E=-N m)]E]EH]E]E]E]E! 1]E]E[#YB]E]EK8~0#]E]E]EP<2 5(\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'MU?]E]E5V@]E]Et,!>.]E]EA00$]E]E6(~0#]E]E]E]E]EM96]E[DJZCZCZCZCW!]E]EJ71%]E]EXAE3\D]ET>>.^$m)]E]EH]E]E]E]E" 1]E]E[#YB]E]EK8~0#]E]E]E* 91$I6]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4' 97$ 5]E]E5;,]E]ET U ]E]E5'4&]E]E6(~0#]E]E]E]E]EP<1]E]EF W@]E]EZC :]E]EJ71%]E]EY"1$]E]E]EM9|/#]E]EH]E]E]E]E" 1]E]E[#YB]E]EK8~0#]E]EZCn*]E]E]Ek(% K8]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EM9 E3]E5 h'h'Gq+ D2]E]E6(~0#]E]E]E]E]EJ7A]E]EI63@/A0=B1]E5(V 9s, M9s, r+ E3B1?D2]E]EH]E]E]E]E" 1]E]E[#YB]EJ7Z"7x."Q<]E( 8J7N:b%=-]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Et,!4']EGCS|/#r+ M]E]E]E6(~0#]E]E]E]E]E7)j(]E]E]E>.7)]ES=i(YBEP]E]E]E\# ]E]E]E]E8E]E]E[#YB]EU m)]EJ7Z"\D]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]E]Es, 4&]EM9o*O:]ED2t,!t,!F4]E]EJ7y."s, @0]E]E]E]E6(~0#]E]E]E]EZC( C2]E]E]E]EWA:+m)f'4'S=]E]E]EH5~0#T ?/XA]E]EH60$d&e&|/#F4]E]E]E]ER=o*G4]E]E]E]EL9o*N:]E]E[#YB]EU?2%Q>.WA]E]EXA:+o*j(3&L9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E4'1%]E]E]EI6F4]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(~0#]E]EXAF4>/ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EK8v-!]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[#YB]E]EK8~0#]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E5'" 9]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E6(N:]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EV@! 9*3&Q<]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E\#YB]E]EM91%]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EG5NV@]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EH6LR=]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E[#r+ ]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Et,!]E]E]EYBE3]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EN:A0@/@/@/A0F4U?]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EN:A0@/@/@/B1H6XA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E@/v-!n*5(XA]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]EW@{/#E3]E]E]E]EV@Q<]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]E]Eportmidi/pm_java/pmdefaults/pmdefaults-license.txt0000644000000000000000000000333711127373026021521 0ustar rootrootLICENSE INFORMATION PmDefaults is a small program to set default MIDI input and output devices for other programs using the PortMidi library. Latest version available at: http://sourceforge.net/projects/portmedia Copyright (c) 1999-2000 Ross Bencina and Phil Burk Copyright (c) 2001-2009 Roger B. Dannenberg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The text above constitutes the entire PortMidi license; however, the PortMusic community also makes the following non-binding requests: Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. It is also requested that these non-binding requests be included along with the license above. portmidi/pm_java/JavaExe.exe0000644000000000000000000040000011127373026015042 0ustar rootrootMZ@ !L!This program cannot be run in DOS mode. $(4rFgrFgrFgnJgrFgmMgrFgnHgrFgmLgrFgmUgrFgrGgrFgQLgrFg;t@grFgRichrFgPELBE  ¹0@@@6xZ0.textH  `.rdata40 0@@.dataPPP@.rsrcZ`@@Vt$Wj VRuj VCtj=Vq3V{GWrhQAVhQAVhQAVhxQAVhlQAVm{h`QAVWehTQAVA>hHQAV+(h8QAVh$QAVhQAVhQAVhPAVhPAV|hPAVOhPAV{9hPAVe hPAVOhPAV9hPAV#htPAV h`PAVtzhTPAVtQhDPAVt?h_^WA_^WnA_^W]PA_^WFA_^ÐVWhQAjj$1APj,1AP t)?t$j WtFW7u_^ÐD$L$VPQtNhQAPLt:F u+VT$hR趙 tD$PF tV?^Ð3V$WAVD$ hQAPڙL$Q T$AR $$AWV'WV$_^Ð 0SUV$WL$PQD$  $$D$$RPVL$,hAQ,؃ۉ\$u _^][ 0S-D$0RAtA$00uAAURUL$(UQUUPU$@hRAR A$HPQ44tKUPU$( hRAR趘$0 3+$уOʃ󤍄$L$PQ4tKUPU$( hRARR$0 3+$уOʃ󤍼$3$+ȃ󤋼$(0tW3+$ $ 3 RA+уOʃƄ$ ARA3$+كOˍ$+كOˍ$+ыOʍ$+ًOˋ\$At$QP"=At,3+$ уOʃ At)$$0uAQP$$ hRAPB9$$0t&3+$ ȃƄ$ $,0uA AUQUT$(URUUPU$@(hQAPϕl$<,tR$$ QR$$j$((P$, QRUD$8SPA$uj2_^][ 0Ë$ 0t/t*$ $QD$ RP`" u |$$$Q A$ RPQ.$,RB$0P讒$4Q~ƃH?H$W$ RL$$PQ1"=AQAϊ:utA:Fuu3Ƀu0$40$Q$ RL$$PQh_^][ 0þQANJ:utP:Vuu3u0$40$P$ QD$$RP_^][ 0ÅtS:_^][ 0;_^][ 0Í$QSr_^][ 0Í$$RL$ PQSIl_^][ 0ÐD$SVWjP.|$8L$0QW?T$8VRmL$@؍D$$PVQ@T$0RjjjWS~<_^[E#P$PL$hPRAQ$$$jR$P$QhDRARPth uFF< t|$l$t WVjՃ ΄tC<"t4u3:D$$u-D$ tF> uFF< t>tWVQՃ NFFu_^][ÐD$L$ T$j PD$ QRPeÐS\$W3D$ UVt$hRAPa u;{hRAPI u{bhRAQ0 u{IhpRAR u{ 0hdRAP u{hXRAQ u{M[^]_[ÐD$VWPAt$jVh@WQttT$ jRh@Wt$_^ÐS\$uA[ÊUt39-nA~jPȐlAȊJtCCù;tLVW3It;v09-nA~jPzlAJtN;wF_^][ÐD$Ul$SVWj%U؃3Cl$+j%ыOS͌tSShFt)3+|$уOʃj%U肌؃q,RA3+ыOʋ3+|$уOʃ_^[]ÐhRA蒏uAÐhRAruAÐD$hPL$Q ÐS\$Ul$VWA3j\+Sȃ"t-x3+ыʃ-t3+ȃf RAf uRj\hA詋tx3+ыA3+ȃj.U[tAthRAU荎t_^]A[ÐVt$t4=nA~jPXlAȊJtFFũ=nA~hP!lAfJ%t ~:u~\tjhRAV t3^ø^ÐD$P0A|L$#;u3ÐD$jPËD$jPáAÐAÐD$AÐS\$VWhRAS>Ѓt4z3hRA+Rȃ ЃuhRASЃt4z3hRA+RȃŒЃuhRAS讌Ѓt4z3hRA+RȃzЃu_^[ÐD$jPÁ U$ VWu _^3] ù3$󫋄$ tD$jPY(3T$+ȃUEu _^3] Sj;Ul$裇؃U-uZ|$+$O̓RA+O͋l$UF3$+j;O͍$RA+O͍kU;l$跆؃ }U:uV|$+$ًO˃RA+ًO˃UW3+$ًO˃󤍄$P[_^] ÐS\$ Vj.S蒆hRAV:thRAV(UWRA3T$+O̓|$+O̓RA+O̓+ًO˃_]^[Ð@ $@SU$L UhSAP蕆 L$$HQR(0A؃VW$X D$RAD$<:utP:Vuu3tpSAD$<:utP:Vuu3t:D$<$PPUhPRAQ܅$`WRD$3ÐD S$P U$P WShAU} U$ThSAP蔂 L$$PQR(0AD$ VD$RAD$@:utP:Vuu3tKSAD$@:utP:Vuu3tD$@SPU uT$L$QR$0A\D$P 0A^_][D ÐD$L$PQ80AP40AÐT$ t*W3QL$ RPD$%PhQAQ<0A_ÐD$VjPD0AL$ QjVT$RjVD$,PjV$jV@0A^ÐD$SV$VPhSAK$ W%3|$L$D$QH0AT$ D$$RhSAPZD$ _w@uD$w5u|$},L$QhSAS)T$RVhPSAJ^[ĘSVhPSAJ ^[ĘÐD$ SUtHt3tHt3ۋ$ P?u ][ VL$ WT$QD$RPt$ $0 u$ WQT$$hTARVhSAIt=ujjh(SAA tmVhSAJD$$PhPSAJNuuIj Sh(SA  t5L$T$QVR"D$ uNjL$T$QRPD$(PD$_^t PD$t PЁD$t P迁][ ÐVt$hpTAhdTAVjh(SA hpTAhXTAVjh(SA hTTAhLTAVjh(SA h4TAh(TAVjh(SA P^ÐVt$ Vu^ËD$VP{^ÐD$ UW3;t8D$;t8D$ ;t8jh(SA A APQ.;SVU|$|$|$0|WU1D$|jU0D$|jU0D$T$RD$PL$ Q؋D$, ttVeT$$D$$ttWJL$(D$(ttS/T$,D$VPL$WQT$(SRU^[_] ÐAÐAÐVW|$ jjWhtu 5At j4+3_^jh1@L0AÐQD$jPjjrx1At5 TAD$;t'utjPh@hAD$TAYÐD$hTAhTAPjhxTA5 ÐD$PjhxTAj ÐD$PYÐVjhxTA> SUl$ WU0D$0Pj0L$(QT$4RUjV2D$LL$HPQjW|2T$HD$DL$@WVSRPQjhxTAn T$lLRSWhV2_][^Ë^ÐD$L$T$ jjPD$QL$jRPQ, ÐD$ L$T$jjPQRuD$ÐD$ L$T$PjjQRÐL$ tD$jjQ jQL$jPQ ÐD$ PL$HT$P L$T$ 3ɍT$fHD$RL$L$jjPQ (ÐL$ tOQt,tJu?D$QL$PQS"T$D$QRPqT$QL$ QR uD$ÐD$ L$T$jPQRÐD$=ktL:}u7D$ L$hDQMBPjQ~ËT$ jRPD$Ph=tPËL$ T$hDQMBQhR=|=~=uȋD$ L$PhQA ËT$ jRPD$PÐ Vt$ u9D$Pvt+D$L$QL$T$ jRjhAPVQ ^ ËT$D$hDQMBRVP^ ÐCD$~~uD$ L$PQj~ V ÃTH73Ҋ7@$7@D$Ht.HtHjjh jjh jjh ËL$ T$jjjjQjRP =It/~t=uI+;3ËL$ T$jQRPËD$ L$PQh =t'=tËT$ D$RPh\ 3ËL$ T$QRh ÍI7@6@6@Y7@S\$Vt$W|$WSVI uu_^A[AD$WSVPt1A_^[Auvh7@hTA(rD$ Pn A jQjjhhhhh hAhTAj1AjhjPA1AAR"]YáAtPQ]AP1AAÐD$AÐD$hUAhTAPjhTAÐD$HÐT$VWjz3΃RL$QD$QRPT0A_^ÐD$S\$U-X0AVpD$jPL$jQST$(ՋD$~4WuAD$jP3QRSՋD$HD$_^][Ð$L$D$QRD$ D$XD$D$ L$ h 9@D$h09@T$L$$hp9@D$$RPQ:Ðd3SUV$W|$PD$PL$$hQU33T0AD$~nRetۉt$~N\$3$PD$$PhQUT0A$RD$HD$ut$VSWjhTA$Wt ۋ~R+vKuVv_^][ĜÐD$hP:@jP9 ÐD$L$VWjPQh UA7V8t%T$RV.tVu_^V3u_^ÐD$ PjhTA: t-D$tjvL$T$h`;@jQRh UAy;ÐASU$ V$W$EtP$$PL$h@UAQq$4$(tjjUWT$ SRu$ jjUWSP3_^][ÐD$T$VWr B L$RQL$QL$QRPVV_^ÐD$|L$;}I <t3ÐD$Vt$PVu^ËD$ V L$Q VjQP^ÐD$L$ QL$jQ IRRÐD$L$ QL$jQ IRRnÐD$Vt$PV t!D$ V L$Q VjQP^ÐVt$ W|$ VWtVWAu_3^ËD$j$P.t_^ÐD$`UAuPUAÐ{PÐT$ D$D$D$L$PQhpUARIrD$ tL$D$tT$ÐS$UD$ t$$tEHUA|* LUA| ttLUAE][VWj$(PQT$,hPRARnD$L$ PQl~dVPotUWVT$(jRlt:3L$D$D$D$PQhxUAWltT$USR D$WTqD$_^][ÐD$ L$SPhUAQnT$hUAR8؃u[ hLUAhHUASE$ tAt;L$T$QRP!D$ HUA ;uD$ LUA;~ 3[ UVWRA3+T$O͍T$hUA+ًOˍD$P=7_^]u[ Í$ QP$RM [ ÐD$ VPtVt ^Ë$T$QhUARlD$P^u0$ T$QhUARlD$P6u^ÍL$Q^ÐT$Vt$ WF,NPQRH u1VhUAuVhUAu V_^ÐD$L$T$PQhPRARkD$PwtL$Q3ÐD$V$ WVhVAPk$L$QWu VWq_^ÐVt$h@VAVu h,VAVuhVAV|^ÐS$SC(hVAhVA4UVL$ WQPRA3+T$O͍T$󤿈VA+O̓_^]L$QPaC u`VAjPT$ hTVARo[ÐW|$G$tASVVA:utP^:uu3^[u_ËuAPjj' _Ð$SUW3Pl$dShxWAh`WA\$(|$VUhHWAh@WAWh`WA t$F$,T$$Qh4WAR5iUh$WAVhHWAM  jhWAhWAVhHWA; jhVAhVAUhVA" PD$Dj/Sg4u@tvL$$QPsud+j/$4щ|$ʃ󤋴$4Vftj/P.fuj.VVgtt$D$SP-Ul$ uUh$WAVhHWAK |$ \$VjhVAWh`WA Ww^$$QS3_][ÐD$SUWP3~UhxWAh`WAl$, |$VShWAhWAWh`WA t$ShWAhWAVhWA hWAVhxWAhVAhWAUhWAt$4Q PD$0؃ t73S+D$ы|$0Pʃ|$t$ hWAVUFt$( V9l$$jhVAWh`WAW^L$$QUk3_][ÐD$ VWHx0;|PQkL$ @_^ÐSUVW3hD$\$f$0;D$t,?t'3+$8ȃJL$T$L$j;L$ T$$$4jQD$hH@RD$8$HD$L$(QVt$(RVu$8PQuqD$C;||$3ۅ~[j.Rct^]_[_3[ÐVW|$ t*t$PztP 7_^_3^ÐQUl$ Vt$SWhAhXAShXAhXAUhXAhXAWhXA|$D6jhXAhXAShXA/jUEDD$UPuaD$tt$ȃ|$jhVAShXAW#SUD$,_[^]Y^3]YÐD$tPYSVW|$3\$j.+Sȃp^tj.P/^^u_^[ÐD$VW$ PWP u$WQ9_^ÐVt$tD$L$PQu^ÅtL$T$ɋL$ RQPt K ^ ^ÐjhVADuUl$VjPU D$ t[3~US\$W:"uB3I~ DI<"uRtPD$VP F;|D$_[^]ÐL$T$ D$PD$ QL$ RPQÐD$uAVPD$ hYAP^$3ɅQ$$T$jD$R$$PQR$t$T$QVPR!D$P^ÐD$ uD$L$T$PQR ËL$T$QRP ÐL$T$ D$PD$ QL$ RPQ%Ð$D$uAVPD$hYAP{]$ 3ɅQ$(T$jD$ R$(PQR$t$ T$QVPR)D$D$PD$%^ÐD$ uD$L$T$PQR %ËL$T$QRP %ÐL$T$ D$PD$ QL$ RPQÐD$VW3uAPD$h$YAPp\$ 3ɅQ$(T$jD$ R$(PQRy$t$ T$QVPRD$P_^ÐD$ uD$L$T$PQR ËL$T$QRP ÐL$T$D$PD$QL$RT$PQR Ð$V$WPV3$(uA[,YAtYAPQL$RQG[$$3҅R$,D$jL$$P$,QRPP(t$$T$QVPR%D$Pv_^ÐD$ uD$L$T$PQR ËL$T$QRP ÐL$T$D$ PQR ÐD$V3uAPD$ hYAPQZ$jL$jT$QRh4YAPj$t$T$QPR D$P^ÐD$L$jPQ ÐQL$ VD$WPQT$PRSu_3^YË|$T$jL$HPQhDYAh+RQC A+ύȹd_^Ð4SUVt$DWVoV4u3ttUtuP^t 3ۋL$jjD$JL$ BD$$J L$(D$,JL$0BD$4J $L$8D$_^YÐD$VP,j:V9 t$@j:P9uj\V8t$@j\P8u틄$t蹬A$$QVPRD$hgAPh:V_=L$ Q螭 ^ÐD$VjjjjjhPp0AV0A3^ÐQSUVWhd0A\$jSx0A-p0AjjjjjhSՋh0At^D$jPjhgAVX0At2|$u+D$$t L$QVЃVt0AD$ t PVT$0V0At!ujSx0Ap_^]3[YËD$,u _^][YËT$ RЃ_^][YÐ3SUV$W|$PD$PL$hQUT0AgAD$:utP^:uu3uG$WI9VU$, ttD$jPWVUX0AUt0At Vq;U|0AU0A_^][ÐVt$FPV>;3^S0AU-0AVW|$jjj2j2hjjPӋjVՅt+j8OT$RjPhv@jjp0AV0A뫐Sd0AVW|$wPhutWփu h%Q:W{:3_^[D$L$ T$VPD$ QRPVj 7L$,T$0HL$0QjPhv@jjP0A^ÐQVWj7|$PET$ORjVh0v@jjN0A_^YÐD$L$T$ hPw@PD$QL$RPQ=ÐL$T$$VPQR30At 3^W$3|$ D$D$L$ P$QjjRP 0A_uL$Qe$ R0A^ÐD$L$PQhL ÐL$T$D$VPQR30Au2D$L$T$PD$QL$RVPQ0AT$RF0A^ÐL$T$D$ jPjQRhÐT$ W3D$ IQL$ RjPQhG_ÐL$T$D$V3Ph?VQR0Au"D$L$PQ0AT$RF0A^ÐD$L$PQh ÐhgAhgAh t@SVgA:utP^:uu3^[u3ÐAÐVjt$hpTAhhAVjhgAhpTAhhAVjhgAxhpTAhhAVjhgAahpTAhthAVjhgAJPhpTAh\hAVjhgA0hpTAhHhAVjhgAhpTAh0hAVjhgAhpTAh$hAVjhgAPhTTAhhAVjhgAh4TAhhAVj hgA(^Ã0SUVW|$D3;t7\$H;t3D$L;t0D$P;t0D$T;tD$X;t0j hgA;l$<eUt$Ht$Lt$t$ t$$t$(t$0|jU&D$D|jUD$H|jUD$|jUD$|jUD$ |jUD$$|jUD$,D$DPL$LD$8QT$D$@RD$D$(PL$0D$(QT$8RyD$DPt$LiD$(tD$4t PtD$8t P֤|$Tt]D$tUQAЊ:utX:^uu3thhARt3t$0|$Xt]D$tUQAЊ:utX:^uu3thhAR萪t3t$0\$Ltntj}tdu33Iы3ILQ!1t/MA"t0RAAtQRURhhAPN0\$Pti|$(ta3AQ0tT$(RhhAP0 hhAIj P-.t@j P.uD$4L$DPQT$@D$PRPL$ T$$QRD$0L$4PQT$@UR|D$LVPqL$XT$\QRbD$tP<_^][0ÐD$`ADAD$3=*LAI3h@AR PATAXAPÐD$jPËD$SVW=DAP3\$ShgA蜽 t%ShgAu*VWW_^[Ë|$VWE_^[ÐD$HwR$@@jjjt jjjc jjjR jjj< @@@<@)@W3@AdAL$ @ADAHAh@R`A(A_u'$At0u$APj"2jYD$,SP؃D$50A=0Ad0APjhօtPhӡľAu_^[F_^3[TVWjj/3|$ D$D$ D$DD$D$ iAD$\A0APVL$dhhAQH(T$D$L$\RPjjjjjjQj00A_^uTËT$\ATÐQV5(1AW=d0A<\AutL$QPօt|$thʐD$P6tL$Qjjhp@jj0AAÐAtjP0AAj]$\AÐS\$$UVSu^][Ël$(W3+AȡA_S~Xt$(UVSUV-L$$Qjjh`@jj0AT$ SR'$hd0AD^][t$(SUVSUVoD$HPjjh$Ajj(jhgA,A0AuhjAhjA0A(AuhpjAhjA(Aá0A ,AL$ T$QRЅu{D$ SUVD$ D$W3~Q\$(l$$T$L$QR,Au!D$SPՋ(AtL$QЅuL$D$G;L$|(A_^][tT$ RЃÐL$SVWqL$3y(;u.Q$t t uAIPQhkAV1A_^[ÐD$H$SX(UVWtt  HPQRD$hkAP1A$,t$odŊ:utP:Vuu3u9D$,PFP$hPRAPt$$:utP:Vuu33ɉL$|$3+PыPʍD$PL$ jQSjh _^]3[ÐL$T$D$ Rh@D$L$ Ð3W|$D$PhБ@m_ÐVt$|'}@At P@A^ÐVt$V|}D$ Pٍ@A^ËL$|&}@AuVt$ VQ^ËD$ÐD$|=} L$ AÐD$|=}A3Ð3SV$W|$ D$ PV$|$ C$h@jVoL$QV {jVRT$RVaD$ PVߜIL$ QV9T$ RV)V"t _^3[ÍD$ PV$jjjjWVSQ臝 _^[Ë@Ɣ@@Ɣ@ޔ@@@@Sh0AV5d0AW|$jW$Au=u hhr-_^3[QW3A+_tL$D$PjQh@jj0AYÐt D$P AÐD$hpTAh0kAPjh kA腦AÐAtjh kAuøÐQV5d0AWh֋ xA=0AD$PQׅtF|$uuL$ FQjVh@jj0A^_ÐVW|$ 3Wt|WgtV藌_^Ð%P0A%1A%1A%1A̍B[Í$d$3D$ST$t B8tфtQu WV ؋ ~333ƃu%t%uu^_[3ËB8t6t8t't8tt8tt^_B[ÍB^_[ÍB^_[ÍB^_[UW}3AOE G8t3_Vt$WF @t:t4VtVvK }Ft PfYǃf _^U} S]W36M Vt*uNx AVYtG< tM uـ'^_[];}u3uPt$t$t$uj@t$ t$ U EVEEEEBPEu EP- MxE EPjYY^Q=L$r-=s+ȋą@PÍD$ Pt$ t$  5,At$YYÃ|$w"t$Yu9D$tt$Yu3áAVt$u;5Aw?V Yt4^Ãu-D$tpj^;5AwP})Yu uj^Vj5AD1A^UQEHw lAARV5lADV^teMEj eEjXM jjjQPEPj,uE #E Ã=ASV5AWteu95AtY.uP5AtF\$t>S.Yt/P-;Yv<8=uWSP- tӋD83_^[̋L$WSV|$tiqtOL$F8tt F8t u^[_3ÊF8u~at(8uĊAtf8t3^[_G^[_Ë^[_U EEIPEE$-EEPEu P-UQVutZAuVYVt6PYY:u&EPEPV& tPuu' Vj5AH1A^̋L$ WtzVSًt$|$uuo!FGIt%t)uuQt FGt/KuD$[^_tGIuulGKu[^D$_ÉIt~Ѓ3‹tބt,tt uƉ3҉3It 3IuuD$[^_áAthPAhPAhPAhPAjjt$  jjt$  Wj_9=Aut$T1APP1A|$ S\$=AAu3w#uj^Vuj5AX1Au=,At VnYu3_^[U EVuEEEu EBEP MxE EPjYY^USVu W7}-eNu]EEE }+3@w/uWVSMm m}E E0WSP ]EE;ƉEw SPUYY~+};v SWUYY}u;}Wr u SE+ˋփ I+;|0M ;sU E +MEE9;F ;sM EE EE0E;+}_^[UEW} ;v=MSVE ]u ;wSVUYY~uuWS+} ;}w^[_]ËD$L$;VtT$JtSr@ANu[^UESVWxM }M ;wKtPEÃeuCEE VuUYYt(}+u}u C Eu 9} v3_^[]Ëtu uUY#E YSUVW|$=nA~jPoYY lAAtG7G-t+u7G3ۃ=nA~ jV.YY lApt \F7Gσ-u_^][t$lYUjh1AhL@dPd%XSVWe`0A3ҊԉAȁ Aʉ AA3VRYujYur91AA08 A55tuЍEP`1A4EEtEj XPuVV\1APp`EPbE MPQ2YYËeuT=(Au^<t$<hnAYYÃ=(Au9<t$i<YhL1ASUVW|$;=ANjAD0tiWe?Yt<tujN?jE?Y;YtW9?YP0Au h0A3W>Yd0t U=Y3%ؕAԕA _^][Vt$F ttvff 3YFF^Vt$u VY^V#Yt^F @tv>Y^3^SVt$ 3WF ȃu7ft1F>+~&WPv> ;uF t$F N Ff_^[jYSVW33395`A~MHAt8H t0|$uP.YtC|$utPYu F;5`A||$t_^[Vt$F @t F f F u VjBYFvvv^@ FtltgV ‚u4NWt+HNIN~WPS: E 3tËAA@ t jjS B FMjE_WPS: E 9} _tN E% F ^[]UHSVW} 3Gۉuu} M3Mu39U |xÊ1A31AE$@MỦU؉UUUUxà t;t-tHHtYMPMGM>M5M,*u#EPYEM؉EEˍDAU*uEPYEMˍDAЉEIt.ht ltwMMM ?6u4uGGM} lUЋ lAUDAtEPuP G} EPuPf %ÃgeXxCHHtpHHtl fE0uMuuEPfEYȉMu nAMENf8@@E M@;ʉ}EfE0uMfEEPt;0PP? E}2E)Zt2 tHYEEEPYt3Ht,EtMEEeMnAEPu guEEũEuHM@EPPEPHAut}uPTAYguuPLAY-u M}WYiHHtQHHE'<+u nAMNt8t@+EEEEt]EE0QEEHEEt;M5EPE Yt fMfME#M@E Et EPYAE t!E@EPt Y%YE@EPtYY3E@t|s؃ڀMEu}} Ee ueEEEM t;ERPWVEU=uċ؃0uWV5=9~]ԋEM뵍E+EEEEtM90uu M@M0E}]@t&tE-tE+ t E Eu+u+u uEPuVj EPEuuP2tuEPuVj0}tA}~;E]xfCPEPC;YY~2MQuPEPOuEPuuuEtEPuVj q} Gۉ} E_^[a@7@R@@@@@@UM IxE QuYYEu]]VW|$O~!t$Vt$t$ >tO_^S\$ KVW~&|$t$WFt$Pu ?tK_^[ËD$@ËD$AQËD$f@jt$t$t$;á0Att$ЅYtjX3Vt$j&\1Af8MZuH uIdhPS1A8ddtj,PyY;Yt0@8t9;uA8uj SP; tttEP}Y[3j9D$hP<1AAt6Au h$Y u^ u5A@1A3jXh@j5AD1AAuËL$%A%AjA AAXáA A ;sT$+P r3UMSVu AW+y iDMIM11UVUU] u~J?vj?ZK;KuL sL!\D u(M!!JL! uM!YM] MS[MZU MZRSJ?vj?Z]]+u]j?u K^;vMщMJ;v;tcM q;qu@ s!tDLu&M!1K!LuM!qM qINM qINu ]}u;M\ щ^NqNqN;Nu`L MLs%}uM DD )}uJM YJꍄ ED0EA A581AH h@SQ֋ AA PA A@A@HCAHyCu `AxuiSjp ֡Apj5AH1AAAȡA+ȍLQHQP9:E A;AvmAAE=AA_^[UAASVWu;AuM; Au%AMB_^[áA AVW3;u0DPP5AW5AX1A;taAAA AhAj5A4D1A;ljFt*jh hW41A;ljF uvW5AH1A3N>~AF_^UQMSVWqA3ۅ|Cj?iZ0DE@@Jujy hhW41Aup;wtƍ4;sCu0jX^;uCF;sN;Euq )u 9U }ƍ4;urq;s~;Esvu@j^X;u%C@;]s +q aq16;s)E 9U r4맍;]s +‰A aAFk+3_^[UQUS] V W}e+G ;M|vE+ȈG`seE4;rU;s 8u@;uBE;w+;v';s338u@<tC cC+MEE_^[Ujh2AhL@dPd%SVWe8A3;u>EPj^Vh2AV 1AtEPVh2AVS1AjX8Au$E;u\Auuu uP1A9]ulAESSuu E @Pu01AE;tc]<ǃ$euWSV- jXËe33M;t)uVuu ju01A;tuPVu 1A3e̋Md _^[U}u3]5Auu uuj5DA-u]Ã]̋L$tAt@u~Ѓ3ƒtAt2t$tt͍AL$+ÍAL$+ÍAL$+ÍAL$+QSUV5AW3;tN1AWWWWjPWjӋ;t>U;YD$t/WWUPj6WjӅtWt$%3FY;Yu3_^][YÃUeSVu 3W]] }}3ۃ=nA~jPYY lAA;t6MWEWP% YYP FFP5 tFFP5Y>%eeeeee3e]]]E]^F=nA~jP~YY lAÊAtEEDCЉEeN>t^*t2FtTIt Lu7EE~6u,~4Fu#EЃee'E"htlt wtEEEMM}O}u uEEE@EԀe}uM}u>%uME xnuDV0uMuMWSYYMWP}MWSs}uE̅u 8EuE_^[Ã=nAV~t$jV#YYt$lApu߃^ËT$Jx A RYÃ|$tt$t$+YYVt$Wt$Wt+YYu_^jt$ t$ , UWVu M};v;xur)$h@Ǻr $@$x@$@@@@#ъFGFGr$h@I#ъFGr$h@#ъFGr$h@I_@L@D@<@4@,@$@@DDDDDDDDDDDDDD$h@x@@@@E^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $@$@IǺr +$@$@@8@`@F#шGNOr$@IF#шGFGr$@F#шGFGFGZ$@I@@@@@@@@DDDDDDDDD D DDDD$@@@(@<@E^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_̋D$L$ ȋL$ u D$S؋D$d$؋D$[USu5Y Xu `jX  "u F < vF> wt< v^S39AVWu"5 A3:t<=tGVYtPVY;5Auj Y= A8t9UWYE?=t"U!;Yuj YW6'YY8u]5 ARY A_^A[UQQS39AVWu "@AhVS1AA5 A8tEPEPSSWMEMP聾;uj$YEPEPEPVWEH5A_^A[UMESV!uW} Et7} 8"uDP@"t)t%AAt tF@tՊFt&F8"uF@CtF@AAt tF@ t t ūuHtfe8 t u@8t7} UE3ۀ8\u@C8"u,u%39}t x"Pu}} 39U‰UKtCt\FKutJ}u t? t:}t.tAAtF@FAAt@@Xt&Ft'E_^[]QQDASU-0AVW333;u3Ջ;t DA(0A;DA;u Ջ;f9t@@f9u@@f9u+Ƌ=1ASS@SSPVSSD$4׋;t2U;YD$t#SSUPt$$VSSׅut$*Y\$\$V0ASuL;u 0A;t<8t @8u@8u+@U臻Y;u3 UWV W1A3_^][YYÃDSUVWhLYujY5AA ;sfF AD$P`1Af|$BD$D0h;.|95A}RAh輺Yt8A ;s`@ 95A|5A3~Ft6Mt.u P0AtNjAȋ MHGE;|3ۡA<4uMFujX HP0AtW0At %>uN@u NNC|5A0A_^][DUSVWUjjhl@u2]_^[]ËL$AtD$T$SVWD$Pjht@d5d%D$ Xp t.;t$$t(4v L$H |uhD@Td _^[3d yt@uQ R 9QuSQA SQAMKCk Y[VC20XC00USVWU] E@EEEECs {ta v|tEVUkT]^] t3x<{SkVS vjDaC T{ v4롸UkjS]]_^[]UL$)APAPy](At u*=nAu!hHAYthYUU3ɸЏA;t A=`A|V;ЏA(Au =nA\hPj1Au\h5APYY\WP\v@Ymu35PWY&UUL0D0t ? u $E ME;ME<< t GEI9MsE@8 uE^ GEsEjPEEjP40T0Au h0AuG}tAD0HtE< t GD1);} u } u jjuL } t GM9MGt0@u +} }E%ؕAԕA _^[LAhhYL$At I AI AAAAaUM S3VWE ]t ]E eEu@u9AtMj^#+t-Ht!HtԕAؕA%EE@EEt& t0t @uuE E]#ʿ;5t.;t*;tt<nE7E.u)tt ;t>EEE t ܕA#Muj^@t Mt t t؃;u%ؕAԕA>jVuEPuuup0A;tV0AuV0Ah0AP YuM@ uMVSYEY E V.|0Y<\uj\V\Y;Yt }w u,9Ev'EԕA"tMMȉMtEEtE؉EE E t83_^[UWVSM&ً}3ˋu F3:GwtIIы[^_UWVu M};v;xur)$ AǺr $A$ A$L AA A0 A#ъFGFGr$ AI#ъFGr$ A#ъFGr$ AI A A A A A| At Al ADDDDDDDDDDDDDD$ A A A A AE^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $P A$ AIǺr +$X A$P Ah A A AF#шGNOr$P AIF#шGFGr$P AF#шGFGFGZ$P AI A A A A$ A, A4 AG ADDDDDDDDD D DDDD$P A` Ah Ax A AE^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_̋T$ L$tG3D$Wr-كt+шGIuʃttGJuD$_ËD$Ujh5AhL@dPd%0SVWe39tAj_u@W2APWPSS0At=tA#W2APWPSS0AtAu;~VuYYu9]~uuYYEtAuuuVuu u0A;9] ulAE ;t 9];uujXx9}~l;AEPu 0AQ;~,}r"E8]tP:tM :r:v@@8uj9]~1}rE8]tP:tM :r:x@@8uzSSVuj u 01AE;]$eĉE܃MjXËe3ۉ]܃Muj_9]uuVuWu 501AօtySSuuj u ֋u;ta}6$蠠e}؃MjXËe33Mu;t-VWuuju 01AtVWuuu u0A3eMd _^[USVWuY;5Auj3;V3ҸhA90tr0B=XA|EPV0A$j@3Y@A}5A󫪉DA}MA;AA@j@3Y@A4R]xA;t,Qt%;wU`AAA@;vAA9uE}rE,APAlA AYDAUAAyHjXAA@=rVYDA,A,A3 A 9xAt3_^[ËD$%xAuxA%0AuxA%0AulAxAËD$-t"t t Ht3øøøøWj@Y3@A3 AA,ADA_UEVP5A0A3@;rEƅ t7SWU ;w+ȍA ˃BBBu_[j5DA5APVPjj5AVPVPV5DA j5AVPVPh5DA \3ftAA@AtAA 〠@A@AA;rI3ArZwAAȀ @AarzwAA Ȁ @A@;r^Ã=Auj,YAUQQSVW39}tUj=u Y;Yut@9ut;A38^;Au PYA;uT9} t9=At&t>_^[; j%;YAt߉89=Auj ;YAtĉ8+u=A}VuYY|C?t>t24<,Y?t GFPu芠YYt<5E2uz}ލPWbYY@M dA} tFu@@PVYYt.uV Y+EYE @#SV0AV耝Y3V5AWt-|$WPt$$ u 8<=ttFu׋+A_^Ë+AW|$3Ʌu3_Ã?Gt AuSUVP萚Yuj 3Y߅tP Y&^][_USVu 3;t9]t:uE;tf3^[]9\AuM;tffjX lADAtMnA~*9E|/39]QuPVj 5lA01AnAu9Er8^uԕA*39]PujVj 5lA01Ayʃ=nA~jt$0YYËD$ lAÀ@s sË333S\$VtAt$F ut2u.~uVY;Fu ~u@F @t8t@^[F F$ F %UQSVuuu V =ԕAAj\V+YY/j/VYY8t ~:h5A螙YEhaYWMt<;t;s CAM#C{<\uj\VY;Yju S9SFP0ANuԕA h0AؕAjuS _ ԕA ^[j YU39,Auu u藑YY]ËUSVAAtZBt 9M uB 9M uBu^[]UM9;uAMVtMu t8;t3"t FAMt-At"t FAMt9tAuȀ9;u Au &+^#]U=,Auu uYY]ËMfft:AAtQAt 9E t9U t A3]ÍA]ЋE +#]UQQS] VWj\Sj/SuEuKj:S[YYu;S8PđYYt}h$6AWSWw t;vMj.V8YYt-jW[YYuuWuEWPJYY]uqWSW lA3Vjuu `A}uuuu%Eu:] Y;tW,YE_^[Uu EPEPuuu ]Vuuu uuuڒ^]UQ=\ASuEaz ]}(=nA~ jSސYY lAXuklADJte E] j e ]jXMjjjQPEPh5\A" tuE EM [Ujh(6AhL@dPd%SVWe39=AuFWWj[Sh2AVW0AtA"WWSh2AVW0A"A9}~uuYYEAuuuuuu u0A9} ulAE WWuuE$@Pu 01A؉];}$`eĉE܃MjXËe3}܃M]9}tfSuuuju 01AtMWWSuu u0Au;t2E t@9};uuuSuu u0A3eȋMd _^[E6$謍e܉]MjXËe33ۃMu;tVSuuu u0At9}WWuWWuuVSh u 1A;qlT$D$VJt 8t@Iu8^u+D$ËVt$tV贼@PBYYt VPYY^3^UQQS]VWj\Sj/SuEuKj:S{YYu;SXPYYtwh$6AWSWw t;vMj.VXYYt'jW{YYuu W EWPpYY]unWS4W辻 |A3Vjuu pA}uu u% Euc]Y;tWUYE_^[UuE PEPuu u ]Vu uu5Auu ^]ËD$V;AsZȃ ATLt>%9t$ u |$ @uɀ f%^ԕA ԕA ^t$0Auh0APYètD$tԕA ؕA3U`EeSVW3;lj}tt~0~ u&EEEt+@8uxHt ԕA=ؕAjDE^VWPu5A ;t!Fȋ A|uNH;uDjfEP|EY0EY3;HT0~7ËA+P APVn+ } tPVP蜶 t߅tE;0u&F&5 Aj% AY3_^[]%0AUWVSu }TAxu; t.F'G8t,A<ɀ A,A<ɀ A8t43ۋ t'FG8tPS؃8t[^_t$t$j US]tRSYuؕAԕA 3[ÍEe PPE@hP]E :E .0APh0At@=wM u!;EEP谅Yȅu ԕA ;E~ԕA"sPQWYYaUEt$e @EEPE :E \0At tjX]3]UWVSM u} TAxuCAZ I& t! tFG8r8w8r8w8u Iu38tKrD@33ۋ t# tFGQPS+؃!Y;u Iu3;t rً[^_UQ=\ASVWuEAZ ]j;^}%95nA~ VSYY lAX#ƅuelADJte jE] X e ]VjMjQPEPW5\A9 t;uE EM _^[======$9:9F9V9h9~9999999::2:>:J:X:f:n:~::::::::; ;9L;^;r;;;A@@@@@@@@t@h@V@F@:@,@@ @$A?????r?`?N?988886;88?(?? ?>b>n>z>>>>>>>=;;;<h=T=@=.==<<<<<<<n<X<B<(<<<;;;&><>>@@EEE50P (8PX700WP `h````ppxxxx(null)(null)__GLOBAL_HEAP_SELECTED__MSVCRT_HEAP_SELECT@@runtime error TLOSS error SING error DOMAIN error R6028 - unable to initialize heap R6027 - not enough space for lowio initialization R6026 - not enough space for stdio initialization R6025 - pure virtual function call R6024 - not enough space for _onexit/atexit table R6019 - unable to open console device R6018 - unexpected heap error R6017 - unexpected multithread lock error R6016 - not enough space for thread data abnormal program termination R6009 - not enough space for environment R6008 - not enough space for arguments R6002 - floating point not loaded Microsoft Visual C++ Runtime Library Runtime Error! Program: ...PATH A A.A2AGetLastActivePopupGetActiveWindowMessageBoxAuser32.dll.com.exe.bat.cmd.\n Ar A"!A&!A6;0,8v=t16=0$8>l18V>1======$9:9F9V9h9~9999999::2:>:J:X:f:n:~::::::::; ;9L;^;r;;;A@@@@@@@@t@h@V@F@:@,@@ @$A?????r?`?N?988886;88?(?? ?>b>n>z>>>>>>>=;;;<h=T=@=.==<<<<<<<n<X<B<(<<<;;;&><>>LoadResourceFindResourceAGetCurrentThreadId!GetLongPathNameA$GetModuleFileNameAGetCommandLineACloseHandle GetFileAttributesAFindCloseFindNextFileAFindFirstFileAWaitForSingleObjectDCreateProcessA>GetProcAddressLoadLibraryAUpdateResourceAdEndUpdateResourceA BeginUpdateResourceAuGetVersionExAASetConsoleCtrlHandler\GetSystemPowerStatusReadFileWriteFileFreeLibrarytGetVersionSleepGetLastErrorFormatMessageA4CreateFileAFlushFileBuffersWaitNamedPipeA^DisconnectNamedPipeJCreateThread#ConnectNamedPipeACreateNamedPipeAOpenProcessGetCurrentProcessId GetExitCodeProcessTerminateThread GetExitCodeThreadFreeResourceMulDivLockResourceKERNEL32.dllLoadIconAqSystemParametersInfoADefWindowProcARSetTimerYCreateWindowExADestroyWindowMessageBoxAwsprintfADialogBoxIndirectParamAAdjustWindowRectExGetDialogBaseUnits7SetMenuDefaultItemuInsertMenuItemAXCreatePopupMenuDestroyMenu|TrackPopupMenu0SetForegroundWindowGetCursorPosPostMessageAGetDoubleClickTimeRegisterWindowMessageARegisterClassADispatchMessageATranslateMessage*GetMessageAUSER32.dll[RegCloseKey{RegQueryValueExAqRegOpenKeyARegSetValueExAdRegDeleteValueArRegOpenKeyExAADVAPI32.dllyShell_NotifyIconASHELL32.dll VerQueryValueAGetFileVersionInfoAGetFileVersionInfoSizeAVERSION.dllHeapAllocHeapFree}ExitProcessTerminateProcessGetCurrentProcessHeapReAlloc&GetModuleHandleAPGetStartupInfoA GetEnvironmentVariableAHeapDestroyHeapCreateVirtualFreeVirtualAllocMultiByteToWideCharSGetStringTypeAVGetStringTypeWWideCharToMultiByteUnhandledExceptionFilterFreeEnvironmentStringsAFreeEnvironmentStringsWGetEnvironmentStringsGetEnvironmentStringsWmSetHandleCountRGetStdHandleGetFileType/RtlUnwind|SetStdHandlejSetFilePointerGetCPInfo!CompareStringA"CompareStringWGetACP1GetOEMCPbSetEnvironmentVariableAaSetEndOfFileLCMapStringALCMapStringWGetCurrentDirectoryAGetFullPathNameAGetDriveTypeA@IA@Path JREPathJREPath BrowserPathBrowserDisplay BoxInstallDisplay_BoxInstallURL InstallJREURL_InstallJREResource DirectoryResourceDirectoryClass DirectoryClassDirectoryRun TypeRunTypeRun As ServiceRunAsServicePersonal OptionsPersonalOptionsMain ClassMainClassMain ArgsMainArgsPersonal ClasspathPersonalClasspathJRE versionJREversionBINr%s\resource21-Djava.library.path=%s%s%s;%s%s%s;%s%s%s%s %s; ;%s%s%s%s%s%s;%s%s%s;%s%s%s"javawjava-classpath%s\%s-deleteCPL-installCPL-stopService-startService-deleteService-installService%USERNAMEUSERDOMAIN_console.http://\=\:\\\.zip.jar..%s\*.*%s\%s\%s.properties8SAAAControlPanelManagementSOFTWARE\Microsoft\Windows\CurrentVersion\Control Panel\Extended Properties\{305CA226-D286-468e-B848-2B2E8E697B74} 2%dService Pack %dSOFTWARE\Microsoft\Windows\CurrentVersion\Control Panel\Cpls%s\%s.cplcplGetInfo()[Ljava/lang/String;cplOpen()VcplIsDeletecplIsCreate()ZTAAASystemEventManagementnotifyEvent(IIILjava/lang/String;[I[B)IJavaExe WinEventAAisOneInstance([Ljava/lang/String;)Z\\.\pipe\JavaExe_OneInstance%s_%sbin\javaw.exebin\java.exe%d.%d\StringFileInfo\000004b0\Full VersionJavaHomeCurrentVersionSOFTWARE\JavaSoft\%s%s\jreJava Development KitJava Runtime Environmentjre\%sbin\hotspot\jvm.dllbin\classic\jvm.dllbin\client\jvm.dlliexplorehttp://java.sun.com/j2se/downloads.htmliexplore.exeSOFTWARE\Microsoft\IE Setup\SetupPath0closejava.util.jar.JarEntrygetNamejava.lang.StringnextElementjava.lang.ObjecthasMoreElements%s.classentriesjava.util.Enumerationjava.util.jar.JarFileLjava/lang/String;getValueMain-ClassgetMainAttributesjava.util.jar.AttributesgetManifestjava.util.jar.Manifest%s.zip%s.jar%s\%s.%szipjarJavaExereadObjectjava.io.ObjectInputStreamLjava/io/InputStream;java.io.ByteArrayInputStream[BtoByteArraywriteObjectLjava/lang/Object;java.io.ObjectOutputStreamLjava/io/OutputStream;java.io.ByteArrayOutputStream(%s)L%s;(%s)V(%s)Z(%s)I(%s)%smain([Ljava/lang/String;)V-Xrs-Dapplication.home=%s-Djava.class.path=%sexitJNI_GetCreatedJavaVMsJNI_CreateJavaVMJNI_GetDefaultJavaVMInitArgsjava.lang.SystemIisAliveenumerate[Ljava/lang/Thread;java.lang.ThreadAWT-ShutdownAWT-EventQueue-0Thread-shell32.dllDllGetVersionSoftware\Microsoft\Windows\CurrentVersion\RunServicesUnlockServiceDatabaseStartServiceCtrlDispatcherAStartServiceASetServiceStatusRegisterServiceCtrlHandlerAOpenServiceAOpenSCManagerALockServiceDatabaseDeleteServiceCreateServiceAControlServiceCloseServiceHandleadvapi32.dllChangeServiceConfig2ADgA gAfAfAfAfAfAhfALfAfAeAeAdeA$eAdAdAdAdA`dAdAcAcAcAtcATcA0cAbApbA8bA(bAbAaAaAaAaAaA`aA,aA`A`A`A@`A,`A`A_A_A_At_AP_A _A_A^A^A4^A^A]A]A]A]A]A]A]A]A]A]A]A]A]A]AA]A]A]A]A]AXA]A]A]A]AXA]A]A]A]A]A]A]A]A]A]A]A]A]A]A]AA]A]A]A]A]AXA]A]A]A]AXAWindows ServiceCan't continueUpdateRsrcJavaExe.PROPERTIES.BMPControl PanelService WindowsJVM.EXE.ICOJava Runtime Environment (JRE)Impossible de continuerYou must rename JavaExe with the same name of your main .CLASS or .JAR Please consult the documentation at http://devwizard.free.fr/JavaExe.htmlThis file is already open : %sSource files not specifiedTarget files not specifiedThis image has the format : %dx%d (%d bits)This executable file is not JavaExeThis file contains the properties : %sIntegration of image %s to %s as startup screen"%s" isn't a BMP fileThe icon file %s was not foundThis file contains %d icon(s) : %s%dx%d (%d colors)The ControlPanel has already installed. Do you want to delete it ?Do you want to install this program as ControlPanel ?You don't have privileges to install a serviceThe service has already installed. Do you want to delete it ?The service has created, do you want to start it ?Do you want to install this program as Windows service ?Can't find main methodCan't find class "%s"Can't find main class "%s"Can't run the JVM"%s" isn't an icon file.EXE file not foundIcon not foundJava %s isn't installed ! Do you want to install it ?This executable file is not completVous devez renommer JavaExe selon le nom de votre .CLASS ou .JAR principal. Veuillez consulter la documentation http://devwizard.free.fr/JavaExe.htmlCe fichier est dj ouvert : %sFichiers sources non spcifisFichiers destinations non spcifisCette image a le format : %dx%d (%d bits)Ce fichier excutable n'est pas JavaExe.Ce fichier contient les properties : %sIntgration de l'image %s vers %s en tant qu'cran de dmarrage"%s" n'est pas un fichier BMPLe fichier d'icone %s est introuvableCe fichier contient %d icone(s) : %s%dx%d (%d couleurs)Le ControlPanel est dj install. Voulez-vous le supprimer ?Voulez-vous installer l'application en tant que ControlPanel ?Vous n'avez pas les droits pour installer un serviceLe service est dj install. Voulez-vous le supprimer ?Le service est cr, voulez-vous le lancer ?Voulez-vous installer l'application en tant que service Windows ?Mthode "main" introuvableClasse "%s" introuvableClasse principale "%s" introuvableImpossible de lancer la JVM"%s" n'est pas une iconeFichier .EXE introuvableIcone introuvableJava %s n'est pas install ! Voulez-vous l'installer ?Ce fichier excutable est incomplet.Systemiphlpapi.dllGetAdaptersInfo%d.%d.%d.%d%s%s(%s$%s)READY33Control Panel\InternationaliCountry gAAAServiceManagementserviceGetInfoserviceFinishserviceInitserviceControl_ShutdownserviceControl_StopserviceControl_ContinueserviceControl_PauseserviceIsDeleteserviceIsLaunchserviceIsCreate %s %s%s%s %strue"%s\%s.exe" __RunService__"%s" __RunService__ __RunServiceUI__ %dWinSta0\Default__RunServiceUI____RunService__gAAApiAAATaskbarManagementtaskDataFromServicetaskDataForServicetaskIsDataForServiceserviceDataFromUI(Ljava/io/Serializable;)VserviceDataForUI()Ljava/io/Serializable;serviceIsDataForUI\\.\pipe\JavaExe_ServiceUI2\\.\pipe\JavaExe_ServiceUI1LsaFreeReturnBufferLsaEnumerateLogonSessionsSecur32.dllLsaGetLogonSessionDataWTSUnRegisterSessionNotificationWtsApi32.dllWTSRegisterSessionNotification%ls\%lspAlAisCloseSplash piA@AAtaskGetBalloonInfotaskIsBalloonShowtaskSetBalloonSupported(Z)VtaskInittaskIsShowtaskDisplayMenu(ZLjava/awt/Component;II)ZtaskDoAction(ZI)VtaskGetDefaultMenuID(Z)ItaskGetInfotaskGetMenu(ZI)[[Ljava/lang/String;toFrontshowsetBoundsIIIIsetUndecoratedZjavax.swing.JDialogJavaExe MsgTaskJavaExe WinTasklAlA ((((( H . @h2AX2AnAnAoAoAnA - ]]  5A4A 4A 4Ap4A@4A4A3A3A3AX3A 3A2Ax2Ay2Az2A2A2A        ! 5A CPR S WY l m pr   )    `A`AAAAAAA`y!@~ڣ @ڣ AϢ[@~QQ^ _j21~6A6A 6A6A6A6A 6A6A@@X (@Xp 0H`p 0:Ph(ph (' 3h@:D:6877~BIN(0`EUUUUUNUUUTDDUUUU^^NEUUTUDDUN^DDN^UDDUUUQQE^DUQTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU_( @EUUUTUTETUU_A^UUUQQUTDUUQUUUUUUUUUUPUUUUUUUUU^UUUUUUUUU^UUUUUUUUUUUUUU( U^^TDEUU^UUUUUUUUU(0`  >1/?32M2K3G4H5H6J7K9Z9L:M:M;[;N<O=R@i@SB^BnBUCVE[EWFhFXGZHZIaImI[J]L`LsL]M^MbPePaQbRkRqReUwUfVfViVdXhYq^Zh]u^|^t`lbqbrb{bteofxffpgvhxjyktlzl|nćn}p~qqrstvǍvxyz{|}ǐ}ʒ}ʓ~‹ÌÍÎĎÏĐőΙƓǔǕǖȗҟɞ˛˜˝͠զĢ΢ΣϣϥЦѨ٭ҩҪԮհְԲܵصصٶٸڸ༱B?ܼܽܽݾ»ýſƿ1.ͺ$!%"(%" -+1-31526397=:A?QMNLRORPWTXU\Z_]kivt|{{qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxX>((D_qqq>!>XpxkX6!6qqqXqqqkpedzqqq>dqqqNxqqqt6qqqp6(!!!((6>_qqq]Xk_qqqSqqqd6e]_X]hnipx!_qqqNXʩΘ(qqqptqqq߯qqqqqq̯qqqׯqqqѯqqqݲqqqү׹qqq׵qqq缻qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq( @Z/U0Z?4G4H6J7L:V:aAyTEXGpGZI\K]LaQbQqQbRfRcSwTfVdXrYj[l]n_o`~`rcse~fgwiÅkzlzm{mpqrrsǍvw}‹̕ÎĎőƓǔǖў˝̞֧͠ΣϣЦѨӬڱֲ׳״صٶ໰ڸڹںݿ¼ý$!2/4274B?EBNLSPRPVShfqnusVWjm33333333333333333333333333333333WWWWWWWWWWWWWWWWWWWWWWWWWWWWW33W3||||||||||||||||||||||||||W33W3||||||<$ )=]|||||||W33W3||||0 4FO\ifaWND2)@||||||W33W3||||TF|||||||||||O||||||W33W3||||||<   &|||||||||||W33W3||||||||HUffi^\||9J|||||||W33W3||||||||I2)9N^||0$||||||W33W3|||||||YNWiWN,F|||)|||||W33W3|||||||\BBBBB@Wi|||O |||||W33W3||||||$$$00B@0 ||2 |||||W33W3|||||||TT||||o|||T@)||||||W33W3|||||||||||t|po|||||||||||W33W3||||||||||r|o`o|||||||||||W33W3|||||||||on|jc||||||||||||W33W3|||||||||qh|go||||||||||||W33W3|||||||||{`x|co|||||||||||W33W3||||||||||o`v|nz||||||||||W33W3|||||||||||obx|vy|||||||||W33W3||||||||||||ogx|||||||||||W33W3|||||||||||||on|||||||||||W33W3||||||||||||||o|||||||||||W33W333333333333333333333333333W33WWWWWWWWWWWWWWWWWWWWWWWWWWWWW33W33WWWWWWW33WWWWWWW33W33WWWWWWWWWWWWWWWWWWWWWWWWWWWWW33333333333333333333333333333333( @pn~װge8Ά<                        (0`tfeUWFP>G4G4G4G4G4G4G4H5M;VEbQ{mþȯUCK8G4G4XFk\xjy¡ykoabRQ?H6O=n`H6H6yWFäiZpa¡̻{myl{¡þɳŦ[JG4G4G4G4G4G4G4n`ʩdTũͽpal]̺Ŀ˸ũʶ̺iYO=ykseTBP>L:K8O=O=O=SBXGr|oG4eUgWiY¼n`gXG4Ũ|ƪĦĦǮͻϾäJ7^M˸_OP>l]uk\n_gWk\ydnmy`reqcJ7cSxjYHaQyyլҼſO=H6ãȰǮ͵>׳bg$!Ѯ.,,*ӓX\$!ї7777$!CD&$t{`e%"GIx,+jqjq)&<=׻@@MP~0//.ԺpxSW܊::99*(glVZ<=t|>>ץ( @ k\ZIRAH6J7G4G4I6I6P>ZIgWG4VEiY|̹οäyl`PUDaQ~qR@r̻ǭͽxjϲylG4I6H5I6G4_Oƫɳ¼gX}pֺoaZISBgWvhʴڧ^MWFο¡Q?ȯħcSrQ?XG~qǫɯ½|G4ʶRAP>wƢśtrp]bQK9Ƿy\e誧᷅xgXFOPR+0Ŀ<@߮$!IK]d=<<<.,HJ5454TXy$!р瞫,+ӥfl$!x唠;;lr)'`e_dZ^/-kr31;;֌( @ǮG4G4ĥG4װ~qG4G4G4װؑ;ؑ;ؑ;G4ڞG4e8G4Ά<Ά JavaExe D SystemPv JavaExe.exeportmidi/pm_java/pmjni/0000755000000000000000000000000011453601074014136 5ustar rootrootportmidi/pm_java/pmjni/pmjni.c0000644000000000000000000002112011450076424015415 0ustar rootroot#include "portmidi.h" #include "porttime.h" #include "jportmidi_JportMidiApi.h" #include // these macros assume JNIEnv *env is declared and valid: // #define CLASS(c, obj) jclass c = (*env)->GetObjectClass(env, obj) #define ADDRESS_FID(fid, c) \ jfieldID fid = (*env)->GetFieldID(env, c, "address", "J") // Uses Java Long (64-bit) to make sure there is room to store a // pointer. Cast this to a C long (either 32 or 64 bit) to match // the size of a pointer. Finally cast int to pointer. All this // is supposed to avoid C compiler warnings and (worse) losing // address bits. #define PMSTREAM(obj, fid) ((PmStream *) (long) (*env)->GetLongField(env, obj, fid)) // Cast stream to long to convert integer to pointer, then expand // integer to 64-bit jlong. This avoids compiler warnings. #define SET_PMSTREAM(obj, fid, stream) \ (*env)->SetLongField(env, obj, fid, (jlong) (long) stream) /* * Method: Pm_Initialize */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize (JNIEnv *env, jclass cl) { return Pm_Initialize(); } /* * Method: Pm_Terminate */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate (JNIEnv *env, jclass cl) { return Pm_Terminate(); } /* * Method: Pm_HasHostError */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError (JNIEnv *env, jclass cl, jobject jstream) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_HasHostError(PMSTREAM(jstream, fid)); } /* * Method: Pm_GetErrorText */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText (JNIEnv *env, jclass cl, jint i) { return (*env)->NewStringUTF(env, Pm_GetErrorText(i)); } /* * Method: Pm_GetHostErrorText */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText (JNIEnv *env, jclass cl) { char msg[PM_HOST_ERROR_MSG_LEN]; Pm_GetHostErrorText(msg, PM_HOST_ERROR_MSG_LEN); return (*env)->NewStringUTF(env, msg); } /* * Method: Pm_CountDevices */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices (JNIEnv *env, jclass cl) { return Pm_CountDevices(); } /* * Method: Pm_GetDefaultInputDeviceID */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID (JNIEnv *env, jclass cl) { return Pm_GetDefaultInputDeviceID(); } /* * Method: Pm_GetDefaultOutputDeviceID */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID (JNIEnv *env, jclass cl) { return Pm_GetDefaultOutputDeviceID(); } /* * Method: Pm_GetDeviceInterf */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf (JNIEnv *env, jclass cl, jint i) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (!info) return NULL; return (*env)->NewStringUTF(env, info->interf); } /* * Method: Pm_GetDeviceName */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName (JNIEnv *env, jclass cl, jint i) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (!info) return NULL; return (*env)->NewStringUTF(env, info->name); } /* * Method: Pm_GetDeviceInput */ JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput (JNIEnv *env, jclass cl, jint i) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (!info) return (jboolean) 0; return (jboolean) info->input; } /* * Method: Pm_GetDeviceOutput */ JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput (JNIEnv *env, jclass cl, jint i) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (!info) return (jboolean) 0; return (jboolean) info->output; } /* * Method: Pm_OpenInput */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput (JNIEnv *env, jclass cl, jobject jstream, jint index, jstring extras, jint bufsiz) { PmError rslt; PortMidiStream *stream; CLASS(c, jstream); ADDRESS_FID(fid, c); rslt = Pm_OpenInput(&stream, index, NULL, bufsiz, NULL, NULL); SET_PMSTREAM(jstream, fid, stream); return rslt; } /* * Method: Pm_OpenOutput */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput (JNIEnv *env, jclass cl, jobject jstream, jint index, jstring extras, jint bufsiz, jint latency) { PmError rslt; PortMidiStream *stream; CLASS(c, jstream); ADDRESS_FID(fid, c); rslt = Pm_OpenOutput(&stream, index, NULL, bufsiz, NULL, NULL, latency); SET_PMSTREAM(jstream, fid, stream); return rslt; } /* * Method: Pm_SetFilter */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter (JNIEnv *env, jclass cl, jobject jstream, jint filters) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_SetFilter(PMSTREAM(jstream, fid), filters); } /* * Method: Pm_SetChannelMask */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask (JNIEnv *env, jclass cl, jobject jstream, jint mask) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_SetChannelMask(PMSTREAM(jstream, fid), mask); } /* * Method: Pm_Abort */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort (JNIEnv *env, jclass cl, jobject jstream) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_Abort(PMSTREAM(jstream, fid)); } /* * Method: Pm_Close */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close (JNIEnv *env, jclass cl, jobject jstream) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_Close(PMSTREAM(jstream, fid)); } /* * Method: Pm_Read */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent) { CLASS(jstream_class, jstream); ADDRESS_FID(address_fid, jstream_class); jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent); jfieldID message_fid = (*env)->GetFieldID(env, jpmevent_class, "message", "I"); jfieldID timestamp_fid = (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I"); PmEvent buffer; PmError rslt = Pm_Read(PMSTREAM(jstream, address_fid), &buffer, 1); (*env)->SetIntField(env, jpmevent, message_fid, buffer.message); (*env)->SetIntField(env, jpmevent, timestamp_fid, buffer.timestamp); return rslt; } /* * Method: Pm_Poll */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll (JNIEnv *env, jclass cl, jobject jstream) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_Poll(PMSTREAM(jstream, fid)); } /* * Method: Pm_Write */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent) { CLASS(jstream_class, jstream); ADDRESS_FID(address_fid, jstream_class); jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent); jfieldID message_fid = (*env)->GetFieldID(env, jpmevent_class, "message", "I"); jfieldID timestamp_fid = (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I"); // note that we call WriteShort because it's simpler than constructing // a buffer and passing it to Pm_Write return Pm_WriteShort(PMSTREAM(jstream, address_fid), (*env)->GetIntField(env, jpmevent, timestamp_fid), (*env)->GetIntField(env, jpmevent, message_fid)); } /* * Method: Pm_WriteShort */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort (JNIEnv *env, jclass cl, jobject jstream, jint when, jint msg) { CLASS(c, jstream); ADDRESS_FID(fid, c); return Pm_WriteShort(PMSTREAM(jstream, fid), when, msg); } /* * Method: Pm_WriteSysEx */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx (JNIEnv *env, jclass cl, jobject jstream, jint when, jbyteArray jmsg) { CLASS(c, jstream); ADDRESS_FID(fid, c); jbyte *bytes = (*env)->GetByteArrayElements(env, jmsg, 0); PmError rslt = Pm_WriteSysEx(PMSTREAM(jstream, fid), when, (unsigned char *) bytes); (*env)->ReleaseByteArrayElements(env, jmsg, bytes, 0); return rslt; } /* * Method: Pt_TimeStart */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart (JNIEnv *env, jclass c, jint resolution) { return Pt_Start(resolution, NULL, NULL); } /* * Method: Pt_TimeStop */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop (JNIEnv *env, jclass c) { return Pt_Stop(); } /* * Method: Pt_Time */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time (JNIEnv *env, jclass c) { return Pt_Time(); } /* * Method: Pt_TimeStarted */ JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted (JNIEnv *env, jclass c) { return Pt_Started(); } portmidi/pm_java/pmjni/pmjni-VC8.vcproj0000644000000000000000000001133111215774554017107 0ustar rootroot portmidi/pm_java/pmjni/pmjni.rc0000644000000000000000000000247011127411440015576 0ustar rootroot// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h0000644000000000000000000002075211445664134020740 0ustar rootroot/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class jportmidi_JPortMidiApi */ #ifndef _Included_jportmidi_JPortMidiApi #define _Included_jportmidi_JPortMidiApi #ifdef __cplusplus extern "C" { #endif #undef jportmidi_JPortMidiApi_PM_FILT_ACTIVE #define jportmidi_JPortMidiApi_PM_FILT_ACTIVE 16384L #undef jportmidi_JPortMidiApi_PM_FILT_SYSEX #define jportmidi_JPortMidiApi_PM_FILT_SYSEX 1L #undef jportmidi_JPortMidiApi_PM_FILT_CLOCK #define jportmidi_JPortMidiApi_PM_FILT_CLOCK 256L #undef jportmidi_JPortMidiApi_PM_FILT_PLAY #define jportmidi_JPortMidiApi_PM_FILT_PLAY 7168L #undef jportmidi_JPortMidiApi_PM_FILT_TICK #define jportmidi_JPortMidiApi_PM_FILT_TICK 512L #undef jportmidi_JPortMidiApi_PM_FILT_FD #define jportmidi_JPortMidiApi_PM_FILT_FD 8192L #undef jportmidi_JPortMidiApi_PM_FILT_UNDEFINED #define jportmidi_JPortMidiApi_PM_FILT_UNDEFINED 8192L #undef jportmidi_JPortMidiApi_PM_FILT_RESET #define jportmidi_JPortMidiApi_PM_FILT_RESET 32768L #undef jportmidi_JPortMidiApi_PM_FILT_REALTIME #define jportmidi_JPortMidiApi_PM_FILT_REALTIME 16641L #undef jportmidi_JPortMidiApi_PM_FILT_NOTE #define jportmidi_JPortMidiApi_PM_FILT_NOTE 50331648L #undef jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH #define jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH 536870912L #undef jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH #define jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH 67108864L #undef jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH #define jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH 603979776L #undef jportmidi_JPortMidiApi_PM_FILT_PROGRAM #define jportmidi_JPortMidiApi_PM_FILT_PROGRAM 268435456L #undef jportmidi_JPortMidiApi_PM_FILT_CONTROL #define jportmidi_JPortMidiApi_PM_FILT_CONTROL 134217728L #undef jportmidi_JPortMidiApi_PM_FILT_PITCHBEND #define jportmidi_JPortMidiApi_PM_FILT_PITCHBEND 1073741824L #undef jportmidi_JPortMidiApi_PM_FILT_MTC #define jportmidi_JPortMidiApi_PM_FILT_MTC 2L #undef jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION #define jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION 4L #undef jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT #define jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT 8L #undef jportmidi_JPortMidiApi_PM_FILT_TUNE #define jportmidi_JPortMidiApi_PM_FILT_TUNE 64L #undef jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON #define jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON 78L /* * Class: jportmidi_JPortMidiApi * Method: Pm_Initialize * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pm_Terminate * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pm_HasHostError * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError (JNIEnv *, jclass, jobject); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetErrorText * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText (JNIEnv *, jclass, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetHostErrorText * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pm_CountDevices * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetDefaultInputDeviceID * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetDefaultOutputDeviceID * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetDeviceInterf * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf (JNIEnv *, jclass, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetDeviceName * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName (JNIEnv *, jclass, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetDeviceInput * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput (JNIEnv *, jclass, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_GetDeviceOutput * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput (JNIEnv *, jclass, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_OpenInput * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;I)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput (JNIEnv *, jclass, jobject, jint, jstring, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_OpenOutput * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;II)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput (JNIEnv *, jclass, jobject, jint, jstring, jint, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_SetFilter * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter (JNIEnv *, jclass, jobject, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_SetChannelMask * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask (JNIEnv *, jclass, jobject, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_Abort * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort (JNIEnv *, jclass, jobject); /* * Class: jportmidi_JPortMidiApi * Method: Pm_Close * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close (JNIEnv *, jclass, jobject); /* * Class: jportmidi_JPortMidiApi * Method: Pm_Read * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read (JNIEnv *, jclass, jobject, jobject); /* * Class: jportmidi_JPortMidiApi * Method: Pm_Poll * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll (JNIEnv *, jclass, jobject); /* * Class: jportmidi_JPortMidiApi * Method: Pm_Write * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write (JNIEnv *, jclass, jobject, jobject); /* * Class: jportmidi_JPortMidiApi * Method: Pm_WriteShort * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;II)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort (JNIEnv *, jclass, jobject, jint, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pm_WriteSysEx * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I[B)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx (JNIEnv *, jclass, jobject, jint, jbyteArray); /* * Class: jportmidi_JPortMidiApi * Method: Pt_TimeStart * Signature: (I)I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart (JNIEnv *, jclass, jint); /* * Class: jportmidi_JPortMidiApi * Method: Pt_TimeStop * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pt_Time * Signature: ()I */ JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time (JNIEnv *, jclass); /* * Class: jportmidi_JPortMidiApi * Method: Pt_TimeStarted * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif /* Header for class jportmidi_JPortMidiApi_PmEvent */ #ifndef _Included_jportmidi_JPortMidiApi_PmEvent #define _Included_jportmidi_JPortMidiApi_PmEvent #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif /* Header for class jportmidi_JPortMidiApi_PortMidiStream */ #ifndef _Included_jportmidi_JPortMidiApi_PortMidiStream #define _Included_jportmidi_JPortMidiApi_PortMidiStream #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif portmidi/pm_java/CMakeLists.txt0000644000000000000000000000403211274243554015566 0ustar rootroot# pm_java if(UNIX) if(APPLE) # java not dealt with in CMake -- see pm_mac/pm_mac.xcodeproj else(APPLE) # linux set(JPORTMIDICLASS JPortMidi.class JPortMidiException.class JPortMidiApi.class) set(PMDEFAULTSCLASS PmDefaultsFrame.class PmDefaults.class) prepend_path(JPORTMIDICLASS2 jportmidi/ ${JPORTMIDICLASS}) prepend_path(PMDEFAULTSCLASS2 pmdefaults/ ${PMDEFAULTSCLASS}) set(PMDEFAULTS_ALL_CLASSES ${JPORTMIDICLASS2} ${PMDEFAULTSCLASS2}) # message(STATUS "PMDEFAULTS_ALL_CLASSES is " ${PMDEFAULTS_ALL_CLASSES}) add_custom_command(OUTPUT pmdefaults/PmDefaultsFrame.class COMMAND javac -classpath . pmdefaults/PmDefaultsFrame.java MAIN_DEPENDENCY pmdefaults/PmDefaultsFrame.java DEPENDS pmdefaults/PmDefaults.java WORKING_DIRECTORY pm_java) add_custom_command(OUTPUT pmdefaults/PmDefaults.class COMMAND javac -classpath . pmdefaults/PmDefaults.java MAIN_DEPENDENCY pmdefaults/PmDefaults.java DEPENDS pmdefaults/PmDefaultsFrame.java WORKING_DIRECTORY pm_java) add_custom_command(OUTPUT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar COMMAND cp pmdefaults/portmusic_logo.png . COMMAND jar cmf pmdefaults/manifest.txt pmdefaults.jar pmdefaults/*.class portmusic_logo.png jportmidi/*.class COMMAND chmod +x pmdefaults/pmdefaults COMMAND cp pmdefaults/pmdefaults ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} COMMAND mv pmdefaults.jar ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} COMMAND rm portmusic_logo.png MAIN_DEPENDENCY pmdefaults/PmDefaults.class DEPENDS ${PMDEFAULTS_ALL_CLASSES} WORKING_DIRECTORY pm_java) add_custom_target(pmdefaults_target ALL DEPENDS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar) # message(STATUS "add_custom_target: pmdefaults.jar") # install the libraries (Linux only) INSTALL(FILES ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar DESTINATION /usr/share/java) INSTALL(PROGRAMS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults DESTINATION /usr/local/bin) endif(APPLE) endif(UNIX) # In windows, use pm_java/make.bat portmidi/pm_qt/0000755000000000000000000000000011453601074012524 5ustar rootrootportmidi/pm_qt/README_QT.txt0000644000000000000000000000104311445664134014633 0ustar rootrootREADME_QT.txt for PortMidi Richard Starfield 20 Sep 2010 This is a QtCreator build file for PortMidi. To build PortMidi on Windows with QtCreator: Move portmidi/pm_qt/portmidi.pro to portmidi/portmidi.pro Open portmidi.pro in QtCreator, change to the release build option and build all to compile the static library. This has been tested in Windows. The project file does include Linux build switches but they haven't been tested yet. To compile a DLL instead of a static library change line 11 from "CONFIG += staticlib" to "CONFIG += DLL" portmidi/pm_qt/portmidi.pro0000644000000000000000000000171311445664134015106 0ustar rootroot#------------------------------------------------- # # Project created by QtCreator 2010-09-02T12:50:47 # #------------------------------------------------- QT -= core gui TARGET = portmidi TEMPLATE = lib CONFIG += staticlib # replace this with DLL for dynamic link on Windows INCLUDEPATH = pm_common/ porttime/ win32 { INCLUDEPATH += pm_win/ LIBS += -lwinmm SOURCES += pm_win/pmwinmm.c \ pm_win/pmwin.c HEADERS += pm_win/pmwinmm.h } # this build hasn't been tested on Linux yet unix { DEFINES += PMALSA INCLUDEPATH += pm_linux/ LIBS += -lasound SOURCES += pm_linux/finddefault.c \ pm_linux/pmlinux.c \ pm_linux/pmlinuxalsa.c HEADERS += pm_linux/pmlinux.h pm_linux/pmlinuxalsa.h } DEFINES -= UNICODE SOURCES += \ pm_common/portmidi.c \ pm_common/pmutil.c \ porttime/porttime.c \ porttime/ptwinmm.c HEADERS += \ pm_common/pmutil.h \ pm_common/pminternal.h \ pm_common/portmidi.h \ porttime/porttime.h portmidi/pm_common/0000755000000000000000000000000011453601074013370 5ustar rootrootportmidi/pm_common/portmidi.h0000755000000000000000000006740511310172344015402 0ustar rootroot#ifndef PORT_MIDI_H #define PORT_MIDI_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * PortMidi Portable Real-Time MIDI Library * PortMidi API Header File * Latest version available at: http://sourceforge.net/projects/portmedia * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * Copyright (c) 2001-2006 Roger B. Dannenberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortMidi license; however, * the PortMusic community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /* CHANGELOG FOR PORTMIDI * (see ../CHANGELOG.txt) * * NOTES ON HOST ERROR REPORTING: * * PortMidi errors (of type PmError) are generic, system-independent errors. * When an error does not map to one of the more specific PmErrors, the * catch-all code pmHostError is returned. This means that PortMidi has * retained a more specific system-dependent error code. The caller can * get more information by calling Pm_HasHostError() to test if there is * a pending host error, and Pm_GetHostErrorText() to get a text string * describing the error. Host errors are reported on a per-device basis * because only after you open a device does PortMidi have a place to * record the host error code. I.e. only * those routines that receive a (PortMidiStream *) argument check and * report errors. One exception to this is that Pm_OpenInput() and * Pm_OpenOutput() can report errors even though when an error occurs, * there is no PortMidiStream* to hold the error. Fortunately, both * of these functions return any error immediately, so we do not really * need per-device error memory. Instead, any host error code is stored * in a global, pmHostError is returned, and the user can call * Pm_GetHostErrorText() to get the error message (and the invalid stream * parameter will be ignored.) The functions * pm_init and pm_term do not fail or raise * errors. The job of pm_init is to locate all available devices so that * the caller can get information via PmDeviceInfo(). If an error occurs, * the device is simply not listed as available. * * Host errors come in two flavors: * a) host error * b) host error during callback * These can occur w/midi input or output devices. (b) can only happen * asynchronously (during callback routines), whereas (a) only occurs while * synchronously running PortMidi and any resulting system dependent calls. * Both (a) and (b) are reported by the next read or write call. You can * also query for asynchronous errors (b) at any time by calling * Pm_HasHostError(). * * NOTES ON COMPILE-TIME SWITCHES * * DEBUG assumes stdio and a console. Use this if you want automatic, simple * error reporting, e.g. for prototyping. If you are using MFC or some * other graphical interface with no console, DEBUG probably should be * undefined. * PM_CHECK_ERRORS more-or-less takes over error checking for return values, * stopping your program and printing error messages when an error * occurs. This also uses stdio for console text I/O. */ #ifndef WIN32 // Linux and OS X have stdint.h #include #else #ifndef INT32_DEFINED // rather than having users install a special .h file for windows, // just put the required definitions inline here. porttime.h uses // these too, so the definitions are (unfortunately) duplicated there typedef int int32_t; typedef unsigned int uint32_t; #define INT32_DEFINED #endif #endif #ifdef _WINDLL #define PMEXPORT __declspec(dllexport) #else #define PMEXPORT #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /* default size of buffers for sysex transmission: */ #define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024 /** List of portmidi errors.*/ typedef enum { pmNoError = 0, pmNoData = 0, /**< A "no error" return that also indicates no data avail. */ pmGotData = 1, /**< A "no error" return that also indicates data available */ pmHostError = -10000, pmInvalidDeviceId, /** out of range or * output device when input is requested or * input device when output is requested or * device is already opened */ pmInsufficientMemory, pmBufferTooSmall, pmBufferOverflow, pmBadPtr, /* PortMidiStream parameter is NULL or * stream is not opened or * stream is output when input is required or * stream is input when output is required */ pmBadData, /** illegal midi data, e.g. missing EOX */ pmInternalError, pmBufferMaxSize /** buffer is already as large as it can be */ /* NOTE: If you add a new error type, be sure to update Pm_GetErrorText() */ } PmError; /** Pm_Initialize() is the library initialisation function - call this before using the library. */ PMEXPORT PmError Pm_Initialize( void ); /** Pm_Terminate() is the library termination function - call this after using the library. */ PMEXPORT PmError Pm_Terminate( void ); /** A single PortMidiStream is a descriptor for an open MIDI device. */ typedef void PortMidiStream; #define PmStream PortMidiStream /** Test whether stream has a pending host error. Normally, the client finds out about errors through returned error codes, but some errors can occur asynchronously where the client does not explicitly call a function, and therefore cannot receive an error code. The client can test for a pending error using Pm_HasHostError(). If true, the error can be accessed and cleared by calling Pm_GetErrorText(). Errors are also cleared by calling other functions that can return errors, e.g. Pm_OpenInput(), Pm_OpenOutput(), Pm_Read(), Pm_Write(). The client does not need to call Pm_HasHostError(). Any pending error will be reported the next time the client performs an explicit function call on the stream, e.g. an input or output operation. Until the error is cleared, no new error codes will be obtained, even for a different stream. */ PMEXPORT int Pm_HasHostError( PortMidiStream * stream ); /** Translate portmidi error number into human readable message. These strings are constants (set at compile time) so client has no need to allocate storage */ PMEXPORT const char *Pm_GetErrorText( PmError errnum ); /** Translate portmidi host error into human readable message. These strings are computed at run time, so client has to allocate storage. After this routine executes, the host error is cleared. */ PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len); #define HDRLENGTH 50 #define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less than this number of characters */ /** Device enumeration mechanism. Device ids range from 0 to Pm_CountDevices()-1. */ typedef int PmDeviceID; #define pmNoDevice -1 typedef struct { int structVersion; /**< this internal structure version */ const char *interf; /**< underlying MIDI API, e.g. MMSystem or DirectX */ const char *name; /**< device name, e.g. USB MidiSport 1x1 */ int input; /**< true iff input is available */ int output; /**< true iff output is available */ int opened; /**< used by generic PortMidi code to do error checking on arguments */ } PmDeviceInfo; /** Get devices count, ids range from 0 to Pm_CountDevices()-1. */ PMEXPORT int Pm_CountDevices( void ); /** Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID() Return the default device ID or pmNoDevice if there are no devices. The result (but not pmNoDevice) can be passed to Pm_OpenMidi(). The default device can be specified using a small application named pmdefaults that is part of the PortMidi distribution. This program in turn uses the Java Preferences object created by java.util.prefs.Preferences.userRoot().node("/PortMidi"); the preference is set by calling prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName); or prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName); In the statements above, prefName is a string describing the MIDI device in the form "interf, name" where interf identifies the underlying software system or API used by PortMdi to access devices and name is the name of the device. These correspond to the interf and name fields of a PmDeviceInfo. (Currently supported interfaces are "MMSystem" for Win32, "ALSA" for Linux, and "CoreMIDI" for OS X, so in fact, there is no choice of interface.) In "interf, name", the strings are actually substrings of the full interface and name strings. For example, the preference "Core, Sport" will match a device with interface "CoreMIDI" and name "In USB MidiSport 1x1". It will also match "CoreMIDI" and "In USB MidiSport 2x2". The devices are enumerated in device ID order, so the lowest device ID that matches the pattern becomes the default device. Finally, if the comma-space (", ") separator between interface and name parts of the preference is not found, the entire preference string is interpreted as a name, and the interface part is the empty string, which matches anything. On the MAC, preferences are stored in /Users/$NAME/Library/Preferences/com.apple.java.util.prefs.plist which is a binary file. In addition to the pmdefaults program, there are utilities that can read and edit this preference file. On the PC, On Linux, */ PMEXPORT PmDeviceID Pm_GetDefaultInputDeviceID( void ); /** see PmDeviceID Pm_GetDefaultInputDeviceID() */ PMEXPORT PmDeviceID Pm_GetDefaultOutputDeviceID( void ); /** PmTimestamp is used to represent a millisecond clock with arbitrary start time. The type is used for all MIDI timestampes and clocks. */ typedef int32_t PmTimestamp; typedef PmTimestamp (*PmTimeProcPtr)(void *time_info); /** TRUE if t1 before t2 */ #define PmBefore(t1,t2) ((t1-t2) < 0) /** \defgroup grp_device Input/Output Devices Handling @{ */ /** Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure referring to the device specified by id. If id is out of range the function returns NULL. The returned structure is owned by the PortMidi implementation and must not be manipulated or freed. The pointer is guaranteed to be valid between calls to Pm_Initialize() and Pm_Terminate(). */ PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ); /** Pm_OpenInput() and Pm_OpenOutput() open devices. stream is the address of a PortMidiStream pointer which will receive a pointer to the newly opened stream. inputDevice is the id of the device used for input (see PmDeviceID above). inputDriverInfo is a pointer to an optional driver specific data structure containing additional information for device setup or handle processing. inputDriverInfo is never required for correct operation. If not used inputDriverInfo should be NULL. outputDevice is the id of the device used for output (see PmDeviceID above.) outputDriverInfo is a pointer to an optional driver specific data structure containing additional information for device setup or handle processing. outputDriverInfo is never required for correct operation. If not used outputDriverInfo should be NULL. For input, the buffersize specifies the number of input events to be buffered waiting to be read using Pm_Read(). For output, buffersize specifies the number of output events to be buffered waiting for output. (In some cases -- see below -- PortMidi does not buffer output at all and merely passes data to a lower-level API, in which case buffersize is ignored.) latency is the delay in milliseconds applied to timestamps to determine when the output should actually occur. (If latency is < 0, 0 is assumed.) If latency is zero, timestamps are ignored and all output is delivered immediately. If latency is greater than zero, output is delayed until the message timestamp plus the latency. (NOTE: the time is measured relative to the time source indicated by time_proc. Timestamps are absolute, not relative delays or offsets.) In some cases, PortMidi can obtain better timing than your application by passing timestamps along to the device driver or hardware. Latency may also help you to synchronize midi data to audio data by matching midi latency to the audio buffer latency. time_proc is a pointer to a procedure that returns time in milliseconds. It may be NULL, in which case a default millisecond timebase (PortTime) is used. If the application wants to use PortTime, it should start the timer (call Pt_Start) before calling Pm_OpenInput or Pm_OpenOutput. If the application tries to start the timer *after* Pm_OpenInput or Pm_OpenOutput, it may get a ptAlreadyStarted error from Pt_Start, and the application's preferred time resolution and callback function will be ignored. time_proc result values are appended to incoming MIDI data, and time_proc times are used to schedule outgoing MIDI data (when latency is non-zero). time_info is a pointer passed to time_proc. Example: If I provide a timestamp of 5000, latency is 1, and time_proc returns 4990, then the desired output time will be when time_proc returns timestamp+latency = 5001. This will be 5001-4990 = 11ms from now. return value: Upon success Pm_Open() returns PmNoError and places a pointer to a valid PortMidiStream in the stream argument. If a call to Pm_Open() fails a nonzero error code is returned (see PMError above) and the value of port is invalid. Any stream that is successfully opened should eventually be closed by calling Pm_Close(). */ PMEXPORT PmError Pm_OpenInput( PortMidiStream** stream, PmDeviceID inputDevice, void *inputDriverInfo, int32_t bufferSize, PmTimeProcPtr time_proc, void *time_info ); PMEXPORT PmError Pm_OpenOutput( PortMidiStream** stream, PmDeviceID outputDevice, void *outputDriverInfo, int32_t bufferSize, PmTimeProcPtr time_proc, void *time_info, int32_t latency ); /** @} */ /** \defgroup grp_events_filters Events and Filters Handling @{ */ /* \function PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters ) Pm_SetFilter() sets filters on an open input stream to drop selected input types. By default, only active sensing messages are filtered. To prohibit, say, active sensing and sysex messages, call Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX); Filtering is useful when midi routing or midi thru functionality is being provided by the user application. For example, you may want to exclude timing messages (clock, MTC, start/stop/continue), while allowing note-related messages to pass. Or you may be using a sequencer or drum-machine for MIDI clock information but want to exclude any notes it may play. */ /* Filter bit-mask definitions */ /** filter active sensing messages (0xFE): */ #define PM_FILT_ACTIVE (1 << 0x0E) /** filter system exclusive messages (0xF0): */ #define PM_FILT_SYSEX (1 << 0x00) /** filter MIDI clock message (0xF8) */ #define PM_FILT_CLOCK (1 << 0x08) /** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */ #define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B)) /** filter tick messages (0xF9) */ #define PM_FILT_TICK (1 << 0x09) /** filter undefined FD messages */ #define PM_FILT_FD (1 << 0x0D) /** filter undefined real-time messages */ #define PM_FILT_UNDEFINED PM_FILT_FD /** filter reset messages (0xFF) */ #define PM_FILT_RESET (1 << 0x0F) /** filter all real-time messages */ #define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \ PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK) /** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */ #define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18)) /** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/ #define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D) /** per-note aftertouch (0xA0-0xAF) */ #define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A) /** filter both channel and poly aftertouch */ #define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH) /** Program changes (0xC0-0xCF) */ #define PM_FILT_PROGRAM (1 << 0x1C) /** Control Changes (CC's) (0xB0-0xBF)*/ #define PM_FILT_CONTROL (1 << 0x1B) /** Pitch Bender (0xE0-0xEF*/ #define PM_FILT_PITCHBEND (1 << 0x1E) /** MIDI Time Code (0xF1)*/ #define PM_FILT_MTC (1 << 0x01) /** Song Position (0xF2) */ #define PM_FILT_SONG_POSITION (1 << 0x02) /** Song Select (0xF3)*/ #define PM_FILT_SONG_SELECT (1 << 0x03) /** Tuning request (0xF6)*/ #define PM_FILT_TUNE (1 << 0x06) /** All System Common messages (mtc, song position, song select, tune request) */ #define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE) PMEXPORT PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters ); #define Pm_Channel(channel) (1<<(channel)) /** Pm_SetChannelMask() filters incoming messages based on channel. The mask is a 16-bit bitfield corresponding to appropriate channels. The Pm_Channel macro can assist in calling this function. i.e. to set receive only input on channel 1, call with Pm_SetChannelMask(Pm_Channel(1)); Multiple channels should be OR'd together, like Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11)) Note that channels are numbered 0 to 15 (not 1 to 16). Most synthesizer and interfaces number channels starting at 1, but PortMidi numbers channels starting at 0. All channels are allowed by default */ PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask); /** Pm_Abort() terminates outgoing messages immediately The caller should immediately close the output port; this call may result in transmission of a partial midi message. There is no abort for Midi input because the user can simply ignore messages in the buffer and close an input device at any time. */ PMEXPORT PmError Pm_Abort( PortMidiStream* stream ); /** Pm_Close() closes a midi stream, flushing any pending buffers. (PortMidi attempts to close open streams when the application exits -- this is particularly difficult under Windows.) */ PMEXPORT PmError Pm_Close( PortMidiStream* stream ); /** Pm_Synchronize() instructs PortMidi to (re)synchronize to the time_proc passed when the stream was opened. Typically, this is used when the stream must be opened before the time_proc reference is actually advancing. In this case, message timing may be erratic, but since timestamps of zero mean "send immediately," initialization messages with zero timestamps can be written without a functioning time reference and without problems. Before the first MIDI message with a non-zero timestamp is written to the stream, the time reference must begin to advance (for example, if the time_proc computes time based on audio samples, time might begin to advance when an audio stream becomes active). After time_proc return values become valid, and BEFORE writing the first non-zero timestamped MIDI message, call Pm_Synchronize() so that PortMidi can observe the difference between the current time_proc value and its MIDI stream time. In the more normal case where time_proc values advance continuously, there is no need to call Pm_Synchronize. PortMidi will always synchronize at the first output message and periodically thereafter. */ PmError Pm_Synchronize( PortMidiStream* stream ); /** Pm_Message() encodes a short Midi message into a 32-bit word. If data1 and/or data2 are not present, use zero. Pm_MessageStatus(), Pm_MessageData1(), and Pm_MessageData2() extract fields from a 32-bit midi message. */ #define Pm_Message(status, data1, data2) \ ((((data2) << 16) & 0xFF0000) | \ (((data1) << 8) & 0xFF00) | \ ((status) & 0xFF)) #define Pm_MessageStatus(msg) ((msg) & 0xFF) #define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF) #define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF) typedef int32_t PmMessage; /**< see PmEvent */ /** All midi data comes in the form of PmEvent structures. A sysex message is encoded as a sequence of PmEvent structures, with each structure carrying 4 bytes of the message, i.e. only the first PmEvent carries the status byte. Note that MIDI allows nested messages: the so-called "real-time" MIDI messages can be inserted into the MIDI byte stream at any location, including within a sysex message. MIDI real-time messages are one-byte messages used mainly for timing (see the MIDI spec). PortMidi retains the order of non-real-time MIDI messages on both input and output, but it does not specify exactly how real-time messages are processed. This is particulary problematic for MIDI input, because the input parser must either prepare to buffer an unlimited number of sysex message bytes or to buffer an unlimited number of real-time messages that arrive embedded in a long sysex message. To simplify things, the input parser is allowed to pass real-time MIDI messages embedded within a sysex message, and it is up to the client to detect, process, and remove these messages as they arrive. When receiving sysex messages, the sysex message is terminated by either an EOX status byte (anywhere in the 4 byte messages) or by a non-real-time status byte in the low order byte of the message. If you get a non-real-time status byte but there was no EOX byte, it means the sysex message was somehow truncated. This is not considered an error; e.g., a missing EOX can result from the user disconnecting a MIDI cable during sysex transmission. A real-time message can occur within a sysex message. A real-time message will always occupy a full PmEvent with the status byte in the low-order byte of the PmEvent message field. (This implies that the byte-order of sysex bytes and real-time message bytes may not be preserved -- for example, if a real-time message arrives after 3 bytes of a sysex message, the real-time message will be delivered first. The first word of the sysex message will be delivered only after the 4th byte arrives, filling the 4-byte PmEvent message field. The timestamp field is observed when the output port is opened with a non-zero latency. A timestamp of zero means "use the current time", which in turn means to deliver the message with a delay of latency (the latency parameter used when opening the output port.) Do not expect PortMidi to sort data according to timestamps -- messages should be sent in the correct order, and timestamps MUST be non-decreasing. See also "Example" for Pm_OpenOutput() above. A sysex message will generally fill many PmEvent structures. On output to a PortMidiStream with non-zero latency, the first timestamp on sysex message data will determine the time to begin sending the message. PortMidi implementations may ignore timestamps for the remainder of the sysex message. On input, the timestamp ideally denotes the arrival time of the status byte of the message. The first timestamp on sysex message data will be valid. Subsequent timestamps may denote when message bytes were actually received, or they may be simply copies of the first timestamp. Timestamps for nested messages: If a real-time message arrives in the middle of some other message, it is enqueued immediately with the timestamp corresponding to its arrival time. The interrupted non-real-time message or 4-byte packet of sysex data will be enqueued later. The timestamp of interrupted data will be equal to that of the interrupting real-time message to insure that timestamps are non-decreasing. */ typedef struct { PmMessage message; PmTimestamp timestamp; } PmEvent; /** @} */ /** \defgroup grp_io Reading and Writing Midi Messages @{ */ /** Pm_Read() retrieves midi data into a buffer, and returns the number of events read. Result is a non-negative number unless an error occurs, in which case a PmError value will be returned. Buffer Overflow The problem: if an input overflow occurs, data will be lost, ultimately because there is no flow control all the way back to the data source. When data is lost, the receiver should be notified and some sort of graceful recovery should take place, e.g. you shouldn't resume receiving in the middle of a long sysex message. With a lock-free fifo, which is pretty much what we're stuck with to enable portability to the Mac, it's tricky for the producer and consumer to synchronously reset the buffer and resume normal operation. Solution: the buffer managed by PortMidi will be flushed when an overflow occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow) and ordinary processing resumes as soon as a new message arrives. The remainder of a partial sysex message is not considered to be a "new message" and will be flushed as well. */ PMEXPORT int Pm_Read( PortMidiStream *stream, PmEvent *buffer, int32_t length ); /** Pm_Poll() tests whether input is available, returning TRUE, FALSE, or an error value. */ PMEXPORT PmError Pm_Poll( PortMidiStream *stream); /** Pm_Write() writes midi data from a buffer. This may contain: - short messages or - sysex messages that are converted into a sequence of PmEvent structures, e.g. sending data from a file or forwarding them from midi input. Use Pm_WriteSysEx() to write a sysex message stored as a contiguous array of bytes. Sysex data may contain embedded real-time messages. */ PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length ); /** Pm_WriteShort() writes a timestamped non-system-exclusive midi message. Messages are delivered in order as received, and timestamps must be non-decreasing. (But timestamps are ignored if the stream was opened with latency = 0.) */ PMEXPORT PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, int32_t msg); /** Pm_WriteSysEx() writes a timestamped system-exclusive midi message. */ PMEXPORT PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg); /** @} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PORT_MIDI_H */ portmidi/pm_common/pmutil.c0000755000000000000000000002034711274243554015065 0ustar rootroot/* pmutil.c -- some helpful utilities for building midi applications that use PortMidi */ #include #include #include #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #ifdef WIN32 #define bzero(addr, siz) memset(addr, 0, siz) #endif // #define QUEUE_DEBUG 1 #ifdef QUEUE_DEBUG #include "stdio.h" #endif typedef struct { long head; long tail; long len; long overflow; int32_t msg_size; /* number of int32_t in a message including extra word */ int32_t peek_overflow; int32_t *buffer; int32_t *peek; int32_t peek_flag; } PmQueueRep; PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg) { int32_t int32s_per_msg = (int32_t) (((bytes_per_msg + sizeof(int32_t) - 1) & ~(sizeof(int32_t) - 1)) / sizeof(int32_t)); PmQueueRep *queue = (PmQueueRep *) pm_alloc(sizeof(PmQueueRep)); if (!queue) /* memory allocation failed */ return NULL; /* need extra word per message for non-zero encoding */ queue->len = num_msgs * (int32s_per_msg + 1); queue->buffer = (int32_t *) pm_alloc(queue->len * sizeof(int32_t)); bzero(queue->buffer, queue->len * sizeof(int32_t)); if (!queue->buffer) { pm_free(queue); return NULL; } else { /* allocate the "peek" buffer */ queue->peek = (int32_t *) pm_alloc(int32s_per_msg * sizeof(int32_t)); if (!queue->peek) { /* free everything allocated so far and return */ pm_free(queue->buffer); pm_free(queue); return NULL; } } bzero(queue->buffer, queue->len * sizeof(int32_t)); queue->head = 0; queue->tail = 0; /* msg_size is in words */ queue->msg_size = int32s_per_msg + 1; /* note extra word is counted */ queue->overflow = FALSE; queue->peek_overflow = FALSE; queue->peek_flag = FALSE; return queue; } PMEXPORT PmError Pm_QueueDestroy(PmQueue *q) { PmQueueRep *queue = (PmQueueRep *) q; /* arg checking */ if (!queue || !queue->buffer || !queue->peek) return pmBadPtr; pm_free(queue->peek); pm_free(queue->buffer); pm_free(queue); return pmNoError; } PMEXPORT PmError Pm_Dequeue(PmQueue *q, void *msg) { long head; PmQueueRep *queue = (PmQueueRep *) q; int i; int32_t *msg_as_int32 = (int32_t *) msg; /* arg checking */ if (!queue) return pmBadPtr; /* a previous peek operation encountered an overflow, but the overflow * has not yet been reported to client, so do it now. No message is * returned, but on the next call, we will return the peek buffer. */ if (queue->peek_overflow) { queue->peek_overflow = FALSE; return pmBufferOverflow; } if (queue->peek_flag) { memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32_t)); queue->peek_flag = FALSE; return pmGotData; } head = queue->head; /* if writer overflows, it writes queue->overflow = tail+1 so that * when the reader gets to that position in the buffer, it can * return the overflow condition to the reader. The problem is that * at overflow, things have wrapped around, so tail == head, and the * reader will detect overflow immediately instead of waiting until * it reads everything in the buffer, wrapping around again to the * point where tail == head. So the condition also checks that * queue->buffer[head] is zero -- if so, then the buffer is now * empty, and we're at the point in the msg stream where overflow * occurred. It's time to signal overflow to the reader. If * queue->buffer[head] is non-zero, there's a message there and we * should read all the way around the buffer before signalling overflow. * There is a write-order dependency here, but to fail, the overflow * field would have to be written while an entire buffer full of * writes are still pending. I'm assuming out-of-order writes are * possible, but not that many. */ if (queue->overflow == head + 1 && !queue->buffer[head]) { queue->overflow = 0; /* non-overflow condition */ return pmBufferOverflow; } /* test to see if there is data in the queue -- test from back * to front so if writer is simultaneously writing, we don't * waste time discovering the write is not finished */ for (i = queue->msg_size - 1; i >= 0; i--) { if (!queue->buffer[head + i]) { return pmNoData; } } memcpy(msg, (char *) &queue->buffer[head + 1], sizeof(int32_t) * (queue->msg_size - 1)); /* fix up zeros */ i = queue->buffer[head]; while (i < queue->msg_size) { int32_t j; i--; /* msg does not have extra word so shift down */ j = msg_as_int32[i]; msg_as_int32[i] = 0; i = j; } /* signal that data has been removed by zeroing: */ bzero((char *) &queue->buffer[head], sizeof(int32_t) * queue->msg_size); /* update head */ head += queue->msg_size; if (head == queue->len) head = 0; queue->head = head; return pmGotData; /* success */ } PMEXPORT PmError Pm_SetOverflow(PmQueue *q) { PmQueueRep *queue = (PmQueueRep *) q; long tail; /* arg checking */ if (!queue) return pmBadPtr; /* no more enqueue until receiver acknowledges overflow */ if (queue->overflow) return pmBufferOverflow; tail = queue->tail; queue->overflow = tail + 1; return pmBufferOverflow; } PMEXPORT PmError Pm_Enqueue(PmQueue *q, void *msg) { PmQueueRep *queue = (PmQueueRep *) q; long tail; int i; int32_t *src = (int32_t *) msg; int32_t *ptr; int32_t *dest; int rslt; if (!queue) return pmBadPtr; /* no more enqueue until receiver acknowledges overflow */ if (queue->overflow) return pmBufferOverflow; rslt = Pm_QueueFull(q); /* already checked above: if (rslt == pmBadPtr) return rslt; */ tail = queue->tail; if (rslt) { queue->overflow = tail + 1; return pmBufferOverflow; } /* queue is has room for message, and overflow flag is cleared */ ptr = &queue->buffer[tail]; dest = ptr + 1; for (i = 1; i < queue->msg_size; i++) { int32_t j = src[i - 1]; if (!j) { *ptr = i; ptr = dest; } else { *dest = j; } dest++; } *ptr = i; tail += queue->msg_size; if (tail == queue->len) tail = 0; queue->tail = tail; return pmNoError; } PMEXPORT int Pm_QueueEmpty(PmQueue *q) { PmQueueRep *queue = (PmQueueRep *) q; return (!queue) || /* null pointer -> return "empty" */ (queue->buffer[queue->head] == 0 && !queue->peek_flag); } PMEXPORT int Pm_QueueFull(PmQueue *q) { long tail; int i; PmQueueRep *queue = (PmQueueRep *) q; /* arg checking */ if (!queue) return pmBadPtr; tail = queue->tail; /* test to see if there is space in the queue */ for (i = 0; i < queue->msg_size; i++) { if (queue->buffer[tail + i]) { return TRUE; } } return FALSE; } PMEXPORT void *Pm_QueuePeek(PmQueue *q) { PmError rslt; int32_t temp; PmQueueRep *queue = (PmQueueRep *) q; /* arg checking */ if (!queue) return NULL; if (queue->peek_flag) { return queue->peek; } /* this is ugly: if peek_overflow is set, then Pm_Dequeue() * returns immediately with pmBufferOverflow, but here, we * want Pm_Dequeue() to really check for data. If data is * there, we can return it */ temp = queue->peek_overflow; queue->peek_overflow = FALSE; rslt = Pm_Dequeue(q, queue->peek); queue->peek_overflow = temp; if (rslt == 1) { queue->peek_flag = TRUE; return queue->peek; } else if (rslt == pmBufferOverflow) { /* when overflow is indicated, the queue is empty and the * first message that was dropped by Enqueue (signalling * pmBufferOverflow to its caller) would have been the next * message in the queue. Pm_QueuePeek will return NULL, but * remember that an overflow occurred. (see Pm_Dequeue) */ queue->peek_overflow = TRUE; } return NULL; } portmidi/pm_common/pmutil.h0000755000000000000000000001322311274243554015065 0ustar rootroot/* pmutil.h -- some helpful utilities for building midi applications that use PortMidi */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef void PmQueue; /* A single-reader, single-writer queue is created by Pm_QueueCreate(), which takes the number of messages and the message size as parameters. The queue only accepts fixed sized messages. Returns NULL if memory cannot be allocated. This queue implementation uses the "light pipe" algorithm which operates correctly even with multi-processors and out-of-order memory writes. (see Alexander Dokumentov, "Lock-free Interprocess Communication," Dr. Dobbs Portal, http://www.ddj.com/, articleID=189401457, June 15, 2006. This algorithm requires that messages be translated to a form where no words contain zeros. Each word becomes its own "data valid" tag. Because of this translation, we cannot return a pointer to data still in the queue when the "peek" method is called. Instead, a buffer is preallocated so that data can be copied there. Pm_QueuePeek() dequeues a message into this buffer and returns a pointer to it. A subsequent Pm_Dequeue() will copy from this buffer. This implementation does not try to keep reader/writer data in separate cache lines or prevent thrashing on cache lines. However, this algorithm differs by doing inserts/removals in units of messages rather than units of machine words. Some performance improvement might be obtained by not clearing data immediately after a read, but instead by waiting for the end of the cache line, especially if messages are smaller than cache lines. See the Dokumentov article for explanation. The algorithm is extended to handle "overflow" reporting. To report an overflow, the sender writes the current tail position to a field. The receiver must acknowlege receipt by zeroing the field. The sender will not send more until the field is zeroed. Pm_QueueDestroy() destroys the queue and frees its storage. */ PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg); PMEXPORT PmError Pm_QueueDestroy(PmQueue *queue); /* Pm_Dequeue() removes one item from the queue, copying it into msg. Returns 1 if successful, and 0 if the queue is empty. Returns pmBufferOverflow if what would have been the next thing in the queue was dropped due to overflow. (So when overflow occurs, the receiver can receive a queue full of messages before getting the overflow report. This protocol ensures that the reader will be notified when data is lost due to overflow. */ PMEXPORT PmError Pm_Dequeue(PmQueue *queue, void *msg); /* Pm_Enqueue() inserts one item into the queue, copying it from msg. Returns pmNoError if successful and pmBufferOverflow if the queue was already full. If pmBufferOverflow is returned, the overflow flag is set. */ PMEXPORT PmError Pm_Enqueue(PmQueue *queue, void *msg); /* Pm_QueueFull() returns non-zero if the queue is full Pm_QueueEmpty() returns non-zero if the queue is empty Either condition may change immediately because a parallel enqueue or dequeue operation could be in progress. Furthermore, Pm_QueueEmpty() is optimistic: it may say false, when due to out-of-order writes, the full message has not arrived. Therefore, Pm_Dequeue() could still return 0 after Pm_QueueEmpty() returns false. On the other hand, Pm_QueueFull() is pessimistic: if it returns false, then Pm_Enqueue() is guaranteed to succeed. Error conditions: Pm_QueueFull() returns pmBadPtr if queue is NULL. Pm_QueueEmpty() returns FALSE if queue is NULL. */ PMEXPORT int Pm_QueueFull(PmQueue *queue); PMEXPORT int Pm_QueueEmpty(PmQueue *queue); /* Pm_QueuePeek() returns a pointer to the item at the head of the queue, or NULL if the queue is empty. The item is not removed from the queue. Pm_QueuePeek() will not indicate when an overflow occurs. If you want to get and check pmBufferOverflow messages, use the return value of Pm_QueuePeek() *only* as an indication that you should call Pm_Dequeue(). At the point where a direct call to Pm_Dequeue() would return pmBufferOverflow, Pm_QueuePeek() will return NULL but internally clear the pmBufferOverflow flag, enabling Pm_Enqueue() to resume enqueuing messages. A subsequent call to Pm_QueuePeek() will return a pointer to the first message *after* the overflow. Using this as an indication to call Pm_Dequeue(), the first call to Pm_Dequeue() will return pmBufferOverflow. The second call will return success, copying the same message pointed to by the previous Pm_QueuePeek(). When to use Pm_QueuePeek(): (1) when you need to look at the message data to decide who should be called to receive it. (2) when you need to know a message is ready but cannot accept the message. Note that Pm_QueuePeek() is not a fast check, so if possible, you might as well just call Pm_Dequeue() and accept the data if it is there. */ PMEXPORT void *Pm_QueuePeek(PmQueue *queue); /* Pm_SetOverflow() allows the writer (enqueuer) to signal an overflow condition to the reader (dequeuer). E.g. when transfering data from the OS to an application, if the OS indicates a buffer overrun, Pm_SetOverflow() can be used to insure that the reader receives a pmBufferOverflow result from Pm_Dequeue(). Returns pmBadPtr if queue is NULL, returns pmBufferOverflow if buffer is already in an overflow state, returns pmNoError if successfully set overflow state. */ PMEXPORT PmError Pm_SetOverflow(PmQueue *queue); #ifdef __cplusplus } #endif /* __cplusplus */ portmidi/pm_common/portmidi-static.vcproj0000644000000000000000000001064111274243554017741 0ustar rootroot portmidi/pm_common/pminternal.h0000755000000000000000000002015511265200032015706 0ustar rootroot/* pminternal.h -- header for interface implementations */ /* this file is included by files that implement library internals */ /* Here is a guide to implementers: provide an initialization function similar to pm_winmm_init() add your initialization function to pm_init() Note that your init function should never require not-standard libraries or fail in any way. If the interface is not available, simply do not call pm_add_device. This means that non-standard libraries should try to do dynamic linking at runtime using a DLL and return without error if the DLL cannot be found or if there is any other failure. implement functions as indicated in pm_fns_type to open, read, write, close, etc. call pm_add_device() for each input and output device, passing it a pm_fns_type structure. assumptions about pm_fns_type functions are given below. */ #ifdef __cplusplus extern "C" { #endif extern int pm_initialized; /* see note in portmidi.c */ /* these are defined in system-specific file */ void *pm_alloc(size_t s); void pm_free(void *ptr); /* if an error occurs while opening or closing a midi stream, set these: */ extern int pm_hosterror; extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN]; struct pm_internal_struct; /* these do not use PmInternal because it is not defined yet... */ typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi, PmEvent *buffer); typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi, PmTimestamp timestamp); typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi, PmTimestamp timestamp); typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi, unsigned char byte, PmTimestamp timestamp); typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi, PmEvent *buffer); typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi, PmTimestamp timestamp); typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi); /* pm_open_fn should clean up all memory and close the device if any part of the open fails */ typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi, void *driverInfo); typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi); /* pm_close_fn should clean up all memory and close the device if any part of the close fails. */ typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi); typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi); typedef void (*pm_host_error_fn)(struct pm_internal_struct *midi, char * msg, unsigned int len); typedef unsigned int (*pm_has_host_error_fn)(struct pm_internal_struct *midi); typedef struct { pm_write_short_fn write_short; /* output short MIDI msg */ pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */ pm_end_sysex_fn end_sysex; /* marks end of sysex message */ pm_write_byte_fn write_byte; /* accumulate one more sysex byte */ pm_write_realtime_fn write_realtime; /* send real-time message within sysex */ pm_write_flush_fn write_flush; /* send any accumulated but unsent data */ pm_synchronize_fn synchronize; /* synchronize portmidi time to stream time */ pm_open_fn open; /* open MIDI device */ pm_abort_fn abort; /* abort */ pm_close_fn close; /* close device */ pm_poll_fn poll; /* read pending midi events into portmidi buffer */ pm_has_host_error_fn has_host_error; /* true when device has had host error message */ pm_host_error_fn host_error; /* provide text readable host error message for device (clears and resets) */ } pm_fns_node, *pm_fns_type; /* when open fails, the dictionary gets this set of functions: */ extern pm_fns_node pm_none_dictionary; typedef struct { PmDeviceInfo pub; /* some portmidi state also saved in here (for autmatic device closing (see PmDeviceInfo struct) */ void *descriptor; /* ID number passed to win32 multimedia API open */ void *internalDescriptor; /* points to PmInternal device, allows automatic device closing */ pm_fns_type dictionary; } descriptor_node, *descriptor_type; extern int pm_descriptor_max; extern descriptor_type descriptors; extern int pm_descriptor_index; typedef uint32_t (*time_get_proc_type)(void *time_info); typedef struct pm_internal_struct { int device_id; /* which device is open (index to descriptors) */ short write_flag; /* MIDI_IN, or MIDI_OUT */ PmTimeProcPtr time_proc; /* where to get the time */ void *time_info; /* pass this to get_time() */ int32_t buffer_len; /* how big is the buffer or queue? */ PmQueue *queue; int32_t latency; /* time delay in ms between timestamps and actual output */ /* set to zero to get immediate, simple blocking output */ /* if latency is zero, timestamps will be ignored; */ /* if midi input device, this field ignored */ int sysex_in_progress; /* when sysex status is seen, this flag becomes * true until EOX is seen. When true, new data is appended to the * stream of outgoing bytes. When overflow occurs, sysex data is * dropped (until an EOX or non-real-timei status byte is seen) so * that, if the overflow condition is cleared, we don't start * sending data from the middle of a sysex message. If a sysex * message is filtered, sysex_in_progress is false, causing the * message to be dropped. */ PmMessage sysex_message; /* buffer for 4 bytes of sysex data */ int sysex_message_count; /* how many bytes in sysex_message so far */ int32_t filters; /* flags that filter incoming message classes */ int32_t channel_mask; /* filter incoming messages based on channel */ PmTimestamp last_msg_time; /* timestamp of last message */ PmTimestamp sync_time; /* time of last synchronization */ PmTimestamp now; /* set by PmWrite to current time */ int first_message; /* initially true, used to run first synchronization */ pm_fns_type dictionary; /* implementation functions */ void *descriptor; /* system-dependent state */ /* the following are used to expedite sysex data */ /* on windows, in debug mode, based on some profiling, these optimizations * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte, * but this does not count time in the driver, so I don't know if it is * important */ unsigned char *fill_base; /* addr of ptr to sysex data */ uint32_t *fill_offset_ptr; /* offset of next sysex byte */ int32_t fill_length; /* how many sysex bytes to write */ } PmInternal; /* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */ void pm_init(void); void pm_term(void); /* defined by portMidi, used by pmwinmm */ PmError none_write_short(PmInternal *midi, PmEvent *buffer); PmError none_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp); PmTimestamp none_synchronize(PmInternal *midi); PmError pm_fail_fn(PmInternal *midi); PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp); PmError pm_success_fn(PmInternal *midi); PmError pm_add_device(char *interf, char *name, int input, void *descriptor, pm_fns_type dictionary); uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len, PmTimestamp timestamp); void pm_read_short(PmInternal *midi, PmEvent *event); #define none_write_flush pm_fail_timestamp_fn #define none_sysex pm_fail_timestamp_fn #define none_poll pm_fail_fn #define success_poll pm_success_fn #define MIDI_REALTIME_MASK 0xf8 #define is_real_time(msg) \ ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK) int pm_find_default_device(char *pattern, int is_input); #ifdef __cplusplus } #endif portmidi/pm_common/pmjni.vcproj0000644000000000000000000001276711274243554015755 0ustar rootroot portmidi/pm_common/portmidi-dynamic.vcproj0000644000000000000000000001662511274243554020106 0ustar rootroot portmidi/pm_common/CMakeLists.txt0000644000000000000000000001162211445664134016141 0ustar rootroot# pm_common # set the build directory for libportmidi.a to be in portmidi, not in # portmidi/pm_common if(APPLE OR WIN32) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) # set the build directory for .dylib libraries set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) # the first time CMake configures, save off CMake's built-in flags if(NOT DEFAULT_DEBUG_FLAGS) set(DEFAULT_DEBUG_FLAGS ${CMAKE_C_FLAGS_DEBUG} CACHE STRING "CMake's default debug flags" FORCE) set(DEFAULT_RELEASE_FLAGS ${CMAKE_C_FLAGS_RELEASE} CACHE STRING "CMake's default release flags" FORCE) else(NOT DEFAULT_DEBUG_FLAGS) message(STATUS "DEFAULT_DEBUG_FLAGS not nil: " ${DEFAULT_DEBUG_FLAGS}) endif(NOT DEFAULT_DEBUG_FLAGS) else(APPLE OR WIN32) set(LINUX_FLAGS "-DPMALSA") endif(APPLE OR WIN32) if(APPLE) set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk CACHE PATH "-isysroot parameter for compiler" FORCE) set(CMAKE_C_FLAGS "-mmacosx-version-min=10.5" CACHE STRING "needed in conjunction with CMAKE_OSX_SYSROOT" FORCE) endif(APPLE) macro(prepend_path RESULT PATH) set(${RESULT}) foreach(FILE ${ARGN}) list(APPEND ${RESULT} "${PATH}${FILE}") endforeach(FILE) endmacro(prepend_path) set(CMAKE_C_FLAGS_DEBUG "${DEFAULT_DEBUG_FLAGS} -DPM_CHECK_ERRORS=1 -DDEBUG ${LINUX_FLAGS}" CACHE STRING "enable extra checks for debugging" FORCE) set(CMAKE_C_FLAGS_RELEASE "${DEFAULT_RELEASE_FLAGS} ${LINUX_FLAGS}" CACHE STRING "flags for release version" FORCE) # first include the appropriate system-dependent file: if(UNIX) # add the -g switch for Linux and Mac OS X (not used in Win32) set (CMAKE_C_FLAGS_DEBUG "-g ${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "enable extra checks for debugging" FORCE) if(APPLE) set(MACSRC pmmacosxcm pmmac readbinaryplist finddefault) prepend_path(LIBSRC ../pm_mac/ ${MACSRC}) list(APPEND LIBSRC ../porttime/ptmacosx_mach) include_directories(${CMAKE_OSX_SYSROOT}/Developer/Headers/FlatCarbon) set(FRAMEWORK_PATH ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks) set(COREAUDIO_LIB "${FRAMEWORK_PATH}/CoreAudio.framework") set(COREFOUNDATION_LIB "${FRAMEWORK_PATH}/CoreFoundation.framework") set(COREMIDI_LIB "${FRAMEWORK_PATH}/CoreMIDI.framework") set(CORESERVICES_LIB "${FRAMEWORK_PATH}/CoreServices.framework") set(PM_NEEDED_LIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB} ${COREMIDI_LIB} ${CORESERVICES_LIB} CACHE INTERNAL "") set(JAVAVM_LIB "${FRAMEWORK_PATH}/JavaVM.framework") set(JAVA_INCLUDE_PATHS ${JAVAVM_LIB}/Headers) message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT}) else(APPLE) # LINUX settings... include(FindJNI) message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) message(STATUS "JAVA_INCLUDE_PATH2 is " ${JAVA_INCLUDE_PATH2}) message(STATUS "JAVA_JVM_LIBRARY is " ${JAVA_JVM_LIBRARY}) set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) # libjvm.so is found relative to JAVA_INCLUDE_PATH: set(JAVAVM_LIB ${JAVA_JVM_LIBRARY}/libjvm.so) set(LINUXSRC pmlinuxalsa pmlinux finddefault) prepend_path(LIBSRC ../pm_linux/ ${LINUXSRC}) list(APPEND LIBSRC ../porttime/ptlinux) set(PM_NEEDED_LIBS pthread asound) endif(APPLE) else(UNIX) if(WIN32) # /MDd is multithread debug DLL, /MTd is multithread debug # /MD is multithread DLL, /MT is multithread. Change to static: include(../pm_win/static.cmake) include(FindJNI) set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS}) set(WINSRC pmwin pmwinmm) prepend_path(LIBSRC ../pm_win/ ${WINSRC}) list(APPEND LIBSRC ../porttime/ptwinmm) set(PM_NEEDED_LIBS winmm.lib) endif(WIN32) endif(UNIX) set(JNI_EXTRA_LIBS ${PM_NEEDED_LIBS} ${JAVA_JVM_LIBRARY}) # this completes the list of library sources by adding shared code list(APPEND LIBSRC pmutil portmidi) # now add the shared files to make the complete list of library sources add_library(portmidi-static ${LIBSRC}) set_target_properties(portmidi-static PROPERTIES OUTPUT_NAME "portmidi_s") target_link_libraries(portmidi-static ${PM_NEEDED_LIBS}) # define the jni library include_directories(${JAVA_INCLUDE_PATHS}) set(JNISRC ${LIBSRC} ../pm_java/pmjni/pmjni.c) add_library(pmjni SHARED ${JNISRC}) target_link_libraries(pmjni ${JNI_EXTRA_LIBS}) set_target_properties(pmjni PROPERTIES EXECUTABLE_EXTENSION "jnilib") # install the libraries (Linux and Mac OS X command line) if(UNIX) INSTALL(TARGETS portmidi-static pmjni LIBRARY DESTINATION /usr/local/lib ARCHIVE DESTINATION /usr/local/lib) # .h files installed by pm_dylib/CMakeLists.txt, so don't need them here # INSTALL(FILES portmidi.h ../porttime/porttime.h # DESTINATION /usr/local/include) endif(UNIX) portmidi/pm_common/portmidi.c0000755000000000000000000011445011310172344015366 0ustar rootroot#ifdef _MSC_VER #pragma warning(disable: 4244) // stop warnings about downsize typecasts #pragma warning(disable: 4018) // stop warnings about signed/unsigned #endif #include "stdlib.h" #include "string.h" #include "portmidi.h" #include "porttime.h" #include "pmutil.h" #include "pminternal.h" #include #define MIDI_CLOCK 0xf8 #define MIDI_ACTIVE 0xfe #define MIDI_STATUS_MASK 0x80 #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 #define MIDI_START 0xFA #define MIDI_STOP 0xFC #define MIDI_CONTINUE 0xFB #define MIDI_F9 0xF9 #define MIDI_FD 0xFD #define MIDI_RESET 0xFF #define MIDI_NOTE_ON 0x90 #define MIDI_NOTE_OFF 0x80 #define MIDI_CHANNEL_AT 0xD0 #define MIDI_POLY_AT 0xA0 #define MIDI_PROGRAM 0xC0 #define MIDI_CONTROL 0xB0 #define MIDI_PITCHBEND 0xE0 #define MIDI_MTC 0xF1 #define MIDI_SONGPOS 0xF2 #define MIDI_SONGSEL 0xF3 #define MIDI_TUNE 0xF6 #define is_empty(midi) ((midi)->tail == (midi)->head) /* this is not static so that pm_init can set it directly if * (see pmmac.c:pm_init()) */ int pm_initialized = FALSE; int pm_hosterror; char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN]; #ifdef PM_CHECK_ERRORS #include #define STRING_MAX 80 static void prompt_and_exit(void) { char line[STRING_MAX]; printf("type ENTER..."); fgets(line, STRING_MAX, stdin); /* this will clean up open ports: */ exit(-1); } static PmError pm_errmsg(PmError err) { if (err == pmHostError) { /* it seems pointless to allocate memory and copy the string, * so I will do the work of Pm_GetHostErrorText directly */ printf("PortMidi found host error...\n %s\n", pm_hosterror_text); pm_hosterror = FALSE; pm_hosterror_text[0] = 0; /* clear the message */ prompt_and_exit(); } else if (err < 0) { printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); prompt_and_exit(); } return err; } #else #define pm_errmsg(err) err #endif /* ==================================================================== system implementation of portmidi interface ==================================================================== */ int pm_descriptor_max = 0; int pm_descriptor_index = 0; descriptor_type descriptors = NULL; /* pm_add_device -- describe interface/device pair to library * * This is called at intialization time, once for each * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1) * The strings are retained but NOT COPIED, so do not destroy them! * * returns pmInvalidDeviceId if device memory is exceeded * otherwise returns pmNoError */ PmError pm_add_device(char *interf, char *name, int input, void *descriptor, pm_fns_type dictionary) { if (pm_descriptor_index >= pm_descriptor_max) { // expand descriptors descriptor_type new_descriptors = (descriptor_type) pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32)); if (!new_descriptors) return pmInsufficientMemory; if (descriptors) { memcpy(new_descriptors, descriptors, sizeof(descriptor_node) * pm_descriptor_max); free(descriptors); } pm_descriptor_max += 32; descriptors = new_descriptors; } descriptors[pm_descriptor_index].pub.interf = interf; descriptors[pm_descriptor_index].pub.name = name; descriptors[pm_descriptor_index].pub.input = input; descriptors[pm_descriptor_index].pub.output = !input; /* default state: nothing to close (for automatic device closing) */ descriptors[pm_descriptor_index].pub.opened = FALSE; /* ID number passed to win32 multimedia API open */ descriptors[pm_descriptor_index].descriptor = descriptor; /* points to PmInternal, allows automatic device closing */ descriptors[pm_descriptor_index].internalDescriptor = NULL; descriptors[pm_descriptor_index].dictionary = dictionary; pm_descriptor_index++; return pmNoError; } /* utility to look up device, given a pattern, note: pattern is modified */ int pm_find_default_device(char *pattern, int is_input) { int id = pmNoDevice; int i; /* first parse pattern into name, interf parts */ char *interf_pref = ""; /* initially assume it is not there */ char *name_pref = strstr(pattern, ", "); if (name_pref) { /* found separator, adjust the pointer */ interf_pref = pattern; name_pref[0] = 0; name_pref += 2; } else { name_pref = pattern; /* whole string is the name pattern */ } for (i = 0; i < pm_descriptor_index; i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if (info->input == is_input && strstr(info->name, name_pref) && strstr(info->interf, interf_pref)) { id = i; break; } } return id; } /* ==================================================================== portmidi implementation ==================================================================== */ PMEXPORT int Pm_CountDevices( void ) { Pm_Initialize(); /* no error checking -- Pm_Initialize() does not fail */ return pm_descriptor_index; } PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) { Pm_Initialize(); /* no error check needed */ if (id >= 0 && id < pm_descriptor_index) { return &descriptors[id].pub; } return NULL; } /* pm_success_fn -- "noop" function pointer */ PmError pm_success_fn(PmInternal *midi) { return pmNoError; } /* none_write -- returns an error if called */ PmError none_write_short(PmInternal *midi, PmEvent *buffer) { return pmBadPtr; } /* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */ PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp) { return pmBadPtr; } PmError none_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp) { return pmBadPtr; } /* pm_fail_fn -- generic function, returns error if called */ PmError pm_fail_fn(PmInternal *midi) { return pmBadPtr; } static PmError none_open(PmInternal *midi, void *driverInfo) { return pmBadPtr; } static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) { *msg = 0; // empty string } static unsigned int none_has_host_error(PmInternal * midi) { return FALSE; } PmTimestamp none_synchronize(PmInternal *midi) { return 0; } #define none_abort pm_fail_fn #define none_close pm_fail_fn pm_fns_node pm_none_dictionary = { none_write_short, none_sysex, none_sysex, none_write_byte, none_write_short, none_write_flush, none_synchronize, none_open, none_abort, none_close, none_poll, none_has_host_error, none_get_host_error }; PMEXPORT const char *Pm_GetErrorText( PmError errnum ) { const char *msg; switch(errnum) { case pmNoError: msg = ""; break; case pmHostError: msg = "PortMidi: `Host error'"; break; case pmInvalidDeviceId: msg = "PortMidi: `Invalid device ID'"; break; case pmInsufficientMemory: msg = "PortMidi: `Insufficient memory'"; break; case pmBufferTooSmall: msg = "PortMidi: `Buffer too small'"; break; case pmBadPtr: msg = "PortMidi: `Bad pointer'"; break; case pmInternalError: msg = "PortMidi: `Internal PortMidi Error'"; break; case pmBufferOverflow: msg = "PortMidi: `Buffer overflow'"; break; case pmBadData: msg = "PortMidi: `Invalid MIDI message Data'"; break; case pmBufferMaxSize: msg = "PortMidi: `Buffer cannot be made larger'"; break; default: msg = "PortMidi: `Illegal error number'"; break; } return msg; } /* This can be called whenever you get a pmHostError return value. * The error will always be in the global pm_hosterror_text. */ PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len) { assert(msg); assert(len > 0); if (pm_hosterror) { strncpy(msg, (char *) pm_hosterror_text, len); pm_hosterror = FALSE; pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it might help with debugging */ msg[len - 1] = 0; /* make sure string is terminated */ } else { msg[0] = 0; /* no string to return */ } } PMEXPORT int Pm_HasHostError(PortMidiStream * stream) { if (pm_hosterror) return TRUE; if (stream) { PmInternal * midi = (PmInternal *) stream; pm_hosterror = (*midi->dictionary->has_host_error)(midi); if (pm_hosterror) { midi->dictionary->host_error(midi, pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); /* now error message is global */ return TRUE; } } return FALSE; } PMEXPORT PmError Pm_Initialize( void ) { if (!pm_initialized) { pm_hosterror = FALSE; pm_hosterror_text[0] = 0; /* the null string */ pm_init(); pm_initialized = TRUE; } return pmNoError; } PMEXPORT PmError Pm_Terminate( void ) { if (pm_initialized) { pm_term(); // if there are no devices, descriptors might still be NULL if (descriptors != NULL) { free(descriptors); descriptors = NULL; } pm_descriptor_index = 0; pm_descriptor_max = 0; pm_initialized = FALSE; } return pmNoError; } /* Pm_Read -- read up to length messages from source into buffer */ /* * returns number of messages actually read, or error code */ PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length) { PmInternal *midi = (PmInternal *) stream; int n = 0; PmError err = pmNoError; pm_hosterror = FALSE; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.input) err = pmBadPtr; /* First poll for data in the buffer... * This either simply checks for data, or attempts first to fill the buffer * with data from the MIDI hardware; this depends on the implementation. * We could call Pm_Poll here, but that would redo a lot of redundant * parameter checking, so I copied some code from Pm_Poll to here: */ else err = (*(midi->dictionary->poll))(midi); if (err != pmNoError) { if (err == pmHostError) { midi->dictionary->host_error(midi, pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); pm_hosterror = TRUE; } return pm_errmsg(err); } while (n < length) { PmError err = Pm_Dequeue(midi->queue, buffer++); if (err == pmBufferOverflow) { /* ignore the data we have retreived so far */ return pm_errmsg(pmBufferOverflow); } else if (err == 0) { /* empty queue */ break; } n++; } return n; } PMEXPORT PmError Pm_Poll( PortMidiStream *stream ) { PmInternal *midi = (PmInternal *) stream; PmError err; pm_hosterror = FALSE; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.input) err = pmBadPtr; else err = (*(midi->dictionary->poll))(midi); if (err != pmNoError) { if (err == pmHostError) { midi->dictionary->host_error(midi, pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); pm_hosterror = TRUE; } return pm_errmsg(err); } return !Pm_QueueEmpty(midi->queue); } /* this is called from Pm_Write and Pm_WriteSysEx to issue a * call to the system-dependent end_sysex function and handle * the error return */ static PmError pm_end_sysex(PmInternal *midi) { PmError err = (*midi->dictionary->end_sysex)(midi, 0); midi->sysex_in_progress = FALSE; if (err == pmHostError) { midi->dictionary->host_error(midi, pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); pm_hosterror = TRUE; } return err; } /* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and Pm_WriteSysEx all operate a state machine that "outputs" calls to write_short, begin_sysex, write_byte, end_sysex, and write_realtime */ PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; int i; int bits; pm_hosterror = FALSE; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.output) err = pmBadPtr; else err = pmNoError; if (err != pmNoError) goto pm_write_error; if (midi->latency == 0) { midi->now = 0; } else { midi->now = (*(midi->time_proc))(midi->time_info); if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) { /* time to resync */ midi->now = (*midi->dictionary->synchronize)(midi); midi->first_message = FALSE; } } /* error recovery: when a sysex is detected, we call * dictionary->begin_sysex() followed by calls to * dictionary->write_byte() and dictionary->write_realtime() * until an end-of-sysex is detected, when we call * dictionary->end_sysex(). After an error occurs, * Pm_Write() continues to call functions. For example, * it will continue to call write_byte() even after * an error sending a sysex message, and end_sysex() will be * called when an EOX or non-real-time status is found. * When errors are detected, Pm_Write() returns immediately, * so it is possible that this will drop data and leave * sysex messages in a partially transmitted state. */ for (i = 0; i < length; i++) { uint32_t msg = buffer[i].message; bits = 0; /* is this a sysex message? */ if (Pm_MessageStatus(msg) == MIDI_SYSEX) { if (midi->sysex_in_progress) { /* error: previous sysex was not terminated by EOX */ midi->sysex_in_progress = FALSE; err = pmBadData; goto pm_write_error; } midi->sysex_in_progress = TRUE; if ((err = (*midi->dictionary->begin_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX, buffer[i].timestamp)) != pmNoError) goto pm_write_error; bits = 8; /* fall through to continue sysex processing */ } else if ((msg & MIDI_STATUS_MASK) && (Pm_MessageStatus(msg) != MIDI_EOX)) { /* a non-sysex message */ if (midi->sysex_in_progress) { /* this should be a realtime message */ if (is_real_time(msg)) { if ((err = (*midi->dictionary->write_realtime)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; } else { midi->sysex_in_progress = FALSE; err = pmBadData; /* ignore any error from this, because we already have one */ /* pass 0 as timestamp -- it's ignored */ (*midi->dictionary->end_sysex)(midi, 0); goto pm_write_error; } } else { /* regular short midi message */ if ((err = (*midi->dictionary->write_short)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; continue; } } if (midi->sysex_in_progress) { /* send sysex bytes until EOX */ /* see if we can accelerate data transfer */ if (bits == 0 && midi->fill_base && /* 4 bytes to copy */ (*midi->fill_offset_ptr) + 4 <= midi->fill_length && (msg & 0x80808080) == 0) { /* all data */ /* copy 4 bytes from msg to fill_base + fill_offset */ unsigned char *ptr = midi->fill_base + *(midi->fill_offset_ptr); ptr[0] = msg; ptr[1] = msg >> 8; ptr[2] = msg >> 16; ptr[3] = msg >> 24; (*midi->fill_offset_ptr) += 4; continue; } /* no acceleration, so do byte-by-byte copying */ while (bits < 32) { unsigned char midi_byte = (unsigned char) (msg >> bits); if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if (midi_byte == MIDI_EOX) { err = pm_end_sysex(midi); if (err != pmNoError) goto error_exit; break; /* from while loop */ } bits += 8; } } else { /* not in sysex mode, but message did not start with status */ err = pmBadData; goto pm_write_error; } } /* after all messages are processed, send the data */ if (!midi->sysex_in_progress) err = (*midi->dictionary->write_flush)(midi, 0); pm_write_error: if (err == pmHostError) { midi->dictionary->host_error(midi, pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); pm_hosterror = TRUE; } error_exit: return pm_errmsg(err); } PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when, PmMessage msg) { PmEvent event; event.timestamp = when; event.message = msg; return Pm_Write(stream, &event, 1); } PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when, unsigned char *msg) { /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */ /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */ #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage))) PmEvent buffer[BUFLEN]; int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */ PmInternal *midi = (PmInternal *) stream; /* the next byte in the buffer is represented by an index, bufx, and a shift in bits */ int shift = 0; int bufx = 0; buffer[0].message = 0; buffer[0].timestamp = when; while (1) { /* insert next byte into buffer */ buffer[bufx].message |= ((*msg) << shift); shift += 8; if (*msg++ == MIDI_EOX) break; if (shift == 32) { shift = 0; bufx++; if (bufx == buffer_size) { PmError err = Pm_Write(stream, buffer, buffer_size); /* note: Pm_Write has already called errmsg() */ if (err) return err; /* prepare to fill another buffer */ bufx = 0; buffer_size = BUFLEN; /* optimization: maybe we can just copy bytes */ if (midi->fill_base) { PmError err; while (*(midi->fill_offset_ptr) < midi->fill_length) { midi->fill_base[(*midi->fill_offset_ptr)++] = *msg; if (*msg++ == MIDI_EOX) { err = pm_end_sysex(midi); if (err != pmNoError) return pm_errmsg(err); goto end_of_sysex; } } /* I thought that I could do a pm_Write here and * change this if to a loop, avoiding calls in Pm_Write * to the slower write_byte, but since * sysex_in_progress is true, this will not flush * the buffer, and we'll infinite loop: */ /* err = Pm_Write(stream, buffer, 0); if (err) return err; */ /* instead, the way this works is that Pm_Write calls * write_byte on 4 bytes. The first, since the buffer * is full, will flush the buffer and allocate a new * one. This primes the buffer so * that we can return to the loop above and fill it * efficiently without a lot of function calls. */ buffer_size = 1; /* get another message started */ } } buffer[bufx].message = 0; buffer[bufx].timestamp = when; } /* keep inserting bytes until you find MIDI_EOX */ } end_of_sysex: /* we're finished sending full buffers, but there may * be a partial one left. */ if (shift != 0) bufx++; /* add partial message to buffer len */ if (bufx) { /* bufx is number of PmEvents to send from buffer */ PmError err = Pm_Write(stream, buffer, bufx); if (err) return err; } return pmNoError; } PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream, PmDeviceID inputDevice, void *inputDriverInfo, int32_t bufferSize, PmTimeProcPtr time_proc, void *time_info) { PmInternal *midi; PmError err = pmNoError; pm_hosterror = FALSE; *stream = NULL; /* arg checking */ if (inputDevice < 0 || inputDevice >= pm_descriptor_index) err = pmInvalidDeviceId; else if (!descriptors[inputDevice].pub.input) err = pmInvalidDeviceId; else if(descriptors[inputDevice].pub.opened) err = pmInvalidDeviceId; if (err != pmNoError) goto error_return; /* create portMidi internal data */ midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); *stream = midi; if (!midi) { err = pmInsufficientMemory; goto error_return; } midi->device_id = inputDevice; midi->write_flag = FALSE; midi->time_proc = time_proc; midi->time_info = time_info; /* windows adds timestamps in the driver and these are more accurate than using a time_proc, so do not automatically provide a time proc. Non-win implementations may want to provide a default time_proc in their system-specific midi_out_open() method. */ if (bufferSize <= 0) bufferSize = 256; /* default buffer size */ midi->queue = Pm_QueueCreate(bufferSize, (int32_t) sizeof(PmEvent)); if (!midi->queue) { /* free portMidi data */ *stream = NULL; pm_free(midi); err = pmInsufficientMemory; goto error_return; } midi->buffer_len = bufferSize; /* portMidi input storage */ midi->latency = 0; /* not used */ midi->sysex_in_progress = FALSE; midi->sysex_message = 0; midi->sysex_message_count = 0; midi->filters = PM_FILT_ACTIVE; midi->channel_mask = 0xFFFF; midi->sync_time = 0; midi->first_message = TRUE; midi->dictionary = descriptors[inputDevice].dictionary; midi->fill_base = NULL; midi->fill_offset_ptr = NULL; midi->fill_length = 0; descriptors[inputDevice].internalDescriptor = midi; /* open system dependent input device */ err = (*midi->dictionary->open)(midi, inputDriverInfo); if (err) { *stream = NULL; descriptors[inputDevice].internalDescriptor = NULL; /* free portMidi data */ Pm_QueueDestroy(midi->queue); pm_free(midi); } else { /* portMidi input open successful */ descriptors[inputDevice].pub.opened = TRUE; } error_return: /* note: if there is a pmHostError, it is the responsibility * of the system-dependent code (*midi->dictionary->open)() * to set pm_hosterror and pm_hosterror_text */ return pm_errmsg(err); } PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream, PmDeviceID outputDevice, void *outputDriverInfo, int32_t bufferSize, PmTimeProcPtr time_proc, void *time_info, int32_t latency ) { PmInternal *midi; PmError err = pmNoError; pm_hosterror = FALSE; *stream = NULL; /* arg checking */ if (outputDevice < 0 || outputDevice >= pm_descriptor_index) err = pmInvalidDeviceId; else if (!descriptors[outputDevice].pub.output) err = pmInvalidDeviceId; else if (descriptors[outputDevice].pub.opened) err = pmInvalidDeviceId; if (err != pmNoError) goto error_return; /* create portMidi internal data */ midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); *stream = midi; if (!midi) { err = pmInsufficientMemory; goto error_return; } midi->device_id = outputDevice; midi->write_flag = TRUE; midi->time_proc = time_proc; /* if latency > 0, we need a time reference. If none is provided, use PortTime library */ if (time_proc == NULL && latency != 0) { if (!Pt_Started()) Pt_Start(1, 0, 0); /* time_get does not take a parameter, so coerce */ midi->time_proc = (PmTimeProcPtr) Pt_Time; } midi->time_info = time_info; midi->buffer_len = bufferSize; midi->queue = NULL; /* unused by output */ /* if latency zero, output immediate (timestamps ignored) */ /* if latency < 0, use 0 but don't return an error */ if (latency < 0) latency = 0; midi->latency = latency; midi->sysex_in_progress = FALSE; midi->sysex_message = 0; /* unused by output */ midi->sysex_message_count = 0; /* unused by output */ midi->filters = 0; /* not used for output */ midi->channel_mask = 0xFFFF; midi->sync_time = 0; midi->first_message = TRUE; midi->dictionary = descriptors[outputDevice].dictionary; midi->fill_base = NULL; midi->fill_offset_ptr = NULL; midi->fill_length = 0; descriptors[outputDevice].internalDescriptor = midi; /* open system dependent output device */ err = (*midi->dictionary->open)(midi, outputDriverInfo); if (err) { *stream = NULL; descriptors[outputDevice].internalDescriptor = NULL; /* free portMidi data */ pm_free(midi); } else { /* portMidi input open successful */ descriptors[outputDevice].pub.opened = TRUE; } error_return: /* note: system-dependent code must set pm_hosterror and * pm_hosterror_text if a pmHostError occurs */ return pm_errmsg(err); } PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; if (midi == NULL) err = pmBadPtr; else midi->channel_mask = mask; return pm_errmsg(err); } PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; /* arg checking */ if (midi == NULL) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else midi->filters = filters; return pm_errmsg(err); } PMEXPORT PmError Pm_Close( PortMidiStream *stream ) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; pm_hosterror = FALSE; /* arg checking */ if (midi == NULL) /* midi must point to something */ err = pmBadPtr; /* if it is an open device, the device_id will be valid */ else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index) err = pmBadPtr; /* and the device should be in the opened state */ else if (!descriptors[midi->device_id].pub.opened) err = pmBadPtr; if (err != pmNoError) goto error_return; /* close the device */ err = (*midi->dictionary->close)(midi); /* even if an error occurred, continue with cleanup */ descriptors[midi->device_id].internalDescriptor = NULL; descriptors[midi->device_id].pub.opened = FALSE; if (midi->queue) Pm_QueueDestroy(midi->queue); pm_free(midi); error_return: /* system dependent code must set pm_hosterror and * pm_hosterror_text if a pmHostError occurs. */ return pm_errmsg(err); } PmError Pm_Synchronize( PortMidiStream* stream ) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; if (midi == NULL) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.output) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else midi->first_message = TRUE; return err; } PMEXPORT PmError Pm_Abort( PortMidiStream* stream ) { PmInternal *midi = (PmInternal *) stream; PmError err; /* arg checking */ if (midi == NULL) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.output) err = pmBadPtr; else if (!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else err = (*midi->dictionary->abort)(midi); if (err == pmHostError) { midi->dictionary->host_error(midi, pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); pm_hosterror = TRUE; } return pm_errmsg(err); } /* pm_channel_filtered returns non-zero if the channel mask is blocking the current channel */ #define pm_channel_filtered(status, mask) \ ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask)))) /* The following two functions will checks to see if a MIDI message matches the filtering criteria. Since the sysex routines only want to filter realtime messages, we need to have separate routines. */ /* pm_realtime_filtered returns non-zero if the filter will kill the current message. Note that only realtime messages are checked here. */ #define pm_realtime_filtered(status, filters) \ ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters))) /* return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE)) || ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK)) || ((status == MIDI_START) && (filters & PM_FILT_PLAY)) || ((status == MIDI_STOP) && (filters & PM_FILT_PLAY)) || ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY)) || ((status == MIDI_F9) && (filters & PM_FILT_F9)) || ((status == MIDI_FD) && (filters & PM_FILT_FD)) || ((status == MIDI_RESET) && (filters & PM_FILT_RESET)) || ((status == MIDI_MTC) && (filters & PM_FILT_MTC)) || ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION)) || ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT)) || ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE)); }*/ /* pm_status_filtered returns non-zero if a filter will kill the current message, based on status. Note that sysex and real time are not checked. It is up to the subsystem (winmm, core midi, alsa) to filter sysex, as it is handled more easily and efficiently at that level. Realtime message are filtered in pm_realtime_filtered. */ #define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters)) /* return ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE)) || ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE)) || ((status == MIDI_CHANNEL_AT) && (filters & PM_FILT_CHANNEL_AFTERTOUCH)) || ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH)) || ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM)) || ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL)) || ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND)); } */ static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp) { PmEvent event; /* there may be nothing in the buffer */ if (midi->sysex_message_count == 0) return; /* nothing to flush */ event.message = midi->sysex_message; event.timestamp = timestamp; /* copied from pm_read_short, avoids filtering */ if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) { midi->sysex_in_progress = FALSE; } midi->sysex_message_count = 0; midi->sysex_message = 0; } /* pm_read_short and pm_read_bytes are the interface between system-dependent MIDI input handlers and the system-independent PortMIDI code. The input handler MUST obey these rules: 1) all short input messages must be sent to pm_read_short, which enqueues them to a FIFO for the application. 2) each buffer of sysex bytes should be reported by calling pm_read_bytes (which sets midi->sysex_in_progress). After the eox byte, pm_read_bytes will clear sysex_in_progress */ /* pm_read_short is the place where all input messages arrive from system-dependent code such as pmwinmm.c. Here, the messages are entered into the PortMidi input buffer. */ void pm_read_short(PmInternal *midi, PmEvent *event) { int status; /* arg checking */ assert(midi != NULL); /* midi filtering is applied here */ status = Pm_MessageStatus(event->message); if (!pm_status_filtered(status, midi->filters) && (!is_real_time(status) || !pm_realtime_filtered(status, midi->filters)) && !pm_channel_filtered(status, midi->channel_mask)) { /* if sysex is in progress and we get a status byte, it had better be a realtime message or the starting SYSEX byte; otherwise, we exit the sysex_in_progress state */ if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) { /* two choices: real-time or not. If it's real-time, then * this should be delivered as a sysex byte because it is * embedded in a sysex message */ if (is_real_time(status)) { midi->sysex_message |= (status << (8 * midi->sysex_message_count++)); if (midi->sysex_message_count == 4) { pm_flush_sysex(midi, event->timestamp); } } else { /* otherwise, it's not real-time. This interrupts * a sysex message in progress */ midi->sysex_in_progress = FALSE; } } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) { midi->sysex_in_progress = FALSE; } } } /* pm_read_bytes -- read one (partial) sysex msg from MIDI data */ /* * returns how many bytes processed */ unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data, int len, PmTimestamp timestamp) { int i = 0; /* index into data, must not be unsigned (!) */ PmEvent event; event.timestamp = timestamp; assert(midi); /* note that since buffers may not have multiples of 4 bytes, * pm_read_bytes may be called in the middle of an outgoing * 4-byte PortMidi message. sysex_in_progress indicates that * a sysex has been sent but no eox. */ if (len == 0) return 0; /* sanity check */ if (!midi->sysex_in_progress) { while (i < len) { /* process all data */ unsigned char byte = data[i++]; if (byte == MIDI_SYSEX && !pm_realtime_filtered(byte, midi->filters)) { midi->sysex_in_progress = TRUE; i--; /* back up so code below will get SYSEX byte */ break; /* continue looping below to process msg */ } else if (byte == MIDI_EOX) { midi->sysex_in_progress = FALSE; return i; /* done with one message */ } else if (byte & MIDI_STATUS_MASK) { /* We're getting MIDI but no sysex in progress. * Either the SYSEX status byte was dropped or * the message was filtered. Drop the data, but * send any embedded realtime bytes. */ /* assume that this is a real-time message: * it is an error to pass non-real-time messages * to pm_read_bytes */ event.message = byte; pm_read_short(midi, &event); } } /* all bytes in the buffer are processed */ } /* Now, isysex_in_progress) { if (midi->sysex_message_count == 0 && i <= len - 4 && ((event.message = (((PmMessage) data[i]) | (((PmMessage) data[i+1]) << 8) | (((PmMessage) data[i+2]) << 16) | (((PmMessage) data[i+3]) << 24))) & 0x80808080) == 0) { /* all data, no status */ if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) { midi->sysex_in_progress = FALSE; } i += 4; } else { while (i < len) { /* send one byte at a time */ unsigned char byte = data[i++]; if (is_real_time(byte) && pm_realtime_filtered(byte, midi->filters)) { continue; /* real-time data is filtered, so omit */ } midi->sysex_message |= (byte << (8 * midi->sysex_message_count++)); if (byte == MIDI_EOX) { midi->sysex_in_progress = FALSE; pm_flush_sysex(midi, event.timestamp); return i; } else if (midi->sysex_message_count == 4) { pm_flush_sysex(midi, event.timestamp); /* after handling at least one non-data byte * and reaching a 4-byte message boundary, * resume trying to send 4 at a time in outer loop */ break; } } } } return i; } portmidi/portmusic_logo.png0000644000000000000000000000136110552167136015165 0ustar rootrootPNG  IHDRXTgAMA7tEXtSoftwareAdobe ImageReadyqe<0PLTẺgk5FH'*uUUU䁐>GIDATx̖ Ey%o&]STH&2c/5ӗ6~~6$=OuWivκ򎫪+u'㋔hZP0#:7lXd\`RȖغS0!  .:)oT'k ޺*vv0iVjOEri(Q}8CРBH1"Xcd8x+p & yrE1+':<]$FW5rXd?O`e*/cݬs[$84FćwR5 \tPx\7q KWp`!EN_c)+hI-lX|V'0I}IENDB`portmidi/pm_cl/0000755000000000000000000000000011453601074012476 5ustar rootrootportmidi/pm_cl/cffi-portmidi.lisp0000644000000000000000000003150611436265364016141 0ustar rootroot;;; ********************************************************************** ;;; Copyright (C) 2005 Heinrich Taube, ;;; ;;; This program is free software; you can redistribute it and/or ;;; modify it under the terms of the Lisp Lesser Gnu Public License. ;;; See http://www.cliki.net/LLGPL for the text of this agreement. ;;; ********************************************************************** ;;; A CFFI interface to Portmidi. Should run in most Common Lisp ;;; implementations on Linux, OS X and Windows. For information about ;;; CFFI see http://common-lisp.net/project/cffi/ (in-package :cl-user) (defvar *libportmidi* (let ((type #+(or darwin macos macosx) "dylib" #+(or linux linux-target (and unix pc386) freebsd) "so" #+(or win32 microsoft-32 cygwin) "dll") (paths (list "/usr/lib/" "/usr/local/lib/" *load-pathname*))) (loop for d in paths for p = (make-pathname :name "libportmidi" :type type :defaults d) when (probe-file p) do (return p) finally (error "Library \"portmidi.~A\" not found. Fix *libportmidi*." type)))) ;;; linux: guess i need to load porttime.so first (?) osx doesnt seem ;;; to need this lib at all... #+(or linux (and clisp unix (not macos))) (let ((lpt (merge-pathnames "libporttime" *libportmidi*))) (if (probe-file lpt) (cffi:load-foreign-library lpt) (error "Porttime: ~a not found. Fix *libportmidi* path." lpt))) ;;; load portmidi lib (cffi:load-foreign-library *libportmidi*) (defpackage :portmidi (:use :common-lisp) (:nicknames :pm :pt) (:shadow :initialize :terminate :time :start :stop :abort :close :read :write :poll) (:export :Initialize :Terminate :HasHostError :GetErrorText :GetHostErrorText :CountDevices :GetDefaultInputDeviceID :GetDefaultOutputDeviceID :GetDeviceInfo :Message :Message.status :Message.data1 :Message.data2 :Event.message :Event.timestamp ;; event buffers added to api :EventBufferNew :EventBufferFree :EventBufferElt :EventBufferMap :OpenInput :OpenOutput :SetFilter :SetChannelMask :Abort :Close :Read :Write :Poll :WriteShort :WriteSysex ;; filtering constants :filt-active :filt-sysex :filt-clock :filt-play :filt-f9 :filt-fd :filt-reset :filt-note :filt-channel-aftertouch :filt-poly-aftertouch :filt-program :filt-control :filt-pitchbend :filt-mtc :filt-song-position :filt-song-select :filt-tune :filt-tick :filt-undefined :filt-realtime :filt-aftertouch :filt-systemcommon ;; porttime. :Start :Stop :Started :Time ;; initialization insurers added to api :portmidi :*portmidi* )) (in-package :portmidi) (cffi:defcstruct pm-device-info (struct-version :int) (interf :pointer) (name :pointer) (input :int) (output :int) (opened :int)) (cffi:define-foreign-type pm-message () ':long) (cffi:define-foreign-type pm-timestamp () ':long) (cffi:defcstruct pm-event (message pm-message) (timestamp pm-timestamp)) (cffi:define-foreign-type pm-error () ':int) (cffi:define-foreign-type port-midi-stream () ':void) (cffi:define-foreign-type pm-device-id () ':int) (cffi:define-foreign-type pm-time-proc-ptr () ':pointer) (cffi:defcfun ("Pm_WriteSysEx" pm-write-sys-ex) pm-error (stream :pointer) (when pm-timestamp) (msg :pointer)) (cffi:defcfun ("Pm_WriteShort" pm-write-short) pm-error (stream :pointer) (when pm-timestamp) (msg :long)) (cffi:defcfun ("Pm_Write" pm-write) pm-error (stream :pointer) (buffer :pointer) (length :long)) (cffi:defcfun ("Pm_Poll" pm-poll) pm-error (stream :pointer)) (cffi:defcfun ("Pm_Read" pm-read) pm-error (stream :pointer) (buffer :pointer) (length :long)) (cffi:defcfun ("Pm_Close" pm-close) pm-error (stream :pointer)) (cffi:defcfun ("Pm_Abort" pm-abort) pm-error (stream :pointer)) ;(cffi:defcfun ("Pm_SetChannelMask" pm-set-channel-mask) pm-error (stream :pointer) (mask :int)) (cffi:defcfun ("Pm_SetFilter" pm-set-filter) pm-error (stream :pointer) (filters :long)) (cffi:defcfun ("Pm_OpenOutput" pm-open-output) pm-error (stream :pointer) (output-device pm-device-id) (output-driver-info :pointer) (buffer-size :long) (time-proc pm-time-proc-ptr) (time-info :pointer) (latency :long)) (cffi:defcfun ("Pm_OpenInput" pm-open-input) pm-error (stream :pointer) (input-device pm-device-id) (input-driver-info :pointer) (buffer-size :long) (time-proc pm-time-proc-ptr) (time-info :pointer)) (cffi:defcfun ("Pm_GetDeviceInfo" pm-get-device-info) :pointer (id pm-device-id)) (cffi:defcfun ("Pm_GetDefaultOutputDeviceID" pm-get-default-output-device-id) pm-device-id) (cffi:defcfun ("Pm_GetDefaultInputDeviceID" pm-get-default-input-device-id) pm-device-id) (cffi:defcfun ("Pm_CountDevices" pm-count-devices) :int) (cffi:defcfun ("Pm_GetHostErrorText" pm-get-host-error-text) :void (msg :pointer) (len :unsigned-int)) (cffi:defcfun ("Pm_GetErrorText" pm-get-error-text) :pointer (errnum pm-error)) (cffi:defcfun ("Pm_HasHostError" pm-has-host-error) :int (stream :pointer)) (cffi:defcfun ("Pm_Terminate" pm-terminate) pm-error) (cffi:defcfun ("Pm_Initialize" pm-initialize) pm-error) ;;; porttime.h (cffi:define-foreign-type pt-error () ':int) (cffi:define-foreign-type pt-timestamp () ':long) (cffi:defcfun ("Pt_Start" pt-start) pt-error (a :int) (b :pointer) (c :pointer)) (cffi:defcfun ("Pt_Stop" pt-stop) pt-error ) (cffi:defcfun ("Pt_Started" pt-started) :int) (cffi:defcfun ("Pt_Time" pt-time) pt-timestamp) (defconstant true 1) (defconstant false 0) (defconstant pmNoError 0) (defconstant pmHostError -10000) (defconstant pm-no-device -1) (defconstant pm-default-sysex-buffer-size 1024) (defconstant filt-active 1) (defconstant filt-sysex 2) (defconstant filt-clock 4) (defconstant filt-play 8) (defconstant filt-f9 16) (defconstant filt-fd 32) (defconstant filt-reset 64) (defconstant filt-note 128) (defconstant filt-channel-aftertouch 256) (defconstant filt-poly-aftertouch 512) (defconstant filt-program 1024) (defconstant filt-control 2048) (defconstant filt-pitchbend 4096) (defconstant filt-mtc 8192) (defconstant filt-song-position 16384) (defconstant filt-song-select 32768) (defconstant filt-tune 65536) (defconstant filt-tick filt-f9) (defconstant filt-undefined (logior filt-f9 filt-fd)) (defconstant filt-realtime (logior filt-active filt-sysex filt-clock filt-play filt-undefined filt-reset)) (defconstant filt-aftertouch (logior filt-channel-aftertouch filt-poly-aftertouch )) (defconstant filt-systemcommon (logior filt-mtc filt-song-position filt-song-select filt-tune)) (defvar *portmidi* nil) ; t if loaded ;;; ;;; utils ;;; (defvar host-error-text (make-string 256 :initial-element #\*)) (defmacro with-pm-error (form) (let ((v (gensym))) `(let ((,v ,form)) (if (not (= ,v pmNoError)) (if (= ,v pmHostError) (cffi:with-foreign-string (host-error host-error-text) (pm-get-host-error-text host-error (length host-error-text)) (error "Host error is: ~a" (cffi:foreign-string-to-lisp host-error))) (error (cffi:foreign-string-to-lisp (pm-get-error-text ,v)))) ,v)))) (defun portmidi () ;; initializer, call before using lib (or *portmidi* (progn (pm-initialize) (setq *portmidi* t)))) (defun Message (status data1 data2) ;; portmidi messages are just unsigneds (logior (logand (ash data2 16) #xFF0000) (logand (ash data1 08) #xFF00) (logand status #xFF))) (defun Message.status (m) (logand m #xFF)) (defun Message.data1 (m) (logand (ash m -08) #xFF)) (defun Message.data2 (m) (logand (ash m -16) #xFF)) ;;; accessors (defun DeviceInfo.interf (ptr) (cffi:foreign-string-to-lisp (cffi:foreign-slot-value ptr 'pm-device-info 'interf))) (defun DeviceInfo.name (ptr) (cffi:foreign-string-to-lisp (cffi:foreign-slot-value ptr 'pm-device-info 'name))) (defun DeviceInfo.input (ptr) (if (= (cffi:foreign-slot-value ptr 'pm-device-info 'input) 0) nil t)) (defun DeviceInfo.output (ptr) (if (= (cffi:foreign-slot-value ptr 'pm-device-info 'output) 0) nil t)) (defun DeviceInfo.opened (ptr) (if (= (cffi:foreign-slot-value ptr 'pm-device-info 'opened) 0) nil t)) (defun Event.message (e &optional (v nil vp)) (if vp (progn (setf (cffi:foreign-slot-value e 'pm-event 'message) v) v) (cffi:foreign-slot-value e 'pm-event 'message))) (defun Event.timestamp (e &optional (v nil vp)) (if vp (progn (setf (cffi:foreign-slot-value e 'pm-event 'timestamp) v) v) (cffi:foreign-slot-value e 'pm-event 'timestamp))) ;;; functions (defun Initialize () (with-pm-error (pm-initialize))) (defun terminate () (with-pm-error (pm-terminate))) (defun HasHostError (pms) (pm-has-host-error pms)) (defun GetErrorText (err) (pm-get-error-text err)) ; how do i do this? ;(progn ; (defalien "pm-GetHostErrorText" void (a c-string) (b unsigned-int)) ; (defun GetHostErrorText () ; (pm-GetHostErrorText 256))) (defun CountDevices () (portmidi) (pm-count-devices )) (defun GetDefaultInputDeviceID () (let ((id (pm-get-default-input-device-id ))) (if (= id pm-no-device) nil id))) (defun GetDefaultOutputDeviceID () (let ((id (pm-get-default-output-device-id ))) (if (= id pm-no-device) nil id))) ;replaced by lispy version end of file. ;(defun GetDeviceInfo (id) (pm-get-device-info id)) (defun OpenInput (device bufsiz) ;; portmidi: timer must be running before opening (unless (Started) (Start)) (cffi:with-foreign-object (p1 :pointer) (let ((err (pm-open-input p1 device (cffi:null-pointer) bufsiz (cffi:null-pointer) (cffi:null-pointer)))) (if (= err pmNoError) (cffi:mem-ref p1 :pointer) (error (pm-get-error-text err)))))) (defun OpenOutput (device bufsiz latency) (unless (Started) (Start)) (cffi:with-foreign-object (p1 :pointer) ;(p (* PortMidi)) (let ((err (pm-open-output p1 device (cffi:null-pointer) bufsiz (cffi:null-pointer) (cffi:null-pointer) latency))) (if (= err pmNoError) (cffi:mem-ref p1 :pointer) (error (pm-get-error-text err)))))) (defun SetFilter (a filts) (with-pm-error (pm-set-filter a filts))) ;(defun SetChannelMask (pms mask) ; (with-pm-error (pm-set-channel-mask pms mask))) (defun Abort (pms) (with-pm-error (pm-abort pms))) (defun Close (pms) (with-pm-error (pm-close pms))) (defun EventBufferFree (buf) (cffi:foreign-free buf)) (defun EventBufferNew (len) (cffi:foreign-alloc 'pm-event :count len)) (defun EventBufferElt (buf i) ;; buf is POINTER to buf (cffi:mem-aref buf 'pm-event i)) (defun EventBufferSet (buffer index timestamp message) (setf (cffi:foreign-slot-value (cffi:mem-aref buffer 'pm-event index) 'pm-event 'timestamp) timestamp) (setf (cffi:foreign-slot-value (cffi:mem-aref buffer 'pm-event index) 'pm-event 'message) message) (values)) (defun EventBufferMap (fn buf end) (loop for i below end for e = (EventBufferElt buf i) do (funcall fn (Event.message e) (Event.timestamp e))) (values)) (defun Read (pms *evbuf len) (let ((res (pm-read pms *evbuf len))) (if (< res 0) (error (pm-get-error-text res)) res))) (defun Poll (pms) (let ((res (pm-poll pms))) (cond ((= res 0) nil) ((= res 1) t) (t (error (pm-get-error-text res)))))) (defun Write (pms *evbuf len) (with-pm-error (pm-write pms *evbuf len))) (defun WriteShort (pms when msg) (with-pm-error (pm-write-short pms when msg))) (defun WriteSysex (pms when string) (cffi:with-foreign-string (ptr string) (with-pm-error (pm-write-sys-ex pms when ptr)))) ;;; porttime.h (defun Started () (let ((res (pt-started))) (if (= res false) nil t))) (defun Start () ;; NB: This has to be called before opening output or input. ;; it seems that if its called 2x we get an error. (unless (Started) (with-pm-error (pt-start 1 (cffi:null-pointer) (cffi:null-pointer)))) (values)) (defun Stop () (when (Started) (with-pm-error (pt-stop))) (values)) (defun Time () (pt-time)) (defun GetDeviceInfo (&optional id) (flet ((getone (id) (let ((d (pm-get-device-info id))) (list :id id :name (DeviceInfo.name d) :type (if (DeviceInfo.input d) ':input ':output) :open (DeviceInfo.opened d))))) ;; make sure lib is initialized before checking devices (portmidi) (if id (getone id) (loop for i below (CountDevices) collect (getone i))))) (pushnew ':portmidi *features*) portmidi/pm_cl/test-no-cm.lisp0000644000000000000000000000640310553302636015362 0ustar rootroot;; this is a half-baked sequence of PortMidi calls to test the interface ;; No calls to Common Music are made, hence test-no-cm.lisp ; setup cffi if it has not been done already (if (not (boundp '*clpath*)) (load "setup-pm.lisp")) (defun println (s) (print s) (terpri)) ;; initialize portmidi lib (pm:portmidi) ;; timer testing (pt:Start ) (pt:Started) (format t "time is ~A, type something~%" (pt:Time)) (read) (format t "time is ~A, type something~%" (pt:Time)) (read) (pt:Time) (format t "time is ~A, type something~%" (pt:Time)) ;; device testing (pm:CountDevices) (pprint (pm:GetDeviceInfo )) (defparameter inid (pm:GetDefaultInputDeviceID )) (pm:GetDeviceInfo inid) (defparameter outid (pm:GetDefaultOutputDeviceID )) (pm:GetDeviceInfo outid) ;; output testing (defparameter outid 4) ; 4 = my SimpleSynth (defparameter outdev (pm:OpenOutput outid 100 1000)) (pm:getDeviceInfo outid) ; :OPEN should be T ;; message tests (defun pm (m &optional (s t)) (format s "#" (ash (logand (pm:Message.status m) #xf0) -4) (logand (pm:Message.status m) #x0f) (pm:Message.data1 m) (pm:Message.data2 m))) (defparameter on (pm:message #b10010000 60 64)) (terpri) (pm on) (pm:Message.status on) (logand (ash (pm:Message.status on) -4) #x0f) (pm:Message.data1 on) (pm:Message.data2 on) (pm:WriteShort outdev (+ (pm:time) 100) on) (defparameter off (pm:message #b10000000 60 64)) (terpri) (pm off) (terpri) (println "type something for note off") (read) (pm:WriteShort outdev (+ (pm:time) 100) off) (println "type something to close output device") (read) (pm:Close outdev) ;; event buffer testing (defparameter buff (pm:EventBufferNew 8)) (loop for i below 8 for x = (pm:EventBufferElt buff i) ;; set buffer events do (pm:Event.message x (pm:message #b1001000 (+ 60 i) (+ 100 i))) (pm:Event.timestamp x (* 1000 i))) (loop for i below 8 for x = (pm:EventBufferElt buff i) ;; check buffer contents collect (list (pm:Event.timestamp x) (pm:Message.data1 (pm:Event.message x)) (pm:Message.data2 (pm:Event.message x)))) (pm:EventBufferFree buff) ;; input testing -- requires external midi keyboard (println (pm:GetDeviceInfo )) (defparameter inid 1) ; 1 = my external keyboard (defparameter indev (pm:OpenInput inid 256)) (pm:GetDeviceInfo inid) ; :OPEN should be T (pm:SetFilter indev pm:filt-realtime) ; ignore active sensing etc. (println "poll says:") (println (pm:Poll indev)) (println "play midi keyboard and type something") (read) ;; ;; ...play midi keyboard, then ... ;; (println "poll says") (println (pm:Poll indev)) (defparameter buff (pm:EventBufferNew 32)) (defparameter num (pm:Read indev buff 32)) (println "pm:Read gets") (println num) (println "input messages:") (pm:EventBufferMap (lambda (a b) b (terpri) (pm a)) buff num) (pm:Poll indev) (println "play keyboard, to stop, play middle-C") ;;; recv testing (defparameter pitch 0) (loop while (/= pitch 60) do (let ((n (pm:Read indev buff 1))) (cond ((= n 1) (pm:EventBufferMap (lambda (a b) b (pm a) (terpri) (setf pitch (pm:Message.data1 a))) buff n))))) (pm:EventBufferFree buff) (pm:Close indev) portmidi/pm_cl/README_CL.txt0000644000000000000000000000676010553302636014565 0ustar rootrootREADME_CL.txt for PortMidi Roger B. Dannenberg 17 Jan 2007 This is a Common Lisp interface to PortMidi. On Mac OSX, you need to build PortMidi as a dynamic link library before you can use PortMidi from Common Lisp. You can build PortMidi as a dynamic link library by running this: cd portmidi make -F pm_mac/Makefile.osx install-with-xcode This is just a shortcut for: cd portmidi/pm_mac sudo xcodebuild -project pm_mac.xcodeproj -configuration Deployment install DSTROOT=/ You can check the file and the architecture for which it is built using: file /usr/local/lib/libportmidi.dylib If you've done this install of portmidi, then you should also have /usr/local/include/portmidi.h This will be necessary to successfully build the cffi interface below. To test PortMidi with Common Lisp, I (RBD) am using SBCL, which I downloaded from http://prdownloads.sourceforge.net/sbcl. Currently, I use sbcl-0.9.17-x86-darwin-binary.tar.bz2 To install this, I unpacked it by just double-clicking in the finder. Then, from a command window, I became root using "sudo sh", and then typed: # INSTALL_ROOT=/usr/local # sh install.sh # exit I also downloaded cffi-061012.tar.gz from http://common-lisp.net/project/cffi/tarballs/?M=D To compile cffi, use the following, where "/Lisp/cffi/" is replaced by the actual directory of cffi, e.g. "/Users/rbd/sbcl-0.9.17-x86-darwin/cffi-061012": % sbcl * (require 'asdf) * (push "/Lisp/cffi/" asdf:*central-registry*) * (asdf:oos 'asdf:load-op :cffi) * (quit) Download Common Music's portmidi module from cvs and build the c side: (Replace "/Lisp" with your lisp directory, e.g. "/Users/rbd/sbcl-0.9.17-x86-darwin". These cvs commands will create a new directory, portmidi.) % cd /Lisp % export CVSROOT=:pserver:anonymous@commonmusic.cvs.sourceforge.net:/cvsroot/commonmusic % cvs login # press Return at password prompt % cvs checkout portmidi % cd portmidi % ./configure % make % cd .. Now compile/load the portmidi module just like cffi. Again, change "/Lisp/cffi/" and "/Lisp/portmidi" to correspond to your local file system. (Note that /Lisp becomes your lisp directory, and "cffi" becomes your cffi folder name, e.g. "cffi-061012". % sbcl * (require 'asdf) * (push "/Lisp/cffi/" asdf:*central-registry*) * (asdf:oos 'asdf:load-op :cffi) * (push "/Lisp/portmidi/" asdf:*central-registry*) * (asdf:oos 'asdf:load-op :portmidi) Look in the file /Lisp/portmidi/test.lisp for a test of the lisp interface to portmidi. For example, while still running sbcl: * (pm:portmidi) ; initialize portmidi * (pt:start) ; start time * (pt:time) ; get time * (pprint (pm:GetDeviceInfo)) ; get list of devices ((:ID 0 :NAME "IAC Driver Bus 1" :TYPE :INPUT :OPEN NIL) (:ID 1 :NAME "IAC Driver Bus 1" :TYPE :OUTPUT :OPEN NIL)) Notice that test.lisp assumes MIDI input devices are connected and uses some hard-wired device numbers, so it may not run as is without error. Since test.lisp uses some Common Music calls, I (RBD) wrote a simpler test, test-no-cm.lisp, which is in the same folder as this (README_CL.txt) file. To use it, first check that the values for outid (4) and inid (1) actually match PortMidi device id's for output and input devices, and make sure the input device is a keyboard that can generate a middle-C -- otherwise the program will hang waiting for input. Run sbcl from this pm_cl folder, and type: (load "test-no-cm.lisp") The program pauses frequently by calling (READ), so you should type t or something, then to continue. (Thanks to Leigh Smith and Rick Taube) portmidi/README.txt0000755000000000000000000000721411257441130013106 0ustar rootrootREADME for PortMidi Roger B. Dannenberg VERSION: please use "svn info" to get info. Documentation for PortMidi is found in pm_common/portmidi.h. Additional documentation: - Windows: see pm_win/README_WIN.txt and pm_win/debugging_dlls.txt - Linux: see pm_linux/README_LINUX.txt - Mac OSX: see pm_mac/README_MAC.txt - Common Lisp: see pm_cl/README_CL.txt - Eclipse: see portmidi_cdt.zip (this was contributed as is; the dlls here are now -- Sep 09 -- out of date. What is really needed is a script to generate this release automatically so we can maintain it.) - C-Sharp: see pm_csharp.zip (also contributed as is) ---------- some notes on the design of PortMidi ---------- POINTERS VS DEVICE NUMBERS When you open a MIDI port, PortMidi allocates a structure to maintain the state of the open device. Since every device is also listed in a table, you might think it would be simpler to use the table index rather than a pointer to identify a device. This would also help with error checking (it's hard to make sure a pointer is valid). PortMidi's design parallels that of PortAudio. ERROR HANDLING Error handling turned out to be much more complicated than expected. PortMidi functions return error codes that the caller can check. In addition, errors may occur asynchronously due to MIDI input. However, for Windows, there are virtually no errors that can occur if the code is correct and not passing bogus values. One exception is an error that the system is out of memory, but my guess is that one is unlikely to recover gracefully from that. Therefore, all errors in callbacks are guarded by assert(), which means not guarded at all in release configurations. Ordinarily, the caller checks for an error code. If the error is system-dependent, pmHostError is returned and the caller can call Pm_GetHostErrorText to get a text description of the error. Host error codes are system-specific and are recorded in the system-specific data allocated for each open MIDI port. However, if an error occurs on open or close, we cannot store the error with the device because there will be no device data (assuming PortMidi cleans up after devices that are not open). For open and close, we will convert the error to text, copy it to a global string, and set pm_hosterror, a global flag. Similarly, whenever a Read or Write operation returns pmHostError, the corresponding error string is copied to a global string and pm_hosterror is set. This makes getting error strings simple and uniform, although it does cost a string copy and some overhead even if the user does not want to look at the error data. The system-specific Read, Write, Poll, etc. implementations should check for asynchronous errors and return immediately if one is found so that these get reported. This happens in the Mac OS X code, where lots of things are happening in callbacks, but again, in Windows, there are no error codes recorded in callbacks. DEBUGGING If you are building a console application for research, we suggest compiling with the option PM_CHECK_ERRORS. This will insert a check for error return values at the end of each PortMidi function. If an error is encountered, a text message is printed using printf(), the user is asked to type ENTER, and then exit(-1) is called to clean up and terminate the program. You should not use PM_CHECK_ERRORS if printf() does not work (e.g. this is not a console application under Windows, or there is no visible console on some other OS), and you should not use PM_CHECK_ERRORS if you intend to recover from errors rather than abruptly terminate the program. The Windows version (and perhaps others) also offers a DEBUG compile-time option. See README_WIN.txt. portmidi/portmidi.sln0000755000000000000000000002267711274243554014000 0ustar rootrootMicrosoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ALL_BUILD", ".\ALL_BUILD.vcproj", "{E1C2664B-91BB-4D4F-868C-433164F81101}" ProjectSection(ProjectDependencies) = postProject {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} {41D78CBF-B04B-4561-BA4A-AC238C40633D} = {41D78CBF-B04B-4561-BA4A-AC238C40633D} {9B448D22-EC7E-4BD8-A552-B268D843CC3C} = {9B448D22-EC7E-4BD8-A552-B268D843CC3C} {EED7440D-04E3-4948-92DB-C85B4ADB1D82} = {EED7440D-04E3-4948-92DB-C85B4ADB1D82} {80193DD1-2C02-4A4C-BDF8-49623AD6F556} = {80193DD1-2C02-4A4C-BDF8-49623AD6F556} {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF} = {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF} {87B548BD-F5CE-4D1F-9181-390966AC5855} = {87B548BD-F5CE-4D1F-9181-390966AC5855} {7283FAD1-7415-4061-A19A-FF5C7BCE9306} = {7283FAD1-7415-4061-A19A-FF5C7BCE9306} {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1} = {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1} {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD} = {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD} {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A} = {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", ".\ZERO_CHECK.vcproj", "{28779535-7541-4FF5-AC12-FAFD66E894EC}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "latency", "pm_test\latency.vcproj", "{41D78CBF-B04B-4561-BA4A-AC238C40633D}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midiclock", "pm_test\midiclock.vcproj", "{9B448D22-EC7E-4BD8-A552-B268D843CC3C}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midithread", "pm_test\midithread.vcproj", "{EED7440D-04E3-4948-92DB-C85B4ADB1D82}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midithru", "pm_test\midithru.vcproj", "{80193DD1-2C02-4A4C-BDF8-49623AD6F556}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mm", "pm_test\mm.vcproj", "{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmjni", "pm_common\pmjni.vcproj", "{87B548BD-F5CE-4D1F-9181-390966AC5855}" ProjectSection(ProjectDependencies) = postProject {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi-dynamic", "pm_dylib\portmidi-dynamic.vcproj", "{7283FAD1-7415-4061-A19A-FF5C7BCE9306}" ProjectSection(ProjectDependencies) = postProject {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi-static", "pm_common\portmidi-static.vcproj", "{2985D5DA-D91E-44E0-924B-E612B6AA33F6}" ProjectSection(ProjectDependencies) = postProject {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtest", "pm_test\qtest.vcproj", "{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sysex", "pm_test\sysex.vcproj", "{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "pm_test\test.vcproj", "{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}" ProjectSection(ProjectDependencies) = postProject {2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6} {28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E1C2664B-91BB-4D4F-868C-433164F81101}.Debug|Win32.ActiveCfg = Debug|Win32 {E1C2664B-91BB-4D4F-868C-433164F81101}.Release|Win32.ActiveCfg = Release|Win32 {28779535-7541-4FF5-AC12-FAFD66E894EC}.Debug|Win32.ActiveCfg = Debug|Win32 {28779535-7541-4FF5-AC12-FAFD66E894EC}.Debug|Win32.Build.0 = Debug|Win32 {28779535-7541-4FF5-AC12-FAFD66E894EC}.Release|Win32.ActiveCfg = Release|Win32 {28779535-7541-4FF5-AC12-FAFD66E894EC}.Release|Win32.Build.0 = Release|Win32 {41D78CBF-B04B-4561-BA4A-AC238C40633D}.Debug|Win32.ActiveCfg = Debug|Win32 {41D78CBF-B04B-4561-BA4A-AC238C40633D}.Debug|Win32.Build.0 = Debug|Win32 {41D78CBF-B04B-4561-BA4A-AC238C40633D}.Release|Win32.ActiveCfg = Release|Win32 {41D78CBF-B04B-4561-BA4A-AC238C40633D}.Release|Win32.Build.0 = Release|Win32 {9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Debug|Win32.ActiveCfg = Debug|Win32 {9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Debug|Win32.Build.0 = Debug|Win32 {9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Release|Win32.ActiveCfg = Release|Win32 {9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Release|Win32.Build.0 = Release|Win32 {EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Debug|Win32.ActiveCfg = Debug|Win32 {EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Debug|Win32.Build.0 = Debug|Win32 {EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Release|Win32.ActiveCfg = Release|Win32 {EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Release|Win32.Build.0 = Release|Win32 {80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Debug|Win32.ActiveCfg = Debug|Win32 {80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Debug|Win32.Build.0 = Debug|Win32 {80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Release|Win32.ActiveCfg = Release|Win32 {80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Release|Win32.Build.0 = Release|Win32 {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Debug|Win32.ActiveCfg = Debug|Win32 {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Debug|Win32.Build.0 = Debug|Win32 {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Release|Win32.ActiveCfg = Release|Win32 {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Release|Win32.Build.0 = Release|Win32 {87B548BD-F5CE-4D1F-9181-390966AC5855}.Debug|Win32.ActiveCfg = Debug|Win32 {87B548BD-F5CE-4D1F-9181-390966AC5855}.Debug|Win32.Build.0 = Debug|Win32 {87B548BD-F5CE-4D1F-9181-390966AC5855}.Release|Win32.ActiveCfg = Release|Win32 {87B548BD-F5CE-4D1F-9181-390966AC5855}.Release|Win32.Build.0 = Release|Win32 {7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Debug|Win32.ActiveCfg = Debug|Win32 {7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Debug|Win32.Build.0 = Debug|Win32 {7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Release|Win32.ActiveCfg = Release|Win32 {7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Release|Win32.Build.0 = Release|Win32 {2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Debug|Win32.ActiveCfg = Debug|Win32 {2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Debug|Win32.Build.0 = Debug|Win32 {2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Release|Win32.ActiveCfg = Release|Win32 {2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Release|Win32.Build.0 = Release|Win32 {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Debug|Win32.ActiveCfg = Debug|Win32 {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Debug|Win32.Build.0 = Debug|Win32 {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Release|Win32.ActiveCfg = Release|Win32 {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Release|Win32.Build.0 = Release|Win32 {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Debug|Win32.ActiveCfg = Debug|Win32 {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Debug|Win32.Build.0 = Debug|Win32 {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Release|Win32.ActiveCfg = Release|Win32 {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Release|Win32.Build.0 = Release|Win32 {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Debug|Win32.ActiveCfg = Debug|Win32 {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Debug|Win32.Build.0 = Debug|Win32 {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Release|Win32.ActiveCfg = Release|Win32 {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal portmidi/ALL_BUILD.vcproj0000644000000000000000000000676311274243554014202 0ustar rootroot portmidi/pm_mingw/0000755000000000000000000000000011453601074013221 5ustar rootrootportmidi/pm_mingw/msys/0000755000000000000000000000000011453601074014214 5ustar rootrootportmidi/pm_mingw/msys/README-MSYS.txt0000644000000000000000000000025111445664134016510 0ustar rootrootOld code was removed from this directory because CMake provides an up-to-date way to use MinGW. See portmidi/pm_mingw/README-MINGW.txt. Roger Dannenberg 20-Sep-2010 portmidi/pm_mingw/eclipse/0000755000000000000000000000000011453601074014645 5ustar rootrootportmidi/pm_mingw/eclipse/dot-cproject0000644000000000000000000012605611076626502017203 0ustar rootroot portmidi/pm_mingw/eclipse/dot-project0000644000000000000000000000376211076626502017036 0ustar rootroot PortMidi org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.buildLocation ${workspace_loc:/PortMidi/Debug} org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.append_environment true ?name? org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.core.cnature portmidi/pm_mingw/eclipse/README.txt0000644000000000000000000000174211445664134016356 0ustar rootrootThese files, dot-cproject and dot-project, come from Philip Martin (posted on Media_api mailing list on September 3, 2008). He writes: "I do not have a makefile. I used Eclipse + CDT to build PortMidi using MinGw. ... The two files .project and .cproject I believe must be in the root of the portmidi tree to work with Eclipse. ... I have only compiled the relevant sources into one .dll here." The .project and .cproject files have been renamed to dot-project and dot-cproject here to make them more visible. To use them, you will need to rename them to .project and .cproject, and probably move them to the portmidi tree root. At this time, no one is actively maintaining Eclipse or MinGw versions of PortMidi, so these files may be out-of-date or have other problems. Feel free to submit updates or discuss the possibility of maintaining these or some equivalent files for MinGw. Update, 20 Sep 2010: CMake supports Code::Blocks in conjunction with MinGW. Roger Dannenberg 18-Oct-2008 portmidi/pm_mingw/README-MINGW.txt0000644000000000000000000000040311453557316015604 0ustar rootrootREADME-MINGW.txt -- note on MinGW and PortMidi Roger Dannenberg 20 Sep 2010 Fabian Rutte writes that CMake can build files for Code::Blocks under MinGW. I would guess that a simple Unix Makefile output from CMake would also work, but I haven't tested it. portmidi/Doxyfile0000644000000000000000000017152511127420662013125 0ustar rootroot# Doxyfile 1.5.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = PortMidi # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 2.2.x # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. # 1.5.7 #IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols # 1.5.7 # SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. # 1.5.7 # SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. # 1.5.7 # SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. # 1.5.7 # LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = \ pm_common/portmidi.h \ pm_common/portmidi.c \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h \ *.c # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = ./pm_test # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = *.cxx \ *.h \ *.H \ *.fl # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = Pm_ #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = YES # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. # 1.5.7 # CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. # 1.5.7 # GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. # 1.5.7 # QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # Qt Help Project / Namespace. # 1.5.7 # QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # Qt Help Project / Virtual Folders. # 1.5.7 # QHP_VIRTUAL_FOLDER = doc # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file . # 1.5.7 # QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 200 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. # 1.5.7 # FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = YES # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = FL_DOXYGEN \ HAVE_CAIRO \ HAVE_GL \ HAVE_GL_OVERLAY \ FL_EXPORT:= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. # 1.5.7 # DOT_FONTNAME = FreeSans # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. # 1.5.7 # DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO portmidi/pm_win/0000755000000000000000000000000011453601074012675 5ustar rootrootportmidi/pm_win/static.cmake0000644000000000000000000000115711445664134015201 0ustar rootroot# static.cmake -- change flags to link with static runtime libraries if(MSVC) foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif(${flag_var} MATCHES "/MD") endforeach(flag_var) message(STATUS "Note: overriding CMAKE_*_FLAGS_* to use Visual C static multithread library") endif(MSVC) portmidi/pm_win/clean_up_vcproj.bat0000644000000000000000000000471311274243554016551 0ustar rootroot@echo off rem Start this program in portmidi\pm_win cd ..\pm_common rename portmidi-static.vcproj portmidi-static.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. portmidi-static.vcproj-cmake > portmidi-static.vcproj del portmidi-static.vcproj-cmake echo portmidi-static rename pmjni.vcproj pmjni.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. pmjni.vcproj-cmake > pmjni.vcproj del pmjni.vcproj-cmake echo pmjni cd ../pm_dylib rename portmidi-dynamic.vcproj portmidi-dynamic.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. portmidi-dynamic.vcproj-cmake > portmidi-dynamic.vcproj del portmidi-dynamic.vcproj-cmake echo portmidi-dynamic cd ..\pm_test rename latency.vcproj latency.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. latency.vcproj-cmake > latency.vcproj del latency.vcproj-cmake echo latency rename midiclock.vcproj midiclock.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. midiclock.vcproj-cmake > midiclock.vcproj del midiclock.vcproj-cmake echo midiclock rename midithread.vcproj midithread.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. midithread.vcproj-cmake > midithread.vcproj del midithread.vcproj-cmake echo midithread rename midithru.vcproj midithru.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. midithru.vcproj-cmake > midithru.vcproj del midithru.vcproj-cmake echo midithru rename mm.vcproj mm.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. mm.vcproj-cmake > mm.vcproj del mm.vcproj-cmake echo mm rename qtest.vcproj qtest.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. qtest.vcproj-cmake > qtest.vcproj del qtest.vcproj-cmake echo qtest rename sysex.vcproj sysex.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. sysex.vcproj-cmake > sysex.vcproj del sysex.vcproj-cmake echo sysex rename test.vcproj test.vcproj-cmake gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. test.vcproj-cmake > test.vcproj del test.vcproj-cmake cd .. echo test rename ALL_BUILD.vcproj ALL_BUILD.vcproj-cmake gawk -f pm_win\clean_up_vcproj.awk -v base_relative=. ALL_BUILD.vcproj-cmake > ALL_BUILD.vcproj del ALL_BUILD.vcproj-cmake echo ALL_BUILD rename ZERO_CHECK.vcproj ZERO_CHECK.vcproj-cmake gawk -f pm_win\clean_up_vcproj.awk -v base_relative=. ZERO_CHECK.vcproj-cmake > ZERO_CHECK.vcproj del ZERO_CHECK.vcproj-cmake echo ZERO_CHECK cd pm_win portmidi/pm_win/clean_cmake.bat0000644000000000000000000000021111436265364015612 0ustar rootrootdel /Q ..\CMakeFiles del /Q ..\CMakeCache.txt del /Q ..\pm_test\CMakeFiles del /Q ..\pm_common\CMakeFiles del /Q ..\pm_dylib\CMakeFiles portmidi/pm_win/pmwinmm.h0000755000000000000000000000015310463413276014541 0ustar rootroot/* midiwin32.h -- system-specific definitions */ void pm_winmm_init( void ); void pm_winmm_term( void ); portmidi/pm_win/debugging_dlls.txt0000755000000000000000000001622010463413276016420 0ustar rootroot======================================================================================================================== Methods for Debugging DLLs ======================================================================================================================== If you have the source for both the DLL and the calling program, open the project for the calling executable file and debug the DLL from there. If you load a DLL dynamically, you must specify it in the Additional DLLs category of the Debug tab in the Project Settings dialog box. If you have the source for the DLL only, open the project that builds the DLL. Use the Debug tab in the Project Settings dialog box to specify the executable file that calls the DLL. You can also debug a DLL without a project. For example, maybe you just picked up a DLL and source code but you dont have an associated project or workspace. You can use the Open command on the File menu to select the .DLL file you want to debug. The debug information should be in either the .DLL or the related .PDB file. After Visual C++ opens the file, on the Build menu click Start Debug and Go to begin debugging. To debug a DLL using the project for the executable file From the Project menu, click Settings. The Project Settings dialog box appears. Choose the Debug tab. In the Category drop-down list box, select General. In the Program Arguments text box, type any command-line arguments required by the executable file. In the Category drop-down list box, select Additional DLLs. In the Local Name column, type the names of DLLs to debug. If you are debugging remotely, the Remote Name column appears. In this column, type the complete path for the remote module to map to the local module name. In the Preload column, select the check box if you want to load the module before debugging begins. Click OK to store the information in your project. From the Build menu, click Start Debug and Go to start the debugger. You can set breakpoints in the DLL or the calling program. You can open a source file for the DLL and set breakpoints in that file, even though it is not a part of the executable files project. To debug a DLL using the project for the DLL From the Project menu, click Settings. The Project Settings dialog box appears. Choose the Debug tab. In the Category drop-down list box, select General. In the Executable For Debug Session text box, type the name of the executable file that calls the DLL. In the Category list box, select Additional DLLs. In the Local Module Name column, type the name of the DLLs you want to debug. Click OK to store the information in your project. Set breakpoints as required in your DLL source files or on function symbols in the DLL. From the Build menu, click Start Debug and Go to start the debugger. To debug a DLL created with an external project From the Project menu, click Settings. The Project Settings dialog box appears. Choose the Debug tab. In the Category drop-down list box, select General. In the Executable For Debug Session text box, type the name of the DLL that your external makefile builds. Click OK to store the information in your project. Build a debug version of the DLL with symbolic debugging information, if you dont already have one. Follow one of the two procedures immediately preceding this one to debug the DLL. ======================================================================================================================== Why Dont My DLL Breakpoints Work? ======================================================================================================================== Some reasons why your breakpoints dont work as expected are listed here, along with solutions or work-arounds for each. If you follow the instructions in one topic and are still having breakpoint problems, look at some of the other topics. Often breakpoint problems result from a combination of conditions. You can't set a breakpoint in a source file when the corresponding symbolic information isn't loaded into memory by the debugger. You cannot set a breakpoint in any source file when the corresponding symbolic information will not be loaded into memory by the debugger. Symptoms include messages such as "the breakpoint cannot be set" or a simple, noninformational beep. When setting breakpoints before the code to be debugged has been started, the debugger uses a breakpoint list to keep track of how and where to set breakpoints. When you actually begin the debugging session, the debugger loads the symbolic information for all the code to be debugged and then walks through its breakpoint list, attempting to set the breakpoints. However, if one or more of the code modules have not been designated to the debugger, there will be no symbolic information for the debugger to use when walking through its breakpoint list. Situations where this is likely to occur include: Attempts to set breakpoints in a DLL before the call to LoadLibrary. Setting a breakpoint in an ActiveX server before the container has started the server. Other similar cases. To prevent this behavior in Visual C++, specify all additional DLLs and COM servers in the Additional DLLs field in the Debug/Options dialog box to notify the debugger that you want it to load symbolic debug information for additional .DLL files. When this has been done, breakpoints set in code that has not yet been loaded into memory will be "virtual" breakpoints. When the code is actually loaded into memory by the loader, these become physical breakpoints. Make sure that these additional debugging processes are not already running when you start your debugging session. The debugging process and these additional processes must be sychronized at the same beginning point to work correctly, hitting all breakpoints. Breakpoints are missed when more than one copy of a DLL is on your hard disk. Having more than one copy of a DLL on your hard drive, especially if it is in your Windows directory, can cause debugger confusion. The debugger will load the symbolic information for the DLL specified to it at run time (with the Additional DLLs field in the Debug/Options dialog box), while Windows has actually loaded a different copy of the DLL itself into memory. Because there is no way to force the debugger to load a specific DLL, it is a good idea to keep only one version of a DLL at a time in your path, current directory, and Windows directory. You cant set "Break When Expression Has Changed" breakpoints on a variable local to a DLL. Setting a "Break When Expression Has Changed" breakpoint on a variable local to a DLL function before the call to LoadLibrary causes the breakpoint to be virtual (there are no physical addresses for the DLL in memory yet). Virtual breakpoints involving expressions pose a special problem. The DLL must be specified to the debugger at startup (causing its symbolic information to be loaded). In addition, the DLL's executable code must also be loaded into memory before this kind of breakpoint can be set. This means that the calling application's code must be executed to the point after its call to LoadLibrary before the debugger will allow this type of breakpoint to be set. portmidi/pm_win/pmwinmm.c0000755000000000000000000014756711445664134014563 0ustar rootroot/* pmwinmm.c -- system specific definitions */ #ifdef _MSC_VER #pragma warning(disable: 4133) // stop warnings about implicit typecasts #endif #ifndef _WIN32_WINNT /* without this define, InitializeCriticalSectionAndSpinCount is * undefined. This version level means "Windows 2000 and higher" */ #define _WIN32_WINNT 0x0500 #endif #include "windows.h" #include "mmsystem.h" #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #include "pmwinmm.h" #include #include "porttime.h" /* asserts used to verify portMidi code logic is sound; later may want something more graceful */ #include #ifdef DEBUG /* this printf stuff really important for debugging client app w/host errors. probably want to do something else besides read/write from/to console for portability, however */ #define STRING_MAX 80 #include "stdio.h" #endif #define streql(x, y) (strcmp(x, y) == 0) #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 /* callback routines */ static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn, WORD wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); #ifdef USE_SYSEX_BUFFERS static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); #endif extern pm_fns_node pm_winmm_in_dictionary; extern pm_fns_node pm_winmm_out_dictionary; static void winmm_out_delete(PmInternal *midi); /* forward reference */ /* A note about buffers: WinMM seems to hold onto buffers longer than one would expect, e.g. when I tried using 2 small buffers to send long sysex messages, at some point WinMM held both buffers. This problem was fixed by making buffers bigger. Therefore, it seems that there should be enough buffer space to hold a whole sysex message. The bufferSize passed into Pm_OpenInput (passed into here as buffer_len) will be used to estimate the largest sysex message (= buffer_len * 4 bytes). Call that the max_sysex_len = buffer_len * 4. For simple midi output (latency == 0), allocate 3 buffers, each with half the size of max_sysex_len, but each at least 256 bytes. For stream output, there will already be enough space in very short buffers, so use them, but make sure there are at least 16. For input, use many small buffers rather than 2 large ones so that when there are short sysex messages arriving frequently (as in control surfaces) there will be more free buffers to fill. Use max_sysex_len / 64 buffers, but at least 16, of size 64 bytes each. The following constants help to represent these design parameters: */ #define NUM_SIMPLE_SYSEX_BUFFERS 3 #define MIN_SIMPLE_SYSEX_LEN 256 #define MIN_STREAM_BUFFERS 16 #define STREAM_BUFFER_LEN 24 #define INPUT_SYSEX_LEN 64 #define MIN_INPUT_BUFFERS 16 /* if we run out of space for output (assume this is due to a sysex msg, expand by up to NUM_EXPANSION_BUFFERS in increments of EXPANSION_BUFFER_LEN */ #define NUM_EXPANSION_BUFFERS 128 #define EXPANSION_BUFFER_LEN 1024 /* A sysex buffer has 3 DWORDS as a header plus the actual message size */ #define MIDIHDR_SYSEX_BUFFER_LENGTH(x) ((x) + sizeof(long)*3) /* A MIDIHDR with a sysex message is the buffer length plus the header size */ #define MIDIHDR_SYSEX_SIZE(x) (MIDIHDR_SYSEX_BUFFER_LENGTH(x) + sizeof(MIDIHDR)) #ifdef USE_SYSEX_BUFFERS /* Size of a MIDIHDR with a buffer contaning multiple MIDIEVENT structures */ #define MIDIHDR_SIZE(x) ((x) + sizeof(MIDIHDR)) #endif /* ============================================================================== win32 mmedia system specific structure passed to midi callbacks ============================================================================== */ /* global winmm device info */ MIDIINCAPS *midi_in_caps = NULL; MIDIINCAPS midi_in_mapper_caps; UINT midi_num_inputs = 0; MIDIOUTCAPS *midi_out_caps = NULL; MIDIOUTCAPS midi_out_mapper_caps; UINT midi_num_outputs = 0; /* per device info */ typedef struct midiwinmm_struct { union { HMIDISTRM stream; /* windows handle for stream */ HMIDIOUT out; /* windows handle for out calls */ HMIDIIN in; /* windows handle for in calls */ } handle; /* midi output messages are sent in these buffers, which are allocated * in a round-robin fashion, using next_buffer as an index */ LPMIDIHDR *buffers; /* pool of buffers for midi in or out data */ int max_buffers; /* length of buffers array */ int buffers_expanded; /* buffers array expanded for extra msgs? */ int num_buffers; /* how many buffers allocated in buffers array */ int next_buffer; /* index of next buffer to send */ HANDLE buffer_signal; /* used to wait for buffer to become free */ #ifdef USE_SYSEX_BUFFERS /* sysex buffers will be allocated only when * a sysex message is sent. The size of the buffer is fixed. */ LPMIDIHDR sysex_buffers[NUM_SYSEX_BUFFERS]; /* pool of buffers for sysex data */ int next_sysex_buffer; /* index of next sysexbuffer to send */ #endif unsigned long last_time; /* last output time */ int first_message; /* flag: treat first message differently */ int sysex_mode; /* middle of sending sysex */ unsigned long sysex_word; /* accumulate data when receiving sysex */ unsigned int sysex_byte_count; /* count how many received */ LPMIDIHDR hdr; /* the message accumulating sysex to send */ unsigned long sync_time; /* when did we last determine delta? */ long delta; /* difference between stream time and real time */ int error; /* host error from doing port midi call */ CRITICAL_SECTION lock; /* prevents reentrant callbacks (input only) */ } midiwinmm_node, *midiwinmm_type; /* ============================================================================= general MIDI device queries ============================================================================= */ static void pm_winmm_general_inputs() { UINT i; WORD wRtn; midi_num_inputs = midiInGetNumDevs(); midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) * midi_num_inputs); if (midi_in_caps == NULL) { /* if you can't open a particular system-level midi interface * (such as winmm), we just consider that system or API to be * unavailable and move on without reporting an error. */ return; } for (i = 0; i < midi_num_inputs; i++) { wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i], sizeof(MIDIINCAPS)); if (wRtn == MMSYSERR_NOERROR) { /* ignore errors here -- if pm_descriptor_max is exceeded, some devices will not be accessible. */ pm_add_device("MMSystem", midi_in_caps[i].szPname, TRUE, (void *) i, &pm_winmm_in_dictionary); } } } static void pm_winmm_mapper_input() { WORD wRtn; /* Note: if MIDIMAPPER opened as input (documentation implies you can, but current system fails to retrieve input mapper capabilities) then you still should retrieve some formof setup info. */ wRtn = midiInGetDevCaps((UINT) MIDIMAPPER, (LPMIDIINCAPS) & midi_in_mapper_caps, sizeof(MIDIINCAPS)); if (wRtn == MMSYSERR_NOERROR) { pm_add_device("MMSystem", midi_in_mapper_caps.szPname, TRUE, (void *) MIDIMAPPER, &pm_winmm_in_dictionary); } } static void pm_winmm_general_outputs() { UINT i; DWORD wRtn; midi_num_outputs = midiOutGetNumDevs(); midi_out_caps = pm_alloc( sizeof(MIDIOUTCAPS) * midi_num_outputs ); if (midi_out_caps == NULL) { /* no error is reported -- see pm_winmm_general_inputs */ return ; } for (i = 0; i < midi_num_outputs; i++) { wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) & midi_out_caps[i], sizeof(MIDIOUTCAPS)); if (wRtn == MMSYSERR_NOERROR) { pm_add_device("MMSystem", midi_out_caps[i].szPname, FALSE, (void *) i, &pm_winmm_out_dictionary); } } } static void pm_winmm_mapper_output() { WORD wRtn; /* Note: if MIDIMAPPER opened as output (pseudo MIDI device maps device independent messages into device dependant ones, via NT midimapper program) you still should get some setup info */ wRtn = midiOutGetDevCaps((UINT) MIDIMAPPER, (LPMIDIOUTCAPS) & midi_out_mapper_caps, sizeof(MIDIOUTCAPS)); if (wRtn == MMSYSERR_NOERROR) { pm_add_device("MMSystem", midi_out_mapper_caps.szPname, FALSE, (void *) MIDIMAPPER, &pm_winmm_out_dictionary); } } /* ========================================================================================= host error handling ========================================================================================= */ static unsigned int winmm_has_host_error(PmInternal * midi) { midiwinmm_type m = (midiwinmm_type)midi->descriptor; return m->error; } /* str_copy_len -- like strcat, but won't overrun the destination string */ /* * returns length of resulting string */ static int str_copy_len(char *dst, char *src, int len) { strncpy(dst, src, len); /* just in case suffex is greater then len, terminate with zero */ dst[len - 1] = 0; return strlen(dst); } static void winmm_get_host_error(PmInternal * midi, char * msg, UINT len) { /* precondition: midi != NULL */ midiwinmm_node * m = (midiwinmm_node *) midi->descriptor; char *hdr1 = "Host error: "; char *hdr2 = "Host callback error: "; msg[0] = 0; /* initialize result string to empty */ if (descriptors[midi->device_id].pub.input) { /* input and output use different winmm API calls */ if (m) { /* make sure there is an open device to examine */ if (m->error != MMSYSERR_NOERROR) { int n = str_copy_len(msg, hdr1, len); /* read and record host error */ int err = midiInGetErrorText(m->error, msg + n, len - n); assert(err == MMSYSERR_NOERROR); m->error = MMSYSERR_NOERROR; } } } else { /* output port */ if (m) { if (m->error != MMSYSERR_NOERROR) { int n = str_copy_len(msg, hdr1, len); int err = midiOutGetErrorText(m->error, msg + n, len - n); assert(err == MMSYSERR_NOERROR); m->error = MMSYSERR_NOERROR; } } } } /* ============================================================================= buffer handling ============================================================================= */ static MIDIHDR *allocate_buffer(long data_size) { LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size)); MIDIEVENT *evt; if (!hdr) return NULL; evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */ hdr->lpData = (LPSTR) evt; hdr->dwBufferLength = MIDIHDR_SYSEX_BUFFER_LENGTH(data_size); hdr->dwBytesRecorded = 0; hdr->dwFlags = 0; hdr->dwUser = hdr->dwBufferLength; return hdr; } #ifdef USE_SYSEX_BUFFERS static MIDIHDR *allocate_sysex_buffer(long data_size) { /* we're actually allocating more than data_size because the buffer * will include the MIDIEVENT header in addition to the data */ LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size)); MIDIEVENT *evt; if (!hdr) return NULL; evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */ hdr->lpData = (LPSTR) evt; hdr->dwFlags = 0; hdr->dwUser = 0; return hdr; } #endif static PmError allocate_buffers(midiwinmm_type m, long data_size, long count) { int i; /* buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */ m->num_buffers = 0; /* in case no memory can be allocated */ m->buffers = (LPMIDIHDR *) pm_alloc(sizeof(LPMIDIHDR) * count); if (!m->buffers) return pmInsufficientMemory; m->max_buffers = count; for (i = 0; i < count; i++) { LPMIDIHDR hdr = allocate_buffer(data_size); if (!hdr) { /* free everything allocated so far and return */ for (i = i - 1; i >= 0; i--) pm_free(m->buffers[i]); pm_free(m->buffers); m->max_buffers = 0; return pmInsufficientMemory; } m->buffers[i] = hdr; /* this may be NULL if allocation fails */ } m->num_buffers = count; return pmNoError; } #ifdef USE_SYSEX_BUFFERS static PmError allocate_sysex_buffers(midiwinmm_type m, long data_size) { PmError rslt = pmNoError; /* sysex_buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */ int i; for (i = 0; i < NUM_SYSEX_BUFFERS; i++) { LPMIDIHDR hdr = allocate_sysex_buffer(data_size); if (!hdr) rslt = pmInsufficientMemory; m->sysex_buffers[i] = hdr; /* this may be NULL if allocation fails */ hdr->dwFlags = 0; /* mark as free */ } return rslt; } #endif #ifdef USE_SYSEX_BUFFERS static LPMIDIHDR get_free_sysex_buffer(PmInternal *midi) { LPMIDIHDR r = NULL; midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (!m->sysex_buffers[0]) { if (allocate_sysex_buffers(m, SYSEX_BYTES_PER_BUFFER)) { return NULL; } } /* busy wait until we find a free buffer */ while (TRUE) { int i; for (i = 0; i < NUM_SYSEX_BUFFERS; i++) { /* cycle through buffers, modulo NUM_SYSEX_BUFFERS */ m->next_sysex_buffer++; if (m->next_sysex_buffer >= NUM_SYSEX_BUFFERS) m->next_sysex_buffer = 0; r = m->sysex_buffers[m->next_sysex_buffer]; if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_sysex_buffer; } /* after scanning every buffer and not finding anything, block */ if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) { #ifdef DEBUG printf("PortMidi warning: get_free_sysex_buffer() wait timed out after 1000ms\n"); #endif } } found_sysex_buffer: r->dwBytesRecorded = 0; r->dwBufferLength = 0; /* changed to correct value later */ return r; } #endif static LPMIDIHDR get_free_output_buffer(PmInternal *midi) { LPMIDIHDR r = NULL; midiwinmm_type m = (midiwinmm_type) midi->descriptor; while (TRUE) { int i; for (i = 0; i < m->num_buffers; i++) { /* cycle through buffers, modulo m->num_buffers */ m->next_buffer++; if (m->next_buffer >= m->num_buffers) m->next_buffer = 0; r = m->buffers[m->next_buffer]; if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer; } /* after scanning every buffer and not finding anything, block */ if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) { #ifdef DEBUG printf("PortMidi warning: get_free_output_buffer() wait timed out after 1000ms\n"); #endif /* if we're trying to send a sysex message, maybe the * message is too big and we need more message buffers. * Expand the buffer pool by 128KB using 1024-byte buffers. */ /* first, expand the buffers array if necessary */ if (!m->buffers_expanded) { LPMIDIHDR *new_buffers = (LPMIDIHDR *) pm_alloc( (m->num_buffers + NUM_EXPANSION_BUFFERS) * sizeof(LPMIDIHDR)); /* if no memory, we could return a no-memory error, but user * probably will be unprepared to deal with it. Maybe the * MIDI driver is temporarily hung so we should just wait. * I don't know the right answer, but waiting is easier. */ if (!new_buffers) continue; /* copy buffers to new_buffers and replace buffers */ memcpy(new_buffers, m->buffers, m->num_buffers * sizeof(LPMIDIHDR)); pm_free(m->buffers); m->buffers = new_buffers; m->max_buffers = m->num_buffers + NUM_EXPANSION_BUFFERS; m->buffers_expanded = TRUE; } /* next, add one buffer and return it */ if (m->num_buffers < m->max_buffers) { r = allocate_buffer(EXPANSION_BUFFER_LEN); /* again, if there's no memory, we may not really be * dead -- maybe the system is temporarily hung and * we can just wait longer for a message buffer */ if (!r) continue; m->buffers[m->num_buffers++] = r; goto found_buffer; /* break out of 2 loops */ } /* else, we've allocated all NUM_EXPANSION_BUFFERS buffers, * and we have no free buffers to send. We'll just keep * polling to see if any buffers show up. */ } } found_buffer: r->dwBytesRecorded = 0; /* actual buffer length is saved in dwUser field */ r->dwBufferLength = (DWORD) r->dwUser; return r; } #ifdef EXPANDING_SYSEX_BUFFERS note: this is not working code, but might be useful if you want to grow sysex buffers. static PmError resize_sysex_buffer(PmInternal *midi, long old_size, long new_size) { LPMIDIHDR big; int i; midiwinmm_type m = (midiwinmm_type) midi->descriptor; /* buffer must be smaller than 64k, but be also a multiple of 4 */ if (new_size > 65520) { if (old_size >= 65520) return pmBufferMaxSize; else new_size = 65520; } /* allocate a bigger message */ big = allocate_sysex_buffer(new_size); /* printf("expand to %d bytes\n", new_size);*/ if (!big) return pmInsufficientMemory; m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR)); if (m->error) { pm_free(big); return pmHostError; } /* make sure we're not going to overwrite any memory */ assert(old_size <= new_size); memcpy(big->lpData, m->hdr->lpData, old_size); /* keep track of how many sysex bytes are in message so far */ big->dwBytesRecorded = m->hdr->dwBytesRecorded; big->dwBufferLength = new_size; /* find which buffer this was, and replace it */ for (i = 0; i < NUM_SYSEX_BUFFERS; i++) { if (m->sysex_buffers[i] == m->hdr) { m->sysex_buffers[i] = big; m->sysex_buffer_size[i] = new_size; pm_free(m->hdr); m->hdr = big; break; } } assert(i != NUM_SYSEX_BUFFERS); return pmNoError; } #endif /* ========================================================================================= begin midi input implementation ========================================================================================= */ static PmError allocate_input_buffer(HMIDIIN h, long buffer_len) { LPMIDIHDR hdr = allocate_buffer(buffer_len); if (!hdr) return pmInsufficientMemory; pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR)); if (pm_hosterror) { pm_free(hdr); return pm_hosterror; } pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR)); return pm_hosterror; } static PmError winmm_in_open(PmInternal *midi, void *driverInfo) { DWORD dwDevice; int i = midi->device_id; int max_sysex_len = midi->buffer_len * 4; int num_input_buffers = max_sysex_len / INPUT_SYSEX_LEN; midiwinmm_type m; dwDevice = (DWORD) descriptors[i].descriptor; /* create system dependent device data */ m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */ midi->descriptor = m; if (!m) goto no_memory; m->handle.in = NULL; m->buffers = NULL; /* not used for input */ m->num_buffers = 0; /* not used for input */ m->max_buffers = FALSE; /* not used for input */ m->buffers_expanded = 0; /* not used for input */ m->next_buffer = 0; /* not used for input */ m->buffer_signal = 0; /* not used for input */ #ifdef USE_SYSEX_BUFFERS for (i = 0; i < NUM_SYSEX_BUFFERS; i++) m->sysex_buffers[i] = NULL; /* not used for input */ m->next_sysex_buffer = 0; /* not used for input */ #endif m->last_time = 0; m->first_message = TRUE; /* not used for input */ m->sysex_mode = FALSE; m->sysex_word = 0; m->sysex_byte_count = 0; m->hdr = NULL; /* not used for input */ m->sync_time = 0; m->delta = 0; m->error = MMSYSERR_NOERROR; /* 4000 is based on Windows documentation -- that's the value used in the memory manager. It's small enough that it should not hurt performance even if it's not optimal. */ InitializeCriticalSectionAndSpinCount(&m->lock, 4000); /* open device */ pm_hosterror = midiInOpen( &(m->handle.in), /* input device handle */ dwDevice, /* device ID */ (DWORD_PTR) winmm_in_callback, /* callback address */ (DWORD_PTR) midi, /* callback instance data */ CALLBACK_FUNCTION); /* callback is a procedure */ if (pm_hosterror) goto free_descriptor; if (num_input_buffers < MIN_INPUT_BUFFERS) num_input_buffers = MIN_INPUT_BUFFERS; for (i = 0; i < num_input_buffers; i++) { if (allocate_input_buffer(m->handle.in, INPUT_SYSEX_LEN)) { /* either pm_hosterror was set, or the proper return code is pmInsufficientMemory */ goto close_device; } } /* start device */ pm_hosterror = midiInStart(m->handle.in); if (pm_hosterror) goto reset_device; return pmNoError; /* undo steps leading up to the detected error */ reset_device: /* ignore return code (we already have an error to report) */ midiInReset(m->handle.in); close_device: midiInClose(m->handle.in); /* ignore return code */ free_descriptor: midi->descriptor = NULL; pm_free(m); no_memory: if (pm_hosterror) { int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); assert(err == MMSYSERR_NOERROR); return pmHostError; } /* if !pm_hosterror, then the error must be pmInsufficientMemory */ return pmInsufficientMemory; /* note: if we return an error code, the device will be closed and memory will be freed. It's up to the caller to free the parameter midi */ } static PmError winmm_in_poll(PmInternal *midi) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; return m->error; } /* winmm_in_close -- close an open midi input device */ /* * assume midi is non-null (checked by caller) */ static PmError winmm_in_close(PmInternal *midi) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (!m) return pmBadPtr; /* device to close */ if (pm_hosterror = midiInStop(m->handle.in)) { midiInReset(m->handle.in); /* try to reset and close port */ midiInClose(m->handle.in); } else if (pm_hosterror = midiInReset(m->handle.in)) { midiInClose(m->handle.in); /* best effort to close midi port */ } else { pm_hosterror = midiInClose(m->handle.in); } midi->descriptor = NULL; DeleteCriticalSection(&m->lock); pm_free(m); /* delete */ if (pm_hosterror) { int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); assert(err == MMSYSERR_NOERROR); return pmHostError; } return pmNoError; } /* Callback function executed via midiInput SW interrupt (via midiInOpen). */ static void FAR PASCAL winmm_in_callback( HMIDIIN hMidiIn, /* midiInput device Handle */ WORD wMsg, /* midi msg */ DWORD dwInstance, /* application data */ DWORD dwParam1, /* MIDI data */ DWORD dwParam2) /* device timestamp (wrt most recent midiInStart) */ { static int entry = 0; PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; /* NOTE: we do not just EnterCriticalSection() here because an * MIM_CLOSE message arrives when the port is closed, but then * the m->lock has been destroyed. */ switch (wMsg) { case MIM_DATA: { /* if this callback is reentered with data, we're in trouble. * It's hard to imagine that Microsoft would allow callbacks * to be reentrant -- isn't the model that this is like a * hardware interrupt? -- but I've seen reentrant behavior * using a debugger, so it happens. */ long new_driver_time; EnterCriticalSection(&m->lock); /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of message LOB; dwParam2 is time message received by input device driver, specified in [ms] from when midiInStart called. each message is expanded to include the status byte */ new_driver_time = dwParam2; if ((dwParam1 & 0x80) == 0) { /* not a status byte -- ignore it. This happened running the sysex.c test under Win2K with MidiMan USB 1x1 interface, but I can't reproduce it. -RBD */ /* printf("non-status byte found\n"); */ } else { /* data to process */ PmEvent event; if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); event.timestamp = dwParam2; event.message = dwParam1; pm_read_short(midi, &event); } LeaveCriticalSection(&m->lock); break; } case MIM_LONGDATA: { MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1; unsigned char *data = (unsigned char *) lpMidiHdr->lpData; unsigned int processed = 0; int remaining = lpMidiHdr->dwBytesRecorded; EnterCriticalSection(&m->lock); /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */ if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); /* can there be more than one message in one buffer? */ /* assume yes and iterate through them */ while (remaining > 0) { unsigned int amt = pm_read_bytes(midi, data + processed, remaining, dwParam2); remaining -= amt; processed += amt; } /* when a device is closed, the pending MIM_LONGDATA buffers are returned to this callback with dwBytesRecorded == 0. In this case, we do not want to send them back to the interface (if we do, the interface will not close, and Windows OS may hang). */ if (lpMidiHdr->dwBytesRecorded > 0) { MMRESULT rslt; lpMidiHdr->dwBytesRecorded = 0; lpMidiHdr->dwFlags = 0; /* note: no error checking -- can this actually fail? */ rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); assert(rslt == MMSYSERR_NOERROR); /* note: I don't think this can fail except possibly for * MMSYSERR_NOMEM, but the pain of reporting this * unlikely but probably catastrophic error does not seem * worth it. */ rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); assert(rslt == MMSYSERR_NOERROR); LeaveCriticalSection(&m->lock); } else { midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR)); LeaveCriticalSection(&m->lock); pm_free(lpMidiHdr); } break; } case MIM_OPEN: break; case MIM_CLOSE: break; case MIM_ERROR: /* printf("MIM_ERROR\n"); */ break; case MIM_LONGERROR: /* printf("MIM_LONGERROR\n"); */ break; default: break; } } /* ========================================================================================= begin midi output implementation ========================================================================================= */ /* begin helper routines used by midiOutStream interface */ /* add_to_buffer -- adds timestamped short msg to buffer, returns fullp */ static int add_to_buffer(midiwinmm_type m, LPMIDIHDR hdr, unsigned long delta, unsigned long msg) { unsigned long *ptr = (unsigned long *) (hdr->lpData + hdr->dwBytesRecorded); *ptr++ = delta; /* dwDeltaTime */ *ptr++ = 0; /* dwStream */ *ptr++ = msg; /* dwEvent */ hdr->dwBytesRecorded += 3 * sizeof(long); /* if the addition of three more words (a message) would extend beyond the buffer length, then return TRUE (full) */ return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength; } static PmTimestamp pm_time_get(midiwinmm_type m) { MMTIME mmtime; MMRESULT wRtn; mmtime.wType = TIME_TICKS; mmtime.u.ticks = 0; wRtn = midiStreamPosition(m->handle.stream, &mmtime, sizeof(mmtime)); assert(wRtn == MMSYSERR_NOERROR); return mmtime.u.ticks; } /* end helper routines used by midiOutStream interface */ static PmError winmm_out_open(PmInternal *midi, void *driverInfo) { DWORD dwDevice; int i = midi->device_id; midiwinmm_type m; MIDIPROPTEMPO propdata; MIDIPROPTIMEDIV divdata; int max_sysex_len = midi->buffer_len * 4; int output_buffer_len; int num_buffers; dwDevice = (DWORD) descriptors[i].descriptor; /* create system dependent device data */ m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */ midi->descriptor = m; if (!m) goto no_memory; m->handle.out = NULL; m->buffers = NULL; m->num_buffers = 0; m->max_buffers = 0; m->buffers_expanded = FALSE; m->next_buffer = 0; #ifdef USE_SYSEX_BUFFERS m->sysex_buffers[0] = NULL; m->sysex_buffers[1] = NULL; m->next_sysex_buffer = 0; #endif m->last_time = 0; m->first_message = TRUE; /* we treat first message as special case */ m->sysex_mode = FALSE; m->sysex_word = 0; m->sysex_byte_count = 0; m->hdr = NULL; m->sync_time = 0; m->delta = 0; m->error = MMSYSERR_NOERROR; /* create a signal */ m->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL); /* this should only fail when there are very serious problems */ assert(m->buffer_signal); /* open device */ if (midi->latency == 0) { /* use simple midi out calls */ pm_hosterror = midiOutOpen( (LPHMIDIOUT) & m->handle.out, /* device Handle */ dwDevice, /* device ID */ /* note: same callback fn as for StreamOpen: */ (DWORD_PTR) winmm_streamout_callback, /* callback fn */ (DWORD_PTR) midi, /* callback instance data */ CALLBACK_FUNCTION); /* callback type */ } else { /* use stream-based midi output (schedulable in future) */ pm_hosterror = midiStreamOpen( &m->handle.stream, /* device Handle */ (LPUINT) & dwDevice, /* device ID pointer */ 1, /* reserved, must be 1 */ (DWORD_PTR) winmm_streamout_callback, (DWORD_PTR) midi, /* callback instance data */ CALLBACK_FUNCTION); } if (pm_hosterror != MMSYSERR_NOERROR) { goto free_descriptor; } if (midi->latency == 0) { num_buffers = NUM_SIMPLE_SYSEX_BUFFERS; output_buffer_len = max_sysex_len / num_buffers; if (output_buffer_len < MIN_SIMPLE_SYSEX_LEN) output_buffer_len = MIN_SIMPLE_SYSEX_LEN; } else { long dur = 0; num_buffers = max(midi->buffer_len, midi->latency / 2); if (num_buffers < MIN_STREAM_BUFFERS) num_buffers = MIN_STREAM_BUFFERS; output_buffer_len = STREAM_BUFFER_LEN; propdata.cbStruct = sizeof(MIDIPROPTEMPO); propdata.dwTempo = 480000; /* microseconds per quarter */ pm_hosterror = midiStreamProperty(m->handle.stream, (LPBYTE) & propdata, MIDIPROP_SET | MIDIPROP_TEMPO); if (pm_hosterror) goto close_device; divdata.cbStruct = sizeof(MIDIPROPTEMPO); divdata.dwTimeDiv = 480; /* divisions per quarter */ pm_hosterror = midiStreamProperty(m->handle.stream, (LPBYTE) & divdata, MIDIPROP_SET | MIDIPROP_TIMEDIV); if (pm_hosterror) goto close_device; } /* allocate buffers */ if (allocate_buffers(m, output_buffer_len, num_buffers)) goto free_buffers; /* start device */ if (midi->latency != 0) { pm_hosterror = midiStreamRestart(m->handle.stream); if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers; } return pmNoError; free_buffers: /* buffers are freed below by winmm_out_delete */ close_device: midiOutClose(m->handle.out); free_descriptor: midi->descriptor = NULL; winmm_out_delete(midi); /* frees buffers and m */ no_memory: if (pm_hosterror) { int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); assert(err == MMSYSERR_NOERROR); return pmHostError; } return pmInsufficientMemory; } /* winmm_out_delete -- carefully free data associated with midi */ /**/ static void winmm_out_delete(PmInternal *midi) { int i; /* delete system dependent device data */ midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (m) { if (m->buffer_signal) { /* don't report errors -- better not to stop cleanup */ CloseHandle(m->buffer_signal); } /* if using stream output, free buffers */ for (i = 0; i < m->num_buffers; i++) { if (m->buffers[i]) pm_free(m->buffers[i]); } m->num_buffers = 0; pm_free(m->buffers); m->max_buffers = 0; #ifdef USE_SYSEX_BUFFERS /* free sysex buffers */ for (i = 0; i < NUM_SYSEX_BUFFERS; i++) { if (m->sysex_buffers[i]) pm_free(m->sysex_buffers[i]); } #endif } midi->descriptor = NULL; pm_free(m); /* delete */ } /* see comments for winmm_in_close */ static PmError winmm_out_close(PmInternal *midi) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (m->handle.out) { /* device to close */ if (midi->latency == 0) { pm_hosterror = midiOutClose(m->handle.out); } else { pm_hosterror = midiStreamClose(m->handle.stream); } /* regardless of outcome, free memory */ winmm_out_delete(midi); } if (pm_hosterror) { int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); assert(err == MMSYSERR_NOERROR); return pmHostError; } return pmNoError; } static PmError winmm_out_abort(PmInternal *midi) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; m->error = MMSYSERR_NOERROR; /* only stop output streams */ if (midi->latency > 0) { m->error = midiStreamStop(m->handle.stream); } return m->error ? pmHostError : pmNoError; } static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; assert(m); if (m->hdr) { m->error = midiOutPrepareHeader(m->handle.out, m->hdr, sizeof(MIDIHDR)); if (m->error) { /* do not send message */ } else if (midi->latency == 0) { /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded * should be zero. This is set in get_free_sysex_buffer(). * The msg length goes in dwBufferLength in spite of what * Microsoft documentation says (or doesn't say). */ m->hdr->dwBufferLength = m->hdr->dwBytesRecorded; m->hdr->dwBytesRecorded = 0; m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR)); } else { m->error = midiStreamOut(m->handle.stream, m->hdr, sizeof(MIDIHDR)); } midi->fill_base = NULL; m->hdr = NULL; if (m->error) { m->hdr->dwFlags = 0; /* release the buffer */ return pmHostError; } } return pmNoError; } #ifdef GARBAGE static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; unsigned char *msg_buffer; /* at the beginning of sysex, m->hdr is NULL */ if (!m->hdr) { /* allocate a buffer if none allocated yet */ m->hdr = get_free_output_buffer(midi); if (!m->hdr) return pmInsufficientMemory; m->sysex_byte_count = 0; } /* figure out where to write byte */ msg_buffer = (unsigned char *) (m->hdr->lpData); assert(m->hdr->lpData == (char *) (m->hdr + 1)); /* check for overflow */ if (m->sysex_byte_count >= m->hdr->dwBufferLength) { /* allocate a bigger message -- double it every time */ LPMIDIHDR big = allocate_buffer(m->sysex_byte_count * 2); /* printf("expand to %d bytes\n", m->sysex_byte_count * 2); */ if (!big) return pmInsufficientMemory; m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR)); if (m->error) { m->hdr = NULL; return pmHostError; } memcpy(big->lpData, msg_buffer, m->sysex_byte_count); msg_buffer = (unsigned char *) (big->lpData); if (m->buffers[0] == m->hdr) { m->buffers[0] = big; pm_free(m->hdr); /* printf("freed m->hdr\n"); */ } else if (m->buffers[1] == m->hdr) { m->buffers[1] = big; pm_free(m->hdr); /* printf("freed m->hdr\n"); */ } m->hdr = big; } /* append byte to message */ msg_buffer[m->sysex_byte_count++] = byte; /* see if we have a complete message */ if (byte == MIDI_EOX) { m->hdr->dwBytesRecorded = m->sysex_byte_count; /* { int i; int len = m->hdr->dwBytesRecorded; printf("OutLongMsg %d ", len); for (i = 0; i < len; i++) { printf("%2x ", msg_buffer[i]); } } */ m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR)); m->hdr = NULL; /* stop using this message buffer */ if (m->error) return pmHostError; } return pmNoError; } #endif static PmError winmm_write_short(PmInternal *midi, PmEvent *event) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; PmError rslt = pmNoError; assert(m); if (midi->latency == 0) { /* use midiOut interface, ignore timestamps */ m->error = midiOutShortMsg(m->handle.out, event->message); if (m->error) rslt = pmHostError; } else { /* use midiStream interface -- pass data through buffers */ unsigned long when = event->timestamp; unsigned long delta; int full; if (when == 0) when = midi->now; /* when is in real_time; translate to intended stream time */ when = when + m->delta + midi->latency; /* make sure we don't go backward in time */ if (when < m->last_time) when = m->last_time; delta = when - m->last_time; m->last_time = when; /* before we insert any data, we must have a buffer */ if (m->hdr == NULL) { /* stream interface: buffers allocated when stream is opened */ m->hdr = get_free_output_buffer(midi); } full = add_to_buffer(m, m->hdr, delta, event->message); if (full) rslt = winmm_write_flush(midi, when); } return rslt; } #define winmm_begin_sysex winmm_write_flush #ifndef winmm_begin_sysex static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; PmError rslt = pmNoError; if (midi->latency == 0) { /* do nothing -- it's handled in winmm_write_byte */ } else { /* sysex expects an empty sysex buffer, so send whatever is here */ rslt = winmm_write_flush(midi); } return rslt; } #endif static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp) { /* could check for callback_error here, but I haven't checked * what happens if we exit early and don't finish the sysex msg * and clean up */ midiwinmm_type m = (midiwinmm_type) midi->descriptor; PmError rslt = pmNoError; LPMIDIHDR hdr = m->hdr; if (!hdr) return rslt; /* something bad happened earlier, do not report an error because it would have been reported (at least) once already */ /* a(n old) version of MIDI YOKE requires a zero byte after * the sysex message, but do not increment dwBytesRecorded: */ hdr->lpData[hdr->dwBytesRecorded] = 0; if (midi->latency == 0) { #ifdef DEBUG_PRINT_BEFORE_SENDING_SYSEX /* DEBUG CODE: */ { int i; int len = m->hdr->dwBufferLength; printf("OutLongMsg %d ", len); for (i = 0; i < len; i++) { printf("%2x ", (unsigned char) (m->hdr->lpData[i])); } } #endif } else { /* Using stream interface. There are accumulated bytes in m->hdr to send using midiStreamOut */ /* add bytes recorded to MIDIEVENT length, but don't count the MIDIEVENT data (3 longs) */ MIDIEVENT *evt = (MIDIEVENT *) (hdr->lpData); evt->dwEvent += hdr->dwBytesRecorded - 3 * sizeof(long); /* round up BytesRecorded to multiple of 4 */ hdr->dwBytesRecorded = (hdr->dwBytesRecorded + 3) & ~3; } rslt = winmm_write_flush(midi, timestamp); return rslt; } static PmError winmm_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp) { /* write a sysex byte */ PmError rslt = pmNoError; midiwinmm_type m = (midiwinmm_type) midi->descriptor; LPMIDIHDR hdr = m->hdr; unsigned char *msg_buffer; assert(m); if (!hdr) { m->hdr = hdr = get_free_output_buffer(midi); assert(hdr); midi->fill_base = (unsigned char *) m->hdr->lpData; midi->fill_offset_ptr = &(hdr->dwBytesRecorded); /* when buffer fills, Pm_WriteSysEx will revert to calling * pmwin_write_byte, which expect to have space, so leave * one byte free for pmwin_write_byte. Leave another byte * of space for zero after message to make early version of * MIDI YOKE driver happy -- therefore dwBufferLength - 2 */ midi->fill_length = hdr->dwBufferLength - 2; if (midi->latency != 0) { unsigned long when = (unsigned long) timestamp; unsigned long delta; unsigned long *ptr; if (when == 0) when = midi->now; /* when is in real_time; translate to intended stream time */ when = when + m->delta + midi->latency; /* make sure we don't go backward in time */ if (when < m->last_time) when = m->last_time; delta = when - m->last_time; m->last_time = when; ptr = (unsigned long *) hdr->lpData; *ptr++ = delta; *ptr++ = 0; *ptr = MEVT_F_LONG; hdr->dwBytesRecorded = 3 * sizeof(long); /* data will be added at an offset of dwBytesRecorded ... */ } } /* add the data byte */ msg_buffer = (unsigned char *) (hdr->lpData); msg_buffer[hdr->dwBytesRecorded++] = byte; /* see if buffer is full, leave one byte extra for pad */ if (hdr->dwBytesRecorded >= hdr->dwBufferLength - 1) { /* write what we've got and continue */ rslt = winmm_end_sysex(midi, timestamp); } return rslt; } #ifdef EXPANDING_SYSEX_BUFFERS note: this code is here as an aid in case you want sysex buffers to expand to hold large messages completely. If so, you will want to change SYSEX_BYTES_PER_BUFFER above to some variable that remembers the buffer size. A good place to put this value would be in the hdr->dwUser field. rslt = resize_sysex_buffer(midi, m->sysex_byte_count, m->sysex_byte_count * 2); if (rslt == pmBufferMaxSize) /* if the buffer can't be resized */ #endif #ifdef EXPANDING_SYSEX_BUFFERS int bytesRecorded = hdr->dwBytesRecorded; /* this field gets wiped out, so we'll save it */ rslt = resize_sysex_buffer(midi, bytesRecorded, 2 * bytesRecorded); hdr->dwBytesRecorded = bytesRecorded; if (rslt == pmBufferMaxSize) /* if buffer can't be resized */ #endif static PmTimestamp winmm_synchronize(PmInternal *midi) { midiwinmm_type m; unsigned long pm_stream_time_2; unsigned long real_time; unsigned long pm_stream_time; /* only synchronize if we are using stream interface */ if (midi->latency == 0) return 0; /* figure out the time */ m = (midiwinmm_type) midi->descriptor; pm_stream_time_2 = pm_time_get(m); do { /* read real_time between two reads of stream time */ pm_stream_time = pm_stream_time_2; real_time = (*midi->time_proc)(midi->time_info); pm_stream_time_2 = pm_time_get(m); /* repeat if more than 1ms elapsed */ } while (pm_stream_time_2 > pm_stream_time + 1); m->delta = pm_stream_time - real_time; m->sync_time = real_time; return real_time; } #ifdef USE_SYSEX_BUFFERS /* winmm_out_callback -- recycle sysex buffers */ static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; LPMIDIHDR hdr = (LPMIDIHDR) dwParam1; int err = 0; /* set to 0 so that no buffer match will also be an error */ /* Future optimization: eliminate UnprepareHeader calls -- they aren't necessary; however, this code uses the prepared-flag to indicate which buffers are free, so we need to do something to flag empty buffers if we leave them prepared */ /* printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n", hdr, wMsg, MOM_DONE); */ if (wMsg == MOM_DONE) { MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, sizeof(MIDIHDR)); assert(ret == MMSYSERR_NOERROR); } /* notify waiting sender that a buffer is available */ err = SetEvent(m->buffer_signal); assert(err); /* false -> error */ } #endif /* winmm_streamout_callback -- unprepare (free) buffer header */ static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; LPMIDIHDR hdr = (LPMIDIHDR) dwParam1; int err; /* Even if an error is pending, I think we should unprepare msgs and signal their arrival */ /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n", hdr, wMsg, MOM_DONE); */ if (wMsg == MOM_DONE) { MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, sizeof(MIDIHDR)); assert(ret == MMSYSERR_NOERROR); } /* signal client in case it is blocked waiting for buffer */ err = SetEvent(m->buffer_signal); assert(err); /* false -> error */ } /* ========================================================================================= begin exported functions ========================================================================================= */ #define winmm_in_abort pm_fail_fn pm_fns_node pm_winmm_in_dictionary = { none_write_short, none_sysex, none_sysex, none_write_byte, none_write_short, none_write_flush, winmm_synchronize, winmm_in_open, winmm_in_abort, winmm_in_close, winmm_in_poll, winmm_has_host_error, winmm_get_host_error }; pm_fns_node pm_winmm_out_dictionary = { winmm_write_short, winmm_begin_sysex, winmm_end_sysex, winmm_write_byte, winmm_write_short, /* short realtime message */ winmm_write_flush, winmm_synchronize, winmm_out_open, winmm_out_abort, winmm_out_close, none_poll, winmm_has_host_error, winmm_get_host_error }; /* initialize winmm interface. Note that if there is something wrong with winmm (e.g. it is not supported or installed), it is not an error. We should simply return without having added any devices to the table. Hence, no error code is returned. Furthermore, this init code is called along with every other supported interface, so the user would have a very hard time figuring out what hardware and API generated the error. Finally, it would add complexity to pmwin.c to remember where the error code came from in order to convert to text. */ void pm_winmm_init( void ) { pm_winmm_mapper_input(); pm_winmm_mapper_output(); pm_winmm_general_inputs(); pm_winmm_general_outputs(); } /* no error codes are returned, even if errors are encountered, because there is probably nothing the user could do (e.g. it would be an error to retry. */ void pm_winmm_term( void ) { int i; #ifdef DEBUG char msg[PM_HOST_ERROR_MSG_LEN]; #endif int doneAny = 0; #ifdef DEBUG printf("pm_winmm_term called\n"); #endif for (i = 0; i < pm_descriptor_index; i++) { PmInternal * midi = descriptors[i].internalDescriptor; if (midi) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (m->handle.out) { /* close next open device*/ #ifdef DEBUG if (doneAny == 0) { printf("begin closing open devices...\n"); doneAny = 1; } /* report any host errors; this EXTEREMELY useful when trying to debug client app */ if (winmm_has_host_error(midi)) { winmm_get_host_error(midi, msg, PM_HOST_ERROR_MSG_LEN); printf("%s\n", msg); } #endif /* close all open ports */ (*midi->dictionary->close)(midi); } } } if (midi_in_caps) { pm_free(midi_in_caps); midi_in_caps = NULL; } if (midi_out_caps) { pm_free(midi_out_caps); midi_out_caps = NULL; } #ifdef DEBUG if (doneAny) { printf("warning: devices were left open. They have been closed.\n"); } printf("pm_winmm_term exiting\n"); #endif pm_descriptor_index = 0; } portmidi/pm_win/clean_up_vcproj.awk0000644000000000000000000000445611274243554016571 0ustar rootroot# gawk script to convert CMake-generated Visual Studio projects into # stand-alone project files # # Roger Dannenberg, October 2009 # # the result uses relative path names (so you can install the project on # any machine and use it) # # NOTE: to run this, you must assign base_relative to the relative path # from the vcproj file to portmidi, e.g. base_relative=.. or base_relative=. BEGIN { state = "normal"; #=================IMPORTANT==================== # change the following path to the path in which # the CMakeLists.txt file resides: base_path = "C:\\\\Users\\\\rbd\\\\portmedia\\\\portmidi"; #============================================== base_path_2 = base_path; gsub("\\\\\\\\", "/", base_path_2) cmake_stuff = 0; # flag to print ... text } # this case removes CMake phases from project state == "cmakelists" { # print "IN CMAKELISTS " file_text = file_text "\n" $0 # collect the ... section if (index($0, "CMakeLists.txt") > 0) { cmake_stuff = 1 # remember to delete this ... section } if (index($0, "") > 0) { state = "normal"; if (cmake_stuff == 0) { gsub(base_path, base_relative, file_text) gsub(base_path_2, base_relative, file_text) print file_text; } cmake_stuff = 0; }; next } # this is the normal case, not in buildPhases list state == "normal" { # print "NOT IN BUILD PHASES" # take out all the absolute paths gsub(base_path, base_relative, $0); gsub(base_path_2, base_relative, $0); # special processing for ... text: if ($0 ~ " /* pm_exit is called when the program exits. It calls pm_term to make sure PortMidi is properly closed. If DEBUG is on, we prompt for input to avoid losing error messages. */ static void pm_exit(void) { pm_term(); #ifdef DEBUG #define STRING_MAX 80 { char line[STRING_MAX]; printf("Type ENTER...\n"); /* note, w/o this prompting, client console application can not see one of its errors before closing. */ fgets(line, STRING_MAX, stdin); } #endif } /* pm_init is the windows-dependent initialization.*/ void pm_init(void) { atexit(pm_exit); #ifdef DEBUG printf("registered pm_exit with atexit()\n"); #endif pm_winmm_init(); /* initialize other APIs (DirectX?) here */ } void pm_term(void) { pm_winmm_term(); } static PmDeviceID pm_get_default_device_id(int is_input, char *key) { HKEY hkey; #define PATTERN_MAX 256 char pattern[PATTERN_MAX]; long pattern_max = PATTERN_MAX; DWORD dwType; /* Find first input or device -- this is the default. */ PmDeviceID id = pmNoDevice; int i, j; Pm_Initialize(); /* make sure descriptors exist! */ for (i = 0; i < pm_descriptor_index; i++) { if (descriptors[i].pub.input == is_input) { id = i; break; } } /* Look in registry for a default device name pattern. */ if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return id; } if (RegOpenKeyEx(hkey, "JavaSoft", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return id; } if (RegOpenKeyEx(hkey, "Prefs", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return id; } if (RegOpenKeyEx(hkey, "/Port/Midi", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return id; } if (RegQueryValueEx(hkey, key, NULL, &dwType, pattern, &pattern_max) != ERROR_SUCCESS) { return id; } /* decode pattern: upper case encoded with "/" prefix */ i = j = 0; while (pattern[i]) { if (pattern[i] == '/' && pattern[i + 1]) { pattern[j++] = toupper(pattern[++i]); } else { pattern[j++] = tolower(pattern[i]); } i++; } pattern[j] = 0; /* end of string */ /* now pattern is the string from the registry; search for match */ i = pm_find_default_device(pattern, is_input); if (i != pmNoDevice) { id = i; } return id; } PmDeviceID Pm_GetDefaultInputDeviceID() { return pm_get_default_device_id(TRUE, "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/I/N/P/U/T_/D/E/V/I/C/E"); } PmDeviceID Pm_GetDefaultOutputDeviceID() { return pm_get_default_device_id(FALSE, "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/O/U/T/P/U/T_/D/E/V/I/C/E"); } #include "stdio.h" void *pm_alloc(size_t s) { return malloc(s); } void pm_free(void *ptr) { free(ptr); } portmidi/pm_win/README_WIN.txt0000755000000000000000000003715211453600330015115 0ustar rootrootFile: PortMidi Win32 Readme Author: Belinda Thom, June 16 2002 Revised by: Roger Dannenberg, June 2002, May 2004, June 2007, Umpei Kurokawa, June 2007 Roger Dannenberg Sep 2009 Contents: Using Portmidi To Install Portmidi To Compile Portmidi About Cmake Using other versions of Visual C++ To Create Your Own Portmidi Client Application ============================================================================= USING PORTMIDI: ============================================================================= Using Microsoft Visual C++ project files (provided with PortMidi), there are two configurations of the PortMidi library. The Debug version is intended for debugging, especially in a console application. The Debug version enables some extra error checking and outputs some text as well as a prompt to type ENTER so that you don't lose any debugging text when the program exits. You can turn off this extra debugging info by taking out the compile-time definition for DEBUG. (But leave _DEBUG, which I think is important for compiling in Debug mode.) This debugging version also defines PM_CHECK_ERRORS, which forces a check for error return codes from every call to PortMidi. You can disable this checking (especially if you want to handle error codes in your own way) by removing PM_CHECK_ERRORS from the predefined symbols list in the Settings dialog box. PortMidi is designed to run without a console and should work perfectly well within a graphical user interface application. The Release version is both optimized and lacking the debugging printout code of the Debug version. Read the portmidi.h file for PortMidi API details on using the PortMidi API. See <...>\pm_test\test.c and other files in pm_test for usage examples. ============================================================================= TO INSTALL PORTMIDI: ============================================================================= 1) get current source from the portmedia project at SourceForge.net 2) copy source into directory: <...>\portmidi ============================================================================= TO COMPILE PORTMIDI: ============================================================================= 3) cd to or open the portmidi directory 4) start or click on the portmidi.sln workspace (note, all Visual Studio files are built by CMake. If you need a different version or have problems with paths, try rebuilding the Visual Studio project files using CMake -- See "Using other versions of visual C++" below.) 5) the following projects exist within this workspace: - portmidi-static, portmidi-dynamic (versions of the PortMidi library) - test (simple midi I/O testing) - midithread (an example illustrating low-latency MIDI processing using a dedicated low-latency thread) - sysex (simple sysex message I/O testing) - latency (uses porttime to measure system latency) - midithru (an example illustrating software MIDI THRU) - qtest (a test of the new multicore-safe queue implementation) - mm (allows monitoring of midi messages) - pmjni (a dll to provide an interface to PortMidi for Java) 6) set the Java SDK path using one of two methods: Method 1: open portmidi/CMakeLists.txt with CMake, configure, and generate -- this should find the Java SDK path and update your solution and project files Method 2: (does not require CMake): - open the pmjni project properties - visit Configuration Properties, C/C++, General - find Additional Include Directories property and open the editor (...) - at the end of the list, you will find two paths mentioning Java - these are absolute paths to the Java SDK; you'll need to install the Java SDK (from Sun) and update these directories in order to build this project. - similarly, the Linker->Input->Additional Dependencies list has a path to the jvm.lib file, which needs to be correct(ed). 6) use Build->Batch Build ... to build everything in the project. If a build fails, try building again. There seem to be some missing dependencies, so you may have to "ALL_BUILD" several times before everything builds successfully. 7) The settings for these projects were distributed in the zip file, so compile should just work. 8) run test project; use the menu that shows up from the command prompt to test that portMidi works on your system. tests include: - verify midi output works - verify midi input works 9) run other projects if you wish: sysex, latency, midithread, mm, qtest, midithru 10) compile the java code: - cd pm_java - make.bat + If there is a problem running javac, note that you must have a path to javac.exe on your PATH environment variable. Edit your path (in Vista) using Control Panel > User Accounts > User Accounts > Change my environment variables; then select Path and click Edit... After changing, you will have to restart the command window to see any effect. + In Vista, you may get a warning about running UpdateRsrcJavaExe.exe. This is called by make.bat, and you should allow the program to run. + Note that make.bat does not build pmjni\jportmidi_JPortMidiApi.h because it is included in the distribution. You can rebuild it from sources as follows: cd pm_java javah jportmidi.JPortMidiApi move jportmidi_JPortMidiApi pmjni\jportmidi_JPortMidiApi.h 11) you might wish to move pm_java/win32 to another location; run the pmdefaults.exe program from the (entire) win32 directory to use PmDefaults. This program let's you select default input/output midi devices for PortMidi applications. ============================================================================ ABOUT CMAKE ============================================================================ cmake was used to generate .vcproj files. cmake embeds absolute paths into .vcproj files, which makes the files non-portable to other systems. To work around this problem, pm_win\clean_up_vcproj.bat can be used to replace absolute paths with relative paths. To use it, you will need to install gawk and set your search path to allow you to execute gawk, e.g. my path includes "C:\Program Files\GnuWin32\bin;". You will also need to edit pm_win\clean_up_vcproj.awk, replacing C:\Users\rbd\portmidi with whatever absolute path cmake uses in your vcproj files. This is not a general or robust fix, but it seems to work with the vcproj files currently created by CMake. ============================================================================ USING OTHER VERSIONS OF VISUAL C++ ============================================================================ You can use cmake to make Visual Studio solution and project files. If you do not want to use the provided Version 9 project files, install cmake, run it, set the "Where is the source code" box to your portmidi directory, and click on Configure. A menu will allow you to choose the Visual Studio project version you want. Click Configure once again, then Generate, and you should be all set to open portmidi.sln. ============================================================================ TO CREATE YOUR OWN PORTMIDI CLIENT APPLICATION: ============================================================================ NOTE: this section needs to be reviewed and tested. My suggestion would be to copy the test project file (test.dsp) and modify it. -RBD The easiest way is to start a new project w/in the portMidi workspace: 1) To open new project: - File->New->Projects - Location: <...>\portmidi\ - check Add to current workspace - select Win32 Console Application (recommended for now) - do *NOT* select the "make dependency" box (you will explicitly do this in the next step) - Click OK - Select "An Empty Project" and click Finish In Visual C++ 2005 Express Edition, - File->New->Projects - Location: <...>\portmidi\ - select Add to solution - select CLR Empty project in CLR - select Win32 Console Application in Win32 - select Empty project in General 2) Now this project will be the active project. Make it explicitly depend on PortMidi dll: - Project->Dependencies - Click pm_dll 3) add whatever files you wish to add to your new project, using portMidi calls as desired (see USING PORTMIDI at top of this readme) 4) when you include portMidi files, do so like this: - #include "..\pm_common\portmidi.h" - etc. 5) build and run your project ============================================================================ DESIGN NOTES ============================================================================ PortMidi for Win32 exists as a simple static library, with Win32-specific code in pmwin.c and MM-specific code in pmwinmm.c. Orderly cleanup after errors are encountered is based on a fixed order of steps and state changes to reflect each step. Here's the order: To open input: initialize return value to NULL - allocate the PmInternal strucure (representation of PortMidiStream) return value is (non-null) PmInternal structure - allocate midi buffer set buffer field of PmInternal structure - call system-dependent open code - allocate midiwinmm_type for winmm dependent data set descriptor field of PmInternal structure - open device set handle field of midiwinmm_type structure - allocate buffers - start device - return - return SYSEX HANDLING -- the most complex, least exercised, and therefore most buggy part of PortMidi (but maybe bugs are finally gone) There are three cases: simple output, stream output, input Each must deal with: 1. Buffer Initialization (creating buffers) 2. Buffer Allocation (finding a free buffer) 3. Buffer Fill (putting bytes in the buffer) 4. Buffer Preparation (midiOutPrepare, etc.) 5. Buffer Send (to Midi device) 6. Buffer Receive (in callback) 7. Buffer Empty (removing bytes from buffer) 8. Buffer Free (returning to the buffer pool) 9. Buffer Finalization (returning to heap) Here's how simple output handles sysex: 1. Buffer Initialization (creating buffers) allocated when code tries to write first byte to a buffer the test is "if (!m->sysex_buffers[0]) { ... }" this field is initialized to NULL when device is opened the size is SYSEX_BYTES_PER_BUFFER allocate_sysex_buffers() does the initialization note that the actual size of the allocation includes additional space for a MIDIEVENT (3 longs) which are not used in this case 2. Buffer Allocation (finding a free buffer) see get_free_sysex_buffer() cycle through m->sysex_buffers[] using m->next_sysex_buffer to determine where to look next if nothing is found, wait by blocking on m->sysex_buffer_signal this is signaled by the callback every time a message is received 3. Buffer Fill (putting bytes in the buffer) essentially a state machine approach hdr->dwBytesRecorded is a position in message pointed to by m->hdr keep appending bytes until dwBytesRecorded >= SYSEX_BYTES_PER_BUFFER then send the message, reseting the state to initial values 4. Buffer Preparation (midiOutPrepare, etc.) just before sending in winmm_end_sysex() 5. Buffer Send (to Midi device) message is padded with zero at end (since extra space was allocated this is ok) -- the zero works around a bug in (an old version of) MIDI YOKE drivers dwBufferLength gets dwBytesRecorded, and dwBytesRecorded gets 0 uses midiOutLongMsg() 6. Buffer Receive (in callback) 7. Buffer Empty (removing bytes from buffer) not applicable for output 8. Buffer Free (returning to the buffer pool) unprepare message to indicate that it is free SetEvent on m->buffer_signal in case client is waiting 9. Buffer Finalization (returning to heap) when device is closed, winmm_out_delete frees all sysex buffers Here's how stream output handles sysex: 1. Buffer Initialization (creating buffers) same code as simple output (see above) 2. Buffer Allocation (finding a free buffer) same code as simple output (see above) 3. Buffer Fill (putting bytes in the buffer) essentially a state machine approach m->dwBytesRecorded is a position in message keep appending bytes until buffer is full (one byte to spare) 4. Buffer Preparation (midiOutPrepare, etc.) done before sending message dwBytesRecorded and dwBufferLength are set in winmm_end_sysex 5. Buffer Send (to Midi device) uses midiStreamOutMsg() 6. Buffer Receive (in callback) 7. Buffer Empty (removing bytes from buffer) not applicable for output 8. Buffer Free (returning to the buffer pool) unprepare message to indicate that it is free SetEvent on m->buffer_signal in case client is waiting 9. Buffer Finalization (returning to heap) when device is closed, winmm_out_delete frees all sysex buffers Here's how input handles sysex: 1. Buffer Initialization (creating buffers) two buffers are allocated in winmm_in_open 2. Buffer Allocation (finding a free buffer) same code as simple output (see above) 3. Buffer Fill (putting bytes in the buffer) not applicable for input 4. Buffer Preparation (midiOutPrepare, etc.) done before sending message -- in winmm_in_open and in callback 5. Buffer Send (to Midi device) uses midiInAddbuffer in allocate_sysex_input_buffer (called from winmm_in_open) and callback 6. Buffer Receive (in callback) 7. Buffer Empty (removing bytes from buffer) done without pause in loop in callback 8. Buffer Free (returning to the buffer pool) done by midiInAddBuffer in callback, no pointer to buffers is retained except by device 9. Buffer Finalization (returning to heap) when device is closed, empty buffers are delivered to callback, which frees them IMPORTANT: In addition to the above, PortMidi now has "shortcuts" to optimize the transfer of sysex data. To enable the optimization for sysex output, the system-dependent code sets fields in the pmInternal structure: fill_base, fill_offset_ptr, and fill_length. When fill_base is non-null, the system-independent part of PortMidi is allowed to directly copy sysex bytes to "fill_base[*fill_offset_ptr++]" until *fill_offset_ptr reaches fill_length. See the code for details. ----------- Additional notes on using VS 2005 (maybe this is obsolete now?): 1) Make sure "Configuration: All Configurations" is selected in all of the following Properties modifications! 2) In my case the project defaulted to compiling all .c files with the C++ compiler, which was disastrous. I had to go to set Properties for each file, to wit: Expand Configuration Properties, Expand C/C++, Select Advanced, set the Compile As popup to Compile as C Code (/TC). (For better or worse, the project I inherited has a bunch of .c files that rely on C++ features, so I couldn't reliably set this the project properties level.) 3) While you're there, make sure that the C/C++ -> General -> "Compile with Common Language Runtime support" is set to "No Common Language Runtime support" (the C compiler *can't* support CLR, but VS won't do anything useful like automatically set the two options to match)-. 4) I never got VS precompiled header thing to work sensibly, so I took the path of least resistance and turned PCH's off for all my files. Properties -> Configuration Properties -> C/C++ -> Precompiled Headers -> Create/Use Precompiled Header popup set to "Not Using Precompiled Headers". The compiler is reasonably fast even if it has to parse all the header files, so unless someone wants to explain VS's PCHs to me, the hell with it, I say. portmidi/pm_mac/0000755000000000000000000000000011453601074012640 5ustar rootrootportmidi/pm_mac/Makefile.osx0000755000000000000000000001025511445664134015125 0ustar rootroot# MAKEFILE FOR PORTMIDI # Roger B. Dannenberg # Sep 2009 # NOTE: you can use # make -f pm_osx/Makefile.osx configuration=Release # to override the default Debug configuration configuration=Release PF=/usr/local # For debugging, define PM_CHECK_ERRORS ifeq ($(configuration),Release) CONFIG = Release else CONFIG = Debug endif current: all all: $(CONFIG)/CMakeCache.txt cd $(CONFIG); make $(CONFIG)/CMakeCache.txt: rm -f CMakeCache.txt mkdir -p $(CONFIG) cd $(CONFIG); cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=$(CONFIG) **** For instructions: make -f pm_mac\Makefile.osx help ****\n' help: echo $$'\n\n\ This is help for portmidi/pm_mac/Makefile.osx\n\n\ Installation path for dylib is $(PF)\n\ To build Release version libraries and test applications,\n \ make -f pm_mac/Makefile.osx\n\ To build Debug version libraries and test applications,\n \ make -f pm_mac/Makefile.osx configuration=Debug\n\ To install universal dynamic library,\n \ sudo make -f pm_mac/Makefile.osx install\n\ To install universal dynamic library with xcode,\n \ make -f pm_mac/Makefile.osx install-with-xcode\n\ To make PmDefaults Java application,\n \ make -f pm_mac/Makefile.osx pmdefaults\n\n \ configuration = $(configuration)\n' clean: rm -f *.o *~ core* */*.o */*/*.o */*~ */core* pm_test/*/pm_dll.dll rm -f *.opt *.ncb *.plg pm_win/Debug/pm_dll.lib pm_win/Release/pm_dll.lib rm -f pm_test/*.opt pm_test/*.ncb rm -f pm_java/pmjni/*.o pm_java/pmjni/*~ pm_java/*.h rm -rf Release/CMakeFiles Debug/CMakeFiles rm -rf pm_mac/pmdefaults/lib pm_mac/pmdefaults/src cleaner: clean rm -rf pm_mac/build rm -rf pm_mac/Debug pm_mac/Release pm_test/Debug pm_test/Release rm -f Debug/*.dylib Release/*.dylib rm -f pm_java/pmjni/Debug/*.jnilib rm -f pm_java/pmjni/Release/*.jnilib cleanest: cleaner rm -f Debug/libportmidi_s.a Release/libportmidi_s.a rm -f pm_test/Debug/test pm_test/Debug/sysex pm_test/Debug/midithread rm -f pm_test/Debug/latency pm_test/Debug/midithru rm -f pm_test/Debug/qtest pm_test/Debug/mm rm -f pm_test/Release/test pm_test/Release/sysex pm_test/Release/midithread rm -f pm_test/Release/latency pm_test/Release/midithru rm -f pm_test/Release/qtest pm_test/Release/mm rm -f pm_java/*/*.class rm -f pm_java/pmjni/jportmidi_JPortMidiApi_PortMidiStream.h backup: cleanest cd ..; zip -r portmidi.zip portmidi install: porttime/porttime.h pm_common/portmidi.h \ $(CONFIG)/libportmidi.dylib install porttime/porttime.h $(PF)/include/ install pm_common/portmidi.h $(PF)/include install $(CONFIG)/libportmidi.dylib $(PF)/lib/ # note - this uses xcode to build and install portmidi universal binaries install-with-xcode: sudo xcodebuild -project pm_mac/pm_mac.xcodeproj \ -configuration Release install DSTROOT=/ ##### build pmdefault ###### pm_java/pmjni/jportmidi_JPortMidiApi.h: pm_java/jportmidi/JPortMidiApi.class cd pm_java; javah jportmidi.JPortMidiApi mv pm_java/jportmidi_JportMidiApi.h pm_java/pmjni JAVASRC = pmdefaults/PmDefaultsFrame.java \ pmdefaults/PmDefaults.java \ jportmidi/JPortMidiApi.java jportmidi/JPortMidi.java \ jportmidi/JPortMidiException.java # this compiles ALL of the java code pm_java/jportmidi/JPortMidiApi.class: $(JAVASRC:%=pm_java/%) cd pm_java; javac $(JAVASRC) $(CONFIG)/libpmjni.dylib: mkdir -p $(CONFIG) cd $(CONFIG); make -f ../pm_mac/$(MAKEFILE) pmdefaults: $(CONFIG)/libpmjni.dylib pm_java/jportmidi/JPortMidiApi.class ifeq ($(CONFIG),Debug) echo "Error: you cannot build pmdefaults in a Debug configuration \n\ You should use configuration=Release in the Makefile command line. " @exit 2 endif xcodebuild -project pm_mac/pm_mac.xcodeproj \ -configuration Release -target PmDefaults echo "pmdefaults java application is made" ###### test plist reader ####### PLHDR = pm_mac/readbinaryplist.h PLSRC = pm_mac/plisttest.c pm_mac/readbinaryplist.c pm_mac/plisttest: $(PLHDR) $(PLSRC) cc $(VFLAGS) -Ipm_mac \ -I/Developer/Headers/FlatCarbon \ -I/System/Library/Frameworks/CoreFoundation.framework/Headers \ -I/System/Library/Frameworks/CoreServices.framework/Headers \ $(PLSRC) -o pm_mac/$(CONFIG)/plisttest \ -framework CoreFoundation -framework CoreServices portmidi/pm_mac/pmmac.h0000755000000000000000000000015310463413276014115 0ustar rootroot/* pmmac.h */ extern PmDeviceID pm_default_input_device_id; extern PmDeviceID pm_default_output_device_id;portmidi/pm_mac/pmmac.c0000755000000000000000000000264511123543562014114 0ustar rootroot/* pmmac.c -- PortMidi os-dependent code */ /* This file only needs to implement: pm_init(), which calls various routines to register the available midi devices, Pm_GetDefaultInputDeviceID(), and Pm_GetDefaultOutputDeviceID(). It is seperate from pmmacosxcm because we might want to register non-CoreMIDI devices. */ #include "stdlib.h" #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #include "pmmacosxcm.h" PmDeviceID pm_default_input_device_id = -1; PmDeviceID pm_default_output_device_id = -1; void pm_init() { PmError err = pm_macosxcm_init(); // this is set when we return to Pm_Initialize, but we need it // now in order to (successfully) call Pm_CountDevices() pm_initialized = TRUE; if (!err) { pm_default_input_device_id = find_default_device( "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE, pm_default_input_device_id); pm_default_output_device_id = find_default_device( "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE, pm_default_output_device_id); } } void pm_term(void) { pm_macosxcm_term(); } PmDeviceID Pm_GetDefaultInputDeviceID() { Pm_Initialize(); return pm_default_input_device_id; } PmDeviceID Pm_GetDefaultOutputDeviceID() { Pm_Initialize(); return pm_default_output_device_id; } void *pm_alloc(size_t s) { return malloc(s); } void pm_free(void *ptr) { free(ptr); } portmidi/pm_mac/finddefault.c0000644000000000000000000000342311206024702015264 0ustar rootroot/* finddefault.c -- find_default_device() implementation Roger Dannenberg, June 2008 */ #include #include #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #include "pmmacosxcm.h" #include "readbinaryplist.h" /* Parse preference files, find default device, search devices -- This parses the preference file(s) once for input and once for output, which is inefficient but much simpler to manage. Note that using the readbinaryplist.c module, you cannot keep two plist files (user and system) open at once (due to a simple memory management scheme). */ PmDeviceID find_default_device(char *path, int input, PmDeviceID id) /* path -- the name of the preference we are searching for input -- true iff this is an input device id -- current default device id returns matching device id if found, otherwise id */ { static char *pref_file = "com.apple.java.util.prefs.plist"; char *pref_str = NULL; // read device preferences value_ptr prefs = bplist_read_user_pref(pref_file); if (prefs) { value_ptr pref_val = value_dict_lookup_using_path(prefs, path); if (pref_val) { pref_str = value_get_asciistring(pref_val); } } if (!pref_str) { bplist_free_data(); /* look elsewhere */ prefs = bplist_read_system_pref(pref_file); if (prefs) { value_ptr pref_val = value_dict_lookup_using_path(prefs, path); if (pref_val) { pref_str = value_get_asciistring(pref_val); } } } if (pref_str) { /* search devices for match */ int i = pm_find_default_device(pref_str, input); if (i != pmNoDevice) { id = i; } } if (prefs) { bplist_free_data(); } return id; } portmidi/pm_mac/pmmacosxcm.c0000755000000000000000000010023111445664134015162 0ustar rootroot/* * Platform interface to the MacOS X CoreMIDI framework * * Jon Parise * and subsequent work by Andrew Zeldis and Zico Kolter * and Roger B. Dannenberg * * $Id: pmmacosx.c,v 1.17 2002/01/27 02:40:40 jon Exp $ */ /* Notes: since the input and output streams are represented by MIDIEndpointRef values and almost no other state, we store the MIDIEndpointRef on descriptors[midi->device_id].descriptor. The only other state we need is for errors: we need to know if there is an error and if so, what is the error text. We use a structure with two kinds of host error: "error" and "callback_error". That way, asynchronous callbacks do not interfere with other error information. OS X does not seem to have an error-code-to-text function, so we will just use text messages instead of error codes. */ #include //#define CM_DEBUG 1 #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #include "porttime.h" #include "pmmac.h" #include "pmmacosxcm.h" #include #include #include #include #include #include #define PACKET_BUFFER_SIZE 1024 /* maximum overall data rate (OS X limit is 15000 bytes/second) */ #define MAX_BYTES_PER_S 14000 /* Apple reports that packets are dropped when the MIDI bytes/sec exceeds 15000. This is computed by "tracking the number of MIDI bytes scheduled into 1-second buckets over the last six seconds and averaging these counts." This is apparently based on timestamps, not on real time, so we have to avoid constructing packets that schedule high speed output even if the actual writes are delayed (which was my first solution). The LIMIT_RATE symbol, if defined, enables code to modify timestamps as follows: After each packet is formed, the next allowable timestamp is computed as this_packet_time + this_packet_len * delay_per_byte This is the minimum timestamp allowed in the next packet. Note that this distorts accurate timestamps somewhat. */ #define LIMIT_RATE 1 #define SYSEX_BUFFER_SIZE 128 #define VERBOSE_ON 1 #define VERBOSE if (VERBOSE_ON) #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 #define MIDI_STATUS_MASK 0x80 // "Ref"s are pointers on 32-bit machines and ints on 64 bit machines // NULL_REF is our representation of either 0 or NULL #ifdef __LP64__ #define NULL_REF 0 #else #define NULL_REF NULL #endif static MIDIClientRef client = NULL_REF; /* Client handle to the MIDI server */ static MIDIPortRef portIn = NULL_REF; /* Input port handle */ static MIDIPortRef portOut = NULL_REF; /* Output port handle */ extern pm_fns_node pm_macosx_in_dictionary; extern pm_fns_node pm_macosx_out_dictionary; typedef struct midi_macosxcm_struct { PmTimestamp sync_time; /* when did we last determine delta? */ UInt64 delta; /* difference between stream time and real time in ns */ UInt64 last_time; /* last output time in host units*/ int first_message; /* tells midi_write to sychronize timestamps */ int sysex_mode; /* middle of sending sysex */ uint32_t sysex_word; /* accumulate data when receiving sysex */ uint32_t sysex_byte_count; /* count how many received */ char error[PM_HOST_ERROR_MSG_LEN]; char callback_error[PM_HOST_ERROR_MSG_LEN]; Byte packetBuffer[PACKET_BUFFER_SIZE]; MIDIPacketList *packetList; /* a pointer to packetBuffer */ MIDIPacket *packet; Byte sysex_buffer[SYSEX_BUFFER_SIZE]; /* temp storage for sysex data */ MIDITimeStamp sysex_timestamp; /* timestamp to use with sysex data */ /* allow for running status (is running status possible here? -rbd): -cpr */ unsigned char last_command; int32_t last_msg_length; /* limit midi data rate (a CoreMidi requirement): */ UInt64 min_next_time; /* when can the next send take place? */ int byte_count; /* how many bytes in the next packet list? */ Float64 us_per_host_tick; /* host clock frequency, units of min_next_time */ UInt64 host_ticks_per_byte; /* host clock units per byte at maximum rate */ } midi_macosxcm_node, *midi_macosxcm_type; /* private function declarations */ MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp); PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp); char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint); static int midi_length(int32_t msg) { int status, high, low; static int high_lengths[] = { 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */ 3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */ }; static int low_lengths[] = { 1, 2, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf8 */ 1, 1, 1, 1, 1, 1, 1, 1 /* 0xf9 through 0xff */ }; status = msg & 0xFF; high = status >> 4; low = status & 15; return (high != 0xF) ? high_lengths[high] : low_lengths[low]; } static PmTimestamp midi_synchronize(PmInternal *midi) { midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; UInt64 pm_stream_time_2 = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); PmTimestamp real_time; UInt64 pm_stream_time; /* if latency is zero and this is an output, there is no time reference and midi_synchronize should never be called */ assert(midi->time_proc); assert(!(midi->write_flag && midi->latency == 0)); do { /* read real_time between two reads of stream time */ pm_stream_time = pm_stream_time_2; real_time = (*midi->time_proc)(midi->time_info); pm_stream_time_2 = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); /* repeat if more than 0.5 ms has elapsed */ } while (pm_stream_time_2 > pm_stream_time + 500000); m->delta = pm_stream_time - ((UInt64) real_time * (UInt64) 1000000); m->sync_time = real_time; return real_time; } static void process_packet(MIDIPacket *packet, PmEvent *event, PmInternal *midi, midi_macosxcm_type m) { /* handle a packet of MIDI messages from CoreMIDI */ /* there may be multiple short messages in one packet (!) */ unsigned int remaining_length = packet->length; unsigned char *cur_packet_data = packet->data; while (remaining_length > 0) { if (cur_packet_data[0] == MIDI_SYSEX || /* are we in the middle of a sysex message? */ (m->last_command == 0 && !(cur_packet_data[0] & MIDI_STATUS_MASK))) { m->last_command = 0; /* no running status */ unsigned int amt = pm_read_bytes(midi, cur_packet_data, remaining_length, event->timestamp); remaining_length -= amt; cur_packet_data += amt; } else if (cur_packet_data[0] == MIDI_EOX) { /* this should never happen, because pm_read_bytes should * get and read all EOX bytes*/ midi->sysex_in_progress = FALSE; m->last_command = 0; } else if (cur_packet_data[0] & MIDI_STATUS_MASK) { /* compute the length of the next (short) msg in packet */ unsigned int cur_message_length = midi_length(cur_packet_data[0]); if (cur_message_length > remaining_length) { #ifdef DEBUG printf("PortMidi debug msg: not enough data"); #endif /* since there's no more data, we're done */ return; } m->last_msg_length = cur_message_length; m->last_command = cur_packet_data[0]; switch (cur_message_length) { case 1: event->message = Pm_Message(cur_packet_data[0], 0, 0); break; case 2: event->message = Pm_Message(cur_packet_data[0], cur_packet_data[1], 0); break; case 3: event->message = Pm_Message(cur_packet_data[0], cur_packet_data[1], cur_packet_data[2]); break; default: /* PortMIDI internal error; should never happen */ assert(cur_message_length == 1); return; /* give up on packet if continued after assert */ } pm_read_short(midi, event); remaining_length -= m->last_msg_length; cur_packet_data += m->last_msg_length; } else if (m->last_msg_length > remaining_length + 1) { /* we have running status, but not enough data */ #ifdef DEBUG printf("PortMidi debug msg: not enough data in CoreMIDI packet"); #endif /* since there's no more data, we're done */ return; } else { /* output message using running status */ switch (m->last_msg_length) { case 1: event->message = Pm_Message(m->last_command, 0, 0); break; case 2: event->message = Pm_Message(m->last_command, cur_packet_data[0], 0); break; case 3: event->message = Pm_Message(m->last_command, cur_packet_data[0], cur_packet_data[1]); break; default: /* last_msg_length is invalid -- internal PortMIDI error */ assert(m->last_msg_length == 1); } pm_read_short(midi, event); remaining_length -= (m->last_msg_length - 1); cur_packet_data += (m->last_msg_length - 1); } } } /* called when MIDI packets are received */ static void readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon) { PmInternal *midi; midi_macosxcm_type m; PmEvent event; MIDIPacket *packet; unsigned int packetIndex; uint32_t now; unsigned int status; #ifdef CM_DEBUG printf("readProc: numPackets %d: ", newPackets->numPackets); #endif /* Retrieve the context for this connection */ midi = (PmInternal *) connRefCon; m = (midi_macosxcm_type) midi->descriptor; assert(m); /* synchronize time references every 100ms */ now = (*midi->time_proc)(midi->time_info); if (m->first_message || m->sync_time + 100 /*ms*/ < now) { /* time to resync */ now = midi_synchronize(midi); m->first_message = FALSE; } packet = (MIDIPacket *) &newPackets->packet[0]; /* printf("readproc packet status %x length %d\n", packet->data[0], packet->length); */ for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) { /* Set the timestamp and dispatch this message */ event.timestamp = (PmTimestamp) /* explicit conversion */ ( (AudioConvertHostTimeToNanos(packet->timeStamp) - m->delta) / (UInt64) 1000000); status = packet->data[0]; /* process packet as sysex data if it begins with MIDI_SYSEX, or MIDI_EOX or non-status byte with no running status */ #ifdef CM_DEBUG printf(" %d", packet->length); #endif if (status == MIDI_SYSEX || status == MIDI_EOX || ((!(status & MIDI_STATUS_MASK)) && !m->last_command)) { /* previously was: !(status & MIDI_STATUS_MASK)) { * but this could mistake running status for sysex data */ /* reset running status data -cpr */ m->last_command = 0; m->last_msg_length = 0; /* printf("sysex packet length: %d\n", packet->length); */ pm_read_bytes(midi, packet->data, packet->length, event.timestamp); } else { process_packet(packet, &event, midi, m); } packet = MIDIPacketNext(packet); } #ifdef CM_DEBUG printf("\n"); #endif } static PmError midi_in_open(PmInternal *midi, void *driverInfo) { MIDIEndpointRef endpoint; midi_macosxcm_type m; OSStatus macHostError; /* insure that we have a time_proc for timing */ if (midi->time_proc == NULL) { if (!Pt_Started()) Pt_Start(1, 0, 0); /* time_get does not take a parameter, so coerce */ midi->time_proc = (PmTimeProcPtr) Pt_Time; } endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor; if (endpoint == NULL_REF) { return pmInvalidDeviceId; } m = (midi_macosxcm_type) pm_alloc(sizeof(midi_macosxcm_node)); /* create */ midi->descriptor = m; if (!m) { return pmInsufficientMemory; } m->error[0] = 0; m->callback_error[0] = 0; m->sync_time = 0; m->delta = 0; m->last_time = 0; m->first_message = TRUE; m->sysex_mode = FALSE; m->sysex_word = 0; m->sysex_byte_count = 0; m->packetList = NULL; m->packet = NULL; m->last_command = 0; m->last_msg_length = 0; macHostError = MIDIPortConnectSource(portIn, endpoint, midi); if (macHostError != noErr) { pm_hosterror = macHostError; sprintf(pm_hosterror_text, "Host error %ld: MIDIPortConnectSource() in midi_in_open()", (long) macHostError); midi->descriptor = NULL; pm_free(m); return pmHostError; } return pmNoError; } static PmError midi_in_close(PmInternal *midi) { MIDIEndpointRef endpoint; OSStatus macHostError; PmError err = pmNoError; midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; if (!m) return pmBadPtr; endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor; if (endpoint == NULL_REF) { pm_hosterror = pmBadPtr; } /* shut off the incoming messages before freeing data structures */ macHostError = MIDIPortDisconnectSource(portIn, endpoint); if (macHostError != noErr) { pm_hosterror = macHostError; sprintf(pm_hosterror_text, "Host error %ld: MIDIPortDisconnectSource() in midi_in_close()", (long) macHostError); err = pmHostError; } midi->descriptor = NULL; pm_free(midi->descriptor); return err; } static PmError midi_out_open(PmInternal *midi, void *driverInfo) { midi_macosxcm_type m; m = (midi_macosxcm_type) pm_alloc(sizeof(midi_macosxcm_node)); /* create */ midi->descriptor = m; if (!m) { return pmInsufficientMemory; } m->error[0] = 0; m->callback_error[0] = 0; m->sync_time = 0; m->delta = 0; m->last_time = 0; m->first_message = TRUE; m->sysex_mode = FALSE; m->sysex_word = 0; m->sysex_byte_count = 0; m->packetList = (MIDIPacketList *) m->packetBuffer; m->packet = NULL; m->last_command = 0; m->last_msg_length = 0; m->min_next_time = 0; m->byte_count = 0; m->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency(); m->host_ticks_per_byte = (UInt64) (1000000.0 / (m->us_per_host_tick * MAX_BYTES_PER_S)); return pmNoError; } static PmError midi_out_close(PmInternal *midi) { midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; if (!m) return pmBadPtr; midi->descriptor = NULL; pm_free(midi->descriptor); return pmNoError; } static PmError midi_abort(PmInternal *midi) { PmError err = pmNoError; OSStatus macHostError; MIDIEndpointRef endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor; macHostError = MIDIFlushOutput(endpoint); if (macHostError != noErr) { pm_hosterror = macHostError; sprintf(pm_hosterror_text, "Host error %ld: MIDIFlushOutput()", (long) macHostError); err = pmHostError; } return err; } static PmError midi_write_flush(PmInternal *midi, PmTimestamp timestamp) { OSStatus macHostError; midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; MIDIEndpointRef endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor; assert(m); assert(endpoint); if (m->packet != NULL) { /* out of space, send the buffer and start refilling it */ /* before we can send, maybe delay to limit data rate. OS X allows * 15KB/s. */ UInt64 now = AudioGetCurrentHostTime(); if (now < m->min_next_time) { usleep((useconds_t) ((m->min_next_time - now) * m->us_per_host_tick)); } macHostError = MIDISend(portOut, endpoint, m->packetList); m->packet = NULL; /* indicate no data in packetList now */ m->min_next_time = now + m->byte_count * m->host_ticks_per_byte; m->byte_count = 0; if (macHostError != noErr) goto send_packet_error; } return pmNoError; send_packet_error: pm_hosterror = macHostError; sprintf(pm_hosterror_text, "Host error %ld: MIDISend() in midi_write()", (long) macHostError); return pmHostError; } static PmError send_packet(PmInternal *midi, Byte *message, unsigned int messageLength, MIDITimeStamp timestamp) { PmError err; midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; assert(m); /* printf("add %d to packet %p len %d\n", message[0], m->packet, messageLength); */ m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer), m->packet, timestamp, messageLength, message); m->byte_count += messageLength; if (m->packet == NULL) { /* out of space, send the buffer and start refilling it */ /* make midi->packet non-null to fool midi_write_flush into sending */ m->packet = (MIDIPacket *) 4; /* timestamp is 0 because midi_write_flush ignores timestamp since * timestamps are already in packets. The timestamp parameter is here * because other API's need it. midi_write_flush can be called * from system-independent code that must be cross-API. */ if ((err = midi_write_flush(midi, 0)) != pmNoError) return err; m->packet = MIDIPacketListInit(m->packetList); assert(m->packet); /* if this fails, it's a programming error */ m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer), m->packet, timestamp, messageLength, message); assert(m->packet); /* can't run out of space on first message */ } return pmNoError; } static PmError midi_write_short(PmInternal *midi, PmEvent *event) { PmTimestamp when = event->timestamp; PmMessage what = event->message; MIDITimeStamp timestamp; UInt64 when_ns; midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; Byte message[4]; unsigned int messageLength; if (m->packet == NULL) { m->packet = MIDIPacketListInit(m->packetList); /* this can never fail, right? failure would indicate something unrecoverable */ assert(m->packet); } /* compute timestamp */ if (when == 0) when = midi->now; /* if latency == 0, midi->now is not valid. We will just set it to zero */ if (midi->latency == 0) when = 0; when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta; timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns); message[0] = Pm_MessageStatus(what); message[1] = Pm_MessageData1(what); message[2] = Pm_MessageData2(what); messageLength = midi_length(what); /* make sure we go foreward in time */ if (timestamp < m->min_next_time) timestamp = m->min_next_time; #ifdef LIMIT_RATE if (timestamp < m->last_time) timestamp = m->last_time; m->last_time = timestamp + messageLength * m->host_ticks_per_byte; #endif /* Add this message to the packet list */ return send_packet(midi, message, messageLength, timestamp); } static PmError midi_begin_sysex(PmInternal *midi, PmTimestamp when) { UInt64 when_ns; midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; assert(m); m->sysex_byte_count = 0; /* compute timestamp */ if (when == 0) when = midi->now; /* if latency == 0, midi->now is not valid. We will just set it to zero */ if (midi->latency == 0) when = 0; when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta; m->sysex_timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns); if (m->packet == NULL) { m->packet = MIDIPacketListInit(m->packetList); /* this can never fail, right? failure would indicate something unrecoverable */ assert(m->packet); } return pmNoError; } static PmError midi_end_sysex(PmInternal *midi, PmTimestamp when) { PmError err; midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; assert(m); /* make sure we go foreward in time */ if (m->sysex_timestamp < m->min_next_time) m->sysex_timestamp = m->min_next_time; #ifdef LIMIT_RATE if (m->sysex_timestamp < m->last_time) m->sysex_timestamp = m->last_time; m->last_time = m->sysex_timestamp + m->sysex_byte_count * m->host_ticks_per_byte; #endif /* now send what's in the buffer */ err = send_packet(midi, m->sysex_buffer, m->sysex_byte_count, m->sysex_timestamp); m->sysex_byte_count = 0; if (err != pmNoError) { m->packet = NULL; /* flush everything in the packet list */ return err; } return pmNoError; } static PmError midi_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp) { midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; assert(m); if (m->sysex_byte_count >= SYSEX_BUFFER_SIZE) { PmError err = midi_end_sysex(midi, timestamp); if (err != pmNoError) return err; } m->sysex_buffer[m->sysex_byte_count++] = byte; return pmNoError; } static PmError midi_write_realtime(PmInternal *midi, PmEvent *event) { /* to send a realtime message during a sysex message, first flush all pending sysex bytes into packet list */ PmError err = midi_end_sysex(midi, 0); if (err != pmNoError) return err; /* then we can just do a normal midi_write_short */ return midi_write_short(midi, event); } static unsigned int midi_has_host_error(PmInternal *midi) { midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; return (m->callback_error[0] != 0) || (m->error[0] != 0); } static void midi_get_host_error(PmInternal *midi, char *msg, unsigned int len) { midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor; msg[0] = 0; /* initialize to empty string */ if (m) { /* make sure there is an open device to examine */ if (m->error[0]) { strncpy(msg, m->error, len); m->error[0] = 0; /* clear the error */ } else if (m->callback_error[0]) { strncpy(msg, m->callback_error, len); m->callback_error[0] = 0; /* clear the error */ } msg[len - 1] = 0; /* make sure string is terminated */ } } MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp) { UInt64 nanos; if (timestamp <= 0) { return (MIDITimeStamp)0; } else { nanos = (UInt64)timestamp * (UInt64)1000000; return (MIDITimeStamp)AudioConvertNanosToHostTime(nanos); } } PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp) { UInt64 nanos; nanos = AudioConvertHostTimeToNanos(timestamp); return (PmTimestamp)(nanos / (UInt64)1000000); } // // Code taken from http://developer.apple.com/qa/qa2004/qa1374.html ////////////////////////////////////// // Obtain the name of an endpoint without regard for whether it has connections. // The result should be released by the caller. CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal) { CFMutableStringRef result = CFStringCreateMutable(NULL, 0); CFStringRef str; // begin with the endpoint's name str = NULL; MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &str); if (str != NULL) { CFStringAppend(result, str); CFRelease(str); } MIDIEntityRef entity = NULL_REF; MIDIEndpointGetEntity(endpoint, &entity); if (entity == NULL_REF) // probably virtual return result; if (CFStringGetLength(result) == 0) { // endpoint name has zero length -- try the entity str = NULL; MIDIObjectGetStringProperty(entity, kMIDIPropertyName, &str); if (str != NULL) { CFStringAppend(result, str); CFRelease(str); } } // now consider the device's name MIDIDeviceRef device = NULL_REF; MIDIEntityGetDevice(entity, &device); if (device == NULL_REF) return result; str = NULL; MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str); if (CFStringGetLength(result) == 0) { CFRelease(result); return str; } if (str != NULL) { // if an external device has only one entity, throw away // the endpoint name and just use the device name if (isExternal && MIDIDeviceGetNumberOfEntities(device) < 2) { CFRelease(result); return str; } else { if (CFStringGetLength(str) == 0) { CFRelease(str); return result; } // does the entity name already start with the device name? // (some drivers do this though they shouldn't) // if so, do not prepend if (CFStringCompareWithOptions( result, /* endpoint name */ str /* device name */, CFRangeMake(0, CFStringGetLength(str)), 0) != kCFCompareEqualTo) { // prepend the device name to the entity name if (CFStringGetLength(result) > 0) CFStringInsert(result, 0, CFSTR(" ")); CFStringInsert(result, 0, str); } CFRelease(str); } } return result; } // Obtain the name of an endpoint, following connections. // The result should be released by the caller. static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint) { CFMutableStringRef result = CFStringCreateMutable(NULL, 0); CFStringRef str; OSStatus err; long i; // Does the endpoint have connections? CFDataRef connections = NULL; long nConnected = 0; bool anyStrings = false; err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID, &connections); if (connections != NULL) { // It has connections, follow them // Concatenate the names of all connected devices nConnected = CFDataGetLength(connections) / (int32_t) sizeof(MIDIUniqueID); if (nConnected) { const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections)); for (i = 0; i < nConnected; ++i, ++pid) { MIDIUniqueID id = EndianS32_BtoN(*pid); MIDIObjectRef connObject; MIDIObjectType connObjectType; err = MIDIObjectFindByUniqueID(id, &connObject, &connObjectType); if (err == noErr) { if (connObjectType == kMIDIObjectType_ExternalSource || connObjectType == kMIDIObjectType_ExternalDestination) { // Connected to an external device's endpoint (10.3 and later). str = EndpointName((MIDIEndpointRef)(connObject), true); } else { // Connected to an external device (10.2) (or something else, catch-all) str = NULL; MIDIObjectGetStringProperty(connObject, kMIDIPropertyName, &str); } if (str != NULL) { if (anyStrings) CFStringAppend(result, CFSTR(", ")); else anyStrings = true; CFStringAppend(result, str); CFRelease(str); } } } } CFRelease(connections); } if (anyStrings) return result; // Here, either the endpoint had no connections, or we failed to obtain names for any of them. return EndpointName(endpoint, false); } char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint) { #ifdef OLDCODE MIDIEntityRef entity; MIDIDeviceRef device; CFStringRef endpointName = NULL; CFStringRef deviceName = NULL; #endif CFStringRef fullName = NULL; CFStringEncoding defaultEncoding; char* newName; /* get the default string encoding */ defaultEncoding = CFStringGetSystemEncoding(); fullName = ConnectedEndpointName(endpoint); #ifdef OLDCODE /* get the entity and device info */ MIDIEndpointGetEntity(endpoint, &entity); MIDIEntityGetDevice(entity, &device); /* create the nicely formated name */ MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &endpointName); MIDIObjectGetStringProperty(device, kMIDIPropertyName, &deviceName); if (deviceName != NULL) { fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@"), deviceName, endpointName); } else { fullName = endpointName; } #endif /* copy the string into our buffer */ newName = (char *) malloc(CFStringGetLength(fullName) + 1); CFStringGetCString(fullName, newName, CFStringGetLength(fullName) + 1, defaultEncoding); /* clean up */ #ifdef OLDCODE if (endpointName) CFRelease(endpointName); if (deviceName) CFRelease(deviceName); #endif if (fullName) CFRelease(fullName); return newName; } pm_fns_node pm_macosx_in_dictionary = { none_write_short, none_sysex, none_sysex, none_write_byte, none_write_short, none_write_flush, none_synchronize, midi_in_open, midi_abort, midi_in_close, success_poll, midi_has_host_error, midi_get_host_error, }; pm_fns_node pm_macosx_out_dictionary = { midi_write_short, midi_begin_sysex, midi_end_sysex, midi_write_byte, midi_write_realtime, midi_write_flush, midi_synchronize, midi_out_open, midi_abort, midi_out_close, success_poll, midi_has_host_error, midi_get_host_error, }; PmError pm_macosxcm_init(void) { ItemCount numInputs, numOutputs, numDevices; MIDIEndpointRef endpoint; int i; OSStatus macHostError; char *error_text; /* Determine the number of MIDI devices on the system */ numDevices = MIDIGetNumberOfDevices(); numInputs = MIDIGetNumberOfSources(); numOutputs = MIDIGetNumberOfDestinations(); /* Return prematurely if no devices exist on the system Note that this is not an error. There may be no devices. Pm_CountDevices() will return zero, which is correct and useful information */ if (numDevices <= 0) { return pmNoError; } /* Initialize the client handle */ macHostError = MIDIClientCreate(CFSTR("PortMidi"), NULL, NULL, &client); if (macHostError != noErr) { error_text = "MIDIClientCreate() in pm_macosxcm_init()"; goto error_return; } /* Create the input port */ macHostError = MIDIInputPortCreate(client, CFSTR("Input port"), readProc, NULL, &portIn); if (macHostError != noErr) { error_text = "MIDIInputPortCreate() in pm_macosxcm_init()"; goto error_return; } /* Create the output port */ macHostError = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut); if (macHostError != noErr) { error_text = "MIDIOutputPortCreate() in pm_macosxcm_init()"; goto error_return; } /* Iterate over the MIDI input devices */ for (i = 0; i < numInputs; i++) { endpoint = MIDIGetSource(i); if (endpoint == NULL_REF) { continue; } /* set the first input we see to the default */ if (pm_default_input_device_id == -1) pm_default_input_device_id = pm_descriptor_index; /* Register this device with PortMidi */ pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint), TRUE, (void *) (long) endpoint, &pm_macosx_in_dictionary); } /* Iterate over the MIDI output devices */ for (i = 0; i < numOutputs; i++) { endpoint = MIDIGetDestination(i); if (endpoint == NULL_REF) { continue; } /* set the first output we see to the default */ if (pm_default_output_device_id == -1) pm_default_output_device_id = pm_descriptor_index; /* Register this device with PortMidi */ pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint), FALSE, (void *) (long) endpoint, &pm_macosx_out_dictionary); } return pmNoError; error_return: pm_hosterror = macHostError; sprintf(pm_hosterror_text, "Host error %ld: %s\n", (long) macHostError, error_text); pm_macosxcm_term(); /* clear out any opened ports */ return pmHostError; } void pm_macosxcm_term(void) { if (client != NULL_REF) MIDIClientDispose(client); if (portIn != NULL_REF) MIDIPortDispose(portIn); if (portOut != NULL_REF) MIDIPortDispose(portOut); } portmidi/pm_mac/readbinaryplist.h0000644000000000000000000000372311310172344016205 0ustar rootroot/* readbinaryplist.h -- header to read preference files Roger B. Dannenberg, Jun 2008 */ #include /* for uint8_t ... */ #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define MAX_KEY_SIZE 256 enum { // Object tags (high nybble) kTAG_SIMPLE = 0x00, // Null, true, false, filler, or invalid kTAG_INT = 0x10, kTAG_REAL = 0x20, kTAG_DATE = 0x30, kTAG_DATA = 0x40, kTAG_ASCIISTRING = 0x50, kTAG_UNICODESTRING = 0x60, kTAG_UID = 0x80, kTAG_ARRAY = 0xA0, kTAG_DICTIONARY = 0xD0, // "simple" object values kVALUE_NULL = 0x00, kVALUE_FALSE = 0x08, kVALUE_TRUE = 0x09, kVALUE_FILLER = 0x0F, kVALUE_FULLDATETAG = 0x33 // Dates are tagged with a whole byte. }; typedef struct pldata_struct { uint8_t *data; size_t len; } pldata_node, *pldata_ptr; typedef struct array_struct { struct value_struct **array; uint64_t length; } array_node, *array_ptr; // a dict_node is a list of pairs typedef struct dict_struct { struct value_struct *key; struct value_struct *value; struct dict_struct *next; } dict_node, *dict_ptr; // an value_node is a value with a tag telling the type typedef struct value_struct { int tag; union { int64_t integer; uint64_t uinteger; double real; char *string; pldata_ptr data; array_ptr array; struct dict_struct *dict; }; } value_node, *value_ptr; value_ptr bplist_read_file(char *filename); value_ptr bplist_read_user_pref(char *filename); value_ptr bplist_read_system_pref(char *filename); void bplist_free_data(); /*************** functions for accessing values ****************/ char *value_get_asciistring(value_ptr v); value_ptr value_dict_lookup_using_string(value_ptr v, char *key); value_ptr value_dict_lookup_using_path(value_ptr v, char *path); /*************** functions for debugging ***************/ void plist_print(value_ptr v); portmidi/pm_mac/README_MAC.txt0000644000000000000000000001263011450076424015022 0ustar rootrootREADME_MAC.txt for PortMidi Roger Dannenberg 20 nov 2009 revised 20 Sep 2010 for Xcode 3.2.4 and CMake 8.2-2 To build PortMidi for Mac OS X, you must install Xcode and CMake. CMake can build either command-line Makefiles or Xcode projects. These approaches are described in separate sections below. ==== CLEANING UP ==== (Skip this for now, but later you might want start from a clean slate.) Start in the portmedia/portmidi directory. make -f pm_mac/Makefile.osx clean will remove .o, CMakeFiles, and other intermediate files. Using "cleaner" instead of "clean" will also remove jni-related intermediate files. Using "cleanest" instead of "clean" or "cleaner" will also remove application binaries and the portmidi libraries. (It will not uninstall anything, however.) ==== USING CMAKE (AND COMMAND LINE TOOLS) ==== Start in the portmedia/portmidi directory. make -f pm_mac/Makefile.osx (Begin note: make will invoke cmake to build a Makefile and then make to build portmidi. This extra level allows you to correctly build both Release and Debug versions. Release is the default, so to get the Debug version, use: make -f pm_mac/Makefile.osx configuration=Debug ) Release version executables and libraries are now in portmedia/portmidi/Release Debug version executables and libraries are created in portmedia/portmidi/Debug The Debug versions are compiled with PM_CHECK_ERRORS which prints an error message and aborts when an error code is returned by PortMidi functions. This is useful for small command line applications. Otherwise, you should check and handle error returns in your program. You can install portmidi as follows: cd Release; sudo make install This will install /usr/local/include/{portmidi.h, porttime.h} and /usr/local/lib/{libportmidi.dylib, libportmidi_s.a, libpmjni.dylib} You should now make the pmdefaults.app: make -f pm_mac/Makefile.osx pmdefaults NOTE: pmdefaults.app will be in pm_mac/Release/. Please copy pmdefaults.app to your Applications folder or wherever you would normally expect to find it. ==== USING CMAKE TO BUILD Xcode PROJECT ==== Before you can use Xcode, you need a portmidi.xcodeproj file. CMake builds a location-dependent Xcode project, so unfortunately it is not easy to provide an Xcode project that is ready to use. Therefore, you should make your own. Once you have it, you can use it almost like any other Xcode project, and you will not have to go back to CMake. (1) Install CMake if you do not have it already. (2) Open portmedia/portmidi/CMakeLists.txt with CMake (3) Use Configure and Generate buttons (4) This creates portmedia/portmidi/portmidi.xcodeproj. Note: You will also use pm_mac/pm_mac.xcodeproj, which is not generated by CMake. (5) Open portmidi/portmidi.xcodeproj with Xcode and build what you need. The simplest thing is to build the ALL_BUILD target. The default will be to build the Debug version, but you may want to change this to Release. NOTE: ALL_BUILD may report errors. Try simply building again or rebuilding specific targets that fail until they build without errors. There appears to be a race condition or missing dependencies in the build system. The Debug version is compiled with PM_CHECK_ERRORS, and the Release version is not. PM_CHECK_ERRORS will print an error message and exit your program if any error is returned from a call into PortMidi. CMake (currently) also creates MinSizRel and RelWithDebInfo versions, but only because I cannot figure out how to disable them. You will probably want the application PmDefaults, which sets default MIDI In and Out devices for PortMidi. You may also want to build a Java application using PortMidi. Since I have not figured out how to use CMake to make an OS X Java application, use pm_mac/pm_mac.xcodeproj as follows: (6) open pm_mac/pm_mac.xcodeproj (7) pm_java/pmjni/portmidi_JportmidiApi.h is needed by libpmjni.jnilib, the Java native interface library. Since portmidi_JportmidiApi.h is included with PortMidi, you can skip to step 8, but if you really want to rebuild everything from scratch, build the JPortMidiHeaders project first, and continue with step 8: (8) If you did not build libpmjni.dylib using portmidi.xcodeproj, do it now. (It depends on portmidi_JportmidiApi.h, and the PmDefaults project depends on libpmjni.dylib.) (9) Returning to pm_mac.xcodeproj, build the PmDefaults program. (10) If you wish, copy pm_mac/build/Deployment/PmDefaults.app to your applications folder. (11) If you want to install libportmidi.dylib, first make it with Xcode, then sudo make -f pm_mac/Makefile.osx install This command will install /usr/local/include/{porttime.h, portmidi.h} and /usr/local/lib/libportmidi.dylib Note that the "install" function of xcode creates portmidi/Release and does not install the library to /usr/local/lib, so please use the command line installer. CHANGELOG 20-Sep-2010 Roger B. Dannenberg Adapted to Xcode 3.2.4 20-Nov-2009 Roger B. Dannenberg Added some install instructions 26-Sep-2009 Roger B. Dannenberg More changes for using CMake, Makefiles, XCode 20-Sep-2009 Roger B. Dannenberg Modifications for using CMake 14-Sep-2009 Roger B. Dannenberg Modifications for using CMake 17-Jan-2007 Roger B. Dannenberg Explicit instructions for Xcode 15-Jan-2007 Roger B. Dannenberg Changed instructions because of changes to Makefile.osx 07-Oct-2006 Roger B. Dannenberg Added directions for xcodebuild 29-aug-2006 Roger B. Dannenberg Updated this documentation. portmidi/pm_mac/pmdefaults/0000755000000000000000000000000011453601074015004 5ustar rootrootportmidi/pm_mac/pmdefaults/make/0000755000000000000000000000000011453601074015721 5ustar rootrootportmidi/pm_mac/pmdefaults/make/find-classrefs.sh0000755000000000000000000000227711445664134021202 0ustar rootroot#!/bin/sh # Prints all class references made by all classes in a Jar file # Depends on the output formatting of javap # create a temporary working directory dir=`mktemp -d $TMPDIR/classrefs.XXXXXX` asm_dump="$dir/asm_dump" all_classes="$dir/all_classes" # for each class in a Jar file, dump the full assembly javap -c -classpath "$1" `/usr/bin/jar tf "$1" | grep "\.class" | sort | xargs | sed -e 's/\.class//g'` > $asm_dump # dump the initial list of all classes in the Jar file /usr/bin/jar tf $1 | grep "\.class" | sed -e 's/\.class//g' >> $all_classes # dump all static class references cat $asm_dump | grep //class | awk -F"//class " '{print $2}' | sort | uniq >> $all_classes # dump all references to classes made in methods cat $asm_dump | grep //Method | awk -F"//Method " '{print $2}' | sort | uniq | grep "\." | awk -F"." '{print $1}' | sort | uniq >> $all_classes # dump all references to classes by direct field access cat $asm_dump | grep //Field | awk -F"//Field " '{print $2}' | sort | uniq | grep "\:L" | awk -F"\:L" '{print $2}' | sort | uniq | awk -F"\;" '{print $1}' >> $all_classes # sort and reformat sort $all_classes | uniq | grep -v "\"" | sed -e 's/\//\./g' # cleanup rm -rf $dir portmidi/pm_mac/pmdefaults/make/build.xml0000644000000000000000000000437611445664134017563 0ustar rootroot "Nothing to do for install-headers phase" portmidi/pm_mac/pmdefaults/resources/0000755000000000000000000000000011453601074017016 5ustar rootrootportmidi/pm_mac/pmdefaults/resources/English.lproj/0000755000000000000000000000000011453601074021534 5ustar rootrootportmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf0000644000000000000000000000054111445664134023655 0ustar rootroot{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \f0\b\fs24 \cf0 Author: \b0 \ Roger B. Dannenberg\ \ \b With special thanks to: \b0 \ National Science Foundation\ }portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings0000644000000000000000000000033411445664134025065 0ustar rootroot/* Localized versions of Info.plist keys */ NSHumanReadableCopyright = " Carnegie Mellon University, 2010";portmidi/pm_mac/pmdefaults/resources/Info.plist0000644000000000000000000000210511445664134020773 0ustar rootroot CFBundleDevelopmentRegion English CFBundleExecutable JavaApplicationStub CFBundleIconFile pmdefaults.icns CFBundleIdentifier CFBundleInfoDictionaryVersion 6.0 CFBundleName PmDefaults CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 1.0 CFBundleShortVersionString 1.0 Java ClassPath $JAVAROOT/pmdefaults.jar JVMVersion 1.5+ MainClass pmdefaults.PmDefaults Properties apple.laf.useScreenMenuBar true portmidi/pm_mac/pmdefaults/resources/Manifest0000644000000000000000000000004211445664134020512 0ustar rootrootMain-Class: pmdefaults/PmDefaults portmidi/pm_mac/pm_mac.xcodeproj/0000755000000000000000000000000011453601074016070 5ustar rootrootportmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj0000755000000000000000000006011411453600656021156 0ustar rootroot// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 44; objects = { /* Begin PBXAggregateTarget section */ 3D634CAB1247805C0020F829 /* JPortMidiHeaders */ = { isa = PBXAggregateTarget; buildConfigurationList = 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */; buildPhases = ( 3D634CAA1247805C0020F829 /* ShellScript */, ); dependencies = ( 3D634CB0124781580020F829 /* PBXTargetDependency */, ); name = JPortMidiHeaders; productName = JPortMidiHeaders; }; 3DE2142D124662AA0033C839 /* CopyJavaSources */ = { isa = PBXAggregateTarget; buildConfigurationList = 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */; buildPhases = ( 3DE2142C124662AA0033C839 /* CopyFiles */, ); comments = "The reason for copying files here is that the Compile Java target looks in a particular place for sources. It would be much better to simply have Compile Java look in the original location for all sources, but I don't know how to do that. -RBD\n"; dependencies = ( ); name = CopyJavaSources; productName = CopyJavaSources; }; 89D0F1C90F3B704E007831A7 /* PmDefaults */ = { isa = PBXAggregateTarget; buildConfigurationList = 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */; buildPhases = ( ); dependencies = ( 89D0F1D10F3B7062007831A7 /* PBXTargetDependency */, 89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */, 3DE21431124662C50033C839 /* PBXTargetDependency */, ); name = PmDefaults; productName = pmdefaults; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 3DE2137E124653FB0033C839 /* portmusic_logo.png */; }; 3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */; }; 3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137B1246538B0033C839 /* PmDefaults.java */; }; 3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21382124654DE0033C839 /* JPortMidiException.java */; }; 3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21381124654CF0033C839 /* JPortMidiApi.java */; }; 3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21380124654BC0033C839 /* JPortMidi.java */; }; 3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 3DE216101246ABE30033C839 /* libpmjni.dylib */; }; 3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3DE216901246C6410033C839 /* pmdefaults.icns */; }; 89C3F2920F5250A300B0048E /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 89C3F2900F5250A300B0048E /* Credits.rtf */; }; 89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 89D0F0210F392F20007831A7 /* InfoPlist.strings */; }; 89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */ = {isa = PBXBuildFile; fileRef = 89D0F03E0F39304A007831A7 /* JavaApplicationStub */; }; 89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 3D634CAF124781580020F829 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 89D0F1C90F3B704E007831A7; remoteInfo = PmDefaults; }; 3DE21430124662C50033C839 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 3DE2142D124662AA0033C839; remoteInfo = CopyJavaSources; }; 3DE2145D124666900033C839 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 3DE2142D124662AA0033C839; remoteInfo = CopyJavaSources; }; 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 8D1107260486CEB800E47090; remoteInfo = "Assemble Application"; }; 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 89D0F0480F393A6F007831A7; remoteInfo = "Compile Java"; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 3DE2142C124662AA0033C839 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "${PROJECT_DIR}/pmdefaults/src/java"; dstSubfolderSpec = 0; files = ( 3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */, 3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */, 3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */, 3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */, 3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; 89D0F0440F393070007831A7 /* Copy Executable */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 6; files = ( 89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */, ); name = "Copy Executable"; runOnlyForDeploymentPostprocessing = 0; }; 89D0F11F0F394189007831A7 /* Copy Java Resources */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 15; files = ( 89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */, 3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */, ); name = "Copy Java Resources"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 3DE2137B1246538B0033C839 /* PmDefaults.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaults.java; path = ../pm_java/pmdefaults/PmDefaults.java; sourceTree = SOURCE_ROOT; }; 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaultsFrame.java; path = ../pm_java/pmdefaults/PmDefaultsFrame.java; sourceTree = SOURCE_ROOT; }; 3DE2137E124653FB0033C839 /* portmusic_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = portmusic_logo.png; path = ../pm_java/pmdefaults/portmusic_logo.png; sourceTree = SOURCE_ROOT; }; 3DE21380124654BC0033C839 /* JPortMidi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidi.java; path = ../pm_java/jportmidi/JPortMidi.java; sourceTree = SOURCE_ROOT; }; 3DE21381124654CF0033C839 /* JPortMidiApi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiApi.java; path = ../pm_java/jportmidi/JPortMidiApi.java; sourceTree = SOURCE_ROOT; }; 3DE21382124654DE0033C839 /* JPortMidiException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiException.java; path = ../pm_java/jportmidi/JPortMidiException.java; sourceTree = SOURCE_ROOT; }; 3DE213841246555A0033C839 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = ""; }; 3DE21390124655760033C839 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; 3DE213BE1246557F0033C839 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; 3DE216101246ABE30033C839 /* libpmjni.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmjni.dylib; path = ../Release/libpmjni.dylib; sourceTree = SOURCE_ROOT; }; 3DE216901246C6410033C839 /* pmdefaults.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = pmdefaults.icns; path = ../pm_java/pmdefaults/pmdefaults.icns; sourceTree = SOURCE_ROOT; }; 89C3F2910F5250A300B0048E /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = ""; }; 89D0F0220F392F20007831A7 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 89D0F0230F392F20007831A7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89D0F03E0F39304A007831A7 /* JavaApplicationStub */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = JavaApplicationStub; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub; sourceTree = ""; }; 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaNativeFoundation.framework; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework; sourceTree = ""; }; 89D0F1390F3948A9007831A7 /* pmdefaults/make */ = {isa = PBXFileReference; lastKnownFileType = folder; path = pmdefaults/make; sourceTree = ""; }; 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = pmdefaults.jar; path = build/Release/pmdefaults.jar; sourceTree = SOURCE_ROOT; }; 89D0F1860F3A2442007831A7 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = ""; }; 8D1107320486CEB800E47090 /* PmDefaults.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PmDefaults.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 3DE213841246555A0033C839 /* CoreMIDI.framework */, 3DE21390124655760033C839 /* CoreFoundation.framework */, 3DE213BE1246557F0033C839 /* CoreAudio.framework */, 89D0F1860F3A2442007831A7 /* JavaVM.framework */, 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */, 8D1107320486CEB800E47090 /* PmDefaults.app */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* pmdefaults */ = { isa = PBXGroup; children = ( 3DE216101246ABE30033C839 /* libpmjni.dylib */, 89D0F0260F392F48007831A7 /* Source */, 89D0F0200F392F20007831A7 /* Resources */, 89D0F1390F3948A9007831A7 /* pmdefaults/make */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = pmdefaults; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 3DE2136A124652E20033C839 /* pm_java */ = { isa = PBXGroup; children = ( 3DE21379124653150033C839 /* pmdefaults */, 3DE2137A1246531D0033C839 /* jportmidi */, ); name = pm_java; path = ..; sourceTree = ""; }; 3DE21379124653150033C839 /* pmdefaults */ = { isa = PBXGroup; children = ( 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */, 3DE2137B1246538B0033C839 /* PmDefaults.java */, ); name = pmdefaults; sourceTree = ""; }; 3DE2137A1246531D0033C839 /* jportmidi */ = { isa = PBXGroup; children = ( 3DE21382124654DE0033C839 /* JPortMidiException.java */, 3DE21381124654CF0033C839 /* JPortMidiApi.java */, 3DE21380124654BC0033C839 /* JPortMidi.java */, ); name = jportmidi; sourceTree = ""; }; 89D0F0200F392F20007831A7 /* Resources */ = { isa = PBXGroup; children = ( 3DE216901246C6410033C839 /* pmdefaults.icns */, 3DE2137E124653FB0033C839 /* portmusic_logo.png */, 89C3F2900F5250A300B0048E /* Credits.rtf */, 89D0F0230F392F20007831A7 /* Info.plist */, 89D0F0210F392F20007831A7 /* InfoPlist.strings */, 89D0F03E0F39304A007831A7 /* JavaApplicationStub */, ); name = Resources; path = pmdefaults/resources; sourceTree = ""; }; 89D0F0260F392F48007831A7 /* Source */ = { isa = PBXGroup; children = ( 3DE2136A124652E20033C839 /* pm_java */, ); name = Source; path = pmdefaults/src; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXLegacyTarget section */ 89D0F0480F393A6F007831A7 /* Compile Java */ = { isa = PBXLegacyTarget; buildArgumentsString = "-e -f \"${SRCROOT}/make/build.xml\" -debug \"$ACTION\""; buildConfigurationList = 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */; buildPhases = ( ); buildToolPath = /usr/bin/ant; buildWorkingDirectory = ""; dependencies = ( 3DE2145E124666900033C839 /* PBXTargetDependency */, ); name = "Compile Java"; passBuildSettingsInEnvironment = 1; productName = "Compile Java"; }; /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ 8D1107260486CEB800E47090 /* Assemble Application */ = { isa = PBXNativeTarget; buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */; buildPhases = ( 89D0F0440F393070007831A7 /* Copy Executable */, 89D0F11F0F394189007831A7 /* Copy Java Resources */, 8D1107290486CEB800E47090 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Assemble Application"; productInstallPath = "$(HOME)/Applications"; productName = pmdefaults; productReference = 8D1107320486CEB800E47090 /* PmDefaults.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */; compatibilityVersion = "Xcode 3.0"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* pmdefaults */; projectDirPath = ""; projectRoot = ""; targets = ( 3D634CAB1247805C0020F829 /* JPortMidiHeaders */, 89D0F1C90F3B704E007831A7 /* PmDefaults */, 3DE2142D124662AA0033C839 /* CopyJavaSources */, 89D0F0480F393A6F007831A7 /* Compile Java */, 8D1107260486CEB800E47090 /* Assemble Application */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D1107290486CEB800E47090 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */, 89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */, 89C3F2920F5250A300B0048E /* Credits.rtf in Resources */, 3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3D634CAA1247805C0020F829 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "echo BUILT_PRODUCTS_DIR is ${BUILT_PRODUCTS_DIR}\njavah -classpath \"${BUILT_PRODUCTS_DIR}/pmdefaults.jar\" -force -o \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" \"jportmidi.JPortMidiApi\"\nmv \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" ../pm_java/pmjni/\necho \"Created ../pm_java/pmjni/jportmidi_JportMidiApi.h\"\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXTargetDependency section */ 3D634CB0124781580020F829 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 89D0F1C90F3B704E007831A7 /* PmDefaults */; targetProxy = 3D634CAF124781580020F829 /* PBXContainerItemProxy */; }; 3DE21431124662C50033C839 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3DE2142D124662AA0033C839 /* CopyJavaSources */; targetProxy = 3DE21430124662C50033C839 /* PBXContainerItemProxy */; }; 3DE2145E124666900033C839 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3DE2142D124662AA0033C839 /* CopyJavaSources */; targetProxy = 3DE2145D124666900033C839 /* PBXContainerItemProxy */; }; 89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D1107260486CEB800E47090 /* Assemble Application */; targetProxy = 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */; }; 89D0F1D10F3B7062007831A7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 89D0F0480F393A6F007831A7 /* Compile Java */; targetProxy = 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 89C3F2900F5250A300B0048E /* Credits.rtf */ = { isa = PBXVariantGroup; children = ( 89C3F2910F5250A300B0048E /* English */, ); name = Credits.rtf; sourceTree = ""; }; 89D0F0210F392F20007831A7 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 89D0F0220F392F20007831A7 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 3D634CAC1247805C0020F829 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; PRODUCT_NAME = JPortMidiHeaders; }; name = Debug; }; 3D634CAD1247805C0020F829 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; PRODUCT_NAME = JPortMidiHeaders; ZERO_LINK = NO; }; name = Release; }; 3DE2142E124662AB0033C839 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; PRODUCT_NAME = CopyJavaSources; }; name = Debug; }; 3DE2142F124662AB0033C839 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; PRODUCT_NAME = CopyJavaSources; ZERO_LINK = NO; }; name = Release; }; 89D0F0490F393A6F007831A7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = pmdefaults; SRCROOT = ./pmdefaults; }; name = Debug; }; 89D0F04A0F393A6F007831A7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = pmdefaults; SRCROOT = ./pmdefaults; }; name = Release; }; 89D0F1CA0F3B704F007831A7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = pmdefaults; }; name = Debug; }; 89D0F1CB0F3B704F007831A7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = pmdefaults; }; name = Release; }; C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = pmdefaults/resources/Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = pmdefaults; WRAPPER_EXTENSION = app; }; name = Debug; }; C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; INFOPLIST_FILE = pmdefaults/resources/Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = PmDefaults; WRAPPER_EXTENSION = app; }; name = Release; }; C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */ = { isa = XCConfigurationList; buildConfigurations = ( 3D634CAC1247805C0020F829 /* Debug */, 3D634CAD1247805C0020F829 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */ = { isa = XCConfigurationList; buildConfigurations = ( 3DE2142E124662AB0033C839 /* Debug */, 3DE2142F124662AB0033C839 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */ = { isa = XCConfigurationList; buildConfigurations = ( 89D0F0490F393A6F007831A7 /* Debug */, 89D0F04A0F393A6F007831A7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */ = { isa = XCConfigurationList; buildConfigurations = ( 89D0F1CA0F3B704F007831A7 /* Debug */, 89D0F1CB0F3B704F007831A7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4B08A954540054247B /* Debug */, C01FCF4C08A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4F08A954540054247B /* Debug */, C01FCF5008A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } portmidi/pm_mac/pmmacosxcm.h0000755000000000000000000000024711030706332015160 0ustar rootroot/* system-specific definitions */ PmError pm_macosxcm_init(void); void pm_macosxcm_term(void); PmDeviceID find_default_device(char *path, int input, PmDeviceID id); portmidi/pm_mac/readbinaryplist.c0000644000000000000000000010233411452617306016207 0ustar rootroot/* readbinaryplist.c -- Roger B. Dannenberg, Jun 2008 Based on ReadBinaryPList.m by Jens Ayton, 2007 Note that this code is intended to read preference files and has an upper bound on file size (currently 100MB) and assumes in some places that 32 bit offsets are sufficient. Here are his comments: Reader for binary property list files (version 00). This has been found to work on all 566 binary plists in my ~/Library/Preferences/ and /Library/Preferences/ directories. This probably does not provide full test coverage. It has also been found to provide different data to Apple's implementation when presented with a key-value archive. This is because Apple's implementation produces undocumented CFKeyArchiverUID objects. My implementation produces dictionaries instead, matching the in-file representation used in XML and OpenStep plists. See extract_uid(). Full disclosure: in implementing this software, I read one comment and one struct defintion in CFLite, Apple's implementation, which is under the APSL license. I also deduced the information about CFKeyArchiverUID from that code. However, none of the implementation was copied. Copyright (C) 2007 Jens Ayton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* A note about memory management: Strings and possibly other values are unique and because the values associated with IDs are cached, you end up with a directed graph rather than a tree. It is tricky to free the data because if you do a simple depth-first search to free nodes, you will free nodes twice. I decided to allocate memory from blocks of 1024 bytes and keep the blocks in a list associated with but private to this module. So the user should access this module by calling: bplist_read_file() or bplist_read_user_pref() or bplist_read_system_pref() which returns a value. When you are done with the value, call bplist_free_data() This will of course free the value_ptr returned by bplist_read_*() To deal with memory exhaustion (what happens when malloc returns NULL?), use setjmp/longjmp -- a single setjmp protects the whole parser, and allocate uses longjmp to abort. After abort, memory is freed and NULL is returned to caller. There is not much here in the way of error reporting. Memory is obtained by calling allocate which either returns the memory requested or calls longjmp, so callers don't have to check. */ #include #include #include #include #include #include #include "readbinaryplist.h" #include #define NO 0 #define YES 1 #define BOOL int #define MAXPATHLEN 256 /* there are 2 levels of error logging/printing: * BPLIST_LOG and BPLIST_LOG_VERBOSE * either or both can be set to non-zero to turn on * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG * is also true. * * In the code, logging is done by calling either * bplist_log() or bplist_log_verbose(), which take * parameters like printf but might be a no-op. */ /* #define BPLIST_LOG_VERBOSE 1 */ #if BPLIST_LOG_VERBOSE #ifndef BPLIST_LOG #define BPLIST_LOG 1 #endif #endif #if BPLIST_LOG #define bplist_log printf #else #define bplist_log(...) #endif #if BPLIST_LOG_VERBOSE #define bplist_log_verbose bplist_log #else #define bplist_log_verbose(...) #endif /********* MEMORY MANAGEMENT ********/ #define BLOCK_SIZE 1024 // memory is aligned to multiples of this; assume malloc automatically // aligns to this number and assume this number is > sizeof(void *) #define ALIGNMENT 8 static void *block_list = NULL; static char *free_ptr = NULL; static char *end_ptr = NULL; static jmp_buf abort_parsing; static void *allocate(size_t size) { void *result; if (free_ptr + size > end_ptr) { size_t how_much = BLOCK_SIZE; // align everything to 8 bytes if (size > BLOCK_SIZE - ALIGNMENT) { how_much = size + ALIGNMENT; } result = malloc(how_much); if (result == NULL) { /* serious problem */ longjmp(abort_parsing, 1); } *((void **)result) = block_list; block_list = result; free_ptr = ((char *) result) + ALIGNMENT; end_ptr = ((char *) result) + how_much; } // now, there is enough rooom at free_ptr result = free_ptr; free_ptr += size; return result; } void bplist_free_data() { while (block_list) { void *next = *(void **)block_list; free(block_list); block_list = next; } free_ptr = NULL; end_ptr = NULL; } // layout of trailer -- last 32 bytes in plist data uint8_t unused[6]; uint8_t offset_int_size; uint8_t object_ref_size; uint64_t object_count; uint64_t top_level_object; uint64_t offset_table_offset; enum { kHEADER_SIZE = 8, kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node), kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE }; static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00"; // map from UID key to previously parsed value typedef struct cache_struct { uint64_t key; value_ptr value; struct cache_struct *next; } cache_node, *cache_ptr; typedef struct bplist_info { uint64_t object_count; const uint8_t *data_bytes; uint64_t length; uint64_t offset_table_offset; uint8_t offset_int_size; uint8_t object_ref_size; cache_ptr cache; } bplist_info_node, *bplist_info_ptr; static value_ptr bplist_read_pldata(pldata_ptr data); static value_ptr bplist_read_pref(char *filename, OSType folder_type); static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size); static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index); static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize); static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef); static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset); static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset); value_ptr value_create() { value_ptr value = (value_ptr) allocate(sizeof(value_node)); return value; } void value_set_integer(value_ptr v, int64_t i) { v->tag = kTAG_INT; v->integer = i; } void value_set_real(value_ptr v, double d) { v->tag = kTAG_REAL; v->real = d; } // d is seconds since 1 January 2001 void value_set_date(value_ptr v, double d) { v->tag = kTAG_DATE; v->real = d; } void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) { v->tag = kTAG_ASCIISTRING; v->string = (char *) allocate(len + 1); memcpy(v->string, s, len); v->string[len] = 0; } void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) { v->tag = kTAG_UNICODESTRING; v->string = (char *) allocate(len + 1); memcpy(v->string, s, len); v->string[len] = 0; } void value_set_uid(value_ptr v, uint64_t uid) { v->tag = kTAG_UID; v->uinteger = uid; } // v->data points to a pldata that points to the actual bytes // the bytes are copied, so caller must free byte source (*data) void value_set_data(value_ptr v, const uint8_t *data, size_t len) { v->tag = kTAG_DATA; pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node)); pldata->data = (uint8_t *) allocate(len); memcpy(pldata->data, data, len); pldata->len = len; v->data = pldata; printf("value at %p gets data at %p\n", v, pldata); } // caller releases ownership of array to value_ptr v void value_set_array(value_ptr v, value_ptr *array, size_t length) { array_ptr a = (array_ptr) allocate(sizeof(array_node)); a->array = array; a->length = length; v->tag = kTAG_ARRAY; v->array = a; } // caller releases ownership of dict to value_ptr v void value_set_dict(value_ptr v, dict_ptr dict) { v->tag = kTAG_DICTIONARY; v->dict = dict; } // look up an objectref in the cache, a ref->value_ptr mapping value_ptr cache_lookup(cache_ptr cache, uint64_t ref) { while (cache) { if (cache->key == ref) { return cache->value; } cache = cache->next; } return NULL; } // insert an objectref and value in the cache void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value) { cache_ptr c = (cache_ptr) allocate(sizeof(cache_node)); c->key = ref; c->value = value; c->next = *cache; *cache = c; } // insert an objectref and value in a dictionary void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value) { dict_ptr d = (dict_ptr) allocate(sizeof(dict_node)); d->key = key; d->value = value; d->next = *dict; *dict = d; } BOOL is_binary_plist(pldata_ptr data) { if (data->len < kMINIMUM_SANE_SIZE) return NO; return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0; } value_ptr bplist_read_file(char *filename) { struct stat stbuf; pldata_node pldata; FILE *file; size_t n; value_ptr value; int rslt = stat(filename, &stbuf); if (rslt) { #if BPLIST_LOG perror("in stat"); #endif bplist_log("Could not stat %s, error %d\n", filename, rslt); return NULL; } // if file is >100MB, assume it is not a preferences file and give up if (stbuf.st_size > 100000000) { bplist_log("Large file %s encountered (%llu bytes) -- not read\n", filename, stbuf.st_size); return NULL; } pldata.len = (size_t) stbuf.st_size; // note: this is supposed to be malloc, not allocate. It is separate // from the graph structure, large, and easy to free right after // parsing. pldata.data = (uint8_t *) malloc(pldata.len); if (!pldata.data) { bplist_log("Could not allocate %lu bytes for %s\n", (unsigned long) pldata.len, filename); return NULL; } file = fopen(filename, "rb"); if (!file) { bplist_log("Could not open %s\n", filename); return NULL; } n = fread(pldata.data, 1, pldata.len, file); if (n != pldata.len) { bplist_log("Error reading from %s\n", filename); return NULL; } value = bplist_read_pldata(&pldata); free(pldata.data); return value; } value_ptr bplist_read_pref(char *filename, OSType folder_type) { FSRef prefdir; char cstr[MAXPATHLEN]; OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type, FALSE, &prefdir); if (err) { bplist_log("Error finding preferences folder: %d\n", err); return NULL; } err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1)); if (err) { bplist_log("Error making path name for preferences folder: %d\n", err); return NULL; } strlcat(cstr, "/", MAXPATHLEN); strlcat(cstr, filename, MAXPATHLEN); return bplist_read_file(cstr); } value_ptr bplist_read_system_pref(char *filename) { return bplist_read_pref(filename, kSystemPreferencesFolderType); } value_ptr bplist_read_user_pref(char *filename) { return bplist_read_pref(filename, kPreferencesFolderType); } // data is stored with high-order bytes first. // read from plist data in a machine-independent fashion // uint64_t convert_uint64(uint8_t *ptr) { uint64_t rslt = 0; int i; // shift in bytes, high-order first for (i = 0; i < sizeof(uint64_t); i++) { rslt <<= 8; rslt += ptr[i]; } return rslt; } value_ptr bplist_read_pldata(pldata_ptr data) { value_ptr result = NULL; bplist_info_node bplist; uint8_t *ptr; uint64_t top_level_object; int i; if (data == NULL) return NULL; if (!is_binary_plist(data)) { bplist_log("Bad binary plist: too short or invalid header.\n"); return NULL; } // read trailer ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE); bplist.offset_int_size = ptr[6]; bplist.object_ref_size = ptr[7]; bplist.object_count = convert_uint64(ptr + 8); top_level_object = convert_uint64(ptr + 16); bplist.offset_table_offset = convert_uint64(ptr + 24); // Basic sanity checks if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 || bplist.object_ref_size < 1 || bplist.object_ref_size > 8 || bplist.offset_table_offset < kHEADER_SIZE) { bplist_log("Bad binary plist: trailer declared insane.\n"); return NULL; } // Ensure offset table is inside file uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count; if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE > data->len) { bplist_log("Bad binary plist: offset table overlaps end of container.\n"); return NULL; } bplist.data_bytes = data->data; bplist.length = data->len; bplist.cache = NULL; /* dictionary is empty */ bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n", bplist.object_count, bplist.offset_int_size, bplist.object_ref_size); /* at this point, we are ready to do some parsing which allocates memory for the result data structure. If memory allocation (using allocate fails, a longjmp will return to here and we simply give up */ i = setjmp(abort_parsing); if (i == 0) { result = extract_object(&bplist, top_level_object); } else { bplist_log("allocate() failed to allocate memory. Giving up.\n"); result = NULL; } if (!result) { bplist_free_data(); } return result; } static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef) { uint64_t offset; value_ptr result = NULL; uint8_t objectTag; if (objectRef >= bplist->object_count) { // Out-of-range object reference. bplist_log("Bad binary plist: object index is out of range.\n"); return NULL; } // Use cached object if it exists result = cache_lookup(bplist->cache, objectRef); if (result != NULL) return result; // Otherwise, find object in file. offset = read_offset(bplist, objectRef); if (offset > bplist->length) { // Out-of-range offset. bplist_log("Bad binary plist: object outside container.\n"); return NULL; } objectTag = *(bplist->data_bytes + offset); switch (objectTag & 0xF0) { case kTAG_SIMPLE: result = extract_simple(bplist, offset); break; case kTAG_INT: result = extract_int(bplist, offset); break; case kTAG_REAL: result = extract_real(bplist, offset); break; case kTAG_DATE: result = extract_date(bplist, offset); break; case kTAG_DATA: result = extract_data(bplist, offset); break; case kTAG_ASCIISTRING: result = extract_ascii_string(bplist, offset); break; case kTAG_UNICODESTRING: result = extract_unicode_string(bplist, offset); break; case kTAG_UID: result = extract_uid(bplist, offset); break; case kTAG_ARRAY: result = extract_array(bplist, offset); break; case kTAG_DICTIONARY: result = extract_dictionary(bplist, offset); break; default: // Unknown tag. bplist_log("Bad binary plist: unknown tag 0x%X.\n", (objectTag & 0x0F) >> 4); result = NULL; } // Cache and return result. if (result != NULL) cache_insert(&bplist->cache, objectRef, result); return result; } static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size) { assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 && offset + size <= bplist->length); uint64_t result = 0; const uint8_t *byte = bplist->data_bytes + offset; do { // note that ints seem to be high-order first result = (result << 8) | *byte++; } while (--size); return result; } static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index) { assert(index < bplist->object_count); return read_sized_int(bplist, bplist->offset_table_offset + bplist->offset_int_size * index, bplist->offset_int_size); } static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize) { uint32_t size; int64_t value; assert(bplist->data_bytes != NULL && offset < bplist->length); size = 1 << (bplist->data_bytes[offset] & 0x0F); if (size > 8) { // Maximum allowable size in this implementation is 1<<3 = 8 bytes. // This also happens to be the biggest we can handle. return NO; } if (offset + 1 + size > bplist->length) { // Out of range. return NO; } value = read_sized_int(bplist, offset + 1, size); if (outValue != NULL) *outValue = value; if (outSize != NULL) *outSize = size + 1; // +1 for tag byte. return YES; } static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset) { assert(bplist->data_bytes != NULL && offset < bplist->length); value_ptr value = value_create(); switch (bplist->data_bytes[offset]) { case kVALUE_NULL: value->tag = kVALUE_NULL; return value; case kVALUE_TRUE: value->tag = kVALUE_TRUE; return value; case kVALUE_FALSE: value->tag = kVALUE_FALSE; return value; } // Note: kVALUE_FILLER is treated as invalid, because it, er, is. bplist_log("Bad binary plist: invalid atom.\n"); free(value); return NULL; } static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset) { value_ptr value = value_create(); value->tag = kTAG_INT; if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) { bplist_log("Bad binary plist: invalid integer object.\n"); } /* NOTE: originally, I sign-extended here. This was the wrong thing; it turns out that negative ints are always stored as 64-bit, and smaller ints are unsigned. */ return value; } static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset) { value_ptr value = value_create(); uint32_t size; assert(bplist->data_bytes != NULL && offset < bplist->length); size = 1 << (bplist->data_bytes[offset] & 0x0F); // FIXME: what to do if faced with other sizes for float/double? assert (sizeof (float) == sizeof (uint32_t) && sizeof (double) == sizeof (uint64_t)); if (offset + 1 + size > bplist->length) { bplist_log("Bad binary plist: %s object overlaps end of container.\n", "floating-point number"); free(value); return NULL; } if (size == sizeof (float)) { // cast is ok because we know size is 4 bytes uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size); // Note that this handles byte swapping. value_set_real(value, *(float *)&i); return value; } else if (size == sizeof (double)) { uint64_t i = read_sized_int(bplist, offset + 1, size); // Note that this handles byte swapping. value_set_real(value, *(double *)&i); return value; } else { // Can't handle floats of other sizes. bplist_log("Bad binary plist: can't handle %u-byte float.\n", size); free(value); return NULL; } } static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset) { value_ptr value; assert(bplist->data_bytes != NULL && offset < bplist->length); // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid. if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) { bplist_log("Bad binary plist: invalid size for date object.\n"); return NULL; } if (offset + 1 + sizeof (double) > bplist->length) { bplist_log("Bad binary plist: %s object overlaps end of container.\n", "date"); return NULL; } // FIXME: what to do if faced with other sizes for double? assert (sizeof (double) == sizeof (uint64_t)); uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double)); // Note that this handles byte swapping. value = value_create(); value_set_date(value, *(double *)&date); return value; } uint64_t bplist_get_a_size(bplist_info_ptr bplist, uint64_t *offset_ptr, char *msg) { uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F; (*offset_ptr)++; if (size == 0x0F) { // 0x0F means separate int size follows. // Smaller values are used for short data. size_t extra; // the length of the data size we are about to read if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) { // Bad data, mistagged size int bplist_log("Bad binary plist: %s object size is not tagged as int.\n", msg); return UINT64_MAX; // error } // read integer data as size, extra tells how many bytes to skip if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) { bplist_log("Bad binary plist: invalid %s object size tag.\n", "data"); return UINT64_MAX; // error } (*offset_ptr) += extra; } if (*offset_ptr + size > bplist->length) { bplist_log("Bad binary plist: %s object overlaps end of container.\n", "data"); return UINT64_MAX; // error } return size; } static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset) { uint64_t size; value_ptr value; assert(bplist->data_bytes != NULL && offset < bplist->length); if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX) return NULL; value = value_create(); // cast is ok because we only allow files up to 100MB: value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size); return value; } static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset) { uint64_t size; value_ptr value; // return value assert(bplist->data_bytes != NULL && offset < bplist->length); if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) == UINT64_MAX) return NULL; value = value_create(); // cast is ok because we only allow 100MB files value_set_ascii_string(value, bplist->data_bytes + (size_t) offset, (size_t) size); return value; } static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset) { uint64_t size; value_ptr value; assert(bplist->data_bytes != NULL && offset < bplist->length); if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) == UINT64_MAX) return NULL; value = value_create(); // cast is ok because we only allow 100MB files value_set_unicode_string(value, bplist->data_bytes + (size_t) offset, (size_t) size); return value; } static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset) { /* UIDs are used by Cocoa's key-value coder. When writing other plist formats, they are expanded to dictionaries of the form CF$UIDvalue, so we do the same here on reading. This results in plists identical to what running plutil -convert xml1 gives us. However, this is not the same result as [Core]Foundation's plist parser, which extracts them as un- introspectable CF objects. In fact, it even seems to convert the CF$UID dictionaries from XML plists on the fly. */ value_ptr value; uint64_t uid; if (!read_self_sized_int(bplist, offset, &uid, NULL)) { bplist_log("Bad binary plist: invalid UID object.\n"); return NULL; } // assert(NO); // original code suggests using a string for a key // but our dictionaries all use big ints for keys, so I don't know // what to do here // In practice, I believe this code is never executed by PortMidi. // I changed it to do something and not raise compiler warnings, but // not sure what the code should do. value = value_create(); value_set_uid(value, uid); // return [NSDictionary dictionaryWithObject: // [NSNumber numberWithUnsignedLongLong:value] // forKey:"CF$UID"]; return value; } static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset) { uint64_t i, count; uint64_t size; uint64_t elementID; value_ptr element = NULL; value_ptr *array = NULL; value_ptr value = NULL; BOOL ok = YES; assert(bplist->data_bytes != NULL && offset < bplist->length); if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX) return NULL; if (count > UINT64_MAX / bplist->object_ref_size - offset) { // Offset overflow. bplist_log("Bad binary plist: %s object overlaps end of container.\n", "array"); return NULL; } size = bplist->object_ref_size * count; if (size + offset > bplist->length) { bplist_log("Bad binary plist: %s object overlaps end of container.\n", "array"); return NULL; } // got count, the number of array elements value = value_create(); assert(value); if (count == 0) { // count must be size_t or smaller because max file size is 100MB value_set_array(value, array, (size_t) count); return value; } array = allocate(sizeof(value_ptr) * (size_t) count); for (i = 0; i != count; ++i) { bplist_log_verbose("[%u]\n", i); elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, bplist->object_ref_size); element = extract_object(bplist, elementID); if (element != NULL) { array[i] = element; } else { ok = NO; break; } } if (ok) { // count is smaller than size_t max because of 100MB file limit value_set_array(value, array, (size_t) count); } return value; } static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset) { uint64_t i, count; uint64_t size; uint64_t elementID; value_ptr value = NULL; dict_ptr dict = NULL; BOOL ok = YES; assert(bplist->data_bytes != NULL && offset < bplist->length); if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX) return NULL; if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) { // Offset overflow. bplist_log("Bad binary plist: %s object overlaps end of container.\n", "dictionary"); return NULL; } size = bplist->object_ref_size * count * 2; if (size + offset > bplist->length) { bplist_log("Bad binary plist: %s object overlaps end of container.\n", "dictionary"); return NULL; } value = value_create(); if (count == 0) { value_set_dict(value, NULL); return value; } for (i = 0; i != count; ++i) { value_ptr key; value_ptr val; elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, bplist->object_ref_size); key = extract_object(bplist, elementID); if (key != NULL) { bplist_log_verbose("key: %p\n", key); } else { ok = NO; break; } elementID = read_sized_int(bplist, offset + (i + count) * bplist->object_ref_size, bplist->object_ref_size); val = extract_object(bplist, elementID); if (val != NULL) { dict_insert(&dict, key, val); } else { ok = NO; break; } } if (ok) { value_set_dict(value, dict); } return value; } /*************** functions for accessing values ****************/ char *value_get_asciistring(value_ptr v) { if (v->tag != kTAG_ASCIISTRING) return NULL; return v->string; } value_ptr value_dict_lookup_using_string(value_ptr v, char *key) { dict_ptr dict; if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary dict = v->dict; /* search for key */ while (dict) { if (dict->key && dict->key->tag == kTAG_ASCIISTRING && strcmp(key, dict->key->string) == 0) { // found it return dict->value; } dict = dict->next; } return NULL; /* not found */ } value_ptr value_dict_lookup_using_path(value_ptr v, char *path) { char key[MAX_KEY_SIZE]; while (*path) { /* more to the path */ int i = 0; while (i < MAX_KEY_SIZE - 1) { key[i] = *path++; if (key[i] == '/') { /* end of entry in path */ key[i + 1] = 0; break; } if (!key[i]) { path--; /* back up to end of string char */ break; /* this will cause outer loop to exit */ } i++; } if (!v || v->tag != kTAG_DICTIONARY) return NULL; /* now, look up the key to get next value */ v = value_dict_lookup_using_string(v, key); if (v == NULL) return NULL; } return v; } /*************** functions for debugging ***************/ void plist_print(value_ptr v) { size_t i; int comma_needed; dict_ptr dict; if (!v) { printf("NULL"); return; } switch (v->tag & 0xF0) { case kTAG_SIMPLE: switch (v->tag) { case kVALUE_NULL: printf("NULL@%p", v); break; case kVALUE_FALSE: printf("FALSE@%p", v); break; case kVALUE_TRUE: printf("TRUE@%p", v); break; default: printf("UNKNOWN tag=%x@%p", v->tag, v); break; } break; case kTAG_INT: printf("%lld@%p", v->integer, v); break; case kTAG_REAL: printf("%g@%p", v->real, v); break; case kTAG_DATE: printf("date:%g@%p", v->real, v); break; case kTAG_DATA: printf("data@%p->%p:[%p:", v, v->data, v->data->data); for (i = 0; i < v->data->len; i++) { printf(" %2x", v->data->data[i]); } printf("]"); break; case kTAG_ASCIISTRING: printf("%p:\"%s\"@%p", v->string, v->string, v); break; case kTAG_UNICODESTRING: printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break; case kTAG_UID: printf("UID:%llu@%p", v->uinteger, v); break; case kTAG_ARRAY: comma_needed = FALSE; printf("%p->%p:[%p:", v, v->array, v->array->array); for (i = 0; i < v->array->length; i++) { if (comma_needed) printf(", "); plist_print(v->array->array[i]); comma_needed = TRUE; } printf("]"); break; case kTAG_DICTIONARY: comma_needed = FALSE; printf("%p:[", v); dict = v->dict; while (dict) { if (comma_needed) printf(", "); printf("%p:", dict); plist_print(dict->key); printf("->"); plist_print(dict->value); comma_needed = TRUE; dict = dict->next; } printf("]"); break; default: printf("UNKNOWN tag=%x", v->tag); break; } } portmidi/license.txt0000644000000000000000000000347111127373026013575 0ustar rootroot/* * PortMidi Portable Real-Time MIDI Library * * license.txt -- a copy of the PortMidi copyright notice and license information * * Latest version available at: http://sourceforge.net/projects/portmedia * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * Copyright (c) 2001-2009 Roger B. Dannenberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortMidi license; however, * the PortMusic community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ portmidi/CHANGELOG.txt0000644000000000000000000002242611267017610013442 0ustar rootroot/* CHANGELOG FOR PORTMIDI * * 19Oct09 Roger Dannenberg * - Changes dynamic library names from portmidi_d to portmidi to * be backward-compatible with programs expecting a library by * the old name. * * 04Oct09 Roger Dannenberg * - Converted to using Cmake. * - Renamed static and dynamic library files to portmidi_s and portmidi_d * - Eliminated VC9 and VC8 files (went back to simply test.vcproj, etc., * use Cmake to switch from the provided VC9 files to VC8 or other) * - Many small changes to prepare for 64-bit architectures (but only * tested on 32-bit machines) * * 16Jun09 Roger Dannenberg * - Started using Microsoft Visual C++ Version 9 (Express). Converted * all *-VC9.vcproj file to *.vcproj and renamed old project files to * *-VC8.proj. Previously, output from VC9 went to special VC9 files, * that breaks any program or script looking for output in release or * debug files, so now both compiler version output to the same folders. * Now, debug version uses static linking with debug DLL runtime, and * release version uses static linking with statically linked runtime. * Converted to Inno Setup and worked on scripts to make things build * properly, especially pmdefaults. * * 02Jan09 Roger Dannenberg * - Created Java interface and wrote PmDefaults application to set * values for Pm_GetDefaultInputDeviceID() and * Pm_GetDefaultOutputDeviceID(). Other fixes. * * 19Jun08 Roger Dannenberg and Austin Sung * - Removed USE_DLL_FOR_CLEANUP -- Windows 2000 through Vista seem to be * fixed now, and can recover if MIDI ports are left open * - Various other minor patches * * 17Jan07 Roger Dannenberg * - Lots more help for Common Lisp user in pm_cl * - Minor fix to eliminate a compiler warning * - Went back to single library in OS X for both portmidi and porttime * * 16Jan07 Roger Dannenberg * - OOPS! fixed bug where short messages all had zero data * - Makefile.osx static library build now makes universal (i386 + ppc) * binaries * * 15Jan07 Roger Dannenberg * - multiple rewrites of sysex handling code to take care of * error-handling, embedded messages, message filtering, * driver bugs, and host limitations. * - fixed windows to use dwBufferLength rather than * dwBytesRecorded for long buffer output (fix by Nigel Brown) * - Win32 MME code always appends an extra zero to long buffer * output to work around a problem with earlier versions of Midi Yoke * - Added mm, a command line Midi Monitor to pm_test suite * - Revised copyright notice to match PortAudio/MIT license (requests * are moved out of the license proper and into a separate paragraph) * * 18Oct06 Roger Dannenberg * - replace FIFO in pmutil with Light Pipe-based multiprocessor-safe alg. * - replace FIFO in portmidi.c with PmQueue from pmutil * * 07Oct06 cpr & Roger Dannenberg * - overhaul of CoreMIDI input to handle running status and multiple * - messages per packet, with additional error detection * - added Leigh Smith and Rick Taube support for Common Lisp and * - dynamic link libraries in OSX * - initialize static global seq = NULL in pmlinuxalsa.c * * 05Sep06 Sebastien Frippiat * - check if (ALSA) seq exists before closing it in pm_linuxalsa_term() * * 05Sep06 Andreas Micheler and Cecilio * - fixed memory leak by freeing someo objects in pm_winmm_term() * - and another leak by freeing descriptors in Pm_Terminate() * * 23Aug06 RBD * - various minor fixes * * 04Nov05 Olivier Tristan * - changes to OS X to properly retrieve real device name on CoreMidi * * 19Jul05 Roger Dannenberg * - included pmBufferMaxSize in Pm_GetErrorText() * * 23Mar05 Torgier Strand Henriksen * - cleaner termination of porttime thread under Linux * * 15Nov04 Ben Allison * - sysex output now uses one buffer/message and reallocates buffer * - if needed * - filters expanded for many message types and channels * - detailed changes are as follows: * ------------- in pmwinmm.c -------------- * - new #define symbol: OUTPUT_BYTES_PER_BUFFER * - change SYSEX_BYTES_PER_BUFFER to 1024 * - added MIDIHDR_BUFFER_LENGTH(x) to correctly count midihdr buffer length * - change MIDIHDR_SIZE(x) to (MIDIHDR_BUFFER_LENGTH(x) + sizeof(MIDIHDR)) * - change allocate_buffer to use new MIDIHDR_BUFFER_LENGTH macro * - new macros for MIDIHDR_SYSEX_SIZE and MIDIHDR_SYSEX_BUFFER_LENGTH * - similar to above, but counts appropriately for sysex messages * - added the following members to midiwinmm_struct for sysex data: * - LPMIDIHDR *sysex_buffers; ** pool of buffers for sysex data ** * - int num_sysex_buffers; ** how many sysex buffers ** * - int next_sysex_buffer; ** index of next sysexbuffer to send ** * - HANDLE sysex_buffer_signal; ** to wait for free sysex buffer ** * - duplicated allocate_buffer, alocate_buffers and get_free_output_buffer * - into equivalent sysex_buffer form * - changed winmm_in_open to initialize new midiwinmm_struct members and * - to use the new allocate_sysex_buffer() function instead of * - allocate_buffer() * - changed winmm_out_open to initialize new members, create sysex buffer * - signal, and allocate 2 sysex buffers * - changed winmm_out_delete to free sysex buffers and shut down the sysex * - buffer signal * - create new function resize_sysex_buffer which resizes m->hdr to the * - passed size, and corrects the midiwinmm_struct accordingly. * - changed winmm_write_byte to use new resize_sysex_buffer function, * - if resize fails, write current buffer to output and continue * - changed winmm_out_callback to use buffer_signal or sysex_buffer_signal * - depending on which buffer was finished * ------------- in portmidi.h -------------- * - added pmBufferMaxSize to PmError to indicate that the buffer would be * - too large for the underlying API * - added additional filters * - added prototype, documentation, and helper macro for Pm_SetChannelMask * ------------- in portmidi.c -------------- * - added pm_status_filtered() and pm_realtime_filtered() functions to * separate filtering logic from buffer logic in pm_read_short * - added Pm_SetChannelMask function * - added pm_channel_filtered() function * ------------- in pminternal.h -------------- * - added member to PortMidiStream for channel mask * * 25May04 RBD * - removed support for MIDI THRU * - moved filtering from Pm_Read to pm_enqueue to avoid buffer ovfl * - extensive work on Mac OS X port, especially sysex and error handling * * 18May04 RBD * - removed side-effects from assert() calls. Now you can disable assert(). * - no longer check pm_hosterror everywhere, fixing a bug where an open * failure could cause a write not to work on a previously opened port * until you call Pm_GetHostErrorText(). * 16May04 RBD and Chris Roberts * - Some documentation wordsmithing in portmidi.h * - Dynamically allocate port descriptor structures * - Fixed parameter error in midiInPrepareBuffer and midiInAddBuffer. * * 09Oct03 RBD * - Changed Thru handling. Now the client does all the work and the client * must poll or read to keep thru messages flowing. * * 31May03 RBD * - Fixed various bugs. * - Added linux ALSA support with help from Clemens Ladisch * - Added Mac OS X support, implemented by Jon Parise, updated and * integrated by Andrew Zeldis and Zico Kolter * - Added latency program to build histogram of system latency using PortTime. * * 30Jun02 RBD Extensive rewrite of sysex handling. It works now. * Extensive reworking of error reporting and error text -- no * longer use dictionary call to delete data; instead, Pm_Open * and Pm_Close clean up before returning an error code, and * error text is saved in a system-independent location. * Wrote sysex.c to test sysex message handling. * * 15Jun02 BCT changes: * - Added pmHostError text handling. * - For robustness, check PortMidi stream args not NULL. * - Re-C-ANSI-fied code (changed many C++ comments to C style) * - Reorganized code in pmwinmm according to input/output functionality (made * cleanup handling easier to reason about) * - Fixed Pm_Write calls (portmidi.h says these should not return length but Pm_Error) * - Cleaned up memory handling (now system specific data deleted via dictionary * call in PortMidi, allows client to query host errors). * - Added explicit asserts to verify various aspects of pmwinmm implementation behaves as * logic implies it should. Specifically: verified callback routines not reentrant and * all verified status for all unchecked Win32 MMedia API calls perform successfully * - Moved portmidi initialization and clean-up routines into DLL to fix Win32 MMedia API * bug (i.e. if devices not explicitly closed, must reboot to debug application further). * With this change, clients no longer need explicitly call Pm_Initialize, Pm_Terminate, or * explicitly Pm_Close open devices when using WinMM version of PortMidi. * * 23Jan02 RBD Fixed bug in pmwinmm.c thru handling * * 21Jan02 RBD Added tests in Pm_OpenInput() and Pm_OpenOutput() to prevent * opening an input as output and vice versa. * Added comments and documentation. * Implemented Pm_Terminate(). * */ portmidi/pm_linux/0000755000000000000000000000000011453601074013237 5ustar rootrootportmidi/pm_linux/pmlinuxalsa.h0000755000000000000000000000016510463413276015757 0ustar rootroot/* pmlinuxalsa.h -- system-specific definitions */ PmError pm_linuxalsa_init(void); void pm_linuxalsa_term(void); portmidi/pm_linux/pmlinuxalsa.c0000755000000000000000000006564011301353626015755 0ustar rootroot/* * pmlinuxalsa.c -- system specific definitions * * written by: * Roger Dannenberg (port to Alsa 0.9.x) * Clemens Ladisch (provided code examples and invaluable consulting) * Jason Cohen, Rico Colon, Matt Filippone (Alsa 0.5.x implementation) */ #include "stdlib.h" #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #include "pmlinuxalsa.h" #include "string.h" #include "porttime.h" #include "pmlinux.h" #include /* I used many print statements to debug this code. I left them in the * source, and you can turn them on by changing false to true below: */ #define VERBOSE_ON 0 #define VERBOSE if (VERBOSE_ON) #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 #if SND_LIB_MAJOR == 0 && SND_LIB_MINOR < 9 #error needs ALSA 0.9.0 or later #endif /* to store client/port in the device descriptor */ #define MAKE_DESCRIPTOR(client, port) ((void*)(((client) << 8) | (port))) #define GET_DESCRIPTOR_CLIENT(info) ((((int)(info)) >> 8) & 0xff) #define GET_DESCRIPTOR_PORT(info) (((int)(info)) & 0xff) #define BYTE unsigned char extern pm_fns_node pm_linuxalsa_in_dictionary; extern pm_fns_node pm_linuxalsa_out_dictionary; static snd_seq_t *seq = NULL; // all input comes here, // output queue allocated on seq static int queue, queue_used; /* one for all ports, reference counted */ typedef struct alsa_descriptor_struct { int client; int port; int this_port; int in_sysex; snd_midi_event_t *parser; int error; /* host error code */ } alsa_descriptor_node, *alsa_descriptor_type; /* get_alsa_error_text -- copy error text to potentially short string */ /**/ static void get_alsa_error_text(char *msg, int len, int err) { int errlen = strlen(snd_strerror(err)); if (errlen < len) { strcpy(msg, snd_strerror(err)); } else if (len > 20) { sprintf(msg, "Alsa error %d", err); } else if (len > 4) { strcpy(msg, "Alsa"); } else { msg[0] = 0; } } /* queue is shared by both input and output, reference counted */ static PmError alsa_use_queue(void) { if (queue_used == 0) { snd_seq_queue_tempo_t *tempo; queue = snd_seq_alloc_queue(seq); if (queue < 0) { pm_hosterror = queue; return pmHostError; } snd_seq_queue_tempo_alloca(&tempo); snd_seq_queue_tempo_set_tempo(tempo, 480000); snd_seq_queue_tempo_set_ppq(tempo, 480); pm_hosterror = snd_seq_set_queue_tempo(seq, queue, tempo); if (pm_hosterror < 0) return pmHostError; snd_seq_start_queue(seq, queue, NULL); snd_seq_drain_output(seq); } ++queue_used; return pmNoError; } static void alsa_unuse_queue(void) { if (--queue_used == 0) { snd_seq_stop_queue(seq, queue, NULL); snd_seq_drain_output(seq); snd_seq_free_queue(seq, queue); VERBOSE printf("queue freed\n"); } } /* midi_message_length -- how many bytes in a message? */ static int midi_message_length(PmMessage message) { message &= 0xff; if (message < 0x80) { return 0; } else if (message < 0xf0) { static const int length[] = {3, 3, 3, 3, 2, 2, 3}; return length[(message - 0x80) >> 4]; } else { static const int length[] = { -1, 2, 3, 2, 0, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1, 1}; return length[message - 0xf0]; } } static PmError alsa_out_open(PmInternal *midi, void *driverInfo) { void *client_port = descriptors[midi->device_id].descriptor; alsa_descriptor_type desc = (alsa_descriptor_type) pm_alloc(sizeof(alsa_descriptor_node)); snd_seq_port_info_t *info; int err; if (!desc) return pmInsufficientMemory; snd_seq_port_info_alloca(&info); snd_seq_port_info_set_port(info, midi->device_id); snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ); snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); snd_seq_port_info_set_port_specified(info, 1); err = snd_seq_create_port(seq, info); if (err < 0) goto free_desc; /* fill in fields of desc, which is passed to pm_write routines */ midi->descriptor = desc; desc->client = GET_DESCRIPTOR_CLIENT(client_port); desc->port = GET_DESCRIPTOR_PORT(client_port); desc->this_port = midi->device_id; desc->in_sysex = 0; desc->error = 0; err = snd_midi_event_new(PM_DEFAULT_SYSEX_BUFFER_SIZE, &desc->parser); if (err < 0) goto free_this_port; if (midi->latency > 0) { /* must delay output using a queue */ err = alsa_use_queue(); if (err < 0) goto free_parser; err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); if (err < 0) goto unuse_queue; /* clean up and return on error */ } else { err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); if (err < 0) goto free_parser; /* clean up and return on error */ } return pmNoError; unuse_queue: alsa_unuse_queue(); free_parser: snd_midi_event_free(desc->parser); free_this_port: snd_seq_delete_port(seq, desc->this_port); free_desc: pm_free(desc); pm_hosterror = err; if (err < 0) { get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); } return pmHostError; } static PmError alsa_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; snd_seq_event_t ev; int err; snd_seq_ev_clear(&ev); if (snd_midi_event_encode_byte(desc->parser, byte, &ev) == 1) { snd_seq_ev_set_dest(&ev, desc->client, desc->port); snd_seq_ev_set_source(&ev, desc->this_port); if (midi->latency > 0) { /* compute relative time of event = timestamp - now + latency */ PmTimestamp now = (midi->time_proc ? midi->time_proc(midi->time_info) : Pt_Time(NULL)); int when = timestamp; /* if timestamp is zero, send immediately */ /* otherwise compute time delay and use delay if positive */ if (when == 0) when = now; when = (when - now) + midi->latency; if (when < 0) when = 0; VERBOSE printf("timestamp %d now %d latency %d, ", (int) timestamp, (int) now, midi->latency); VERBOSE printf("scheduling event after %d\n", when); /* message is sent in relative ticks, where 1 tick = 1 ms */ snd_seq_ev_schedule_tick(&ev, queue, 1, when); /* NOTE: for cases where the user does not supply a time function, we could optimize the code by not starting Pt_Time and using the alsa tick time instead. I didn't do this because it would entail changing the queue management to start the queue tick count when PortMidi is initialized and keep it running until PortMidi is terminated. (This should be simple, but it's not how the code works now.) -RBD */ } else { /* send event out without queueing */ VERBOSE printf("direct\n"); /* ev.queue = SND_SEQ_QUEUE_DIRECT; ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; */ snd_seq_ev_set_direct(&ev); } VERBOSE printf("sending event\n"); err = snd_seq_event_output(seq, &ev); if (err < 0) { desc->error = err; return pmHostError; } } return pmNoError; } static PmError alsa_out_close(PmInternal *midi) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; if (!desc) return pmBadPtr; if (pm_hosterror = snd_seq_disconnect_to(seq, desc->this_port, desc->client, desc->port)) { // if there's an error, try to delete the port anyway, but don't // change the pm_hosterror value so we retain the first error snd_seq_delete_port(seq, desc->this_port); } else { // if there's no error, delete the port and retain any error pm_hosterror = snd_seq_delete_port(seq, desc->this_port); } if (midi->latency > 0) alsa_unuse_queue(); snd_midi_event_free(desc->parser); midi->descriptor = NULL; /* destroy the pointer to signify "closed" */ pm_free(desc); if (pm_hosterror) { get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, pm_hosterror); return pmHostError; } return pmNoError; } static PmError alsa_in_open(PmInternal *midi, void *driverInfo) { void *client_port = descriptors[midi->device_id].descriptor; alsa_descriptor_type desc = (alsa_descriptor_type) pm_alloc(sizeof(alsa_descriptor_node)); snd_seq_port_info_t *info; snd_seq_port_subscribe_t *sub; snd_seq_addr_t addr; int err; if (!desc) return pmInsufficientMemory; err = alsa_use_queue(); if (err < 0) goto free_desc; snd_seq_port_info_alloca(&info); snd_seq_port_info_set_port(info, midi->device_id); snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ); snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); snd_seq_port_info_set_port_specified(info, 1); err = snd_seq_create_port(seq, info); if (err < 0) goto free_queue; /* fill in fields of desc, which is passed to pm_write routines */ midi->descriptor = desc; desc->client = GET_DESCRIPTOR_CLIENT(client_port); desc->port = GET_DESCRIPTOR_PORT(client_port); desc->this_port = midi->device_id; desc->in_sysex = 0; desc->error = 0; VERBOSE printf("snd_seq_connect_from: %d %d %d\n", desc->this_port, desc->client, desc->port); snd_seq_port_subscribe_alloca(&sub); addr.client = snd_seq_client_id(seq); addr.port = desc->this_port; snd_seq_port_subscribe_set_dest(sub, &addr); addr.client = desc->client; addr.port = desc->port; snd_seq_port_subscribe_set_sender(sub, &addr); snd_seq_port_subscribe_set_time_update(sub, 1); /* this doesn't seem to work: messages come in with real timestamps */ snd_seq_port_subscribe_set_time_real(sub, 0); err = snd_seq_subscribe_port(seq, sub); /* err = snd_seq_connect_from(seq, desc->this_port, desc->client, desc->port); */ if (err < 0) goto free_this_port; /* clean up and return on error */ return pmNoError; free_this_port: snd_seq_delete_port(seq, desc->this_port); free_queue: alsa_unuse_queue(); free_desc: pm_free(desc); pm_hosterror = err; if (err < 0) { get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); } return pmHostError; } static PmError alsa_in_close(PmInternal *midi) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; if (!desc) return pmBadPtr; if (pm_hosterror = snd_seq_disconnect_from(seq, desc->this_port, desc->client, desc->port)) { snd_seq_delete_port(seq, desc->this_port); /* try to close port */ } else { pm_hosterror = snd_seq_delete_port(seq, desc->this_port); } alsa_unuse_queue(); pm_free(desc); if (pm_hosterror) { get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, pm_hosterror); return pmHostError; } return pmNoError; } static PmError alsa_abort(PmInternal *midi) { /* NOTE: ALSA documentation is vague. This is supposed to * remove any pending output messages. If you can test and * confirm this code is correct, please update this comment. -RBD */ /* Unfortunately, I can't even compile it -- my ALSA version * does not implement snd_seq_remove_events_t, so this does * not compile. I'll try again, but it looks like I'll need to * upgrade my entire Linux OS -RBD */ /* alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; snd_seq_remove_events_t info; snd_seq_addr_t addr; addr.client = desc->client; addr.port = desc->port; snd_seq_remove_events_set_dest(&info, &addr); snd_seq_remove_events_set_condition(&info, SND_SEQ_REMOVE_DEST); pm_hosterror = snd_seq_remove_events(seq, &info); if (pm_hosterror) { get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, pm_hosterror); return pmHostError; } */ printf("WARNING: alsa_abort not implemented\n"); return pmNoError; } #ifdef GARBAGE This is old code here temporarily for reference static PmError alsa_write(PmInternal *midi, PmEvent *buffer, int32_t length) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; int i, bytes; unsigned char byte; PmMessage msg; desc->error = 0; for (; length > 0; length--, buffer++) { VERBOSE printf("message 0x%x\n", buffer->message); if (Pm_MessageStatus(buffer->message) == MIDI_SYSEX) desc->in_sysex = TRUE; if (desc->in_sysex) { msg = buffer->message; for (i = 0; i < 4; i++) { byte = msg; /* extract next byte to send */ alsa_write_byte(midi, byte, buffer->timestamp); if (byte == MIDI_EOX) { desc->in_sysex = FALSE; break; } if (desc->error < 0) break; msg >>= 8; /* shift next byte into position */ } } else { bytes = midi_message_length(buffer->message); msg = buffer->message; for (i = 0; i < bytes; i++) { byte = msg; /* extract next byte to send */ VERBOSE printf("sending 0x%x\n", byte); alsa_write_byte(midi, byte, buffer->timestamp); if (desc->error < 0) break; msg >>= 8; /* shift next byte into position */ } } } if (desc->error < 0) return pmHostError; VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); desc->error = snd_seq_drain_output(seq); if (desc->error < 0) return pmHostError; desc->error = pmNoError; return pmNoError; } #endif static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); desc->error = snd_seq_drain_output(seq); if (desc->error < 0) return pmHostError; desc->error = pmNoError; return pmNoError; } static PmError alsa_write_short(PmInternal *midi, PmEvent *event) { int bytes = midi_message_length(event->message); PmMessage msg = event->message; int i; alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; for (i = 0; i < bytes; i++) { unsigned char byte = msg; VERBOSE printf("sending 0x%x\n", byte); alsa_write_byte(midi, byte, event->timestamp); if (desc->error < 0) break; msg >>= 8; /* shift next byte into position */ } if (desc->error < 0) return pmHostError; desc->error = pmNoError; return pmNoError; } /* alsa_sysex -- implements begin_sysex and end_sysex */ PmError alsa_sysex(PmInternal *midi, PmTimestamp timestamp) { return pmNoError; } static PmTimestamp alsa_synchronize(PmInternal *midi) { return 0; /* linux implementation does not use this synchronize function */ /* Apparently, Alsa data is relative to the time you send it, and there is no reference. If this is true, this is a serious shortcoming of Alsa. If not true, then PortMidi has a serious shortcoming -- it should be scheduling relative to Alsa's time reference. */ } static void handle_event(snd_seq_event_t *ev) { int device_id = ev->dest.port; PmInternal *midi = descriptors[device_id].internalDescriptor; PmEvent pm_ev; PmTimeProcPtr time_proc = midi->time_proc; PmTimestamp timestamp; /* time stamp should be in ticks, using our queue where 1 tick = 1ms */ assert((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_TICK); /* if no time_proc, just return "native" ticks (ms) */ if (time_proc == NULL) { timestamp = ev->time.tick; } else { /* translate time to time_proc basis */ snd_seq_queue_status_t *queue_status; snd_seq_queue_status_alloca(&queue_status); snd_seq_get_queue_status(seq, queue, queue_status); /* return (now - alsa_now) + alsa_timestamp */ timestamp = (*time_proc)(midi->time_info) + ev->time.tick - snd_seq_queue_status_get_tick_time(queue_status); } pm_ev.timestamp = timestamp; switch (ev->type) { case SND_SEQ_EVENT_NOTEON: pm_ev.message = Pm_Message(0x90 | ev->data.note.channel, ev->data.note.note & 0x7f, ev->data.note.velocity & 0x7f); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_NOTEOFF: pm_ev.message = Pm_Message(0x80 | ev->data.note.channel, ev->data.note.note & 0x7f, ev->data.note.velocity & 0x7f); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_KEYPRESS: pm_ev.message = Pm_Message(0xa0 | ev->data.note.channel, ev->data.note.note & 0x7f, ev->data.note.velocity & 0x7f); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_CONTROLLER: pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, ev->data.control.param & 0x7f, ev->data.control.value & 0x7f); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_PGMCHANGE: pm_ev.message = Pm_Message(0xc0 | ev->data.note.channel, ev->data.control.value & 0x7f, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_CHANPRESS: pm_ev.message = Pm_Message(0xd0 | ev->data.note.channel, ev->data.control.value & 0x7f, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_PITCHBEND: pm_ev.message = Pm_Message(0xe0 | ev->data.note.channel, (ev->data.control.value + 0x2000) & 0x7f, ((ev->data.control.value + 0x2000) >> 7) & 0x7f); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_CONTROL14: if (ev->data.control.param < 0x20) { pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, ev->data.control.param, (ev->data.control.value >> 7) & 0x7f); pm_read_short(midi, &pm_ev); pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, ev->data.control.param + 0x20, ev->data.control.value & 0x7f); pm_read_short(midi, &pm_ev); } else { pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, ev->data.control.param & 0x7f, ev->data.control.value & 0x7f); pm_read_short(midi, &pm_ev); } break; case SND_SEQ_EVENT_SONGPOS: pm_ev.message = Pm_Message(0xf2, ev->data.control.value & 0x7f, (ev->data.control.value >> 7) & 0x7f); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_SONGSEL: pm_ev.message = Pm_Message(0xf3, ev->data.control.value & 0x7f, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_QFRAME: pm_ev.message = Pm_Message(0xf1, ev->data.control.value & 0x7f, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_START: pm_ev.message = Pm_Message(0xfa, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_CONTINUE: pm_ev.message = Pm_Message(0xfb, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_STOP: pm_ev.message = Pm_Message(0xfc, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_CLOCK: pm_ev.message = Pm_Message(0xf8, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_TUNE_REQUEST: pm_ev.message = Pm_Message(0xf6, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_RESET: pm_ev.message = Pm_Message(0xff, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_SENSING: pm_ev.message = Pm_Message(0xfe, 0, 0); pm_read_short(midi, &pm_ev); break; case SND_SEQ_EVENT_SYSEX: { const BYTE *ptr = (const BYTE *) ev->data.ext.ptr; /* assume there is one sysex byte to process */ pm_read_bytes(midi, ptr, ev->data.ext.len, timestamp); break; } } } static PmError alsa_poll(PmInternal *midi) { snd_seq_event_t *ev; /* expensive check for input data, gets data from device: */ while (snd_seq_event_input_pending(seq, TRUE) > 0) { /* cheap check on local input buffer */ while (snd_seq_event_input_pending(seq, FALSE) > 0) { /* check for and ignore errors, e.g. input overflow */ /* note: if there's overflow, this should be reported * all the way through to client. Since input from all * devices is merged, we need to find all input devices * and set all to the overflow state. * NOTE: this assumes every input is ALSA based. */ int rslt = snd_seq_event_input(seq, &ev); if (rslt >= 0) { handle_event(ev); } else if (rslt == -ENOSPC) { int i; for (i = 0; i < pm_descriptor_index; i++) { if (descriptors[i].pub.input) { PmInternal *midi = (PmInternal *) descriptors[i].internalDescriptor; /* careful, device may not be open! */ if (midi) Pm_SetOverflow(midi->queue); } } } } } return pmNoError; } static unsigned int alsa_has_host_error(PmInternal *midi) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; return desc->error; } static void alsa_get_host_error(PmInternal *midi, char *msg, unsigned int len) { alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; int err = (pm_hosterror || desc->error); get_alsa_error_text(msg, len, err); } pm_fns_node pm_linuxalsa_in_dictionary = { none_write_short, none_sysex, none_sysex, none_write_byte, none_write_short, none_write_flush, alsa_synchronize, alsa_in_open, alsa_abort, alsa_in_close, alsa_poll, alsa_has_host_error, alsa_get_host_error }; pm_fns_node pm_linuxalsa_out_dictionary = { alsa_write_short, alsa_sysex, alsa_sysex, alsa_write_byte, alsa_write_short, /* short realtime message */ alsa_write_flush, alsa_synchronize, alsa_out_open, alsa_abort, alsa_out_close, none_poll, alsa_has_host_error, alsa_get_host_error }; /* pm_strdup -- copy a string to the heap. Use this rather than strdup so * that we call pm_alloc, not malloc. This allows portmidi to avoid * malloc which might cause priority inversion. Probably ALSA is going * to call malloc anyway, so this extra work here may be pointless. */ char *pm_strdup(const char *s) { int len = strlen(s); char *dup = (char *) pm_alloc(len + 1); strcpy(dup, s); return dup; } PmError pm_linuxalsa_init( void ) { int err; snd_seq_client_info_t *cinfo; snd_seq_port_info_t *pinfo; unsigned int caps; /* Previously, the last parameter was SND_SEQ_NONBLOCK, but this * would cause messages to be dropped if the ALSA buffer fills up. * The correct behavior is for writes to block until there is * room to send all the data. The client should normally allocate * a large enough buffer to avoid blocking on output. * Now that blocking is enabled, the seq_event_input() will block * if there is no input data. This is not what we want, so must * call seq_event_input_pending() to avoid blocking. */ err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0); if (err < 0) return err; snd_seq_client_info_alloca(&cinfo); snd_seq_port_info_alloca(&pinfo); snd_seq_client_info_set_client(cinfo, -1); while (snd_seq_query_next_client(seq, cinfo) == 0) { snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); snd_seq_port_info_set_port(pinfo, -1); while (snd_seq_query_next_port(seq, pinfo) == 0) { if (snd_seq_port_info_get_client(pinfo) == SND_SEQ_CLIENT_SYSTEM) continue; /* ignore Timer and Announce ports on client 0 */ caps = snd_seq_port_info_get_capability(pinfo); if (!(caps & (SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE))) continue; /* ignore if you cannot read or write port */ if (caps & SND_SEQ_PORT_CAP_SUBS_WRITE) { if (pm_default_output_device_id == -1) pm_default_output_device_id = pm_descriptor_index; pm_add_device("ALSA", pm_strdup(snd_seq_port_info_get_name(pinfo)), FALSE, MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), snd_seq_port_info_get_port(pinfo)), &pm_linuxalsa_out_dictionary); } if (caps & SND_SEQ_PORT_CAP_SUBS_READ) { if (pm_default_input_device_id == -1) pm_default_input_device_id = pm_descriptor_index; pm_add_device("ALSA", pm_strdup(snd_seq_port_info_get_name(pinfo)), TRUE, MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), snd_seq_port_info_get_port(pinfo)), &pm_linuxalsa_in_dictionary); } } } return pmNoError; } void pm_linuxalsa_term(void) { if (seq) { snd_seq_close(seq); pm_free(descriptors); descriptors = NULL; pm_descriptor_index = 0; pm_descriptor_max = 0; } } portmidi/pm_linux/README_LINUX.txt0000755000000000000000000000721511327663412015730 0ustar rootrootREADME_LINUX.txt for PortMidi Roger Dannenberg 14 Oct 2009 To make PortMidi, you need cmake and the Java SDK. Go back up to the portmidi directory and type: ccmake . Type 'c' (configure) and then 'g' (generate). You may have to manually set JAVA_INCLUDE_PATH and JAVA_JVM_LIBRARY by typing 't' (toggle to advanced mode) and using the editor to change the fields. You can find possible values for JAVA_INCLUDE_PATH by typing "locate jni.h", and for JAVA_JVM_LIBRARY by typing locate libjvm". You also need JAVA_INCLUDE_PATH2, but this will normally be set automatically after you set JAVA_INCLUDE_PATH and run "configure" (type "c" to ccmake). Normally, JAVA_INCLUDE_PATH2 is the linux subdirectory within JAVA_INCLUDE_PATH. Notice that the CMAKE_BUILD_TYPE can be Debug or Release. Stick with Release if you are not debugging. After successfully generating make files with ccmake, you can run make: make The Makefile will build all test programs and the portmidi library. For experimental software, especially programs running from the command line, we recommend using the Debug version -- it will terminate your program and print a helpful message if any PortMidi function returns an error code. (Released software should check for error codes and handle them, but for quick, non-critical projects, the automatic "print and die" handling can save some work.) THE pmdefaults PROGRAM You should install pmdefaults. It provides a graphical interface for selecting default MIDI IN and OUT devices so that you don't have to build device selection interfaces into all your programs and so users have a single place to set a preference. Follow the instructions above to run ccmake, making sure that CMAKE_BUILD_TYPE is Release. Run make as described above. Then: sudo make install This will install PortMidi libraries and the pmdefault program. You must alos have the environment variable LD_LIBRARY_PATH set to include /usr/local/lib (where libpmjni.so is installed). Now, you can run pmdefault. SETTING LD_LIBRARY_PATH pmdefaults will not work unless LD_LIBRARY_PATH includes a directory (normally /usr/local/lib) containing libpmjni.so, installed as described above. To set LD_LIBRARY_PATH, you might want to add this to your ~/.profile (if you use the bash shell): LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib export LD_LIBRARY_PATH A NOTE ABOUT AMD64: When compiling portmidi under linux on an AMD64, I had to add the -fPIC flag to the gcc flags. Reason: when trying to build John Harrison's pyPortMidi gcc bailed out with this error: ./linux/libportmidi.a(pmlinux.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC ./linux/libportmidi.a: could not read symbols: Bad value collect2: ld returned 1 exit status error: command 'gcc' failed with exit status 1 What they said: http://www.gentoo.org/proj/en/base/amd64/howtos/index.xml?part=1&chap=3 On certain architectures (AMD64 amongst them), shared libraries *must* be "PIC-enabled". CHANGELOG 22-jan-2010 Roger B. Dannenberg Updated instructions about Java paths 14-oct-2009 Roger B. Dannenberg Using CMake now for building and configuration 29-aug-2006 Roger B. Dannenberg Fixed PortTime to join with time thread for clean exit. 28-aug-2006 Roger B. Dannenberg Updated this documentation. 08-Jun-2004 Roger B. Dannenberg Updated code to use new system abstraction. 12-Apr-2003 Roger B. Dannenberg Fixed pm_test/test.c to filter clocks and active messages. Integrated changes from Clemens Ladisch: cleaned up pmlinuxalsa.c record timestamp on sysex input deallocate some resources previously left open portmidi/pm_linux/pmlinux.h0000755000000000000000000000015710463413276015117 0ustar rootroot/* pmlinux.h */ extern PmDeviceID pm_default_input_device_id; extern PmDeviceID pm_default_output_device_id; portmidi/pm_linux/finddefault.c0000644000000000000000000000567711135174122015703 0ustar rootroot/* finddefault.c -- find_default_device() implementation Roger Dannenberg, Jan 2009 */ #include #include #include #include "portmidi.h" #define STRING_MAX 256 /* skip over spaces, return first non-space */ void skip_spaces(FILE *inf) { char c; while (isspace(c = getc(inf))) ; ungetc(c, inf); } /* trim leading spaces and match a string */ int match_string(FILE *inf, char *s) { skip_spaces(inf); while (*s && *s == getc(inf)) s++; return (*s == 0); } /* /* Parse preference files, find default device, search devices -- */ PmDeviceID find_default_device(char *path, int input, PmDeviceID id) /* path -- the name of the preference we are searching for input -- true iff this is an input device id -- current default device id returns matching device id if found, otherwise id */ { static char *pref_2 = "/.java/.userPrefs/"; static char *pref_3 = "prefs.xml"; char *pref_1 = getenv("HOME"); char *full_name, *path_ptr; FILE *inf; int c, i; if (!pref_1) goto nopref; // cannot find preference file // full_name will be larger than necessary full_name = malloc(strlen(pref_1) + strlen(pref_2) + strlen(pref_3) + strlen(path) + 2); strcpy(full_name, pref_1); strcat(full_name, pref_2); // copy all but last path segment to full_name if (*path == '/') path++; // skip initial slash in path path_ptr = strrchr(path, '/'); if (path_ptr) { // copy up to slash after full_name path_ptr++; int offset = strlen(full_name); memcpy(full_name + offset, path, path_ptr - path); full_name[offset + path_ptr - path] = 0; // end of string } else { path_ptr = path; } strcat(full_name, pref_3); inf = fopen(full_name, "r"); if (!inf) goto nopref; // cannot open preference file // We're not going to build or link in a full XML parser. // Instead, find the path string and quoute. Then, look for // "value", "=", quote. Then get string up to quote. while ((c = getc(inf)) != EOF) { char pref_str[STRING_MAX]; if (c != '"') continue; // scan up to quote // look for quote string quote if (!match_string(inf, path_ptr)) continue; // path not found if (getc(inf) != '"') continue; // path not found, keep scanning if (!match_string(inf, "value")) goto nopref; // value not found if (!match_string(inf, "=")) goto nopref; // = not found if (!match_string(inf, "\"")) goto nopref; // quote not found // now read the value up to the close quote for (i = 0; i < STRING_MAX; i++) { if ((c = getc(inf)) == '"') break; pref_str[i] = c; } if (i == STRING_MAX) continue; // value too long, ignore pref_str[i] == 0; i = pm_find_default_device(pref_str, input); if (i != pmNoDevice) { id = i; } break; } nopref: return id; } portmidi/pm_linux/pmlinux.c0000755000000000000000000000370711265200032015077 0ustar rootroot/* pmlinux.c -- PortMidi os-dependent code */ /* This file only needs to implement pm_init(), which calls various routines to register the available midi devices. This file must be separate from the main portmidi.c file because it is system dependent, and it is separate from, pmlinuxalsa.c, because it might need to register non-alsa devices as well. NOTE: if you add non-ALSA support, you need to fix :alsa_poll() in pmlinuxalsa.c, which assumes all input devices are ALSA. */ #include "stdlib.h" #include "portmidi.h" #include "pmutil.h" #include "pminternal.h" #ifdef PMALSA #include "pmlinuxalsa.h" #endif #ifdef PMNULL #include "pmlinuxnull.h" #endif PmDeviceID pm_default_input_device_id = -1; PmDeviceID pm_default_output_device_id = -1; void pm_init() { /* Note: it is not an error for PMALSA to fail to initialize. * It may be a design error that the client cannot query what subsystems * are working properly other than by looking at the list of available * devices. */ #ifdef PMALSA pm_linuxalsa_init(); #endif #ifdef PMNULL pm_linuxnull_init(); #endif // this is set when we return to Pm_Initialize, but we need it // now in order to (successfully) call Pm_CountDevices() pm_initialized = TRUE; pm_default_input_device_id = find_default_device( "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE, pm_default_input_device_id); pm_default_output_device_id = find_default_device( "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE, pm_default_output_device_id); } void pm_term(void) { #ifdef PMALSA pm_linuxalsa_term(); #endif } PmDeviceID Pm_GetDefaultInputDeviceID() { Pm_Initialize(); return pm_default_input_device_id; } PmDeviceID Pm_GetDefaultOutputDeviceID() { Pm_Initialize(); return pm_default_output_device_id; } void *pm_alloc(size_t s) { return malloc(s); } void pm_free(void *ptr) { free(ptr); } portmidi/pm_dylib/0000755000000000000000000000000011453601074013203 5ustar rootrootportmidi/pm_dylib/README.txt0000644000000000000000000000114711274243554014712 0ustar rootrootpm_dylib The purpose of this directory is to provide a separate CMakeLists.txt file for building a dynamic link library version of portmidi. This version (in Windows) is linked using the Multithreaded C Runtime DLL whereas the static library version in ../pm_common uses the (static) Multithreaded C Runtime. There's no good reason not to build both versions of portmidi in ../pm_common, but (the current) Cmake has the restriction that you must either share compiler flags across configurations (debug and release) or across targets (static and dynamic). Here, we need individual settings for all combinations. portmidi/pm_dylib/portmidi-dynamic.vcproj0000644000000000000000000001173711274243554017720 0ustar rootroot portmidi/pm_dylib/CMakeLists.txt0000644000000000000000000001222711301353626015746 0ustar rootroot# pm_dylib # set the build directory for libraries to be in portmidi, not in # portmidi/pm_dylib if(APPLE OR WIN32) # set the build directory for .dylib libraries set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) # the "archive" output directory says where to put portmidi.lib, the # static part of the lib/dll pair: set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) # the first time CMake configures, save off CMake's built-in flags if(NOT DEFAULT_DEBUG_FLAGS) set(DEFAULT_DEBUG_FLAGS ${CMAKE_C_FLAGS_DEBUG} CACHE STRING "CMake's default debug flags" FORCE) set(DEFAULT_RELEASE_FLAGS ${CMAKE_C_FLAGS_RELEASE} CACHE STRING "CMake's default release flags" FORCE) else(NOT DEFAULT_DEBUG_FLAGS) message(STATUS "DEFAULT_DEBUG_FLAGS not nil: " ${DEFAULT_DEBUG_FLAGS}) endif(NOT DEFAULT_DEBUG_FLAGS) else(APPLE OR WIN32) set(LINUX_FLAGS "-DPMALSA") endif(APPLE OR WIN32) macro(prepend_path RESULT PATH) set(${RESULT}) foreach(FILE ${ARGN}) list(APPEND ${RESULT} "${PATH}${FILE}") endforeach(FILE) endmacro(prepend_path) set(CMAKE_C_FLAGS_DEBUG "${DEFAULT_DEBUG_FLAGS} -DPM_CHECK_ERRORS=1 -DDEBUG ${LINUX_FLAGS}" CACHE STRING "enable extra checks for debugging" FORCE) set(CMAKE_C_FLAGS_RELEASE "${DEFAULT_RELEASE_FLAGS} ${LINUX_FLAGS}" CACHE STRING "flags for release version" FORCE) # first include the appropriate system-dependent file: if(UNIX) # add the -g switch for Linux and Mac OS X (not used in Win32) set (CMAKE_C_FLAGS_DEBUG "-g ${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "enable extra checks for debugging" FORCE) if(APPLE) set(MACSRC pmmacosxcm pmmac readbinaryplist finddefault) prepend_path(LIBSRC ../pm_mac/ ${MACSRC}) list(APPEND LIBSRC ../porttime/ptmacosx_mach) include_directories(${CMAKE_OSX_SYSROOT}/Developer/Headers/FlatCarbon) set(FRAMEWORK_PATH ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks) set(COREAUDIO_LIB "${FRAMEWORK_PATH}/CoreAudio.framework") set(COREFOUNDATION_LIB "${FRAMEWORK_PATH}/CoreFoundation.framework") set(COREMIDI_LIB "${FRAMEWORK_PATH}/CoreMIDI.framework") set(CORESERVICES_LIB "${FRAMEWORK_PATH}/CoreServices.framework") set(PM_NEEDED_LIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB} ${COREMIDI_LIB} ${CORESERVICES_LIB} CACHE INTERNAL "") set(JAVAVM_LIB "${FRAMEWORK_PATH}/JavaVM.framework") set(JAVA_INCLUDE_PATHS ${JAVAVM_LIB}/Headers) set(INSTALL_NAME_DIR "/usr/local/lib") message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT}) else(APPLE) # LINUX settings... include(FindJNI) # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) # note: should use JAVA_JVM_LIB_PATH, but it is not set properly # note: user might need to set JAVA_INCLUDE_PATH manually # # this will probably break on BSD and other Unix systems; the fix # depends on whether FindJNI can find Java or not. If yes, then # we should try to rely on automatically set JAVA_INCLUDE_PATH and # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation # because JAVA_INCLUDE_PATH2 is pretty obscure) set(JAVA_INCLUDE_PATH ${JAVA_INCLUDE_PATH-UNKNOWN} CACHE STRING "where to find Java SDK include directory") set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux) # libjvm.so is found relative to JAVA_INCLUDE_PATH: set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so) set(LINUXSRC pmlinuxalsa pmlinux finddefault) prepend_path(LIBSRC ../pm_linux/ ${LINUXSRC}) list(APPEND LIBSRC ../porttime/ptlinux) set(PM_NEEDED_LIBS pthread asound) endif(APPLE) else(UNIX) if(WIN32) # /MDd is multithread debug DLL, /MTd is multithread debug # /MD is multithread DLL, /MT is multithread include(FindJNI) # note: should use JAVA_JVM_LIB_PATH, but it is not set properly set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib) set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS}) set(WINSRC pmwin pmwinmm) prepend_path(LIBSRC ../pm_win/ ${WINSRC}) list(APPEND LIBSRC ../porttime/ptwinmm) set(PM_NEEDED_LIBS winmm.lib) # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB}) endif(WIN32) endif(UNIX) set(JNI_EXTRA_LIBS ${PM_NEEDED_LIBS} ${JAVAVM_LIB}) # this completes the list of library sources by adding shared code set(SHARED_FILES pmutil portmidi) prepend_path(SHARED_PATHS ../pm_common/ ${SHARED_FILES}) list(APPEND LIBSRC ${SHARED_PATHS}) add_library(portmidi-dynamic SHARED ${LIBSRC}) set_target_properties(portmidi-dynamic PROPERTIES OUTPUT_NAME "portmidi") target_link_libraries(portmidi-dynamic ${PM_NEEDED_LIBS}) # install the libraries (Linux and Mac OS X command line) if(UNIX) INSTALL(TARGETS portmidi-dynamic LIBRARY DESTINATION /usr/local/lib ARCHIVE DESTINATION /usr/local/lib) INSTALL(FILES ../pm_common/portmidi.h ../porttime/porttime.h DESTINATION /usr/local/include) endif(UNIX) portmidi/porttime/0000755000000000000000000000000011453601074013247 5ustar rootrootportmidi/porttime/porttime.vcproj0000755000000000000000000000741211215774554016360 0ustar rootroot portmidi/porttime/ptmacosx_cf.c0000755000000000000000000000712511252403336015727 0ustar rootroot/* ptmacosx.c -- portable timer implementation for mac os x */ #include #include #include #include #import #import #import #import #include "porttime.h" #define THREAD_IMPORTANCE 30 #define LONG_TIME 1000000000.0 static int time_started_flag = FALSE; static CFAbsoluteTime startTime = 0.0; static CFRunLoopRef timerRunLoop; typedef struct { int resolution; PtCallback *callback; void *userData; } PtThreadParams; void Pt_CFTimerCallback(CFRunLoopTimerRef timer, void *info) { PtThreadParams *params = (PtThreadParams*)info; (*params->callback)(Pt_Time(), params->userData); } static void* Pt_Thread(void *p) { CFTimeInterval timerInterval; CFRunLoopTimerContext timerContext; CFRunLoopTimerRef timer; PtThreadParams *params = (PtThreadParams*)p; //CFTimeInterval timeout; /* raise the thread's priority */ kern_return_t error; thread_extended_policy_data_t extendedPolicy; thread_precedence_policy_data_t precedencePolicy; extendedPolicy.timeshare = 0; error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY, (thread_policy_t)&extendedPolicy, THREAD_EXTENDED_POLICY_COUNT); if (error != KERN_SUCCESS) { mach_error("Couldn't set thread timeshare policy", error); } precedencePolicy.importance = THREAD_IMPORTANCE; error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&precedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); if (error != KERN_SUCCESS) { mach_error("Couldn't set thread precedence policy", error); } /* set up the timer context */ timerContext.version = 0; timerContext.info = params; timerContext.retain = NULL; timerContext.release = NULL; timerContext.copyDescription = NULL; /* create a new timer */ timerInterval = (double)params->resolution / 1000.0; timer = CFRunLoopTimerCreate(NULL, startTime+timerInterval, timerInterval, 0, 0, Pt_CFTimerCallback, &timerContext); timerRunLoop = CFRunLoopGetCurrent(); CFRunLoopAddTimer(timerRunLoop, timer, CFSTR("PtTimeMode")); /* run until we're told to stop by Pt_Stop() */ CFRunLoopRunInMode(CFSTR("PtTimeMode"), LONG_TIME, false); CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, CFSTR("PtTimeMode")); CFRelease(timer); free(params); return NULL; } PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { PtThreadParams *params = (PtThreadParams*)malloc(sizeof(PtThreadParams)); pthread_t pthread_id; printf("Pt_Start() called\n"); // /* make sure we're not already playing */ if (time_started_flag) return ptAlreadyStarted; startTime = CFAbsoluteTimeGetCurrent(); if (callback) { params->resolution = resolution; params->callback = callback; params->userData = userData; pthread_create(&pthread_id, NULL, Pt_Thread, params); } time_started_flag = TRUE; return ptNoError; } PtError Pt_Stop() { printf("Pt_Stop called\n"); CFRunLoopStop(timerRunLoop); time_started_flag = FALSE; return ptNoError; } int Pt_Started() { return time_started_flag; } PtTimestamp Pt_Time() { CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); return (PtTimestamp) ((now - startTime) * 1000.0); } void Pt_Sleep(int32_t duration) { usleep(duration * 1000); } portmidi/porttime/porttime.h0000755000000000000000000000440411274243554015276 0ustar rootroot/* porttime.h -- portable interface to millisecond timer */ /* CHANGE LOG FOR PORTTIME 10-Jun-03 Mark Nelson & RBD boost priority of timer thread in ptlinux.c implementation */ /* Should there be a way to choose the source of time here? */ #ifdef WIN32 #ifndef INT32_DEFINED // rather than having users install a special .h file for windows, // just put the required definitions inline here. portmidi.h uses // these too, so the definitions are (unfortunately) duplicated there typedef int int32_t; typedef unsigned int uint32_t; #define INT32_DEFINED #endif #else #include // needed for int32_t #endif #ifdef __cplusplus extern "C" { #endif #ifndef PMEXPORT #ifdef _WINDLL #define PMEXPORT __declspec(dllexport) #else #define PMEXPORT #endif #endif typedef enum { ptNoError = 0, /* success */ ptHostError = -10000, /* a system-specific error occurred */ ptAlreadyStarted, /* cannot start timer because it is already started */ ptAlreadyStopped, /* cannot stop timer because it is already stopped */ ptInsufficientMemory /* memory could not be allocated */ } PtError; typedef int32_t PtTimestamp; typedef void (PtCallback)( PtTimestamp timestamp, void *userData ); /* Pt_Start() starts a real-time service. resolution is the timer resolution in ms. The time will advance every resolution ms. callback is a function pointer to be called every resolution ms. userData is passed to callback as a parameter. return value: Upon success, returns ptNoError. See PtError for other values. */ PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData); /* Pt_Stop() stops the timer. return value: Upon success, returns ptNoError. See PtError for other values. */ PMEXPORT PtError Pt_Stop(); /* Pt_Started() returns true iff the timer is running. */ PMEXPORT int Pt_Started(); /* Pt_Time() returns the current time in ms. */ PMEXPORT PtTimestamp Pt_Time(); /* Pt_Sleep() pauses, allowing other threads to run. duration is the length of the pause in ms. The true duration of the pause may be rounded to the nearest or next clock tick as determined by resolution in Pt_Start(). */ PMEXPORT void Pt_Sleep(int32_t duration); #ifdef __cplusplus } #endif portmidi/porttime/porttime.dsp0000755000000000000000000000553110463413276015636 0ustar rootroot# Microsoft Developer Studio Project File - Name="porttime" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=porttime - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "porttime.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "porttime.mak" CFG="porttime - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "porttime - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "porttime - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "porttime - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ELSEIF "$(CFG)" == "porttime - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_LIB" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ENDIF # Begin Target # Name "porttime - Win32 Release" # Name "porttime - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\porttime.c # End Source File # Begin Source File SOURCE=.\ptwinmm.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\porttime.h # End Source File # End Group # End Target # End Project portmidi/porttime/porttime.c0000755000000000000000000000017610463413276015272 0ustar rootroot/* porttime.c -- portable API for millisecond timer */ /* There is no machine-independent implementation code to put here */ portmidi/porttime/porttime-VC8.vcproj0000644000000000000000000001072311215774554016752 0ustar rootroot portmidi/porttime/ptmacosx_mach.c0000755000000000000000000000710311252403336016243 0ustar rootroot/* ptmacosx.c -- portable timer implementation for mac os x */ #include #include #include #import #import #import #import #include #include "porttime.h" #include "sys/time.h" #include "pthread.h" #define NSEC_PER_MSEC 1000000 #define THREAD_IMPORTANCE 30 static int time_started_flag = FALSE; static UInt64 start_time; static pthread_t pt_thread_pid; /* note that this is static data -- we only need one copy */ typedef struct { int id; int resolution; PtCallback *callback; void *userData; } pt_callback_parameters; static int pt_callback_proc_id = 0; static void *Pt_CallbackProc(void *p) { pt_callback_parameters *parameters = (pt_callback_parameters *) p; int mytime = 1; kern_return_t error; thread_extended_policy_data_t extendedPolicy; thread_precedence_policy_data_t precedencePolicy; extendedPolicy.timeshare = 0; error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY, (thread_policy_t)&extendedPolicy, THREAD_EXTENDED_POLICY_COUNT); if (error != KERN_SUCCESS) { mach_error("Couldn't set thread timeshare policy", error); } precedencePolicy.importance = THREAD_IMPORTANCE; error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&precedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); if (error != KERN_SUCCESS) { mach_error("Couldn't set thread precedence policy", error); } /* to kill a process, just increment the pt_callback_proc_id */ /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */ while (pt_callback_proc_id == parameters->id) { /* wait for a multiple of resolution ms */ UInt64 wait_time; int delay = mytime++ * parameters->resolution - Pt_Time(); PtTimestamp timestamp; if (delay < 0) delay = 0; wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC); wait_time += AudioGetCurrentHostTime(); error = mach_wait_until(wait_time); timestamp = Pt_Time(); (*(parameters->callback))(timestamp, parameters->userData); } free(parameters); return NULL; } PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { if (time_started_flag) return ptAlreadyStarted; start_time = AudioGetCurrentHostTime(); if (callback) { int res; pt_callback_parameters *parms; parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters)); if (!parms) return ptInsufficientMemory; parms->id = pt_callback_proc_id; parms->resolution = resolution; parms->callback = callback; parms->userData = userData; res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms); if (res != 0) return ptHostError; } time_started_flag = TRUE; return ptNoError; } PtError Pt_Stop() { /* printf("Pt_Stop called\n"); */ pt_callback_proc_id++; pthread_join(pt_thread_pid, NULL); time_started_flag = FALSE; return ptNoError; } int Pt_Started() { return time_started_flag; } PtTimestamp Pt_Time() { UInt64 clock_time, nsec_time; clock_time = AudioGetCurrentHostTime() - start_time; nsec_time = AudioConvertHostTimeToNanos(clock_time); return (PtTimestamp)(nsec_time / NSEC_PER_MSEC); } void Pt_Sleep(int32_t duration) { usleep(duration * 1000); } portmidi/porttime/ptwinmm.c0000755000000000000000000000277511274243554015132 0ustar rootroot/* ptwinmm.c -- portable timer implementation for win32 */ #include "porttime.h" #include "windows.h" #include "time.h" TIMECAPS caps; static long time_offset = 0; static int time_started_flag = FALSE; static long time_resolution; static MMRESULT timer_id; static PtCallback *time_callback; void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { (*time_callback)(Pt_Time(), (void *) dwUser); } PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { if (time_started_flag) return ptAlreadyStarted; timeBeginPeriod(resolution); time_resolution = resolution; time_offset = timeGetTime(); time_started_flag = TRUE; time_callback = callback; if (callback) { timer_id = timeSetEvent(resolution, 1, winmm_time_callback, (DWORD_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if (!timer_id) return ptHostError; } return ptNoError; } PMEXPORT PtError Pt_Stop() { if (!time_started_flag) return ptAlreadyStopped; if (time_callback && timer_id) { timeKillEvent(timer_id); time_callback = NULL; timer_id = 0; } time_started_flag = FALSE; timeEndPeriod(time_resolution); return ptNoError; } PMEXPORT int Pt_Started() { return time_started_flag; } PMEXPORT PtTimestamp Pt_Time() { return timeGetTime() - time_offset; } PMEXPORT void Pt_Sleep(int32_t duration) { Sleep(duration); } portmidi/porttime/ptlinux.c0000755000000000000000000000763511452617306015140 0ustar rootroot/* ptlinux.c -- portable timer implementation for linux */ /* IMPLEMENTATION NOTES (by Mark Nelson): Unlike Windows, Linux has no system call to request a periodic callback, so if Pt_Start() receives a callback parameter, it must create a thread that wakes up periodically and calls the provided callback function. If running as superuser, use setpriority() to renice thread to -20. One could also set the timer thread to a real-time priority (SCHED_FIFO and SCHED_RR), but this is dangerous for This is necessary because if the callback hangs it'll never return. A more serious reason is that the current scheduler implementation busy-waits instead of sleeping when realtime threads request a sleep of <=2ms (as a way to get around the 10ms granularity), which means the thread would never let anyone else on the CPU. CHANGE LOG 18-Jul-03 Roger Dannenberg -- Simplified code to set priority of timer thread. Simplified implementation notes. */ /* stdlib, stdio, unistd, and sys/types were added because they appeared * in a Gentoo patch, but I'm not sure why they are needed. -RBD */ #include #include #include #include #include "porttime.h" #include "sys/time.h" #include "sys/resource.h" #include "sys/timeb.h" #include "pthread.h" #define TRUE 1 #define FALSE 0 static int time_started_flag = FALSE; static struct timeb time_offset = {0, 0, 0, 0}; static pthread_t pt_thread_pid; static int pt_thread_created = FALSE; /* note that this is static data -- we only need one copy */ typedef struct { int id; int resolution; PtCallback *callback; void *userData; } pt_callback_parameters; static int pt_callback_proc_id = 0; static void *Pt_CallbackProc(void *p) { pt_callback_parameters *parameters = (pt_callback_parameters *) p; int mytime = 1; /* to kill a process, just increment the pt_callback_proc_id */ /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */ if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20); while (pt_callback_proc_id == parameters->id) { /* wait for a multiple of resolution ms */ struct timeval timeout; int delay = mytime++ * parameters->resolution - Pt_Time(); if (delay < 0) delay = 0; timeout.tv_sec = 0; timeout.tv_usec = delay * 1000; select(0, NULL, NULL, NULL, &timeout); (*(parameters->callback))(Pt_Time(), parameters->userData); } /* printf("Pt_CallbackProc exiting\n"); */ // free(parameters); return NULL; } PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { if (time_started_flag) return ptNoError; ftime(&time_offset); /* need this set before process runs */ if (callback) { int res; pt_callback_parameters *parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters)); if (!parms) return ptInsufficientMemory; parms->id = pt_callback_proc_id; parms->resolution = resolution; parms->callback = callback; parms->userData = userData; res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms); if (res != 0) return ptHostError; pt_thread_created = TRUE; } time_started_flag = TRUE; return ptNoError; } PtError Pt_Stop() { /* printf("Pt_Stop called\n"); */ pt_callback_proc_id++; if (pt_thread_created) { pthread_join(pt_thread_pid, NULL); pt_thread_created = FALSE; } time_started_flag = FALSE; return ptNoError; } int Pt_Started() { return time_started_flag; } PtTimestamp Pt_Time() { long seconds, milliseconds; struct timeb now; ftime(&now); seconds = now.time - time_offset.time; milliseconds = now.millitm - time_offset.millitm; return seconds * 1000 + milliseconds; } void Pt_Sleep(int32_t duration) { usleep(duration * 1000); } portmidi/pm_csharp/0000755000000000000000000000000011453601074013360 5ustar rootrootportmidi/pm_csharp/README.txt0000644000000000000000000000301311127442610015050 0ustar rootrootThis code was offered by Aaron Oxford as is. The pm_managed directory contains the code. If you develop a more complete C# wrapper for PortMidi, please consider contributing your code to the project. -RBD ---- from Aaron Oxford ---- I've attached the managed C++ project which I've inserted into my 2005 version of PortMIDI's VS solution. I wouldn't think the functions I've implemented would have changed so it all should still work with the latest version of PM. Obviously you won't want to permanently embed this since it means the whole solution can only be built under VS2005, but it's easy for a VS2005 user to insert the project after the solution is converted or even just build it separately. Making the managed wrapper turned out to be dead easy in the end (it was more of a battle finding the correct build settings & SDK's and learning to configure VS than anything else). Anyone wanting to use something I've not implemented yet simply needs to add more stubs like this int Pm_Initialize() { ::Pm_Initialize(); return 0; } to the code. To call from C# it's just a matter of ManagedPortMIDI mpm = new ManagedPortMIDI(); int err = mpm.Pm_Initialize(); Anyway as the little code example above indicates, the support really is basic and more likely than not to break at the first hint of something unexpected. As I said, I'd be happy to contribute but I don't think there's much to contribute yet. :-) portmidi/pm_csharp/pm_managed/0000755000000000000000000000000011453601074015450 5ustar rootrootportmidi/pm_csharp/pm_managed/ReadMe.txt0000755000000000000000000000216611127442610017353 0ustar rootroot======================================================================== DYNAMIC LINK LIBRARY : pm_managed Project Overview ======================================================================== AppWizard has created this pm_managed DLL for you. This file contains a summary of what you will find in each of the files that make up your pm_managed application. pm_managed.vcproj This is the main project file for VC++ projects generated using an Application Wizard. It contains information about the version of Visual C++ that generated the file, and information about the platforms, configurations, and project features selected with the Application Wizard. pm_managed.cpp This is the main DLL source file. pm_managed.h This file contains a class declaration. AssemblyInfo.cpp Contains custom attributes for modifying assembly metadata. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize. ///////////////////////////////////////////////////////////////////////////// portmidi/pm_csharp/pm_managed/app.rc0000755000000000000000000000232311127442610016556 0ustar rootroot// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon placed first or with lowest ID value becomes application icon LANGUAGE 9, 3 #pragma code_page(1252) 1 ICON "app.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" "\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED portmidi/pm_csharp/pm_managed/Stdafx.h0000755000000000000000000000025511127442610017054 0ustar rootroot// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once portmidi/pm_csharp/pm_managed/pm_managed.vcproj0000755000000000000000000001266611127442610021000 0ustar rootroot portmidi/pm_csharp/pm_managed/app.ico0000755000000000000000000000206611127442610016730 0ustar rootroot &(( @wwwwwwwwwwwwwwpDDDDDDDDDDDDDDppppppppppppppppppppDDDDDDDDDDDDDDpLLLLLLLLLNItpDDDDDDDDDDDDD@( wwwwwwwDDDDDDDGOGOGOGOGOGOGOGOGHGLGDDDDDDportmidi/pm_csharp/pm_managed/AssemblyInfo.cpp0000755000000000000000000000251211127442610020547 0ustar rootroot#include "stdafx.h" using namespace System; using namespace System::Reflection; using namespace System::Runtime::CompilerServices; using namespace System::Runtime::InteropServices; using namespace System::Security::Permissions; // // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. // [assembly:AssemblyTitleAttribute("pm_managed")]; [assembly:AssemblyDescriptionAttribute("")]; [assembly:AssemblyConfigurationAttribute("")]; [assembly:AssemblyCompanyAttribute("Innovative Computer Solutions")]; [assembly:AssemblyProductAttribute("pm_managed")]; [assembly:AssemblyCopyrightAttribute("Copyright (c) Innovative Computer Solutions 2006")]; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; // // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the value or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly:AssemblyVersionAttribute("1.0.*")]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; [assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; portmidi/pm_csharp/pm_managed/pm_managed.cpp0000755000000000000000000000011511127442610020241 0ustar rootroot// This is the main DLL file. #include "stdafx.h" #include "pm_managed.h" portmidi/pm_csharp/pm_managed/pm_managed.h0000755000000000000000000000205011127442610017706 0ustar rootroot// pm_managed.h #pragma once #include "portmidi.h" using namespace System; namespace pm_managed { public ref class MpmDeviceInfo { public: int structVersion; System::String^ interf; /* underlying MIDI API, e.g. MMSystem or DirectX */ System::String^ name; /* device name, e.g. USB MidiSport 1x1 */ bool input; /* true iff input is available */ bool output; /* true iff output is available */ int opened; /* used by generic PortMidi code to do error checking on arguments */ MpmDeviceInfo(const PmDeviceInfo* info) { structVersion = info->structVersion; input = (info->input != 0); output = (info->output != 0); opened = info->opened; interf = gcnew System::String(info->interf); name = gcnew System::String(info->name); } }; public ref class ManagedPortMIDI { public: int Pm_Initialize() { ::Pm_Initialize(); return 0; } int Pm_CountDevices() { return ::Pm_CountDevices(); } MpmDeviceInfo^ Pm_GetDeviceInfo(int id) { return gcnew MpmDeviceInfo(::Pm_GetDeviceInfo(id)); } }; } portmidi/pm_csharp/pm_managed/Stdafx.cpp0000755000000000000000000000031111127442610017400 0ustar rootroot// stdafx.cpp : source file that includes just the standard includes // pm_managed.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" portmidi/pm_csharp/pm_managed/resource.h0000755000000000000000000000013011127442610017442 0ustar rootroot//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by app.rc portmidi/pm_python/0000755000000000000000000000000011453601074013421 5ustar rootrootportmidi/pm_python/pyportmidi/0000755000000000000000000000000011453601074015621 5ustar rootrootportmidi/pm_python/pyportmidi/examples/0000755000000000000000000000000011453601074017437 5ustar rootrootportmidi/pm_python/pyportmidi/__init__.py0000644000000000000000000000002611447645574017750 0ustar rootroot from .midi import * portmidi/pm_python/pyportmidi/_pyportmidi.c0000644000000000000000000076163311447645574020364 0ustar rootroot/* Generated by Cython 0.12.1 on Sun Sep 26 13:30:09 2010 */ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "structmember.h" #ifndef Py_PYTHON_H #error Python headers needed to compile C extensions, please install development version of Python. #else #ifndef PY_LONG_LONG #define PY_LONG_LONG LONG_LONG #endif #ifndef DL_EXPORT #define DL_EXPORT(t) t #endif #if PY_VERSION_HEX < 0x02040000 #define METH_COEXIST 0 #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type) #define PyDict_Contains(d,o) PySequence_Contains(d,o) #endif #if PY_VERSION_HEX < 0x02050000 typedef int Py_ssize_t; #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN #define PY_FORMAT_SIZE_T "" #define PyInt_FromSsize_t(z) PyInt_FromLong(z) #define PyInt_AsSsize_t(o) PyInt_AsLong(o) #define PyNumber_Index(o) PyNumber_Int(o) #define PyIndex_Check(o) PyNumber_Check(o) #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message) #endif #if PY_VERSION_HEX < 0x02060000 #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) #define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, #define PyType_Modified(t) typedef struct { void *buf; PyObject *obj; Py_ssize_t len; Py_ssize_t itemsize; int readonly; int ndim; char *format; Py_ssize_t *shape; Py_ssize_t *strides; Py_ssize_t *suboffsets; void *internal; } Py_buffer; #define PyBUF_SIMPLE 0 #define PyBUF_WRITABLE 0x0001 #define PyBUF_FORMAT 0x0004 #define PyBUF_ND 0x0008 #define PyBUF_STRIDES (0x0010 | PyBUF_ND) #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) #endif #if PY_MAJOR_VERSION < 3 #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" #else #define __Pyx_BUILTIN_MODULE_NAME "builtins" #endif #if PY_MAJOR_VERSION >= 3 #define Py_TPFLAGS_CHECKTYPES 0 #define Py_TPFLAGS_HAVE_INDEX 0 #endif #if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3) #define Py_TPFLAGS_HAVE_NEWBUFFER 0 #endif #if PY_MAJOR_VERSION >= 3 #define PyBaseString_Type PyUnicode_Type #define PyString_Type PyUnicode_Type #define PyString_CheckExact PyUnicode_CheckExact #else #define PyBytes_Type PyString_Type #define PyBytes_CheckExact PyString_CheckExact #endif #if PY_MAJOR_VERSION >= 3 #define PyInt_Type PyLong_Type #define PyInt_Check(op) PyLong_Check(op) #define PyInt_CheckExact(op) PyLong_CheckExact(op) #define PyInt_FromString PyLong_FromString #define PyInt_FromUnicode PyLong_FromUnicode #define PyInt_FromLong PyLong_FromLong #define PyInt_FromSize_t PyLong_FromSize_t #define PyInt_FromSsize_t PyLong_FromSsize_t #define PyInt_AsLong PyLong_AsLong #define PyInt_AS_LONG PyLong_AS_LONG #define PyInt_AsSsize_t PyLong_AsSsize_t #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) #else #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) #endif #if PY_MAJOR_VERSION >= 3 #define PyMethod_New(func, self, klass) PyInstanceMethod_New(func) #endif #if !defined(WIN32) && !defined(MS_WINDOWS) #ifndef __stdcall #define __stdcall #endif #ifndef __cdecl #define __cdecl #endif #ifndef __fastcall #define __fastcall #endif #else #define _USE_MATH_DEFINES #endif #if PY_VERSION_HEX < 0x02050000 #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),((char *)(n))) #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a)) #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),((char *)(n))) #else #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),(n)) #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a)) #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),(n)) #endif #if PY_VERSION_HEX < 0x02050000 #define __Pyx_NAMESTR(n) ((char *)(n)) #define __Pyx_DOCSTR(n) ((char *)(n)) #else #define __Pyx_NAMESTR(n) (n) #define __Pyx_DOCSTR(n) (n) #endif #ifdef __cplusplus #define __PYX_EXTERN_C extern "C" #else #define __PYX_EXTERN_C extern #endif #include #define __PYX_HAVE_API___pyportmidi #include "portmidi.h" #include "porttime.h" #ifndef CYTHON_INLINE #if defined(__GNUC__) #define CYTHON_INLINE __inline__ #elif defined(_MSC_VER) #define CYTHON_INLINE __inline #else #define CYTHON_INLINE #endif #endif typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/ /* Type Conversion Predeclarations */ #if PY_MAJOR_VERSION < 3 #define __Pyx_PyBytes_FromString PyString_FromString #define __Pyx_PyBytes_FromStringAndSize PyString_FromStringAndSize #define __Pyx_PyBytes_AsString PyString_AsString #else #define __Pyx_PyBytes_FromString PyBytes_FromString #define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize #define __Pyx_PyBytes_AsString PyBytes_AsString #endif #define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((char*)s) #define __Pyx_PyBytes_AsUString(s) ((unsigned char*) __Pyx_PyBytes_AsString(s)) #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); #if !defined(T_PYSSIZET) #if PY_VERSION_HEX < 0x02050000 #define T_PYSSIZET T_INT #elif !defined(T_LONGLONG) #define T_PYSSIZET \ ((sizeof(Py_ssize_t) == sizeof(int)) ? T_INT : \ ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : -1)) #else #define T_PYSSIZET \ ((sizeof(Py_ssize_t) == sizeof(int)) ? T_INT : \ ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : \ ((sizeof(Py_ssize_t) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))) #endif #endif #if !defined(T_ULONGLONG) #define __Pyx_T_UNSIGNED_INT(x) \ ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \ ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \ ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \ ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : -1)))) #else #define __Pyx_T_UNSIGNED_INT(x) \ ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \ ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \ ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \ ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : \ ((sizeof(x) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))))) #endif #if !defined(T_LONGLONG) #define __Pyx_T_SIGNED_INT(x) \ ((sizeof(x) == sizeof(char)) ? T_BYTE : \ ((sizeof(x) == sizeof(short)) ? T_SHORT : \ ((sizeof(x) == sizeof(int)) ? T_INT : \ ((sizeof(x) == sizeof(long)) ? T_LONG : -1)))) #else #define __Pyx_T_SIGNED_INT(x) \ ((sizeof(x) == sizeof(char)) ? T_BYTE : \ ((sizeof(x) == sizeof(short)) ? T_SHORT : \ ((sizeof(x) == sizeof(int)) ? T_INT : \ ((sizeof(x) == sizeof(long)) ? T_LONG : \ ((sizeof(x) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))))) #endif #define __Pyx_T_FLOATING(x) \ ((sizeof(x) == sizeof(float)) ? T_FLOAT : \ ((sizeof(x) == sizeof(double)) ? T_DOUBLE : -1)) #if !defined(T_SIZET) #if !defined(T_ULONGLONG) #define T_SIZET \ ((sizeof(size_t) == sizeof(unsigned int)) ? T_UINT : \ ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : -1)) #else #define T_SIZET \ ((sizeof(size_t) == sizeof(unsigned int)) ? T_UINT : \ ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : \ ((sizeof(size_t) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))) #endif #endif static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*); #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) #ifdef __GNUC__ /* Test for GCC > 2.95 */ #if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else /* __GNUC__ > 2 ... */ #define likely(x) (x) #define unlikely(x) (x) #endif /* __GNUC__ > 2 ... */ #else /* __GNUC__ */ #define likely(x) (x) #define unlikely(x) (x) #endif /* __GNUC__ */ static PyObject *__pyx_m; static PyObject *__pyx_b; static PyObject *__pyx_empty_tuple; static PyObject *__pyx_empty_bytes; static int __pyx_lineno; static int __pyx_clineno = 0; static const char * __pyx_cfilenm= __FILE__; static const char *__pyx_filename; static const char **__pyx_f; /* Type declarations */ /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":394 * * * cdef class Input: # <<<<<<<<<<<<<< * """ * class Input: */ struct __pyx_obj_11_pyportmidi_Input { PyObject_HEAD PmStream *midi; int debug; int i; }; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":201 * return Pm_Channel(chan-1) * * cdef class Output: # <<<<<<<<<<<<<< * """ * class Output: */ struct __pyx_obj_11_pyportmidi_Output { PyObject_HEAD int i; PmStream *midi; int debug; int _aborted; }; #ifndef CYTHON_REFNANNY #define CYTHON_REFNANNY 0 #endif #if CYTHON_REFNANNY typedef struct { void (*INCREF)(void*, PyObject*, int); void (*DECREF)(void*, PyObject*, int); void (*GOTREF)(void*, PyObject*, int); void (*GIVEREF)(void*, PyObject*, int); void* (*SetupContext)(const char*, int, const char*); void (*FinishContext)(void**); } __Pyx_RefNannyAPIStruct; static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) { PyObject *m = NULL, *p = NULL; void *r = NULL; m = PyImport_ImportModule((char *)modname); if (!m) goto end; p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); if (!p) goto end; r = PyLong_AsVoidPtr(p); end: Py_XDECREF(p); Py_XDECREF(m); return (__Pyx_RefNannyAPIStruct *)r; } #define __Pyx_RefNannySetupContext(name) void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) #define __Pyx_RefNannyFinishContext() __Pyx_RefNanny->FinishContext(&__pyx_refnanny) #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0) #else #define __Pyx_RefNannySetupContext(name) #define __Pyx_RefNannyFinishContext() #define __Pyx_INCREF(r) Py_INCREF(r) #define __Pyx_DECREF(r) Py_DECREF(r) #define __Pyx_GOTREF(r) #define __Pyx_GIVEREF(r) #define __Pyx_XDECREF(r) Py_XDECREF(r) #endif /* CYTHON_REFNANNY */ #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0) #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0) static void __Pyx_RaiseDoubleKeywordsError( const char* func_name, PyObject* kw_name); /*proto*/ static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/ static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name); /*proto*/ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { PyObject *r; if (!j) return NULL; r = PyObject_GetItem(o, j); Py_DECREF(j); return r; } #define __Pyx_GetItemInt_List(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ __Pyx_GetItemInt_List_Fast(o, i, size <= sizeof(long)) : \ __Pyx_GetItemInt_Generic(o, to_py_func(i))) static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, int fits_long) { if (likely(o != Py_None)) { if (likely((0 <= i) & (i < PyList_GET_SIZE(o)))) { PyObject *r = PyList_GET_ITEM(o, i); Py_INCREF(r); return r; } else if ((-PyList_GET_SIZE(o) <= i) & (i < 0)) { PyObject *r = PyList_GET_ITEM(o, PyList_GET_SIZE(o) + i); Py_INCREF(r); return r; } } return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); } #define __Pyx_GetItemInt_Tuple(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ __Pyx_GetItemInt_Tuple_Fast(o, i, size <= sizeof(long)) : \ __Pyx_GetItemInt_Generic(o, to_py_func(i))) static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, int fits_long) { if (likely(o != Py_None)) { if (likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) { PyObject *r = PyTuple_GET_ITEM(o, i); Py_INCREF(r); return r; } else if ((-PyTuple_GET_SIZE(o) <= i) & (i < 0)) { PyObject *r = PyTuple_GET_ITEM(o, PyTuple_GET_SIZE(o) + i); Py_INCREF(r); return r; } } return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); } #define __Pyx_GetItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ __Pyx_GetItemInt_Fast(o, i, size <= sizeof(long)) : \ __Pyx_GetItemInt_Generic(o, to_py_func(i))) static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) { PyObject *r; if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) { r = PyList_GET_ITEM(o, i); Py_INCREF(r); } else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) { r = PyTuple_GET_ITEM(o, i); Py_INCREF(r); } else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) { r = PySequence_GetItem(o, i); } else { r = __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); } return r; } static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) { if (likely(PyList_CheckExact(L))) { if (PyList_Append(L, x) < 0) return NULL; Py_INCREF(Py_None); return Py_None; /* this is just to have an accurate signature */ } else { PyObject *r, *m; m = __Pyx_GetAttrString(L, "append"); if (!m) return NULL; r = PyObject_CallFunctionObjArgs(m, x, NULL); Py_DECREF(m); return r; } } static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmDeviceID(PmDeviceID); static CYTHON_INLINE PmDeviceID __Pyx_PyInt_from_py_PmDeviceID(PyObject *); static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PtTimestamp(PtTimestamp); static int __Pyx_Print(PyObject *, int); /*proto*/ #if PY_MAJOR_VERSION >= 3 static PyObject* __pyx_print = 0; static PyObject* __pyx_print_kwargs = 0; #endif static int __Pyx_PrintOne(PyObject *o); /*proto*/ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmMessage(PmMessage); static CYTHON_INLINE PmMessage __Pyx_PyInt_from_py_PmMessage(PyObject *); static CYTHON_INLINE PmTimestamp __Pyx_PyInt_from_py_PmTimestamp(PyObject *); static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmTimestamp(PmTimestamp); static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *); static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *); static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject *); static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject *); static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject *); static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject *); static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject *); static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject *); static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject *); static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject *); static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject *); static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject *); static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject *); static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject *); static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *); static void __Pyx_AddTraceback(const char *funcname); /*proto*/ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ /* Module declarations from _pyportmidi */ static PyTypeObject *__pyx_ptype_11_pyportmidi_Output = 0; static PyTypeObject *__pyx_ptype_11_pyportmidi_Input = 0; #define __Pyx_MODULE_NAME "_pyportmidi" int __pyx_module_is_main__pyportmidi = 0; /* Implementation of _pyportmidi */ static PyObject *__pyx_builtin_Exception; static PyObject *__pyx_builtin_IndexError; static PyObject *__pyx_builtin_range; static char __pyx_k_1[] = "Opening Midi Output"; static char __pyx_k_2[] = "Unable to open Midi OutputDevice="; static char __pyx_k_3[] = " err="; static char __pyx_k_4[] = "Closing MIDI output stream and destroying instance"; static char __pyx_k_5[] = "midi Output not open."; static char __pyx_k_6[] = "midi Output aborted. Need to call Close after Abort."; static char __pyx_k_7[] = "maximum list length is 1024"; static char __pyx_k_8[] = " arguments in event list"; static char __pyx_k_9[] = " : "; static char __pyx_k_10[] = "writing to midi buffer"; static char __pyx_k_11[] = "Writing to MIDI buffer"; static char __pyx_k_12[] = "MIDI input opened."; static char __pyx_k_13[] = "Closing MIDI input stream and destroying instance"; static char __pyx_k_14[] = "midi Input not open."; static char __pyx_k_15[] = "maximum buffer length is 1024"; static char __pyx_k_16[] = "minimum buffer length is 1"; static char __pyx_k_17[] = "0.07"; static char __pyx_k_18[] = "FILT_CHANNEL_AFTERTOUCH"; static char __pyx_k_19[] = "FILT_POLY_AFTERTOUCH"; static char __pyx_k_20[] = "Initialize (line 132)"; static char __pyx_k_21[] = "Terminate (line 139)"; static char __pyx_k_22[] = "GetDeviceInfo (line 156)"; static char __pyx_k_23[] = "Time (line 173)"; static char __pyx_k_24[] = "GetErrorText (line 180)"; static char __pyx_k_25[] = "Channel (line 187)"; static char __pyx_k_26[] = "Output._check_open (line 248)"; static char __pyx_k_27[] = "Output.Close (line 258)"; static char __pyx_k_28[] = "Output.Abort (line 274)"; static char __pyx_k_29[] = "Output.Write (line 293)"; static char __pyx_k_30[] = "Output.WriteShort (line 333)"; static char __pyx_k_31[] = "Output.WriteSysEx (line 356)"; static char __pyx_k_32[] = "Input._check_open (line 422)"; static char __pyx_k_33[] = "Input.Close (line 430)"; static char __pyx_k_34[] = "Input.SetFilter (line 447)"; static char __pyx_k_35[] = "Input.SetChannelMask (line 481)"; static char __pyx_k_36[] = "Input.Poll (line 502)"; static char __pyx_k_37[] = "Input.Read (line 514)"; static char __pyx_k__B[] = "B"; static char __pyx_k__i[] = "i"; static char __pyx_k__msg[] = "msg"; static char __pyx_k__Poll[] = "Poll"; static char __pyx_k__Read[] = "Read"; static char __pyx_k__TRUE[] = "TRUE"; static char __pyx_k__Time[] = "Time"; static char __pyx_k__midi[] = "midi"; static char __pyx_k__name[] = "name"; static char __pyx_k__when[] = "when"; static char __pyx_k__Abort[] = "Abort"; static char __pyx_k__Close[] = "Close"; static char __pyx_k__FALSE[] = "FALSE"; static char __pyx_k__Input[] = "Input"; static char __pyx_k__Write[] = "Write"; static char __pyx_k__array[] = "array"; static char __pyx_k__data1[] = "data1"; static char __pyx_k__data2[] = "data2"; static char __pyx_k__debug[] = "debug"; static char __pyx_k__input[] = "input"; static char __pyx_k__range[] = "range"; static char __pyx_k__Output[] = "Output"; static char __pyx_k__interf[] = "interf"; static char __pyx_k__opened[] = "opened"; static char __pyx_k__output[] = "output"; static char __pyx_k__status[] = "status"; static char __pyx_k__Channel[] = "Channel"; static char __pyx_k__FILT_F9[] = "FILT_F9"; static char __pyx_k__FILT_FD[] = "FILT_FD"; static char __pyx_k__latency[] = "latency"; static char __pyx_k__message[] = "message"; static char __pyx_k__FILT_MTC[] = "FILT_MTC"; static char __pyx_k____main__[] = "__main__"; static char __pyx_k____test__[] = "__test__"; static char __pyx_k___aborted[] = "_aborted"; static char __pyx_k__tostring[] = "tostring"; static char __pyx_k__Exception[] = "Exception"; static char __pyx_k__FILT_NOTE[] = "FILT_NOTE"; static char __pyx_k__FILT_PLAY[] = "FILT_PLAY"; static char __pyx_k__FILT_TICK[] = "FILT_TICK"; static char __pyx_k__FILT_TUNE[] = "FILT_TUNE"; static char __pyx_k__SetFilter[] = "SetFilter"; static char __pyx_k__Terminate[] = "Terminate"; static char __pyx_k__timestamp[] = "timestamp"; static char __pyx_k__FILT_CLOCK[] = "FILT_CLOCK"; static char __pyx_k__FILT_RESET[] = "FILT_RESET"; static char __pyx_k__FILT_SYSEX[] = "FILT_SYSEX"; static char __pyx_k__IndexError[] = "IndexError"; static char __pyx_k__Initialize[] = "Initialize"; static char __pyx_k__WriteShort[] = "WriteShort"; static char __pyx_k__WriteSysEx[] = "WriteSysEx"; static char __pyx_k__buffersize[] = "buffersize"; static char __pyx_k__FILT_ACTIVE[] = "FILT_ACTIVE"; static char __pyx_k__InputDevice[] = "InputDevice"; static char __pyx_k____version__[] = "__version__"; static char __pyx_k___check_open[] = "_check_open"; static char __pyx_k__FILT_CONTROL[] = "FILT_CONTROL"; static char __pyx_k__FILT_PROGRAM[] = "FILT_PROGRAM"; static char __pyx_k__GetErrorText[] = "GetErrorText"; static char __pyx_k__OutputDevice[] = "OutputDevice"; static char __pyx_k__FILT_REALTIME[] = "FILT_REALTIME"; static char __pyx_k__GetDeviceInfo[] = "GetDeviceInfo"; static char __pyx_k__FILT_PITCHBEND[] = "FILT_PITCHBEND"; static char __pyx_k__FILT_UNDEFINED[] = "FILT_UNDEFINED"; static char __pyx_k__SetChannelMask[] = "SetChannelMask"; static char __pyx_k__FILT_AFTERTOUCH[] = "FILT_AFTERTOUCH"; static char __pyx_k__FILT_SONG_SELECT[] = "FILT_SONG_SELECT"; static char __pyx_k__FILT_SONG_POSITION[] = "FILT_SONG_POSITION"; static PyObject *__pyx_kp_s_1; static PyObject *__pyx_kp_s_10; static PyObject *__pyx_kp_s_11; static PyObject *__pyx_kp_s_12; static PyObject *__pyx_kp_s_13; static PyObject *__pyx_kp_s_14; static PyObject *__pyx_kp_s_15; static PyObject *__pyx_kp_s_16; static PyObject *__pyx_kp_s_17; static PyObject *__pyx_n_s_18; static PyObject *__pyx_n_s_19; static PyObject *__pyx_kp_s_2; static PyObject *__pyx_kp_u_20; static PyObject *__pyx_kp_u_21; static PyObject *__pyx_kp_u_22; static PyObject *__pyx_kp_u_23; static PyObject *__pyx_kp_u_24; static PyObject *__pyx_kp_u_25; static PyObject *__pyx_kp_u_26; static PyObject *__pyx_kp_u_27; static PyObject *__pyx_kp_u_28; static PyObject *__pyx_kp_u_29; static PyObject *__pyx_kp_s_3; static PyObject *__pyx_kp_u_30; static PyObject *__pyx_kp_u_31; static PyObject *__pyx_kp_u_32; static PyObject *__pyx_kp_u_33; static PyObject *__pyx_kp_u_34; static PyObject *__pyx_kp_u_35; static PyObject *__pyx_kp_u_36; static PyObject *__pyx_kp_u_37; static PyObject *__pyx_kp_s_4; static PyObject *__pyx_kp_s_5; static PyObject *__pyx_kp_s_6; static PyObject *__pyx_kp_s_7; static PyObject *__pyx_kp_s_8; static PyObject *__pyx_kp_s_9; static PyObject *__pyx_n_s__Abort; static PyObject *__pyx_n_s__B; static PyObject *__pyx_n_s__Channel; static PyObject *__pyx_n_s__Close; static PyObject *__pyx_n_s__Exception; static PyObject *__pyx_n_s__FALSE; static PyObject *__pyx_n_s__FILT_ACTIVE; static PyObject *__pyx_n_s__FILT_AFTERTOUCH; static PyObject *__pyx_n_s__FILT_CLOCK; static PyObject *__pyx_n_s__FILT_CONTROL; static PyObject *__pyx_n_s__FILT_F9; static PyObject *__pyx_n_s__FILT_FD; static PyObject *__pyx_n_s__FILT_MTC; static PyObject *__pyx_n_s__FILT_NOTE; static PyObject *__pyx_n_s__FILT_PITCHBEND; static PyObject *__pyx_n_s__FILT_PLAY; static PyObject *__pyx_n_s__FILT_PROGRAM; static PyObject *__pyx_n_s__FILT_REALTIME; static PyObject *__pyx_n_s__FILT_RESET; static PyObject *__pyx_n_s__FILT_SONG_POSITION; static PyObject *__pyx_n_s__FILT_SONG_SELECT; static PyObject *__pyx_n_s__FILT_SYSEX; static PyObject *__pyx_n_s__FILT_TICK; static PyObject *__pyx_n_s__FILT_TUNE; static PyObject *__pyx_n_s__FILT_UNDEFINED; static PyObject *__pyx_n_s__GetDeviceInfo; static PyObject *__pyx_n_s__GetErrorText; static PyObject *__pyx_n_s__IndexError; static PyObject *__pyx_n_s__Initialize; static PyObject *__pyx_n_s__Input; static PyObject *__pyx_n_s__InputDevice; static PyObject *__pyx_n_s__Output; static PyObject *__pyx_n_s__OutputDevice; static PyObject *__pyx_n_s__Poll; static PyObject *__pyx_n_s__Read; static PyObject *__pyx_n_s__SetChannelMask; static PyObject *__pyx_n_s__SetFilter; static PyObject *__pyx_n_s__TRUE; static PyObject *__pyx_n_s__Terminate; static PyObject *__pyx_n_s__Time; static PyObject *__pyx_n_s__Write; static PyObject *__pyx_n_s__WriteShort; static PyObject *__pyx_n_s__WriteSysEx; static PyObject *__pyx_n_s____main__; static PyObject *__pyx_n_s____test__; static PyObject *__pyx_n_s____version__; static PyObject *__pyx_n_s___aborted; static PyObject *__pyx_n_s___check_open; static PyObject *__pyx_n_s__array; static PyObject *__pyx_n_s__buffersize; static PyObject *__pyx_n_s__data1; static PyObject *__pyx_n_s__data2; static PyObject *__pyx_n_s__debug; static PyObject *__pyx_n_s__i; static PyObject *__pyx_n_s__input; static PyObject *__pyx_n_s__interf; static PyObject *__pyx_n_s__latency; static PyObject *__pyx_n_s__message; static PyObject *__pyx_n_s__midi; static PyObject *__pyx_n_s__msg; static PyObject *__pyx_n_s__name; static PyObject *__pyx_n_s__opened; static PyObject *__pyx_n_s__output; static PyObject *__pyx_n_s__range; static PyObject *__pyx_n_s__status; static PyObject *__pyx_n_s__timestamp; static PyObject *__pyx_n_s__tostring; static PyObject *__pyx_n_s__when; static PyObject *__pyx_int_0; static PyObject *__pyx_int_1; static PyObject *__pyx_int_8; static PyObject *__pyx_int_16; static PyObject *__pyx_int_0x1; static PyObject *__pyx_int_0x2; static PyObject *__pyx_int_0x4; static PyObject *__pyx_int_0x8; static PyObject *__pyx_int_0x10; static PyObject *__pyx_int_0x20; static PyObject *__pyx_int_0x30; static PyObject *__pyx_int_0x40; static PyObject *__pyx_int_0x7F; static PyObject *__pyx_int_0x80; static PyObject *__pyx_int_0xFF; static PyObject *__pyx_int_1024; static PyObject *__pyx_int_4096; static PyObject *__pyx_int_0x100; static PyObject *__pyx_int_0x200; static PyObject *__pyx_int_0x300; static PyObject *__pyx_int_0x400; static PyObject *__pyx_int_0x800; static PyObject *__pyx_int_0x1000; static PyObject *__pyx_int_0x2000; static PyObject *__pyx_int_0x4000; static PyObject *__pyx_int_0x8000; static PyObject *__pyx_int_0xFF00; static PyObject *__pyx_int_0x10000; static PyObject *__pyx_int_0xFF0000; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":132 * TRUE=1 * * def Initialize(): # <<<<<<<<<<<<<< * """ * Initialize: call this first */ static PyObject *__pyx_pf_11_pyportmidi_Initialize(PyObject *__pyx_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_Initialize[] = "\nInitialize: call this first\n "; static PyObject *__pyx_pf_11_pyportmidi_Initialize(PyObject *__pyx_self, PyObject *unused) { PyObject *__pyx_r = NULL; __Pyx_RefNannySetupContext("Initialize"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":136 * Initialize: call this first * """ * Pm_Initialize() # <<<<<<<<<<<<<< * Pt_Start(1, NULL, NULL) # /[inserted by cython to avoid comment start]* equiv to TIME_START: start timer w/ ms accuracy *[inserted by cython to avoid comment closer]/ * */ Pm_Initialize(); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":137 * """ * Pm_Initialize() * Pt_Start(1, NULL, NULL) # /[inserted by cython to avoid comment start]* equiv to TIME_START: start timer w/ ms accuracy *[inserted by cython to avoid comment closer]/ # <<<<<<<<<<<<<< * * def Terminate(): */ Pt_Start(1, NULL, NULL); __pyx_r = Py_None; __Pyx_INCREF(Py_None); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":139 * Pt_Start(1, NULL, NULL) # /[inserted by cython to avoid comment start]* equiv to TIME_START: start timer w/ ms accuracy *[inserted by cython to avoid comment closer]/ * * def Terminate(): # <<<<<<<<<<<<<< * """ * Terminate: call this to clean up Midi streams when done. */ static PyObject *__pyx_pf_11_pyportmidi_Terminate(PyObject *__pyx_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_Terminate[] = "\nTerminate: call this to clean up Midi streams when done.\nIf you do not call this on Windows machines when you are\ndone with MIDI, your system may crash.\n "; static PyObject *__pyx_pf_11_pyportmidi_Terminate(PyObject *__pyx_self, PyObject *unused) { PyObject *__pyx_r = NULL; __Pyx_RefNannySetupContext("Terminate"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":145 * done with MIDI, your system may crash. * """ * Pm_Terminate() # <<<<<<<<<<<<<< * * def GetDefaultInputDeviceID(): */ Pm_Terminate(); __pyx_r = Py_None; __Pyx_INCREF(Py_None); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":147 * Pm_Terminate() * * def GetDefaultInputDeviceID(): # <<<<<<<<<<<<<< * return Pm_GetDefaultInputDeviceID() * */ static PyObject *__pyx_pf_11_pyportmidi_GetDefaultInputDeviceID(PyObject *__pyx_self, PyObject *unused); /*proto*/ static PyObject *__pyx_pf_11_pyportmidi_GetDefaultInputDeviceID(PyObject *__pyx_self, PyObject *unused) { PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; __Pyx_RefNannySetupContext("GetDefaultInputDeviceID"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":148 * * def GetDefaultInputDeviceID(): * return Pm_GetDefaultInputDeviceID() # <<<<<<<<<<<<<< * * def GetDefaultOutputDeviceID(): */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = __Pyx_PyInt_to_py_PmDeviceID(Pm_GetDefaultInputDeviceID()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.GetDefaultInputDeviceID"); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":150 * return Pm_GetDefaultInputDeviceID() * * def GetDefaultOutputDeviceID(): # <<<<<<<<<<<<<< * return Pm_GetDefaultOutputDeviceID() * */ static PyObject *__pyx_pf_11_pyportmidi_GetDefaultOutputDeviceID(PyObject *__pyx_self, PyObject *unused); /*proto*/ static PyObject *__pyx_pf_11_pyportmidi_GetDefaultOutputDeviceID(PyObject *__pyx_self, PyObject *unused) { PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; __Pyx_RefNannySetupContext("GetDefaultOutputDeviceID"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":151 * * def GetDefaultOutputDeviceID(): * return Pm_GetDefaultOutputDeviceID() # <<<<<<<<<<<<<< * * def CountDevices(): */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = __Pyx_PyInt_to_py_PmDeviceID(Pm_GetDefaultOutputDeviceID()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.GetDefaultOutputDeviceID"); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":153 * return Pm_GetDefaultOutputDeviceID() * * def CountDevices(): # <<<<<<<<<<<<<< * return Pm_CountDevices() * */ static PyObject *__pyx_pf_11_pyportmidi_CountDevices(PyObject *__pyx_self, PyObject *unused); /*proto*/ static PyObject *__pyx_pf_11_pyportmidi_CountDevices(PyObject *__pyx_self, PyObject *unused) { PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; __Pyx_RefNannySetupContext("CountDevices"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":154 * * def CountDevices(): * return Pm_CountDevices() # <<<<<<<<<<<<<< * * def GetDeviceInfo(i): */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = PyInt_FromLong(Pm_CountDevices()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.CountDevices"); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":156 * return Pm_CountDevices() * * def GetDeviceInfo(i): # <<<<<<<<<<<<<< * """ * GetDeviceInfo(): returns 5 parameters */ static PyObject *__pyx_pf_11_pyportmidi_GetDeviceInfo(PyObject *__pyx_self, PyObject *__pyx_v_i); /*proto*/ static char __pyx_doc_11_pyportmidi_GetDeviceInfo[] = "\nGetDeviceInfo(): returns 5 parameters\n - underlying MIDI API\n - device name\n - TRUE iff input is available\n - TRUE iff output is available\n - TRUE iff device stream is already open\n "; static PyObject *__pyx_pf_11_pyportmidi_GetDeviceInfo(PyObject *__pyx_self, PyObject *__pyx_v_i) { PmDeviceInfo *__pyx_v_info; PyObject *__pyx_r = NULL; PmDeviceID __pyx_t_1; int __pyx_t_2; PyObject *__pyx_t_3 = NULL; PyObject *__pyx_t_4 = NULL; PyObject *__pyx_t_5 = NULL; PyObject *__pyx_t_6 = NULL; PyObject *__pyx_t_7 = NULL; PyObject *__pyx_t_8 = NULL; __Pyx_RefNannySetupContext("GetDeviceInfo"); __pyx_self = __pyx_self; __Pyx_INCREF(__pyx_v_i); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":168 * * # disregarding the constness from Pm_GetDeviceInfo, since pyrex doesn't do const. * info = Pm_GetDeviceInfo(i) # <<<<<<<<<<<<<< * * if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened */ __pyx_t_1 = __Pyx_PyInt_from_py_PmDeviceID(__pyx_v_i); if (unlikely((__pyx_t_1 == (PmDeviceID)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_info = ((PmDeviceInfo *)Pm_GetDeviceInfo(__pyx_t_1)); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":170 * info = Pm_GetDeviceInfo(i) * * if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened # <<<<<<<<<<<<<< * else: return * */ __pyx_t_2 = (__pyx_v_info != NULL); if (__pyx_t_2) { __Pyx_XDECREF(__pyx_r); __pyx_t_3 = __Pyx_PyBytes_FromString(__pyx_v_info->interf); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); __pyx_t_4 = __Pyx_PyBytes_FromString(__pyx_v_info->name); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); __pyx_t_5 = PyInt_FromLong(__pyx_v_info->input); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); __pyx_t_6 = PyInt_FromLong(__pyx_v_info->output); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __pyx_t_7 = PyInt_FromLong(__pyx_v_info->opened); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_7); __pyx_t_8 = PyTuple_New(5); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_8, 0, ((PyObject *)__pyx_t_3)); __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); PyTuple_SET_ITEM(__pyx_t_8, 1, ((PyObject *)__pyx_t_4)); __Pyx_GIVEREF(((PyObject *)__pyx_t_4)); PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_8, 3, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 4, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_3 = 0; __pyx_t_4 = 0; __pyx_t_5 = 0; __pyx_t_6 = 0; __pyx_t_7 = 0; __pyx_r = __pyx_t_8; __pyx_t_8 = 0; goto __pyx_L0; goto __pyx_L5; } /*else*/ { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":171 * * if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened * else: return # <<<<<<<<<<<<<< * * def Time(): */ __Pyx_XDECREF(__pyx_r); __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; } __pyx_L5:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_3); __Pyx_XDECREF(__pyx_t_4); __Pyx_XDECREF(__pyx_t_5); __Pyx_XDECREF(__pyx_t_6); __Pyx_XDECREF(__pyx_t_7); __Pyx_XDECREF(__pyx_t_8); __Pyx_AddTraceback("_pyportmidi.GetDeviceInfo"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF(__pyx_v_i); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":173 * else: return * * def Time(): # <<<<<<<<<<<<<< * """ * Time() returns the current time in ms */ static PyObject *__pyx_pf_11_pyportmidi_Time(PyObject *__pyx_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_Time[] = "\nTime() returns the current time in ms\nof the PortMidi timer\n "; static PyObject *__pyx_pf_11_pyportmidi_Time(PyObject *__pyx_self, PyObject *unused) { PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; __Pyx_RefNannySetupContext("Time"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":178 * of the PortMidi timer * """ * return Pt_Time() # <<<<<<<<<<<<<< * * def GetErrorText(err): */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = __Pyx_PyInt_to_py_PtTimestamp(Pt_Time()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.Time"); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":180 * return Pt_Time() * * def GetErrorText(err): # <<<<<<<<<<<<<< * """ * GetErrorText() returns human-readable error */ static PyObject *__pyx_pf_11_pyportmidi_GetErrorText(PyObject *__pyx_self, PyObject *__pyx_v_err); /*proto*/ static char __pyx_doc_11_pyportmidi_GetErrorText[] = "\nGetErrorText() returns human-readable error\nmessages translated from error numbers\n "; static PyObject *__pyx_pf_11_pyportmidi_GetErrorText(PyObject *__pyx_self, PyObject *__pyx_v_err) { PyObject *__pyx_r = NULL; PmError __pyx_t_1; PyObject *__pyx_t_2 = NULL; __Pyx_RefNannySetupContext("GetErrorText"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":185 * messages translated from error numbers * """ * return Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * def Channel(chan): */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __pyx_r = ((PyObject *)__pyx_t_2); __pyx_t_2 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("_pyportmidi.GetErrorText"); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":187 * return Pm_GetErrorText(err) * * def Channel(chan): # <<<<<<<<<<<<<< * """ * Channel() is used with ChannelMask on input MIDI streams. */ static PyObject *__pyx_pf_11_pyportmidi_Channel(PyObject *__pyx_self, PyObject *__pyx_v_chan); /*proto*/ static char __pyx_doc_11_pyportmidi_Channel[] = "\nChannel() is used with ChannelMask on input MIDI streams.\nExample: to receive input on channels 1 and 10 on a MIDI\n stream called MidiIn:\nMidiIn.SetChannelMask(pypm.Channel(1) | pypm.Channel(10))\n\nnote: PyPortMidi Channel function has been altered from\n the original PortMidi c call to correct for what\n seems to be a bug --- i.e. channel filters were\n all numbered from 0 to 15 instead of 1 to 16.\n "; static PyObject *__pyx_pf_11_pyportmidi_Channel(PyObject *__pyx_self, PyObject *__pyx_v_chan) { PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; int __pyx_t_2; __Pyx_RefNannySetupContext("Channel"); __pyx_self = __pyx_self; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":199 * all numbered from 0 to 15 instead of 1 to 16. * """ * return Pm_Channel(chan-1) # <<<<<<<<<<<<<< * * cdef class Output: */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = PyNumber_Subtract(__pyx_v_chan, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_1 = PyInt_FromLong(Pm_Channel(__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.Channel"); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":214 * cdef int _aborted * * def __init__(self, OutputDevice, latency=0): # <<<<<<<<<<<<<< * * cdef PmError err */ static int __pyx_pf_11_pyportmidi_6Output___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static int __pyx_pf_11_pyportmidi_6Output___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_OutputDevice = 0; PyObject *__pyx_v_latency = 0; PmError __pyx_v_err; PmTimeProcPtr __pyx_v_PmPtr; PyObject *__pyx_v_s; int __pyx_r; int __pyx_t_1; PyObject *__pyx_t_2 = NULL; int __pyx_t_3; long __pyx_t_4; static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__OutputDevice,&__pyx_n_s__latency,0}; __Pyx_RefNannySetupContext("__init__"); if (unlikely(__pyx_kwds)) { Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); PyObject* values[2] = {0,0}; values[1] = ((PyObject *)__pyx_int_0); switch (PyTuple_GET_SIZE(__pyx_args)) { case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); case 0: break; default: goto __pyx_L5_argtuple_error; } switch (PyTuple_GET_SIZE(__pyx_args)) { case 0: values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__OutputDevice); if (likely(values[0])) kw_args--; else goto __pyx_L5_argtuple_error; case 1: if (kw_args > 1) { PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__latency); if (unlikely(value)) { values[1] = value; kw_args--; } } } if (unlikely(kw_args > 0)) { if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } __pyx_v_OutputDevice = values[0]; __pyx_v_latency = values[1]; } else { __pyx_v_latency = ((PyObject *)__pyx_int_0); switch (PyTuple_GET_SIZE(__pyx_args)) { case 2: __pyx_v_latency = PyTuple_GET_ITEM(__pyx_args, 1); case 1: __pyx_v_OutputDevice = PyTuple_GET_ITEM(__pyx_args, 0); break; default: goto __pyx_L5_argtuple_error; } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("_pyportmidi.Output.__init__"); return -1; __pyx_L4_argument_unpacking_done:; __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_OutputDevice); __Pyx_INCREF(__pyx_v_latency); __pyx_v_s = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":220 * cdef PmTimeProcPtr PmPtr * * self.i = OutputDevice # <<<<<<<<<<<<<< * self.debug = 0 * self._aborted = 0 */ __pyx_t_1 = __Pyx_PyInt_AsInt(__pyx_v_OutputDevice); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 220; __pyx_clineno = __LINE__; goto __pyx_L1_error;} ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->i = __pyx_t_1; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":221 * * self.i = OutputDevice * self.debug = 0 # <<<<<<<<<<<<<< * self._aborted = 0 * */ ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":222 * self.i = OutputDevice * self.debug = 0 * self._aborted = 0 # <<<<<<<<<<<<<< * * if latency == 0: */ ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->_aborted = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":224 * self._aborted = 0 * * if latency == 0: # <<<<<<<<<<<<<< * PmPtr = NULL * else: */ __pyx_t_2 = PyObject_RichCompare(__pyx_v_latency, __pyx_int_0, Py_EQ); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (__pyx_t_3) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":225 * * if latency == 0: * PmPtr = NULL # <<<<<<<<<<<<<< * else: * PmPtr = &Pt_Time */ __pyx_v_PmPtr = NULL; goto __pyx_L6; } /*else*/ { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":227 * PmPtr = NULL * else: * PmPtr = &Pt_Time # <<<<<<<<<<<<<< * if self.debug: print "Opening Midi Output" * # Why is bufferSize 0 here? */ __pyx_v_PmPtr = ((PmTimestamp (*)(void *))(&Pt_Time)); } __pyx_L6:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":228 * else: * PmPtr = &Pt_Time * if self.debug: print "Opening Midi Output" # <<<<<<<<<<<<<< * # Why is bufferSize 0 here? * err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency) */ __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug; if (__pyx_t_1) { if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 228; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L7; } __pyx_L7:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":230 * if self.debug: print "Opening Midi Output" * # Why is bufferSize 0 here? * err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency) # <<<<<<<<<<<<<< * if err < 0: * s = Pm_GetErrorText(err) */ __pyx_t_4 = __Pyx_PyInt_AsLong(__pyx_v_latency); if (unlikely((__pyx_t_4 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 230; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_err = Pm_OpenOutput((&((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi), ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->i, NULL, 0, __pyx_v_PmPtr, NULL, __pyx_t_4); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":231 * # Why is bufferSize 0 here? * err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency) * if err < 0: # <<<<<<<<<<<<<< * s = Pm_GetErrorText(err) * # Something's amiss here - if we try to throw an Exception */ __pyx_t_3 = (__pyx_v_err < 0); if (__pyx_t_3) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":232 * err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency) * if err < 0: * s = Pm_GetErrorText(err) # <<<<<<<<<<<<<< * # Something's amiss here - if we try to throw an Exception * # here, we crash. */ __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_DECREF(__pyx_v_s); __pyx_v_s = ((PyObject *)__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":235 * # Something's amiss here - if we try to throw an Exception * # here, we crash. * if not err == -10000: # <<<<<<<<<<<<<< * raise Exception,s * else: */ __pyx_t_3 = (!(__pyx_v_err == -10000)); if (__pyx_t_3) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":236 * # here, we crash. * if not err == -10000: * raise Exception,s # <<<<<<<<<<<<<< * else: * print "Unable to open Midi OutputDevice=",OutputDevice," err=",s */ __Pyx_Raise(__pyx_builtin_Exception, __pyx_v_s, 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L9; } /*else*/ { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":238 * raise Exception,s * else: * print "Unable to open Midi OutputDevice=",OutputDevice," err=",s # <<<<<<<<<<<<<< * * def __dealloc__(self): */ __pyx_t_2 = PyTuple_New(4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_INCREF(((PyObject *)__pyx_kp_s_2)); PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_kp_s_2)); __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_2)); __Pyx_INCREF(__pyx_v_OutputDevice); PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_OutputDevice); __Pyx_GIVEREF(__pyx_v_OutputDevice); __Pyx_INCREF(((PyObject *)__pyx_kp_s_3)); PyTuple_SET_ITEM(__pyx_t_2, 2, ((PyObject *)__pyx_kp_s_3)); __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_3)); __Pyx_INCREF(__pyx_v_s); PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_v_s); __Pyx_GIVEREF(__pyx_v_s); if (__Pyx_Print(__pyx_t_2, 1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; } __pyx_L9:; goto __pyx_L8; } __pyx_L8:; __pyx_r = 0; goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("_pyportmidi.Output.__init__"); __pyx_r = -1; __pyx_L0:; __Pyx_DECREF(__pyx_v_s); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_OutputDevice); __Pyx_DECREF(__pyx_v_latency); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":240 * print "Unable to open Midi OutputDevice=",OutputDevice," err=",s * * def __dealloc__(self): # <<<<<<<<<<<<<< * if self.debug: print "Closing MIDI output stream and destroying instance" * #err = Pm_Abort(self.midi) */ static void __pyx_pf_11_pyportmidi_6Output___dealloc__(PyObject *__pyx_v_self); /*proto*/ static void __pyx_pf_11_pyportmidi_6Output___dealloc__(PyObject *__pyx_v_self) { PyObject *__pyx_v_err; int __pyx_t_1; PyObject *__pyx_t_2 = NULL; int __pyx_t_3; PmError __pyx_t_4; __Pyx_RefNannySetupContext("__dealloc__"); __Pyx_INCREF((PyObject *)__pyx_v_self); __pyx_v_err = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":241 * * def __dealloc__(self): * if self.debug: print "Closing MIDI output stream and destroying instance" # <<<<<<<<<<<<<< * #err = Pm_Abort(self.midi) * #if err < 0: raise Exception, Pm_GetErrorText(err) */ __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug; if (__pyx_t_1) { if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_4)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":244 * #err = Pm_Abort(self.midi) * #if err < 0: raise Exception, Pm_GetErrorText(err) * err = Pm_Close(self.midi) # <<<<<<<<<<<<<< * if err < 0: raise Exception, Pm_GetErrorText(err) * */ __pyx_t_2 = PyInt_FromLong(Pm_Close(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_v_err); __pyx_v_err = __pyx_t_2; __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":245 * #if err < 0: raise Exception, Pm_GetErrorText(err) * err = Pm_Close(self.midi) * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * */ __pyx_t_2 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (__pyx_t_3) { __pyx_t_4 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_4)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("_pyportmidi.Output.__dealloc__"); __pyx_L0:; __Pyx_DECREF(__pyx_v_err); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_RefNannyFinishContext(); } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":248 * * * def _check_open(self): # <<<<<<<<<<<<<< * """ checks to see if the midi is open, and if not, raises an error. * """ */ static PyObject *__pyx_pf_11_pyportmidi_6Output__check_open(PyObject *__pyx_v_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_6Output__check_open[] = " checks to see if the midi is open, and if not, raises an error.\n "; static PyObject *__pyx_pf_11_pyportmidi_6Output__check_open(PyObject *__pyx_v_self, PyObject *unused) { PyObject *__pyx_r = NULL; int __pyx_t_1; int __pyx_t_2; __Pyx_RefNannySetupContext("_check_open"); __Pyx_INCREF((PyObject *)__pyx_v_self); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":252 * """ * * if self.midi == NULL: # <<<<<<<<<<<<<< * raise Exception, "midi Output not open." * */ __pyx_t_1 = (((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi == NULL); if (__pyx_t_1) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":253 * * if self.midi == NULL: * raise Exception, "midi Output not open." # <<<<<<<<<<<<<< * * if self._aborted: */ __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_kp_s_5), 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 253; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":255 * raise Exception, "midi Output not open." * * if self._aborted: # <<<<<<<<<<<<<< * raise Exception, "midi Output aborted. Need to call Close after Abort." * */ __pyx_t_2 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->_aborted; if (__pyx_t_2) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":256 * * if self._aborted: * raise Exception, "midi Output aborted. Need to call Close after Abort." # <<<<<<<<<<<<<< * * def Close(self): */ __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_kp_s_6), 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_AddTraceback("_pyportmidi.Output._check_open"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":258 * raise Exception, "midi Output aborted. Need to call Close after Abort." * * def Close(self): # <<<<<<<<<<<<<< * """ * Close() */ static PyObject *__pyx_pf_11_pyportmidi_6Output_Close(PyObject *__pyx_v_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_6Output_Close[] = "\nClose()\n closes a midi stream, flushing any pending buffers.\n (PortMidi attempts to close open streams when the application\n exits -- this is particularly difficult under Windows.)\n "; static PyObject *__pyx_pf_11_pyportmidi_6Output_Close(PyObject *__pyx_v_self, PyObject *unused) { PyObject *__pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; int __pyx_t_2; PmError __pyx_t_3; __Pyx_RefNannySetupContext("Close"); __Pyx_INCREF((PyObject *)__pyx_v_self); __pyx_v_err = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":268 * # return * * err = Pm_Close(self.midi) # <<<<<<<<<<<<<< * if err < 0: * raise Exception, Pm_GetErrorText(err) */ __pyx_t_1 = PyInt_FromLong(Pm_Close(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_v_err); __pyx_v_err = __pyx_t_1; __pyx_t_1 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":269 * * err = Pm_Close(self.midi) * if err < 0: # <<<<<<<<<<<<<< * raise Exception, Pm_GetErrorText(err) * #self.midi = NULL */ __pyx_t_1 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; if (__pyx_t_2) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":270 * err = Pm_Close(self.midi) * if err < 0: * raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * #self.midi = NULL * */ __pyx_t_3 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_3)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0); __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.Output.Close"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF(__pyx_v_err); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":274 * * * def Abort(self): # <<<<<<<<<<<<<< * """ * Abort() terminates outgoing messages immediately */ static PyObject *__pyx_pf_11_pyportmidi_6Output_Abort(PyObject *__pyx_v_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_6Output_Abort[] = "\nAbort() terminates outgoing messages immediately\n The caller should immediately close the output port;\n this call may result in transmission of a partial midi message.\n There is no abort for Midi input because the user can simply\n ignore messages in the buffer and close an input device at\n any time.\n "; static PyObject *__pyx_pf_11_pyportmidi_6Output_Abort(PyObject *__pyx_v_self, PyObject *unused) { PyObject *__pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; int __pyx_t_2; PmError __pyx_t_3; __Pyx_RefNannySetupContext("Abort"); __Pyx_INCREF((PyObject *)__pyx_v_self); __pyx_v_err = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":286 * # return * * err = Pm_Abort(self.midi) # <<<<<<<<<<<<<< * if err < 0: * raise Exception, Pm_GetErrorText(err) */ __pyx_t_1 = PyInt_FromLong(Pm_Abort(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_v_err); __pyx_v_err = __pyx_t_1; __pyx_t_1 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":287 * * err = Pm_Abort(self.midi) * if err < 0: # <<<<<<<<<<<<<< * raise Exception, Pm_GetErrorText(err) * */ __pyx_t_1 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 287; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 287; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; if (__pyx_t_2) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":288 * err = Pm_Abort(self.midi) * if err < 0: * raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * self._aborted = 1 */ __pyx_t_3 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 288; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_3)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 288; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0); __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 288; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":290 * raise Exception, Pm_GetErrorText(err) * * self._aborted = 1 # <<<<<<<<<<<<<< * * */ ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->_aborted = 1; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.Output.Abort"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF(__pyx_v_err); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":293 * * * def Write(self, data): # <<<<<<<<<<<<<< * """ * Write(data) */ static PyObject *__pyx_pf_11_pyportmidi_6Output_Write(PyObject *__pyx_v_self, PyObject *__pyx_v_data); /*proto*/ static char __pyx_doc_11_pyportmidi_6Output_Write[] = "\nWrite(data)\n output a series of MIDI information in the form of a list:\n Write([[[status <,data1><,data2><,data3>],timestamp],\n [[status <,data1><,data2><,data3>],timestamp],...])\n fields are optional\n example: choose program change 1 at time 20000 and\n send note 65 with velocity 100 500 ms later.\n Write([[[0xc0,0,0],20000],[[0x90,60,100],20500]])\n notes:\n 1. timestamps will be ignored if latency = 0.\n 2. To get a note to play immediately, send MIDI info with\n timestamp read from function Time.\n 3. understanding optional data fields:\n Write([[[0xc0,0,0],20000]]) is equivalent to\n Write([[[0xc0],20000]])\n "; static PyObject *__pyx_pf_11_pyportmidi_6Output_Write(PyObject *__pyx_v_self, PyObject *__pyx_v_data) { PmEvent __pyx_v_buffer[1024]; PmError __pyx_v_err; int __pyx_v_i; PyObject *__pyx_v_loop1; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; Py_ssize_t __pyx_t_3; int __pyx_t_4; Py_ssize_t __pyx_t_5; PyObject *__pyx_t_6 = NULL; Py_ssize_t __pyx_t_7; int __pyx_t_8; PyObject *__pyx_t_9 = NULL; PyObject *__pyx_t_10 = NULL; PmMessage __pyx_t_11; PmTimestamp __pyx_t_12; __Pyx_RefNannySetupContext("Write"); __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_data); __pyx_v_loop1 = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":315 * cdef int i * * self._check_open() # <<<<<<<<<<<<<< * * */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 315; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 315; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":318 * * * if len(data) > 1024: raise IndexError, 'maximum list length is 1024' # <<<<<<<<<<<<<< * else: * for loop1 in range(len(data)): */ __pyx_t_3 = PyObject_Length(__pyx_v_data); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 318; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_4 = (__pyx_t_3 > 1024); if (__pyx_t_4) { __Pyx_Raise(__pyx_builtin_IndexError, ((PyObject *)__pyx_kp_s_7), 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 318; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } /*else*/ { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":320 * if len(data) > 1024: raise IndexError, 'maximum list length is 1024' * else: * for loop1 in range(len(data)): # <<<<<<<<<<<<<< * if ((len(data[loop1][0]) > 4) | * (len(data[loop1][0]) < 1)): */ __pyx_t_5 = PyObject_Length(__pyx_v_data); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_Call(__pyx_builtin_range, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) { __pyx_t_3 = 0; __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); } else { __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); } __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; for (;;) { if (likely(PyList_CheckExact(__pyx_t_1))) { if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break; __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; } else if (likely(PyTuple_CheckExact(__pyx_t_1))) { if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break; __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; } else { __pyx_t_2 = PyIter_Next(__pyx_t_1); if (!__pyx_t_2) { if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} break; } __Pyx_GOTREF(__pyx_t_2); } __Pyx_DECREF(__pyx_v_loop1); __pyx_v_loop1 = __pyx_t_2; __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":321 * else: * for loop1 in range(len(data)): * if ((len(data[loop1][0]) > 4) | # <<<<<<<<<<<<<< * (len(data[loop1][0]) < 1)): * raise IndexError, str(len(data[loop1][0]))+' arguments in event list' */ __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_6 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_5 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":322 * for loop1 in range(len(data)): * if ((len(data[loop1][0]) > 4) | * (len(data[loop1][0]) < 1)): # <<<<<<<<<<<<<< * raise IndexError, str(len(data[loop1][0]))+' arguments in event list' * buffer[loop1].message = 0 */ __pyx_t_6 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_6, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __pyx_t_7 = PyObject_Length(__pyx_t_2); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_4 = ((__pyx_t_5 > 4) | (__pyx_t_7 < 1)); if (__pyx_t_4) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":323 * if ((len(data[loop1][0]) > 4) | * (len(data[loop1][0]) < 1)): * raise IndexError, str(len(data[loop1][0]))+' arguments in event list' # <<<<<<<<<<<<<< * buffer[loop1].message = 0 * for i in range(len(data[loop1][0])): */ __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_6 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __pyx_t_6 = PyInt_FromSsize_t(__pyx_t_7); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = 0; __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)&PyString_Type)), __pyx_t_2, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyNumber_Add(__pyx_t_6, ((PyObject *)__pyx_kp_s_8)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __Pyx_Raise(__pyx_builtin_IndexError, __pyx_t_2, 0); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L8; } __pyx_L8:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":324 * (len(data[loop1][0]) < 1)): * raise IndexError, str(len(data[loop1][0]))+' arguments in event list' * buffer[loop1].message = 0 # <<<<<<<<<<<<<< * for i in range(len(data[loop1][0])): * buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i)) */ __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L1_error;} (__pyx_v_buffer[__pyx_t_7]).message = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":325 * raise IndexError, str(len(data[loop1][0]))+' arguments in event list' * buffer[loop1].message = 0 * for i in range(len(data[loop1][0])): # <<<<<<<<<<<<<< * buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i)) * buffer[loop1].timestamp = data[loop1][1] */ __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 325; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_6 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 325; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 325; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) { __pyx_v_i = __pyx_t_8; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":326 * buffer[loop1].message = 0 * for i in range(len(data[loop1][0])): * buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i)) # <<<<<<<<<<<<<< * buffer[loop1].timestamp = data[loop1][1] * if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp */ __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_6 = __Pyx_PyInt_to_py_PmMessage((__pyx_v_buffer[__pyx_t_5]).message); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_9 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_9) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_9); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_9, __pyx_v_i, sizeof(int), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; __pyx_t_9 = PyNumber_And(__pyx_t_2, __pyx_int_0xFF); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_9); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyInt_FromLong((8 * __pyx_v_i)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_10 = PyNumber_Lshift(__pyx_t_9, __pyx_t_2); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_10); __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyNumber_Add(__pyx_t_6, __pyx_t_10); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; __pyx_t_11 = __Pyx_PyInt_from_py_PmMessage(__pyx_t_2); if (unlikely((__pyx_t_11 == (PmMessage)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;} (__pyx_v_buffer[__pyx_t_5]).message = __pyx_t_11; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":327 * for i in range(len(data[loop1][0])): * buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i)) * buffer[loop1].timestamp = data[loop1][1] # <<<<<<<<<<<<<< * if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp * if self.debug: print "writing to midi buffer" */ __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_10 = __Pyx_GetItemInt(__pyx_t_2, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_10) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_10); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_12 = __Pyx_PyInt_from_py_PmTimestamp(__pyx_t_10); if (unlikely((__pyx_t_12 == (PmTimestamp)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;} (__pyx_v_buffer[__pyx_t_5]).timestamp = __pyx_t_12; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":328 * buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i)) * buffer[loop1].timestamp = data[loop1][1] * if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp # <<<<<<<<<<<<<< * if self.debug: print "writing to midi buffer" * err= Pm_Write(self.midi, buffer, len(data)) */ __pyx_t_8 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug; if (__pyx_t_8) { __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_10 = __Pyx_PyInt_to_py_PmMessage((__pyx_v_buffer[__pyx_t_5]).message); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_10); __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_2 = __Pyx_PyInt_to_py_PmTimestamp((__pyx_v_buffer[__pyx_t_5]).timestamp); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_6 = PyTuple_New(5); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_INCREF(__pyx_v_loop1); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_v_loop1); __Pyx_GIVEREF(__pyx_v_loop1); __Pyx_INCREF(((PyObject *)__pyx_kp_s_9)); PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_kp_s_9)); __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_9)); PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_10); __Pyx_GIVEREF(__pyx_t_10); __Pyx_INCREF(((PyObject *)__pyx_kp_s_9)); PyTuple_SET_ITEM(__pyx_t_6, 3, ((PyObject *)__pyx_kp_s_9)); __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_9)); PyTuple_SET_ITEM(__pyx_t_6, 4, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); __pyx_t_10 = 0; __pyx_t_2 = 0; if (__Pyx_Print(__pyx_t_6, 1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; goto __pyx_L11; } __pyx_L11:; } __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":329 * buffer[loop1].timestamp = data[loop1][1] * if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp * if self.debug: print "writing to midi buffer" # <<<<<<<<<<<<<< * err= Pm_Write(self.midi, buffer, len(data)) * if err < 0: raise Exception, Pm_GetErrorText(err) */ __pyx_t_8 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug; if (__pyx_t_8) { if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_10)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 329; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L12; } __pyx_L12:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":330 * if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp * if self.debug: print "writing to midi buffer" * err= Pm_Write(self.midi, buffer, len(data)) # <<<<<<<<<<<<<< * if err < 0: raise Exception, Pm_GetErrorText(err) * */ __pyx_t_3 = PyObject_Length(__pyx_v_data); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 330; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_err = Pm_Write(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi, __pyx_v_buffer, __pyx_t_3); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":331 * if self.debug: print "writing to midi buffer" * err= Pm_Write(self.midi, buffer, len(data)) * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * def WriteShort(self, status, data1 = 0, data2 = 0): */ __pyx_t_4 = (__pyx_v_err < 0); if (__pyx_t_4) { __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 331; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0); __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 331; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L13; } __pyx_L13:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_6); __Pyx_XDECREF(__pyx_t_9); __Pyx_XDECREF(__pyx_t_10); __Pyx_AddTraceback("_pyportmidi.Output.Write"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF(__pyx_v_loop1); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_data); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":333 * if err < 0: raise Exception, Pm_GetErrorText(err) * * def WriteShort(self, status, data1 = 0, data2 = 0): # <<<<<<<<<<<<<< * """ * WriteShort(status <, data1><, data2>) */ static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteShort(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static char __pyx_doc_11_pyportmidi_6Output_WriteShort[] = "\nWriteShort(status <, data1><, data2>)\n output MIDI information of 3 bytes or less.\n data fields are optional\n status byte could be:\n 0xc0 = program change\n 0x90 = note on\n etc.\n data bytes are optional and assumed 0 if omitted\n example: note 65 on with velocity 100\n WriteShort(0x90,65,100)\n "; static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteShort(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_status = 0; PyObject *__pyx_v_data1 = 0; PyObject *__pyx_v_data2 = 0; PmEvent __pyx_v_buffer[1]; PmError __pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; PmMessage __pyx_t_4; int __pyx_t_5; int __pyx_t_6; static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__status,&__pyx_n_s__data1,&__pyx_n_s__data2,0}; __Pyx_RefNannySetupContext("WriteShort"); if (unlikely(__pyx_kwds)) { Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); PyObject* values[3] = {0,0,0}; values[1] = ((PyObject *)__pyx_int_0); values[2] = ((PyObject *)__pyx_int_0); switch (PyTuple_GET_SIZE(__pyx_args)) { case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); case 0: break; default: goto __pyx_L5_argtuple_error; } switch (PyTuple_GET_SIZE(__pyx_args)) { case 0: values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__status); if (likely(values[0])) kw_args--; else goto __pyx_L5_argtuple_error; case 1: if (kw_args > 1) { PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__data1); if (unlikely(value)) { values[1] = value; kw_args--; } } case 2: if (kw_args > 1) { PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__data2); if (unlikely(value)) { values[2] = value; kw_args--; } } } if (unlikely(kw_args > 0)) { if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "WriteShort") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 333; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } __pyx_v_status = values[0]; __pyx_v_data1 = values[1]; __pyx_v_data2 = values[2]; } else { __pyx_v_data1 = ((PyObject *)__pyx_int_0); __pyx_v_data2 = ((PyObject *)__pyx_int_0); switch (PyTuple_GET_SIZE(__pyx_args)) { case 3: __pyx_v_data2 = PyTuple_GET_ITEM(__pyx_args, 2); case 2: __pyx_v_data1 = PyTuple_GET_ITEM(__pyx_args, 1); case 1: __pyx_v_status = PyTuple_GET_ITEM(__pyx_args, 0); break; default: goto __pyx_L5_argtuple_error; } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; __Pyx_RaiseArgtupleInvalid("WriteShort", 0, 1, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 333; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("_pyportmidi.Output.WriteShort"); return NULL; __pyx_L4_argument_unpacking_done:; __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_status); __Pyx_INCREF(__pyx_v_data1); __Pyx_INCREF(__pyx_v_data2); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":348 * cdef PmEvent buffer[1] * cdef PmError err * self._check_open() # <<<<<<<<<<<<<< * * buffer[0].timestamp = Pt_Time() */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":350 * self._check_open() * * buffer[0].timestamp = Pt_Time() # <<<<<<<<<<<<<< * buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF)) * if self.debug: print "Writing to MIDI buffer" */ (__pyx_v_buffer[0]).timestamp = Pt_Time(); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":351 * * buffer[0].timestamp = Pt_Time() * buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF)) # <<<<<<<<<<<<<< * if self.debug: print "Writing to MIDI buffer" * err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length */ __pyx_t_2 = PyNumber_Lshift(__pyx_v_data2, __pyx_int_16); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_1 = PyNumber_And(__pyx_t_2, __pyx_int_0xFF0000); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyNumber_Lshift(__pyx_v_data1, __pyx_int_8); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyNumber_And(__pyx_t_2, __pyx_int_0xFF00); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyNumber_Or(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = PyNumber_And(__pyx_v_status, __pyx_int_0xFF); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_t_1 = PyNumber_Or(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_4 = __Pyx_PyInt_from_py_PmMessage(__pyx_t_1); if (unlikely((__pyx_t_4 == (PmMessage)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; (__pyx_v_buffer[0]).message = __pyx_t_4; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":352 * buffer[0].timestamp = Pt_Time() * buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF)) * if self.debug: print "Writing to MIDI buffer" # <<<<<<<<<<<<<< * err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length * if err < 0 : raise Exception, Pm_GetErrorText(err) */ __pyx_t_5 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug; if (__pyx_t_5) { if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_11)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 352; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":353 * buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF)) * if self.debug: print "Writing to MIDI buffer" * err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length # <<<<<<<<<<<<<< * if err < 0 : raise Exception, Pm_GetErrorText(err) * */ __pyx_v_err = Pm_Write(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi, __pyx_v_buffer, 1); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":354 * if self.debug: print "Writing to MIDI buffer" * err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length * if err < 0 : raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * def WriteSysEx(self, when, msg): */ __pyx_t_6 = (__pyx_v_err < 0); if (__pyx_t_6) { __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0); __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L7; } __pyx_L7:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_AddTraceback("_pyportmidi.Output.WriteShort"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_status); __Pyx_DECREF(__pyx_v_data1); __Pyx_DECREF(__pyx_v_data2); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":356 * if err < 0 : raise Exception, Pm_GetErrorText(err) * * def WriteSysEx(self, when, msg): # <<<<<<<<<<<<<< * """ * WriteSysEx(,) */ static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteSysEx(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static char __pyx_doc_11_pyportmidi_6Output_WriteSysEx[] = "\n WriteSysEx(,)\n writes a timestamped system-exclusive midi message.\n can be a *list* or a *string*\n example:\n (assuming y is an input MIDI stream)\n y.WriteSysEx(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7')\n is equivalent to\n y.WriteSysEx(pypm.Time,\n [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])\n "; static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteSysEx(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_when = 0; PyObject *__pyx_v_msg = 0; PmError __pyx_v_err; char *__pyx_v_cmsg; PtTimestamp __pyx_v_CurTime; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; int __pyx_t_3; PyObject *__pyx_t_4 = NULL; char *__pyx_t_5; PmTimestamp __pyx_t_6; static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__when,&__pyx_n_s__msg,0}; __Pyx_RefNannySetupContext("WriteSysEx"); if (unlikely(__pyx_kwds)) { Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); PyObject* values[2] = {0,0}; switch (PyTuple_GET_SIZE(__pyx_args)) { case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); case 0: break; default: goto __pyx_L5_argtuple_error; } switch (PyTuple_GET_SIZE(__pyx_args)) { case 0: values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__when); if (likely(values[0])) kw_args--; else goto __pyx_L5_argtuple_error; case 1: values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__msg); if (likely(values[1])) kw_args--; else { __Pyx_RaiseArgtupleInvalid("WriteSysEx", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } if (unlikely(kw_args > 0)) { if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "WriteSysEx") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } __pyx_v_when = values[0]; __pyx_v_msg = values[1]; } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { goto __pyx_L5_argtuple_error; } else { __pyx_v_when = PyTuple_GET_ITEM(__pyx_args, 0); __pyx_v_msg = PyTuple_GET_ITEM(__pyx_args, 1); } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; __Pyx_RaiseArgtupleInvalid("WriteSysEx", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("_pyportmidi.Output.WriteSysEx"); return NULL; __pyx_L4_argument_unpacking_done:; __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_when); __Pyx_INCREF(__pyx_v_msg); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":372 * cdef PtTimestamp CurTime * * self._check_open() # <<<<<<<<<<<<<< * * if type(msg) is list: */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":374 * self._check_open() * * if type(msg) is list: # <<<<<<<<<<<<<< * msg = array.array('B',msg).tostring() # Markus Pfaff contribution * cmsg = msg */ __pyx_t_3 = (((PyObject *)Py_TYPE(__pyx_v_msg)) == ((PyObject *)((PyObject*)&PyList_Type))); if (__pyx_t_3) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":375 * * if type(msg) is list: * msg = array.array('B',msg).tostring() # Markus Pfaff contribution # <<<<<<<<<<<<<< * cmsg = msg * */ __pyx_t_2 = __Pyx_GetName(__pyx_m, __pyx_n_s__array); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__array); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_INCREF(((PyObject *)__pyx_n_s__B)); PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_n_s__B)); __Pyx_GIVEREF(((PyObject *)__pyx_n_s__B)); __Pyx_INCREF(__pyx_v_msg); PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_msg); __Pyx_GIVEREF(__pyx_v_msg); __pyx_t_4 = PyObject_Call(__pyx_t_1, __pyx_t_2, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__tostring); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __pyx_t_4 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_v_msg); __pyx_v_msg = __pyx_t_4; __pyx_t_4 = 0; goto __pyx_L6; } __pyx_L6:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":376 * if type(msg) is list: * msg = array.array('B',msg).tostring() # Markus Pfaff contribution * cmsg = msg # <<<<<<<<<<<<<< * * CurTime = Pt_Time() */ __pyx_t_5 = __Pyx_PyBytes_AsString(__pyx_v_msg); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 376; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_cmsg = __pyx_t_5; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":378 * cmsg = msg * * CurTime = Pt_Time() # <<<<<<<<<<<<<< * err = Pm_WriteSysEx(self.midi, when, cmsg) * if err < 0 : raise Exception, Pm_GetErrorText(err) */ __pyx_v_CurTime = Pt_Time(); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":379 * * CurTime = Pt_Time() * err = Pm_WriteSysEx(self.midi, when, cmsg) # <<<<<<<<<<<<<< * if err < 0 : raise Exception, Pm_GetErrorText(err) * while Pt_Time() == CurTime: # wait for SysEx to go thru or...my */ __pyx_t_6 = __Pyx_PyInt_from_py_PmTimestamp(__pyx_v_when); if (unlikely((__pyx_t_6 == (PmTimestamp)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_err = Pm_WriteSysEx(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi, __pyx_t_6, ((unsigned char *)__pyx_v_cmsg)); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":380 * CurTime = Pt_Time() * err = Pm_WriteSysEx(self.midi, when, cmsg) * if err < 0 : raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * while Pt_Time() == CurTime: # wait for SysEx to go thru or...my * pass # win32 machine crashes w/ multiple SysEx */ __pyx_t_3 = (__pyx_v_err < 0); if (__pyx_t_3) { __pyx_t_4 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_4), 0); __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L7; } __pyx_L7:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":381 * err = Pm_WriteSysEx(self.midi, when, cmsg) * if err < 0 : raise Exception, Pm_GetErrorText(err) * while Pt_Time() == CurTime: # wait for SysEx to go thru or...my # <<<<<<<<<<<<<< * pass # win32 machine crashes w/ multiple SysEx * */ while (1) { __pyx_t_3 = (Pt_Time() == __pyx_v_CurTime); if (!__pyx_t_3) break; } __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_4); __Pyx_AddTraceback("_pyportmidi.Output.WriteSysEx"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_when); __Pyx_DECREF(__pyx_v_msg); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":404 * cdef int i * * def __init__(self, InputDevice, buffersize=4096): # <<<<<<<<<<<<<< * cdef PmError err * self.i = InputDevice */ static int __pyx_pf_11_pyportmidi_5Input___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static int __pyx_pf_11_pyportmidi_5Input___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { PyObject *__pyx_v_InputDevice = 0; PyObject *__pyx_v_buffersize = 0; PmError __pyx_v_err; int __pyx_r; int __pyx_t_1; long __pyx_t_2; int __pyx_t_3; PyObject *__pyx_t_4 = NULL; static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__InputDevice,&__pyx_n_s__buffersize,0}; __Pyx_RefNannySetupContext("__init__"); if (unlikely(__pyx_kwds)) { Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); PyObject* values[2] = {0,0}; values[1] = ((PyObject *)__pyx_int_4096); switch (PyTuple_GET_SIZE(__pyx_args)) { case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); case 0: break; default: goto __pyx_L5_argtuple_error; } switch (PyTuple_GET_SIZE(__pyx_args)) { case 0: values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__InputDevice); if (likely(values[0])) kw_args--; else goto __pyx_L5_argtuple_error; case 1: if (kw_args > 1) { PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__buffersize); if (unlikely(value)) { values[1] = value; kw_args--; } } } if (unlikely(kw_args > 0)) { if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } __pyx_v_InputDevice = values[0]; __pyx_v_buffersize = values[1]; } else { __pyx_v_buffersize = ((PyObject *)__pyx_int_4096); switch (PyTuple_GET_SIZE(__pyx_args)) { case 2: __pyx_v_buffersize = PyTuple_GET_ITEM(__pyx_args, 1); case 1: __pyx_v_InputDevice = PyTuple_GET_ITEM(__pyx_args, 0); break; default: goto __pyx_L5_argtuple_error; } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("_pyportmidi.Input.__init__"); return -1; __pyx_L4_argument_unpacking_done:; __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_InputDevice); __Pyx_INCREF(__pyx_v_buffersize); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":406 * def __init__(self, InputDevice, buffersize=4096): * cdef PmError err * self.i = InputDevice # <<<<<<<<<<<<<< * self.debug = 0 * err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL) */ __pyx_t_1 = __Pyx_PyInt_AsInt(__pyx_v_InputDevice); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;} ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->i = __pyx_t_1; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":407 * cdef PmError err * self.i = InputDevice * self.debug = 0 # <<<<<<<<<<<<<< * err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL) * if err < 0: raise Exception, Pm_GetErrorText(err) */ ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->debug = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":408 * self.i = InputDevice * self.debug = 0 * err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL) # <<<<<<<<<<<<<< * if err < 0: raise Exception, Pm_GetErrorText(err) * if self.debug: print "MIDI input opened." */ __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_v_buffersize); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 408; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_err = Pm_OpenInput((&((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi), ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->i, NULL, __pyx_t_2, (&Pt_Time), NULL); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":409 * self.debug = 0 * err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL) * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * if self.debug: print "MIDI input opened." * */ __pyx_t_3 = (__pyx_v_err < 0); if (__pyx_t_3) { __pyx_t_4 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_4), 0); __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":410 * err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL) * if err < 0: raise Exception, Pm_GetErrorText(err) * if self.debug: print "MIDI input opened." # <<<<<<<<<<<<<< * * def __dealloc__(self): */ __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->debug; if (__pyx_t_1) { if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_12)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L7; } __pyx_L7:; __pyx_r = 0; goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_4); __Pyx_AddTraceback("_pyportmidi.Input.__init__"); __pyx_r = -1; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_InputDevice); __Pyx_DECREF(__pyx_v_buffersize); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":412 * if self.debug: print "MIDI input opened." * * def __dealloc__(self): # <<<<<<<<<<<<<< * cdef PmError err * if self.debug: print "Closing MIDI input stream and destroying instance" */ static void __pyx_pf_11_pyportmidi_5Input___dealloc__(PyObject *__pyx_v_self); /*proto*/ static void __pyx_pf_11_pyportmidi_5Input___dealloc__(PyObject *__pyx_v_self) { PmError __pyx_v_err; int __pyx_t_1; int __pyx_t_2; PyObject *__pyx_t_3 = NULL; __Pyx_RefNannySetupContext("__dealloc__"); __Pyx_INCREF((PyObject *)__pyx_v_self); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":414 * def __dealloc__(self): * cdef PmError err * if self.debug: print "Closing MIDI input stream and destroying instance" # <<<<<<<<<<<<<< * * err = Pm_Close(self.midi) */ __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->debug; if (__pyx_t_1) { if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_13)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 414; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":416 * if self.debug: print "Closing MIDI input stream and destroying instance" * * err = Pm_Close(self.midi) # <<<<<<<<<<<<<< * if err < 0: * raise Exception, Pm_GetErrorText(err) */ __pyx_v_err = Pm_Close(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":417 * * err = Pm_Close(self.midi) * if err < 0: # <<<<<<<<<<<<<< * raise Exception, Pm_GetErrorText(err) * */ __pyx_t_2 = (__pyx_v_err < 0); if (__pyx_t_2) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":418 * err = Pm_Close(self.midi) * if err < 0: * raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * */ __pyx_t_3 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_3), 0); __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_3); __Pyx_AddTraceback("_pyportmidi.Input.__dealloc__"); __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_RefNannyFinishContext(); } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":422 * * * def _check_open(self): # <<<<<<<<<<<<<< * """ checks to see if the midi is open, and if not, raises an error. * """ */ static PyObject *__pyx_pf_11_pyportmidi_5Input__check_open(PyObject *__pyx_v_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_5Input__check_open[] = " checks to see if the midi is open, and if not, raises an error.\n "; static PyObject *__pyx_pf_11_pyportmidi_5Input__check_open(PyObject *__pyx_v_self, PyObject *unused) { PyObject *__pyx_r = NULL; int __pyx_t_1; __Pyx_RefNannySetupContext("_check_open"); __Pyx_INCREF((PyObject *)__pyx_v_self); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":426 * """ * * if self.midi == NULL: # <<<<<<<<<<<<<< * raise Exception, "midi Input not open." * */ __pyx_t_1 = (((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi == NULL); if (__pyx_t_1) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":427 * * if self.midi == NULL: * raise Exception, "midi Input not open." # <<<<<<<<<<<<<< * * */ __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_kp_s_14), 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 427; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_AddTraceback("_pyportmidi.Input._check_open"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":430 * * * def Close(self): # <<<<<<<<<<<<<< * """ * Close() */ static PyObject *__pyx_pf_11_pyportmidi_5Input_Close(PyObject *__pyx_v_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_5Input_Close[] = "\nClose()\n closes a midi stream, flushing any pending buffers.\n (PortMidi attempts to close open streams when the application\n exits -- this is particularly difficult under Windows.)\n "; static PyObject *__pyx_pf_11_pyportmidi_5Input_Close(PyObject *__pyx_v_self, PyObject *unused) { PyObject *__pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; int __pyx_t_2; PmError __pyx_t_3; __Pyx_RefNannySetupContext("Close"); __Pyx_INCREF((PyObject *)__pyx_v_self); __pyx_v_err = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":440 * # return * * err = Pm_Close(self.midi) # <<<<<<<<<<<<<< * if err < 0: * raise Exception, Pm_GetErrorText(err) */ __pyx_t_1 = PyInt_FromLong(Pm_Close(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 440; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_v_err); __pyx_v_err = __pyx_t_1; __pyx_t_1 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":441 * * err = Pm_Close(self.midi) * if err < 0: # <<<<<<<<<<<<<< * raise Exception, Pm_GetErrorText(err) * #self.midi = NULL */ __pyx_t_1 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; if (__pyx_t_2) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":442 * err = Pm_Close(self.midi) * if err < 0: * raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * #self.midi = NULL * */ __pyx_t_3 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_3)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0); __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("_pyportmidi.Input.Close"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF(__pyx_v_err); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":447 * * * def SetFilter(self, filters): # <<<<<<<<<<<<<< * """ * SetFilter() sets filters on an open input stream */ static PyObject *__pyx_pf_11_pyportmidi_5Input_SetFilter(PyObject *__pyx_v_self, PyObject *__pyx_v_filters); /*proto*/ static char __pyx_doc_11_pyportmidi_5Input_SetFilter[] = "\n SetFilter() sets filters on an open input stream\n to drop selected input types. By default, only active sensing\n messages are filtered. To prohibit, say, active sensing and\n sysex messages, call\n SetFilter(stream, FILT_ACTIVE | FILT_SYSEX);\n\n Filtering is useful when midi routing or midi thru functionality\n is being provided by the user application.\n For example, you may want to exclude timing messages\n (clock, MTC, start/stop/continue), while allowing note-related\n messages to pass. Or you may be using a sequencer or drum-machine\n for MIDI clock information but want to exclude any notes\n it may play.\n\n Note: SetFilter empties the buffer after setting the filter,\n just in case anything got through.\n "; static PyObject *__pyx_pf_11_pyportmidi_5Input_SetFilter(PyObject *__pyx_v_self, PyObject *__pyx_v_filters) { PmEvent __pyx_v_buffer[1]; PmError __pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; long __pyx_t_3; int __pyx_t_4; __Pyx_RefNannySetupContext("SetFilter"); __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_filters); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":469 * cdef PmError err * * self._check_open() # <<<<<<<<<<<<<< * * */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":472 * * * err = Pm_SetFilter(self.midi, filters) # <<<<<<<<<<<<<< * * if err < 0: raise Exception, Pm_GetErrorText(err) */ __pyx_t_3 = __Pyx_PyInt_AsLong(__pyx_v_filters); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 472; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_err = Pm_SetFilter(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_t_3); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":474 * err = Pm_SetFilter(self.midi, filters) * * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * while(Pm_Poll(self.midi) != pmNoError): */ __pyx_t_4 = (__pyx_v_err < 0); if (__pyx_t_4) { __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 474; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 474; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":476 * if err < 0: raise Exception, Pm_GetErrorText(err) * * while(Pm_Poll(self.midi) != pmNoError): # <<<<<<<<<<<<<< * * err = Pm_Read(self.midi,buffer,1) */ while (1) { __pyx_t_4 = (Pm_Poll(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi) != pmNoError); if (!__pyx_t_4) break; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":478 * while(Pm_Poll(self.midi) != pmNoError): * * err = Pm_Read(self.midi,buffer,1) # <<<<<<<<<<<<<< * if err < 0: raise Exception, Pm_GetErrorText(err) * */ __pyx_v_err = Pm_Read(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_v_buffer, 1); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":479 * * err = Pm_Read(self.midi,buffer,1) * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * def SetChannelMask(self, mask): */ __pyx_t_4 = (__pyx_v_err < 0); if (__pyx_t_4) { __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L8; } __pyx_L8:; } __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("_pyportmidi.Input.SetFilter"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_filters); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":481 * if err < 0: raise Exception, Pm_GetErrorText(err) * * def SetChannelMask(self, mask): # <<<<<<<<<<<<<< * """ * SetChannelMask() filters incoming messages based on channel. */ static PyObject *__pyx_pf_11_pyportmidi_5Input_SetChannelMask(PyObject *__pyx_v_self, PyObject *__pyx_v_mask); /*proto*/ static char __pyx_doc_11_pyportmidi_5Input_SetChannelMask[] = "\n SetChannelMask() filters incoming messages based on channel.\n The mask is a 16-bit bitfield corresponding to appropriate channels\n Channel() can assist in calling this function.\n i.e. to set receive only input on channel 1, call with\n SetChannelMask(Channel(1))\n Multiple channels should be OR'd together, like\n SetChannelMask(Channel(10) | Channel(11))\n note: PyPortMidi Channel function has been altered from\n the original PortMidi c call to correct for what\n seems to be a bug --- i.e. channel filters were\n all numbered from 0 to 15 instead of 1 to 16.\n "; static PyObject *__pyx_pf_11_pyportmidi_5Input_SetChannelMask(PyObject *__pyx_v_self, PyObject *__pyx_v_mask) { PmError __pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; int __pyx_t_3; int __pyx_t_4; __Pyx_RefNannySetupContext("SetChannelMask"); __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_mask); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":497 * cdef PmError err * * self._check_open() # <<<<<<<<<<<<<< * * err = Pm_SetChannelMask(self.midi,mask) */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":499 * self._check_open() * * err = Pm_SetChannelMask(self.midi,mask) # <<<<<<<<<<<<<< * if err < 0: raise Exception, Pm_GetErrorText(err) * */ __pyx_t_3 = __Pyx_PyInt_AsInt(__pyx_v_mask); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 499; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_err = Pm_SetChannelMask(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_t_3); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":500 * * err = Pm_SetChannelMask(self.midi,mask) * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * * def Poll(self): */ __pyx_t_4 = (__pyx_v_err < 0); if (__pyx_t_4) { __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 500; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 500; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("_pyportmidi.Input.SetChannelMask"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_mask); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":502 * if err < 0: raise Exception, Pm_GetErrorText(err) * * def Poll(self): # <<<<<<<<<<<<<< * """ * Poll tests whether input is available, */ static PyObject *__pyx_pf_11_pyportmidi_5Input_Poll(PyObject *__pyx_v_self, PyObject *unused); /*proto*/ static char __pyx_doc_11_pyportmidi_5Input_Poll[] = "\n Poll tests whether input is available,\n returning TRUE, FALSE, or an error value.\n "; static PyObject *__pyx_pf_11_pyportmidi_5Input_Poll(PyObject *__pyx_v_self, PyObject *unused) { PmError __pyx_v_err; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; int __pyx_t_3; __Pyx_RefNannySetupContext("Poll"); __Pyx_INCREF((PyObject *)__pyx_v_self); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":508 * """ * cdef PmError err * self._check_open() # <<<<<<<<<<<<<< * * err = Pm_Poll(self.midi) */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 508; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 508; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":510 * self._check_open() * * err = Pm_Poll(self.midi) # <<<<<<<<<<<<<< * if err < 0: raise Exception, Pm_GetErrorText(err) * return err */ __pyx_v_err = Pm_Poll(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":511 * * err = Pm_Poll(self.midi) * if err < 0: raise Exception, Pm_GetErrorText(err) # <<<<<<<<<<<<<< * return err * */ __pyx_t_3 = (__pyx_v_err < 0); if (__pyx_t_3) { __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 511; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 511; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":512 * err = Pm_Poll(self.midi) * if err < 0: raise Exception, Pm_GetErrorText(err) * return err # <<<<<<<<<<<<<< * * def Read(self,length): */ __Pyx_XDECREF(__pyx_r); __pyx_t_2 = PyInt_FromLong(__pyx_v_err); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_r = __pyx_t_2; __pyx_t_2 = 0; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_AddTraceback("_pyportmidi.Input.Poll"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":514 * return err * * def Read(self,length): # <<<<<<<<<<<<<< * """ * Read(length): returns up to midi events stored in */ static PyObject *__pyx_pf_11_pyportmidi_5Input_Read(PyObject *__pyx_v_self, PyObject *__pyx_v_length); /*proto*/ static char __pyx_doc_11_pyportmidi_5Input_Read[] = "\nRead(length): returns up to midi events stored in\nthe buffer and returns them as a list:\n[[[status,data1,data2,data3],timestamp],\n [[status,data1,data2,data3],timestamp],...]\nexample: Read(50) returns all the events in the buffer,\n up to 50 events.\n "; static PyObject *__pyx_pf_11_pyportmidi_5Input_Read(PyObject *__pyx_v_self, PyObject *__pyx_v_length) { PmEvent __pyx_v_buffer[1024]; PyObject *__pyx_v_x; PyObject *__pyx_v_NumEvents; PyObject *__pyx_v_loop; PyObject *__pyx_r = NULL; PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; int __pyx_t_3; long __pyx_t_4; PmError __pyx_t_5; Py_ssize_t __pyx_t_6; Py_ssize_t __pyx_t_7; PyObject *__pyx_t_8 = NULL; PyObject *__pyx_t_9 = NULL; PyObject *__pyx_t_10 = NULL; PyObject *__pyx_t_11 = NULL; __Pyx_RefNannySetupContext("Read"); __Pyx_INCREF((PyObject *)__pyx_v_self); __Pyx_INCREF(__pyx_v_length); __pyx_v_x = Py_None; __Pyx_INCREF(Py_None); __pyx_v_NumEvents = Py_None; __Pyx_INCREF(Py_None); __pyx_v_loop = Py_None; __Pyx_INCREF(Py_None); /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":525 * cdef PmEvent buffer[1024] * * self._check_open() # <<<<<<<<<<<<<< * * x = [] */ __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 525; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 525; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":527 * self._check_open() * * x = [] # <<<<<<<<<<<<<< * * if length > 1024: raise IndexError, 'maximum buffer length is 1024' */ __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_DECREF(__pyx_v_x); __pyx_v_x = ((PyObject *)__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":529 * x = [] * * if length > 1024: raise IndexError, 'maximum buffer length is 1024' # <<<<<<<<<<<<<< * if length < 1: raise IndexError, 'minimum buffer length is 1' * NumEvents = Pm_Read(self.midi,buffer,length) */ __pyx_t_2 = PyObject_RichCompare(__pyx_v_length, __pyx_int_1024, Py_GT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 529; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 529; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (__pyx_t_3) { __Pyx_Raise(__pyx_builtin_IndexError, ((PyObject *)__pyx_kp_s_15), 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 529; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":530 * * if length > 1024: raise IndexError, 'maximum buffer length is 1024' * if length < 1: raise IndexError, 'minimum buffer length is 1' # <<<<<<<<<<<<<< * NumEvents = Pm_Read(self.midi,buffer,length) * if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents) */ __pyx_t_2 = PyObject_RichCompare(__pyx_v_length, __pyx_int_1, Py_LT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 530; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 530; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (__pyx_t_3) { __Pyx_Raise(__pyx_builtin_IndexError, ((PyObject *)__pyx_kp_s_16), 0); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 530; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":531 * if length > 1024: raise IndexError, 'maximum buffer length is 1024' * if length < 1: raise IndexError, 'minimum buffer length is 1' * NumEvents = Pm_Read(self.midi,buffer,length) # <<<<<<<<<<<<<< * if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents) * x=[] */ __pyx_t_4 = __Pyx_PyInt_AsLong(__pyx_v_length); if (unlikely((__pyx_t_4 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 531; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_2 = PyInt_FromLong(Pm_Read(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_v_buffer, __pyx_t_4)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 531; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_v_NumEvents); __pyx_v_NumEvents = __pyx_t_2; __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":532 * if length < 1: raise IndexError, 'minimum buffer length is 1' * NumEvents = Pm_Read(self.midi,buffer,length) * if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents) # <<<<<<<<<<<<<< * x=[] * if NumEvents >= 1: */ __pyx_t_2 = PyObject_RichCompare(__pyx_v_NumEvents, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (__pyx_t_3) { __pyx_t_5 = ((PmError)PyInt_AsLong(__pyx_v_NumEvents)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_5)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L7; } __pyx_L7:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":533 * NumEvents = Pm_Read(self.midi,buffer,length) * if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents) * x=[] # <<<<<<<<<<<<<< * if NumEvents >= 1: * for loop in range(NumEvents): */ __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 533; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); __Pyx_DECREF(__pyx_v_x); __pyx_v_x = ((PyObject *)__pyx_t_2); __pyx_t_2 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":534 * if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents) * x=[] * if NumEvents >= 1: # <<<<<<<<<<<<<< * for loop in range(NumEvents): * x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp]) */ __pyx_t_2 = PyObject_RichCompare(__pyx_v_NumEvents, __pyx_int_1, Py_GE); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 534; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 534; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (__pyx_t_3) { /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":535 * x=[] * if NumEvents >= 1: * for loop in range(NumEvents): # <<<<<<<<<<<<<< * x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp]) * return x */ __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_INCREF(__pyx_v_NumEvents); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_NumEvents); __Pyx_GIVEREF(__pyx_v_NumEvents); __pyx_t_1 = PyObject_Call(__pyx_builtin_range, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) { __pyx_t_6 = 0; __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); } else { __pyx_t_6 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); } __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; for (;;) { if (likely(PyList_CheckExact(__pyx_t_2))) { if (__pyx_t_6 >= PyList_GET_SIZE(__pyx_t_2)) break; __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++; } else if (likely(PyTuple_CheckExact(__pyx_t_2))) { if (__pyx_t_6 >= PyTuple_GET_SIZE(__pyx_t_2)) break; __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++; } else { __pyx_t_1 = PyIter_Next(__pyx_t_2); if (!__pyx_t_1) { if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;} break; } __Pyx_GOTREF(__pyx_t_1); } __Pyx_DECREF(__pyx_v_loop); __pyx_v_loop = __pyx_t_1; __pyx_t_1 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":536 * if NumEvents >= 1: * for loop in range(NumEvents): * x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp]) # <<<<<<<<<<<<<< * return x */ __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_1 = __Pyx_PyInt_to_py_PmMessage(((__pyx_v_buffer[__pyx_t_7]).message & 0xff)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_8 = __Pyx_PyInt_to_py_PmMessage((((__pyx_v_buffer[__pyx_t_7]).message >> 8) & 0xFF)); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_8); __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_9 = __Pyx_PyInt_to_py_PmMessage((((__pyx_v_buffer[__pyx_t_7]).message >> 16) & 0xFF)); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_9); __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_10 = __Pyx_PyInt_to_py_PmMessage((((__pyx_v_buffer[__pyx_t_7]).message >> 24) & 0xFF)); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_10); __pyx_t_11 = PyList_New(4); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_11)); PyList_SET_ITEM(__pyx_t_11, 0, __pyx_t_1); __Pyx_GIVEREF(__pyx_t_1); PyList_SET_ITEM(__pyx_t_11, 1, __pyx_t_8); __Pyx_GIVEREF(__pyx_t_8); PyList_SET_ITEM(__pyx_t_11, 2, __pyx_t_9); __Pyx_GIVEREF(__pyx_t_9); PyList_SET_ITEM(__pyx_t_11, 3, __pyx_t_10); __Pyx_GIVEREF(__pyx_t_10); __pyx_t_1 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_t_10 = __Pyx_PyInt_to_py_PmTimestamp((__pyx_v_buffer[__pyx_t_7]).timestamp); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_10); __pyx_t_9 = PyList_New(2); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_9)); PyList_SET_ITEM(__pyx_t_9, 0, ((PyObject *)__pyx_t_11)); __Pyx_GIVEREF(((PyObject *)__pyx_t_11)); PyList_SET_ITEM(__pyx_t_9, 1, __pyx_t_10); __Pyx_GIVEREF(__pyx_t_10); __pyx_t_11 = 0; __pyx_t_10 = 0; __pyx_t_10 = __Pyx_PyObject_Append(__pyx_v_x, ((PyObject *)__pyx_t_9)); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_10); __Pyx_DECREF(((PyObject *)__pyx_t_9)); __pyx_t_9 = 0; __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; } __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; goto __pyx_L8; } __pyx_L8:; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":537 * for loop in range(NumEvents): * x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp]) * return x # <<<<<<<<<<<<<< */ __Pyx_XDECREF(__pyx_r); __Pyx_INCREF(__pyx_v_x); __pyx_r = __pyx_v_x; goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_8); __Pyx_XDECREF(__pyx_t_9); __Pyx_XDECREF(__pyx_t_10); __Pyx_XDECREF(__pyx_t_11); __Pyx_AddTraceback("_pyportmidi.Input.Read"); __pyx_r = NULL; __pyx_L0:; __Pyx_DECREF(__pyx_v_x); __Pyx_DECREF(__pyx_v_NumEvents); __Pyx_DECREF(__pyx_v_loop); __Pyx_DECREF((PyObject *)__pyx_v_self); __Pyx_DECREF(__pyx_v_length); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_tp_new_11_pyportmidi_Output(PyTypeObject *t, PyObject *a, PyObject *k) { PyObject *o = (*t->tp_alloc)(t, 0); if (!o) return 0; return o; } static void __pyx_tp_dealloc_11_pyportmidi_Output(PyObject *o) { { PyObject *etype, *eval, *etb; PyErr_Fetch(&etype, &eval, &etb); ++Py_REFCNT(o); __pyx_pf_11_pyportmidi_6Output___dealloc__(o); if (PyErr_Occurred()) PyErr_WriteUnraisable(o); --Py_REFCNT(o); PyErr_Restore(etype, eval, etb); } (*Py_TYPE(o)->tp_free)(o); } static struct PyMethodDef __pyx_methods_11_pyportmidi_Output[] = { {__Pyx_NAMESTR("_check_open"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output__check_open, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output__check_open)}, {__Pyx_NAMESTR("Close"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_Close, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_Close)}, {__Pyx_NAMESTR("Abort"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_Abort, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_Abort)}, {__Pyx_NAMESTR("Write"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_Write, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_Write)}, {__Pyx_NAMESTR("WriteShort"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_WriteShort, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_WriteShort)}, {__Pyx_NAMESTR("WriteSysEx"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_WriteSysEx, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_WriteSysEx)}, {0, 0, 0, 0} }; static PyNumberMethods __pyx_tp_as_number_Output = { 0, /*nb_add*/ 0, /*nb_subtract*/ 0, /*nb_multiply*/ #if PY_MAJOR_VERSION < 3 0, /*nb_divide*/ #endif 0, /*nb_remainder*/ 0, /*nb_divmod*/ 0, /*nb_power*/ 0, /*nb_negative*/ 0, /*nb_positive*/ 0, /*nb_absolute*/ 0, /*nb_nonzero*/ 0, /*nb_invert*/ 0, /*nb_lshift*/ 0, /*nb_rshift*/ 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ #if PY_MAJOR_VERSION < 3 0, /*nb_coerce*/ #endif 0, /*nb_int*/ #if PY_MAJOR_VERSION >= 3 0, /*reserved*/ #else 0, /*nb_long*/ #endif 0, /*nb_float*/ #if PY_MAJOR_VERSION < 3 0, /*nb_oct*/ #endif #if PY_MAJOR_VERSION < 3 0, /*nb_hex*/ #endif 0, /*nb_inplace_add*/ 0, /*nb_inplace_subtract*/ 0, /*nb_inplace_multiply*/ #if PY_MAJOR_VERSION < 3 0, /*nb_inplace_divide*/ #endif 0, /*nb_inplace_remainder*/ 0, /*nb_inplace_power*/ 0, /*nb_inplace_lshift*/ 0, /*nb_inplace_rshift*/ 0, /*nb_inplace_and*/ 0, /*nb_inplace_xor*/ 0, /*nb_inplace_or*/ 0, /*nb_floor_divide*/ 0, /*nb_true_divide*/ 0, /*nb_inplace_floor_divide*/ 0, /*nb_inplace_true_divide*/ #if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_INDEX) 0, /*nb_index*/ #endif }; static PySequenceMethods __pyx_tp_as_sequence_Output = { 0, /*sq_length*/ 0, /*sq_concat*/ 0, /*sq_repeat*/ 0, /*sq_item*/ 0, /*sq_slice*/ 0, /*sq_ass_item*/ 0, /*sq_ass_slice*/ 0, /*sq_contains*/ 0, /*sq_inplace_concat*/ 0, /*sq_inplace_repeat*/ }; static PyMappingMethods __pyx_tp_as_mapping_Output = { 0, /*mp_length*/ 0, /*mp_subscript*/ 0, /*mp_ass_subscript*/ }; static PyBufferProcs __pyx_tp_as_buffer_Output = { #if PY_MAJOR_VERSION < 3 0, /*bf_getreadbuffer*/ #endif #if PY_MAJOR_VERSION < 3 0, /*bf_getwritebuffer*/ #endif #if PY_MAJOR_VERSION < 3 0, /*bf_getsegcount*/ #endif #if PY_MAJOR_VERSION < 3 0, /*bf_getcharbuffer*/ #endif #if PY_VERSION_HEX >= 0x02060000 0, /*bf_getbuffer*/ #endif #if PY_VERSION_HEX >= 0x02060000 0, /*bf_releasebuffer*/ #endif }; PyTypeObject __pyx_type_11_pyportmidi_Output = { PyVarObject_HEAD_INIT(0, 0) __Pyx_NAMESTR("_pyportmidi.Output"), /*tp_name*/ sizeof(struct __pyx_obj_11_pyportmidi_Output), /*tp_basicsize*/ 0, /*tp_itemsize*/ __pyx_tp_dealloc_11_pyportmidi_Output, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ &__pyx_tp_as_number_Output, /*tp_as_number*/ &__pyx_tp_as_sequence_Output, /*tp_as_sequence*/ &__pyx_tp_as_mapping_Output, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ &__pyx_tp_as_buffer_Output, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ __Pyx_DOCSTR("\nclass Output:\n define an output MIDI stream. Takes the form:\n x = pypm.Output(MidiOutputDevice, latency)\n latency is in ms.\n If latency = 0 then timestamps for output are ignored.\n "), /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ __pyx_methods_11_pyportmidi_Output, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ __pyx_pf_11_pyportmidi_6Output___init__, /*tp_init*/ 0, /*tp_alloc*/ __pyx_tp_new_11_pyportmidi_Output, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0, /*tp_weaklist*/ 0, /*tp_del*/ #if PY_VERSION_HEX >= 0x02060000 0, /*tp_version_tag*/ #endif }; static PyObject *__pyx_tp_new_11_pyportmidi_Input(PyTypeObject *t, PyObject *a, PyObject *k) { PyObject *o = (*t->tp_alloc)(t, 0); if (!o) return 0; return o; } static void __pyx_tp_dealloc_11_pyportmidi_Input(PyObject *o) { { PyObject *etype, *eval, *etb; PyErr_Fetch(&etype, &eval, &etb); ++Py_REFCNT(o); __pyx_pf_11_pyportmidi_5Input___dealloc__(o); if (PyErr_Occurred()) PyErr_WriteUnraisable(o); --Py_REFCNT(o); PyErr_Restore(etype, eval, etb); } (*Py_TYPE(o)->tp_free)(o); } static struct PyMethodDef __pyx_methods_11_pyportmidi_Input[] = { {__Pyx_NAMESTR("_check_open"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input__check_open, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input__check_open)}, {__Pyx_NAMESTR("Close"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_Close, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_Close)}, {__Pyx_NAMESTR("SetFilter"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_SetFilter, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_SetFilter)}, {__Pyx_NAMESTR("SetChannelMask"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_SetChannelMask, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_SetChannelMask)}, {__Pyx_NAMESTR("Poll"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_Poll, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_Poll)}, {__Pyx_NAMESTR("Read"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_Read, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_Read)}, {0, 0, 0, 0} }; static PyNumberMethods __pyx_tp_as_number_Input = { 0, /*nb_add*/ 0, /*nb_subtract*/ 0, /*nb_multiply*/ #if PY_MAJOR_VERSION < 3 0, /*nb_divide*/ #endif 0, /*nb_remainder*/ 0, /*nb_divmod*/ 0, /*nb_power*/ 0, /*nb_negative*/ 0, /*nb_positive*/ 0, /*nb_absolute*/ 0, /*nb_nonzero*/ 0, /*nb_invert*/ 0, /*nb_lshift*/ 0, /*nb_rshift*/ 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ #if PY_MAJOR_VERSION < 3 0, /*nb_coerce*/ #endif 0, /*nb_int*/ #if PY_MAJOR_VERSION >= 3 0, /*reserved*/ #else 0, /*nb_long*/ #endif 0, /*nb_float*/ #if PY_MAJOR_VERSION < 3 0, /*nb_oct*/ #endif #if PY_MAJOR_VERSION < 3 0, /*nb_hex*/ #endif 0, /*nb_inplace_add*/ 0, /*nb_inplace_subtract*/ 0, /*nb_inplace_multiply*/ #if PY_MAJOR_VERSION < 3 0, /*nb_inplace_divide*/ #endif 0, /*nb_inplace_remainder*/ 0, /*nb_inplace_power*/ 0, /*nb_inplace_lshift*/ 0, /*nb_inplace_rshift*/ 0, /*nb_inplace_and*/ 0, /*nb_inplace_xor*/ 0, /*nb_inplace_or*/ 0, /*nb_floor_divide*/ 0, /*nb_true_divide*/ 0, /*nb_inplace_floor_divide*/ 0, /*nb_inplace_true_divide*/ #if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_INDEX) 0, /*nb_index*/ #endif }; static PySequenceMethods __pyx_tp_as_sequence_Input = { 0, /*sq_length*/ 0, /*sq_concat*/ 0, /*sq_repeat*/ 0, /*sq_item*/ 0, /*sq_slice*/ 0, /*sq_ass_item*/ 0, /*sq_ass_slice*/ 0, /*sq_contains*/ 0, /*sq_inplace_concat*/ 0, /*sq_inplace_repeat*/ }; static PyMappingMethods __pyx_tp_as_mapping_Input = { 0, /*mp_length*/ 0, /*mp_subscript*/ 0, /*mp_ass_subscript*/ }; static PyBufferProcs __pyx_tp_as_buffer_Input = { #if PY_MAJOR_VERSION < 3 0, /*bf_getreadbuffer*/ #endif #if PY_MAJOR_VERSION < 3 0, /*bf_getwritebuffer*/ #endif #if PY_MAJOR_VERSION < 3 0, /*bf_getsegcount*/ #endif #if PY_MAJOR_VERSION < 3 0, /*bf_getcharbuffer*/ #endif #if PY_VERSION_HEX >= 0x02060000 0, /*bf_getbuffer*/ #endif #if PY_VERSION_HEX >= 0x02060000 0, /*bf_releasebuffer*/ #endif }; PyTypeObject __pyx_type_11_pyportmidi_Input = { PyVarObject_HEAD_INIT(0, 0) __Pyx_NAMESTR("_pyportmidi.Input"), /*tp_name*/ sizeof(struct __pyx_obj_11_pyportmidi_Input), /*tp_basicsize*/ 0, /*tp_itemsize*/ __pyx_tp_dealloc_11_pyportmidi_Input, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ &__pyx_tp_as_number_Input, /*tp_as_number*/ &__pyx_tp_as_sequence_Input, /*tp_as_sequence*/ &__pyx_tp_as_mapping_Input, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ &__pyx_tp_as_buffer_Input, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ __Pyx_DOCSTR("\nclass Input:\n define an input MIDI stream. Takes the form:\n x = pypm.Input(MidiInputDevice)\n "), /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ __pyx_methods_11_pyportmidi_Input, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ __pyx_pf_11_pyportmidi_5Input___init__, /*tp_init*/ 0, /*tp_alloc*/ __pyx_tp_new_11_pyportmidi_Input, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ 0, /*tp_bases*/ 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0, /*tp_weaklist*/ 0, /*tp_del*/ #if PY_VERSION_HEX >= 0x02060000 0, /*tp_version_tag*/ #endif }; static struct PyMethodDef __pyx_methods[] = { {__Pyx_NAMESTR("Initialize"), (PyCFunction)__pyx_pf_11_pyportmidi_Initialize, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Initialize)}, {__Pyx_NAMESTR("Terminate"), (PyCFunction)__pyx_pf_11_pyportmidi_Terminate, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Terminate)}, {__Pyx_NAMESTR("GetDefaultInputDeviceID"), (PyCFunction)__pyx_pf_11_pyportmidi_GetDefaultInputDeviceID, METH_NOARGS, __Pyx_DOCSTR(0)}, {__Pyx_NAMESTR("GetDefaultOutputDeviceID"), (PyCFunction)__pyx_pf_11_pyportmidi_GetDefaultOutputDeviceID, METH_NOARGS, __Pyx_DOCSTR(0)}, {__Pyx_NAMESTR("CountDevices"), (PyCFunction)__pyx_pf_11_pyportmidi_CountDevices, METH_NOARGS, __Pyx_DOCSTR(0)}, {__Pyx_NAMESTR("GetDeviceInfo"), (PyCFunction)__pyx_pf_11_pyportmidi_GetDeviceInfo, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_GetDeviceInfo)}, {__Pyx_NAMESTR("Time"), (PyCFunction)__pyx_pf_11_pyportmidi_Time, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Time)}, {__Pyx_NAMESTR("GetErrorText"), (PyCFunction)__pyx_pf_11_pyportmidi_GetErrorText, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_GetErrorText)}, {__Pyx_NAMESTR("Channel"), (PyCFunction)__pyx_pf_11_pyportmidi_Channel, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Channel)}, {0, 0, 0, 0} }; static void __pyx_init_filenames(void); /*proto*/ #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef __pyx_moduledef = { PyModuleDef_HEAD_INIT, __Pyx_NAMESTR("_pyportmidi"), 0, /* m_doc */ -1, /* m_size */ __pyx_methods /* m_methods */, NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL /* m_free */ }; #endif static __Pyx_StringTabEntry __pyx_string_tab[] = { {&__pyx_kp_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 0}, {&__pyx_kp_s_10, __pyx_k_10, sizeof(__pyx_k_10), 0, 0, 1, 0}, {&__pyx_kp_s_11, __pyx_k_11, sizeof(__pyx_k_11), 0, 0, 1, 0}, {&__pyx_kp_s_12, __pyx_k_12, sizeof(__pyx_k_12), 0, 0, 1, 0}, {&__pyx_kp_s_13, __pyx_k_13, sizeof(__pyx_k_13), 0, 0, 1, 0}, {&__pyx_kp_s_14, __pyx_k_14, sizeof(__pyx_k_14), 0, 0, 1, 0}, {&__pyx_kp_s_15, __pyx_k_15, sizeof(__pyx_k_15), 0, 0, 1, 0}, {&__pyx_kp_s_16, __pyx_k_16, sizeof(__pyx_k_16), 0, 0, 1, 0}, {&__pyx_kp_s_17, __pyx_k_17, sizeof(__pyx_k_17), 0, 0, 1, 0}, {&__pyx_n_s_18, __pyx_k_18, sizeof(__pyx_k_18), 0, 0, 1, 1}, {&__pyx_n_s_19, __pyx_k_19, sizeof(__pyx_k_19), 0, 0, 1, 1}, {&__pyx_kp_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 0}, {&__pyx_kp_u_20, __pyx_k_20, sizeof(__pyx_k_20), 0, 1, 0, 0}, {&__pyx_kp_u_21, __pyx_k_21, sizeof(__pyx_k_21), 0, 1, 0, 0}, {&__pyx_kp_u_22, __pyx_k_22, sizeof(__pyx_k_22), 0, 1, 0, 0}, {&__pyx_kp_u_23, __pyx_k_23, sizeof(__pyx_k_23), 0, 1, 0, 0}, {&__pyx_kp_u_24, __pyx_k_24, sizeof(__pyx_k_24), 0, 1, 0, 0}, {&__pyx_kp_u_25, __pyx_k_25, sizeof(__pyx_k_25), 0, 1, 0, 0}, {&__pyx_kp_u_26, __pyx_k_26, sizeof(__pyx_k_26), 0, 1, 0, 0}, {&__pyx_kp_u_27, __pyx_k_27, sizeof(__pyx_k_27), 0, 1, 0, 0}, {&__pyx_kp_u_28, __pyx_k_28, sizeof(__pyx_k_28), 0, 1, 0, 0}, {&__pyx_kp_u_29, __pyx_k_29, sizeof(__pyx_k_29), 0, 1, 0, 0}, {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0}, {&__pyx_kp_u_30, __pyx_k_30, sizeof(__pyx_k_30), 0, 1, 0, 0}, {&__pyx_kp_u_31, __pyx_k_31, sizeof(__pyx_k_31), 0, 1, 0, 0}, {&__pyx_kp_u_32, __pyx_k_32, sizeof(__pyx_k_32), 0, 1, 0, 0}, {&__pyx_kp_u_33, __pyx_k_33, sizeof(__pyx_k_33), 0, 1, 0, 0}, {&__pyx_kp_u_34, __pyx_k_34, sizeof(__pyx_k_34), 0, 1, 0, 0}, {&__pyx_kp_u_35, __pyx_k_35, sizeof(__pyx_k_35), 0, 1, 0, 0}, {&__pyx_kp_u_36, __pyx_k_36, sizeof(__pyx_k_36), 0, 1, 0, 0}, {&__pyx_kp_u_37, __pyx_k_37, sizeof(__pyx_k_37), 0, 1, 0, 0}, {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0}, {&__pyx_kp_s_5, __pyx_k_5, sizeof(__pyx_k_5), 0, 0, 1, 0}, {&__pyx_kp_s_6, __pyx_k_6, sizeof(__pyx_k_6), 0, 0, 1, 0}, {&__pyx_kp_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 0}, {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0}, {&__pyx_kp_s_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 0, 1, 0}, {&__pyx_n_s__Abort, __pyx_k__Abort, sizeof(__pyx_k__Abort), 0, 0, 1, 1}, {&__pyx_n_s__B, __pyx_k__B, sizeof(__pyx_k__B), 0, 0, 1, 1}, {&__pyx_n_s__Channel, __pyx_k__Channel, sizeof(__pyx_k__Channel), 0, 0, 1, 1}, {&__pyx_n_s__Close, __pyx_k__Close, sizeof(__pyx_k__Close), 0, 0, 1, 1}, {&__pyx_n_s__Exception, __pyx_k__Exception, sizeof(__pyx_k__Exception), 0, 0, 1, 1}, {&__pyx_n_s__FALSE, __pyx_k__FALSE, sizeof(__pyx_k__FALSE), 0, 0, 1, 1}, {&__pyx_n_s__FILT_ACTIVE, __pyx_k__FILT_ACTIVE, sizeof(__pyx_k__FILT_ACTIVE), 0, 0, 1, 1}, {&__pyx_n_s__FILT_AFTERTOUCH, __pyx_k__FILT_AFTERTOUCH, sizeof(__pyx_k__FILT_AFTERTOUCH), 0, 0, 1, 1}, {&__pyx_n_s__FILT_CLOCK, __pyx_k__FILT_CLOCK, sizeof(__pyx_k__FILT_CLOCK), 0, 0, 1, 1}, {&__pyx_n_s__FILT_CONTROL, __pyx_k__FILT_CONTROL, sizeof(__pyx_k__FILT_CONTROL), 0, 0, 1, 1}, {&__pyx_n_s__FILT_F9, __pyx_k__FILT_F9, sizeof(__pyx_k__FILT_F9), 0, 0, 1, 1}, {&__pyx_n_s__FILT_FD, __pyx_k__FILT_FD, sizeof(__pyx_k__FILT_FD), 0, 0, 1, 1}, {&__pyx_n_s__FILT_MTC, __pyx_k__FILT_MTC, sizeof(__pyx_k__FILT_MTC), 0, 0, 1, 1}, {&__pyx_n_s__FILT_NOTE, __pyx_k__FILT_NOTE, sizeof(__pyx_k__FILT_NOTE), 0, 0, 1, 1}, {&__pyx_n_s__FILT_PITCHBEND, __pyx_k__FILT_PITCHBEND, sizeof(__pyx_k__FILT_PITCHBEND), 0, 0, 1, 1}, {&__pyx_n_s__FILT_PLAY, __pyx_k__FILT_PLAY, sizeof(__pyx_k__FILT_PLAY), 0, 0, 1, 1}, {&__pyx_n_s__FILT_PROGRAM, __pyx_k__FILT_PROGRAM, sizeof(__pyx_k__FILT_PROGRAM), 0, 0, 1, 1}, {&__pyx_n_s__FILT_REALTIME, __pyx_k__FILT_REALTIME, sizeof(__pyx_k__FILT_REALTIME), 0, 0, 1, 1}, {&__pyx_n_s__FILT_RESET, __pyx_k__FILT_RESET, sizeof(__pyx_k__FILT_RESET), 0, 0, 1, 1}, {&__pyx_n_s__FILT_SONG_POSITION, __pyx_k__FILT_SONG_POSITION, sizeof(__pyx_k__FILT_SONG_POSITION), 0, 0, 1, 1}, {&__pyx_n_s__FILT_SONG_SELECT, __pyx_k__FILT_SONG_SELECT, sizeof(__pyx_k__FILT_SONG_SELECT), 0, 0, 1, 1}, {&__pyx_n_s__FILT_SYSEX, __pyx_k__FILT_SYSEX, sizeof(__pyx_k__FILT_SYSEX), 0, 0, 1, 1}, {&__pyx_n_s__FILT_TICK, __pyx_k__FILT_TICK, sizeof(__pyx_k__FILT_TICK), 0, 0, 1, 1}, {&__pyx_n_s__FILT_TUNE, __pyx_k__FILT_TUNE, sizeof(__pyx_k__FILT_TUNE), 0, 0, 1, 1}, {&__pyx_n_s__FILT_UNDEFINED, __pyx_k__FILT_UNDEFINED, sizeof(__pyx_k__FILT_UNDEFINED), 0, 0, 1, 1}, {&__pyx_n_s__GetDeviceInfo, __pyx_k__GetDeviceInfo, sizeof(__pyx_k__GetDeviceInfo), 0, 0, 1, 1}, {&__pyx_n_s__GetErrorText, __pyx_k__GetErrorText, sizeof(__pyx_k__GetErrorText), 0, 0, 1, 1}, {&__pyx_n_s__IndexError, __pyx_k__IndexError, sizeof(__pyx_k__IndexError), 0, 0, 1, 1}, {&__pyx_n_s__Initialize, __pyx_k__Initialize, sizeof(__pyx_k__Initialize), 0, 0, 1, 1}, {&__pyx_n_s__Input, __pyx_k__Input, sizeof(__pyx_k__Input), 0, 0, 1, 1}, {&__pyx_n_s__InputDevice, __pyx_k__InputDevice, sizeof(__pyx_k__InputDevice), 0, 0, 1, 1}, {&__pyx_n_s__Output, __pyx_k__Output, sizeof(__pyx_k__Output), 0, 0, 1, 1}, {&__pyx_n_s__OutputDevice, __pyx_k__OutputDevice, sizeof(__pyx_k__OutputDevice), 0, 0, 1, 1}, {&__pyx_n_s__Poll, __pyx_k__Poll, sizeof(__pyx_k__Poll), 0, 0, 1, 1}, {&__pyx_n_s__Read, __pyx_k__Read, sizeof(__pyx_k__Read), 0, 0, 1, 1}, {&__pyx_n_s__SetChannelMask, __pyx_k__SetChannelMask, sizeof(__pyx_k__SetChannelMask), 0, 0, 1, 1}, {&__pyx_n_s__SetFilter, __pyx_k__SetFilter, sizeof(__pyx_k__SetFilter), 0, 0, 1, 1}, {&__pyx_n_s__TRUE, __pyx_k__TRUE, sizeof(__pyx_k__TRUE), 0, 0, 1, 1}, {&__pyx_n_s__Terminate, __pyx_k__Terminate, sizeof(__pyx_k__Terminate), 0, 0, 1, 1}, {&__pyx_n_s__Time, __pyx_k__Time, sizeof(__pyx_k__Time), 0, 0, 1, 1}, {&__pyx_n_s__Write, __pyx_k__Write, sizeof(__pyx_k__Write), 0, 0, 1, 1}, {&__pyx_n_s__WriteShort, __pyx_k__WriteShort, sizeof(__pyx_k__WriteShort), 0, 0, 1, 1}, {&__pyx_n_s__WriteSysEx, __pyx_k__WriteSysEx, sizeof(__pyx_k__WriteSysEx), 0, 0, 1, 1}, {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1}, {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1}, {&__pyx_n_s____version__, __pyx_k____version__, sizeof(__pyx_k____version__), 0, 0, 1, 1}, {&__pyx_n_s___aborted, __pyx_k___aborted, sizeof(__pyx_k___aborted), 0, 0, 1, 1}, {&__pyx_n_s___check_open, __pyx_k___check_open, sizeof(__pyx_k___check_open), 0, 0, 1, 1}, {&__pyx_n_s__array, __pyx_k__array, sizeof(__pyx_k__array), 0, 0, 1, 1}, {&__pyx_n_s__buffersize, __pyx_k__buffersize, sizeof(__pyx_k__buffersize), 0, 0, 1, 1}, {&__pyx_n_s__data1, __pyx_k__data1, sizeof(__pyx_k__data1), 0, 0, 1, 1}, {&__pyx_n_s__data2, __pyx_k__data2, sizeof(__pyx_k__data2), 0, 0, 1, 1}, {&__pyx_n_s__debug, __pyx_k__debug, sizeof(__pyx_k__debug), 0, 0, 1, 1}, {&__pyx_n_s__i, __pyx_k__i, sizeof(__pyx_k__i), 0, 0, 1, 1}, {&__pyx_n_s__input, __pyx_k__input, sizeof(__pyx_k__input), 0, 0, 1, 1}, {&__pyx_n_s__interf, __pyx_k__interf, sizeof(__pyx_k__interf), 0, 0, 1, 1}, {&__pyx_n_s__latency, __pyx_k__latency, sizeof(__pyx_k__latency), 0, 0, 1, 1}, {&__pyx_n_s__message, __pyx_k__message, sizeof(__pyx_k__message), 0, 0, 1, 1}, {&__pyx_n_s__midi, __pyx_k__midi, sizeof(__pyx_k__midi), 0, 0, 1, 1}, {&__pyx_n_s__msg, __pyx_k__msg, sizeof(__pyx_k__msg), 0, 0, 1, 1}, {&__pyx_n_s__name, __pyx_k__name, sizeof(__pyx_k__name), 0, 0, 1, 1}, {&__pyx_n_s__opened, __pyx_k__opened, sizeof(__pyx_k__opened), 0, 0, 1, 1}, {&__pyx_n_s__output, __pyx_k__output, sizeof(__pyx_k__output), 0, 0, 1, 1}, {&__pyx_n_s__range, __pyx_k__range, sizeof(__pyx_k__range), 0, 0, 1, 1}, {&__pyx_n_s__status, __pyx_k__status, sizeof(__pyx_k__status), 0, 0, 1, 1}, {&__pyx_n_s__timestamp, __pyx_k__timestamp, sizeof(__pyx_k__timestamp), 0, 0, 1, 1}, {&__pyx_n_s__tostring, __pyx_k__tostring, sizeof(__pyx_k__tostring), 0, 0, 1, 1}, {&__pyx_n_s__when, __pyx_k__when, sizeof(__pyx_k__when), 0, 0, 1, 1}, {0, 0, 0, 0, 0, 0, 0} }; static int __Pyx_InitCachedBuiltins(void) { __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_builtin_IndexError = __Pyx_GetName(__pyx_b, __pyx_n_s__IndexError); if (!__pyx_builtin_IndexError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 318; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_builtin_range = __Pyx_GetName(__pyx_b, __pyx_n_s__range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;} return 0; __pyx_L1_error:; return -1; } static int __Pyx_InitGlobals(void) { if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_16 = PyInt_FromLong(16); if (unlikely(!__pyx_int_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x1 = PyInt_FromLong(0x1); if (unlikely(!__pyx_int_0x1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x2 = PyInt_FromLong(0x2); if (unlikely(!__pyx_int_0x2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x4 = PyInt_FromLong(0x4); if (unlikely(!__pyx_int_0x4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x8 = PyInt_FromLong(0x8); if (unlikely(!__pyx_int_0x8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x10 = PyInt_FromLong(0x10); if (unlikely(!__pyx_int_0x10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x20 = PyInt_FromLong(0x20); if (unlikely(!__pyx_int_0x20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x30 = PyInt_FromLong(0x30); if (unlikely(!__pyx_int_0x30)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x40 = PyInt_FromLong(0x40); if (unlikely(!__pyx_int_0x40)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x7F = PyInt_FromLong(0x7F); if (unlikely(!__pyx_int_0x7F)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x80 = PyInt_FromLong(0x80); if (unlikely(!__pyx_int_0x80)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0xFF = PyInt_FromLong(0xFF); if (unlikely(!__pyx_int_0xFF)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_1024 = PyInt_FromLong(1024); if (unlikely(!__pyx_int_1024)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_4096 = PyInt_FromLong(4096); if (unlikely(!__pyx_int_4096)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x100 = PyInt_FromLong(0x100); if (unlikely(!__pyx_int_0x100)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x200 = PyInt_FromLong(0x200); if (unlikely(!__pyx_int_0x200)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x300 = PyInt_FromLong(0x300); if (unlikely(!__pyx_int_0x300)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x400 = PyInt_FromLong(0x400); if (unlikely(!__pyx_int_0x400)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x800 = PyInt_FromLong(0x800); if (unlikely(!__pyx_int_0x800)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x1000 = PyInt_FromLong(0x1000); if (unlikely(!__pyx_int_0x1000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x2000 = PyInt_FromLong(0x2000); if (unlikely(!__pyx_int_0x2000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x4000 = PyInt_FromLong(0x4000); if (unlikely(!__pyx_int_0x4000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x8000 = PyInt_FromLong(0x8000); if (unlikely(!__pyx_int_0x8000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0xFF00 = PyInt_FromLong(0xFF00); if (unlikely(!__pyx_int_0xFF00)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0x10000 = PyInt_FromLong(0x10000); if (unlikely(!__pyx_int_0x10000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; __pyx_int_0xFF0000 = PyInt_FromLong(0xFF0000); if (unlikely(!__pyx_int_0xFF0000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; return 0; __pyx_L1_error:; return -1; } #if PY_MAJOR_VERSION < 3 PyMODINIT_FUNC init_pyportmidi(void); /*proto*/ PyMODINIT_FUNC init_pyportmidi(void) #else PyMODINIT_FUNC PyInit__pyportmidi(void); /*proto*/ PyMODINIT_FUNC PyInit__pyportmidi(void) #endif { PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; #if CYTHON_REFNANNY void* __pyx_refnanny = NULL; __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); if (!__Pyx_RefNanny) { PyErr_Clear(); __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); if (!__Pyx_RefNanny) Py_FatalError("failed to import 'refnanny' module"); } __pyx_refnanny = __Pyx_RefNanny->SetupContext("PyMODINIT_FUNC PyInit__pyportmidi(void)", __LINE__, __FILE__); #endif __pyx_init_filenames(); __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} #if PY_MAJOR_VERSION < 3 __pyx_empty_bytes = PyString_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} #else __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} #endif /*--- Library function declarations ---*/ /*--- Threads initialization code ---*/ #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS #ifdef WITH_THREAD /* Python build with threading support? */ PyEval_InitThreads(); #endif #endif /*--- Module creation code ---*/ #if PY_MAJOR_VERSION < 3 __pyx_m = Py_InitModule4(__Pyx_NAMESTR("_pyportmidi"), __pyx_methods, 0, 0, PYTHON_API_VERSION); #else __pyx_m = PyModule_Create(&__pyx_moduledef); #endif if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; #if PY_MAJOR_VERSION < 3 Py_INCREF(__pyx_m); #endif __pyx_b = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME)); if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; if (__Pyx_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; /*--- Initialize various global constants etc. ---*/ if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} if (__pyx_module_is_main__pyportmidi) { if (__Pyx_SetAttrString(__pyx_m, "__name__", __pyx_n_s____main__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; } /*--- Builtin init code ---*/ if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /*--- Global init code ---*/ /*--- Function export code ---*/ /*--- Type init code ---*/ if (PyType_Ready(&__pyx_type_11_pyportmidi_Output) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L1_error;} if (__Pyx_SetAttrString(__pyx_m, "Output", (PyObject *)&__pyx_type_11_pyportmidi_Output) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_ptype_11_pyportmidi_Output = &__pyx_type_11_pyportmidi_Output; if (PyType_Ready(&__pyx_type_11_pyportmidi_Input) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;} if (__Pyx_SetAttrString(__pyx_m, "Input", (PyObject *)&__pyx_type_11_pyportmidi_Input) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_ptype_11_pyportmidi_Input = &__pyx_type_11_pyportmidi_Input; /*--- Type import code ---*/ /*--- Function import code ---*/ /*--- Execution code ---*/ /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":7 * # harrison@media.mit.edu * # written in Pyrex * __version__="0.07" # <<<<<<<<<<<<<< * * import array */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s____version__, ((PyObject *)__pyx_kp_s_17)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":9 * __version__="0.07" * * import array # <<<<<<<<<<<<<< * * # CHANGES: */ __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s__array), 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyObject_SetAttr(__pyx_m, __pyx_n_s__array, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":108 * PtTimestamp Pt_Time() * * FILT_ACTIVE=0x1 # <<<<<<<<<<<<<< * FILT_SYSEX=0x2 * FILT_CLOCK=0x4 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_ACTIVE, __pyx_int_0x1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":109 * * FILT_ACTIVE=0x1 * FILT_SYSEX=0x2 # <<<<<<<<<<<<<< * FILT_CLOCK=0x4 * FILT_PLAY=0x8 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_SYSEX, __pyx_int_0x2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":110 * FILT_ACTIVE=0x1 * FILT_SYSEX=0x2 * FILT_CLOCK=0x4 # <<<<<<<<<<<<<< * FILT_PLAY=0x8 * FILT_F9=0x10 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_CLOCK, __pyx_int_0x4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":111 * FILT_SYSEX=0x2 * FILT_CLOCK=0x4 * FILT_PLAY=0x8 # <<<<<<<<<<<<<< * FILT_F9=0x10 * FILT_TICK=0x10 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_PLAY, __pyx_int_0x8) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":112 * FILT_CLOCK=0x4 * FILT_PLAY=0x8 * FILT_F9=0x10 # <<<<<<<<<<<<<< * FILT_TICK=0x10 * FILT_FD=0x20 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_F9, __pyx_int_0x10) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":113 * FILT_PLAY=0x8 * FILT_F9=0x10 * FILT_TICK=0x10 # <<<<<<<<<<<<<< * FILT_FD=0x20 * FILT_UNDEFINED=0x30 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_TICK, __pyx_int_0x10) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":114 * FILT_F9=0x10 * FILT_TICK=0x10 * FILT_FD=0x20 # <<<<<<<<<<<<<< * FILT_UNDEFINED=0x30 * FILT_RESET=0x40 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_FD, __pyx_int_0x20) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":115 * FILT_TICK=0x10 * FILT_FD=0x20 * FILT_UNDEFINED=0x30 # <<<<<<<<<<<<<< * FILT_RESET=0x40 * FILT_REALTIME=0x7F */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_UNDEFINED, __pyx_int_0x30) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":116 * FILT_FD=0x20 * FILT_UNDEFINED=0x30 * FILT_RESET=0x40 # <<<<<<<<<<<<<< * FILT_REALTIME=0x7F * FILT_NOTE=0x80 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_RESET, __pyx_int_0x40) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":117 * FILT_UNDEFINED=0x30 * FILT_RESET=0x40 * FILT_REALTIME=0x7F # <<<<<<<<<<<<<< * FILT_NOTE=0x80 * FILT_CHANNEL_AFTERTOUCH=0x100 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_REALTIME, __pyx_int_0x7F) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":118 * FILT_RESET=0x40 * FILT_REALTIME=0x7F * FILT_NOTE=0x80 # <<<<<<<<<<<<<< * FILT_CHANNEL_AFTERTOUCH=0x100 * FILT_POLY_AFTERTOUCH=0x200 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_NOTE, __pyx_int_0x80) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":119 * FILT_REALTIME=0x7F * FILT_NOTE=0x80 * FILT_CHANNEL_AFTERTOUCH=0x100 # <<<<<<<<<<<<<< * FILT_POLY_AFTERTOUCH=0x200 * FILT_AFTERTOUCH=0x300 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s_18, __pyx_int_0x100) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":120 * FILT_NOTE=0x80 * FILT_CHANNEL_AFTERTOUCH=0x100 * FILT_POLY_AFTERTOUCH=0x200 # <<<<<<<<<<<<<< * FILT_AFTERTOUCH=0x300 * FILT_PROGRAM=0x400 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s_19, __pyx_int_0x200) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":121 * FILT_CHANNEL_AFTERTOUCH=0x100 * FILT_POLY_AFTERTOUCH=0x200 * FILT_AFTERTOUCH=0x300 # <<<<<<<<<<<<<< * FILT_PROGRAM=0x400 * FILT_CONTROL=0x800 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_AFTERTOUCH, __pyx_int_0x300) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":122 * FILT_POLY_AFTERTOUCH=0x200 * FILT_AFTERTOUCH=0x300 * FILT_PROGRAM=0x400 # <<<<<<<<<<<<<< * FILT_CONTROL=0x800 * FILT_PITCHBEND=0x1000 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_PROGRAM, __pyx_int_0x400) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":123 * FILT_AFTERTOUCH=0x300 * FILT_PROGRAM=0x400 * FILT_CONTROL=0x800 # <<<<<<<<<<<<<< * FILT_PITCHBEND=0x1000 * FILT_MTC=0x2000 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_CONTROL, __pyx_int_0x800) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":124 * FILT_PROGRAM=0x400 * FILT_CONTROL=0x800 * FILT_PITCHBEND=0x1000 # <<<<<<<<<<<<<< * FILT_MTC=0x2000 * FILT_SONG_POSITION=0x4000 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_PITCHBEND, __pyx_int_0x1000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":125 * FILT_CONTROL=0x800 * FILT_PITCHBEND=0x1000 * FILT_MTC=0x2000 # <<<<<<<<<<<<<< * FILT_SONG_POSITION=0x4000 * FILT_SONG_SELECT=0x8000 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_MTC, __pyx_int_0x2000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":126 * FILT_PITCHBEND=0x1000 * FILT_MTC=0x2000 * FILT_SONG_POSITION=0x4000 # <<<<<<<<<<<<<< * FILT_SONG_SELECT=0x8000 * FILT_TUNE=0x10000 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_SONG_POSITION, __pyx_int_0x4000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":127 * FILT_MTC=0x2000 * FILT_SONG_POSITION=0x4000 * FILT_SONG_SELECT=0x8000 # <<<<<<<<<<<<<< * FILT_TUNE=0x10000 * FALSE=0 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_SONG_SELECT, __pyx_int_0x8000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":128 * FILT_SONG_POSITION=0x4000 * FILT_SONG_SELECT=0x8000 * FILT_TUNE=0x10000 # <<<<<<<<<<<<<< * FALSE=0 * TRUE=1 */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_TUNE, __pyx_int_0x10000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":129 * FILT_SONG_SELECT=0x8000 * FILT_TUNE=0x10000 * FALSE=0 # <<<<<<<<<<<<<< * TRUE=1 * */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FALSE, __pyx_int_0) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":130 * FILT_TUNE=0x10000 * FALSE=0 * TRUE=1 # <<<<<<<<<<<<<< * * def Initialize(): */ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__TRUE, __pyx_int_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":1 * # pyPortMidi # <<<<<<<<<<<<<< * # Python bindings for PortMidi * # John Harrison */ __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Initialize); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_2, "__doc__"); __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_20), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Terminate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_21), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__GetDeviceInfo); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_2, "__doc__"); __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_22), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Time); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_23), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__GetErrorText); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_2, "__doc__"); __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_24), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Channel); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_25), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s___check_open); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_26), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Close); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_27), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Abort); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_28), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Write); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_29), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__WriteShort); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_30), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__WriteSysEx); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_31), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s___check_open); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_32), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Close); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_33), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__SetFilter); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_34), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__SetChannelMask); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_35), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Poll); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_36), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Read); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__"); __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_37), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (PyObject_SetAttr(__pyx_m, __pyx_n_s____test__, ((PyObject *)__pyx_t_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); if (__pyx_m) { __Pyx_AddTraceback("init _pyportmidi"); Py_DECREF(__pyx_m); __pyx_m = 0; } else if (!PyErr_Occurred()) { PyErr_SetString(PyExc_ImportError, "init _pyportmidi"); } __pyx_L0:; __Pyx_RefNannyFinishContext(); #if PY_MAJOR_VERSION < 3 return; #else return __pyx_m; #endif } static const char *__pyx_filenames[] = { "_pyportmidi.pyx", }; /* Runtime support code */ static void __pyx_init_filenames(void) { __pyx_f = __pyx_filenames; } static void __Pyx_RaiseDoubleKeywordsError( const char* func_name, PyObject* kw_name) { PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION >= 3 "%s() got multiple values for keyword argument '%U'", func_name, kw_name); #else "%s() got multiple values for keyword argument '%s'", func_name, PyString_AS_STRING(kw_name)); #endif } static void __Pyx_RaiseArgtupleInvalid( const char* func_name, int exact, Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found) { Py_ssize_t num_expected; const char *number, *more_or_less; if (num_found < num_min) { num_expected = num_min; more_or_less = "at least"; } else { num_expected = num_max; more_or_less = "at most"; } if (exact) { more_or_less = "exactly"; } number = (num_expected == 1) ? "" : "s"; PyErr_Format(PyExc_TypeError, #if PY_VERSION_HEX < 0x02050000 "%s() takes %s %d positional argument%s (%d given)", #else "%s() takes %s %zd positional argument%s (%zd given)", #endif func_name, more_or_less, num_expected, number, num_found); } static int __Pyx_ParseOptionalKeywords( PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name) { PyObject *key = 0, *value = 0; Py_ssize_t pos = 0; PyObject*** name; PyObject*** first_kw_arg = argnames + num_pos_args; while (PyDict_Next(kwds, &pos, &key, &value)) { name = first_kw_arg; while (*name && (**name != key)) name++; if (*name) { values[name-argnames] = value; } else { #if PY_MAJOR_VERSION < 3 if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) { #else if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) { #endif goto invalid_keyword_type; } else { for (name = first_kw_arg; *name; name++) { #if PY_MAJOR_VERSION >= 3 if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && PyUnicode_Compare(**name, key) == 0) break; #else if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && _PyString_Eq(**name, key)) break; #endif } if (*name) { values[name-argnames] = value; } else { /* unexpected keyword found */ for (name=argnames; name != first_kw_arg; name++) { if (**name == key) goto arg_passed_twice; #if PY_MAJOR_VERSION >= 3 if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice; #else if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && _PyString_Eq(**name, key)) goto arg_passed_twice; #endif } if (kwds2) { if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; } else { goto invalid_keyword; } } } } } return 0; arg_passed_twice: __Pyx_RaiseDoubleKeywordsError(function_name, **name); goto bad; invalid_keyword_type: PyErr_Format(PyExc_TypeError, "%s() keywords must be strings", function_name); goto bad; invalid_keyword: PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION < 3 "%s() got an unexpected keyword argument '%s'", function_name, PyString_AsString(key)); #else "%s() got an unexpected keyword argument '%U'", function_name, key); #endif bad: return -1; } static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { PyObject *__import__ = 0; PyObject *empty_list = 0; PyObject *module = 0; PyObject *global_dict = 0; PyObject *empty_dict = 0; PyObject *list; __import__ = __Pyx_GetAttrString(__pyx_b, "__import__"); if (!__import__) goto bad; if (from_list) list = from_list; else { empty_list = PyList_New(0); if (!empty_list) goto bad; list = empty_list; } global_dict = PyModule_GetDict(__pyx_m); if (!global_dict) goto bad; empty_dict = PyDict_New(); if (!empty_dict) goto bad; module = PyObject_CallFunctionObjArgs(__import__, name, global_dict, empty_dict, list, NULL); bad: Py_XDECREF(empty_list); Py_XDECREF(__import__); Py_XDECREF(empty_dict); return module; } static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmDeviceID(PmDeviceID val) { const PmDeviceID neg_one = (PmDeviceID)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PmDeviceID) < sizeof(long)) { return PyInt_FromLong((long)val); } else if (sizeof(PmDeviceID) == sizeof(long)) { if (is_unsigned) return PyLong_FromUnsignedLong((unsigned long)val); else return PyInt_FromLong((long)val); } else { /* (sizeof(PmDeviceID) > sizeof(long)) */ if (is_unsigned) return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val); else return PyLong_FromLongLong((PY_LONG_LONG)val); } } static CYTHON_INLINE PmDeviceID __Pyx_PyInt_from_py_PmDeviceID(PyObject* x) { const PmDeviceID neg_one = (PmDeviceID)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PmDeviceID) == sizeof(char)) { if (is_unsigned) return (PmDeviceID)__Pyx_PyInt_AsUnsignedChar(x); else return (PmDeviceID)__Pyx_PyInt_AsSignedChar(x); } else if (sizeof(PmDeviceID) == sizeof(short)) { if (is_unsigned) return (PmDeviceID)__Pyx_PyInt_AsUnsignedShort(x); else return (PmDeviceID)__Pyx_PyInt_AsSignedShort(x); } else if (sizeof(PmDeviceID) == sizeof(int)) { if (is_unsigned) return (PmDeviceID)__Pyx_PyInt_AsUnsignedInt(x); else return (PmDeviceID)__Pyx_PyInt_AsSignedInt(x); } else if (sizeof(PmDeviceID) == sizeof(long)) { if (is_unsigned) return (PmDeviceID)__Pyx_PyInt_AsUnsignedLong(x); else return (PmDeviceID)__Pyx_PyInt_AsSignedLong(x); } else if (sizeof(PmDeviceID) == sizeof(PY_LONG_LONG)) { if (is_unsigned) return (PmDeviceID)__Pyx_PyInt_AsUnsignedLongLong(x); else return (PmDeviceID)__Pyx_PyInt_AsSignedLongLong(x); #if 0 } else if (sizeof(PmDeviceID) > sizeof(short) && sizeof(PmDeviceID) < sizeof(int)) { /* __int32 ILP64 ? */ if (is_unsigned) return (PmDeviceID)__Pyx_PyInt_AsUnsignedInt(x); else return (PmDeviceID)__Pyx_PyInt_AsSignedInt(x); #endif } PyErr_SetString(PyExc_TypeError, "PmDeviceID"); return (PmDeviceID)-1; } static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PtTimestamp(PtTimestamp val) { const PtTimestamp neg_one = (PtTimestamp)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PtTimestamp) < sizeof(long)) { return PyInt_FromLong((long)val); } else if (sizeof(PtTimestamp) == sizeof(long)) { if (is_unsigned) return PyLong_FromUnsignedLong((unsigned long)val); else return PyInt_FromLong((long)val); } else { /* (sizeof(PtTimestamp) > sizeof(long)) */ if (is_unsigned) return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val); else return PyLong_FromLongLong((PY_LONG_LONG)val); } } #if PY_MAJOR_VERSION < 3 static PyObject *__Pyx_GetStdout(void) { PyObject *f = PySys_GetObject((char *)"stdout"); if (!f) { PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); } return f; } static int __Pyx_Print(PyObject *arg_tuple, int newline) { PyObject *f; PyObject* v; int i; if (!(f = __Pyx_GetStdout())) return -1; for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) { if (PyFile_SoftSpace(f, 1)) { if (PyFile_WriteString(" ", f) < 0) return -1; } v = PyTuple_GET_ITEM(arg_tuple, i); if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0) return -1; if (PyString_Check(v)) { char *s = PyString_AsString(v); Py_ssize_t len = PyString_Size(v); if (len > 0 && isspace(Py_CHARMASK(s[len-1])) && s[len-1] != ' ') PyFile_SoftSpace(f, 0); } } if (newline) { if (PyFile_WriteString("\n", f) < 0) return -1; PyFile_SoftSpace(f, 0); } return 0; } #else /* Python 3 has a print function */ static int __Pyx_Print(PyObject *arg_tuple, int newline) { PyObject* kwargs = 0; PyObject* result = 0; PyObject* end_string; if (!__pyx_print) { __pyx_print = __Pyx_GetAttrString(__pyx_b, "print"); if (!__pyx_print) return -1; } if (!newline) { if (!__pyx_print_kwargs) { __pyx_print_kwargs = PyDict_New(); if (!__pyx_print_kwargs) return -1; end_string = PyUnicode_FromStringAndSize(" ", 1); if (!end_string) return -1; if (PyDict_SetItemString(__pyx_print_kwargs, "end", end_string) < 0) { Py_DECREF(end_string); return -1; } Py_DECREF(end_string); } kwargs = __pyx_print_kwargs; } result = PyObject_Call(__pyx_print, arg_tuple, kwargs); if (!result) return -1; Py_DECREF(result); return 0; } #endif #if PY_MAJOR_VERSION < 3 static int __Pyx_PrintOne(PyObject *o) { PyObject *f; if (!(f = __Pyx_GetStdout())) return -1; if (PyFile_SoftSpace(f, 0)) { if (PyFile_WriteString(" ", f) < 0) return -1; } if (PyFile_WriteObject(o, f, Py_PRINT_RAW) < 0) return -1; if (PyFile_WriteString("\n", f) < 0) return -1; return 0; /* the line below is just to avoid compiler * compiler warnings about unused functions */ return __Pyx_Print(NULL, 0); } #else /* Python 3 has a print function */ static int __Pyx_PrintOne(PyObject *o) { int res; PyObject* arg_tuple = PyTuple_New(1); if (unlikely(!arg_tuple)) return -1; Py_INCREF(o); PyTuple_SET_ITEM(arg_tuple, 0, o); res = __Pyx_Print(arg_tuple, 1); Py_DECREF(arg_tuple); return res; } #endif static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { PyObject *result; result = PyObject_GetAttr(dict, name); if (!result) PyErr_SetObject(PyExc_NameError, name); return result; } static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) { PyObject *tmp_type, *tmp_value, *tmp_tb; PyThreadState *tstate = PyThreadState_GET(); tmp_type = tstate->curexc_type; tmp_value = tstate->curexc_value; tmp_tb = tstate->curexc_traceback; tstate->curexc_type = type; tstate->curexc_value = value; tstate->curexc_traceback = tb; Py_XDECREF(tmp_type); Py_XDECREF(tmp_value); Py_XDECREF(tmp_tb); } static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) { PyThreadState *tstate = PyThreadState_GET(); *type = tstate->curexc_type; *value = tstate->curexc_value; *tb = tstate->curexc_traceback; tstate->curexc_type = 0; tstate->curexc_value = 0; tstate->curexc_traceback = 0; } #if PY_MAJOR_VERSION < 3 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { Py_XINCREF(type); Py_XINCREF(value); Py_XINCREF(tb); /* First, check the traceback argument, replacing None with NULL. */ if (tb == Py_None) { Py_DECREF(tb); tb = 0; } else if (tb != NULL && !PyTraceBack_Check(tb)) { PyErr_SetString(PyExc_TypeError, "raise: arg 3 must be a traceback or None"); goto raise_error; } /* Next, replace a missing value with None */ if (value == NULL) { value = Py_None; Py_INCREF(value); } #if PY_VERSION_HEX < 0x02050000 if (!PyClass_Check(type)) #else if (!PyType_Check(type)) #endif { /* Raising an instance. The value should be a dummy. */ if (value != Py_None) { PyErr_SetString(PyExc_TypeError, "instance exception may not have a separate value"); goto raise_error; } /* Normalize to raise , */ Py_DECREF(value); value = type; #if PY_VERSION_HEX < 0x02050000 if (PyInstance_Check(type)) { type = (PyObject*) ((PyInstanceObject*)type)->in_class; Py_INCREF(type); } else { type = 0; PyErr_SetString(PyExc_TypeError, "raise: exception must be an old-style class or instance"); goto raise_error; } #else type = (PyObject*) Py_TYPE(type); Py_INCREF(type); if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { PyErr_SetString(PyExc_TypeError, "raise: exception class must be a subclass of BaseException"); goto raise_error; } #endif } __Pyx_ErrRestore(type, value, tb); return; raise_error: Py_XDECREF(value); Py_XDECREF(type); Py_XDECREF(tb); return; } #else /* Python 3+ */ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { if (tb == Py_None) { tb = 0; } else if (tb && !PyTraceBack_Check(tb)) { PyErr_SetString(PyExc_TypeError, "raise: arg 3 must be a traceback or None"); goto bad; } if (value == Py_None) value = 0; if (PyExceptionInstance_Check(type)) { if (value) { PyErr_SetString(PyExc_TypeError, "instance exception may not have a separate value"); goto bad; } value = type; type = (PyObject*) Py_TYPE(value); } else if (!PyExceptionClass_Check(type)) { PyErr_SetString(PyExc_TypeError, "raise: exception class must be a subclass of BaseException"); goto bad; } PyErr_SetObject(type, value); if (tb) { PyThreadState *tstate = PyThreadState_GET(); PyObject* tmp_tb = tstate->curexc_traceback; if (tb != tmp_tb) { Py_INCREF(tb); tstate->curexc_traceback = tb; Py_XDECREF(tmp_tb); } } bad: return; } #endif static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmMessage(PmMessage val) { const PmMessage neg_one = (PmMessage)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PmMessage) < sizeof(long)) { return PyInt_FromLong((long)val); } else if (sizeof(PmMessage) == sizeof(long)) { if (is_unsigned) return PyLong_FromUnsignedLong((unsigned long)val); else return PyInt_FromLong((long)val); } else { /* (sizeof(PmMessage) > sizeof(long)) */ if (is_unsigned) return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val); else return PyLong_FromLongLong((PY_LONG_LONG)val); } } static CYTHON_INLINE PmMessage __Pyx_PyInt_from_py_PmMessage(PyObject* x) { const PmMessage neg_one = (PmMessage)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PmMessage) == sizeof(char)) { if (is_unsigned) return (PmMessage)__Pyx_PyInt_AsUnsignedChar(x); else return (PmMessage)__Pyx_PyInt_AsSignedChar(x); } else if (sizeof(PmMessage) == sizeof(short)) { if (is_unsigned) return (PmMessage)__Pyx_PyInt_AsUnsignedShort(x); else return (PmMessage)__Pyx_PyInt_AsSignedShort(x); } else if (sizeof(PmMessage) == sizeof(int)) { if (is_unsigned) return (PmMessage)__Pyx_PyInt_AsUnsignedInt(x); else return (PmMessage)__Pyx_PyInt_AsSignedInt(x); } else if (sizeof(PmMessage) == sizeof(long)) { if (is_unsigned) return (PmMessage)__Pyx_PyInt_AsUnsignedLong(x); else return (PmMessage)__Pyx_PyInt_AsSignedLong(x); } else if (sizeof(PmMessage) == sizeof(PY_LONG_LONG)) { if (is_unsigned) return (PmMessage)__Pyx_PyInt_AsUnsignedLongLong(x); else return (PmMessage)__Pyx_PyInt_AsSignedLongLong(x); #if 0 } else if (sizeof(PmMessage) > sizeof(short) && sizeof(PmMessage) < sizeof(int)) { /* __int32 ILP64 ? */ if (is_unsigned) return (PmMessage)__Pyx_PyInt_AsUnsignedInt(x); else return (PmMessage)__Pyx_PyInt_AsSignedInt(x); #endif } PyErr_SetString(PyExc_TypeError, "PmMessage"); return (PmMessage)-1; } static CYTHON_INLINE PmTimestamp __Pyx_PyInt_from_py_PmTimestamp(PyObject* x) { const PmTimestamp neg_one = (PmTimestamp)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PmTimestamp) == sizeof(char)) { if (is_unsigned) return (PmTimestamp)__Pyx_PyInt_AsUnsignedChar(x); else return (PmTimestamp)__Pyx_PyInt_AsSignedChar(x); } else if (sizeof(PmTimestamp) == sizeof(short)) { if (is_unsigned) return (PmTimestamp)__Pyx_PyInt_AsUnsignedShort(x); else return (PmTimestamp)__Pyx_PyInt_AsSignedShort(x); } else if (sizeof(PmTimestamp) == sizeof(int)) { if (is_unsigned) return (PmTimestamp)__Pyx_PyInt_AsUnsignedInt(x); else return (PmTimestamp)__Pyx_PyInt_AsSignedInt(x); } else if (sizeof(PmTimestamp) == sizeof(long)) { if (is_unsigned) return (PmTimestamp)__Pyx_PyInt_AsUnsignedLong(x); else return (PmTimestamp)__Pyx_PyInt_AsSignedLong(x); } else if (sizeof(PmTimestamp) == sizeof(PY_LONG_LONG)) { if (is_unsigned) return (PmTimestamp)__Pyx_PyInt_AsUnsignedLongLong(x); else return (PmTimestamp)__Pyx_PyInt_AsSignedLongLong(x); #if 0 } else if (sizeof(PmTimestamp) > sizeof(short) && sizeof(PmTimestamp) < sizeof(int)) { /* __int32 ILP64 ? */ if (is_unsigned) return (PmTimestamp)__Pyx_PyInt_AsUnsignedInt(x); else return (PmTimestamp)__Pyx_PyInt_AsSignedInt(x); #endif } PyErr_SetString(PyExc_TypeError, "PmTimestamp"); return (PmTimestamp)-1; } static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmTimestamp(PmTimestamp val) { const PmTimestamp neg_one = (PmTimestamp)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(PmTimestamp) < sizeof(long)) { return PyInt_FromLong((long)val); } else if (sizeof(PmTimestamp) == sizeof(long)) { if (is_unsigned) return PyLong_FromUnsignedLong((unsigned long)val); else return PyInt_FromLong((long)val); } else { /* (sizeof(PmTimestamp) > sizeof(long)) */ if (is_unsigned) return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val); else return PyLong_FromLongLong((PY_LONG_LONG)val); } } static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) { const unsigned char neg_one = (unsigned char)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(unsigned char) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(unsigned char)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to unsigned char" : "value too large to convert to unsigned char"); } return (unsigned char)-1; } return (unsigned char)val; } return (unsigned char)__Pyx_PyInt_AsUnsignedLong(x); } static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject* x) { const unsigned short neg_one = (unsigned short)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(unsigned short) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(unsigned short)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to unsigned short" : "value too large to convert to unsigned short"); } return (unsigned short)-1; } return (unsigned short)val; } return (unsigned short)__Pyx_PyInt_AsUnsignedLong(x); } static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject* x) { const unsigned int neg_one = (unsigned int)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(unsigned int) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(unsigned int)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to unsigned int" : "value too large to convert to unsigned int"); } return (unsigned int)-1; } return (unsigned int)val; } return (unsigned int)__Pyx_PyInt_AsUnsignedLong(x); } static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject* x) { const char neg_one = (char)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(char) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(char)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to char" : "value too large to convert to char"); } return (char)-1; } return (char)val; } return (char)__Pyx_PyInt_AsLong(x); } static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject* x) { const short neg_one = (short)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(short) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(short)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to short" : "value too large to convert to short"); } return (short)-1; } return (short)val; } return (short)__Pyx_PyInt_AsLong(x); } static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject* x) { const int neg_one = (int)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(int) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(int)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to int" : "value too large to convert to int"); } return (int)-1; } return (int)val; } return (int)__Pyx_PyInt_AsLong(x); } static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject* x) { const signed char neg_one = (signed char)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(signed char) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(signed char)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to signed char" : "value too large to convert to signed char"); } return (signed char)-1; } return (signed char)val; } return (signed char)__Pyx_PyInt_AsSignedLong(x); } static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject* x) { const signed short neg_one = (signed short)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(signed short) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(signed short)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to signed short" : "value too large to convert to signed short"); } return (signed short)-1; } return (signed short)val; } return (signed short)__Pyx_PyInt_AsSignedLong(x); } static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject* x) { const signed int neg_one = (signed int)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; if (sizeof(signed int) < sizeof(long)) { long val = __Pyx_PyInt_AsLong(x); if (unlikely(val != (long)(signed int)val)) { if (!unlikely(val == -1 && PyErr_Occurred())) { PyErr_SetString(PyExc_OverflowError, (is_unsigned && unlikely(val < 0)) ? "can't convert negative value to signed int" : "value too large to convert to signed int"); } return (signed int)-1; } return (signed int)val; } return (signed int)__Pyx_PyInt_AsSignedLong(x); } static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject* x) { const unsigned long neg_one = (unsigned long)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_VERSION_HEX < 0x03000000 if (likely(PyInt_Check(x))) { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned long"); return (unsigned long)-1; } return (unsigned long)val; } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned long"); return (unsigned long)-1; } return PyLong_AsUnsignedLong(x); } else { return PyLong_AsLong(x); } } else { unsigned long val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return (unsigned long)-1; val = __Pyx_PyInt_AsUnsignedLong(tmp); Py_DECREF(tmp); return val; } } static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject* x) { const unsigned PY_LONG_LONG neg_one = (unsigned PY_LONG_LONG)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_VERSION_HEX < 0x03000000 if (likely(PyInt_Check(x))) { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned PY_LONG_LONG"); return (unsigned PY_LONG_LONG)-1; } return (unsigned PY_LONG_LONG)val; } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned PY_LONG_LONG"); return (unsigned PY_LONG_LONG)-1; } return PyLong_AsUnsignedLongLong(x); } else { return PyLong_AsLongLong(x); } } else { unsigned PY_LONG_LONG val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return (unsigned PY_LONG_LONG)-1; val = __Pyx_PyInt_AsUnsignedLongLong(tmp); Py_DECREF(tmp); return val; } } static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject* x) { const long neg_one = (long)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_VERSION_HEX < 0x03000000 if (likely(PyInt_Check(x))) { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to long"); return (long)-1; } return (long)val; } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to long"); return (long)-1; } return PyLong_AsUnsignedLong(x); } else { return PyLong_AsLong(x); } } else { long val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return (long)-1; val = __Pyx_PyInt_AsLong(tmp); Py_DECREF(tmp); return val; } } static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject* x) { const PY_LONG_LONG neg_one = (PY_LONG_LONG)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_VERSION_HEX < 0x03000000 if (likely(PyInt_Check(x))) { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to PY_LONG_LONG"); return (PY_LONG_LONG)-1; } return (PY_LONG_LONG)val; } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to PY_LONG_LONG"); return (PY_LONG_LONG)-1; } return PyLong_AsUnsignedLongLong(x); } else { return PyLong_AsLongLong(x); } } else { PY_LONG_LONG val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1; val = __Pyx_PyInt_AsLongLong(tmp); Py_DECREF(tmp); return val; } } static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject* x) { const signed long neg_one = (signed long)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_VERSION_HEX < 0x03000000 if (likely(PyInt_Check(x))) { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to signed long"); return (signed long)-1; } return (signed long)val; } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to signed long"); return (signed long)-1; } return PyLong_AsUnsignedLong(x); } else { return PyLong_AsLong(x); } } else { signed long val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return (signed long)-1; val = __Pyx_PyInt_AsSignedLong(tmp); Py_DECREF(tmp); return val; } } static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject* x) { const signed PY_LONG_LONG neg_one = (signed PY_LONG_LONG)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; #if PY_VERSION_HEX < 0x03000000 if (likely(PyInt_Check(x))) { long val = PyInt_AS_LONG(x); if (is_unsigned && unlikely(val < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to signed PY_LONG_LONG"); return (signed PY_LONG_LONG)-1; } return (signed PY_LONG_LONG)val; } else #endif if (likely(PyLong_Check(x))) { if (is_unsigned) { if (unlikely(Py_SIZE(x) < 0)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to signed PY_LONG_LONG"); return (signed PY_LONG_LONG)-1; } return PyLong_AsUnsignedLongLong(x); } else { return PyLong_AsLongLong(x); } } else { signed PY_LONG_LONG val; PyObject *tmp = __Pyx_PyNumber_Int(x); if (!tmp) return (signed PY_LONG_LONG)-1; val = __Pyx_PyInt_AsSignedLongLong(tmp); Py_DECREF(tmp); return val; } } #include "compile.h" #include "frameobject.h" #include "traceback.h" static void __Pyx_AddTraceback(const char *funcname) { PyObject *py_srcfile = 0; PyObject *py_funcname = 0; PyObject *py_globals = 0; PyCodeObject *py_code = 0; PyFrameObject *py_frame = 0; #if PY_MAJOR_VERSION < 3 py_srcfile = PyString_FromString(__pyx_filename); #else py_srcfile = PyUnicode_FromString(__pyx_filename); #endif if (!py_srcfile) goto bad; if (__pyx_clineno) { #if PY_MAJOR_VERSION < 3 py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno); #else py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno); #endif } else { #if PY_MAJOR_VERSION < 3 py_funcname = PyString_FromString(funcname); #else py_funcname = PyUnicode_FromString(funcname); #endif } if (!py_funcname) goto bad; py_globals = PyModule_GetDict(__pyx_m); if (!py_globals) goto bad; py_code = PyCode_New( 0, /*int argcount,*/ #if PY_MAJOR_VERSION >= 3 0, /*int kwonlyargcount,*/ #endif 0, /*int nlocals,*/ 0, /*int stacksize,*/ 0, /*int flags,*/ __pyx_empty_bytes, /*PyObject *code,*/ __pyx_empty_tuple, /*PyObject *consts,*/ __pyx_empty_tuple, /*PyObject *names,*/ __pyx_empty_tuple, /*PyObject *varnames,*/ __pyx_empty_tuple, /*PyObject *freevars,*/ __pyx_empty_tuple, /*PyObject *cellvars,*/ py_srcfile, /*PyObject *filename,*/ py_funcname, /*PyObject *name,*/ __pyx_lineno, /*int firstlineno,*/ __pyx_empty_bytes /*PyObject *lnotab*/ ); if (!py_code) goto bad; py_frame = PyFrame_New( PyThreadState_GET(), /*PyThreadState *tstate,*/ py_code, /*PyCodeObject *code,*/ py_globals, /*PyObject *globals,*/ 0 /*PyObject *locals*/ ); if (!py_frame) goto bad; py_frame->f_lineno = __pyx_lineno; PyTraceBack_Here(py_frame); bad: Py_XDECREF(py_srcfile); Py_XDECREF(py_funcname); Py_XDECREF(py_code); Py_XDECREF(py_frame); } static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { while (t->p) { #if PY_MAJOR_VERSION < 3 if (t->is_unicode) { *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); } else if (t->intern) { *t->p = PyString_InternFromString(t->s); } else { *t->p = PyString_FromStringAndSize(t->s, t->n - 1); } #else /* Python 3+ has unicode identifiers */ if (t->is_unicode | t->is_str) { if (t->intern) { *t->p = PyUnicode_InternFromString(t->s); } else if (t->encoding) { *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); } else { *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); } } else { *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); } #endif if (!*t->p) return -1; ++t; } return 0; } /* Type Conversion Functions */ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { if (x == Py_True) return 1; else if ((x == Py_False) | (x == Py_None)) return 0; else return PyObject_IsTrue(x); } static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { PyNumberMethods *m; const char *name = NULL; PyObject *res = NULL; #if PY_VERSION_HEX < 0x03000000 if (PyInt_Check(x) || PyLong_Check(x)) #else if (PyLong_Check(x)) #endif return Py_INCREF(x), x; m = Py_TYPE(x)->tp_as_number; #if PY_VERSION_HEX < 0x03000000 if (m && m->nb_int) { name = "int"; res = PyNumber_Int(x); } else if (m && m->nb_long) { name = "long"; res = PyNumber_Long(x); } #else if (m && m->nb_int) { name = "int"; res = PyNumber_Long(x); } #endif if (res) { #if PY_VERSION_HEX < 0x03000000 if (!PyInt_Check(res) && !PyLong_Check(res)) { #else if (!PyLong_Check(res)) { #endif PyErr_Format(PyExc_TypeError, "__%s__ returned non-%s (type %.200s)", name, name, Py_TYPE(res)->tp_name); Py_DECREF(res); return NULL; } } else if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "an integer is required"); } return res; } static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { Py_ssize_t ival; PyObject* x = PyNumber_Index(b); if (!x) return -1; ival = PyInt_AsSsize_t(x); Py_DECREF(x); return ival; } static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { #if PY_VERSION_HEX < 0x02050000 if (ival <= LONG_MAX) return PyInt_FromLong((long)ival); else { unsigned char *bytes = (unsigned char *) &ival; int one = 1; int little = (int)*(unsigned char*)&one; return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0); } #else return PyInt_FromSize_t(ival); #endif } static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) { unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x); if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) { return (size_t)-1; } else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) { PyErr_SetString(PyExc_OverflowError, "value too large to convert to size_t"); return (size_t)-1; } return (size_t)val; } #endif /* Py_PYTHON_H */ portmidi/pm_python/pyportmidi/_pyportmidi.pyx0000644000000000000000000004173011447645574020747 0ustar rootroot# pyPortMidi # Python bindings for PortMidi # John Harrison # http://sound.media.mit.edu/~harrison # harrison@media.mit.edu # written in Pyrex __version__="0.07" import array # CHANGES: # 0.0.5: (June 1st, 2009) # Output no longer calls abort when it deallocates. # Added abort and close methods. # Need to call Abort() explicityly if you want that to happen. # # 0.0.3: (March 15, 2005) # changed everything from tuples to lists # return 4 values for PmRead instead of 3 (for SysEx) # minor fixes for flexibility and error checking # flushed out DistUtils package and added Mac and Linux compile support # Markus Pfaff: added ability for WriteSysEx to accept lists as well # as strings # 0.0.2: # fixed pointer to function calls to avoid necessity of pyport library # 0.0.1: # initial release cdef extern from "portmidi.h": ctypedef enum PmError: pmNoError = 0, pmHostError = -10000, pmInvalidDeviceId, #/* out of range or output device when input is requested or vice versa */ pmInsufficientMemory, pmBufferTooSmall, pmBufferOverflow, pmBadPtr, pmBadData, #/* illegal midi data, e.g. missing EOX */ pmInternalError, pmBufferMaxSize, #/* buffer is already as large as it can be */ PmError Pm_Initialize() PmError Pm_Terminate() ctypedef void PortMidiStream ctypedef PortMidiStream PmStream # CHECK THIS! ctypedef int PmDeviceID int Pm_HasHostError( PortMidiStream * stream ) char *Pm_GetErrorText( PmError errnum ) Pm_GetHostErrorText(char * msg, unsigned int len) ctypedef struct PmDeviceInfo: int structVersion char *interf #/* underlying MIDI API, e.g. MMSystem or DirectX */ char *name #/* device name, e.g. USB MidiSport 1x1 */ int input #/* true iff input is available */ int output #/* true iff output is available */ int opened #/* used by generic PortMidi code to do error checking on arguments */ int Pm_CountDevices() PmDeviceID Pm_GetDefaultInputDeviceID() PmDeviceID Pm_GetDefaultOutputDeviceID() ctypedef long PmTimestamp ctypedef PmTimestamp (*PmTimeProcPtr)(void *time_info) #PmBefore is not defined... PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) PmError Pm_OpenInput( PortMidiStream** stream, PmDeviceID inputDevice, void *inputDriverInfo, long bufferSize, long (*PmPtr) (), # long = PtTimestamp void *time_info ) PmError Pm_OpenOutput( PortMidiStream** stream, PmDeviceID outputDevice, void *outputDriverInfo, long bufferSize, #long (*PmPtr) (), # long = PtTimestamp PmTimeProcPtr time_proc, # long = PtTimestamp void *time_info, long latency ) PmError Pm_SetFilter( PortMidiStream* stream, long filters ) PmError Pm_Abort( PortMidiStream* stream ) PmError Pm_Close( PortMidiStream* stream ) ctypedef long PmMessage ctypedef struct PmEvent: PmMessage message PmTimestamp timestamp PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length ) PmError Pm_Poll( PortMidiStream *stream) int Pm_Channel(int channel) PmError Pm_SetChannelMask(PortMidiStream *stream, int mask) PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length ) PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg) cdef extern from "porttime.h": ctypedef enum PtError: ptNoError = 0, ptHostError = -10000, ptAlreadyStarted, ptAlreadyStopped, ptInsufficientMemory ctypedef long PtTimestamp ctypedef void (* PtCallback)( PtTimestamp timestamp, void *userData ) PtError Pt_Start(int resolution, PtCallback *callback, void *userData) PtTimestamp Pt_Time() FILT_ACTIVE=0x1 FILT_SYSEX=0x2 FILT_CLOCK=0x4 FILT_PLAY=0x8 FILT_F9=0x10 FILT_TICK=0x10 FILT_FD=0x20 FILT_UNDEFINED=0x30 FILT_RESET=0x40 FILT_REALTIME=0x7F FILT_NOTE=0x80 FILT_CHANNEL_AFTERTOUCH=0x100 FILT_POLY_AFTERTOUCH=0x200 FILT_AFTERTOUCH=0x300 FILT_PROGRAM=0x400 FILT_CONTROL=0x800 FILT_PITCHBEND=0x1000 FILT_MTC=0x2000 FILT_SONG_POSITION=0x4000 FILT_SONG_SELECT=0x8000 FILT_TUNE=0x10000 FALSE=0 TRUE=1 def Initialize(): """ Initialize: call this first """ Pm_Initialize() Pt_Start(1, NULL, NULL) # /* equiv to TIME_START: start timer w/ ms accuracy */ def Terminate(): """ Terminate: call this to clean up Midi streams when done. If you do not call this on Windows machines when you are done with MIDI, your system may crash. """ Pm_Terminate() def GetDefaultInputDeviceID(): return Pm_GetDefaultInputDeviceID() def GetDefaultOutputDeviceID(): return Pm_GetDefaultOutputDeviceID() def CountDevices(): return Pm_CountDevices() def GetDeviceInfo(i): """ GetDeviceInfo(): returns 5 parameters - underlying MIDI API - device name - TRUE iff input is available - TRUE iff output is available - TRUE iff device stream is already open """ cdef PmDeviceInfo *info # disregarding the constness from Pm_GetDeviceInfo, since pyrex doesn't do const. info = Pm_GetDeviceInfo(i) if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened else: return def Time(): """ Time() returns the current time in ms of the PortMidi timer """ return Pt_Time() def GetErrorText(err): """ GetErrorText() returns human-readable error messages translated from error numbers """ return Pm_GetErrorText(err) def Channel(chan): """ Channel() is used with ChannelMask on input MIDI streams. Example: to receive input on channels 1 and 10 on a MIDI stream called MidiIn: MidiIn.SetChannelMask(pypm.Channel(1) | pypm.Channel(10)) note: PyPortMidi Channel function has been altered from the original PortMidi c call to correct for what seems to be a bug --- i.e. channel filters were all numbered from 0 to 15 instead of 1 to 16. """ return Pm_Channel(chan-1) cdef class Output: """ class Output: define an output MIDI stream. Takes the form: x = pypm.Output(MidiOutputDevice, latency) latency is in ms. If latency = 0 then timestamps for output are ignored. """ cdef int i cdef PmStream *midi cdef int debug cdef int _aborted def __init__(self, OutputDevice, latency=0): cdef PmError err #cdef PtTimestamp (*PmPtr) () cdef PmTimeProcPtr PmPtr self.i = OutputDevice self.debug = 0 self._aborted = 0 if latency == 0: PmPtr = NULL else: PmPtr = &Pt_Time if self.debug: print "Opening Midi Output" # Why is bufferSize 0 here? err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency) if err < 0: s = Pm_GetErrorText(err) # Something's amiss here - if we try to throw an Exception # here, we crash. if not err == -10000: raise Exception,s else: print "Unable to open Midi OutputDevice=",OutputDevice," err=",s def __dealloc__(self): if self.debug: print "Closing MIDI output stream and destroying instance" #err = Pm_Abort(self.midi) #if err < 0: raise Exception, Pm_GetErrorText(err) err = Pm_Close(self.midi) if err < 0: raise Exception, Pm_GetErrorText(err) def _check_open(self): """ checks to see if the midi is open, and if not, raises an error. """ if self.midi == NULL: raise Exception, "midi Output not open." if self._aborted: raise Exception, "midi Output aborted. Need to call Close after Abort." def Close(self): """ Close() closes a midi stream, flushing any pending buffers. (PortMidi attempts to close open streams when the application exits -- this is particularly difficult under Windows.) """ #if not self.midi: # return err = Pm_Close(self.midi) if err < 0: raise Exception, Pm_GetErrorText(err) #self.midi = NULL def Abort(self): """ Abort() terminates outgoing messages immediately The caller should immediately close the output port; this call may result in transmission of a partial midi message. There is no abort for Midi input because the user can simply ignore messages in the buffer and close an input device at any time. """ #if not self.midi: # return err = Pm_Abort(self.midi) if err < 0: raise Exception, Pm_GetErrorText(err) self._aborted = 1 def Write(self, data): """ Write(data) output a series of MIDI information in the form of a list: Write([[[status <,data1><,data2><,data3>],timestamp], [[status <,data1><,data2><,data3>],timestamp],...]) fields are optional example: choose program change 1 at time 20000 and send note 65 with velocity 100 500 ms later. Write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) notes: 1. timestamps will be ignored if latency = 0. 2. To get a note to play immediately, send MIDI info with timestamp read from function Time. 3. understanding optional data fields: Write([[[0xc0,0,0],20000]]) is equivalent to Write([[[0xc0],20000]]) """ cdef PmEvent buffer[1024] cdef PmError err cdef int i self._check_open() if len(data) > 1024: raise IndexError, 'maximum list length is 1024' else: for loop1 in range(len(data)): if ((len(data[loop1][0]) > 4) | (len(data[loop1][0]) < 1)): raise IndexError, str(len(data[loop1][0]))+' arguments in event list' buffer[loop1].message = 0 for i in range(len(data[loop1][0])): buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i)) buffer[loop1].timestamp = data[loop1][1] if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp if self.debug: print "writing to midi buffer" err= Pm_Write(self.midi, buffer, len(data)) if err < 0: raise Exception, Pm_GetErrorText(err) def WriteShort(self, status, data1 = 0, data2 = 0): """ WriteShort(status <, data1><, data2>) output MIDI information of 3 bytes or less. data fields are optional status byte could be: 0xc0 = program change 0x90 = note on etc. data bytes are optional and assumed 0 if omitted example: note 65 on with velocity 100 WriteShort(0x90,65,100) """ cdef PmEvent buffer[1] cdef PmError err self._check_open() buffer[0].timestamp = Pt_Time() buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF)) if self.debug: print "Writing to MIDI buffer" err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length if err < 0 : raise Exception, Pm_GetErrorText(err) def WriteSysEx(self, when, msg): """ WriteSysEx(,) writes a timestamped system-exclusive midi message. can be a *list* or a *string* example: (assuming y is an input MIDI stream) y.WriteSysEx(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7') is equivalent to y.WriteSysEx(pypm.Time, [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7]) """ cdef PmError err cdef char *cmsg cdef PtTimestamp CurTime self._check_open() if type(msg) is list: msg = array.array('B',msg).tostring() # Markus Pfaff contribution cmsg = msg CurTime = Pt_Time() err = Pm_WriteSysEx(self.midi, when, cmsg) if err < 0 : raise Exception, Pm_GetErrorText(err) while Pt_Time() == CurTime: # wait for SysEx to go thru or...my pass # win32 machine crashes w/ multiple SysEx cdef class Input: """ class Input: define an input MIDI stream. Takes the form: x = pypm.Input(MidiInputDevice) """ cdef PmStream *midi cdef int debug cdef int i def __init__(self, InputDevice, buffersize=4096): cdef PmError err self.i = InputDevice self.debug = 0 err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL) if err < 0: raise Exception, Pm_GetErrorText(err) if self.debug: print "MIDI input opened." def __dealloc__(self): cdef PmError err if self.debug: print "Closing MIDI input stream and destroying instance" err = Pm_Close(self.midi) if err < 0: raise Exception, Pm_GetErrorText(err) def _check_open(self): """ checks to see if the midi is open, and if not, raises an error. """ if self.midi == NULL: raise Exception, "midi Input not open." def Close(self): """ Close() closes a midi stream, flushing any pending buffers. (PortMidi attempts to close open streams when the application exits -- this is particularly difficult under Windows.) """ #if not self.midi: # return err = Pm_Close(self.midi) if err < 0: raise Exception, Pm_GetErrorText(err) #self.midi = NULL def SetFilter(self, filters): """ SetFilter() sets filters on an open input stream to drop selected input types. By default, only active sensing messages are filtered. To prohibit, say, active sensing and sysex messages, call SetFilter(stream, FILT_ACTIVE | FILT_SYSEX); Filtering is useful when midi routing or midi thru functionality is being provided by the user application. For example, you may want to exclude timing messages (clock, MTC, start/stop/continue), while allowing note-related messages to pass. Or you may be using a sequencer or drum-machine for MIDI clock information but want to exclude any notes it may play. Note: SetFilter empties the buffer after setting the filter, just in case anything got through. """ cdef PmEvent buffer[1] cdef PmError err self._check_open() err = Pm_SetFilter(self.midi, filters) if err < 0: raise Exception, Pm_GetErrorText(err) while(Pm_Poll(self.midi) != pmNoError): err = Pm_Read(self.midi,buffer,1) if err < 0: raise Exception, Pm_GetErrorText(err) def SetChannelMask(self, mask): """ SetChannelMask() filters incoming messages based on channel. The mask is a 16-bit bitfield corresponding to appropriate channels Channel() can assist in calling this function. i.e. to set receive only input on channel 1, call with SetChannelMask(Channel(1)) Multiple channels should be OR'd together, like SetChannelMask(Channel(10) | Channel(11)) note: PyPortMidi Channel function has been altered from the original PortMidi c call to correct for what seems to be a bug --- i.e. channel filters were all numbered from 0 to 15 instead of 1 to 16. """ cdef PmError err self._check_open() err = Pm_SetChannelMask(self.midi,mask) if err < 0: raise Exception, Pm_GetErrorText(err) def Poll(self): """ Poll tests whether input is available, returning TRUE, FALSE, or an error value. """ cdef PmError err self._check_open() err = Pm_Poll(self.midi) if err < 0: raise Exception, Pm_GetErrorText(err) return err def Read(self,length): """ Read(length): returns up to midi events stored in the buffer and returns them as a list: [[[status,data1,data2,data3],timestamp], [[status,data1,data2,data3],timestamp],...] example: Read(50) returns all the events in the buffer, up to 50 events. """ cdef PmEvent buffer[1024] self._check_open() x = [] if length > 1024: raise IndexError, 'maximum buffer length is 1024' if length < 1: raise IndexError, 'minimum buffer length is 1' NumEvents = Pm_Read(self.midi,buffer,length) if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents) x=[] if NumEvents >= 1: for loop in range(NumEvents): x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp]) return x portmidi/pm_python/pyportmidi/midi.py0000644000000000000000000004573311447645574017151 0ustar rootroot""" Module for interacting with midi input and output. The midi module can send output to midi devices, and get input from midi devices. It can also list midi devices on the system. Including real midi devices, and virtual ones. It uses the portmidi library. Is portable to which ever platforms portmidi supports (currently windows, OSX, and linux). """ import atexit _init = False _pypm = None __all__ = [ "Input", "MidiException", "Output", "get_count", "get_default_input_id", "get_default_output_id", "get_device_info", "init", "quit", "time", ] __theclasses__ = ["Input", "Output"] def init(): """initialize the midi module pyportmidi.init(): return None Call the initialisation function before using the midi module. It is safe to call this more than once. """ global _init, _pypm if not _init: import pyportmidi._pyportmidi _pypm = pyportmidi._pyportmidi _pypm.Initialize() _init = True atexit.register(quit) def quit(): """uninitialize the midi module pyportmidi.quit(): return None Called automatically atexit if you don't call it. It is safe to call this function more than once. """ global _init, _pypm if _init: # TODO: find all Input and Output classes and close them first? _pypm.Terminate() _init = False del _pypm def _check_init(): if not _init: raise RuntimeError("pyportmidi not initialised.") def get_count(): """gets the number of devices. pyportmidi.get_count(): return num_devices Device ids range from 0 to get_count() -1 """ _check_init() return _pypm.CountDevices() def get_default_input_id(): """gets default input device number pyportmidi.get_default_input_id(): return default_id Return the default device ID or -1 if there are no devices. The result can be passed to the Input()/Ouput() class. On the PC, the user can specify a default device by setting an environment variable. For example, to use device #1. set PM_RECOMMENDED_INPUT_DEVICE=1 The user should first determine the available device ID by using the supplied application "testin" or "testout". In general, the registry is a better place for this kind of info, and with USB devices that can come and go, using integers is not very reliable for device identification. Under Windows, if PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is *NOT* found in the environment, then the default device is obtained by looking for a string in the registry under: HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device for a string. The number of the first device with a substring that matches the string exactly is returned. For example, if the string in the registry is "USB", and device 1 is named "In USB MidiSport 1x1", then that will be the default input because it contains the string "USB". In addition to the name, get_device_info() returns "interf", which is the interface name. (The "interface" is the underlying software system or API used by PortMidi to access devices. Examples are MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.) At present, the only Win32 interface is "MMSystem", the only Linux interface is "ALSA", and the only Max OS X interface is "CoreMIDI". To specify both the interface and the device name in the registry, separate the two with a comma and a space, e.g.: MMSystem, In USB MidiSport 1x1 In this case, the string before the comma must be a substring of the "interf" string, and the string after the space must be a substring of the "name" name string in order to match the device. Note: in the current release, the default is simply the first device (the input or output device with the lowest PmDeviceID). """ return _pypm.GetDefaultInputDeviceID() def get_default_output_id(): """gets default output device number pyportmidi.get_default_output_id(): return default_id Return the default device ID or -1 if there are no devices. The result can be passed to the Input()/Ouput() class. On the PC, the user can specify a default device by setting an environment variable. For example, to use device #1. set PM_RECOMMENDED_OUTPUT_DEVICE=1 The user should first determine the available device ID by using the supplied application "testin" or "testout". In general, the registry is a better place for this kind of info, and with USB devices that can come and go, using integers is not very reliable for device identification. Under Windows, if PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is *NOT* found in the environment, then the default device is obtained by looking for a string in the registry under: HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device for a string. The number of the first device with a substring that matches the string exactly is returned. For example, if the string in the registry is "USB", and device 1 is named "In USB MidiSport 1x1", then that will be the default input because it contains the string "USB". In addition to the name, get_device_info() returns "interf", which is the interface name. (The "interface" is the underlying software system or API used by PortMidi to access devices. Examples are MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.) At present, the only Win32 interface is "MMSystem", the only Linux interface is "ALSA", and the only Max OS X interface is "CoreMIDI". To specify both the interface and the device name in the registry, separate the two with a comma and a space, e.g.: MMSystem, In USB MidiSport 1x1 In this case, the string before the comma must be a substring of the "interf" string, and the string after the space must be a substring of the "name" name string in order to match the device. Note: in the current release, the default is simply the first device (the input or output device with the lowest PmDeviceID). """ _check_init() return _pypm.GetDefaultOutputDeviceID() def get_device_info(an_id): """ returns information about a midi device pyportmidi.get_device_info(an_id): return (interf, name, input, output, opened) interf - a text string describing the device interface, eg 'ALSA'. name - a text string for the name of the device, eg 'Midi Through Port-0' input - 0, or 1 if the device is an input device. output - 0, or 1 if the device is an output device. opened - 0, or 1 if the device is opened. If the id is out of range, the function returns None. """ _check_init() return _pypm.GetDeviceInfo(an_id) class Input(object): """Input is used to get midi input from midi devices. Input(device_id) Input(device_id, buffer_size) buffer_size -the number of input events to be buffered waiting to be read using Input.read() """ def __init__(self, device_id, buffer_size=4096): """ The buffer_size specifies the number of input events to be buffered waiting to be read using Input.read(). """ _check_init() if device_id == -1: raise MidiException("Device id is -1, not a valid output id. -1 usually means there were no default Output devices.") try: r = get_device_info(device_id) except TypeError: raise TypeError("an integer is required") except OverflowError: raise OverflowError("long int too large to convert to int") # and now some nasty looking error checking, to provide nice error # messages to the kind, lovely, midi using people of whereever. if r: interf, name, input, output, opened = r if input: try: self._input = _pypm.Input(device_id, buffer_size) except TypeError: raise TypeError("an integer is required") self.device_id = device_id elif output: raise MidiException("Device id given is not a valid input id, it is an output id.") else: raise MidiException("Device id given is not a valid input id.") else: raise MidiException("Device id invalid, out of range.") def _check_open(self): if self._input is None: raise MidiException("midi not open.") def close(self): """ closes a midi stream, flushing any pending buffers. Input.close(): return None PortMidi attempts to close open streams when the application exits -- this is particularly difficult under Windows. """ _check_init() if not (self._input is None): self._input.Close() self._input = None def read(self, num_events): """reads num_events midi events from the buffer. Input.read(num_events): return midi_event_list Reads from the Input buffer and gives back midi events. [[[status,data1,data2,data3],timestamp], [[status,data1,data2,data3],timestamp],...] """ _check_init() self._check_open() return self._input.Read(num_events) def poll(self): """returns true if there's data, or false if not. Input.poll(): return Bool raises a MidiException on error. """ _check_init() self._check_open() r = self._input.Poll() if r == _pypm.TRUE: return True elif r == _pypm.FALSE: return False else: err_text = GetErrorText(r) raise MidiException( (r, err_text) ) class Output(object): """Output is used to send midi to an output device Output(device_id) Output(device_id, latency = 0) Output(device_id, buffer_size = 4096) Output(device_id, latency, buffer_size) The buffer_size specifies the number of output events to be buffered waiting for output. (In some cases -- see below -- PortMidi does not buffer output at all and merely passes data to a lower-level API, in which case buffersize is ignored.) latency is the delay in milliseconds applied to timestamps to determine when the output should actually occur. (If latency is < 0, 0 is assumed.) If latency is zero, timestamps are ignored and all output is delivered immediately. If latency is greater than zero, output is delayed until the message timestamp plus the latency. (NOTE: time is measured relative to the time source indicated by time_proc. Timestamps are absolute, not relative delays or offsets.) In some cases, PortMidi can obtain better timing than your application by passing timestamps along to the device driver or hardware. Latency may also help you to synchronize midi data to audio data by matching midi latency to the audio buffer latency. """ def __init__(self, device_id, latency = 0, buffer_size = 4096): """Output(device_id) Output(device_id, latency = 0) Output(device_id, buffer_size = 4096) Output(device_id, latency, buffer_size) The buffer_size specifies the number of output events to be buffered waiting for output. (In some cases -- see below -- PortMidi does not buffer output at all and merely passes data to a lower-level API, in which case buffersize is ignored.) latency is the delay in milliseconds applied to timestamps to determine when the output should actually occur. (If latency is < 0, 0 is assumed.) If latency is zero, timestamps are ignored and all output is delivered immediately. If latency is greater than zero, output is delayed until the message timestamp plus the latency. (NOTE: time is measured relative to the time source indicated by time_proc. Timestamps are absolute, not relative delays or offsets.) In some cases, PortMidi can obtain better timing than your application by passing timestamps along to the device driver or hardware. Latency may also help you to synchronize midi data to audio data by matching midi latency to the audio buffer latency. """ _check_init() self._aborted = 0 if device_id == -1: raise MidiException("Device id is -1, not a valid output id. -1 usually means there were no default Output devices.") try: r = get_device_info(device_id) except TypeError: raise TypeError("an integer is required") except OverflowError: raise OverflowError("long int too large to convert to int") # and now some nasty looking error checking, to provide nice error # messages to the kind, lovely, midi using people of whereever. if r: interf, name, input, output, opened = r if output: try: self._output = _pypm.Output(device_id, latency) except TypeError: raise TypeError("an integer is required") self.device_id = device_id elif input: raise MidiException("Device id given is not a valid output id, it is an input id.") else: raise MidiException("Device id given is not a valid output id.") else: raise MidiException("Device id invalid, out of range.") def _check_open(self): if self._output is None: raise MidiException("midi not open.") if self._aborted: raise MidiException("midi aborted.") def close(self): """ closes a midi stream, flushing any pending buffers. Output.close(): return None PortMidi attempts to close open streams when the application exits -- this is particularly difficult under Windows. """ _check_init() if not (self._output is None): self._output.Close() self._output = None def abort(self): """terminates outgoing messages immediately Output.abort(): return None The caller should immediately close the output port; this call may result in transmission of a partial midi message. There is no abort for Midi input because the user can simply ignore messages in the buffer and close an input device at any time. """ _check_init() if self._output: self._output.Abort() self._aborted = 1 def write(self, data): """writes a list of midi data to the Output Output.write(data) writes series of MIDI information in the form of a list: write([[[status <,data1><,data2><,data3>],timestamp], [[status <,data1><,data2><,data3>],timestamp],...]) fields are optional example: choose program change 1 at time 20000 and send note 65 with velocity 100 500 ms later. write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) notes: 1. timestamps will be ignored if latency = 0. 2. To get a note to play immediately, send MIDI info with timestamp read from function Time. 3. understanding optional data fields: write([[[0xc0,0,0],20000]]) is equivalent to write([[[0xc0],20000]]) Can send up to 1024 elements in your data list, otherwise an IndexError exception is raised. """ _check_init() self._check_open() self._output.Write(data) def write_short(self, status, data1 = 0, data2 = 0): """write_short(status <, data1><, data2>) Output.write_short(status) Output.write_short(status, data1 = 0, data2 = 0) output MIDI information of 3 bytes or less. data fields are optional status byte could be: 0xc0 = program change 0x90 = note on etc. data bytes are optional and assumed 0 if omitted example: note 65 on with velocity 100 write_short(0x90,65,100) """ _check_init() self._check_open() self._output.WriteShort(status, data1, data2) def write_sys_ex(self, when, msg): """writes a timestamped system-exclusive midi message. Output.write_sys_ex(when, msg) msg - can be a *list* or a *string* when - a timestamp in miliseconds example: (assuming o is an onput MIDI stream) o.write_sys_ex(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7') is equivalent to o.write_sys_ex(pyportmidi.time(), [0xF0,0x7D,0x10,0x11,0x12,0x13,0xF7]) """ _check_init() self._check_open() self._output.WriteSysEx(when, msg) def note_on(self, note, velocity=None, channel = 0): """turns a midi note on. Note must be off. Output.note_on(note, velocity=None, channel = 0) Turn a note on in the output stream. The note must already be off for this to work correctly. """ if velocity is None: velocity = 0 if not (0 <= channel <= 15): raise ValueError("Channel not between 0 and 15.") self.write_short(0x90+channel, note, velocity) def note_off(self, note, velocity=None, channel = 0): """turns a midi note off. Note must be on. Output.note_off(note, velocity=None, channel = 0) Turn a note off in the output stream. The note must already be on for this to work correctly. """ if velocity is None: velocity = 0 if not (0 <= channel <= 15): raise ValueError("Channel not between 0 and 15.") self.write_short(0x80 + channel, note, velocity) def set_instrument(self, instrument_id, channel = 0): """select an instrument, with a value between 0 and 127 Output.set_instrument(instrument_id, channel = 0) """ if not (0 <= instrument_id <= 127): raise ValueError("Undefined instrument id: %d" % instrument_id) if not (0 <= channel <= 15): raise ValueError("Channel not between 0 and 15.") self.write_short(0xc0+channel, instrument_id) def time(): """returns the current time in ms of the PortMidi timer pyportmidi.time(): return time The time is reset to 0, when the module is inited. """ return _pypm.Time() class MidiException(Exception): """MidiException(errno) that can be raised. """ def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) portmidi/pm_python/pyportmidi/tests/0000755000000000000000000000000011453601074016763 5ustar rootrootportmidi/pm_python/setup.py0000644000000000000000000001263411447645574015161 0ustar rootrootimport sys import os import logging from distutils.core import setup, Command from distutils.extension import Extension try: from Cython.Distutils import build_ext except ImportError: logging.warn("Cython is preferred over pyrex for python3 compatibility.") from Pyrex.Distutils import build_ext DESCRIPTION = open('README_PYTHON.txt').read() CHANGES = open('CHANGES.txt').read() TODO = open('TODO.txt').read() EXTRAS = {} long_description = DESCRIPTION + CHANGES + TODO #import sys #if "checkdocs" in sys.argv: # print long_description METADATA = { 'name': 'pyportmidi', 'version': '0.0.7', 'license': 'MIT License', 'url': 'http://pypi.python.org/pyportmidi/', 'author': 'John Harrison, Roger B. Dannenberg, Rene Dudfield, others...', 'author_email': 'renesd@gmail.com', 'maintainer': 'Rene Dudfield', 'maintainer_email': 'renesd@gmail.com', 'description': 'Python Wrappings for PortMidi #python. CHANGES: new package layout.', 'long_description': long_description, 'classifiers': [ 'Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'License :: OSI Approved :: BSD License', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Programming Language :: Cython', 'Programming Language :: C', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Topic :: Multimedia :: Sound/Audio :: MIDI', 'Topic :: Software Development :: Libraries', ], } if "bdist_msi" in sys.argv: # hack the version name to a format msi doesn't have trouble with METADATA["version"] = METADATA["version"].replace("pre", "a0") METADATA["version"] = METADATA["version"].replace("rc", "b0") METADATA["version"] = METADATA["version"].replace("release", "") # allow optionally using setuptools for bdist_egg. using_setuptools = False if "-setuptools" in sys.argv: using_setuptools = True from setuptools import setup, Command sys.argv.remove ("-setuptools") EXTRAS.update({'include_package_data': True, 'install_requires': [], 'zip_safe': False, 'test_suite' : 'pyportmidi.tests', } ) # test command. For doing 'python setup.py test' class TestCommand(Command): user_options = [ ] def initialize_options(self): self._dir = os.getcwd() def finalize_options(self): pass def run(self): ''' runs the tests with default options. ''' import pyportmidi.tests pyportmidi.tests.main() #import subprocess #return subprocess.call([sys.executable, "run_tests.py"]) cmdclass = {'build_ext': build_ext} # we use our test command. if not using_setuptools: import os cmdclass['test'] = TestCommand scripts = [] PACKAGEDATA = { 'cmdclass': cmdclass, 'package_dir': {'pyportmidi': 'pyportmidi', #'pyportmidi.tests': 'test', #'pyportmidi.docs': 'docs', #'pyportmidi.examples': 'examples', }, 'packages': ['pyportmidi', 'pyportmidi.tests', ], 'scripts': scripts, } PACKAGEDATA.update(METADATA) PACKAGEDATA.update(EXTRAS) if sys.platform == 'win32': print "Found Win32 platform" EXTENSION = dict( ext_modules=[ Extension("pyportmidi._pyportmidi", [os.path.join("pyportmidi", "_pyportmidi.pyx")], library_dirs = ["../Release"], libraries = ["portmidi", "winmm"], include_dirs = ["../porttime"], # define_macros = [("_WIN32_", None)]) # needed by portmidi.h extra_compile_args = ["/DWIN32"]) # needed by portmidi.h ] ) elif sys.platform == 'darwin': print "Found darwin (OS X) platform" library_dirs = ["/usr/local/lib"] include_dirs = ["/usr/local/include"] EXTENSION = dict( ext_modules=[ Extension("pyportmidi._pyportmidi", [os.path.join("pyportmidi", "_pyportmidi.pyx")], library_dirs = library_dirs, include_dirs = include_dirs, libraries = ["portmidi"], extra_link_args=["-framework", "CoreFoundation", "-framework", "CoreMIDI", "-framework", "CoreAudio"]) ] ) else: print "Assuming Linux platform" EXTENSION = dict( ext_modules=[ Extension("pyportmidi._pyportmidi", [os.path.join("pyportmidi", "_pyportmidi.pyx")], library_dirs=["./linux"], libraries = ["portmidi", "asound", "pthread"] ) ] ) PACKAGEDATA.update(EXTENSION) setup(**PACKAGEDATA) portmidi/pm_python/README_PYTHON.txt0000644000000000000000000000242011447645574016236 0ustar rootrootPyPortMidi v0.03 03/15/05 Python wrappings for PortMidi John Harrison harrison@media.mit.edu Modified by Roger B. Dannenberg, Nov 2009 PyPortMidi ---------- PyPortMidi is a Python wrapper for PortMidi. PortMidi is a cross-platform C library for realtime MIDI control. Using PyPortMidi, you can send and receive MIDI data in realtime from Python. Besides using PyPortMidi to communicate to synthesizers and the like, it is possible to use PyPortMidi as a way to send MIDI messages between software packages on the same computer. For example, Using PyPortMidi and MIDI-YOKE on a Windows machine, it is possible to send realtime MIDI messages between programs on the same computer using loopback virtual MIDI ports. (At this time, MIDI-YOKE does not appear to run on Windows Vista.) PyPortMidi is cross-platform, but it will require some small changes in the setup.py file for it to install correctly on Linux machines. The changes should be pretty straightforward, and I am anxious to work with a Linux user on the port. PyPortMidi works with Python 2.6 and Python 3.1, although the ports are mostly separate because of various language incompatibilities. Please see README26.txt for information about the Python 2.6 version. See README31.txt for information about the Python 3.1 version. portmidi/CMakeLists.txt0000644000000000000000000000573011445664134014160 0ustar rootroot# portmidi # Roger B. Dannenberg # 20 Sep 2009 cmake_minimum_required(VERSION 2.6) if(UNIX) # allow user to set Release or Debug set(CMAKE_BUILD_TYPE Release CACHE STRING "Semicolon-separate list of supported configuration types") # set default directories but don't override cached values... set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE} CACHE STRING "libraries go here") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE} CACHE STRING "libraries go here") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE} CACHE STRING "executables go here") else(UNIX) # this does not seem to work for xcode: set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Semicolon-separate list of supported configuration types") endif(UNIX) #set(CMAKE_RELATIVE_PATHS ON CACHE STRING "avoid absolute paths" FORCE) # Clear out the built-in C++ compiler and link flags for each of the # unused configurations. set(CMAKE_CXX_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused") set(CMAKE_OSX_ARCHITECTURES i386 ppc x86_64 CACHE STRING "change to needed architecture for a smaller library" FORCE) PROJECT(portmidi) if(UNIX) # Problem: if there was an old Debug build and you change # CMAKE_BUILD_TYPE to Release, then the OUTPUT_DIRECTORY's will # still be Debug. Try to fix this by checking if the DIRECTORY's # look wrong, and if so, force them to the defaults: if(CMAKE_BUILD_TYPE MATCHES "Debug") set(BAD_DIR "Release") else(CMAKE_BUILD_TYPE MATCHES "Debug") set(BAD_DIR "Debug") endif(CMAKE_BUILD_TYPE MATCHES "Debug") # use library as reference -- if you give it a non-BAD_DIR location # then every other path is left alone if(CMAKE_LIBRARY_OUTPUT_DIRECTORY MATCHES ${BAD_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE} CACHE STRING "executables go here" FORCE) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE} CACHE STRING "libraries go here" FORCE) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE} CACHE STRING "libraries go here" FORCE) endif(CMAKE_LIBRARY_OUTPUT_DIRECTORY MATCHES ${BAD_DIR}) endif(UNIX) include_directories(pm_common porttime) add_subdirectory(pm_common) add_subdirectory(pm_test) add_subdirectory(pm_dylib) # Cannot figure out how to make an xcode Java application with CMake add_subdirectory(pm_java) portmidi/portmidi_cdt.zip0000644000000000000000000063253711257441130014626 0ustar rootrootPK h^9 portmidi/PK]9퐯40portmidi/.cproject]moܸ^A9kww}We'EaEoNk{^V%e,o!D<zđt"LW Y‰a2%xӁ#KE% ~%'_~ #Փ )\~b$2ͽ9~K1s|`? +~P*~ce Z 4 +*rFŠ(dPRJ/sE5k*BV>-JbYUs+iބp[2/?&h{W%6\2"o^?}8}_eS0E^y]+LӼ|<n5-`'N+!M uD4L-_ ` ПNKLnzhְJq88 /+Q03 p[USR`;nka/9J#1J\yC岖=ڤEM~z\(s"z%SeFG^e }r{4TqZǛ0y& p(BP,s\N#Jx36VJȪ 4 MGc6M ַ/~柊E^_MU"+u nT[s Iriø:M0ZxEJ,r/p Gӄ- kIm-X;q|5q8rj0CVZ#ӀJ&:Hk+BkE5\-Si@} *P20 Dzڨ>e%z_;2a&pQXoi0êB?{oY|M qI'5U3[/Pu0tPUñ-k=?#Y9*rUE؎^Hy~wAbE8GDGLқR!Z|]D^ Wvdcq O~íiiN'G ;Z-0V昆vgdKQ@|ʏK̭AVT]u4⚄F"6Ru\[E&Qxmm\VEaiLs0iQ(/K;R)IKJ͊ ̱ trZW,hBj@n(*Ĭ*2 IM)M[y"L&/ӨP\p 3)Wa*-i ?za_$lX\]۫?_iqiH|qtNXݜ@- M,%hId(a04Wk,iֺW Ck"Eㇴ"Y&b#$ qBޗ„l s%(2U~^ 0\MfX&E-ͦ5?If\+%2xI0t<5+cuȷn]!aW0 MԽBe%J?T5XZptDm&eXJ^-.|ċm[sⰋe@>xʔF,0!TKmb&{'1h^W_yYͪkt,s%*@o.S;A3e>#C`YHAx# z[]#kt)܋UHq~#Hxүw(= O $/j3HVW"J(u+Pk[5_R1LJe\R] DSpE Ř-hUfU*CVcY]!6`:|Z.j l[HmRϖF;!UHxwyN40f]^ )m8RgDAJakf(i9CJ1tA~v#Gɜ[5*R S#b.kgP%u%9Z_*9<(R"_Y]vk$Ҋ;`^l3+טN8:aED$ȴtc)K:iRe< ݈IfUþ؊8`6{>>>._3 v#Bh xE, w˰t֧ Sr:7^%aظK[P'.޾[RuI!_m !AJhؗe lw@#xkv9DGWv$)ٞ_`_%{,Oӿ%.JPmMQKP6-\W/ßkŗy{RUC0;GX^%(ҧJk>N}B\얪lE6e6 ˴%EX99CD:J7Ap,-xALM u7*@ gcsߗIqf4úc؁&ҫ4(Wlh]%Tw}%)~}c78)rRh:[PAd_˗.nΕY~yfte5;14!^I򾌓CDN!!)s=Zᚮg[7l!2\zK.Wk+/^9w9fx l31m}†ñe߭2й2fc1+Ϙ-Aэ|DXD%e!I>kF[Mk6#yym5#}ZqH kpĶ{#2hXl+c[WE5gxl+=lчV} 0{gZ70Ѷi%2b'I=%QIma#V A@6 ?  Ѣg75wkaN) |!-WPP!!!?x*`b-VA[g*EI0kh\'Rуڻ~ 2WEbc&[-S7*tǤ@\obe#.ܛ%L jB,Ip1LL5w3Emsh<-E&fZrHab,[ 6bZ5@ulmp̴MP ! j i +nVCU\zrM!P!QӪNh&! ֐iBpm韄l (Q6/h{Zk뙘iZṙݙrNV_!)G,e<{R6ĕa7++GK_1a7987gFѵV<=cqp)[0~'Dl"R֠lx''R ]0ۓ)Weò ^<;eH &r~/' D ź 96l<c1աՁp SAcAP+eO$ȅ8A d<#O}d-2 : :) 3?5PU:WWAf㫠CueUG1$4N{c { lS1m}†㮁e߭2й2c1+)ϘvI4g,̲uRf j}@ʘY׏rl6f>c* foHAfB5-{~ J*2HMJ|PK]9p7portmidi/.projectUMo0 =oCZmmd;ZdʠlŰ>Q u5km>|ْ(?jj]PО~9?~3N^< oZM9;$&8)8,u 'RtOM?Y49Y.Uh Qh*mb+ U:TV+谍G$gm6;CMKgtlw%f8]1R\X _0r)r޶f|;TfY,ĘGPz%Z7z!/~jVZ)0J>EP!aP]z`>K0ne^*Z5 \; ;}OyOv?m '|GэܳOꉬC9^RvQ hs -azRJvc:{@xykJPK ^9portmidi/Debug/PK]9w portmidi/Debug/libPortMidi.dll \TPQȰF;"r14P"ʨ(7aFH9gDee'.vuRdNJRS"&9~fA}߳}?̌YoEQ|9_d_>K~ Y+t%Ks uKsͺ%&]H_K6SWXg ݻgGQQ2Pb{*Bf{yib 0S3Ubp@qɋL .KGU+ʬh(W(>E[ 7x g!k1 57*S5mU^* a%lS%/)+Cx6]]1>ƧQ58_p._>کu[[p uO-k^2s' NڕK @aB=PN_m_8g^ouxl} DPB=׶ h2ol?Q[sA_AZempjwe'G&<\65+JG6TC#CQ*3zˤɾ~Ӣ&4t h{0;M%[OpQ-2YF:8D"M v[_((cSPbDms(U;g|ۍYP>6Ц嘵#".ׄ=Ba 폰[|cPߦk쳵j@[(f:c珧f+$ IaCoO2 yZᯘCUUkKo}_E >^2Z+E'%_ɷA-= aoNU_XIw%`_q E b-OȮtc6c}v\U/ ڼEEaЬ6VmVkEb:KIX I2IG"%Zkެ|s%sEE}v+Ek\LqZѦb%rQ LW) T/vjI,&Cn;Pt jwRvJm& iAivF\X`o;!R}ERڀ-jMEP{[+*c!,RCS|>ZE!ԫh:"hCbC+ͥ3wZA& GoZ8Tʹډƶ Ɂ(-pbv}O%anm^/Xtk`Jnl&o5`,O4&hkTZ 1bǘOvrŲ`tÕ<|<ީ]6%#d+7Su=Tڴ JVlT߀)so!F@LMb"TmU>1}z9R9[vS;!b;W͓,3.S8L5(A.[F_:| bbPH*nZѠƆCiP@gOCiIqSj3TjK_+.?$H"_(E. qI.m\wE.w'HqƷ84u+x'9gkd(^Q-[_hm >,'I*`"v'iIcוAO`jn y@WJ:zorvM֊&u7iX,_sx4ް8'kbtaȞ먷)P+Pel}c-Hi4)6etVd_ 0WLZqF a~?#oc#q9m}xf-!Q:`kȁkiS 9~s8jZ`߸7nlї <=ayň8IFֆ>{Eqmd}*[#9a4* v]1 z9yX|]L}ZgbO}Ժ'u&r*Ł[|pz+4Z+[a[LX gʹSg66[e'v礴%'v}R_2nY;ey= Z[Z0Wq{5j)VdulXrl2;VNfeڇa-7a4cx,{:dޞ&g\Q;>Ti8jGa4m6tƃvU;1E[g]k-븵8ǵ"`zkFefk`PK$*GE3 G -1]kZfٍVoO Z/ϓc.8JK+_uǔ!˔?3YVww.ﮓ=s:*WNVPsڢtpc܁X5v]O=ihyp`\tY3ԑ ,JpΏU{k0vl tdW#N]ʇ>\WCDVAKDlIȠ:ܴgp)7[&C{|l =vwW>Fr|hZnvVd4֋`hHQ;u+[sYRP:X;36@T;֕k+U[eYi|Vڴrf+nYDYELzcĊΈ:ZFpOO4!Y'PղCzT=L"-5DmOK_ȚګvizgFq¹U.m.ur_xcQۨ|v][DcG={V'q7b-E>9G@us1-Iriwo uDusklX,9 Nƻ:4Fip~k/e|sk,ND0?KZ "4rLm;>Al^l*p{Bہ$aTA8nAIZ@1Ŕ|xb5b(9iVU6( 6R/`?pe ;Y5x֫p:A2=-1 n:\^^Ij9j'nbt)p!2՝8v>|`YhBBH"xf_S>b9t R+"Tg"Uo #[NV oỚ< H=2m&AM碚?R::rv=֧ϕ JZ0w3p.`{SWhNJצKJ)BJW!btiXv '58*CԾ Cln3a'ѳO<;{$/٥>ѕ/IvLc抎v#`+pIl#y y0<?4) Sac yT&pS*y״̇|0 `$m { o!h@Sp5A @5mFM=e4q<oMdž`3^ϣCqX;:2U^owK4Ut;xw> {< 95;w=TNsiؚdiѯ^mD_;DntfT:]1(^ur#qWӺ:\4o@=m{Ϯb?] yckZCR/ hD>;'k?=nRMiJhC|y,"0߼dx5>r GX֜lxpaiQ<'<[wևY!V0{%Ymmz?u-m إ ugs5/Gq 덇㽜9E $e(f uLz؇={,&xUZ8K&dоo{*Ռ/|T7YtaiZB۸ڞ V'B[AmEV*`0ZܥVi8|E 5b t=RlPu(貵E³1K%{a:c?t8ħ$Wnթ>AuQltHPT:JUsu+v6pT:[lu&?:߿Lrm];? S}ğܱ) vr{I9fy=tuyWAN=X# *PW^ǁGnfww5s-GBCeޮPퟲ OG%OLO tXa5ZMqO# uux_Rʃݎm[SZC>UCg!¡#mG(FQGoz:ˀK>y \a':h#ȇ=y{)am/UVt4#5TTeS.T*/BKF ^^_G7-Zx0uGOue=X҈~>q4q>p0{6fm/6U|fImʯEХkWd`D-iKZ"5f \RlkaGq.Ξfypՙ/KP(L( Ko>V|S ڡ_kՐ7 ~XܴE%G>ͳYV'#wQ,'Qz]na=0/zuBP^፬R;a$e]*'AnNY֋N[h~O<7q}_<>ԄƇ-/"ͽԏw$<ju\C:K vi .??iGmtPj SڨQ}W>CKXbn5p!M"JPz4]&00}&ɏ M4`&FS;,b_@y̎)C|sGt><Gj~r;^ *n4,Bؗu{:j^$ԃ֚8;'OHZ<>:pIilD=}оMt=R:@ %Jޓw8z(Ɂ}f=@ (zk x-<ⲯނ >/m?~-sf킪{#>SYTʠ~ңeױ)}67;goa;M<^è3C1V(`d.~r Ls :~ $1Od}{1G;RUSUYvwθl5'q[c|D{z4O uPkkΐi/|tޏ4{}M+ x[2X POPOT>и5(Nqi f:N[şKQI]v|$rH`<~_ y :BZHM&tuizlia3p4ƾv4~EOʶ3 uR*W$ai3frFj mRkhmU TOXOKjGЧ6ǀ] W.rGl٫|lw=lM`6W-7]UYiP '>7A|jvBWLpr=Gk$'M Hɉ~7G_/WN }=rpz߯W n8mkmdJv9IQ/ɚp;?z~C)?I2\, p m {'vEn8=Dpf[.jpmp{ {. 7\,LpVpw{3j w\np34xhO? ~G EX__ TUJr2PF Q)*V(CPe2\TF)1J2V W)z%BTe*8e$(JR9l(م9)K@@HyRdNM-& ]2z,˵'XT`r-ZV 4̂_rU0ke. `Yf4e)NE!cJMf˛n>-^ K7BfL3>dN[ +lL/QLS>΂=HM|3W@Kߺ2cmΙY`2sLy,X)KsKʔιӈlpD1t&ls LӖk(GA_yxQ1}b@/5ҒEYRM,+)2$ MJPL2*xi:䛑LfW0A Ta0ryiTX|Ļ4IJ}WSTmZH?R7 (Lǥ =NS~^xe:uBLsӝZfq~SS 6(؍NG"˜`L3 64g=5X.dl8࡞ E\/-.H}"PTˋjT<96v'iƢL+oF~ȯ"[#{E]5#0,/ToQ~aaaaᯆ'  ѷG?TtPLHL\$7_4*ދ(nĐw7w{% KK;aG‰ މSO\LNx /֯FH塚Ĩ~`\݆3 G$LY<sWL+bqŕo6x?H}YƄք_|&'%%>B='&YOڗt$铤OV0WÛ>H?JQJQ~%!IYz"&FdGQiy[duG>RoG~}_6ꚨPvEu6%|m!od67TNGGF?^h,1 1i\Kܒ 5 u NTD{IIg.##WoFh3^QiQKD5G Ж#c|x6\&_ҐȤԤIKJ$ݕp I>J:t.IɆ5 īS3K-P _o;Q S#EQ'♈7#EEDGygCG~ 5z'F^8ꋨo~rD6D 7r aN NFGEψ^]%.G}6\&_̐ȘԘ7Jc@x8慘1Ŝ,}zVևuPH}z?#IOb<@-1b~a8x⃌ONJt_$ 6 =(Hr\43nf6"}{H6ⳤ +īM"-2i%-ƿK(m^܃UHw}IqhA@33n$"-Zd=_+~o } X? G~ 1>i l Iof-m_'}-c| bdMz;%OX~*VwL@n$Ƨ&H[˸5?"q@yWO0)⋤2|ܫ'$$I3H,9>YڼDL'}RW0f6CI_T^I4iquۙMf:rEH61_cidc$$S[&II}ͣēI٬@"Ƶo2t҇1NXYf|٤NA^BbۦHo@.$}> ́ȷOӤw~lS>q 㻦KogX'6Sr4y3<> yw2͖3#K~9ҟeMlgҧ1޸@_|U/d+WKyI&N 2ql=?d}iXG&_rx/@*t ͻvҿgR(mJ\M y(BxX Akl ?IFϕHW|Dz+RiSdF>Cz5fihA5HSߓ~еl'n'}7ͬrI_ris?1[H/c-Ҧj^|Hp[ލ饌vO˷K=_x=tpIIψ/~v:;Jӛ>d-g?֢;G;ͱ]ȑxߤMq Lxy"9xHڄ !}F|yGh~!GͪGi~!}'OegQW63=66E%7OH.~GIO}SϐngM六>qf񛤿gfgAϲ>I|NơI?'c>"^ȸz #q3l| ^6{_FC{;_f)od֎!%}뒧.m^{ސz4qtZI1^tEBwEw7:"9CeϳU;7##"~؛(q~?$v`bx3B܇ q駘~XKz[R'Kz7#~FܟOA([ A2} bz-U~u2} 08H#G!'>$9)9 -ߗTg6?bȈ{f ěHH?Oy$rߝd{SO}+LyMKˉ?a>A"L=OD=Doei8^C2"g 2ҿe_ҦDKMŸAd|l'};6;?=!xe9K_KN 3e|迡5$sۿa_$ql,%~nM؜B&;lGH/fH뾓67кJUsVw?=iCM6m6D'}c ?J!~sl ҏ3q`?M<K g~fk )72!yB;y&o3>_ٜEx&^Cg6˂o!}+g$h_{ SI> OE~o%~+ƽaM:ž :is.<$G0&7BٝDƵ?% G##>ZAccH`,ύC~􍌟`86m"Y/g|Disx? ^7Db6 ȇHx#&ȰD:ҧ2.K6! $Ɍd؅ȟ6Y)ߒ*y"y4 K.ˌ=e|~O`}+q WgH!mӻ7vпg&ŷőfGT8\Bgxc$5~!Oߐj gEK pߠ;?v9o?'Xgjœd3K+.sC2gk%2?3͉WxW.p2+[п^]Mm\>jL e).FB8?/.)֚+oG[nFw\wut\'λ\ p//%Ghn7ŝq3<qO◸;.gR8f8[\#q-ޥq%T[Yn{W÷p;۰K{.=m_/^]7/,n]Q̉x.Wp$*83qb∏̉?Y韋<32Ի8v?O̻^8QX1>MV|C&Ϸݾ!^->+C?3ߠ_(>%~]3ߣ'~"Ï{^̯'wcy͟wFq8wO'/-#)dQ}xN_b3Qͩ蟋G.] Oű\1y請.@Q9lg\~eN?G| 4mG?HcnJ_O9\X^xxJ?S*9}c`-9X&<֥1'~]5(^]3g-]7$x>;x,y'Nwafpu߿o |Ln~fАQfϸ/vżw.)qiqWL6F\Ňq޹A|͋c35iKDf38jNb9|_gx̬mOn1-}<?C..9~.N\[mq) ~]6E]ox"Zƻ vو?ĉʚ׎gq>.QLN_2 /Ľ"</{ܼ 7.G >h/>ބC+zg.gN8w%܌8wew z‰p*EpbN<'opR9']q <q@UO7pwnΎacHnMֆ iToAx/^ē2k8[){<2'΄].8i?c]U|4gކ}/pq'2?..s6m쒡1.+].8ic܌XM{]'ano+aC"6w܁o\qc>-~+NOW/gZ-gôΊ]ze>]ksF.83JJw6~~I?WO̟hk.B8I;%{{syo?E\G`{n;׊OZnʼn;z~[,.I`fFr?xGx o9.җb^JBKJx>Wx Nռ*x}?{7GfވMތ-nc_я$OЯ_.Ǿ6_ ;wo{z2?$!]"6?O/"]65Cx#9J_<8 ,š?p/I‘p~ȸ5@>;/.5wo_ƿ3,8;`7Ix}!/_4C͵ˊ.نWw.7o+#пmqnGes7إHsVfyy,Q q~>XBإxmzx☓=;}mq;mdv2u _~8tqp fx.gſcUq~2f92}mXnQq~9MqLoŻd\sfyp<\~x4v)}7i8xO܀8Bטּ!.[ܘ~n]lF '\"qfM?/ι?ֽ;2?g_ėeq{wd>r$j~y% v1%swy/p̴^e^J?ZK ^m^ET|YfOFgDke爏|u=? ~y?}!q;hrv88xgJLoOӏo_Gc*}޵ߤSlw-[{ů){Oŧe~6_ĉ{.v.O*]b6G o'n+[5{;臈׉w>{/Ώ]7r#n/]`?&n&].Ĺz74lMCŭ-|>a/v8G3_#x3n(/"7.NЏ?sIs,Iإ)sbY%is ūK3%ųKLYM#_8;}ޕ=pK]3۱K XnێIq8=:Oؐ S_t6w~%q?=^ў_`xh]b=^QWx6~+<sݾE=}x)sƨaCMq"W38~-NϴxmΌYIc΅7`opnq˷y|g.Kqڿ͕pIWw5{X8m|_[ؐ̏Hu}f|~Q^vaqO~>;38:^$>] &Qإgxx=v6y:͑Dž}#~G]|W#zq-@\5w{&s$>G#XQʨ.}. إ~ w}o !w < x1ݴ6|kfӧe~ㇸ!~{x-} ?O:%v8v~硫x:.3.S&2Í{ŕ$˧d6ɓ{W.R/Mg.]&WL43"9`.̻GWfr&9BX8MfsE\BWCĿ9f΅>(˦@5!l&AMҽټa)>$~,ɳ_R/œpwĩrzeKD|R'vɕלxr^?)<+qEpW_!>+~&5 k)"^]2ץ%/]H>1}ޥq[ч,](+-qcNq@F*fWx v)Qܓxr;;%saʥc;7a{.}y_`[OeGZ|xv9.LO跈_Ļķewy{iess̋oc2[NJWcQs.Oq*8Kb+8?,k`U?.k7.p};5cyxܒ~/mΡ7uI܍8E]إ~̧gJ_Y] 62//"^]b66LOF<+Ļkro/Ի:Gay8\3,إ)G?XF|A#57&n, 5ph ,{Q~K Kp;n 84‘ 3?O_|!$-ģˇ;8}yl~8tg+^,>vs^I%psaw6.嶛8?|.cq aw.+na^q`9P> ^&>]Z/^'gxN6.]%sn]U'xW7xދ7G8Dő&I'qӸ >_ _O=Żc诉M3_4Gt@|G(,slKdmģK'>.av}~/Kqm|m|Wc5gέ;a}lŢlݪquB Daws[o]f@oU_C`&* [qL<§qlq`G_iN;Dx%N$8*sR's뉓c8ڜ©p/iU'ZcNx΀On{5gpf<g;pVgEיa8>s͹p Oyi`}?~9[pM6]znw."?]qMnl.]mQ|c.]3xo鶋;*>/en>xv)n]| %h1!>]Z?'u.Y]Vopg95vyÄ1;(*} qJ<kKctqz\gK#śKwv崹*dvy'}a{E|_‘|35tѕ,Ž~=+v\ G<^0UАW2S#3q'|wQM'xqY7q?w>o汸o'yx(3K~7/»n9ℸxĹeN=,m9}ۭOl)Cܑc]saGn .#ݓׅ+2&rp]ZD q~]2?롹=fk&!%cso\~x4sQ<?>OVK`Cҏ<1?>?3k58s?o1^x..~.NDQuC{q:ߤќGߏI 碏5p>үŅOH0䳀5p)yG ʸ"}[\ /G}԰<>^qkq~LB3gec"'O2Q<lI+Wfaɼo) 4`GJ?/g2 q2&Nq~fhF8oX^8i&?+w/\ 52.f\%,EIfgކ18jv?G 9͝)-nϜ;y3YUK}LR{^f5T{#9Z{&>uS{~^/MfޔVY2˚?1SJL\O0Q!WќXɻbesnf:'bU<ǪgWS\/[܀~f MCjz.jy'm⮵VGYfCkdl̤W0 7\Yإfx+3ğd&O3y ~;]".3wpO}$J_;ܣ<)JO z'+6/s>(^_ƾmnۊ`p}qOOe`s].Ή\8snH?ve k-_߳gNI|Cf7ף$]z4wtxHo0wsQ~FFя1x(}1L<~Dz҇Έ]3ܶx8D ěh^Ns&{<'N6oq9sG_;>Sd4?Vm\C d 32SJ?/̼ǝg 1 k-1G>_e03/3Oz ;cӿx_nL.q-A<[pL5K2fLu޳fvޡI%.]l/+~-Qdn=^oɷqo[6f?9'5ILB~c&}昸x8.s'qBf9lj?Iq=dN'N{mWvJ*5qH\ /!\.x'vtmsqE)vWqKQ᨟y,.|7}+N|» vy~һ)R<:o3dfy98l8xqѻćde83_3zǾfLQq'(\ 23w93!xgcm73x.z'gbfV̛ Exz=_u]=2^]s?Lދq};23m/sb>d=pjKA<<—c.:v)}[| O}\Ep?Ow5L8[%Fxfq'49"}9qǠ;%vicӏN@(E6礯Q͕l?w`OGp!2?6< ?6~&l, Pܘg%=6]Vn;L8ŻwKǸŧq7I\0܋8_|so\;Y>xa x8N ɐ7č R5}+sOLܗ8~1ﶏxaBN<<~6^Wo+kGa'cߚwѯ.?G ׷W2f[O6z&hN0wV%ZC|?/}Ϣ }a?ps&4#kad#͹?g~] E׉o^ dctyeq~fOTel7tǙa>B_F3k`73[x6v)7xlcA< |ќ>|<\8"y/.6w/{%t?}6q !er)pzf1'+pS| /·}qU3ŧɝ… y\f!w嵈׉|5 uwš܍8~iy(} q kx!2`/9}nAZhw>Y~sHs{wݜCޙuJHB𰟏{vIzԜxv)s̜{R9{xq'ͥ ۈGbǧ̵食.,n-!}3ޕq;4ܔ~U~5jq{{?kBv{ܝ~9y/Λ{ї=O#^.K/lAxvż~"vysռ>5ua(73b7Wݾ-~]&9ŭ v.Ü;~ipz7DǙkgmѸމ;.;x*.2 ^w.7=b=WoҙC+ox-̾v_'>'~]=0#>*zhDX<~dMWB<#>#]܆~vi܉x*pWy +0vI܋1v9G}fsn,_{&o;bo{ݼ8;?S+N_ˍ0B,wAr砿'WcK`m23,BILK6WBxx8b48x=. "]"{7]pO,f(;}q5{tT L-_x}pϤӻML?'y}!qGN L8Ile+/Cx.s:=2S=y3}X26y{^qU2q8q|رR I|xxvٔ|}{`Gxx~xv9H/w~=96]kQ}.AMww7ҍ4H"!Htt#-pK# H# t s~ެ}9xsg֬Y׵gN2l47+ BP86U%8y'iTL䅕cSnfq {y,֥[(¦䷔d.NKTlZu?æ6_W~T!nIQy26'\ʍ?QMƝ)e]B 6=x0hT++æ~*gd- ^@^I 6x9y]<^!rGI [Q~G#)[+Ħo'~Qʕ;*U^|x/(/.6HrֹcSJOQ >Qx!Vʱ?S׎/+Gg7?Wq?/>B>VyIlmaSY ʵ"K=$B~A9?y /U?]򄃬KaSS[o6QnM%"~I^X(ldqYSM]i_YW~:3R~kuQlj6NKr8|cOq>`s\|Uĥ*Q>Me-.O^Qlq53Ǧ>+G>C]'~W q?ō5.>^ΆpS<]GLq8ⶸ;+& 5;xr"+xoジ Gy(_pŕ[긟坸]9qMO}kwpwu \<\Ys6{ϖѓ9+k <#pi< ƣ:<_cqq* x1OI؛!3)<:<3<')ópljM\[*Ox.yls|&&,r-x~凪Mx;LʵsɿPzg665 '_jk4yq|r? yڅu&ag׋{5lb3c<^͜-.Mqɯ*'Yf]'c-˔O*?QN8=M_!M@ 典Һ6hy~ 崫bSp Uku+¦OT[qՕ;`Ss֋?!ߡ|S9۾F#cS?mO"Y<7¦m/"|/V~!^MK^oOϔ}g]8v.Kr'+cS=wVހ uAF2x\T]䕱YnwQަڤ#~N^A;6{kcS><&rArͩĹȟ+)Vڏ&KL658)<p28=s,7aS+qVRNy˶/~[\@U\<\|Cf]qE'včȇ)oJ7'o·%K(w#pʧHT93qr7OPߓdJVj|CIxF!ߙ_xG~gag3u={bS_%ެ R}|M]q79TWq=T<'zOq)^W<oQMţq^VI'e R3nsR73~'y=ߙsB,SG| ĉG\x4M}yE>\yl^@-{SWMHʬWyx-x-ZɟڟT#UɬsJ.>C\Yl*C %(Ŧʥ$o_]xŦ,%cS7U^3:ywljM~Q9n6ۦ!OզEvqSǦ%C6#ρ? Oq{ީt%AjTS ǐ?WΘϺ"6x!yӰ>g*WM-">M@9uQTbK)wUMu).C>Aymljo S;%`S ʙJY7Ʀ~nW.Rں#6O)/c]ꇣ/Wm_"]>82埔*sQn65mq%ʿ(M,N>@y.lQ{ ZSnn)M-='fۯ.a+?T_CW+Ǭi`Sq?7ײ䧔ٰCx=ucS_;o+ǯk7{+/RA/SOP/xy{ٔ)ŦwS5.M?Snj۷ƧȿTިd{_|rWdͬ(wæw6M+?W¶'li]I6U)yS1ʛ/+*<*V78WW*?(Ħv5Q6#󄼱puؔI3yvC)3T>|{H|^{}Ïi+Q>M%DQk}TO*J8yy叕g;z5;xzS~3RX oRUc]Q5)T>;ʙZq_7pή\w'+oyqCqD_'NuC7g]7^|AY|Ş3wV甽iQ8Lx_¸{g"\]O]g]In&o6.މKC ?鰩CC\K**¦r  zaƝFZOQOwƊۑ< z>^<<4<[U<#ȫ)wǦ$Aru%l)SLmbL.B>]y-l*52]cSuʉc] Ry ^|M5/NIZsT=( JTy*l!q?3Mu9"nH>VyTw+*PMd][#lnMJ91T踸#yV}\'=(WM?QxҺ 65&߬|M9)=܏r壪}xyʟbS+ #+=c7CȿPިjx(y%ϔaSO _|M99~&FKrX<,_ վB1[cS/#<R<+_TvL{ ʷpu x@y7/)Ǹf U{*OZ/K'8X9 x4}MLr&îSi3΂6pG< ΋x.wW\ K<%q[\ n{=[TgQXCgf'mLo89z9I/ȿ{ҾSM[< i_!,v1Tj.y*Gp|g8 _22(.k⪸?/g?pn8m.NS_㫆rNNoSxMx!bYi)++J^W F|os^:]c܃D:S-[$߫m6 m?oXos^rE70UcxL 5Qc3\9cUsf ް-lλoEnK` _WrS-5w^a|'F'`9u kRS_N|~٨|S6/ްdv:u6g+8?w ܴvDs ": f1Y2cֻX7Zo޸xnRNDnFNVܺm&8@S{8=)isν,]vf-bm{]W1וy{s}J]'O>8{GiцAUuc̾w&ɜ\GywlK_.srpa7q pQsk pqppIcg.W+?cXptwClvq^K5fN4Vsntn&wеFj]v&Tn.ݬD[gvoU]=VMϽFj (?㉿d<[GS< rqYjQ瓹js nK "s^U*^nMlq 6Ɩ-$b(;b-+b}O;@O#;&t92k}s_GZ+Mj?HRhx/7W3e EOHlj <{N%=?'D^mN'oyO dh-LM vbדmI]L5WS-<%ږ4j["<;oz)8WP3{Zk!YH{8 p.o pB='v pN p1n p R^ 7Db\)UŸIkx=ĸf-v1nI1n]c1n#ƭ^xĸWX?qGwK _r="8z8~P9-`3n|UO9>=={g'{xɾ࿭^]oOZ/g/:S#cO{K %߽b|k!w?Cu>K)ƾ9`eqte5}6犷ȧz$||.JC7W|,c6`9AJVw)pO|ػ`~A~;hjnRYg+<җ9ߒ.;(\X*ߗ9-8o-U$~&~˷夾OT\ 7{!c[yGmK2 }{lfR},oye_?+og3O~G:W#yɣϷ|{.~1.R)MNY{ pyW?Es\kR!\۷:_nG ~÷6b$ƝŸWGĸJ{Cˏ/Ɵo~ 1>{b׷0b<)_x?WKKO?bն'~:>~M>7~K>">e??Ơ?2XjW)o0kD;AEu>k {ٷͯu/q5}Û-?V֨ݤoBX]wn~Vy/ |y^?~_-|9oWvB c/Táb-o<X 5V5B2V/CvjcU; ٹ]/dcPn!;&!{6 mC2tR[~ඡ{N[P~1*zjdܒŵC.*yÐsF!9oōC~svqPQ7d*= sPRJ+CxDU<+d? ๡&ʃg)oVY9\Wp9IC b9#- ala\gb<[\Y] NJ!΁\ ΃x9.OB%.p ēq-|-u&xpKOg ߎ'Z` Upb#5g:͢~60K-$}M gc97FSI-mC/~38gSٺq=wJ63HCdȩ;o|JuF-0P}kJ[[շTߚ,hBxgA 9䅂lk<;9Cnjd|$< BwB<6O''w^'s{N.NB-r/=%᜿~|7m̵"m2Nlp6p.{q^'.#kAU\p\%%\ Ojn/+Jf%ORkr5g/J!Q3m1'S}7"\(Bw8֌89mn[0B&pW[{T?co)#ƽb(ybD8x^~·7qI?XTׅQ4\,g9XNsXObVOvJuwrY4]k]W` Ow|y!hcKu,g=X,36#m?322k;Y|˜O_2SxZ-\ ~ŴA91-$`^vvlwp*a\nt\nL^Sb}>*$SKg_-k Nfy$yd씪܏?SWs箪b|s|YO9s:.Cz7gp pF3Η{/GɨeooΦ]-Kw x^U yWR{:UB='_ҳצR6&pk.)m y)o{ gyoqunN zzz_fzGfqgowqWw}f"p3unﯧ^-yǁ9^} fޝ{pAvSλ%3&7mO6?0ev\fb>ǟ0F?efƽoEgQ Qhh{:zm?k3ASgS6F={V={)|ϡ2mS|K?_u3-0YT69TsR~u7~ەEmW7n׻vV?vϽږ"j[m)Ҿ ^F;VNP,;MU>\#;5#\ӿ*ԻHGǭ"o?Č[CJŨqkh-0Ըƭoۛ9zz>\[g[|;E{Kt׽Fjqm~JQcj xzo ^kVxz'n/`΂7}\._7-V߭QCPi5gߵ9o5ܘ_M 7OYMMhlߩؖiYtO~4Nbj15Dzo^_+5ΎzUPx8!;qC?4dN-iB8mh-㌡ b)t@ۯqP 1%9C8WU~6CFziьdp&|8N:q}%gq28s˴W> \/hc>O}2ϚsGvc|QtY,/΄M/ls|G%gw#c̈9{|NQί)9ܸc?krD.byw\9(ٹc?;syc$blK)ς˕b\)%U 'νe8s{ {n;5՜~Tz,˸[qJF}n~ϵ;>;SzTUߚfTզz^zڮj:yű]-nNOaΗbx4>tjǜ)|Y"'| 3?gj>;];c?5ٍNfmUh1?ۑog~;}+us)DZsO`\v>5~WsU߯+o9>2p|,]_Ւ w沈yt4j<:zF|]j6M!72*>RŽ}jCMI@˷fZkJw,4[YloWPE-oDj3A lbW_ H [RWu)en<>_r},5۟r_o>nV˝]F f2`oȊoWx妿nG/o6Zz+Qd?oσ7`{[Ηzo_@_T䬕]ՖM GD8V H-ݙF],ׯ߾]_K8/w굗?[ERbi#;Ivsn8w5QWMZ}TTTܟlv']K - 7Ty;<k D6r豪M&_} mW3>PuJ$ Jtdj$H5}ш2Uӄc␭-uFrp l+4ߝk4}hkF/hRw%&dɛDbl$tvH`Y_*u6ȩo]'hEp:PIaϪԮM(vaO1X uH!cDm+"߯O&t@C^?P೫ UUw>AkϒUH>:|&rv9!>vg@ ["۲,bXT/ķ Ojt7͛~eRtEFoMTS9]NLZv>}5GIM&TSvRB'aI;]i#ٻבPMW X?:;+UitsA ,U4@ Ҷgc< y فUIR NH:%Z,-EL'ԬV'M&U86aB7mTO1hm@ʬiV4/g_2gV5kQN+>lȼ"ٟG]esmdǘ|1KO[,4юFzxmdz>COb}n駕aV'ɰ#QcN\*>Te4D; DWڎPKqzDQi'@AVzz9*#YfVc`yFE.p1 l4NY{9(Nj#VͿEʿy-ټ-@S&Mf+"||h]Mⶏ4"q;qIv4K8V/SNrFP;p;0PMR:^OP~peT'W[q+eEL% QI𗑘)Uא<9Vl*4@>WCI_":ȩˏ]> q9P芞i %UEZDDXPgW鯹ZfwDd0<ͷ H 7bEJ\T" 2H"@9U=P\9}3{icr!:Ezq'ۛ"lIK٤d=V5!۬ ^nJ4`◳``2N ҥRBp31d0+QuXi`$tP^ h)˼y}}+J=t+۸d-1IN"l^}96y2i®;M4j=pS!O@$yViioA+͇LF?e=(X&kC^uL) 4HrGtjп雑*$jyzMa}j*ufo bWL3V"jDT 4;+x=oLEt@rl1m=v+d. IA t#ICE7Fply|TO~q)QˈXԓNHj׉7ba*v>N^cjyγK}jmi㤕6_H`&SRk.@-KX0tWhe1x\-)KNlUn 1Ő ul2sh\T M Fxw=ޜ3Ӟq?͡ibX^ABa `>jt=.lqv ЀX=\4@,&t"¨d:QhH56RㅥDKNL27XF_PpC ~RZI8YG U+P' X\; zIXC]j1t.G+=hx1 2b qe?{gD_;JDI%?aHCU&PE%&$8ķgN1O{/g{5b5 }-W3=&\.d F"G_w#:3]e\B,@ד؎m"zG3S E,#c:(Oa+DaO'gW)*{hۖme8*ˈA3l cU &)qgԤaz*`'rzF+l؛H]VGj˹AL? ě7 ; _ݱ iۉW tf,FJ)jd1՚^8uO-yel-\U,t8|xjXǛr.4][^)ت_-]3e\>B _ZyIZvǍmZ|Zjp@]sW+돳mP&?D{ G]3jѝfb!y4 iF"x&z,ɆW-Z'|YcY, 8Y݅VrkZ/ ^휀7/8f. FP¤n_㭃I-$ s$4GXDi,%yL 4 VA+\d(1uY w)>}q_nZ&W57̋,ڎ4_o-MoW.Lu,*abb9VF`) F2 $4ƽ+ifдi3+Xu[se}<[,#FC]J7aQ5 j36`j CRk.d,]K2ك B"HZ] yJMζkwu %,% (צUA8ov WE|UWJufsphZiaы8ztېCL;jj5Y3dlz٤RںѲx4LzaL!BS$e^D#}iKqXe<7hC_EI\w; E`(]Fy:鿛7-WW(?*>v!~h$J (kZ1d`R3fLw/%<;kLf+o?m9`YLo#hBe?vVF4idnscTO|l,WBZ%83ٸ5t^]XM.gwXw;}͏`N꛿ݐ@ b$d,=ٌWʁg[q,tZMmP&g%bf|ӶԗԩSJ%1iHTHiAQIu_0.L<Ԥ EJi~ҩD$dYR 2KRN WKQ$ptIҬaҳ 0RaѰztQRE 0/'lBz޴oэ.whkix.!A9]<-C&m-^py^> 5qdU$&k?HS;KP~z+;2.Qr6)xϞ ga6U%:hv~{vyE;΀7&ÄGKy׊= u鵜ZAH^L ޖSl$K_M2F́g>^> ?8sCbm#FK"l'O[Rn\1AX IP6DkL[&XT#8+S!)S&20zxQBd(vu|4Xy\G'd$Yp:΅΢Kn_Lb;qFj{pf8!9ch0:Cv~;#0D \*{HIp&k$[e`jIv^;V\I+;:*3NeLQ9OP<SxQ ge[*BFFWzCPt/> 6Ü]HOoPPuB%{Pr=f{kM by }c3=d؂XDS% bZ$}Ʒ.1onH5ӣ@G/Z[BDGO2&X`G{!i'>c^$C_&;g{&\l,2~<d<䖞K?Ix@n.${Exₘb4p 8\nY9xF8ހout(xS rp#RhJ .ᜃs"buVCX =yJѩ'o3x)M{&ۀciJ: cqy{HUMƶxO 0I[`o=NNTj5YqQFdu -K Ikr?g,=v!cYOF>Kg$cn{9k#ݖy #t2#'ǥN b1?issծf$U=_tҏ]3q* N2:ф iokif5uh)c;sfݍ8i8[q3h*ul.%&%⼤^-nH\Ѵ QuLݜd+A{Yl&}[|fV8 22] / <8*VšV,W"e) J,aH*c^@2S4[BG#zIVT9cNzԾ+.8S~i8C[]p04aU8ќ-k/r6GCuZ&%Qi): pkUIoJh"'A˒.;R(}HS@$Ql*=)^L6i&B|aN"2OB8Pز Br`6^2?V#86G+8 !+.ȹ#|zZSONU~hP%"z &k< ٘uʮQ-#$)ugdOt"@k+ৄ.0ym=n$#H|v|}>zE $Jh5Ln5)[Aٮ~_lz<gF۰6GXc4tGqRnPno>7~ Xo7_rcxjoQu!/Aȸ]g!㝝PؾCc0$p:n2%;Qv.22Lfi7V>I;zjd Lhv5+ b i2 f=g0҈5DiP9Amhn[wR^FNn]Q4i fv` &;qs+V QG~?ew&46xy8wbS}?YAF6xQ_BڟIɋaDlԹJ0R* < Wl=K[ ā}Pe-i|/ĩ[5s܄߹{"'𗻹J_vyDYB̃OW.aWO) ȄMfqSfBblM4,>P,/.LH6_VsPss9Y+TOũ޴CIK*MM;_Vߌp~Wp#Z]p'Ъx ]t} d z&kc;`+Rz4-GvLlCKI 'KwKR4EՎlhw,-w^h~VU#ԓ@vmxlfFՀ:TtA{HY梻!SۙaROv[GZ&FWe ubg~6ǖ&L$aCnZykG4m`]Q !00lD8hvz6z*m\8n^-!}j]yu }:yz(3O}>@g ir5[6.UZ_z]/yhc0M:htn=Κ%?[~%cWe\B $:GsCo/4`dtVqͣmڰ2\//N-@ˎQأJ2L={ʸH`M=DvWΕYhg;u8d+@+;S*4ZħvMRxz;y;GU|avsCd傣*Tߦ5 Zv%-L e8W5>w?E zV>)c?2yb7&?>-p7.t.hteQj'8; Bq2ML8Mr0JuCpX!3+# G$3}s}qV㶰1?76O3gǽ!JJ92+l!c Q#ဠ.G }$LndLBzL:tS @MZe\J%@HY=1< '˂goF_,zjg`]~!E,>n{T`wP8&xhiաe9Tc)(( P\{zJ h2z/" ,'E{ۨ M^2Qe'h@.$TFO:T;Ӣ|t樂T P ]Ez M%}h8QF#[ݥFQ+]EAB!̲"Z+o-*Da!@DaɁj_SŧPi~ENm.ҙ::Dmt@G` 5j&xr-*\Gje-XoNcŞb~ H1#**i0Y4 I|)iU,U;C E:E߿‡JiiyDDvx$~4`Q%{5u͡Kcr˻: $UZ6^t3hIԧfu *r2 O犑g=^舳6F~`ᇀ, 7V{$&@rZJW tB!ī`#hϖsWa>^q[u'h$.Mk[OGGFE^e q^l7I@;Y49'XC`[|+YBxT4p;gw1W1{}ɦ99;C[ϖhj,~Q0u#PwE!I0Vg"-B} td!}M'6ѝUߧuh)!BEał0{ɉm,OglɢOru7-~J HrB:_:RRiz4_lq*w+u[-+M-ZtX􇋼d̝u_o厩$y$E>Zrڪ[mqԡDćg)2xi"Qv]ʆ[RnRj/8ѐBW{D*68b6^UM֢4t^T t0&4|wfGi=8GEO6Y{qu~_/wd )o 2`u^p<U6x'};ƥ>CZ 'q)1Pѝi(P6=K B{j>ߥ}=ɏ0y{rh,ik4YB]>)ɇC2r#tM궭;+\c z =Bf5Ǔ0urzUtqu[ٸdg.Mw}|7tkb,z*dvxw'BT%45g˓ nv{ڧx[ѢOR&n\gK&.t[W *SN$3t 7-hu' w6/E6(gUSI/&3lZmߡDÃ]_,RkZ:xIx\$2" ^HūO6ХT%,tԜm0 CQ-s}ї4a_Z@:3> 1V qdYt8͇zοNZƊ*Qz?Ү7K$rnoh_gxJEG jBH1X՟a! FBǧss4 ҸӓIo2qYeq-anCH~S,}Ǖy"_7$H}H#(݇H'ڡ.Y|;{g<#vӲYLmfi~ʶl6١XfQOVn$k*t6(dn۷gI8ͶzUϾTS{8IG%lxr(8*u& Bx=![wT7[.I*%0]qZyOL8)f*Z*K{tB\& m|59f[qz8 ^Gܺ3âϸ@ϡ@p]eb&.ש-cCߗRt``I; o~^;驪M*,v*}*?AA(ƞGjwIxIDgDJaHחkW a2?ۥ|J}GS2t͐2H;:Db<3AN_˓aӐ™}O1%n*OB.RH^Qi@Uy }ݺ>d4Nڃo |R㊂.އ"+MzH/ ye*6?/k]֊#W6.w˶Zyds>4Yhh$652#C2\'齞k/oWEx/͍d$~.T!Ͱ'ҝOeHFIgB 9^#kӆ2=Q trm2_܌+S!찰1pʲVkEq\?nxYR~<4D1E0G_ [u99𡁫1HG5[ uiYU Oepp‹7vK9U3P;#N0DZę>{γfJ_ ̧L ڋmy$=\=em/`(!27s}jJw!~"7bArod(>+C_pfRXܖ5D4vN%51^aL\T?;:aW bq~1j8-'ׅm;65Pl.I$Vr<6uQf^LׅT.s晿 #&=vlj wV32p㴤 )Ska|"?eyI}/4;._ALa:tέʕk8$Ԍ7pR\C4ՈF>0d,?k!qF-j*>Yo; 坤$4.: >d^!VCࡪI:@JIf.{.XtajȮ k{.{ȁf3}k lI9E1&ֹ`<^+`9G 4jL>T>dYkKyjՕS+v\KpAb$ -j+^SO)PoPC%)kGxת.缲k5ۖfo]d\ՒAZRL38? ۇZ9s,E9- m)]cF"۽|D /c#eMILW;xp/RZg¸PK`WޜqȠyTCӄ5ɛA((,}n!9 GWq3i3dSrbMʛC7I>UTi^+H [jZO~!-K&UlEcZȤS͕^階e4 ֫j u@vԍX&iPKvҚrZbI{!-Ya!!WPF {4b"\ HʛK3~3Q /GOh-7,T XF*ǧE( uf,+fȡb}*1!KDUIA_Bj =Y9B)(I|% o z)}s"r~Am5N&!}#*WPdP!,jؗ #U bB/i4!zOIu4O~6 -S-)PWiOMS PH' 1^&LJweW \C/O((+L읞;5-z쎨.F?cx)j{@B [m  ?sj+ Єj4 MCH @,GP Ø)T0⣪QcG}K nokn8o8> eS#)] EDZ3oX;?f\ɇԖ 0k BPZ юT) c _1y 2?mząrvRn߾]_̰|^lXDoOY^ٽ]i ==z9g-Vc|PT^)N7hIOҴ4+6p攦 (6Em?Ct@Hb| FoDZ,+`dP}3Uƥ45Z҃0Bѯp1Y5-+m 2(> l=I͍W*($qu@m#(t,Mĩ/Ԓ`VI#'S̥6_5۾e2Dٓq$p+Ҿ ](YHp8&a4.DWDF2v t*oʖYVEYC6K?ҙO*I֚t!enmXkGzDRx)!u99U/DS[]O9UHbT!yeD /)a )JOzfzMB;'lsƮy'^^#D*ڽA,R|ͧPtjϮ'y it֫aIZ4~!o`Z@AbLG#H$J.cRipդ";<*í]񽝚 {u"u{Í^bӎ2kFR!)Ix(7?MJMt1yl˰ϭt7ץVoe7d̕Q,;VjLŨ9;=W`ܻ$高k󸔥{fʵh o Eہ44] %WgjNg+_S9//9FgݫoEnmoGp&~_|'[SLc6Zj()`>o_ P HW]b pKʆZ39dA/;x.{EﲸU9<Զ"C2!eŒkI bDr)Y}G11i l$l0i(t(ơ{I1IʪXWm ;$jآi>,Km8tن/j?YBGYת|vtCj.1lint?@G1*I" okcHditdbپ$Ah. ׮ty]W-G:SS?ƖP~ ;ռX+e#M8mTAQ ?R'uĕ UGҋɖhvfGlKv `'AD+] xͮb|#Bv-VKUe8TyϕL2%̼eAW;Bxy&mhgaÝlo5Fz*yv R`t'~6>+/=0}2ּ&=!@kP&7¡ЁoT{jD8Gq/I2Ù4WyH̀ţ**[UIJ E[=It讛|5-!9d5NA?7=<泴Hy}g2t#Q`0:/F 593?}J|=p` !6-T,(m*zCEv@hhrq 䯳PK~=:g<g=f]zG eóKJC+FG&&!vN/ bS1vH,§t pÕ.L $Z>̝G,5QP$.$P)Z_?jDOӚoK&(qy>]nr-R~~>L2ۢ2emT&&aY>~ <,OV귌o"lU?*`|!=a7N†y*hr 07Ox!cur0$°LSYjSɦv Bsf hkQź  kl!p?w> >ElyRtW1UMCGFM=,ȉn JwC7KWSD@n9t"`Ac~ x puгoCBrSqrW|x6fN@(?ʣ ~TU̓͜>t_ ?J돲#4^PUrQi fW3brve>a0gGO %p6o&(!~e^: .'L e/_&$>k'EsؔoD&az(.x:!Rd^*,SY/=j6<Y'gF"pqPa>vg͟2slQS!!LߙfWsΜpdȑtHMBAsJTNkA$sW֜<^eHޯ+._tlY>cv:3]d8@-I:iQp /t=&"%Bjml03T28nmEUZՔqؙI .<$BAa@ [_E6d]\rkbk5䱤z#.+50 JPmtȋ ] NjE1U1`]h;7V3':z:s%C~yo JֆĀC]Eb02 ⎬PU. "4LT5jٺFLyvMlb>gژ^7T1P}F1fՁ<f}l޲vW>9`2`sb^޾N+sӚuNM܅W+@(~Gg$Y"_? ?hHgᎤsN04 N8p}(tچdcBέ fG!{LThCuO n8E%cȓ5,9u0ˍ:1p:n ܈ˑi*q֖65'65bׅdZ9F4)>a$!1X 3r>2 XxO|YL QY\_b<4UW@(.vVyE="e[YMtcyg޳ř4 7wO#аCR: &Ḧ(H\7UuJ3YN(Rp4klC L"0%7VpA??̯PE&KOs `(BlAm`˃5i0<űEvK&uޯw.Ž7,d wZuL<8T(iuZQ;  ެD;1ʋ X׃ 2x.սM7斉p)O/Fu2۬m=",o,r\7ƧWoPߊdfGwȆCqs,Cm /@\nIpnj/MuY X/Ze0F5I{n|,ȹdjR)gnX8ţ=H[9ckКveCͯ`[Mg&ߓx|6u%Hk6t5Z<ǬTdtfF_Vd` a9L8gf <`UNf\krzgW@a5J~nй@yo <_0kL.+7Rg;Pzn2:L3pC07 P^zC ?ݐym3tCx 3tCeFQ7TVY02  !pDz"p">ʛPf_dFng $6,nhи;HwTY;sjwtI Z0hu6f@ Ƴ'cu.lt|xݒ6_]Ў3Þ%owܢd$5ԦڔYA653%¦.8OW&)Li;҈'!Ak;ip0"x=nXa*z#̗Ec$~"d^D&~r6+=oU`U'O:PT5BU>qƠZ0Mv%hXki.hDA5g ל-i֜8EQsiUϋVe&"R#| 扜ƠU +Z PJ1Ut(7Wqr6 3*]4A8S6ѿ8[G/wrȂƣ|`DT?Ԋg,~`i,k`PJgvƗ1 TC+CZӴ3+Ob X[KЪLʼn9~7uEϓ@/}E^[C]~E)t]"IzvhUx9KR'cZ/;5ܐĺKP4 #YR̒b+Uc:ؽ2"=N׻_0t"ɶb׹9jɒ檏Q,q`'y y)) Pb-߲9ݛ7'W_lwMڪ~qoQU<墇A7)ADQ␁O϶T~WVߠ<|p~6C~B>jT(;ױyES0I5)EOBiɻXںt.fxvE7+,n,g`vtMm˖P4F&}VN(xfYri.JE6{EOJ"ƚ@BJ@8p_6+Hdb_Y\$8(nLJ@h4) `m2"e5^&k$l|󤀴쉌2};(6 'X"'05W\] 5pAIc&>`&47CZpvƟLt2~re8#mf֭F[; 0#d!&^0աJ~دɃ_3_9Ai2b Ni['w/.%~fmkDMja>5Bt@ mXah`Kq|%ݍ]mM>He2kPF)lz0n7Ѩ74 Qn"MQ/A] $zF]-] .lhoaE{ -\hFf4Z8hڼ`Ac -[hOZC͒h1V\k_G{~>: jOw PZ7} /s? ) g]~Ro?@SR,e8tגIĈ&nsX]R;pLC9T(LCL?PE!?%+D:ϓ%N*(|bLR+N0p:8&ɠ׉DOU0V`ҿ;a_Ȏ- (öNSUez@0Vu*$H אT'ԁ|2bU*v7{~oVoXyb^'lU-ARAP4)5=X5|ӋBON).hś;=Eue !KK(l*% ^Qmyt>IBߢROͩBIr_B>zpEJSư)V':Lt7N +'_qlՂ ix TɛW"EE|#y.!C,: fȪ@$2XEJ.>=cH{LHo߭.^ԉSV .2UGF'م]0Q殣//fR+Uv$IǘAz+b!+"RoɵY}VA&W(@T\~Ju2P |b>:JpyPuCX` bC0O2A6N %|4Uά:@Apl]ëȃߩ~I-cP( ~"%m&'d?¥ǿ"fB)Ȉ@C VɤNS}K:qWt@KJM (TH7_^׉9\32։qpT&o]K~]\0V`'`(3c݅1[x@k2yaHa&FR ׍ˈCjxD>ѰdՆ]&$e`[7q&@ ]kNcm ް?jq# 8Ge]9: /ؘE$DslWg}goGU,4߼  jn;@Au颉c g#{KvdBBsKAO'bN O47ӟhjca:8l$bGfdҐ҉!f"דŷ: )dH[I ?"'̆&nKfT&e'JS,#p}"ZkT;vu+f+Ltz1@3 t QD$avF:nX$vy1Kȭt"!{|{IؔJQc%0R@B d4tl$U OStSm, !3S= AƒIR`̓ߗ_)f^~ #/>ˇZG9BvE6pNCdh]^q` 29:F`}L(s9O@icM;vP/vZ{BTY]ݙyP1BT($%K[iTgnwϻT }|[D@b>3Eǩ] 'p"Lۼ.0&"5h;uK'} B7%L/kEĮ1*w8J*ZB*M!.KN*Dp+?>GB{lЧ&,Wn7987M/ I{xK+2Y^g=7<d^9f!&HgHgy(4Ц ^?lM6h<:ZxjXfvl &5v'sm #'!yF<fŎ7>bGHO>((ZӱԌCNH/@cIrQ~jqpcjmvD2ʉ"kɉd?LLs0E(; ާ GRI0%´RDC>O4͠z $LhT4!@ާ2_2QowntpsM Son6۵f兰N eQ3ɖ4Y!+"Gĥ=`< }LueҌq _rr?Չ34lbE!R"иM~/m}0݅旅gq)Vfp6܁)Ai|P H?uT{1u(D_&xi_jmg&=Ǹ E=lUS܌i}O6㐔fܣXi~K5m6>aPM+N8"48:yt`Ora佺i:LLPwD He6c^3T|7V$_K[2,Ctxy9r,<.>aqT7gFnz@p YtyzXd`o3K2ѷ6 pFqx۽G/G:3'aHVvۖ ̪m׿4$!~Z 2m[QŞVe BEa"~v۪g?vtš D,03a5.̽>d^Zs_tt1CWw=ps\~ 6/^(\ -:# K`\E(vp;0sLꖷz BXkK9 7* $F*bz1_^w׭JǪhZB)~KZ e/9%Z_׏Y+Q@N bwri籹px>!3 {Bfbr_{̼pR=* {D6&"?stc:?0lώz n_;oO;.wGSED-;K>9Ax[oY!v?5ZVP?5LTU]grcz ޚiz.deqqrMO=ޘMYI1 MXm6C{bN‚yF-EI4QH4`xPpw_ 3~!;n E`@KZB3 GU@Uɴ`Q2Vv@MlkChL$vS>xzfӟvsӗ{3&?o[nW럾mvf2G'S:?(bdu|51Py\& T޹JtЃ:̍o95N>#>Sk/$ `(\I>HAV0>۬N͕$B$7SfSo^(VS0&0Aحc>'p@(\+"冲2^̏-NͼWT9xNx_;x^^3g*00H#t9$FGF$&:ԧ07-eU[{oW`v;#K upr=cE/LpEEp {ʼT(K+siTJSIǦAŶ~[oj+! HS|c@@ٙ\)%" DW{|lLb`d< _8< "lhch,"tC=L#['ޚ C %$ 3] D5ʜܯM> !%`F z nn5!ڤ>t ]ƿ d`\`#fkk@؂dg,B rܦBDwC8aP9a 0 ?r4\ߦ\H1Fb s8 EW77]3]7! t M;uJKN(P2Wv@%ɜF0D,HPJ641pAwgO]V%^{ Rs1Pp "Er,MpnMAn ɕۅٮā*)uZ- ffSRװ/f悝 NdQsC(X={ ir'MDL*Ҳ=6,ڷ۹f`d@WeAy @e(jԒ\ý>K,}R㐊4Y.ff~8;)8iT;Y)>Xi]-ŒuMMdZ>)n !^AQ뙹cu" f1אnITFfut+m餡ǡVm>(3 nD $2""`+ÑQv8CP0i7GRPP(7ɉAp6KD8dx6'"bM_-nvT]?[챙tb+?*vBqCo+ 7#Yjɺw Keݙ.,jߛW0oEm–bL܎b%(F~Q)X`{Qʰk>ScB8:_[ɍ)FEzyB<$G7:&ˇMّF5~ĺ߻ص=eKmfJ&e?d [?oHKMU"1:dKnJtc&p>RO-3KLS܎OW/|= .{{ Uhl6~=5c%vbThh:y0W(QaX Rڶ -mi }M5j.ƨWy6΋ *0ʎW++h:nPt}~/ц֚hQh 6{2H]AlUoPAojcW:~w'cg5!/ bL9fiZ-5!!Y{sTSRUJR)h }S=@A1d员M 9;U (45"ځfl/}F1!3mnq15ߍ\t\i#f.v }# a G)uj =.6JR>QΩÒ:Ĕ3 ӃtBuEzp42ADZduF /uskj0A,͇gbϪ`,ϩufҭX;#GNQ9C£%RHH[ X$KscȾ/w镤qi;yk\16^Wch&dp (.$8;knpm'/4w= o+oQGYSrkff薭iVd$E!! 8б(I$6@\luj,gLYo9k?S~'(9]no;IpCld!4 CD`UJl[]TP%_|eZ5NM1DW O,pSstD7XR#/Ēzh1hlsP}(|/NalCY}8>8 \%%+1PGrީKq^6 ?279"-=o77$P+$0V;r$K}ǯQs|9 enÒA&%mm mv6f02-)(,H>M0MdKr,"i$ LCd4jg5K9,fفiI5 o`dB9eצ@M~Ob v=wLL 0~~d9Izl̉4Jkػ|: 3,-.GT?r*)&?r;T>@7m=sTRiO@EGg3cA'hXĄ.4UGh!כkU6CRP8,4\{xp@Sedi+bruy=tUvd@ΪnIt=-3-?ݒq5r?H[Ғ\-"YSΚZ~L4'Տp쾦5U~"oS@۪C?pJSFOe=O3?LHu> qOgJz fxMssg5jׇioN=;+&9G ITtwĠ(O r[- :'v}%s#DE_Z+N[0!clބ͋5!&f?gƻpѲXlƝ'zbw}sŐɖœ$8é $S6tC%DsNdŘb律sSd|PQX ._~[1u;8w[:-ػ -q)'tNY*$ǮgԔF ? r6&LvHZ!9md5)iآB2uWz;8c'AK8Y"Xgϼ~Gx@G:=CJRS4n*g˙z 3[7Nn_r<궽~YulBgK<ٷsa)6dvQHijfP?u7{ Tf5wB'$ju (,GH0 b88݁q8I%dNRx Emʃ8&2< J _Vj-?T4Wrpm>MLAkECA[Fa{z >+jB(6؎veNj'^KJJC=!"@Bxx 5=ފ\;iVEKg`%l "W2ڌўT:H{Xpo<81Z2YԾڊl 7iҳ#$oH.I™&#;;ҳ88$P&ua]וֹ4z=o߯qnLj+ k $`h b300DlZR pևjgͳC3@(\ 3 k뽑,O,Zkh5$xG)#9u7|k*\pE 鶁ZFy,&x1jͩ3F5ᡱֽǓT#;٥\9‡K-Hń]`E`M}bw"_1YFf($~;hN@&Kgܸe%SB>i^ Ik>iɨZ\,b8 9/ͤ˒W]u2zX恍1@&MJ7'IzMC3fS-pV{$ MNsQj&3. L/t$:݌Zy)gdXMYx<b6VNuCXUaUKZDvXpb<*~R<5jiZz) Mt̲F]; %IB~rE$Dn }r_{|㘒LJxN kC~(|PÏ >lq G$9TV'=U'0٢ wz2\4Ҟ3Op@  />th} Q}ἵ1DJ Z~N[;Yv#WD1ERSK\=L-%uwsU}kl]s]Y^4c)K7)H]˰ gm.B(Yowg1i!DM'V&r8=s@'H}@_ gIPA^Xر?!P!=ٍ!^8+µcȝx @3M[{l{dwz7c9 .p`}V@@"%A ]>?3(do|\=!=fק&*u/i)Ӛ'L̘zrĴ\" MKUm t#a T;pJa,iob\G2eGnMgד'Gg]"?.cgԲ%˘1cʈL~PgᲖZ}7+k%+f?n4qR\irUz6FC1e(ye_O^eQ,$ n%~}ub}eWc3@R$Nf/>Fj}qwUuI|3n1vt=fAa-J(B_G9ٲ~wgyh16TS~&Άp"|`';olz5ĂRCtyt -E"s$PtMC-PVfݎ%|&H>{!xcYOd6| ;/o/of;uӏf}x$..]#?'yZHc'b-FiS &z-t,3Js&SҒ24~Ғ24gIe:B;S 2wGù<izgt)pEb59 paT"J#+ oi#r%[tT7,bHey>oa90QxHLq  #(8b8VхLHl T%&ugeodmd*гnn~l:Tf(]w h iwoWK7+=34=ˆ{rSD}eTtkIi⫷Fe@O^-_>&84>Vws4njw4,D E5癊Ϟ0[Qc('vI*9q:iKg\Ʉ+|Bj*T|r.j.$eT-$jAzCe Z 9A]Gd|jŠ:t0~<菟C V= jqzw#d9>e}!0t ~>_Wwxnr*h qωt"eI;Rvx+=QD- u/2ϵN81$E)#pj':.Zqά%<2n-6JU犺#\Qk\aRU?N:<< 3tpt: ͈~M.V".+=~S 3#:m(N)H۴ rゐ>Arq-_U82:'E_r]l̡;2b_ݧZ?j_qc4TAY~pa9)zNߌ8wG2LTC>he:/摬R0[h6W[l9lpZfqNft*I,g/nt@4(0LM>ݯw!_}PBu_(C"y֗ zRPQX@\0Y K] ڃq6cq0r 2WFCc~h9unqLR~"l``fc6:u}˛b$6yqª"fH~(E:ש[]v("T⸕I:Z tZDyMT'JaB@)1}tY̆~a>VvRfÑx_2ǫûFiz4|]2^X在[1ȏ#uȘoNwdZ ,eB. *xEeMUר\SVu\ABS}Rp7z]u 20-v(Ⱦ@ch@2@kK5rŦ0;ȴ޹e9=W0ZXi hZX÷\pd뗊CU6|TI<3Oh:HFy˒,|r7+k\֚ϺjƹB # .v<%LPrOtS>\p=wQ~Q~r=9Õ vftoKx:!KB#wQC@!) xaЙ[afSL!H.&9\8ȑsy۟+cضDK;7K>(Ѽ !ӹ)<#e~\p%ydm1Z' 'Ӯ'/ӗN:;4~/S,KtU1Ui^6T@2ېeӄ*i'wƣKLSy56&/W%K;z5χwǼ1gkKҜ j7h/"\Џb=Y"RDR@*c 3E z2 ZNrX]Esz#I6GrD'!`N.:au/$ީ1B,+面0 Dl\%J`>0٦Ci/|jaܦVGw\s Ԁ$Dx"h#;MTj—Sǵ9Yؘɻ,[<~eڴO6sc$u napkWXB%LxiIslGo!#<&t )*d9k[7|bncgsCW{m橪x:7nקnoLf6٩̵kӵYMԶC,!+Ar璻p3{-ü,9+.&?;׌57uūC@nzqr*X$5 '%xKH3I&Rբ '3)5(}*6OMxM0 ִo>mvE[[1KL="'X1[k+dp5$+-+qBYuTiza<\ϵtיw@XcyZJ[iR A=!$#SkvJGc<ԪBe~y4ν!"rԳ;Zlۯ.9A[wFHű\3riDM*b hAC Fl@oƔ'ͺe7K& 0Rc;pĪp˂ F.1}H$t{ uei:űt]o7"D0RL[sg=B1Dȹ#cR,ݓ ` Fal29!v-vk]+luo[D CCr+G;F2R?VԳJ<5'wx椔SO@UPg2=\:.zAGXBYK[ӛPۙ$%\qBM2@ l S0LڄM qLhƨ?)ڎ!tT ƀ&''v@p&5~p~2Cdo@vqݰlnpxY c~'m9>̽8uuJ:rOnF9wd$]|]{Fq@fOd.e *wAn0L.%9B[S& yWv2=2$HrirHZjH`z*^ F+|>e&]^m9S씺G^Bx}1J/(& ,1=E8JU(M`+^)ԵP{1z"tO`EfDTd[7CdYz8p9߽`xA6VOs]_/ /Kmp"ѭ D5P`2~3:XAUOƳtncF_DM r&LˋtMgx&H|x9{*Ch <&ZMPLdLxTM su rai 9TWHH4CYtXd4V>ܾI8WL]W*pӁSK`E&D i0mgU##9EŲ""K"}W#lŮG>£6Cu|M7ecAԋ0ޅ2]< CPZ:"eQ=]L$$8"0d;*AM* x<^3b~OoMop6W8oRVsEۮ4;/@mS[R0*JyXPc1x4&ɝ t%M8!8^1&)d̴惸b2ئ\GrڕY Q<+p"a4͡E6#dK. ĀHm X!me+#RWDFG=qlϺs{{~+,FNl_}"k|FM';mQ! 3\hJ Q1.%ܥHW< GRMeFG@ȌЦ[kw}oOjWCc5TAL:SCX`9 5 ŒNhilsrk_,#l#dl2d鮘4R A̕Cieٮp!1ʁjLZD[m:B2ryj<sʺ`^ӶۏxeMp\I쵌=rcnzɤrN#6p6$ kx6rz:RjV-SqǞ! P2=<[\Wp[ };{IK2;BQكywd9k'BKN'Ā ]͝ ,_9,|"bP5W$YLsE64w$Μ0,'W$qB\Qa)4DƝ`v㧵,š.!NGU 2zT PsGCXɨ~ v^b91NMVҊr5a}ؘMk_>OW{7V|X!]F~JOڱMJLC"Մd{q7I_}~)Bi@N2k( ,s֊sGE`EDD9+4XmGOL("i$E#5sm&LĶB:,'‹7)gpul+tEU,p%d] r/CCN85DJYeN-)UA1@A &.bП@Aw{;F* MH!* a?$k?M;׆1mg8'ӑc{fy o%͛$g3 [+FFR9}B܇NDߛ3`5#A&Ie2(lfYSy3Xd]sX McBgLi. $@`A23ǂoY2F,^󆝱}EIFR\ʙĆ]krcNbyltZ&g$c(' "PW grͣӃ?wunK&,>" 3ޯ]dpn̩-T0yNAr 34!sv>j ,jGECpS ((deMl/.`c 'L[Bh/"^ձp)rf@k1k󤼥ϋgyZz K'ܘΘ_˞t"luɗ_̭xRg]bF">5 NVyN9Kqn)!]6M'r8FqUx&HS,:{ۭuSR@W}I'N0FH;8#MJ•LL1]Z!uF_LRJNRL'.­6}80߽NO U4 ;9BUptq;X% ]Jv;j:zacU \Bc:id|ܻZ:ĊD8k u%yT2IOKӽُx,2Lt#cV/y3Nv8DX*^:ڑIm㌧'&t|q<:99%,Ɨ77/ګ0ԘT(ti 3x'oʡխFHX41b_; 9Rqݖ龭QRǰRdh8<zx_AL~bҴG1Azb)EJ)`5qLF l^x8s܌޵l=P f}ۙ; r64ܚq9C;У)l2%MU}0A@Ѫ(eEl AMā]}Kz%#tfS[]f"clo)T;ՑL umb 4%dx:Ic:\O|arjђ86dd,)t|ztʾv^ZoŪ/&5Nq> d-E2S\իsj0]QZC?Q NҚ~޷-#SL(ֽh9S5"EQ6i* (>1MHd&nYG2}!~9Q(y' X(ۏˉqQRcٻPF}/@ 5l~nU4OYQ :ZL1 $ MEԕ>_]$ƺSZ^`N JEu|O(%+cȽ@Ubd_I,OO]i)ЮsaW/ǽʐ}rJ303u[$swFXԔJ\]]2•:u!φYYdYԡ6Ģ L]dvL`@{Hp8١QF"J Uațpk{rh% wU9p)Yavj[`P,<:Q( Oh,#C݋nd#u?Cj^ʲ 9~U*r/$%# Ћ̘%<>*N?iJ޺9$_Z*![|\},#*MpM&ͮɡg8ӹ8W90sE b}P6>hǠ}6^/v¹A_޷IINR+9%'sz|jYNKTw'(JHi! (H;9sTNk~<7$>=FPEģF OCVCz\1Qg=T NMCs4)$V@E\aȈ%+7;H8$('Rui0(N;Sda{& =nY,#"#xwM+EѦ3$P3w\wi<}k^麭AuB[vZK冡pREZFpێRJЂЕTa 1]RF$VQ', OfOI5r*@l9RSUufx;J|WA]r,qߑVǓN޸Eh<"8aR$&qU?h@)rQ.ceC- N|uy5oČL@5Wk}9Bgu&0V?Ӱ*6{Ǫr2h W lp!+۟4@O{L OTڔR`wϛGXJ,;[2e0 rP˶4<i(ep_aĬ&f2j"iZfZOFL i-2jP@?d&rbu# A'_*U k- lBVw&ZQ~),:ZV[/p?;W{H:~Uv;}l4yߪԻ[[%ݪwPn6\:6(GZuaaݜ7'L,as091xPYe.BO ș * DRj\;Z7]Ph4+u t~f͎ ݝql|Zߟ]J<Fdn[$Q2[a RhI5~ЀzPOu D}SL2QU^7}`uF|7p.'[).$eyw^FO1TEY rugS)s~T&(LQRff,8SP` A/wgo'l39b#7 ;C$л‹P{ۡVd!>q睎`oR [Crnu_?7Vl8຺~Kѯb*LKL 5x00X?dװĠS c͇a \H<,ϫv-O`+YVB{,W8bVE__ܨ 1:Ie +Wl‘NJּB L`Mt,xNoU?Pp46sz#HQSx6 ܘ&Dx+ }~Z/F>eW=ܛ Cg ^I =-W 춓t)JK"(M/6F'2ܩ]8:L̐bKm~R]Ȍ S}@ `Vrjp{b^ 2020q1 OZpT͋M~4]PWʯ䢣 L. J>vs|s#:+:]| #bjPǛ9R>ӕYg<ˆ *KmSxpGu$ҒLO+@ve3#zڒfW?^VK*4ΰ-2]z7}wZ rMJRdSi t·n9fV墌gܪN"Cr/Vhb{W+[4>íg7lQ!k诬 yˣ 3=ӉD\[3_P[w-光^us֦P.1 'f'PV}dTm%hZ]4+`{\n]ioۃNOډu΂rJ27et4LzʶܩRq8w>C]1=@ ֶʣ bҨ* T=d3E!@OtwNC/`}x d#DPFo%&qҠ{*mPTˌsŲ^L1}]'bq5a߽L;]m3%|5v_q`86VDCbM?ٿیj#!LɅ!4r#ljqp/~5N0SUӌd&%1HfZT0e"a ɷ_¡M ,10R͎ڵwvϽrCY ]F.9nHȵwUb )KS\^a#S0&]@_PTR" %oJ3Cx bhD*l+ֶ`WG`SNa6IYՇ3)xڨq|LiNMs h x}CY:<[Vp[~T^sN`G2y@V_ 1VsQ'fXr @ҨC$QMCcc3F<@b5X~Ib{gS&WJ~1{#:|TQew&Kb0ɣa A\ġ(y m%Dy)D-+dA90 oeAF95d8' d@ !Q V` ߠ*\J✩"a\@=1>@Π (lLE8Ann`ϱ%'@7u0 ИOnL%#اmn4brA%3憬1>ȉaA\F\G{1we^2/$2RdDo7uts Ԧ3HԟV`&1E^tF/&9ȭThXLV0jaJъ$CJL'OJ>: ϫfv(ywj1p1v_=19Ox͟c=pIe %.0hn'lbjivq I*HJ&%>?YI)%|jbڳ88:cŅo,R:ˈkq+T\7u )))!7PGcݔrŞO-A}\i"^3='V%D&NRi^)W(b}ӘNGUClL yhf/pxZVtwrWɫ5]\w?o"[۴$|Γk 0ozoYUDh 7?웴j $@r m$up5UDnpи # >Bh`O>AgP)I 8G3Wu.aPZb)'^`F!$@qAlF|:Ӝk].":P*qLI Mt# ֋Zeq=؏"^TnLK!,ۃIbܸϾcHk'sr&DE3( i C$Xֿed՟ ~BuY[dKc}ԊEf_]+:Xn,D%( - CX%ЖR2] `B 6#v+:crwE蕁X'oS$ŢdD=,nMilu5uڟ߫L bњ`b`P>xfnMѝ2UcCė>,o-^]tz%\?p<[sV%K_fGTP?񥥹fND١ ;ڡ졲ތxstn݈mLI u<,l q,L{gr 7gr t#`bg]3½>3cbCB', 0$:."/d"!Ԡp>) `b`>xfݳz[=o=eWxD=2"ܳ^F\ǎm'Xշz^/sy.xIng:˅LB ܀YxWOtKǐPO_ӟ {UDOQDE/g/per32Y i[#g/7c,|7גZK`Kd\.?I~09RWa֢ u^ N *GMTe0{V/|AusK)_,/j)vi5ǺʋQX/΁^a/:9XJj_q<+hnnɱ!G[{QM!z Z'6Y&Ń!bb beZA~zqcwOhK?Alitcܠ6!XaF歯#oT1Lzs\?WָK(h@C! ~5i$?T{B^TN I|PA9erB~#( SؐXW7Z0M7n #\('#ŗv[&O-,-rX'*͐VTo`ZC ^ZԊ=*УT]`lTnKF!5%oBWP@SM Edb ty}*HP^xj~Ap_B #rغ\Zp)%zʒ=آݟr.ͧվB\BxTSjXEn bt*BY$W|zNvuZZdzC=CB P]T2 alnby9h bŶJK0Q4@ZNB06Η8" hVa$tiRz YSKr-u:N,& +D2 u:N&"}HL7atYt8B {4T\W"O2SjrKЩ9YzKb8M+=KN׽]mƤ.Et݃-; $ 1%S]YDw-OW4b>H挛U GKrJnv&-AZӶ{IL1S_璨t) 'vyVbf*qy<.?#,y* EaZ~VJՙn aA*I9άrXn7˓ G5 x6o]i&bיݎU\!\'n 9 1 NMddש WAe9S+ڒRtJ:JB~ -E'XmA-'ձWΡ3eAPџ-w«#AJM?-O]b}R߃\R&ĩJY$EΟRIΟ-ӪcVBjQJuOmvR8>-?nRatl$c} xj*W!"7>1vܺ6bՄVqX%dE=OHӎ6<_T\pҙ)'yJTOݴp=.7 OiKxK'hmR.$7 \)[vGcUZ&hr u 'p<αXQ2i<R99ĒCܖq0`j9UnDC5%h`Ѥbs{qb8od Yjfi~DЯՅ:[lI,si$1NNy/5e/of<o Q8t #FLl G|z]ljTog\pIpe1r=[ln!7Tonԛthg F*z2 87UM`+VӡZkeh/d4YP5@/oWxFxq g0 _F’j,c:pb)Yq27 ۻ9NxEe$(iZg};_^R%)%Sfܤ .mUaKWeyp~G4E^o~c'dKȖ6l5Ҧ,ܒ fQ6YT6 ˩*ֻ[<؃FALA´`2#wV5[u =)n܈rZ6qBƴaWM3'Sd‰**Q5Y;<[CVaOzA,)kA8 R Fúfiz}$cqyS\a<)_?}JY4n2Hi,&? ;pA8r%gAFffׂ VV׎g~.@KTf_T_5 M&a2 'ę! lD`BǷ:צ1񈘺 *" z5L*)6$|$"RtDBdB9 9Y8"6Wڕ n0#ץ ,MoŠϛR²c:DX Kc1x¡'W_5IF):ۡP'``Xܦ*h_sohU "|CЭݥ %T;mXx0m$SZX^'׻7O|oz|dO7jfuV ͳ;׏k/ C`Z_UHvLKXLFcuavtXhu՗&*Cg4+)w^z{yZ-e4FP_ NH`MP <>yB_7?췊yBmx ݖ﫛.1&aK-j}<}2BDV B8T=>PA@x݋,^]*{w4iQ~i4igj{=m`VǤyYAVՁ%Mnj6!VєE:QuqjìsfM5(]Y4deTLO(;1jP% *S7 XEjh(n10cSFtvv,5gZaHA4Np݃4LWt! b-߷%0҉ڭys[u| ca/"4%7"`|Ia;mیXzݺM5$f@D JDK1K'~Z:dǽ=Cs4,3)f]BLKH¤6QMC&1>~rfu}h<&Ze'wnw2.dvX֝GL3,ato]?>gקO˧CNG|T|s;I;<:-թ'~LSE+`r^ŧ-'>רw7}759N>(@ChVr{,y?Y:K\rxIr @LzB 6X03Ci='1 2FKz6A~YnzrO0lmWQDHfzRZ)Q@[xWlE)".%)N0uND~B=HL>E췺W&Av?WSgނ3/($K"Ofy??F/*枲{pH%`I sd_"a1eb  GcL駕E~4a7$YD_/<)|X zUc0DPQZvUN\k d_H,_?IuT͖yQIP8ZMA|\S^m)c|$nIܔAEʄè(! ʳ h)ǽ eA|Q[҆R *~'3|uzp®j%$C7>әK`8L}W~4_aeprԷZU0Y}z!csZu_jxr?kwtD'Su-9K tx$>W=nծ!KrWΰeK׸=LfqÝ9E|Y×{;i O` x8ocCM=)^>1$wBXj=s2 s1f/g'FvzEB:픦Md-2#(@,Ycl`R]X,&{Ұrq(k5r[4zujHK1a~ ^$(1!a)Gg'cAƲa\%-XILiÔL2OD)2'wp@))w+p2W!zfǜ>fIqodu8VwgqT7#U.Ugwkz|֏KĭL8?ߪ۵"e6nz=tFfUdRn ⻬Or}_doK-柳~WQ``Sf;; ?jvvX li<>, 1pv_YaH CJa>gvӇW繾^RO3ahG߁7OfLfc5oJ$ 3J ۜToO-ذe-'[an jҰQT֛פN 65Hc& v}5Ua,==D[|Up$gp6P\K/^ +.l0&1%c0 oC6 J( G{uwkg#ɖ4lw_wO;S“^KW`Ms(E=hܪQf^(1L^4݃l:^WƆ-!hM=Q<`섃%t,\?ߜ=pktr0q(j~s}$2.lXUcվCvtgOHL1~fS/b&7W[fz4"۽IPݸߵ=wYb4`tw~;/jsGFҾeMol~J Cb0-N`C(q~B3EU{Z.:a Ke7Ƕ[%H@ON7p|K̬L A 3nx}|9|Ȉ͖ RJ VDw.l /9!׽}`i&etnkmZ=]-)ZXZ>=~ҸJGVI+ALl$_՞$geo!ei*D C-zǑʒO5XWT[qz/Γ̼᫉Oٶ!ɅA$]ߒ/"#Ѿ-2#sd 7.%Se[f `gц16ǿ Ӧ}yw3xn> Ib. p0GS'fMu/'ͽcݜl8k܁>Rl%4#d?laf)ςsl۾+sx5?m{&rYb5DXzPMHQG \ġB\A;Xfkw;}ѽ7kj cʼnrÒv[ˮp DUZ|ɽ J敀}i^%Rܮm0鏻zp- y.PPoqey>-Es|u2-h= YmSmV6q|&*Je'CNs1yܵӵ[w gLKm`%*-76Y-Ĥ\)p_CG⃲7Yܬ]ɢ+#&! ^:MuydN5-2$sfsս|*f #5EWF5˂ZRIoXV@> P'-ڜtmWWv&d+2|z=Zȧ6 jcaǨj_Mxι+}o2|, +2,r\;;>_1rW+L^}+$xJjH~}w~Q{9۸(yد^>קГ_ݔ:<޴5xΛnOT3ϝzgg6rA7Xw-APsy•vbQƇFJgYOt>_^ŖykQ #k6&qaG]7v{þ{(c SL@\rj_q0o}zlr ı<.Y{*Lv0.FTu#&.l3}I(\- ܯ|y;QRg=YOɤ/5AKbF*{sZd/5Ͼ]i&(o$중 _E;^6A }TknO Z._.qe* uAL՟_jsUk#z J w 9hy"f|ڍ3`Nuᷙ՜;wjV̵߮9~F3Bug8,PoN~Ţ[LcIi~!~A:?gq5y4saҪ+K2Ƽ*5%@33|Xcr4y{0~"B OEQZS\nVf9AggJS͹^BOv𥣴2N+D;݃WG7sJ+E K@}\g4$ ƒDDCQҥ4(rf jv\'dM]jG+XRה3Չ&8 \NKXUJm )ql4be "R?؂`MD}lM%*+o9{c grmδ{~;9fPE) u{Ө47Bjem+y0 ؚY)-uIrE"Y޸(kѕ3=h#sF>z}\o1|LAMgebX&0^8]xpC$~߭m7j1];$*q+~SPū2*g ,lZkH]e )M0u^Omx7zvQPNDw^{WL{OVΤ4 D'BI}hSԘD&]/q'B̫ٕ۝(eJ?֗󳄿&ӵh3:K-g09ceQĖRl)ĖR9[?mD3|n+bEk˥'prE [ $\!Vڦ'HDg$$Sg*XA Zb]{3]iJ$֫?fejWyn89/9"qp=&ZݎfCyL *A6F'h݀) $yHI"GA cRI >l].FD[mF|(+ob< * m9&>+Vu-{_K:9,]vD & L{uE Ө\vDI2Mj.K1'[xmN hQOz=ʢݏ!Կ>Nw/vrK cI#Cg>7L?ݑ?Vs'\//Ȅi_ޮм}LJ~Jo^zCRoHBC (oK[rd؂{X"?  Ƚ ߉0) 0] [yr̚l]eg-r(E/|%涵g%ĐO0|6Eq Uqb[*5/.50+ϒI/Ʉ+?S(^mj$ȒĖ@zr1֫@fh+~k׺Be=?֊gcDEsN(6;1ʟ0){fSUǔ"B. h."a,r8r,W'ʸ{;\eMoR)bΖ4lO.Ix;ȹU胵@=ԴTjNc |Xocu4 MFZLW@UxW~rZ~B=RzUpi}jNjSjȽ̽|  z}i8Ulk"V7^?,x dK~uK Llp@dCZHX@Z\жroqAIts:ty2**۴/٬ X5af{r(*$,ɽ}d _u/ )8w0dO7/qw~hPy'p,~4nfAbW;0,!AiI>̪_qƮyN6Va u6NӪFypf{"Bچ'rl_j) Ϡ`\#h'|93c* TKf/ j&>䥙.D{U~i t7yīr]cv]׮' w#+K2~>-=>َn^5'lr(#SRfO$LLE»|Yွd^ǯh]& SplG!NO \%262g0K νRmm-6b|gח&ne7VUߜ*}»D~\]`=%̐P  otǥ țD_rnɫ[Iq;^_Llei(^uU~6ևT% NC{ЦIU3T{s//<\{y@ N d;4"s/2 h~$s@!) ?M C~BSEsp{@,=g} P> i^Ye?Pz{򋟑)4pB'4151^G3ɠvkԑH64L%ltIp'r`"CQUPWN]z~"T%'&ai'u0^eQ-ԟ$afP P 6a^Rτl1KJ7{V?IIV MNτlCE9@ Pha:P-99ʡj3BE?Sˎ2oEE$*,OQUHuD (*†Z2LU0S< #2 WY;BкѬUQ5T_G8ޙj4 pͬܮ{{wr"2>Ongs wPsGl#S>>=&XpY TN^IA:&pӤ4#jssюI]$c?4O?^0a %q9ok?{Z贩Qi͜Zn"Ic!>%Wgl`(2ix֤~)ǤJ>PE =&jY6#ɺkJ4 EIIn~kӳf^5#s XM3\E{9qSSN+WGf40RVXB#PB]{!0<&R5:b08LhD51 &g-|*[-nB#L䳤t{-f<F-*hݕ4P,F< ;jޚeZVx>4q&1DŽi) ,@;AU15<7,o1kc+&k/ q0gh 8lC:y;_lml9r& _ַm#[N~s;*Dݓ;!d bu"z QAl$qD"י;5ĩcN+ۡw)[֜"ײۋV/A D,lv.E! 3# d @\v-^<"{'g`iqW%ϹB`yK"xKQnUt[)s>^nQTqܪRqՉrK",r$,8p&*#=%w>a+'1#T0I*?ZX Km&W~I-QT:V~fO_lW_otoc\jl辸  um9 +D'7/M2囔NoƧ7M|Yy-4S1ylOlSiǛ!~¬rj$gZՉ"²x8 g(s:^YTqfFqũJU)gkUa"d|XoPzS4Vty'.7 +F~2WEg"L|LTљLqpa)9uKYt_(LREE 5)cV 7KȔ9/(jj2"%ZnH3ʍ O|XoPzS4VtQNumRac]EW]*QɮM)dצ2|qiRE4]~!A%c:bA}LMPсK^ F{-E'iF{-B+uגqhDq?_Fͣ\a}Ru͠K&}x"HMN KNJʜuKH\af`Gw]\݌Ec"!pRZ\CnCTaوC ;4͕ٜphZ(9t~񰊰,}&k^ zȤL_*0($^wGyn1&P`˒\WO HEp{,opLx3$r2ʬSy€fkU7l\Qcθ e06 aN*+t9̩  dڻ:w4T%u*x]Gt5=;M^-cb{3P⌉vh{ӶOre0t\~\lGpP7rSTDWQ.ٺ~ǿ%ҨvUtoyW4h%<ɬbCU!\\9UT*$<ˣh8XN"߽aM&[//Re CJףr۞;El\ݙ-h3bʑy8ϓ*Om[PR+L ei!@!T lksz:ltD7fT(FQsfTfTait$VpE~,»T^8ɹ1Ōa٣ Ee{XEXbt~c+2iKۜ+2mp-DVDQtɎ?nܖy`qĻ?d;cbGy#7kj%Wxpց\2xfHbOխ^B`6'ײX^vT:3L5ԑ[\fbƖ@L6DXcraN=P`=oYYWZ´B3ޟ }BdV=:d2ر_)R5 c $0:\K}#:\ <EEX9v5,cqQ*"9eDT 3'ڤPXkʿuHdhD;lqOntTJ@t, I*`hTA?HZv*2*DcA #c䖪5V!I3XA~kSEgD#@>m+Դ'O`= HCX_a 8q2VƼ7]>B(I@Jպb3#|z| e4 X_[[$r@ӫB`--8xxEx9M6>U|wjqc9r0ٔ S-Zv&S{ 3EfQO’s{ ˜pC.nbC}LMТ+HZ76V",+瞿܋s kBZHfݴܙvj5S cWGܠ_(֤ @*SN+’Náϕ*aHVNyp\=7W?5' w+nx{+*L7*X$ c0"\7nxp]`դm)WK͉hH -h֬TƝfb΀rJ@~I3~vBK?,D$MTŬ", ~+#b"' 9W`#!ifw qϷ9ivo?~ |sL45-GXk(Ld*G{ aGdӀ \MnJ5:oEDX1vv/Տ'%*sė`xl| >? Cq;? [jEp2hWNbC@L&a2(cezpLac' L>({1xF~z,*"ۀ(0-<HK7t+2|-c󠋏1:g{yG7c- K!TUКORr#F@Dc<ѨnpQJT^qۓNͣ6!;l,Am7D|V:)SK'lHԓK;oJ"x|ۛ&$on3CSi7@y&L`|YcUB!BR*;>U[1D_8)@"d|ءL҂UݕLaMq5~wxܞT k7>-L+0u2ы}iGᠫܳN]FbO(IZj)UiA6:OK ;1?AbR:kM)˻Md>w <_sk *Dxm!(S*h΄+*<0U`bFЊxB3;\ldef gV:tj ԃq2\BL6@&}<}=-W!?|lc 6ba 3[DaJvK-Z|Z_Q-bvNUM=ԡo\MA,6 8^jz7}ͫ[gIce~#c#қomnjYtK3MwX2\G fKza5CC 5ulĊl|Ku3י̿Inޕ6;$(\~g&ͲATMwj)fai6ΘɋmW3=.U\6p# &'z`wBl2{A#,ٴ[vPSx.zgV:hĜ?͖E)(ܳ%Y-6;$(\+v[hU8yʫE^mtzc*׷vrɝ̰{tEt9 nK=!2Va"ox~ TVYYnBEE\ČuRP(*"[Y"{RΟLLTb:|S/_[v3e,=F_k-f![}7um_MgiO1,ܾoƻٕ];+c^%ʚy,ۑ| 2dTn.b^/ߺ%=$."Mɀi:^,'?`2L&7q$lfp;B~m_#yڔ?ױ;Mb}5 "hI٠5K+']fz5j*I˹Xϲ e>[Wx@=ވQˆR'u#KfW.Ϙ6{I1j ^vvg'1$Uĺ$*A_ضRV:^k>Uk kZ^oׯDm9~y:RV2v0 Ѫ1l;>ҟag֦*;/ ڿ}| $g R[%@0Ky/"_,Rzd#>ŖC/D֜'fAA*Ԓ#[4cPeQuʬmHyuh }nlЎK|U1?(q٣z zYW/'oq?|-}ۀW(vc$sUUjz])L/(H2ɗ`|פU򫛫r(ʣI)yISʵYkj.x'҃z̽;Ӯ;# xo}*viRi ~n-~wpXOloێP+#T%oڶKJ7Ķd!]JE %xm@Z)nR<"%f+ߪ+0w}<}/곹~/;o%ߟ{wUܗק/HDk[} 1S7@ZE,Tm\1AllSKn?S Lmdo|Q1|0W[x÷ZSt4 Lm&!6 )JۏhgAǠ_ø'vK'*HK)ƺ{$$ӘT {,4-J}Heq[w 3zt!_Oσw9A"h[]P" PndޑZ >t Jd"<gM_˨]12MDtj\S?s'0Հyh*#)T&3k |>L Ce&bޒoW|nOW|VlCmC@[Lp=vmyh7`+F|ol٪!pN_4El+pQΕK/ɪ%ܹ@;&?*?_y}u:fԚg=Y'3#ɟߢm[kRM?0ݯR|ǗpC kt 7 эF]zy}I%sἄ3T0V`~P!:TmZ&gRyAD3o?n^Q?Ge0Q_I}k,LzIhhh_ܭ3ۿ_|qff#bа iB1S3g2?_&?e],vhtLbXX!9 -f-y.3ܘŮA͂KNtzMo1+iٺT:hERlם;sdNm h|n57O^W`zuw_>4wmoL442zxdzE>y}z-a#Fmp>ʱLյ94 AN_EyH .ՐYA!N\orHQ>Ȅn?n~?y8) Gf_dH"u:1[ǴF2mMMCg!>|~o903A6L&#rk#H|.0?> ݮVu,||v>Z'>Ra >=!Eة0Y,tLwuH_bMgYZOo&kK:KO ҄{ !s?.nTb5~0! ˋ)EQh(sT1G!Ӡ{e"v|UN\Fv5cR,Ik$^ݝOm6bY3k TIuYhHb ;k_U٪~oPXěڪ'&!А$ꏠ2nNG]Z;gOL}ܢB/[)~(m&W{+Hnnc<>??%l%Т'\d(\|F .)IeI:͆=4\2k]cbT]jA*zjnME:v=) ?lm`oFH̝^DT[QYP^6,w?ƹQe?#%n 7ޮm"I^~2 t+;ČDТ{q&ںF/Y7vlФ.n*ȂD#_vPX2XP湫zL(VI?kh֎$\&jR\ަ<UL޽[M EIbY!%HIxeQewgo],KED)X"F+V9ز$5-HrJ&$?ngkmwHo2 !L(v=[۪ڎe J'k\,\o0=łtuS,% ͯl.'5r-S_f}_FRQ|yx/OL ݎבw:{>gzr$!aW4MRϤ nYD~׋n Tmτr6z?DC+bO Ii6d#{X73$Y(rBC80DIl`M*Whz̻}4"~iJZP+X%:5V4/t-?n%MjLՍm8浴4gP8۰bMNiW̺nW3`nҋLӏn#`˦朚Q!JXw Z!ۻڙ*ڒyB#1:iwr2Č{QlNMq7).tCAQB.\ L??,?@K oÇ[M(MX`TDݞ dH}#zbK:Qd(s:?hgA5+ƞT\5Tt&Mu-,}Bc/ŐfD ejQ~RbDYC>>T*,+8ƊDfED7K9 n9HIOZo!3jQq¿YjĿvRڍA%DPnNΣ3EC}e6 . ̼Th5B3{f4&rfUМ+`,iR&S|c(9skO 6X*Kպւ,'"nA W(CڹAl^_?l#SwU2N/43P.K3/,YK~ۧmU<p.S _&ʑDEvPrG.2CtW Ez*KPO O*KSȆ(sCԙX>*K+_Ge:K^GeaG QKrdU7a&IՑ +[H5sUBѩb-$Hº-|h8)##\j=7k"*67,tq6HM* w1JXUANB9 3Mh/f{AzJbN7l$ :p fjl`H%pxe|ߐP3p7}\euJwa]LP&}Cg,Sg},E.cxV:^C<مQUΠz{VIgX(feŌTwjZ 8/{}CCE7G׹y>Mts!7'2h*7+ft<:k,q_T$7>!=)[dw2: 9q|m'VsS3ޢ`li2x;16bNF`Њ`C+~Fm랙lhfvʒ @*9ÄZ^Y2hWmݮ,d[9+V5cONH_eP9dUyV*ϭn@Wy|wMYynn ɻj(X%|ZarLC$1΍,3v]m` ö/+}̻4X.Qޏ"rMR[*᎛F?渟$n >$)&lBH!p Y2dsI61U+@x~zvyP'~4 ;sܲ[zW7 iR\JnYk3A:,KZKIqĬKF`Us@vT`$V$S);*+,cι3}!̿KKv:'#ޑgOS5?aƔB7|<}F bB:}dK~- j^}ei26 n{n;|\CNq^\{X轇{x;e?Ӌq|2߈h.:N|hKj>5R*)֯̏PB+G*r| ᶀ12)T@?v0_&4SRIăyeSw>SZ9R4MU^eC a[NS(0b*TQe>|~Ufr}p5`Dqߓ|[2\)k{Y[o\)k%s=xoN*_Q}8m0Kt\\;RT,XKNNߏUȩPIʚ%VA*H#KdF? nΧ7-fwW"^)#k1k/x;ҸbL< P w.k$Ooo[Ch0.A{׼3ȍtzĔo=b7yLL}ge^e.zꖫny\m7OV/;QHo@p Ɗ_/fC%\l~ٕ*En} ]b:,Cet7 *ʁ&!/灊tOPLq2<<hb$ɅمOa~d0/#W=q7Y0Q'w&qKv#Cï/Qj)&CnteS9Uv_sDiҲZZkO[2:V(0,UX̉g`U XN|*ۼՄ~$&tE ~hGX{ʉ #jh_7Q}tNS7fU6pOWBn 35߷z Va Z4 E[_3d]3nNRdh8I,3y8u$fE}9y}/4UL;n&fҴcRx5Bݝ'Vēk\ijK,CUGn\}aV ~Mr8'ӂHEfx"*^|MEf{H'έyyRtƊ ˂'[KO4:/HFW+CX"5ؠ'-K|xrB ۻ5Cxe̾lLׁ)ktfg1ssdC lmpåɍ ; ޶L[3#* "0@oL]v Sg}ov.Pn/1Yg,y-=ZWuO)!lPj _=F"tm( }6@w =t+X[i9(k3eVE|Ln":XgزE1;H~[DaW<lUwdw_vaNx;[AnE$YdkscA",*0vB{AsCP,C-lws2zNݒ `fQDt#lޭBtܣRΤʞpMTчr:'?!h47V(uB*J+=o2N'WϞYjBY+JۆsK?dEQj.`#9QqЁ̠ )X 9SP<=Lyfg p)/Mlg{BM GlwiXji7DN!w9QY~WaO"Iok^CHs*9D%Ei%Va8Z.׻Lf]w^@܆7OT0NKϢ &B~\kwŝ+-M̓vRC#TaΪ}Υ'I~`F֕', 9Xi8-Vgo8cei)TҌY^ İ*3Uca t=(?1؇x;E("9yBn-ti.X, 7fQCM9w:’u u)v"djFr-֦;'$',!oOdux]c2}^x&AχsNAeJFfbtu%HL:m0DKV kLG}O YόF{"iWqYysW{sO<?H4HCUVC=fl [Ybj2/UsVֽTYix5gVмArnEp/,v&m3ˣL?ѽH҇!]yInNv_lVi\OB,n`~7Փ2H^ 7oI,i,b7q?~u4XC5oy H+WS~A6b63W-FOhb_}%0~u;tR dGGˎԌ7@wn(zKH_ 'o,xdi{Қ)1h ܗLy,HS|ho|πNr oF(PNjg!Rq,!PW{b_#0u '8q$.(敧&S@C7º5N ty V׀w{!A15J{k:&d%"b.U8Nߦ3F^Dܚ\qXkdV4:'"@"'@+vz6dR!nҨDpR 15,nVI6(-/H-ڈFGF<ВxIR\RN @ШΨw"qXhH>RgE*\D2=y4jQ"C-#Ar-ʹ %J(3 /0CÉNdJRjth4ȟ\#5d"ݘiZڸ{#;3Cx18k -I'Rz8 @(4V2TJs~W3bWfs˿*hΓl*gJyQ# k^i z_(RMH _FyaB%'Nfڑ9K1`;psr}<$bG4q.ɃTtdj^~)|b;9߽C(/]=@T Iz "OrC^OGm|%VНz,(fN lq@jQgjV7mU$WEBK§flжOӖI :Z˻۳jvR#T@x72'7iT āR!-Ί!bӢ9U+kh2$m]ʟYLX)MRD"ij*.v _ EV뚣3G,bEDxY  4vYOk{jٽ #3 &EGVU(=\qaϺz{9NP$Iu$ I5}Ϥ*t% wV8O87$7"-QίFl7??!R5|B]=AU\$j7wGX[Z8[{;23L$S3Zٺ%@bE[v~Z+hi"2J^;P($%KR:PrFGd\R^(%>5*0bDM-\3C2݇=j'-T$ )eibzx m:OSÃ̀t 19_{S?+p?h?QE,%&<݀;Ctҫp!^:YN pc+ֈ%fL_W#oNq"Z$,B @B5)iz gjZk%Nv%jX k pFaxJ/E.tWNS?Ww_m!rx_V? ϋ4`i!BGnn[[^Tnq? (neŽ)OJ" @Nyw%'}$%e)("J NxW.p#6RʥY>(i$}I!j9[ :=h?`ߜ24_OTo&M.ƾfc*z]}[=.?wc8~oDI #I3QRU´_/ ۛNn//O3L'? B?lb1/=SUSAT_G /qzu2\ׅi_|'_DGaZˈ_ Y =]kD7xTѸTC` ;Qb C7'AwJVܯ'X?ۓn~6%ˮ5u{PzύF .@o8SӧZ?x#as`XΗхƫ+űiZ6i V%oDI#i7sT(00 (q7=/'_IpQm,dNsTPZAB(sPI!I_ebpַ8ye:{uTXn "FɱlS:bP$MT[#)'Fgw@!ܛaF!AB7͵\srmDW *FAlP>SfN>/wAjuKDPqK[*M {؅Xz}Ǥ\_ *at2Р10 Bi助faXï=dq,V²︼-+m +(` @P @.vZܦ @IEclhnNs .@]kM+Ƥn_~ bla%%,@jBL C${yr%.T4~(S9nbURvȗ8;О*1t'E]x?č7C`ܾ+ ^d-7&,Ԣ>v8 })*)k)q SQ}hD|rFtx}G:O-Xa թSCK9qpru%`zwwmz ˳]}bV#oڌZ}Cԓ؎e!{:ePe$ f33ab9(%~pmo(uQJggR ) $aL :`ƌA9 `xVc*m`yb  34qz1T ^CT~E`&ONvԛBcaWwO=8tZ>D~Y$OG'YO ,T}+/:9ۿI0'qu;Xخ> d5VEUk(mO%Cր{yf}Zaz}j_@WirO_|GS}nk_Xq-Wˮt~rw1]/|G}<^wPWuҟ'X}}? yL#,Ն>y'3`jH5fa9&S'P&Uap}|S?n{dCo7&N->Sf R 5B\\FpX|;\gT9ֈ$ ׇ~n;X1!bX\ryzZ~P#GqO#㛓]s:<a_+|lU̼LZ%?u^x7^WhSZul2Z|`^<& &O;{+nmqXBx ( KkC#Z(m20lv{ߌeqn~W3hu8n"DU2uىqTP8JtKbzH~d<7wt؁LD-mQu+_abOr"lٶfb*PajJ8,՝?@3LgZLs k+3b?7*QF+JSca*ŸLOtȦvΖOlv=_śm62#meZ[-Mww3}bOO.z#wooIJ\#` x}}MˉgK k㏳N[Azzc;|6~ک2ۘ g6gOR4i6;)1l5g h /VwkΖ?=1aO.^9Ch9S CLj'FO+}CÂbb&0zb7ƿu1}ݹdU6R/NH.&R;r$;Jk7:$D,g~Xsx"ps0^V|yx'-Hv c/;aqկld(o;<3yVuI}!. `gә2ˉ?b7Krgm_%${ۑyQdNzU(č 6"ՋQTo+ #0!H;mCEaNY`n'r奿rnpJ%C̸{~uS fœof?~<ιkë%,58ix[0Tmr{1np,i,%nC otX@;iܯӪp47iACib'pADtDC'J[@d7TBSѫ|[M|!dk0gE$̬9H?Ѓk-;K3ȵ3_-# A#1E kQbrߡWt."qD>Hɏp=Kpj0KT.%0O8\[N18$ePWBY"xz;KWXr3L2,ߡLH˰^xR6J˭/M|]wXu+p3qS,BePy:ks][sǧxjQT)G+/N }y4xB6fi s\jqi>"HfiAⅼ޴3oߺ~_u>jwBŬltF6D{3bH-Q' $'te6$'>GozTu(79(\رRA48t!2@x1",Ev'dȞN-RkG(3-c3*O%ԚkiAgܰ,S1=cb |MZRHxQsM#+/?GY ƩFSIҹþl6 ajЙ y5Fo;0.ډ,}x*7WV"nN8kUm}$0 =%HAe`SdKC\@EtPVXRSP.qt=% @ 뭼kU֏qZc.aiƸɣGy$w{xNv&}ίح{t )ط`xViXlqݨ]rSǚ5Vhh&xh93z& 980) ୂ|;Њš &f~>iV`Zج?A6ٮUHcX/rC4~FcOq!>Sr+8+OY6v}a=MՊhJ]v&2/ CmRv/>s˝OYsM~ټK5;%fx~}uAP=!Na7$d]HV6Ɏye57'J$œgUk(N<ڬv{΀ qf֕[qJMX愕vn0k~z:=?WpsVU2ن-b9_mw{aƵ>`?&z: qQ'މ84ܰĶ]ql=,QbzG,t{ADؔ㗴>{c bsmcN8Siu=vTшږj|u{6`B`,LC} v4ĵ3~nkGjT]HD}8Dv9xk@P6 |`יTܒ_k3^WrEL.@w ,ˮw](eXV[7TlN7,8핌^Λet"$uYw[%ݰ1eiB;tUI Pi#  6XYo!BƗa̕af}g/2~aUǻŪKt넆#/Ԍ0 (°_q6h1+pjЏGϼG/_ƳkqLNWeZe'E?6R<;M )f(c\"OO..;yjNj,IvyE<΀KE=B81ΚC^ݹ:ߖṾթ.?A}l6Fk I.;) 7`0ą*;^WtLkxECn]:1G`G3+b ]*zTP8Gs JX!>8 /6;I8U- FZxq,Sf`<' AQEk_`SNtP;! \\Ȑϛ !0 >An3VJشEhK9ܙ*Zp#%?1L J6+K{HB\ :\%8ܔPnLUeJDE.pet蚚!PЁxtSrX. =kw g }q`*tDZb3 B2=9 hO޵J6 úwGl:}\.K1slnjAs)" /a+}<>4a)?#<~]=X%(i&v qV._}Ḡǎx?쁃ǎ?ܭ^U1=P_F;AcMbR6WʅǍGZG=*8R. o) :ɧOaޏߍ"nǭ*[9Mbt ϷyEp^,]-W8VN!j>GOn6">2;Kx r~vJdz7;iڔRL\o/& "ov}0 h%b'P@HJS߆x1yb͇8|yX:IT*Q6㊑F#uuPѝv7X< r[wc&r8-èøTq!ZO>>?xcN:wqm*kΎBpxRTy //v1'{ږQ Oxs_`GWMRIpr*ix٩Z";đCuO4)>4ǼkZZP]Bv&x#K3$ܾ7G0W 1-iE qE봊^isbITaYXvϸ>R G2#aT!\Ay?[U>[{Ve%a-ǡH8 AJ^nm 0B~o> x 0h5NAaB|b6~w92qW BHUkoRvRXM C/ӷӷ犡D Cl>N?fBΞDai !c]Nӹ nsZ27F%,7/7܇~-cfxȯ OOtkG_PKq'xx'!?V1?&֯z3jwCİЍ0M<,چ\.l}>۷1/ᔫtP];$w *݊z̡μ=:oá&MeU)5P5g?^)yNna6%;Bt(\Ctݏ *,2WRNz؅gWEXK^R1'KX 'hi!Mo f5L]aDt#;W2!L/gv#;P8Jn;tqx6eKJdQn׉19 \ɑ gGU9yZ!7/QaT)(C;db_~es8/_fV`xv`T%l=B ڞU z9K_̯σ Y(~/«mjNVm%ł79H雂KwEF$ڥlK#Z3wNCKvg~DSHE$]-(v|S9W2 WG uïdPߥr -G[lV5O^-R<0&s=vˇ$DgZ ?H~+_}feҢ2t]ߑfg0å5݁)hȯoziUW~hk_aΈv!ۃW"'6vH}, *A6trzu:ImpOP/>d0^Ֆk1;Cۣ$]U uv @ĒD$[pO0kx !V.CZ[ZCv9x%dltk0%%?sY=F[HgJ}Qn;J 7=%cLW =-GWшT\yBD i]ÍjbUǯh 5(κdK% NFkTSkQ(ZE54k<Ĝ x`p< t'`SOv6#XDqN7jiᰉwb?ѿUW֙Sm#ZQc<>m+餃Kvkm!\~ԛ5HI'-^ aoB!vuzkT߫7e*[)mvMTbn['Ѧ67_ 0'n#tJkۺ!o(5'=q|AE?<-7Ta{4RJ ve>x&L^$Dov2G612Hjl}T X#D@T1g39mTH/yoo˽]ܼZ'p#н)ÓdEGlntqYo _5 ׈+:(\i3W~ǎ4.r}ϖ\$ t§]qmYקSt˘%MX޾+ݶ4z ^#;ہhM"R>bhnhie^z`UOKn_tRYIӍXf;@ ,\2cbԞW/8k.Ne-*\#SA՘>jw}eئnavgMY#$D,?-t$=vl&Mg}~8Ys5H;;L8%zLO CGq_z`ۉ~WB1`kRKY@Hp" i%eјp@)g2pE"$M9r`~3*SBgp"OIyn~*Ѐݕ g9O>GEO&T@#zM>lhpvw)yڗ-vTzڪp> \-9k_S|ڞ545b=Ň+u_A"~FcjWO: ތ)Q^R4瑅GA/K2>8Od8qh!mF#ls*Ao$.EBe?9\S t4*gOtÖa0;8^Afo w(hH#oܽ\ 42G7^T]=R cxUDMD>rqӛK9}dtq1>AmTiqwIc&TCǹDdp,_Q`a1K/ ,YyȤŏ>\89k3Bŧm]|`E~9ںZ!bg}JgwQJoy7ʼnp8-wa:+݌Qe 5ݨ+r0_:y/kQx̨32nH/sq/q0]fzGpv_5n̓<}j_@tbQou5&VeYw;Fv;g/gH= b`p`FAp ӫS܃wP%n6İfwr[wvQV,g#FK@:i tWx<0| ^rѸhrj1a&oA1CC0ps0aO*ԫRcPWVH B7߶0%fG鵰QNGYph?@,-g! 7|0C\a^o`~Lﮗ_#oׁj5Mv z{uT_: g>wp1dؗBѕc}mRJ]ʜC+s8҈ #+WPc{~.lZ>TU6ؕ;cٝz?L[,; eT{|Hvk1o!v2. V]U~MV}UNunN2WNn^K%4R ځCAd:3{שa'nv;POu [ŁuBx)O !@0@,41Q78oxq9ߺlXevkɺ:8'̰ l7J6/Jc\x9}LbG ו:WuD1jd6Gʺ{^nyF7B^o wqQ<*3@DYOq?&=%i6\zV7}?t:z;.w<h'bR6 y'?Kwp8 "-g SZnfBK:{jF{-I癒Tr:i#'J&ſ|wdXrct>-#.v; J$;CʔtD:q-89l4yݥPJ`b aw2գ%ˆZDHա x[k=ġ| bΗIXl(uㇵ$dwbLB|U&2`ы +PaGDF5qgRnVV9>bgXj\y {‡"}p O˵l)H&W.׆E@>|(UF})Qg) x[K/,Au= v ,K:mXR#Xc+6&9hiASBܜLXfG&V :"V}|?}ז,<,V?~$66OL%#57|iqD}X $8_5OّaLTh/E䑪~?AϏ:n8&SeI@_|:1pn ܎#}i+u6cNI!\mƌ֏_GAFB{}tyq{l`~?dqxg9/#'DY/zͤ3ϧ"K"-~7&|,W\kpeW>cn堹Ϛ[V>gn倹V[9hneϙ[9dn尹)/jU\D1m^|.T ;k2LF5ZY[7ً2"Nϯfѥ8*DŽnaHnw 滱D$tWu ! { L q^&'GBe,+'\7J)t2ۇٕ% ~^{1Tc,UjN'pJ{yŽc׀;SϿ^r+Nj?Z ui{Zo[%_κnW֧ DF2Gޯrn":WG)TAo$ -YwXK:|F&"`ѾN0՞J@ByuTָ |p4Qtv38I+*s1=d#KC7#vXe=!ζՏ8-YTSIЏ며w;xR7<{}C#_ׇ5*0Ns] ) 3ۛ[ZhDž`@Yw Z-d<;P9g,LLM2*gjmhʜz!B .,`GMqB BUazPU~/AhjB vBy7=r"2(Y}՞(:pE̠R(/3= 8Cdـ32pFagd3TrFL8,%Jx (4`4{rz2:ra痾ݿMH ̑W;8 ρoje}Q^Ik^D@X$Xz1wZ܈Nn~[3E8aJჹmڨns-6V D\M.1ciYE4wK9/*5(aibnMnJ'F3尡bA6U}s-+ d3%& 3Ƕ߾aއ?K<];n.緫٥i숕) 8ߖ6 % Pk7Wd% Uc[b}ৎ{鮨%^6A*BH""r`ɢ 1WST@,B<2crLYUE}v FU,[H(1Z(PN@:( JF-c%.Tr%3iTZl4hcr1ϑ|?Yxߏ@ A $B@Eӏ( !<0Ee9-S^:kf"|)Fkltp6XAV?FѩoKֹK 151hD(/,kdzT UK7mwgp8)E,Cme> S|";x I0O]JO[ ⹍ UPNϦS|D*%5,C*J3 NONK4ְqyJ;'70s8ŁCh"텚o˃kzxA?VP#8y;d  )w~׬CdPSY_~۸ۺ1Vmw%BzKfF92) u6>~qO:!Tz z{ɫ|XM& hQMi{WM1KxU(_|1R`q<^?W)8Y̜v٢eapNŹQ( @'P!P[[ЊkޠMSpNcB4KI>CJ) j*ɂD?O>\)3p^=v+s;8cYW:g|qUHZ:),[n?2,73F:{kƏCrcw7Ȳ>Boˏj}h{gdn%pv!Ӟ]6d},[S$3dD}5QtpwF*ƻ]O_Ʒ$% st?hX⇍ݽR^.m9} P֔2Pk ك M$Q`9kNy*sTF[XL`>h˃%vdInLro̚LL8\\2É]l cWf{hY a&\IL >]%-ֿҨή2}rh9'oN3şn> )F`-CUvF-JLXM"WB*^L6[=X 5c \ eN>"ER U8UN f> PZ ߾֚B*L֒ osh`-6hPs6+Tw+ΉlҊ#׷N-Zr,Zb( 1'r0Wcp2OQ28YT"4 Ҵ2S4A8hr cŲgbS+F ;t~OMe6E}, Y`T-PIX`#^i^2_jEVVV<.5TN'*L ҋ)iV%ѡ0ĞHK50g UIbX;t(l<+4S1w gERShVdI1+dWׄ{ILiu (v&|"*˝^w:PK?X^|C(pS!KT)~kRWbwdQ#r]_~ׄOeaB^[& !r-†ߋ mCᘊS6+fGi_  IG ԋBnB5ZWjq>51(gC9SvNAMyRڦ+R' YQB ʥ\ok,51⦚TRE1 h¾;9u4C(J%`CҤ4  mɃ6N.Wg'5ұlY<󤀴lh}jhzUH ,=+g$1o8j-Z Φ-l@'/BB,hl/tF:_cdwE@'dSCPb<]#&*L簿MnZCJs`4&/aHۚ|= 3٦P׈d5GW,rd %c[l`yJ8;?'M>MYng pw1ywh9"s:{E[}U Fn5EU|4|kH)FY-s5h6FNe6ښÕlt6&mhm,ml,ilFcT)SgIh15-˶;ۈ=M'O.GbQݿʠB0t,+9^? A .cnXJc@ԪR!KǒI{" %mզLH9(sɊL+CuX RG㿝/ -z&$x7='c~5% `tM5yH/B$* ƪu}i$?{@m+0uH0Y7Vǩ T;)>qBVLgYvVxXhWnfq 6nYBdKdIU#`_S6qzZyuG5kT<~HȒВ Z ^n2Nsdj9( &FGwqR/\vCe8Md4. O(6-_ "$H_gv Zd⢳Q &ixMyd r|rLQkzD\K3dU0jbR17t ?l7rNШA8qJRPz0<*gVOSBaPc/be@W<$q%Ů^(vE1|Y"~O:⤟!aKV@* i*̏UNjTB'q' <=97`a7nZ0/61xF<1C`'8)BK](^HY mdc#]ك gԾ} qd$c75 P(m"w 9]{5y_{.0SV#N]& D&M F޶yptO=6KzS %` !Dqأ5W:N Xڵ䗅C c%"J]6>ZJcXQn|fo|A\gݐ\8¦ ;ې}BCSjURJhbC@M ;s\XqEwa4piQ5QM^ʏK+grӤ$oa Ra `ttLm}D8>@qH0:NQvpj4F8aXIrzȭD8dRfYs<$&Hj JOMVIwA];:)f}:aedcGऋ̳}GWy!^O [or@[QǾܵ;v-XG'Tyd-3/+Uɱ]~{ܩ/C?;[+VtɶaL\}gqx3}OH4X.VR9B B4'?"+2J7v޾},iS􋹛[ӳj33EǙ.&6OऋT;%SyGA|{Ew!!A?=-a{Y("v%-~;י79OϺ} _Y 1Y"WcJ4kڠ| 907˜aj0h-^%#XglQg}i@:~E>J96/_Ld t ]KI6h{&|H.0`rr%Ԕ$HYloz,a9zLZx2evl 'zWΦOkϤ3(H ,x^nDgҵX4a)`!=C9\K94gb :TP̄cY4yX"jLA: (^%7_}]޵[:y.Z޶]ھ5ƷrntD UDFY ؏0+tp*PػCO^o1xsێ`bG,{dQ[3o\( 7'[NzB*g@w-縗LwLfڕMў@VLz"n'2Kp|';6ϻfGb]/> /v)w&C5Z>< <]ٍgK]bfj ] 8dߑc7,)DZh'sl>l*grQp N{jV~sh'4dYxlO- 8,czQ%?2PA#}r&Siv:G="^Y`>VX% =@SK@j m4t۾\uAݴlo_{xG7D*;2^?1ǃwlL0+0pV1mtx{lV&|Q/ lu b^Vw+uq+es+ G׭YR~B1V 3V!V 5V~έ4׭u  r+nTϻZ̭Xz[_VtVĭTn^cحnncحb[P۬9dĪ 3_ fv]2sFK͆˂r6;4~!NO“~ IhJ8+ _xgDQ1̾ǯvhh /tƞV(q XH}Eca xDw|@0*s EO-5-(bc&s<&]!_ v\vrsf~{{e t _޺r6e4gGCh"B;`?cɺy~ޱE9{B&p$3 WpgcS00ѓ܂U`L;a?֣^?jMtczt'p#sR޵%Gˌm}O6fhBК M@wmU9cllj`m_!QTk!qQOOE]/^^ݿiP }oT iz̶`/kfN8_LVWx2}f~J',]Ǎq9B#x@"1t5ص2g VQ0ŧ̚LMRΈFgѣ `Xi^P/qfZ s! "4Jl*;A]i"В e+)}e*{t*r=VˡoX.Tp:4E_9xd[K):3}e[Ʊm$d'V:M?؝%rr;_ ̜9Ur6{%?(m}ݎdc5GEtCBߜ]CàA\sq`d/->4)S)4Z7w1R Ý TZNI%@8 BI;gd*}u+6=$+ `wcnpw/z !o/=*c<5>rŸQ! Q'ķj}rON]`jeAeK曋lp?y/&Ei#bgiS< Q702wX]܋HHf=lg-/T( ۫=$Lll%=tz G~cOAkEe[:& ly7νe>TJ7fqS zkB$V{p.tpɩ^^Έ2<:2ôǮ,?k]oDJn pQdŐj8vx|J>UnQca-TU|Z# A ؎vw_p7OnH*w 6'usާ nb˝BD]ZQJ1\v="GZ)qgIDڒNf<+"nyGI]bZvt2(LpyneEDvoH}fg­9Ibgh {NW6^ƒ43ONϙ`3ɰzrF_N_0]x3Tk&ùsn)i+v**8(rZЍ/As\ ; kK܃_ "N§FId 3hazp'ww6Jce&Z4S\4Z= E`hK^: Z%F@"0ki2fC /Q OxII¯^ &ۭ~1pR:F̒۱kXq Ůs69{х̖Fù{\ѯs)TNYɆ8o F/HB,߁u`\.7` KE~~wYGLvBB-(yف1Rl$݀/]cV'R%(@:>&R)O<`si@LVKN5J ;r;,)@E48ri۞D8;W)V ܡFXxe9nIf>Ow+*w2;Wr "0KT% ?`dfz L7(E=&` @-^ 2R]D+(E)W:R|s@1Tn @S;C.1:ZfP]E˒z9A'DԂhșr&vo>gp&V$g@n\z sn֏0!sW| JK"wb(d鳇K>?^-W' O^K(H-z gf99}rt:9;͏ȨùgbXu6 .\\nrbb$eM0};'l *s Ce(mwJ_KCSs6x›7ryڍ,E%\`_$ i̖dV>%RxigGE>D1&-V;onclK76|W=RPK_o 7 gq{t<7ep#X.iENj0 LFDqG7*f5]^"ǽw<[$LNti>l7G(xf~-Ih"ND9: dբK*0~ yjpDTnVWv!dӺ ;o쨴-oܣI L& "u6w{ 9DFFwa$QjM(1}KlxEsA 1& !܉≯M/9fzh0ُT ~%w/eE)ѱ 5T]cRD[ - gr3$rqbv< IK2J&9**+[m賛C*]2;ҠKP-9"reH>r[f}R:.- { b)w3C5au\C)ȴk4~5LrTvòQ:od}*\B 5Wܞ(= *Iu0&".tfN0aARH|I z΀uPL C@QӃz`O]i P*P*+?/Uyq7w̓}DN-m3 ʦrH HJ.]qH_zݽ 8\/W8D'T=TN 5-In_%$@ -XXp"i+5 ƐnH<'\fon 9԰z7BX8"sA%Ø$F޾^n/A%Onց'ҭ;3lCkv<ˠN/^ZD_BEzmo3:PEuINJe ̧総׎-..Xd(W܀g9zfrs߅^3hW{I<+&v$tw٦Xv@m*Nh)E}/;?@ GHMbͫh^T4(&rk<8L- |ݛIFkN n;~@<:F+5 č% P(b)&EA<\Q"cC*%mBvp\ S^U3]mU q"œTH.EJPYsH@$ Hz1n,9~#Ѕ퇐H;Rki@ V>A/IGOdV*:7сFݮ=gRYxf!%i( ;*i6&Ϡ|9qrLY1:ΗOCۃ>j iÀ{]}M;WK) dCvzI[w/YxPGM7O:>ٻn~E覶M9hmvqWTnE$c6 ." KmX1$|&ZJ: k Cv:7+ d>*{o3|%`ocXM!VCF$@o7qbiHȼʙRXHI1CuG4^#kys* tqAu)*l{vKJʅ>ReB@~ lV>IAw#pRvf~qK\u\|Q^Gdji܀Wdoy X(5[5nO"4"M xyxN#]VOKCUbB"*xqn W#zhªc![ Qj5vpؿ]Ⲫh`;fK!ū\n뛴Rn`q4e&:Cͬ9:?t{㲮&z\FQ*΅?dM2<64)o؍7!:Jq>J`-t'DsP-Xp$7B tji8SܛCfƀB; @}@cqJ;ސ{ iLE D^Qa{}v{{|1쐂kF{vK5vd>[in v"1[a)1tCʶaokR[ex#^ 9N֏X#%67cN.x-MLU*ܱ?"cS(nF G9z4D^vmյo#\vbH.HF'/@,L&g=?ݴ\c= y"L QQ{.V"dWGg׿Y'I1K7SM&d 2b犵JǢǴ}OJ" Ew1ny L \D ( QkpL`xR"kFDdhvQbIbTB` pt%l1&z@!ݟL A đ8Up!]*Ee}"/ޞNm[0ݗ#N_~YQds; =C^b^NaM k|W ɋ,W"KEUCYH˲\ !\p*,eIzFoi08 =_}ʟS%D~QJ^_SԮ?7ӳ>=_Fs6_뇱n6Bⱙjr:~ }I@0T^ϴuwj\#-(UTtbT}R> ]]#ƹ(B0KeFZ6eKN`< ~'Y.)EW%;O{%I~U5o,sON>p0H;{=9>wexʣd+]Y A&mx"[)U k3B4rUPMnS}xe?~rwQQՓ+}k*p N 4OW“Nq|{#O8#9AqV ɰYXΒ|XZKnċK(\r /5:CahTJhϭS> #ҟNJv@8=;;9$e7%d|ၣiVAʱ:-w]NmbًܴK|]CnzQjL}gV5C/:avw迊.*#J1 |Q7+U_X`V3׏ww_ g1glwAK`֫:dX):)g :9̓CDt/]u;$J%k)Zs]T( ,? Cfx¿K^K_'CHL:qL8cSѱ@`DV 46d+t/s-fC,OM#Lڎ`kb;/6G+2)ו/ww]xCXB0Cuի%CzXKƆWR1ٰ b\)Z!TZ_L( )GK9E82ɉ dm!j+9M]*)Wizx%IA%G{F^YH_żws<,6w3%޲ix >6r ➣4SPF$tvbDT0syX Th5c, ꮬ>{lZܺdԋJw`j^thQ|H(H܈2$.|צHs+yE?Jsj)Tx"7`w׭Wck&:Zrg?/tD=&~@ޭ]+טNΎ&&hmFD3=FT;)~~.\<ͯR[-rYKqڸAeZ*묕B&֟wD8kY0p:zE3E$mDRy@n ,6T"6+(Y~y}txp[BE)a7l28bOr 'DIDEA:P6hWX*0fXZK^5'cN+ Cy5Zw(h47X#,\۸[ȽpP7ȥ2a(A1|DK?srt\ >|p/v"ptJJUpY)!Jhkm~3VL-+sX/.h 1&z#`5؁G)<`d '"HjzNUGIHhR,43rJcGtkyO:t+~x~ b2Z }3_ eV݇4G".V@eEvcQf1]RHpΝ t$^3e hsC,қCNG}$t9yʮ>\ۛ !7ytu3nQՕ^p~V?[{U=BK b(C0~yG;3U$S‚v+1Qy"ag< ;qSą)A |VtÎn">amr÷xKTXF24`$x`jwuVu4CluQuFlb↰k C&643MjZ+# O`;D6Gڛ ;v=ҙLG; ݕ/2^sAjt|snЌ9VKLcؗNy'N:xU V5L1|Xl[ŹWa#VhZ:ѱ7ٸ76&6iL, h|zw X] M 컙9۠L7SYp3[?g4_e͔Je ?ީANYy:t9 y t ɚdt !2qЯ*t_bH->j5s͏oKB,zڰ{@{;bon]xi]/Dݸ=34LwWLSGr.98o LJW2WͻuU)ކ m҃Ş BJ(J:~"t \*åR R)b㦰TDǶi'8e;`L2E3jF=/q<~>Ϸ۾$m%Kf (WƬPoVC1~E#Wdހw^_ m_YΞjcbq>u |$f%Y+uDߎ9J岲& A|_K֏ r*ԛP~TZJ5X{I`-fm_`L5M@Vo{.~A6 ; egcL~2)ܝu1Qv3n J[^mqG "Х9zF%-i7HqXB㝻pSj4T|K< 4v7L\* pU]Z 8ӌ*ayd|Bi6ڍg9WU+yօYs 'A?5ADvP5f kc\{\kiK5BaF@McM郴i샴)}6}6}}}}֥Ү¤6}H q}24^#n* Plo"?Č~xEbgIDgHX;\p+g.mR7IbH0$8TAa#=aãX|.Gi/yk8 Ҁ3L 0-ʸdZm+L>~0'Ѷ+5286г+0jRZĵCyul3_wM1C=:<~J2!y~LUWuDA:˻&fA{$fAQ$ܗsFIl}x\k>B0mvE3 hHk>]]-f$tYnyH4 3,>:Y-.טr2tRS>-ע̦jq]֫h=EĚDAƸ<8a\ȹb1'a{+vpZRW>>=캣B`щ qN_zsI4 !j^br#dS/mzޓF~L8e+*X-1hB`hrΛAzYv,~qt4#ѩF2V1hD+=K~TcnCyy#ʁFu6# MLI+2n^θ+T'LF@5Agم`~S}d| l5ed<ٵC2%zYYBj#G>a;+ώ/0*jJh|^Urg녮\gL8Laƌ J&vw4je<'<DEMl7E;N`\;_].7[,d6-x{o}>z|Դ^}(b`01&<=m4mZyv 飲XaMSݎOvd/(ƄU&>0:QDcp^drзD- k%ҘXv xPZBgaY[WMc1\{O R?dL PQ0Aݿα]4_,n\32zc((ߎg(|PiOZ,Z{MXe*h22DavϘ&$!o$ݦ(),}r hO2Kly"< q`!֠xaEgd3hˌg*)twL|c؍hSq+w MtʤoiT/CA{oߨҌ|W&82:JMB4( 39j#S)S :[{Mvy|BFKCheķ‚5Qb|+++OJxa!@ea)(~Ic@C Yg>Ϙnx߯[S&1 ([:hy"|Ӿ ZIS8C\9y{4{_2V KhJyhȱ,Dvt{jĔqݵ=Sdq7T@n2ZQZujaJ5pM5Wgd0Cpfj`'H3y=b%+}q89Y$#})*)ʁH}Qn5p/ Ivq-Yo=PRa8*P p% u ;jP[PZPPu!;ysg.HZML93sΙ3gkO}P0%N"Ŷer]I O| xs|xeb2X~kBUȕ͆&l(= cbR.լ_4Y+`CPzκPC,B̳ YUQhBo3.%eb"9-kQ-B9a4fG=2TsBڏ F z,Rl[&eJ]5ntVeHmevvuveHF+ۖtҮ-!͡]m®,Rl[&1Ov[K5fs>d8C-Wi<G\3 j!Mç.,<$AFQ_ AHpvL`A3$_`GVdN†3z`UxWM'p 8{#N!, Wt=K>ImcrVZY0úX O zt#E(/ ij>Ny)W* L}lVȷ'Lg<ЊfYئHؚ3  ȈU'YؾP2+A :x%K+29rG=O>BYȑ:6-y;vK cOԙ\^<,,=WB*vn|mzϠm=++q@tP-~yoܜL+=&9f"Z*#p<9Jѹ6<h}d,E|:Ө+sE.iLƘWڡy4:m=Wz~Tz"+wYzy1wLB>aK7=pam &BҠ{*|l]&TW+c6^}W|3~y~FƅNsYȎw yQΩ'EAA|wEװ(r&9LAʊc\vX4H#'o'#G9~FVC5LLs9 'O-Un]I{y 0!a9ޟv 0(b\k.17U+&LN&^dc5SF O&9˱Fxݵdr!~0TD:.NK2rǡrB>@W^>/m4nM{iQR0nF-(^8UNxBvGO;yN8__ Gۥz$3g/LS%lUL\~&JJ $ڹUUaiRG+ȋD1|j>L숖xp8,LmArwkq|2gGjJIV`X3壼݋@H;ί]٘h~,9m/uaN獎I>@Ѩ֏zKEU 4T6D ʨ)676Ǧ$Sk޼,o:BsCP&FOȱpWRJ]?зEc|f̺|dboDǁZQ؋P UAJ(0y Y8OSX mfXR9cK5 _Uc3[Ge$~JBՅ>JTR &Bas3UZA@vqFH7vT Vxq qVWmL6nx<*OFWj#õFs>texMmVr :RMHa&tBL֚fdו &L0PM0 Zi:?M ;mOuW=<9>peK3pj۳Bޚ(*$OJj=sP{+[wGAWѴjCG>ROq8Tߛ%ߞܜ&9}- {^<,ͽ^rAW3 >r#Ō`WK]zRj^I?\Rp^Fi^R΂/̥7W\̥ V8 ҨrSih{70uV#%QfFP K #*N(uTٛI(NlQ)]nP.. c̀#i9]3_8AxF ꉲARF #(X%ı :+^\aPMTa++.l`Kjƭ[|G-Reu¢ VxpgN~tL}hiDSoܕB>@0B^hj7M!k5mhUW}@e Y V8'?m.htiR<446S3N7yFGk5NJH%g'0+ ZQ[;k%̼Zǫ0llk&0y|%WCB-DJ+aWF'zQU 7m9.r`޼qeK`+D'x | w7iқ d@ j,1|H0CB-+ċ  oyN \AnM9왱b+x cE! /fb5hl?ű~;t;sƓEpрNUHkx4Vtܿ59_֚LLRWjBrB0F.VѶ9JZ~G;svB"B hS}^NڴǷm*bAR0SANSk%'てDZW/wxeIRuv9; o"Mi|M8IC"B07\4.SyNc  :8Bk.QN3Qcr³Ng( ( Nm@es*FUluzD  -|8X4K}qL0k!"8B /6!cҜ-d(6Fʼ}]4@Ý~QL[jfoRȣ7`"b`,&xB82k-y#v'guM5ags5jE i -|4 C2jڲO4oyRzr>@D\‹M?S~vD]tjv(9%[ mvח0PZx (O|txr"G3@W.hs .Bê4hKVӜHo YYئH"~yˣ0s:#,RlW$EFx/M{g\[I&sMhK$Yp?&''h wzJ[1GaTOi6t&"v%h';6 S$b2]w^ wTf(+]i1n G24 9Ԯn*obRϊOzT˧Hgzp "#߀ɉ$ p3ym5h<3vkFϴǣvٞI$۞I3ۙ㙄=\3Iw@K= -HcU w^ݚghK|H  -\c 7>tlE87bGՇb[]\)weo M7"٣fgbB U?ѓGkq x-;O% 7R`p‹F|nγo[vnKPhl,Z0E#>"޶x` Niv VZJ /ๆMZzSì@ZZC d.܄eSE\fh ɥ 7 qQk_b|Bo! MfPe$(0E$E#=>K1+M~A.БF["C"b%2H/$a%pt6CϽ\.5[ &-  Zq v`2ȦD?cqxPJ2-!HOK>hlzCJI?aq͠@ PQ^ ˋZKiM!fpM4+4-ض֥ R|j;$B ?6غHq>D*%~pF')9TPBl[3 aGun3o)JX(C2V!h@5Z<:g!?D).FE:hKdL,~HJH L- "_"[-DfD0l*D.DpрNfh@n7jlX%e g0ء9Y l3aT7:D^4,IkPS5𣣖FBCB ԏktрNf#ʅOƫGrظ_mtV"pS/P/w6.r xL)~o'iz!ܼWW=֖?O+}͞m Wʅaaóc3M>-GkeӒ]]Ϥg;9d,P#]>* 5-;-6@SSImTRR};Zqc06׆+U1su9 *Oq§rÏ/<> KPP 8rK>JURg7ɴ1. ]TObZKKPğ6UtI ȱ|P%JS Ԭvݍ-# [-CX;F_T!ruי YV2XKYBO^6ޙ\qU QZyẑgpUuO gf `k>C\iʺdtkgL -2sgvv/tV :l+d֐0$p0o]&N3D e"N2U,gvU,.K l,GA%$4c9 y9z蕈٠7]B= 3W9UTT*b[m@ C}1IEb5.ڜX|?*F2߮+n%bLhhfY!QѕK5I?m4lt20J/L&8W`8uU9@Xu:}݋%5WJ]M̋W~pt X6;Hا0ע !ڛ Lz͕(  cŠP. NaQ޷ʙw77{Fw9]qF<eMqY Up~I. :YDj錦U7S-sqWSu %5O-_~_U885M2^ ><9rC4ATe92@:hXXczD ݕ+F\I8ˣçPH6އQFagE*'zmb}(9Pp-qHcEjZ.I$+ ̀:RS9<|]}6&/2͂%m],hL4_[2$S -EDriLFȶO6A[%HIW AK+dRmsHjlx Z^!3A /l Wg.RWrLv/EֳjNF7qXsPAI.gq = 6JWᓈI3z$,u@gSP"Q}XV|{:^i(]I{zQaժCFj̒F Tz c__DMD:"}zWgib2.>4!/I#GXcfsFPy+\)! P_tQc Q5?>~T}_(ѕua\aJqZʭIA5<+3whTv1~ n)B\L3Ʉ2J qaWk U{jk$(+X\įUy"@&k`PO:F]4^$r@DeR%`bĬC 1ƽ2nf]V|Z,u#BEh&*BjfKHCʑYUݐIM0C=Aj},M;O+*_o9@sV-!-REkZ Jݕ6dIQkl8lى1A:οz6~;mt7]rhc򹑶=&/t8: *Ų3VЉʵKKA\W*ŘҤ'i53͵E7Rc#X3@,(8ks<^u,QWm s*V'Bd_ 3ad^(B_ F"j%wFƐ-hċ 9RCH6SAQo$ mͫl掱5<2G-| jM*5%IK HT'2ᠿ%ZgߪlV+Z:$?VU2IUܤ*1INM0TC3@t*9mTr?fv"|7J~~+V"4S0S@;} djRP!VTXh8Mɏ+~LUeriN }ğ-Mğ+MSIc4iL&n4IO4qv9Ҥ)E4gHPZGoz0XD}¿4H HnuV5G9/?JdX|>9*F#oj}ejTZ[ķ61hOFvV4hωRvNꌕ;@%sR6|L+WԎ Ls7U&8Y't.nnt.u;L*AF1S,%fی#w )v1E.SulB`IUqZeG1ʰo0Ն/͆ئ^Ct!j7Kv{!4D 7q!jπyhY2Cde n@#՚WrTW"Ui ˌLGq*-P{1Ѐf:YbPbuՑiw*+U~RYQuT_\p%"(=-^=5[G+SY?wW#$)qW,m7J-ؽC$U QH52`*$#ds1̉WiTq7]P]-X#%\h i5V' XpkT5QKy8fH#$s\03ܗ{$#ѳꡳb7f7_)W(DjܙިbD`1"rNe~ƿ3a$NH3J^2/Tl `b9rL bY:zwd gu8*-վ_EƄeiq񃾴=WëOIMgh!TA"vp $~ 9aM>,mbpՌJp)Ǒ+:1JcrJEBLNպHjL~pq`2dКV?,_ػ_ ]OS:i&^xjGr͒t]SdJYe=%?[os9iׅD}t|2)D@ }GaQ~6mnᖽz@9#畆~/ߧjo(k.gv_vxY_2)+&tI6Sϟz^v1t_P _("׶ЗWl8^6KKU=_oWfmϿGyyM (ǤPuT{MʊP}&e*(P(}I'B)iR5WwoKJuK@pC0,KH}ۤP~FPIɄP^+&By_5)1)@(zI.{gRP~k2)I(?&Ij<|b{pq1c >0[QPu3Q@ b iȫ5 屿:uvwؤKi==W٢z.f=J7sEO$=}6vȏu`M5ʖPz5ʳB(KBw\6QM/j?F3zIKMJ*0)Dža *7)Ȑ|f'g~6g OA!fC(o~PSl7),3_4)_{C;B9t(_Q!E&叄l 7cf8I Y+Dž(ϿQʶ"?.v14 b^?O=;)[=Ҟ|Aj%I9/5ʊP&Ӥ2)ׄ Cͫ{#ٚ]H/SjQ1O1f-YKٹdu4)%>p/)\?H?H?Ho%}ՑH/u#ppvKG֣ǖKmIﶥsIÑ-G ;%}hMG\HۑH#k濵x#}4􇜾nq_K#N_w GhWeK~.o:_wǑ^8}q.;# GsIۑ##o:t\pGu\9t-]&yul3ۼt%G}!G#\O8cGzqsI/#=vWG\t/8t|ew}KzHؑ3NGsI_vȑ;H6Gq?H#}#G>GsI?Hԑ#GsI9H/7;;r?E:+:+}ZuVft}kiq;DՋ=s;bޝwWvW}^bp߯<3g^s<3rṤ?H֑.7g #}y.8ҧu"Ϲ髎1Gh.#G#}ՑG_s_qKvؑ~}.pc~GsI_u‘1w%r8g8ү8\ү8G#W>u%)G5]έ.bs;.b"}E ]1'{wfDoY?+?NY%U=.ʋwK M6}HR:M&) |>>;@/,۪Bu.BůEN~8d6P j*/T̆l|P](~!B)j>)iy~Ҡ<)_;WICܨaPZ{%PKBy9-FeZ_|O'IPP ByVB9Z|1kca/ՅUD[6 E4"&$-it."E} TKAC|(ROR 񡨠7o2gm7g3wY {V dIq~ țWRZ= $Sr:ۖ·@hA ()rI+9_ҌdEoӜ_]@Wq VXju HEIYM#m`=$gh^ЦIM{n9+[_䝤}D6zc;ف,sHd f."(9fڕ_rIq~ȋj>Tˊ>G6~dN)߽6lR3_KIݺ9dI @)O-\4Z~_v۱5dy@WZ'=}E3dAq>#䢇}]տ H |uz=K> ! $a1ui )w?d5(,%ᯁOy[@:F$ޯ^J @>W3"3@fu79< OLA M{ 9 C |磻/z}cJV@,@?*<1}95zȀ UJ@T|^BJ/d#vV8/G@N+MċlJld"j~ TT(RQHdYyHqDRPR;CL_8@383yEs4}j>9ƺ6݊ 6' NѧiU4Jh:cRQ p JYq CnaČ{"~6U&F1#G|e:s9oo"lo|e$KRT#VP $|2vZy'ڦV]!JsOh4ąhe! 3&y4(oSʴ엤ᰬG}Tҫ x xjsL N +{`4`ᛪFbzgf[iNm#֐O^Z 1 = 1p09H竆dQ%#/dfԪ `N<:Qu'Mʌp+s)TqSbErr(ɨFq=De$sLQLP%B0[49y6/_ts Eb$#TUBJAm;|>` -6|,ѶAֆ| /PL;fl|)yD,H>;hZ@a#r&(̑Ys<]E4Aof,XBSJlT0FʠI?irÚcP2B3] lhv0[p$vT1;Psb3L!Sm)wBpa+Ѩ6:J< L>&+ j2/?^שv"V^x봛6̉<|N+B݉-ǚɴ]kU-*NY7'V&m T%A *;<>bV械*'%@3 lMFJC]Q Uђ@u3j=Zl8ۇ-z F_bG\Jn[bSV4%/'doex:s.K+U96Gu$$U7hR-BwUr9ƒИr[arSLa{/1z# b1Mě$#GrM*O׿{ؚqrWp_So'EVO7<޲s{ /ZXOcOIsOM6J%ONzO?x He[wfVK7[r.MӺNY*v͵F3S;GԽ PK]96tu h portmidi/Debug/libPortMidi_dll.aolYvUEUlٖeőʉI6&AYi)h]z?( #GQ(C=T(z0zʡ)|!Ǣr8rC%iLI73rkqdRL-LNnT*O>O6p`+*/}*ۿ+*cT&2T,Qʾ/$WI=*'B8I%ߡR/r2*O\y*RyC*WES*PyϠT~rJoTOT,|GR{J1@FJ#*?Q5;T~:Eg Tާ?ʯ.QgT~Rs*+a)ժ FsZ*Zj&Jf̄ҭU:պYZ,j ŏdRy,E6,l]e)Uj*nV=:˰Ͼq?+V&w^촻f]Z܀$[(vA6\1ۮMjXf3F۾Ve_'I^< i^)WkNJ+;j6mꛪVʝ~I߂ݵ݋f[ر:cO-7;6RaWDRnoDvr6tf`>$Ga]Ө[fg$)/BP'B4+0lvEQFx)9vd}͇mF.K4}:[pjloln~Sc[v0;]{B>IS[݄-߆ q?ȂSn82Xn&B#[>}i@F~W_& l'9bXi2AJTOTJ$(@5$jIԞFp-qe)&Pt42 c&g&'0#$|C#yd0 = }N) UW\&Os_ǜ1iy^.DNl2FQ]7`@ 9KC0ӏdf}Z ;!p3q3dtZ[z@p@^e.sg?lR>ꫳ9 1ǃsvmC6XԤЖz*kKd@53)7 ܐsŘ%0scf1MMI ΥRB`˄@J#-FJ$LA;^@` "{^//4$<h\# tR 9Ibyd7Aou$#F!#W)0rc c$~:% !7B!!" !d adD{ Gqu[7 t1EѓYy:x9d sʐANf5dd:̃klZEy> q\ZT~5Ŧ >3%%]MC >Ϊs/P읞VYRPw$j̸ڟMYL8O]FSsPRim=U&e@ASڥ#ԌvB^>5Gz!_bkv@gk99m}v(P5)7-!'AW((JDxKɬfa)3خ-A,άDeu-%RvD3Ym,֭0?~ $_\Q*ALXcr& rRvD5?j3WQq1$$=Hz#陊g2==Kn^Y) $q$}@H\ $d#-_x.Z=xIs_y|&ӕ ެ~B׼uU 7һF֙9sB.ŧj0$>k&@hmt-e&&:|Z1S};F[01SexJg)BR\KPK]9`lB'portmidi/Debug/PortMidi_dll.defm͎0y @v9TE&}Mc ;3WmSBh;`BA4K<Kh:t9=H:׼}hVt:bE4 JJ!p2C.#'߉r/~ͩط`#M߰oV0Bf"KPZ+q(VM OC3~v'9Dd( CydܗPnkI|%d+?Z]kHhb@,0"HuT53E~~C5JV iL>0 iIy/*^-{1w F@;yeE{=}Fg.wBP+NRp;Y20gpFOB(돸mJRemocDpˮႲso$GBYy(!xJ6y+<0'pybwVO@m[jZi*8WtyB⽲TV]0qsjϔ7&ׅtOl*\o?^fsϿ{ޙ\. `DNA 5\>yKcߜi(ysJذζo[5m5…ejO%*4J]Pb#|sw\A>a 1iLepVȏ E+ vG]|x+ ~\[srU%r\]&LwY$iWrn [^@=L|&abv|8< +[v(.*ďUr,5[ ֟(nJ4JViI\h͉YN@pstljGndm;wIk0:nFm>+c3o YCqDdz,2k XU"i?|qϽ}foV%Ta=K$'^oj BH c(L)K7b f]n@pүCďZN$æ%FјDC-g tu*v62t/֩)6K+m phZo7QQ{xz.UXT]Za?;64$~D>ba&)`n ԉ $'NC,QC1x%gY% 'ר4,L4DcT(eں ?q$9#soew#y L) ̘'N/C;dMƓg <`]ɰQUqf88DfpJAM jɢLD4'aGvKJ)PO3x8#bc ]Nj mKeP2F2oL }3]҈ʴAu/SLM IB1SIrK` Mē1Xup "IK%FDW E#{fbғ[務u{-@@*JeFpX`_L_TO*\]ֳeAg Xj̺+O3RvKQLB>91@H*m3 8<ˌ#p3St\N KV)׺/ƲE`#-{-/`xUD_wwX` =F{UYɗx _lvIkSK|˗T&_CA =+ǛkjȸAYZ%XL4hIm&j4.3 M4du#>İU~T5au\"+Ffi툥-~P"$͏'!\&niHעɮТe_X'k Z!M%82xqoR 0"^Bi݆mzm0 U+Akf%5Nl#<} lX:Uj c^Y< KM}' HI ;GQv"D!}}yѭCSXRa<'iQr(!2<#*8j'wKh)"/ZPxI1kqbM&݅].s9 " 0s(5JYj̿ Ҹ!aV΅cKXΔkM-b[>>'5-rxtJrtL%H|ՍMZ.`=sbʣ:B(\ S6Hm_ %k0$"4F\_ b{=] ,B+.n!l "Ę| }f8i,F,2r꯿A/e(:u~ٰD {XHYܿttb;9,#|BB#asu14$u`*ޏO3\.S Q#ܬFlXhtNQ%Hgoi;M:7Bf1|k;Q)ϥ+4۸hj*\&:Jw3Kt:H9ԅ2er#~ni -Y M gcVQ Ewξ6bey70CLmy~C“n9NgL"OPF=jemr ;! OP&Anem"5-BA'*ڭnES7:ű)h9⅚$؝DčݓUeh'~ҕ$`PC[oKhcy]ᗪҒK (~+'Nxx[ Wn 4y¬ BM1``+-v9^@;MkY6װB]e[N&Q2*^Cl'n >MKřURm\ &Xs[$:iz`[/P2!|(1hoeѯNmm@j A'Dw %OYZ}x`237UL-Iku|ⱊ𨢑* |Yg9Af N}'rС5ttezY_Ե=Q$plJjhgnIs[%:n:PwxhpKh_2Q|Lѿ4)YĂsM++TI 0ێLFndq7L]qRE<VpPI܆ichs3q]AFy|?K%7j9H_Ow2vMi]zM|WQp=83ڸ ϢN}H.Afh~< 6aP֖᮳Oɛm9{TWsn9%a$쟨zn9{oTvDcYY9q% [Ξ!$T?k;YA7ϸ <[yʰVfDdКײ;G"@̡p6}`˶;ׯlW 텧ڪ)eJuH1'0YEV^FOXct0õ3t}G<9Um_ƺMB<ԭ $ێo& Aq9AvtePXx"4*/^1;NѪyXJ_Y̋2:uz)+ !5O2Ct΁@,urVeJU^kz"-a Sgd1~[B#3e[Φl]r/(YlT^ r xa-/i7XF T]$$gr>T}~dawP:}AQ0̊ beWHXZ#c0nٟ*mZfmY\۟('c;Rou?i Na RitRov+CXn .4}+ޭ,.岔T @[LZd@LY*#_Qo-ʯs^N 4ł&[1wKJ%g((];I_ /h̲"պ.Yp~hkV.h4 D3eq஖?#+7柔s1JMpf?͊5៿ yl!I揰->ڪm/4mC"_^,v9Hb_c_ˁUы \屝,19}cq?7l}ᨬ<*{&z̍g85̝*Rۤ!/a2 R,JK)ki\X(GֻhF dKYĒs+fx]{V(tƗrp u,'=,Mqʸ̈́MF8ulvi;J< յ0Z!Zkxbk9o <,V0 Q3-# 7.VR(qT;Bm ieC"B.m}2)3ra6KK',([g@[?w=sKtNk- pŖ]3 ]q[v̌g@{?}co_}񳴙iPb_G hֿg鲑Q&.vL> Q> rPMo bDb N];=ϊ,d~{zTCwA')r4HF{ O kfDˮVb-W8 6K Gg֫ fQ, Ѫ́hm-/kĢixL{SEA˂ȡ,4F$6hDYZ8!3M<741y0[CrO+B,[G)FsڞT&۞m-maU{{QX"IQr*QNX)KXq߬&`l&S9@':K|Or=U[_H)T9A:VcjQ2=Kx,Nc5H}8l{23б~X@ؽGuf&SpA?h7b/Ww=[<}myqܜstaU|[n?%5u=k~x YN[}FPwtKr.XfYgc-وa V 1>&/1ዧy T*j/gZ[}R)0v)G %͸.euQ:%Aco;;0{[)h~W2KT>߸}ÍH A7"c[0>s, RnCnjMCŁR#=Gd}aoa0;h~B<@ῶgc<stAT2/M'+-$<| J3Wpۭo!c3 lm@Q>]K[tb\w_&"",0cS?s:_F_3l^+nLj4:^EӦ +*mx=Şٲn_ZNXS(_: zNPZSU_]II5,DpNsztNmZXYuV6VYWKNNjPTLŵ4zlU~F"VƳѶjxdpۖ˽ekXi\U۰gUT+m кfeo54nԷjjeϴVxA"tR]_Um6Z$Vxpȼyݵ#ꪪa`4C"V+#jeC]]o0jalmJmAEI uzɼgLwOO^v{/>ނSLqg-㩫]VU8Mɗ~S ݶ4kmorAg+W~U53f2`Caǟo[PUɳM-;HRʈz)rwwo$ ocᎀ#`iXP طU_@: 3YXZy`<8!]õhdf KkKoFLajoY߾־MS $ Gqӎ:Ⱔ$,OY);)oҗIg)όy[f|fޙRRNM4Qs͜|5gF+&͗/XDgҹpe,XXe>iف]sM΍9u9ø~q}cl撙ͩnlsbΧsbi7N{*iv.9g;uFc:_tStkKӫMN fXqwꌇ3g82ʘ|4=#diYwgZ>kbvRvF5f7G;_~={_c˙Ssoy'磜Os;s=>͞j/i7۷ڿe:ñ}'1e^ )y*g5n6=v3Iy}}2dgz3_8 geޑ8sUfCz{297xǙe4f]5%+?"2˓NedO̾!;%;?{Q쇳~&e0TvLĜrRrss作%Fn[q͞hjOg %R{}}}ھ^koZ;O?o~h۲XDZGJQ0c Ӻ67ME!*?˜:ȧd]⫼\#/b/rν&vAúCq^Y(] .ˬ0^cIl |J k䴟+,"AΠ e6b'Qru8?ӥk"Z!neްeK/hT( :,dxX%"M',M~Ҭ0(H8\ H)2 0adЬ'j! "!n@r- Nd;q "I"!o"!%#!gGzX\rU!|O;v~ըe8 o<í!v\5ޣp(^ix."!w< q+ۚ^ l>v]mC&];~X6_iM5wt~@>B>@8"!Ү|( /SهK+\z'EŻ:ȧ t>ΕXuA2NP+[$^A SMFߔVMh|C$@Jo)pFB~Fު!s[$פ+)oJHh#puVwr?7'"<ϗ1jLh7ěJόe$.Y*@u:3; >Q@:fq6Eau Qb煣D9 /2OGGsDBfDAR3 Q DtDmw;=7*{9B{"{'rS9i/8;F=qq{ ܏ ܻF=q?q?q4Fsc96{߈渿q9#~~/ i#}? U#q㸟sFĽ~~nc$} {q?qoท\M"m5痏F~;"q~~>NA߿ӽ}D9ݧr'qw9qx{)}爸'pܓ8va{׈q7sMq w#?|q>8"8w+q#ntq9[9q8V{=nW9b]/}DOpܿฟw㸛}DOrq{U`xcUDWHNWl.Op^|W߽ k2UG3ˠ/D'upA}wawZ|qf\gN C[κ*e\=e$/O?>? ˌF猑ɛl5;Hs^ΛS{3&^ۋ 9p"[//K'P0_5Cz_5VK诮K诜Uf2'OG_'aѣ`X<k}(3 ތT ҧyc:oR0I轄=5 N%Π-E.툸rܗqܗsq//WsܷqGĽ9!3%e|q{ǽ㾄8q_qs7p>{-p玈{1ǽ㾆8#q/帗+`%\P̓)%%SK/!K uOmϩ/uv.dEƿ>+?̋0y!v[wP C>0d4 |&]8Z~A¢qRBT CdS|~ّ_c7Z&6Dj@L18^< HNcU?]g$AG :o 5p># KtF"@Q]+ hdOn@B:o#@l:_DR pq2ȣlDq+ڿ\׃7]{ qQ䤎:Ȗd$W)grMc? ::-~H>9#a1b%{ut 9,wUG:MNՋ| ͺz15 bkɀ<xik5  ::.F2k'G09͆2:~N2FaWZ@:t@ ]geY ZDG;&(e-'|%kƓb?p( bI8z"|C5g @|]njN;ӫ01["^m@, v:GUr 5wa- H1<o#OMϯ-U4}''ְjϣV|q~UUCvʃF6@'W!yؽlOÚ*;S8mZiA;N6zUvıVi'J3 G$% =ȷFboϳAh'B NK#_sNtG--nBQw-,FuԼD}j{c;v?чues12Yunn!nNwyOCuOt돇tO uG/>`q;xPwġnInȃI1"Q)gumÊZw5mA+COJ,KV?JGai7HNvW z=+}8r6z} Z&ePJOC7]߳19*2|&OJӘynÜ/Jh*ϛr* JK敕#t't r c8ѧq~!iL1 . u!r#C?Ykji@b$rh]p8| i4x !܍i#Vώk\*44§yӸU݇~VQn #X$e6jjg#y՚졪[kE"L4Ea*|S3zß! E Q =NJkA.l\lɯPP7&y[ްUiW"zCԺb7"]/8ֆ^ w!w¤j5*<| CFTu}  AJӛN;2֪A.PEƨznÜ:Jr]@TD ^aX>:[ÈU_7~՟m: y+k5T\ބ*[p~iSEzrgGÝ?~l(5u#8UWkHV#hi)Krk]i I~:I) S/Fi5(>|B^;*#ua ]%p)yx'6TU%\>^\(.?PKpZ9З2 h"portmidi/Release/libPortMidi_dll.aˏe!f ,0e;L6dӹt*eKyKta`d gF~*[> *ۿ29Ae*Ke2T|IeWST^rwJvq*TI*'R9K*s *or6wQ)ߧr_T<T>OnSJ(TVnQ/T\-Q~L'*׿rkOlT>'_ Ry*oS~*w~Nr?LQi"F}.kJѨjӀJeŨւP^7J4*KFcl27ەvecl{Z}WoM+lF{g*NMniv+˦Pdew*H&t7{FױT-zxFt1Ziuc$Bl[c&jaU<ֳ ԌRY'ڬpIԋXEQ3Cn-9{i{VV_bWPқqSƾՎMsi2뷘aihJn<,^44Q[A-MZzƖJ8 њ344 [UX:n\ڎMҝjg,OhN0f=t@%}n2m\psyI]6zFc:3^Vi4.T031.UVn7F0M7sS vcPy?uZJP_PK{:n\lEG,yLxI\|A@Igݳ^ n۱DsW'AhUF؊vo-R~`=%ކzګIG[;vݝhn1I>7s4w®l߈p-mo2JB'Ga]ӸSfg$)/BP'B Fqr6bcg(|x)vd}͇GߍBO4yt6aZFX220ȣ+lcv|ܵǖ +2)K GN@x#.{GlˍDy3 4ht4ul1.v#]ն,9DDE $QHƑD!j,QoW-E8N # 2fxfY=3M73,E0C@xGio{B0m%hxlp58Z~lXu)#JQOƞuBtψ Ax|mMky^rgyNpyU%~0f(?Sڋ; !"| cK&cIww9us"Qtȥ/'&C',poocmOطS'Ra93fJbbVJ)>g zDa.Zˮ'X3[fb@|n %H%zg8Ra}du|XnXMZjx9I"bo z  xH!cQ ~_I& ߲"r2kyސd$226![=dL!؏b@XoOu[O 9J.s-OѶf$4v~,@lgg-Is\ >V[Eww~Rt3ib-2@X55eFM12r|iVQ`Dԭ׌FFY_=%扔$o [cCIq #f̌"@2Q2sc0n9n ғ ֛hK! (TV#=saRvQ_=A1U у2YR ljRB[5K-Ւ>bMkU+3hhJrhp!. (]Rr)o3RL ϖe*N Y ~> -c2ZB\#AH N:$`z˼QƛL:F|#{?P]1F 9NIB>/BF !" !dݠcdDy Gqu[g1%8os |Vg2^g9e '2r2W̃pC:WN6MC >Ϊs/PMO˩~WLhLz<)1KIgi1p(bjJB:g;ʤlHϑfv)1k!=mPfWyqC~j:mPw.5X_#]!|)hkB9lIsԼl)? ǡLFQUqNfz4Gtu~moUX۳HO/ࣻ:ʾUb!yC̋P/,1ب]`RfDz58e~ 5%j.kXF.'e92(s= RrQ`I,1lǵvR&IW: _nԛ3- -3C В qle7Ul96Au ;8clv#acp`q1#:SSJ5ľ 7IPKpZ9`lB'!portmidi/Release/PortMidi_dll.defm͎0y @v9TE&}Mc ;3WmSBh;`BA4K<Kh:t9=H:׼}hVt:bE4 JJ!p2C.#'߉r/~ͩط`#M߰oV0Bf"KPZ+q(VM OC3~v'9Dd( CydܗPnkI|%d+?Z]kHhb@,0"HuT53E~~C5JV iL>0 iIy/*^-{1w F@;yeE{=}Fg.wBP+NRp;Y20gpFOB(돸mJRemocDpˮႲso$GBYy(!xJ6y+<0'pybwVO@m[jZi*8WtyB⽲TV]0qsjϔ7&ׅtOl*\