From 40a899bd6ee536eae093337bf2d0dcc8db4e46f1 Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Mon, 7 Oct 2024 19:30:56 +0200 Subject: Moved example code examples folder --- portmidi/pm_test/CMakeLists.txt | 46 ---- portmidi/pm_test/README.txt | 363 ------------------------ portmidi/pm_test/fast.c | 290 -------------------- portmidi/pm_test/fastrcv.c | 255 ----------------- portmidi/pm_test/latency.c | 287 ------------------- portmidi/pm_test/midiclock.c | 282 ------------------- portmidi/pm_test/midithread.c | 343 ----------------------- portmidi/pm_test/midithru.c | 455 ------------------------------ portmidi/pm_test/mm.c | 595 ---------------------------------------- portmidi/pm_test/multivirtual.c | 223 --------------- portmidi/pm_test/pmlist.c | 63 ----- portmidi/pm_test/qtest.c | 174 ------------ portmidi/pm_test/recvvirtual.c | 175 ------------ portmidi/pm_test/sendvirtual.c | 194 ------------- portmidi/pm_test/sysex.c | 556 ------------------------------------- portmidi/pm_test/testio.c | 594 --------------------------------------- portmidi/pm_test/txdata.syx | 257 ----------------- portmidi/pm_test/virttest.c | 339 ----------------------- 18 files changed, 5491 deletions(-) delete mode 100644 portmidi/pm_test/CMakeLists.txt delete mode 100644 portmidi/pm_test/README.txt delete mode 100644 portmidi/pm_test/fast.c delete mode 100644 portmidi/pm_test/fastrcv.c delete mode 100755 portmidi/pm_test/latency.c delete mode 100644 portmidi/pm_test/midiclock.c delete mode 100755 portmidi/pm_test/midithread.c delete mode 100755 portmidi/pm_test/midithru.c delete mode 100755 portmidi/pm_test/mm.c delete mode 100644 portmidi/pm_test/multivirtual.c delete mode 100644 portmidi/pm_test/pmlist.c delete mode 100644 portmidi/pm_test/qtest.c delete mode 100644 portmidi/pm_test/recvvirtual.c delete mode 100644 portmidi/pm_test/sendvirtual.c delete mode 100755 portmidi/pm_test/sysex.c delete mode 100755 portmidi/pm_test/testio.c delete mode 100755 portmidi/pm_test/txdata.syx delete mode 100644 portmidi/pm_test/virttest.c (limited to 'portmidi/pm_test') diff --git a/portmidi/pm_test/CMakeLists.txt b/portmidi/pm_test/CMakeLists.txt deleted file mode 100644 index ae0fe48..0000000 --- a/portmidi/pm_test/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# CMake file to build tests in this directory: 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) -# if(NOT BUILD_SHARED_LIBS) - # /MDd is multithread debug DLL, /MTd is multithread debug - # /MD is multithread DLL, /MT is multithread. Change to static: -# include(../pm_win/static.cmake) -# endif() -# endif(WIN32) - -if(HAIKU) - add_compile_options(-fPIC) # Haiku x86_64 needs this explicitly -endif() - -macro(add_test name) - add_executable(${name} ${name}.c) - target_link_libraries(${name} PRIVATE portmidi) - set_property(TARGET ${name} PROPERTY MSVC_RUNTIME_LIBRARY - "MultiThreaded$<$:Debug>${MSVCRT_DLL}") -endmacro(add_test) - -add_test(testio) -add_test(midithread) -add_test(midithru) -add_test(sysex) -add_test(latency) -add_test(mm) -add_test(midiclock) -add_test(qtest) -add_test(fast) -add_test(fastrcv) -add_test(pmlist) -if(WIN32) -# windows does not implement Pm_CreateVirtualInput or Pm_CreateVirtualOutput -else(WIN32) -add_test(recvvirtual) -add_test(sendvirtual) -add_test(multivirtual) -add_test(virttest) -endif(WIN32) diff --git a/portmidi/pm_test/README.txt b/portmidi/pm_test/README.txt deleted file mode 100644 index 6c0c7ab..0000000 --- a/portmidi/pm_test/README.txt +++ /dev/null @@ -1,363 +0,0 @@ -README.txt - for pm_test directory - -These are all test programs for PortMidi - -Because device numbers depend on the system, there is no automated -script to run all tests on PortMidi. - -To run the full set of tests manually: - -Note: everything is run from the ../Debug or ../Release directory. -Actual or example input is marked with >>, e.g., >>0 means type 0 -Comments are shown in square brackets [like this] - -1. ./qtest -- output should show a bunch of tests and no error message. - -2. ./testio [test input] -Latency in ms: >>0 -enter your choice... >>1 -Type input number: >>6 [pick a working input device] -[play some notes, look for note-on (0x90) with pitch and velocity data] - -3. ./testio [test input (fail w/assert)] -Latency in ms: >>0 -enter your choice... >>2 -Type input number: >>6 [pick a working input device] -[play some notes, program will abort after 5 messages -(this test only applies to a Debug build, otherwise -the assert() macro is disabled.)] - -4. ./testio [test input (fail w/NULL assign)] -Latency in ms: >>0 -enter your choice... >>3 -Type input number: >>6 [pick a working input device] -[play some notes, program will Segmentation fault after 5 messages -(this test may not Segfault in the Release build; if not -try testing with a Debug build.)] - -5. ./testio [test output, no latency] -Latency in ms: >>0 -enter your choice... >>4 -Type output number: >>2 [pick a working output device] ->> [type ENTER when prompted (7 times)] -[hear note on, note off, note on, note off, chord] - -6. ./testio [test output, latency > 0] -Latency in ms: >>300 -enter your choice... >>4 -Type output number: >>2 [pick a working output device] ->> [type ENTER when prompted (7 times)] -[hear note on, note off, note on, note off, arpeggiated chord - (delay of 300ms should be apparent)] - -7. ./testio [for both, no latency] -Latency in ms: >>0 -enter your choice... >>5 -Type input number: >>6 [pick a working input device] -Type output number: >>2 [pick a working output device] -[play notes on input, hear them on output] - -8. ./testio [for both, latency > 0] -Latency in ms: >>300 -enter your choice... >>5 -Type input number: >>6 [pick a working input device] -Type output number: >>2 [pick a working output device] -[play notes on input, hear them on output (delay of 300ms is apparent)] - -9. ./testio [stream test] -Latency in ms: >>0 [does not matter] -enter your choice... >>6 -Type output number: >>2 [pick a working output device] ->> [type ENTER to start] -[hear 4 notes: C D E F# at one note per second, then all turn off] -ready to close and terminate... (type ENTER) :>> [type ENTER (twice)] - -10. ./testio [isochronous out] -Latency in ms: >>300 -enter your choice... >>7 -Type output number: >>2 [pick a working output device] -ready to send program 1 change... (type ENTER): >> [type ENTER] -[hear 80 notes, exactly 4 notes per second, no jitter] - -11. ./latency [no MIDI, histogram] -Choose timer period (in ms, >= 1): >>1 -? >>1 [No MIDI traffic option] -[wait about 10 seconds] ->> [type ENTER] -[output should be something like ... Maximum latency: 1 milliseconds] - -12. ./latency [MIDI input, histogram] -Choose timer period (in ms, >= 1): >>1 -? >>2 [MIDI input option] -Midi input device number: >>6 [pick a working input device] -[wait about 5 seconds, play input for 10 seconds ] ->> [type ENTER] -[output should be something like ... Maximum latency: 3 milliseconds] - -13. ./latency [MIDI output, histogram] -Choose timer period (in ms, >= 1): >>1 -? >>3 [MIDI output option] -Midi output device number: >>2 [pick a working output device] -Midi output should be sent every __ callback iterations: >>50 -[wait until you hear notes for 5 or 10 seconds] ->> [type ENTER to stop] -[output should be something like ... Maximum latency: 2 milliseconds] - -14. ./latency [MIDI input and output, histogram] -Choose timer period (in ms, >= 1): >>1 -? >>4 [MIDI input and output option] -Midi input device number: >>6 [pick a working input device] -Midi output device number: >>2 [pick a working output device] -Midi output should be sent every __ callback iterations: >>50 -[wait until you hear notes, simultaneously play notes for 5 or 10 seconds] ->> [type ENTER to stop] -[output should be something like ... Maximum latency: 1 milliseconds] - -15. ./mm [test with device input] -Type input device number: >>6 [pick a working input device] -[play some notes, see notes printed] ->>q [Type q ENTER when finished to exit] - -16. ./midithread -i 6 -o 2 [use working input/output device numbers] ->>5 [enter a transposition number] -[play some notes, hear parallel 4ths] ->>q [quit after ENTER a couple of times] - -17. ./midiclock [in one shell] - ./mm [in another shell] -[Goal is send clock messages to MIDI monitor program. This requires - either a hardware loopback (MIDI cable from OUT to IN on interface) - or a software loopback (macOS IAC bus or ALSA MIDI Through Port)] -[For midiclock application:] - Type output device number: >>0 [pick a device with loopback] - Type ENTER to start MIDI CLOCK: >> [type ENTER] -[For mm application:] - Type input device number: >>1 [pick device with loopback] - [Wait a few seconds] - >>s [to get Clock Count] - >>s [expect to get a higher Clock Count] -[For midiclock application:] - >>c [turn off clocks] -[For mm application:] - >>s [to get Clock Count] - >>s [expect to Clock Count stays the same] -[For midiclock application:] - >>t [turn on time code, see Time Code Quarter Frame messages from mm] - >>q [to quit] -[For mm application:] - >>q [to quit] - -18. ./midithru -i 6 -o 2 [use working input/output device numbers] -[Play notes on input evice; notes are sent immediately and also with a - 2 sec delay to the output device; program terminates in 60 seconds or - when you play B3 (B below Middle C)] ->> [ENTER to exit] - -19. ./recvvirtual -h [in one shell, macOS and Linux only] - ./recvvirtual -m vvv [for mac, or -c vvv -p vvvport for linux] - ./testio [in another shell] -[For testio application:] - Latency in ms: >>0 - enter your choice... >>4 [test output] - Type output number: >>9 [select the "portmidi (output)" device] - [type ENTER to each prompt, see that recvvirtual "Got message 0" - through "Got message 9"] - >> [ENTER to quit] -[For recvvirtual application:] - >> [ENTER to quit] - -20. ./sendvirtual -h [in one shell, macOS and Linux only] - ./sendvirtual -m vvv [for mac, or -c vvv -p vvvport for linux] - ./mm [in another shell] -[For mm application:] - Type input device number: >>10 [select the "portmidi" device] -[For sendvirtual application:] - Type ENTER to send messages: >> [type ENTER] - [see NoteOn and off messages received by mm for Key 60-64] - >> [ENTER to quit] -[For mm application:] - >>q [and ENTER twice to quit] - -21. ./sysex [no latency] -[This requires either a hardware loopback (MIDI cable from OUT to IN - on interface) or a software loopback (macOS IAC bus or ALSA MIDI - Through Port)] ->>l [for loopback test] -Type output device number: >>0 [pick output device to loopback] -Latency in milliseconds: >>0 -Type input device number: >>0 [pick input device for loopback] -[Program will send 100,000 bytes. After awhile, program will quit. - You can read the Cummulative bytes/sec value.] - -22. ./sysex [latency > 0] -[This requires either a hardware loopback (MIDI cable from OUT to IN - on interface) or a software loopback (macOS IAC bus or ALSA MIDI - Through Port)] ->>l [for loopback test] -Type output device number: >>0 [pick output device to loopback] -Latency in milliseconds: >>100 -Type input device number: >>0 [pick input device for loopback] -[Program will send 100,000 bytes. After awhile, program will quit. You - can read the Cummulative bytes/sec value; it is affected by latency.] - -23. ./fast [no latency] - ./fastrcv [in another shell] -[This is a speed check, especially for macOSX IAC bus connections, - which are known to drop messages if you send messages too fast. - fast and fastrcv must use a loopback to function.] -[In fastrcv:] - Input device number: >>1 [pick a non-hardware device if possible] -[In fast:] - Latency in ms: >>0 - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>0 [pick a non-hardware device if possible] - sending output... -[see message counts and times; on Linux you should get about 10000 - messages/s; on macOS you should get about 1800 messages/s; Windows - does not have software ports, so data rate might be limited by the - loopback device you use.] - -Check output of fastrcv: there should be no errors, just msg/sec.] - -24. ./fast [latency > 0] - ./fastrcv [in another shell] -[This is a speed check, especially for macOSX IAC bus connections, - which are known to drop messages if you send messages too fast. - fast and fastrcv must use a loopback to function.] -[In fastrcv:] - Input device number: >>1 [pick a non-hardware device if possible] -[In fast:] - Latency in ms: >>30 [Note for ALSA, use latency * msgs/ms < 400] - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>0 [pick a non-hardware device if possible] - sending output... -[see message counts and times; on Linux you should get about 10000 - messages/s; on macOS you should get about 1800 messages/s; Windows - does not have software ports, so data rate might be limited by the - loopback device you use.] - -Check output of fastrcv: there should be no errors, just msg/sec.] - -25. ./fast [virtual output port, latency = 0, macOS and Linux only] - ./fastrcv [in another shell] -[Start fast first:] - Latency in ms: >>0 - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>9 [enter number listed for "Create virtual - port named 'fast' (output)"] - Pausing so you can connect a receiver to the newly created - "fast" port. Type ENTER to proceed: -[In fastrcv:] - Input device number: >>3 [pick the device named "fast (input)"] -[In fast:] - >> [type ENTER to start] -[see message counts and times as above ] - -Check output of fastrcv: there should be no errors, just msg/sec.] - -26. ./fast [virtual output port, latency > 0, macOS and Linux only] - ./fastrcv [in another shell] -[Start fast first:] - Latency in ms: >>30 [Note for ALSA, use latency * msgs/ms < 400] - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>9 [enter number listed for "Create virtual - port named 'fast' (output)"] - Pausing so you can connect a receiver to the newly created - "fast" port. Type ENTER to proceed: -[In fastrcv:] - Input device number: >>3 [pick the device named "fast (input)"] -[In fast:] - >> [type ENTER to start] -[see message counts and times as above ] - -Check output of fastrcv: there should be no errors, just msg/sec.] - -27. ./fast [latency = 0, macOS and Linux only] - ./fastrcv [virtual input port, in another shell] -[In fastrcv:] - Input device number: >>8 [enter number listed for "Create virtual - port named 'fastrcv' (input)"] -[In fast:] - Latency in ms: >>0 - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>7 [pick the device named "fastrcv (output)"] - sending output... -[see message counts and times as above ] - -Check output of fastrcv: there should be no errors, just msg/sec.] - -28. ./fast [latency > 0, macOS and Linux only] - ./fastrcv [virtual input port, in another shell] -[In fastrcv:] - Input device number: >>8 [enter number listed for "Create virtual - port named 'fastrcv' (input)"] -[In fast:] - Latency in ms: >>30 [Note for ALSA, use latency * msgs/ms < 400] - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>7 [pick the device named "fastrcv (output)"] - sending output... -[see message counts and times as above ] - -Check output of fastrcv: there should be no errors, just msg/sec.] - -29. ./midithru -v -n [virtual input and output, macOS and Linux only] - ./fast [latency = 0] - ./fastrcv [in another shell] -[Start midithru first, it will run for 60 seconds] -[In fastrcv:] - Input device number: >>3 [pick the device named - port named "midithru (input)"] -[In fast:] - Latency in ms: >>0 - Rate in messages per second: >>10000 - Duration in seconds: >>10 - Output device number: >>8 [pick the device named "midithru (output)"] - sending output... -[see message counts and times as above, on Mac, output from fast to - midithru AND output from midithru to fastrcv are rate limited, so - as in other tests, it will take more than 10s to receive all the - messages and the receiving message rate will be about 1800 messages/second] - -30. ./multivirtual [macOS and Linux only] - ./testio - ./testio -[Start multivirtual first] -[In first testio:] - Latency in ms: >>0 - enter your choice... >>5 [test both] - Type input number: >>1 [pick portmidi1 (input) - Type output number: >>4 [pick portmidi1 (output) -[In second testio:] - Latency in ms: >>10 - enter your choice... >>5 [test both] - Type input number: >>2 [pick portmidi2 (input) - Type output number: >>5 [pick portmidi2 (output) -[In multivirtual:] - Type ENTER to send messages: >> [type ENTER to start] -[see that each testio gets 11 messages (0 to 10) at reasonable times - (e.g. 2077 to 7580, and the "@" times (real times) should match the - timestamps). multivirtual should also report reasonable times and - line near the end of output should be "Got 11 messages from - portmidi1 and 11 from portmidi2; expected 11."] - -31. ./multivirtual [macOS and Linux only] - ./multivirtual -[Second instance should report "PortMidi call failed... - PortMidi: Cannot create virtual device: name is taken"] - -32. pmlist - ./pmlist [check the output] - [plug in or remove a device] - >> [type RETURN] - [check for changes in device list] - >>q - - - - diff --git a/portmidi/pm_test/fast.c b/portmidi/pm_test/fast.c deleted file mode 100644 index 102697e..0000000 --- a/portmidi/pm_test/fast.c +++ /dev/null @@ -1,290 +0,0 @@ -/* fast.c -- send many MIDI messages very fast. - * - * This is a stress test created to explore reports of - * pm_write() call blocking (forever) on Linux when - * sending very dense MIDI sequences. - * - * Modified 8 Aug 2017 with -n to send expired timestamps - * to test a theory about why Linux ALSA hangs in Audacity. - * - * Modified 9 Aug 2017 with -m, -p to test when timestamps are - * wrapping from negative to positive or positive to negative. - * - * Roger B. Dannenberg, Aug 2017 - */ - -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define DEVICE_INFO NULL -#define DRIVER_INFO NULL -#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ - -#define STRING_MAX 80 /* used for console input */ -// need to get declaration for Sleep() -#ifdef WIN32 -#include "windows.h" -#else -#include -#define Sleep(n) usleep(n * 1000) -#endif - - -int32_t latency = 0; -int32_t msgrate = 0; -int deviceno = -9999; -int duration = 0; -int expired_timestamps = FALSE; -int use_timeoffset = 0; - -/* read a number from console */ -/**/ -int get_number(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - return i; -} - - -/* get_time -- the time reference. Normally, this will be the default - * time, Pt_Time(), but if you use the -p or -m option, the time - * reference will start at an offset of -10s for -m, or - * maximum_time - 10s for -p, so that we can observe what happens - * with negative time or when time changes sign or wraps (by - * generating output for more than 10s). - */ -PmTimestamp get_time(void *info) -{ - PmTimestamp now = (PmTimestamp) (Pt_Time() + use_timeoffset); - return now; -} - - -void fast_test() -{ - PmStream *midi; - char line[STRING_MAX]; - int pause = FALSE; /* pause if this is a virtual output port */ - PmError err = pmNoError; - /* output buffer size should be a little more than - msgrate * latency / 1000. PortMidi will guarantee - a minimum of latency / 2 */ - int buffer_size = msgrate * latency / 900; - PmTimestamp start, now; - int msgcnt = 0; - int polling_count = 0; - int pitch = 60; - int printtime = 1000; - - /* It is recommended to start timer before PortMidi */ - TIME_START; - - /* open output device */ - if (deviceno == Pm_CountDevices()) { - deviceno = Pm_CreateVirtualOutput("fast", NULL, DEVICE_INFO); - if (deviceno >= 0) { - err = Pm_OpenOutput(&midi, deviceno, DRIVER_INFO, buffer_size, - get_time, NULL, latency); - pause = TRUE; - } - } else if (err >= pmNoError) { - err = Pm_OpenOutput(&midi, deviceno, DRIVER_INFO, buffer_size, - get_time, NULL, latency); - } - if (err == pmHostError) { - Pm_GetHostErrorText(line, STRING_MAX); - printf("PortMidi found host error...\n %s\n", line); - goto done; - } else if (err < 0) { - printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); - goto done; - } - printf("Midi Output opened with %ld ms latency.\n", (long) latency); - if (pause) { - printf("Pausing so you can connect a receiver to the newly created\n" - " \"fast\" port. Type ENTER to proceed: "); - while (getchar() != '\n') ; - } - /* wait a sec after printing previous line */ - start = get_time(NULL) + 1000; - while (start > get_time(NULL)) { - Sleep(10); - } - printf("sending output...\n"); - fflush(stdout); /* make sure message goes to console */ - - /* every 10ms send on/off pairs at timestamps set to current time */ - now = get_time(NULL); - /* if expired_timestamps, we want to send timestamps that have - * expired. They should be sent immediately, but there's a suggestion - * that negative delay might cause problems in the ALSA implementation - * so this is something we can test using the -n flag. - */ - if (expired_timestamps) { - now = now - 2 * latency; - } - - while (((PmTimestamp) (now - start)) < duration * 1000 || pitch != 60) { - /* how many messages do we send? Total should be - * (elapsed * rate) / 1000 - */ - int send_total = (((PmTimestamp) ((now - start))) * msgrate) / 1000; - /* always send until pitch would be 60 so if we run again, the - next pitch (60) will be expected */ - if (msgcnt < send_total) { - if ((msgcnt & 1) == 0) { - Pm_WriteShort(midi, now, Pm_Message(0x90, pitch, 100)); - } else { - Pm_WriteShort(midi, now, Pm_Message(0x90, pitch, 0)); - /* play 60, 61, 62, ... 71, then wrap back to 60, 61, ... */ - pitch = (pitch - 59) % 12 + 60; - } - msgcnt += 1; - if (((PmTimestamp) (now - start)) >= printtime) { - printf("%d at %dms, polling count %d\n", msgcnt, now - start, - polling_count); - fflush(stdout); /* make sure message goes to console */ - printtime += 1000; /* next msg in 1s */ - } - } - now = get_time(NULL); - polling_count++; - } - /* close device (this not explicitly needed in most implementations) */ - printf("ready to close and terminate... (type RETURN):"); - while (getchar() != '\n') ; - - Pm_Close(midi); - done: - Pm_Terminate(); - printf("done closing and terminating...\n"); -} - - -void show_usage() -{ - printf("Usage: fast [-h] [-l latency] [-r rate] [-d device] [-s dur] " - "[-n] [-p] [-m]\n" - ", where latency is in ms,\n" - " rate is messages per second,\n" - " device is the PortMidi device number,\n" - " dur is the length of the test in seconds,\n" - " -n means send timestamps in the past,\n" - " -p means use a large positive time offset,\n" - " -m means use a large negative time offset, and\n" - " -h means help.\n"); -} - -int main(int argc, char *argv[]) -{ - int default_in; - int default_out; - char *deflt; - int i = 0; - int latency_valid = FALSE; - int rate_valid = FALSE; - int device_valid = FALSE; - int dur_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"); - - if (argc <= 1) { - show_usage(); - } else { - 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 if (strcmp(argv[i], "-r") == 0) { - i = i + 1; - msgrate = atoi(argv[i]); - printf("Rate will be %d messages/second\n", msgrate); - rate_valid = TRUE; - } else if (strcmp(argv[i], "-d") == 0) { - i = i + 1; - deviceno = atoi(argv[i]); - printf("Device will be %d\n", deviceno); - } else if (strcmp(argv[i], "-s") == 0) { - i = i + 1; - duration = atoi(argv[i]); - printf("Duration will be %d seconds\n", duration); - dur_valid = TRUE; - } else if (strcmp(argv[i], "-n") == 0) { - printf("Sending expired timestamps (-n)\n"); - expired_timestamps = TRUE; - } else if (strcmp(argv[i], "-p") == 0) { - printf("Time offset set to 2147473648 (-p)\n"); - use_timeoffset = 2147473648; - } else if (strcmp(argv[i], "-m") == 0) { - printf("Time offset set to -10000 (-m)\n"); - use_timeoffset = -10000; - } else { - show_usage(); - } - } - } - - if (!latency_valid) { - // coerce to known size - latency = (int32_t) get_number("Latency in ms: "); - } - - if (!rate_valid) { - // coerce from "%d" to known size - msgrate = (int32_t) get_number("Rate in messages per second: "); - } - - if (!dur_valid) { - duration = get_number("Duration in seconds: "); - } - - /* list device information */ - default_in = Pm_GetDefaultInputDeviceID(); - default_out = Pm_GetDefaultOutputDeviceID(); - for (i = 0; i < Pm_CountDevices(); i++) { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - if (info->output) { - printf("%d: %s, %s", i, info->interf, info->name); - if (i == deviceno) { - device_valid = TRUE; - deflt = "selected "; - } else if (i == default_out) { - deflt = "default "; - } else { - deflt = ""; - } - printf(" (%soutput)\n", deflt); - } - } - printf("%d: Create virtual port named \"fast\"", i); - if (i == deviceno) { - device_valid = TRUE; - deflt = "selected "; - } else { - deflt = ""; - } - printf(" (%soutput)\n", deflt); - - if (!device_valid) { - deviceno = get_number("Output device number: "); - } - - fast_test(); - return 0; -} diff --git a/portmidi/pm_test/fastrcv.c b/portmidi/pm_test/fastrcv.c deleted file mode 100644 index dabf9fa..0000000 --- a/portmidi/pm_test/fastrcv.c +++ /dev/null @@ -1,255 +0,0 @@ -/* fastrcv.c -- send many MIDI messages very fast. - * - * This is a stress test created to explore reports of - * pm_write() call blocking (forever) on Linux when - * sending very dense MIDI sequences. - * - * Modified 8 Aug 2017 with -n to send expired timestamps - * to test a theory about why Linux ALSA hangs in Audacity. - * - * Roger B. Dannenberg, Aug 2017 - */ - -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define INPUT_BUFFER_SIZE 1000 /* big to avoid losing any input */ -#define DEVICE_INFO NULL -#define DRIVER_INFO NULL -#define TIME_PROC ((PmTimeProcPtr) 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 */ -// need to get declaration for Sleep() -#ifdef WIN32 -#include "windows.h" -#else -#include -#define Sleep(n) usleep(n * 1000) -#endif - - -int deviceno = -9999; -int verbose = FALSE; - - -static void prompt_and_exit(void) -{ - printf("type ENTER..."); - while (getchar() != '\n') ; - /* this will clean up open ports: */ - exit(-1); -} - - -static PmError checkerror(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 - */ - char errmsg[80]; - Pm_GetHostErrorText(errmsg, 80); - printf("PortMidi found host error...\n %s\n", errmsg); - prompt_and_exit(); - } else if (err < 0) { - printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); - prompt_and_exit(); - } - return err; -} - - -/* read a number from console */ -/**/ -int get_number(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - return i; -} - - -void fastrcv_test() -{ - PmStream * midi; - PmError status, length; - PmEvent buffer[1]; - PmTimestamp start; - /* every 10ms read all messages, keep counts */ - /* every 1000ms, print report */ - int msgcnt = 0; - /* expect repeating sequence of 60 through 71, alternating on/off */ - int expected_pitch = 60; - int expected_on = TRUE; - int report_time; - PmTimestamp last_timestamp = -1; - PmTimestamp last_delta = -1; - - /* It is recommended to start timer before PortMidi */ - TIME_START; - - /* open output device */ - if (deviceno == Pm_CountDevices()) { - int id = Pm_CreateVirtualInput("fastrcv", NULL, DEVICE_INFO); - if (id < 0) checkerror(id); /* error reporting */ - checkerror(Pm_OpenInput(&midi, id, DRIVER_INFO, - INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO)); - } else { - Pm_OpenInput(&midi, deviceno, DRIVER_INFO, INPUT_BUFFER_SIZE, - TIME_PROC, TIME_INFO); - } - printf("Midi Input opened.\n"); - - /* wait a sec after printing previous line */ - start = Pt_Time() + 1000; - while (start > Pt_Time()) { - Sleep(10); - } - - report_time = Pt_Time() + 1000; /* report every 1s */ - while (TRUE) { - PmTimestamp now = Pt_Time(); - status = Pm_Poll(midi); - if (status == TRUE) { - length = Pm_Read(midi, buffer, 1); - if (length > 0) { - int status = Pm_MessageStatus(buffer[0].message); - if (status == 0x80) { /* convert NoteOff to NoteOn, vel=0 */ - status = 0x90; - buffer[0].message = Pm_Message(status, - Pm_MessageData1(buffer[0].message), 0); - } - /* only listen to NOTEON messages */ - if (status == 0x90) { - int pitch = Pm_MessageData1(buffer[0].message); - int vel = Pm_MessageData2(buffer[0].message); - int is_on = (vel > 0); - if (verbose) { - printf("Note pitch %d vel %d\n", pitch, vel); - } - msgcnt++; - if (pitch != expected_pitch || expected_on != is_on) { - printf("Unexpected note-on: pitch %d vel %d, " - "expected: pitch %d Note%s\n", pitch, vel, - expected_pitch, (expected_on ? "On" : "Off")); - } - if (is_on) { - expected_on = FALSE; - expected_pitch = pitch; - } else { - expected_on = TRUE; - expected_pitch = (pitch + 1) % 72; - if (expected_pitch < 60) expected_pitch = 60; - } - if (last_timestamp >= 0) { - last_delta = buffer[0].timestamp - last_timestamp; - } - last_timestamp = buffer[0].timestamp; - } - } - } - if (now >= report_time) { - printf("%d msgs/sec", msgcnt); - /* if available, print the last timestamp and last delta time */ - if (last_timestamp >= 0) { - printf(" last timestamp %d", (int) last_timestamp); - last_timestamp = -1; - } - if (last_delta >= 0) { - printf(" last delta time %d", (int) last_delta); - last_delta = -1; - } - printf("\n"); - report_time += 1000; - msgcnt = 0; - } - } -} - - -void show_usage() -{ - printf("Usage: fastrcv [-h] [-v] [-d device], where\n" - "device is the PortMidi device number,\n" - "-h means help,\n" - "-v means verbose (print messages)\n"); -} - -int main(int argc, char *argv[]) -{ - int default_in; - int default_out; - char *deflt; - - int i = 0; - int test_input = 0, test_output = 0, test_both = 0; - int stream_test = 0; - int device_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"); - - if (argc <= 1) { - show_usage(); - } else { - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-h") == 0) { - show_usage(); - } else if (strcmp(argv[i], "-v") == 0) { - verbose = TRUE; - } else if (strcmp(argv[i], "-d") == 0) { - i = i + 1; - deviceno = atoi(argv[i]); - printf("Device will be %d\n", deviceno); - } else { - show_usage(); - } - } - } - - /* list device information */ - default_in = Pm_GetDefaultInputDeviceID(); - default_out = Pm_GetDefaultOutputDeviceID(); - for (i = 0; i < Pm_CountDevices(); i++) { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - if (!info->output) { - printf("%d: %s, %s", i, info->interf, info->name); - if (i == deviceno) { - device_valid = TRUE; - deflt = "selected "; - } else if (i == default_out) { - deflt = "default "; - } else { - deflt = ""; - } - printf(" (%sinput)\n", deflt); - } - } - printf("%d: Create virtual port named \"fastrcv\"", i); - if (i == deviceno) { - device_valid = TRUE; - deflt = "selected "; - } else { - deflt = ""; - } - printf(" (%sinput)\n", deflt); - - if (!device_valid) { - deviceno = get_number("Input device number: "); - } - - fastrcv_test(); - return 0; -} diff --git a/portmidi/pm_test/latency.c b/portmidi/pm_test/latency.c deleted file mode 100755 index 06ea80d..0000000 --- a/portmidi/pm_test/latency.c +++ /dev/null @@ -1,287 +0,0 @@ -/* 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(const 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(); - 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() -{ - 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("Latency measurements will start in 5 seconds. " - "Type return to stop: "); - Pt_Start(period, &pt_callback, 0); - while (getchar() != '\n') ; - stop = Pt_Time(); - Pt_Stop(); - - /* courteously turn off the last note, if necessary */ - if (note_on) { - PmEvent buffer[1]; - buffer[0].timestamp = Pt_Time(); - 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..."); - while (getchar() != '\n') ; - - 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(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - return i; -} diff --git a/portmidi/pm_test/midiclock.c b/portmidi/pm_test/midiclock.c deleted file mode 100644 index f0a6897..0000000 --- a/portmidi/pm_test/midiclock.c +++ /dev/null @@ -1,282 +0,0 @@ -/* 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 ((PmTimeProcPtr) 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(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - 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) -{ - 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) { - puts(Pm_GetErrorText(err)); - goto error_exit_no_device; - } - active = true; - - printf("Type ENTER to start MIDI CLOCK:\n"); - while (getchar() != '\n') ; - send_start_stop = true; /* send START and then CLOCKs */ - - while (!done) { - doascii(getchar()); - while (getchar() != '\n') ; - } - - 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); -} - diff --git a/portmidi/pm_test/midithread.c b/portmidi/pm_test/midithread.c deleted file mode 100755 index ea0613b..0000000 --- a/portmidi/pm_test/midithread.c +++ /dev/null @@ -1,343 +0,0 @@ -/* 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) -{ - printf("%s\n", msg); - while (getchar() != '\n') ; - exit(1); -} - -int main(int argc, char *argv[]) -{ - int32_t n; - const PmDeviceInfo *info; - char line[STRING_MAX]; - int spin; - int done = FALSE; - int i; - int input = -1, output = -1; - - printf("Usage: midithread [-i input] [-o output]\n" - "where input and output are portmidi device numbers\n"); - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-i") == 0) { - i++; - input = atoi(argv[i]); - printf("Input device number: %d\n", input); - } else if (strcmp(argv[i], "-o") == 0) { - i++; - output = atoi(argv[i]); - printf("Output device number: %d\n", output); - } else { - return -1; - } - } - 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(); - - output = (output < 0 ? Pm_GetDefaultOutputDeviceID() : output); - info = Pm_GetDeviceInfo(output); - if (info == NULL) { - printf("Could not open output device (%d).", output); - 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, - output, - DRIVER_INFO, - OUTPUT_BUFFER_SIZE, - TIME_PROC, - TIME_INFO, - LATENCY); - - input = (input < 0 ? Pm_GetDefaultInputDeviceID() : input); - info = Pm_GetDeviceInfo(input); - if (info == NULL) { - printf("Could not open default input device (%d).", input); - exit_with_message(""); - } - printf("Opening input device %s %s\n", info->interf, info->name); - Pm_OpenInput(&midi_in, - input, - 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("Type 'q' to quit, 'm' to monitor next pitch, t to toggle thru or\n" - "type a number to specify transposition.\n" - "Must terminate with [ENTER]\n"); - - while (!done) { - int32_t msg; - int input; - int len; - if (!fgets(line, STRING_MAX, stdin)) break; /* no stdin? */ - /* remove the newline: */ - len = (int) 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); - - fputs("finished portMidi multithread test.\n" - "type ENTER to quit:", stdout); - while (getchar() != '\n') ; - return 0; -} diff --git a/portmidi/pm_test/midithru.c b/portmidi/pm_test/midithru.c deleted file mode 100755 index 94b4f13..0000000 --- a/portmidi/pm_test/midithru.c +++ /dev/null @@ -1,455 +0,0 @@ -/* 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 using lock-free queues. 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 -#define STRING_MAX 80 /* used for console input */ - -/* active is set true when midi processing should start, must be - * volatile to force thread to check for updates by other thread */ -int active = FALSE; -/* process_midi_exit_flag is set when the timer thread shuts down; - * must be volatile so it is re-read in the while loop that waits on it */ -volatile 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; -/* this is volatile because it is set in the process_midi callback and - * the main thread reads it to sense elapsed time. Without volatile, the - * optimizer can put it in a register and not see the updates. - */ -volatile PmTimestamp current_timestamp = 0; -int thru_sysex_in_progress = FALSE; -int app_sysex_in_progress = FALSE; -PmTimestamp last_timestamp = 0; - - -static void prompt_and_exit(void) -{ - printf("type ENTER..."); - while (getchar() != '\n') ; - /* this will clean up open ports: */ - exit(-1); -} - - -static PmError checkerror(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 - */ - char errmsg[80]; - Pm_GetHostErrorText(errmsg, 80); - printf("PortMidi found host error...\n %s\n", errmsg); - prompt_and_exit(); - } else if (err < 0) { - printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); - prompt_and_exit(); - } - return err; -} - - -/* 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 */ - - /* 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 - printf("%s\nType ENTER...", msg); - while (getchar() != '\n') ; - exit(1); -} - - -void initialize(int input, int output, int virtual) -/* 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; - - /* 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(); - - if (output < 0) { - if (!virtual) { - output = Pm_GetDefaultOutputDeviceID(); - } - } - if (output >= 0) { - info = Pm_GetDeviceInfo(output); - if (info == NULL) { - printf("Could not open default output device (%d).", output); - 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, - output, - NULL /* driver info */, - OUT_QUEUE_SIZE, - &midithru_time_proc, - NULL /* time info */, - 0 /* Latency */); - } else { /* send to virtual port */ - int id; - printf("Opening virtual output device \"midithru\"\n"); - id = Pm_CreateVirtualOutput("midithru", NULL, NULL); - if (id < 0) checkerror(id); /* error reporting */ - checkerror(Pm_OpenOutput(&midi_out, id, NULL, OUT_QUEUE_SIZE, - &midithru_time_proc, NULL, 0)); - } - if (input < 0) { - if (!virtual) { - input = Pm_GetDefaultInputDeviceID(); - } - } - if (input >= 0) { - info = Pm_GetDeviceInfo(input); - if (info == NULL) { - printf("Could not open default input device (%d).", input); - exit_with_message(""); - } - - printf("Opening input device %s %s\n", info->interf, info->name); - Pm_OpenInput(&midi_in, - input, - NULL /* driver info */, - 0 /* use default input size */, - &midithru_time_proc, - NULL /* time info */); - } else { /* receive from virtual port */ - int id; - printf("Opening virtual input device \"midithru\"\n"); - id = Pm_CreateVirtualInput("midithru", NULL, NULL); - if (id < 0) checkerror(id); /* error reporting */ - checkerror(Pm_OpenInput(&midi_in, id, NULL, 0, - &midithru_time_proc, NULL)); - } - /* 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; - int i; - int input = -1, output = -1; - int virtual = FALSE; - int delay_enable = TRUE; - - printf("Usage: midithru [-i input] [-o output] [-v] [-n]\n" - "where input and output are portmidi device numbers\n" - "if -v and input and/or output are not specified,\n" - "then virtual ports are created and used instead.\n" - "-n turns off the default MIDI delay effect.\n"); - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-i") == 0) { - i++; - input = atoi(argv[i]); - printf("Input device number: %d\n", input); - } else if (strcmp(argv[i], "-o") == 0) { - i++; - output = atoi(argv[i]); - printf("Output device number: %d\n", output); - } else if (strcmp(argv[i], "-v") == 0) { - virtual = TRUE; - } else if (strcmp(argv[i], "-n") == 0) { - delay_enable = FALSE; - printf("delay_effect is disabled\n"); - } else { - return -1; - } - } - printf("begin PortMidi midithru program...\n"); - - initialize(input, output, virtual); /* set up and start midi processing */ - - printf("This program will run for 60 seconds, " - "or until you play B below middle C,\n" - "All input is sent immediately, implementing software MIDI THRU.\n" - "Also, all input is echoed with a 2 second delay.\n"); - - 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); */ - if (delay_enable) { - buffer.timestamp = buffer.timestamp + 2000; /* delay */ - Pm_Enqueue(out_queue, &buffer); - } - /* play B3 to break out of loop */ - if (Pm_MessageStatus(buffer.message) == 0x90 && - Pm_MessageData1(buffer.message) == 59) { - goto quit_now; - } - } - } -quit_now: - finalize(); - exit_with_message("finished PortMidi midithru program."); - return 0; /* never executed, but keeps the compiler happy */ -} diff --git a/portmidi/pm_test/mm.c b/portmidi/pm_test/mm.c deleted file mode 100755 index ab9d32e..0000000 --- a/portmidi/pm_test/mm.c +++ /dev/null @@ -1,595 +0,0 @@ -/* 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(const char *prompt); - - -/* read a number from console */ -/**/ -int get_number(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - 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 puts(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 */ - puts("MIDI input devices:"); - 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) { - puts(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) { - doascii(getchar()); - while (getchar() != '\n') ; - } - 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; - if (inited) { - printf("Clock and Active Sense Counting %s\n", (clksencnt ? "ON" : "OFF")); - printf("Resetting Clock and Active Sense counts.\n"); - clockcount = actsensecount = 0; - } - } else if (c == 's') { - if (inited) { - printf("Clock Count %ld\nActive Sense Count %ld\n", - (long) clockcount, (long) actsensecount); - } - } 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)) { - if (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) { - if (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) { - if (controls) { - 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) { - if (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) { - if (bender) { - showbytes(data, 2, verbose); - if (verbose) { - printf(" A.Touch Chan %2d Val %2d\n", chan, - Pm_MessageData1(data)); - } - } - } else if (command == MIDI_BEND) { - if (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) { - if (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) { - if (realdata) { - showbytes(data, 1, verbose); - if (verbose) { - printf(" Start\n"); - } - } - } else if (Pm_MessageStatus(data) == MIDI_CONTINUE) { - if (realdata) { - showbytes(data, 1, verbose); - if (verbose) { - printf(" Continue\n"); - } - } - } else if (Pm_MessageStatus(data) == MIDI_STOP) { - if (realdata) { - showbytes(data, 1, verbose); - if (verbose) { - printf(" Stop\n"); - } - } - } else if (Pm_MessageStatus(data) == MIDI_SYS_RESET) { - if (realdata) { - showbytes(data, 1, verbose); - if (verbose) { - printf(" System Reset\n"); - } - } - } else if (Pm_MessageStatus(data) == MIDI_TIME_CLOCK) { - clockcount++; - if (clksencnt) { - showbytes(data, 1, verbose); - if (verbose) { - printf(" Clock\n"); - } - } - } else if (Pm_MessageStatus(data) == MIDI_ACTIVE_SENSING) { - actsensecount++; - if (clksencnt) { - 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); - fputs(result, stdout); - return (int) 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 messages, clears counts"); - 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"); -} diff --git a/portmidi/pm_test/multivirtual.c b/portmidi/pm_test/multivirtual.c deleted file mode 100644 index b90d860..0000000 --- a/portmidi/pm_test/multivirtual.c +++ /dev/null @@ -1,223 +0,0 @@ -/* multivirtual.c -- test for creating two input and two output virtual ports */ -/* - * Roger B. Dannenberg - * Oct 2021 - */ -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define OUTPUT_BUFFER_SIZE 0 -#define DEVICE_INFO NULL -#define DRIVER_INFO NULL -#define TIME_PROC ((PmTimeProcPtr) Pt_Time) -#define TIME_INFO NULL -#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ - -int latency = 0; - -static void prompt_and_exit(void) -{ - printf("type ENTER..."); - while (getchar() != '\n') ; - /* this will clean up open ports: */ - exit(-1); -} - - -static PmError checkerror(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 - */ - char errmsg[80]; - Pm_GetHostErrorText(errmsg, 80); - printf("PortMidi found host error...\n %s\n", errmsg); - prompt_and_exit(); - } else if (err < 0) { - printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); - prompt_and_exit(); - } - return err; -} - -static int msg_count[2] = {0, 0}; - -void poll_input(PmStream *in, int which) -{ - PmEvent buffer[1]; - int pitch, expected, length; - PmError status = Pm_Poll(in); - if (status == TRUE) { - length = Pm_Read(in, buffer, 1); - if (length > 0) { - printf("Got message %d from portmidi%d: " - "time %ld, %2x %2x %2x\n", - msg_count[which], which + 1, (long) buffer[0].timestamp, - (status = Pm_MessageStatus(buffer[0].message)), - (pitch = Pm_MessageData1(buffer[0].message)), - Pm_MessageData2(buffer[0].message)); - if (status == 0x90) { /* 1 & 2 are on/off 60, 3 & 4 are 61, etc. */ - expected = (((msg_count[which] - 1) / 2) % 12) + 60 + - which * 12; - if (pitch != expected) { - printf("WARNING: expected pitch %d, got pitch %d\n", - expected, pitch); - } - } - msg_count[which]++; - } else { - assert(0); - } - } -} - - -void wait_until(PmTimestamp when, PmStream *in1, PmStream *in2) -{ - while (when > Pt_Time()) { - poll_input(in1, 0); - poll_input(in2, 1); - Pt_Sleep(10); - } -} - - -/* create one virtual output device and one input device */ -void init(const char *name, PmStream **midi_out, PmStream **midi_in, - int *id_out, int *id_in) -{ - PmEvent buffer[1]; - - *id_out = checkerror(Pm_CreateVirtualOutput(name, NULL, DEVICE_INFO)); - checkerror(Pm_OpenOutput(midi_out, *id_out, DRIVER_INFO, OUTPUT_BUFFER_SIZE, - TIME_PROC, TIME_INFO, latency)); - printf("Virtual Output \"%s\" id %d created and opened.\n", name, *id_out); - - *id_in = checkerror(Pm_CreateVirtualInput(name, NULL, DRIVER_INFO)); - checkerror(Pm_OpenInput(midi_in, *id_in, NULL, 0, NULL, NULL)); - printf("Virtual Input \"%s\" id %d created and opened.\n", name, *id_in); - Pm_SetFilter(*midi_in, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX); - /* empty the buffer after setting filter, just in case anything - got through */ - while (Pm_Read(*midi_in, buffer, 1)) ; -} - - -void main_test(int num) -{ - PmStream *midi1_out; - PmStream *midi2_out; - PmStream *midi1_in; - PmStream *midi2_in; - int id1_out; - int id2_out; - int id1_in; - int id2_in; - int32_t next_time; - PmEvent buffer[1]; - int pitch = 60; - int expected_count = num + 1; /* add 1 for MIDI Program message */ - - /* It is recommended to start timer before Midi; otherwise, PortMidi may - start the timer with its (default) parameters - */ - TIME_START; - - init("portmidi1", &midi1_out, &midi1_in, &id1_out, &id1_in); - init("portmidi2", &midi2_out, &midi2_in, &id2_out, &id2_in); - - printf("Type ENTER to send messages: "); - while (getchar() != '\n') ; - - buffer[0].timestamp = Pt_Time(); -#define PROGRAM 0 - buffer[0].message = Pm_Message(0xC0, PROGRAM, 0); - Pm_Write(midi1_out, buffer, 1); - Pm_Write(midi2_out, buffer, 1); - next_time = Pt_Time() + 1000; /* wait 1s */ - while (num > 0) { - wait_until(next_time, midi1_in, midi2_in); - Pm_WriteShort(midi1_out, next_time, Pm_Message(0x90, pitch, 100)); - Pm_WriteShort(midi2_out, next_time, Pm_Message(0x90, pitch + 12, 100)); - printf("Note On pitch %d\n", pitch); - num--; - next_time += 500; - - wait_until(next_time, midi1_in, midi2_in); - Pm_WriteShort(midi1_out, next_time, Pm_Message(0x90, pitch, 0)); - Pm_WriteShort(midi2_out, next_time, Pm_Message(0x90, pitch + 12, 0)); - printf("Note Off pitch %d\n", pitch); - num--; - pitch = (pitch + 1) % 12 + 60; - next_time += 500; - } - wait_until(next_time, midi1_in, midi2_in); /* get final note-offs */ - - printf("Got %d messages from portmidi1 and %d from portmidi2; " - "expected %d.\n", msg_count[0], msg_count[1], expected_count); - - /* close devices (this not explicitly needed in most implementations) */ - printf("ready to close..."); - checkerror(Pm_Close(midi1_out)); - checkerror(Pm_Close(midi2_out)); - checkerror(Pm_Close(midi1_in)); - checkerror(Pm_Close(midi2_in)); - printf("done closing.\nNow delete the virtual devices..."); - checkerror(Pm_DeleteVirtualDevice(id1_out)); - checkerror(Pm_DeleteVirtualDevice(id1_in)); - checkerror(Pm_DeleteVirtualDevice(id2_out)); - checkerror(Pm_DeleteVirtualDevice(id2_in)); - printf("done deleting.\n"); -} - - -void show_usage() -{ - printf("Usage: multivirtual [-h] [-l latency-in-ms] [n]\n" - " -h for this message,\n" - " -l ms designates latency for precise timing (default 0),\n" - " n is number of message to send each output, not counting\n" - " initial program change.\n" - "sends change program to 1, then one note per second with 0.5s on,\n" - "0.5s off, for n/2 seconds to both output ports portmidi1 and\n" - "portmidi2. portmidi1 gets pitches from C4 (60). portmidi2 gets\n" - "pitches an octave higher. Latency >0 uses the device driver for \n" - "precise timing (see PortMidi documentation). Inputs print what\n" - "they get and print WARNING if they get something unexpected.\n" - "The expected test is use two instances of testio to loop\n" - "portmidi1 back to portmidi1 and portmidi2 back to portmidi2.\n"); - exit(0); -} - - -int main(int argc, char *argv[]) -{ - int num = 10; - int i; - 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 %d\n", latency); - } else { - num = atoi(argv[1]); - if (num <= 0) { - show_usage(); - } - printf("Sending %d messages.\n", num); - } - } - - main_test(num); - - printf("finished sendvirtual test...type ENTER to quit..."); - while (getchar() != '\n') ; - return 0; -} diff --git a/portmidi/pm_test/pmlist.c b/portmidi/pm_test/pmlist.c deleted file mode 100644 index 5e3d1db..0000000 --- a/portmidi/pm_test/pmlist.c +++ /dev/null @@ -1,63 +0,0 @@ -/* pmlist.c -- list portmidi devices and numbers - * - * This program lists devices. When you type return, it - * restarts portmidi and lists devices again. It is mainly - * a test for shutting down and restarting. - * - * Roger B. Dannenberg, Feb 2022 - */ - -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define DEVICE_INFO NULL -#define DRIVER_INFO NULL -#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ - -#define STRING_MAX 80 /* used for console input */ - -void show_usage() -{ - printf("Usage: pmlist [-h]\n -h means help.\n" - " Type return to rescan and list devices, q to quit\n"); -} - - -int main(int argc, char *argv[]) -{ - if (argc > 1) { - show_usage(); - exit(0); - } - - while (1) { - char input[STRING_MAX]; - const char *deflt; - const char *in_or_out; - int default_in, default_out, i; - - // Pm_Initialize(); - /* list device information */ - default_in = Pm_GetDefaultInputDeviceID(); - default_out = Pm_GetDefaultOutputDeviceID(); - for (i = 0; i < Pm_CountDevices(); i++) { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - printf("%d: %s, %s", i, info->interf, info->name); - deflt = ""; - if (i == default_out || i == default_in) { - deflt = "default "; - } - in_or_out = (info->input ? "input" : "output"); - printf(" (%s%s)\n", deflt, in_or_out); - } - if (fgets(input, STRING_MAX, stdin) && input[0] == 'q') { - return 0; - } - Pm_Terminate(); - } - return 0; -} diff --git a/portmidi/pm_test/qtest.c b/portmidi/pm_test/qtest.c deleted file mode 100644 index 14d803e..0000000 --- a/portmidi/pm_test/qtest.c +++ /dev/null @@ -1,174 +0,0 @@ -#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; -} diff --git a/portmidi/pm_test/recvvirtual.c b/portmidi/pm_test/recvvirtual.c deleted file mode 100644 index f8d9848..0000000 --- a/portmidi/pm_test/recvvirtual.c +++ /dev/null @@ -1,175 +0,0 @@ -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define INPUT_BUFFER_SIZE 100 -#define TIME_PROC ((PmTimeProcPtr) 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 */ - -char *portname = "portmidi"; - -PmSysDepInfo *sysdepinfo = NULL; -char *port_name = "portmidi"; - -static void set_sysdepinfo(char m_or_p, const char *name) -{ - if (!sysdepinfo) { - // allocate some space we will alias with open-ended PmDriverInfo: - // there is space for 4 parameters: - static char dimem[sizeof(PmSysDepInfo) + sizeof(void *) * 8]; - sysdepinfo = (PmSysDepInfo *) dimem; - // build the driver info structure: - sysdepinfo->structVersion = PM_SYSDEPINFO_VERS; - sysdepinfo->length = 0; - } - if (sysdepinfo->length > 1) { - printf("Error: sysdepinfo was allocated to hold 2 parameters\n"); - exit(1); - } - int i = sysdepinfo->length++; - enum PmSysDepPropertyKey k = pmKeyNone; - if (m_or_p == 'm') k = pmKeyCoreMidiManufacturer; - else if (m_or_p == 'p') k = pmKeyAlsaPortName; - else if (m_or_p == 'c') k = pmKeyAlsaClientName; - sysdepinfo->properties[i].key = k; - sysdepinfo->properties[i].value = name; -} - - -static void prompt_and_exit(void) -{ - printf("type ENTER..."); - while (getchar() != '\n') ; - /* this will clean up open ports: */ - exit(-1); -} - - -static PmError checkerror(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 - */ - char errmsg[80]; - Pm_GetHostErrorText(errmsg, 80); - printf("PortMidi found host error...\n %s\n", errmsg); - prompt_and_exit(); - } else if (err < 0) { - printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); - prompt_and_exit(); - } - return err; -} - - -void main_test_input(int num) -{ - PmStream *midi; - PmError status, length; - PmEvent buffer[1]; - int id; - int i = 0; /* count messages as they arrive */ - /* It is recommended to start timer before Midi; otherwise, PortMidi may - start the timer with its (default) parameters - */ - TIME_START; - - /* create a virtual input device */ - id = checkerror(Pm_CreateVirtualInput(port_name, NULL, sysdepinfo)); - checkerror(Pm_OpenInput(&midi, id, sysdepinfo, 0, NULL, NULL)); - - 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 */ - 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); - } - } - } - - /* close device (this not explicitly needed in most implementations) */ - printf("ready to close..."); - Pm_Close(midi); - printf("done closing.\nNow delete the virtual device..."); - checkerror(Pm_DeleteVirtualDevice(id)); - printf("done deleting.\n"); -} - - -void show_usage() -{ - printf("Usage: recvvirtual [-h] [-m manufacturer] [-c clientname] " - "[-p portname] [n]\n" - " -h for this message,\n" - " -m name designates a manufacturer name (macOS only),\n" - " -c name designates a client name (linux only),\n" - " -p name designates a port name (linux only),\n" - " n is number of message to wait for.\n"); - exit(0); -} - - -int main(int argc, char *argv[]) -{ - char line[STRING_MAX]; - int num = 10; - int i; - if (argc <= 1) { - show_usage(); - } - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-h") == 0) { - show_usage(); - } else if (strcmp(argv[i], "-m") == 0 && (i + 1 < argc)) { - i = i + 1; - set_sysdepinfo('m', argv[i]); - printf("Manufacturer name will be %s\n", argv[i]); - } else if (strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) { - i = i + 1; - port_name = argv[i]; - set_sysdepinfo('p', port_name); - printf("Port name will be %s\n", port_name); - } else if (strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) { - i = i + 1; - set_sysdepinfo('c', argv[i]); - printf("Client name will be %s\n", argv[i]); - } else { - num = atoi(argv[i]); - if (num <= 0) { - printf("Zero value or non-number for n\n"); - show_usage(); - } - printf("Waiting for %d messages.\n", num); - } - } - - main_test_input(num); - - printf("finished portMidi test...type ENTER to quit..."); - while (getchar() != '\n') ; - return 0; -} diff --git a/portmidi/pm_test/sendvirtual.c b/portmidi/pm_test/sendvirtual.c deleted file mode 100644 index a60a48f..0000000 --- a/portmidi/pm_test/sendvirtual.c +++ /dev/null @@ -1,194 +0,0 @@ -/* sendvirtual.c -- test for creating a virtual device and sending to it */ -/* - * Roger B. Dannenberg - * Sep 2021 - */ -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define OUTPUT_BUFFER_SIZE 0 -#define TIME_PROC ((PmTimeProcPtr) Pt_Time) -#define TIME_INFO NULL -#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ - -int latency = 0; -PmSysDepInfo *sysdepinfo = NULL; -char *port_name = "portmidi"; - -static void set_sysdepinfo(char m_or_p, const char *name) -{ - if (!sysdepinfo) { - // allocate some space we will alias with open-ended PmDriverInfo: - // there is space for 4 parameters: - static char dimem[sizeof(PmSysDepInfo) + sizeof(void *) * 8]; - sysdepinfo = (PmSysDepInfo *) dimem; - // build the driver info structure: - sysdepinfo->structVersion = PM_SYSDEPINFO_VERS; - sysdepinfo->length = 0; - } - if (sysdepinfo->length > 1) { - printf("Error: sysdepinfo was allocated to hold 2 parameters\n"); - exit(1); - } - int i = sysdepinfo->length++; - enum PmSysDepPropertyKey k = pmKeyNone; - if (m_or_p == 'm') k = pmKeyCoreMidiManufacturer; - else if (m_or_p == 'p') k = pmKeyAlsaPortName; - else if (m_or_p == 'c') k = pmKeyAlsaClientName; - sysdepinfo->properties[i].key = k; - sysdepinfo->properties[i].value = name; -} - - -static void prompt_and_exit(void) -{ - printf("type ENTER..."); - while (getchar() != '\n') ; - /* this will clean up open ports: */ - exit(-1); -} - - -static PmError checkerror(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 - */ - char errmsg[80]; - Pm_GetHostErrorText(errmsg, 80); - printf("PortMidi found host error...\n %s\n", errmsg); - prompt_and_exit(); - } else if (err < 0) { - printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err)); - prompt_and_exit(); - } - return err; -} - - -void wait_until(PmTimestamp when) -{ - PtTimestamp now = Pt_Time(); - if (when > now) { - Pt_Sleep(when - now); - } -} - - -void main_test_output(int num) -{ - PmStream *midi; - int32_t next_time; - PmEvent buffer[1]; - PmTimestamp timestamp; - int pitch = 60; - int id; - - /* It is recommended to start timer before Midi; otherwise, PortMidi may - start the timer with its (default) parameters - */ - TIME_START; - - /* create a virtual output device */ - id = checkerror(Pm_CreateVirtualOutput(port_name, NULL, sysdepinfo)); - checkerror(Pm_OpenOutput(&midi, id, sysdepinfo, OUTPUT_BUFFER_SIZE, - TIME_PROC, TIME_INFO, latency)); - - printf("Midi Output Virtual Device \"%s\" created.\n", port_name); - printf("Type ENTER to send messages: "); - while (getchar() != '\n') ; - - buffer[0].timestamp = Pt_Time(); -#define PROGRAM 0 - buffer[0].message = Pm_Message(0xC0, PROGRAM, 0); - Pm_Write(midi, buffer, 1); - next_time = Pt_Time() + 1000; /* wait 1s */ - while (num > 0) { - wait_until(next_time); - Pm_WriteShort(midi, next_time, Pm_Message(0x90, pitch, 100)); - printf("Note On pitch %d\n", pitch); - num--; - next_time += 500; - - wait_until(next_time); - Pm_WriteShort(midi, next_time, Pm_Message(0x90, pitch, 0)); - printf("Note Off pitch %d\n", pitch); - num--; - pitch = (pitch + 1) % 12 + 60; - next_time += 500; - } - - /* close device (this not explicitly needed in most implementations) */ - printf("ready to close..."); - Pm_Close(midi); - printf("done closing.\nNow delete the virtual device..."); - checkerror(Pm_DeleteVirtualDevice(id)); - printf("done deleting.\n"); -} - - -void show_usage() -{ - printf("Usage: sendvirtual [-h] [-l latency-in-ms] [-m manufacturer] " - "[-c clientname] [-p portname] [n]\n" - " -h for this message,\n" - " -l ms designates latency for precise timing (default 0),\n" - " -m name designates a manufacturer name (macOS only),\n" - " -c name designates a client name (linux only),\n" - " -p name designates a port name (linux only),\n" - " n is number of message to send.\n" - "sends change program to 1, then one note per second with 0.5s on,\n" - "0.5s off, for n/2 seconds. Latency >0 uses the device driver for \n" - "precise timing (see PortMidi documentation).\n"); - exit(0); -} - - -int main(int argc, char *argv[]) -{ - int num = 10; - int i; - if (argc <= 1) { - show_usage(); - } - 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 %d\n", latency); - } else if (strcmp(argv[i], "-m") == 0 && (i + 1 < argc)) { - i = i + 1; - set_sysdepinfo('m', argv[i]); - printf("Manufacturer name will be %s\n", argv[i]); - } else if (strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) { - i = i + 1; - port_name = argv[i]; - set_sysdepinfo('p', port_name); - printf("Port name will be %s\n", port_name); - } else if (strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) { - i = i + 1; - set_sysdepinfo('c', argv[i]); - printf("Client name will be %s\n", argv[i]); - } else { - num = atoi(argv[i]); - if (num <= 0) { - printf("Zero value or non-number for n\n"); - show_usage(); - } - printf("Sending %d messages.\n", num); - } - } - - main_test_output(num); - - printf("finished sendvirtual test...type ENTER to quit..."); - while (getchar() != '\n') ; - return 0; -} diff --git a/portmidi/pm_test/sysex.c b/portmidi/pm_test/sysex.c deleted file mode 100755 index c2c7187..0000000 --- a/portmidi/pm_test/sysex.c +++ /dev/null @@ -1,556 +0,0 @@ -/* 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 - -// enable some extra printing -#ifndef VERBOSE -#define VERBOSE 0 -#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(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - while (getchar() != '\n') ; - } - 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]; - 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 (total_bytes < 100000) { - 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) { - int c; - printf("Type return to send message, q to quit: "); - while ((c = getchar()) != '\n') { - if (c == '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 two ways: 1) Pm_WriteSysEx, 2) Pm_Write */ - if (total_bytes & 1) { - printf("Sending %d byte sysex msg via Pm_WriteSysEx.\n", len + 2); - Pm_WriteSysEx(midi_out, 0, msg); - } else { - PmEvent event = {0, 0}; - int bits = 0; - printf("Sending %d byte sysex msg via Pm_Write(s).\n", len + 2); - for (i = 0; i < len + 2; i++) { - event.message |= (msg[i] << bits); - bits += 8; - if (bits == 32) { /* full message - send it */ - Pm_Write(midi_out, &event, 1); - bits = 0; - event.message = 0; - } - } - if (bits > 0) { /* last message is partially full */ - Pm_Write(midi_out, &event, 1); - } - } - - /* receive the message and compare to msg[] */ - data = 0; - shift = 0; - i = 0; - start_time = Pt_Time(); - if (VERBOSE) { - printf("start_time %d\n", start_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 */ - } - if (VERBOSE) { - printf("read %08x ", 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 time %d byte %d: sent %x recd %x.\n", Pt_Time(), - error_position, expected, actual); - break; - } else if (i != len + 2) { - printf("Error at time %d: byte %d not received.\n", Pt_Time(), 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, %d%% done.\n", - (int) (total_bytes / seconds), - (int) (100 * total_bytes / 100000)); - } - } -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 */ - if (!fgets(line, STRING_MAX, stdin)) return; /* no more 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 */ - if (!fgets(line, STRING_MAX, stdin)) return; /* no more 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; - - /* 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) { - char cmd; - printf("Type r to receive sysex, s to send," - " l for loopback test, m to send multiple," - " n to receive multiple, q to quit: "); - cmd = getchar(); - while (getchar() != '\n') ; - switch (cmd) { - 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; -} diff --git a/portmidi/pm_test/testio.c b/portmidi/pm_test/testio.c deleted file mode 100755 index 2711286..0000000 --- a/portmidi/pm_test/testio.c +++ /dev/null @@ -1,594 +0,0 @@ -#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 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 WAIT_FOR_ENTER while (getchar() != '\n') ; - -int32_t latency = 0; -int verbose = FALSE; -PmSysDepInfo *sysdepinfo = NULL; - -/* 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(const char *prompt) -{ - int n = 0, i; - fputs(prompt, stdout); - while (n != 1) { - n = scanf("%d", &i); - WAIT_FOR_ENTER - } - return i; -} - - -static void set_sysdepinfo(char m_or_p, const char *name) -{ - if (!sysdepinfo) { - // allocate some space we will alias with open-ended PmDriverInfo: - // there is space for 4 parameters: - static char dimem[sizeof(PmSysDepInfo) + sizeof(void *) * 8]; - sysdepinfo = (PmSysDepInfo *) dimem; - // build the driver info structure: - sysdepinfo->structVersion = PM_SYSDEPINFO_VERS; - sysdepinfo->length = 0; - } - if (sysdepinfo->length > 1) { - printf("Error: sysdepinfo was allocated to hold 2 parameters\n"); - exit(1); - } - int i = sysdepinfo->length++; - enum PmSysDepPropertyKey k = pmKeyNone; - if (m_or_p == 'm') k = pmKeyCoreMidiManufacturer; - else if (m_or_p == 'p') k = pmKeyAlsaPortName; - else if (m_or_p == 'c') k = pmKeyAlsaClientName; - sysdepinfo->properties[i].key = k; - sysdepinfo->properties[i].value = name; -} - - -/* - * 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, - sysdepinfo, - 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: timestamp %ld, " - "%2lx %2lx %2lx\n", i, (long) Pt_Time(), - (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(int isochronous_test) -{ - PmStream * midi; - 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, - sysdepinfo, - 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 ENTER):"); - WAIT_FOR_ENTER - /* 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 = Pt_Time(); - /* 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); - - if (isochronous_test) { // play 4 notes per sec for 20s - int count; - PmTimestamp start; - if (latency < 100) { - printf("Warning: latency < 100, but this test sends messages" - " at times that are jittered by up to 100ms, so you" - " may hear uneven timing\n"); - } - printf("Starting in 1s..."); fflush(stdout); - Pt_Sleep(1000); - start = Pt_Time(); - for (count = 0; count < 80; count++) { - PmTimestamp next_time; - buffer[0].timestamp = start + count * 250; - buffer[0].message = Pm_Message(0x90, 69, 100); - buffer[1].timestamp = start + count * 250 + 200; - buffer[1].message = Pm_Message(0x90, 69, 0); - Pm_Write(midi, buffer, 2); - next_time = start + (count + 1) * 250; - // sleep for a random time up to 100ms to add jitter to - // the times at which we send messages. PortMidi timing - // should remove the jitter if latency > 100 - while (Pt_Time() < next_time) { - Pt_Sleep(rand() % 100); - } - } - printf("Done sending 80 notes at 4 notes per second.\n"); - } else { - PmError err = 0; - printf("ready to note-on... (type ENTER):"); - WAIT_FOR_ENTER - buffer[0].timestamp = Pt_Time(); - buffer[0].message = Pm_Message(0x90, 60, 100); - if ((err = Pm_Write(midi, buffer, 1))) { - printf("Pm_Write returns error: %d (%s)\n", - err, Pm_GetErrorText(err)); - if (err == pmHostError) { - char errmsg[128]; - Pm_GetHostErrorText(errmsg, 127); - printf(" Host error: %s\n", errmsg); - } - } - printf("ready to note-off... (type ENTER):"); - WAIT_FOR_ENTER - buffer[0].timestamp = Pt_Time(); - buffer[0].message = Pm_Message(0x90, 60, 0); - if ((err = Pm_Write(midi, buffer, 1))) { - printf("Pm_Write returns error: %d (%s)\n", - err, Pm_GetErrorText(err)); - if (err == pmHostError) { - char errmsg[128]; - Pm_GetHostErrorText(errmsg, 127); - printf(" Host error: %s\n", errmsg); - } - } - - /* output short note on/off w/latency offset; hold until user prompts */ - printf("ready to note-on (short form)... (type ENTER):"); - WAIT_FOR_ENTER - Pm_WriteShort(midi, Pt_Time(), - Pm_Message(0x90, 60, 100)); - printf("ready to note-off (short form)... (type ENTER):"); - WAIT_FOR_ENTER - Pm_WriteShort(midi, Pt_Time(), - Pm_Message(0x90, 60, 0)); - - /* output several note on/offs to test timing. - Should be 1s between notes */ - if (latency == 0) { - printf("chord should not arpeggiate, latency == 0\n"); - } else { - printf("chord should arpeggiate (latency = %ld > 0\n", - (long) latency); - } - printf("ready to chord-on/chord-off... (type ENTER):"); - WAIT_FOR_ENTER - timestamp = Pt_Time(); - printf("starting timestamp %ld\n", (long) timestamp); - 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 (Pt_Time() < off_time) - /* There was a report that Pm_Write with zero length sent last - * message again, so call Pm_Write here to see if note repeats - */ - Pm_Write(midi, buffer, 0); - Pt_Sleep(20); /* 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 ENTER):"); - WAIT_FOR_ENTER - - 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 = 11; - - 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, - sysdepinfo, - 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, - sysdepinfo, - 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: timestamp %ld, " - "%2lx %2lx %2lx\n", i, (long) Pt_Time(), - (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); - } - } - } - /* allow time for last message to go out */ - Pt_Sleep(100 + latency); - - /* 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; - 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, - sysdepinfo, - 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 ENTER):"); - WAIT_FOR_ENTER - - /* 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 = Pt_Time(); - 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 = Pt_Time(); - 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) - Pt_Sleep(10); - /* 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 ENTER):"); - WAIT_FOR_ENTER - - Pm_Close(midi); - Pm_Terminate(); - printf("done closing and terminating...\n"); -} - - -void show_usage() -{ - printf("Usage: test [-h] [-l latency-in-ms] [-c clientname] " - "[-p portname] [-v]\n" - " -h for this help message (only)\n" - " -l for latency\n" - " -c name designates a client name (linux only),\n" - " -p name designates a port name (linux only),\n" - " -v for verbose (enables more output)\n"); -} - -int main(int argc, char *argv[]) -{ - int default_in; - int default_out; - int i = 0, n = 0; - int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0; - int isochronous_test = 0; - int stream_test = 0; - int latency_valid = FALSE; - - show_usage(); - 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) { - exit(0); - } else if (strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) { - i = i + 1; - const char *port_name = argv[i]; - set_sysdepinfo('p', port_name); - printf("Port name will be %s\n", port_name); - } else if (strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) { - i = i + 1; - set_sysdepinfo('c', argv[i]); - printf("Client name will be %s\n", argv[i]); - } 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 if (strcmp(argv[i], "-v") == 0) { - printf("Verbose is now TRUE\n"); - verbose = TRUE; /* not currently used for anything */ - } else { - show_usage(); - exit(0); - } - } - - 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("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 (for WinMM)\n" - " 7. isochronous out\n"); - while (n != 1) { - n = scanf("%d", &i); - WAIT_FOR_ENTER - 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; - case 7: - test_output = 1; - isochronous_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(isochronous_test); - } else if (test_both) { - main_test_both(); - } - - printf("finished portMidi test...type ENTER to quit..."); - WAIT_FOR_ENTER - return 0; -} diff --git a/portmidi/pm_test/txdata.syx b/portmidi/pm_test/txdata.syx deleted file mode 100755 index 1e06e5a..0000000 --- a/portmidi/pm_test/txdata.syx +++ /dev/null @@ -1,257 +0,0 @@ -20 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 \ No newline at end of file diff --git a/portmidi/pm_test/virttest.c b/portmidi/pm_test/virttest.c deleted file mode 100644 index 1aeb09b..0000000 --- a/portmidi/pm_test/virttest.c +++ /dev/null @@ -1,339 +0,0 @@ -/* virttest.c -- test for creating/deleting virtual ports */ -/* - * Roger B. Dannenberg - * Oct 2021 - -This test is performed by running 2 instances of the program. The -first instance makes input and output ports named portmidi and waits -for a message. The second tries to do the same, but will fail because -portmidi already exists. It then opens portmidi (both input and -output). In greater detail: - -FIRST INSTANCE SECOND INSTANCE --------------- --------------- - -initialize PortMidi initialize PortMidi -create portmidi in -create portmidi out -wait for input - create portmidi in -> fails - open portmidi in/out - send to portmidi -recv from portmidi -send to portmidi -wait 1s recv from portmidi - close portmidi in and out - terminate PortMidi -list all devices: - - check for correct number - - check for good description of portmidi in port (open) - - check for good description of portmidi out port (open) -close portmidi in -list all devices: - - check for correct number - - check for good description of portmidi in port (closed) - - check for good description of portmidi out port (open) -close portmidi out -list all devices: - - check for correct number - - check for good description of portmidi in port (closed) - - check for good description of portmidi out port (closed) -delete portmidi in - - check for correct number - - check for NULL description of portmidi in port - - check for good description of portmidi out port (closed) -delete portmidi out - - check for correct number - - check for NULL description of portmidi in port - - check for NULL description of portmidi out port -terminate portmidi -REPEAT 3 TIMES wait 2 seconds to give head start to other instance - REPEAT 3 TIMES - */ - -#include "portmidi.h" -#include "porttime.h" -#include "stdlib.h" -#include "stdio.h" -#include "string.h" -#include "assert.h" - -#define OUTPUT_BUFFER_SIZE 0 -#define INPUT_BUFFER_SIZE 10 -#define DEVICE_INFO NULL -#define DRIVER_INFO NULL -#define TIME_PROC ((PmTimeProcPtr) Pt_Time) -#define TIME_INFO NULL -#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */ - - -static void prompt_and_exit(void) -{ - printf("type ENTER..."); - while (getchar() != '\n') ; - /* this will clean up open ports: */ - exit(-1); -} - - -static PmError printerror(PmError err, const char *msg) -{ - if (err == pmHostError) { - /* it seems pointless to allocate memory and copy the string, - * so I will do the work of Pm_GetHostErrorText directly - */ - char errmsg[80]; - Pm_GetHostErrorText(errmsg, 80); - printf("%s\n %s\n", msg, errmsg); - } else if (err < 0) { - printf("%s\n %s\n", msg, Pm_GetErrorText(err)); - } - return err; -} - - -static PmError checkerror(PmError err) -{ - if (err < 0) { - printerror(err, "PortMidi call failed..."); - prompt_and_exit(); - } - return err; -} - - -void wait_until(PmTimestamp when) -{ - PtTimestamp now = Pt_Time(); - if (when > now) { - Pt_Sleep(when - now); - } -} - - -void show_usage() -{ - printf("Usage: virttest\n" - " run two instances to test virtual port create/delete\n"); -} - - -void check_info(int id, char stat, int input, int virtual) -{ - const PmDeviceInfo *info = Pm_GetDeviceInfo(id); - if (stat == 'd') { - if (info) { - printf("Expected device %d to be deleted.\n", id); - prompt_and_exit(); - } - return; - } - if (!info) { - printf("Expected device %d to not be deleted.\n", id); - prompt_and_exit(); - } - if (strcmp("portmidi", info->name) != 0) { - printf("Device %d name is %s, not \"portmidi\".\n", id, info->name); - prompt_and_exit(); - } - if (info->input != input || (!info->output) != input) { - printf("Device %d input/output fields are wrong.\n", id); - prompt_and_exit(); - } - if ((!info->opened && stat == 'o') || (info->opened && stat == 'c')) { - printf("Device %d opened==%d, status should be %c.\n", id, - info->opened, stat); - prompt_and_exit(); - } - if (info->is_virtual != virtual) { - printf("Expected device %d to be virtual.\n", id); - prompt_and_exit(); - } -} - - -/* stat is 'o' for open, 'c' for closed, 'd' for deleted device */ -void check_ports(int cnt, int in_id, char in_stat, - int out_id, char out_stat, int virtual) -{ - if (cnt != Pm_CountDevices()) { - printf("Device count changed from %d to %d.\n", cnt, Pm_CountDevices()); - prompt_and_exit(); - } - check_info(in_id, in_stat, TRUE, virtual); - check_info(out_id, out_stat, FALSE, virtual); -} - - -void devices_list() -{ - int i; - for (i = 0; i < Pm_CountDevices(); i++) { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - if (info) { - printf("%d: %s %s %s %s\n", i, info->name, - (info->input ? "input" : "output"), - (info->is_virtual ? "virtual" : "real_device"), - (info->opened ? "opened" : "closed")); - } - } -} - - -void test2() -{ - PmStream *out = NULL; - PmStream *in = NULL; - int out_id; - int in_id; - PmEvent buffer[1]; - PmTimestamp timestamp; - int pitch = 60; - int device_count = 0; - int i; - - printf("This must be virttest instance #2\n"); - - /* find and open portmidi in and out */ - device_count = Pm_CountDevices(); - for (i = 0; i < device_count; i++) { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - if (info && strcmp(info->name, "portmidi") == 0) { - if (info->input) { - checkerror(Pm_OpenInput(&in, i, DRIVER_INFO, - INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO)); - in_id = i; - } else { - checkerror(Pm_OpenOutput(&out, i, DRIVER_INFO, - OUTPUT_BUFFER_SIZE, NULL, NULL, 0)); - out_id = i; - } - } - } - if (!in) { - printf("Did not open portmidi as input (virtual output).\n"); - prompt_and_exit(); - } - if (!out) { - printf("Did not open portmidi as output (virtual input).\n"); - prompt_and_exit(); - } - printf("Input device %d and output device %d are open.\n", in_id, out_id); - - /* send a message */ - buffer[0].timestamp = 0; - buffer[0].message = Pm_Message(0x90, pitch, 100); - checkerror(Pm_Write(out, buffer, 1)); - - /* wait for reply */ - printf("Sent message, waiting for reply...\n"); - while (Pm_Read(in, buffer, 1) < 1) Pt_Sleep(10); - - printf("********** GOT THE MESSAGE, SHUTTING DOWN ************\n"); - - /* close in */ - checkerror(Pm_Close(in)); - check_ports(device_count, in_id, 'c', out_id, 'o', FALSE); - printf("Closed input %d\n", in_id); - - /* close out */ - checkerror(Pm_Close(out)); - check_ports(device_count, in_id, 'c', out_id, 'c', FALSE); - printf("Closed output %d\n", out_id); - - Pt_Sleep(1000); - /* wrap it up */ - Pm_Terminate(); - printf("Got reply and terminated...\n"); - Pt_Sleep(2000); /* 2 seconds because other is waiting 1s. */ - /* 1 more second to make sure other shuts down before test repeats. */ -} - -extern int pm_check_errors; - -void test() -{ - PmStream *out; - PmStream *in; - int out_id; - int in_id; - PmEvent buffer[1]; - PmTimestamp timestamp; - int device_count = 0; - - TIME_START; - - printf("******** INITIALIZING PORTMIDI ***********\n"); - timestamp = Pt_Time(); - Pm_Initialize(); - printf("Pm_Initialize took %dms\n", Pt_Time() - timestamp); - devices_list(); - - pm_check_errors = FALSE; /* otherwise, PM_CHECK_ERRORS, if defined, */ - /* can cause this program to report an error and exit on pmNameConflict. */ - in_id = Pm_CreateVirtualInput("portmidi", NULL, DEVICE_INFO); - pm_check_errors = TRUE; /* there should be no other errors */ - if (in_id < 0) { - printerror(in_id, "Pm_CreateVirtualInput failed..."); - test2(); - return; - } - printf("Created portmidi virtual input; this is virttest instance #1\n"); - out_id = checkerror(Pm_CreateVirtualOutput("portmidi", NULL, DRIVER_INFO)); - device_count = Pm_CountDevices(); - - checkerror(Pm_OpenInput(&in, in_id, NULL, 0, NULL, NULL)); - checkerror(Pm_OpenOutput(&out, out_id, DRIVER_INFO, OUTPUT_BUFFER_SIZE, - TIME_PROC, TIME_INFO, 0)); - printf("Created/Opened input %d and output %d\n", in_id, out_id); - Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX); - /* empty the buffer after setting filter, just in case anything - got through */ - while (Pm_Read(in, buffer, 1)) ; - - /* wait for input */ - printf("Waiting for input...\n"); - while (Pm_Read(in, buffer, 1) < 1) Pt_Sleep(10); - - /* send two replies (only one would be fine) */ - checkerror(Pm_Write(out, buffer, 1)); - printf("Received input, writing output...\n"); - - /* wait 1s so receiver can get the message before we shut down */ - Pt_Sleep(1000); - printf("****** Closing everything and shutting down...\n"); - - /* expect 2 open ports */ - check_ports(device_count, in_id, 'o', out_id, 'o', TRUE); - /* close in */ - checkerror(Pm_Close(in)); - check_ports(device_count, in_id, 'c', out_id, 'o', TRUE); - - /* close out */ - checkerror(Pm_Close(out)); - check_ports(device_count, in_id, 'c', out_id, 'c', TRUE); - - /* delete in */ - checkerror(Pm_DeleteVirtualDevice(in_id)); - check_ports(device_count, in_id, 'd', out_id, 'c', TRUE); - - /* delete out */ - checkerror(Pm_DeleteVirtualDevice(out_id)); - check_ports(device_count, in_id, 'd', out_id, 'd', TRUE); - - /* we are done */ - Pm_Terminate(); -} - - -int main(int argc, char *argv[]) -{ - int i; - show_usage(); - for (i = 0; i < 3; i++) { - test(); - } - printf("finished virttest (SUCCESS). Type ENTER to quit..."); - while (getchar() != '\n') ; - return 0; -} -- cgit v1.2.3