diff options
Diffstat (limited to 'portmidi/pm_test/sysex.c')
| -rwxr-xr-x | portmidi/pm_test/sysex.c | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/portmidi/pm_test/sysex.c b/portmidi/pm_test/sysex.c new file mode 100755 index 0000000..c2c7187 --- /dev/null +++ b/portmidi/pm_test/sysex.c | |||
| @@ -0,0 +1,556 @@ | |||
| 1 | /* sysex.c -- example program showing how to send and receive sysex | ||
| 2 | messages | ||
| 3 | |||
| 4 | Messages are stored in a file using 2-digit hexadecimal numbers, | ||
| 5 | one per byte, separated by blanks, with up to 32 numbers per line: | ||
| 6 | F0 14 A7 4B ... | ||
| 7 | |||
| 8 | */ | ||
| 9 | |||
| 10 | #include "stdio.h" | ||
| 11 | #include "stdlib.h" | ||
| 12 | #include "assert.h" | ||
| 13 | #include "portmidi.h" | ||
| 14 | #include "porttime.h" | ||
| 15 | #include "string.h" | ||
| 16 | #ifdef WIN32 | ||
| 17 | // need to get declaration for Sleep() | ||
| 18 | #include "windows.h" | ||
| 19 | #else | ||
| 20 | #include <unistd.h> | ||
| 21 | #define Sleep(n) usleep(n * 1000) | ||
| 22 | #endif | ||
| 23 | |||
| 24 | // enable some extra printing | ||
| 25 | #ifndef VERBOSE | ||
| 26 | #define VERBOSE 0 | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #define MIDI_SYSEX 0xf0 | ||
| 30 | #define MIDI_EOX 0xf7 | ||
| 31 | |||
| 32 | #define STRING_MAX 80 | ||
| 33 | |||
| 34 | #ifndef true | ||
| 35 | #define true 1 | ||
| 36 | #define false 0 | ||
| 37 | #endif | ||
| 38 | |||
| 39 | int latency = 0; | ||
| 40 | |||
| 41 | /* read a number from console */ | ||
| 42 | /**/ | ||
| 43 | int get_number(const char *prompt) | ||
| 44 | { | ||
| 45 | int n = 0, i; | ||
| 46 | fputs(prompt, stdout); | ||
| 47 | while (n != 1) { | ||
| 48 | n = scanf("%d", &i); | ||
| 49 | while (getchar() != '\n') ; | ||
| 50 | } | ||
| 51 | return i; | ||
| 52 | } | ||
| 53 | |||
| 54 | |||
| 55 | /* loopback test -- send/rcv from 2 to 1000 bytes of random midi data */ | ||
| 56 | /**/ | ||
| 57 | void loopback_test() | ||
| 58 | { | ||
| 59 | int outp; | ||
| 60 | int inp; | ||
| 61 | PmStream *midi_in; | ||
| 62 | PmStream *midi_out; | ||
| 63 | unsigned char msg[1024]; | ||
| 64 | int32_t len; | ||
| 65 | int i; | ||
| 66 | int data; | ||
| 67 | PmEvent event; | ||
| 68 | int shift; | ||
| 69 | long total_bytes = 0; | ||
| 70 | int32_t begin_time; | ||
| 71 | |||
| 72 | Pt_Start(1, 0, 0); | ||
| 73 | |||
| 74 | printf("Connect a midi cable from an output port to an input port.\n"); | ||
| 75 | printf("This test will send random data via sysex message from output\n"); | ||
| 76 | printf("to input and check that the correct data was received.\n"); | ||
| 77 | outp = get_number("Type output device number: "); | ||
| 78 | /* Open output with 1ms latency -- when latency is non-zero, the Win32 | ||
| 79 | implementation supports sending sysex messages incrementally in a | ||
| 80 | series of buffers. This is nicer than allocating a big buffer for the | ||
| 81 | message, and it also seems to work better. Either way works. | ||
| 82 | */ | ||
| 83 | while ((latency = get_number( | ||
| 84 | "Latency in milliseconds (0 to send data immediatedly,\n" | ||
| 85 | " >0 to send timestamped messages): ")) < 0); | ||
| 86 | Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency); | ||
| 87 | inp = get_number("Type input device number: "); | ||
| 88 | /* since we are going to send and then receive, make sure the input buffer | ||
| 89 | is large enough for the entire message */ | ||
| 90 | Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL); | ||
| 91 | |||
| 92 | srand((unsigned int) Pt_Time()); /* seed for random numbers */ | ||
| 93 | |||
| 94 | begin_time = Pt_Time(); | ||
| 95 | while (total_bytes < 100000) { | ||
| 96 | PmError count; | ||
| 97 | int32_t start_time; | ||
| 98 | int error_position = -1; /* 0; -1; -1 for continuous */ | ||
| 99 | int expected = 0; | ||
| 100 | int actual = 0; | ||
| 101 | /* this modification will run until an error is detected */ | ||
| 102 | /* set error_position above to 0 for interactive, -1 for */ | ||
| 103 | /* continuous */ | ||
| 104 | if (error_position >= 0) { | ||
| 105 | int c; | ||
| 106 | printf("Type return to send message, q to quit: "); | ||
| 107 | while ((c = getchar()) != '\n') { | ||
| 108 | if (c == 'q') goto cleanup; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /* compose the message */ | ||
| 113 | len = rand() % 998 + 2; /* len only counts data bytes */ | ||
| 114 | msg[0] = (char) MIDI_SYSEX; /* start of SYSEX message */ | ||
| 115 | /* data bytes go from 1 to len */ | ||
| 116 | for (i = 0; i < len; i++) { | ||
| 117 | /* pick whether data is sequential or random... (docs say random) */ | ||
| 118 | #define DATA_EXPR (i+1) | ||
| 119 | // #define DATA_EXPR rand() | ||
| 120 | msg[i + 1] = DATA_EXPR & 0x7f; /* MIDI data */ | ||
| 121 | } | ||
| 122 | /* final EOX goes in len+1, total of len+2 bytes in msg */ | ||
| 123 | msg[len + 1] = (char) MIDI_EOX; | ||
| 124 | |||
| 125 | /* sanity check: before we send, there should be no queued data */ | ||
| 126 | count = Pm_Read(midi_in, &event, 1); | ||
| 127 | |||
| 128 | if (count != 0) { | ||
| 129 | printf("Before sending anything, a MIDI message was found in\n"); | ||
| 130 | printf("the input buffer. Please try again.\n"); | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* send the message two ways: 1) Pm_WriteSysEx, 2) Pm_Write */ | ||
| 135 | if (total_bytes & 1) { | ||
| 136 | printf("Sending %d byte sysex msg via Pm_WriteSysEx.\n", len + 2); | ||
| 137 | Pm_WriteSysEx(midi_out, 0, msg); | ||
| 138 | } else { | ||
| 139 | PmEvent event = {0, 0}; | ||
| 140 | int bits = 0; | ||
| 141 | printf("Sending %d byte sysex msg via Pm_Write(s).\n", len + 2); | ||
| 142 | for (i = 0; i < len + 2; i++) { | ||
| 143 | event.message |= (msg[i] << bits); | ||
| 144 | bits += 8; | ||
| 145 | if (bits == 32) { /* full message - send it */ | ||
| 146 | Pm_Write(midi_out, &event, 1); | ||
| 147 | bits = 0; | ||
| 148 | event.message = 0; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | if (bits > 0) { /* last message is partially full */ | ||
| 152 | Pm_Write(midi_out, &event, 1); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | /* receive the message and compare to msg[] */ | ||
| 157 | data = 0; | ||
| 158 | shift = 0; | ||
| 159 | i = 0; | ||
| 160 | start_time = Pt_Time(); | ||
| 161 | if (VERBOSE) { | ||
| 162 | printf("start_time %d\n", start_time); | ||
| 163 | } | ||
| 164 | error_position = -1; | ||
| 165 | /* allow up to 2 seconds for transmission */ | ||
| 166 | while (data != MIDI_EOX && start_time + 2000 > Pt_Time()) { | ||
| 167 | count = Pm_Read(midi_in, &event, 1); | ||
| 168 | if (count == 0) { | ||
| 169 | Sleep(1); /* be nice: give some CPU time to the system */ | ||
| 170 | continue; /* continue polling for input */ | ||
| 171 | } | ||
| 172 | if (VERBOSE) { | ||
| 173 | printf("read %08x ", event.message); | ||
| 174 | fflush(stdout); | ||
| 175 | } | ||
| 176 | /* compare 4 bytes of data until you reach an eox */ | ||
| 177 | for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) { | ||
| 178 | data = (event.message >> shift) & 0xFF; | ||
| 179 | if (data != msg[i] && error_position < 0) { | ||
| 180 | error_position = i; | ||
| 181 | expected = msg[i]; | ||
| 182 | actual = data; | ||
| 183 | } | ||
| 184 | i++; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | if (error_position >= 0) { | ||
| 188 | printf("Error at time %d byte %d: sent %x recd %x.\n", Pt_Time(), | ||
| 189 | error_position, expected, actual); | ||
| 190 | break; | ||
| 191 | } else if (i != len + 2) { | ||
| 192 | printf("Error at time %d: byte %d not received.\n", Pt_Time(), i); | ||
| 193 | break; | ||
| 194 | } else { | ||
| 195 | int seconds = (Pt_Time() - begin_time) / 1000; | ||
| 196 | if (seconds == 0) seconds = 1; | ||
| 197 | printf("Correctly received %d byte sysex message.\n", i); | ||
| 198 | total_bytes += i; | ||
| 199 | printf("Cummulative bytes/sec: %d, %d%% done.\n", | ||
| 200 | (int) (total_bytes / seconds), | ||
| 201 | (int) (100 * total_bytes / 100000)); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | cleanup: | ||
| 205 | Pm_Close(midi_out); | ||
| 206 | Pm_Close(midi_in); | ||
| 207 | return; | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | /* send_multiple test -- send many sysex messages */ | ||
| 212 | /**/ | ||
| 213 | void send_multiple_test() | ||
| 214 | { | ||
| 215 | int outp; | ||
| 216 | int length; | ||
| 217 | int num_msgs; | ||
| 218 | PmStream *midi_out; | ||
| 219 | unsigned char msg[1024]; | ||
| 220 | int i; | ||
| 221 | PtTimestamp start_time; | ||
| 222 | PtTimestamp stop_time; | ||
| 223 | |||
| 224 | Pt_Start(1, 0, 0); | ||
| 225 | |||
| 226 | printf("This is for performance testing. You should be sending to this\n"); | ||
| 227 | printf("program running the receive multiple test. Do NOT send to\n"); | ||
| 228 | printf("a synthesizer or you risk reprogramming it\n"); | ||
| 229 | outp = get_number("Type output device number: "); | ||
| 230 | while ((latency = get_number( | ||
| 231 | "Latency in milliseconds (0 to send data immediatedly,\n" | ||
| 232 | " >0 to send timestamped messages): ")) < 0); | ||
| 233 | Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency); | ||
| 234 | while ((length = get_number("Message length (7 - 1024): ")) < 7 || | ||
| 235 | length > 1024) ; | ||
| 236 | while ((num_msgs = get_number("Number of messages: ")) < 1); | ||
| 237 | /* latency, length, and num_msgs should now all be valid */ | ||
| 238 | /* compose the message except for sequence number in first 5 bytes */ | ||
| 239 | msg[0] = (char) MIDI_SYSEX; | ||
| 240 | for (i = 6; i < length - 1; i++) { | ||
| 241 | msg[i] = i % 128; /* this is just filler */ | ||
| 242 | } | ||
| 243 | msg[length - 1] = (char) MIDI_EOX; | ||
| 244 | |||
| 245 | start_time = Pt_Time(); | ||
| 246 | /* send the messages */ | ||
| 247 | for (i = num_msgs; i > 0; i--) { | ||
| 248 | /* insert sequence number into first 5 data bytes */ | ||
| 249 | /* sequence counts down to zero */ | ||
| 250 | int j; | ||
| 251 | int count = i; | ||
| 252 | /* 7 bits of message count i goes into each data byte */ | ||
| 253 | for (j = 1; j <= 5; j++) { | ||
| 254 | msg[j] = count & 127; | ||
| 255 | count >>= 7; | ||
| 256 | } | ||
| 257 | /* send the message */ | ||
| 258 | Pm_WriteSysEx(midi_out, 0, msg); | ||
| 259 | } | ||
| 260 | stop_time = Pt_Time(); | ||
| 261 | Pm_Close(midi_out); | ||
| 262 | return; | ||
| 263 | } | ||
| 264 | |||
| 265 | #define MAX_MSG_LEN 1024 | ||
| 266 | static unsigned char receive_msg[MAX_MSG_LEN]; | ||
| 267 | static int receive_msg_index; | ||
| 268 | static int receive_msg_length; | ||
| 269 | static int receive_msg_count; | ||
| 270 | static int receive_msg_error; | ||
| 271 | static int receive_msg_messages; | ||
| 272 | static PmStream *receive_msg_midi_in; | ||
| 273 | static int receive_poll_running; | ||
| 274 | |||
| 275 | /* receive_poll -- callback function to check for midi input */ | ||
| 276 | /**/ | ||
| 277 | void receive_poll(PtTimestamp timestamp, void *userData) | ||
| 278 | { | ||
| 279 | PmError count; | ||
| 280 | PmEvent event; | ||
| 281 | int shift; | ||
| 282 | int data = 0; | ||
| 283 | int i; | ||
| 284 | |||
| 285 | if (!receive_poll_running) return; /* wait until midi device is opened */ | ||
| 286 | shift = 0; | ||
| 287 | while (data != MIDI_EOX) { | ||
| 288 | count = Pm_Read(receive_msg_midi_in, &event, 1); | ||
| 289 | if (count == 0) return; | ||
| 290 | |||
| 291 | /* compare 4 bytes of data until you reach an eox */ | ||
| 292 | for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) { | ||
| 293 | receive_msg[receive_msg_index++] = data = | ||
| 294 | (event.message >> shift) & 0xFF; | ||
| 295 | if (receive_msg_index >= MAX_MSG_LEN) { | ||
| 296 | printf("error: incoming sysex too long\n"); | ||
| 297 | goto error; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | } | ||
| 301 | /* check the message */ | ||
| 302 | if (receive_msg_length == 0) { | ||
| 303 | receive_msg_length = receive_msg_index; | ||
| 304 | } | ||
| 305 | if (receive_msg_length != receive_msg_index) { | ||
| 306 | printf("error: incoming sysex wrong length\n"); | ||
| 307 | goto error; | ||
| 308 | } | ||
| 309 | if (receive_msg[0] != MIDI_SYSEX) { | ||
| 310 | printf("error: incoming sysex missing status byte\n"); | ||
| 311 | goto error; | ||
| 312 | } | ||
| 313 | /* get and check the count */ | ||
| 314 | count = 0; | ||
| 315 | for (i = 0; i < 5; i++) { | ||
| 316 | count += receive_msg[i + 1] << (7 * i); | ||
| 317 | } | ||
| 318 | if (receive_msg_count == -1) { | ||
| 319 | receive_msg_count = count; | ||
| 320 | receive_msg_messages = count; | ||
| 321 | } | ||
| 322 | if (receive_msg_count != count) { | ||
| 323 | printf("error: incoming sysex has wrong count\n"); | ||
| 324 | goto error; | ||
| 325 | } | ||
| 326 | for (i = 6; i < receive_msg_index - 1; i++) { | ||
| 327 | if (receive_msg[i] != i % 128) { | ||
| 328 | printf("error: incoming sysex has bad data\n"); | ||
| 329 | goto error; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | if (receive_msg[receive_msg_length - 1] != MIDI_EOX) goto error; | ||
| 333 | receive_msg_index = 0; /* get ready for next message */ | ||
| 334 | receive_msg_count--; | ||
| 335 | return; | ||
| 336 | error: | ||
| 337 | receive_msg_error = 1; | ||
| 338 | return; | ||
| 339 | } | ||
| 340 | |||
| 341 | |||
| 342 | /* receive_multiple_test -- send/rcv from 2 to 1000 bytes of random midi data */ | ||
| 343 | /**/ | ||
| 344 | void receive_multiple_test() | ||
| 345 | { | ||
| 346 | PmError err; | ||
| 347 | int inp; | ||
| 348 | |||
| 349 | printf("This test expects to receive data sent by the send_multiple test\n"); | ||
| 350 | printf("The test will check that correct data is received.\n"); | ||
| 351 | |||
| 352 | /* Important: start PortTime first -- if it is not started first, it will | ||
| 353 | be started by PortMidi, and then our attempt to open again will fail */ | ||
| 354 | receive_poll_running = false; | ||
| 355 | if ((err = Pt_Start(1, receive_poll, 0))) { | ||
| 356 | printf("PortTime error code: %d\n", err); | ||
| 357 | goto cleanup; | ||
| 358 | } | ||
| 359 | inp = get_number("Type input device number: "); | ||
| 360 | Pm_OpenInput(&receive_msg_midi_in, inp, NULL, 512, NULL, NULL); | ||
| 361 | receive_msg_index = 0; | ||
| 362 | receive_msg_length = 0; | ||
| 363 | receive_msg_count = -1; | ||
| 364 | receive_msg_error = 0; | ||
| 365 | receive_poll_running = true; | ||
| 366 | while ((!receive_msg_error) && (receive_msg_count != 0)) { | ||
| 367 | #ifdef WIN32 | ||
| 368 | Sleep(1000); | ||
| 369 | #else | ||
| 370 | sleep(1); /* block and wait */ | ||
| 371 | #endif | ||
| 372 | } | ||
| 373 | if (receive_msg_error) { | ||
| 374 | printf("Receive_multiple test encountered an error\n"); | ||
| 375 | } else { | ||
| 376 | printf("Receive_multiple test successfully received %d sysex messages\n", | ||
| 377 | receive_msg_messages); | ||
| 378 | } | ||
| 379 | cleanup: | ||
| 380 | receive_poll_running = false; | ||
| 381 | Pm_Close(receive_msg_midi_in); | ||
| 382 | Pt_Stop(); | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | |||
| 386 | |||
| 387 | #define is_real_time_msg(msg) ((0xF0 & Pm_MessageStatus(msg)) == 0xF8) | ||
| 388 | |||
| 389 | |||
| 390 | void receive_sysex() | ||
| 391 | { | ||
| 392 | char line[80]; | ||
| 393 | FILE *f; | ||
| 394 | PmStream *midi; | ||
| 395 | int shift = 0; | ||
| 396 | int data = 0; | ||
| 397 | int bytes_on_line = 0; | ||
| 398 | PmEvent msg; | ||
| 399 | |||
| 400 | /* determine which output device to use */ | ||
| 401 | int i = get_number("Type input device number: "); | ||
| 402 | |||
| 403 | /* open input device */ | ||
| 404 | Pm_OpenInput(&midi, i, NULL, 512, NULL, NULL); | ||
| 405 | printf("Midi Input opened, type file for sysex data: "); | ||
| 406 | |||
| 407 | /* open file */ | ||
| 408 | if (!fgets(line, STRING_MAX, stdin)) return; /* no more stdin? */ | ||
| 409 | /* remove the newline character */ | ||
| 410 | if (strlen(line) > 0) line[strlen(line) - 1] = 0; | ||
| 411 | f = fopen(line, "w"); | ||
| 412 | if (!f) { | ||
| 413 | printf("Could not open %s\n", line); | ||
| 414 | Pm_Close(midi); | ||
| 415 | return; | ||
| 416 | } | ||
| 417 | |||
| 418 | printf("Ready to receive a sysex message\n"); | ||
| 419 | |||
| 420 | /* read data and write to file */ | ||
| 421 | while (data != MIDI_EOX) { | ||
| 422 | PmError count; | ||
| 423 | count = Pm_Read(midi, &msg, 1); | ||
| 424 | /* CAUTION: this causes busy waiting. It would be better to | ||
| 425 | be in a polling loop to avoid being compute bound. PortMidi | ||
| 426 | does not support a blocking read since this is so seldom | ||
| 427 | useful. | ||
| 428 | */ | ||
| 429 | if (count == 0) continue; | ||
| 430 | /* ignore real-time messages */ | ||
| 431 | if (is_real_time_msg(Pm_MessageStatus(msg.message))) continue; | ||
| 432 | |||
| 433 | /* write 4 bytes of data until you reach an eox */ | ||
| 434 | for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) { | ||
| 435 | data = (msg.message >> shift) & 0xFF; | ||
| 436 | /* if this is a status byte that's not MIDI_EOX, the sysex | ||
| 437 | message is incomplete and there is no more sysex data */ | ||
| 438 | if (data & 0x80 && data != MIDI_EOX) break; | ||
| 439 | fprintf(f, "%2x ", data); | ||
| 440 | if (++bytes_on_line >= 16) { | ||
| 441 | fprintf(f, "\n"); | ||
| 442 | bytes_on_line = 0; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | } | ||
| 446 | fclose(f); | ||
| 447 | Pm_Close(midi); | ||
| 448 | } | ||
| 449 | |||
| 450 | |||
| 451 | void send_sysex() | ||
| 452 | { | ||
| 453 | char line[80]; | ||
| 454 | FILE *f; | ||
| 455 | PmStream *midi; | ||
| 456 | int data; | ||
| 457 | int shift = 0; | ||
| 458 | PmEvent msg; | ||
| 459 | |||
| 460 | /* determine which output device to use */ | ||
| 461 | int i = get_number("Type output device number: "); | ||
| 462 | while ((latency = get_number( | ||
| 463 | "Latency in milliseconds (0 to send data immediatedly,\n" | ||
| 464 | " >0 to send timestamped messages): ")) < 0); | ||
| 465 | |||
| 466 | msg.timestamp = 0; /* no need for timestamp */ | ||
| 467 | |||
| 468 | /* open output device */ | ||
| 469 | Pm_OpenOutput(&midi, i, NULL, 0, NULL, NULL, latency); | ||
| 470 | printf("Midi Output opened, type file with sysex data: "); | ||
| 471 | |||
| 472 | /* open file */ | ||
| 473 | if (!fgets(line, STRING_MAX, stdin)) return; /* no more stdin? */ | ||
| 474 | /* remove the newline character */ | ||
| 475 | if (strlen(line) > 0) line[strlen(line) - 1] = 0; | ||
| 476 | f = fopen(line, "r"); | ||
| 477 | if (!f) { | ||
| 478 | printf("Could not open %s\n", line); | ||
| 479 | Pm_Close(midi); | ||
| 480 | return; | ||
| 481 | } | ||
| 482 | |||
| 483 | /* read file and send data */ | ||
| 484 | msg.message = 0; | ||
| 485 | while (1) { | ||
| 486 | /* get next byte from file */ | ||
| 487 | |||
| 488 | if (fscanf(f, "%x", &data) == 1) { | ||
| 489 | /* printf("read %x, ", data); */ | ||
| 490 | /* OR byte into message at proper offset */ | ||
| 491 | msg.message |= (data << shift); | ||
| 492 | shift += 8; | ||
| 493 | } | ||
| 494 | /* send the message if it's full (shift == 32) or if we are at end */ | ||
| 495 | if (shift == 32 || data == MIDI_EOX) { | ||
| 496 | /* this will send sysex data 4 bytes at a time -- it would | ||
| 497 | be much more efficient to send multiple PmEvents at once | ||
| 498 | but this method is simpler. See Pm_WriteSysEx for a more | ||
| 499 | efficient code example. | ||
| 500 | */ | ||
| 501 | Pm_Write(midi, &msg, 1); | ||
| 502 | msg.message = 0; | ||
| 503 | shift = 0; | ||
| 504 | } | ||
| 505 | if (data == MIDI_EOX) { /* end of message */ | ||
| 506 | fclose(f); | ||
| 507 | Pm_Close(midi); | ||
| 508 | return; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | |||
| 514 | int main() | ||
| 515 | { | ||
| 516 | int i; | ||
| 517 | |||
| 518 | /* list device information */ | ||
| 519 | for (i = 0; i < Pm_CountDevices(); i++) { | ||
| 520 | const PmDeviceInfo *info = Pm_GetDeviceInfo(i); | ||
| 521 | printf("%d: %s, %s", i, info->interf, info->name); | ||
| 522 | if (info->input) printf(" (input)"); | ||
| 523 | if (info->output) printf(" (output)"); | ||
| 524 | printf("\n"); | ||
| 525 | } | ||
| 526 | while (1) { | ||
| 527 | char cmd; | ||
| 528 | printf("Type r to receive sysex, s to send," | ||
| 529 | " l for loopback test, m to send multiple," | ||
| 530 | " n to receive multiple, q to quit: "); | ||
| 531 | cmd = getchar(); | ||
| 532 | while (getchar() != '\n') ; | ||
| 533 | switch (cmd) { | ||
| 534 | case 'r': | ||
| 535 | receive_sysex(); | ||
| 536 | break; | ||
| 537 | case 's': | ||
| 538 | send_sysex(); | ||
| 539 | break; | ||
| 540 | case 'l': | ||
| 541 | loopback_test(); | ||
| 542 | break; | ||
| 543 | case 'm': | ||
| 544 | send_multiple_test(); | ||
| 545 | break; | ||
| 546 | case 'n': | ||
| 547 | receive_multiple_test(); | ||
| 548 | break; | ||
| 549 | case 'q': | ||
| 550 | exit(0); | ||
| 551 | default: | ||
| 552 | break; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | return 0; | ||
| 556 | } | ||
