summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/portmidi/pm_test
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portmidi/pm_test')
-rw-r--r--3rdparty/portmidi/pm_test/CMakeLists.txt52
-rw-r--r--3rdparty/portmidi/pm_test/README.txt376
-rw-r--r--3rdparty/portmidi/pm_test/fast.c290
-rw-r--r--3rdparty/portmidi/pm_test/fastrcv.c255
-rw-r--r--3rdparty/portmidi/pm_test/latency.c25
-rw-r--r--3rdparty/portmidi/pm_test/latency.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/midiclock.c23
-rw-r--r--3rdparty/portmidi/pm_test/midiclock.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/midithread.c60
-rw-r--r--3rdparty/portmidi/pm_test/midithread.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/midithru.c211
-rw-r--r--3rdparty/portmidi/pm_test/midithru.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/mm.c31
-rw-r--r--3rdparty/portmidi/pm_test/mm.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/multivirtual.c224
-rw-r--r--3rdparty/portmidi/pm_test/pmlist.c63
-rw-r--r--3rdparty/portmidi/pm_test/qtest.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/recvvirtual.c125
-rw-r--r--3rdparty/portmidi/pm_test/sendvirtual.c148
-rw-r--r--3rdparty/portmidi/pm_test/sysex.c84
-rw-r--r--3rdparty/portmidi/pm_test/sysex.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/test.vcproj148
-rw-r--r--3rdparty/portmidi/pm_test/testio.c (renamed from 3rdparty/portmidi/pm_test/test.c)294
-rw-r--r--3rdparty/portmidi/pm_test/virttest.c339
24 files changed, 2303 insertions, 1481 deletions
diff --git a/3rdparty/portmidi/pm_test/CMakeLists.txt b/3rdparty/portmidi/pm_test/CMakeLists.txt
index b89074b0bd5..ae0fe48b53d 100644
--- a/3rdparty/portmidi/pm_test/CMakeLists.txt
+++ b/3rdparty/portmidi/pm_test/CMakeLists.txt
@@ -1,4 +1,4 @@
-# pm_test
+# 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:
@@ -6,21 +6,41 @@ if(APPLE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
endif(APPLE)
-if(WIN32)
-include(../pm_win/static.cmake)
-endif(WIN32)
+# 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(make_a_test name)
+macro(add_test name)
add_executable(${name} ${name}.c)
- target_link_libraries(${name} portmidi-static ${PM_NEEDED_LIBS})
- add_dependencies(${name} portmidi-static)
-endmacro(make_a_test)
+ target_link_libraries(${name} PRIVATE portmidi)
+ set_property(TARGET ${name} PROPERTY MSVC_RUNTIME_LIBRARY
+ "MultiThreaded$<$<CONFIG:Debug>:Debug>${MSVCRT_DLL}")
+endmacro(add_test)
-make_a_test(test)
-make_a_test(midithread)
-make_a_test(midithru)
-make_a_test(sysex)
-make_a_test(latency)
-make_a_test(mm)
-make_a_test(midiclock)
-make_a_test(qtest)
+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/3rdparty/portmidi/pm_test/README.txt b/3rdparty/portmidi/pm_test/README.txt
new file mode 100644
index 00000000000..b5a83d693b8
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/README.txt
@@ -0,0 +1,376 @@
+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<ENTER>
+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 [in one shell, macOS and Linux only]
+ ./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 [in one shell, macOS and Linux only]
+ ./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. pmdefaults (if built, requires Java and some CMake options)
+ [must be run from pm_java/pmdefaults]
+ ./testio
+[In pmdefaults:
+ Select an input device. Input should flash the green
+ test light.
+ Select an output device. Test button should play a note.
+ Save the selections.
+ Quit the program.]
+[In testio:]
+ Latency in ms: >>0
+ enter your choice... >>5 [test both]
+ [In the device list, default devices are marked. They
+ should match the devices selected with pmdefaults.]
+ ^C to quit.
+33. pmlist
+ ./pmlist [check the output]
+ [plug in or remove a device]
+ >> [type RETURN]
+ [check for changes in device list]
+ >>q
+
+
+
+
diff --git a/3rdparty/portmidi/pm_test/fast.c b/3rdparty/portmidi/pm_test/fast.c
new file mode 100644
index 00000000000..102697e456e
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/fast.c
@@ -0,0 +1,290 @@
+/* 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 <unistd.h>
+#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/3rdparty/portmidi/pm_test/fastrcv.c b/3rdparty/portmidi/pm_test/fastrcv.c
new file mode 100644
index 00000000000..daee40c5fa0
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/fastrcv.c
@@ -0,0 +1,255 @@
+/* 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 <unistd.h>
+#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, n = 0;
+ int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 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/3rdparty/portmidi/pm_test/latency.c b/3rdparty/portmidi/pm_test/latency.c
index bfcdc0ca0a3..fe355511c1e 100644
--- a/3rdparty/portmidi/pm_test/latency.c
+++ b/3rdparty/portmidi/pm_test/latency.c
@@ -87,7 +87,7 @@ CHANGE LOG
#define min(a, b) ((a) <= (b) ? (a) : (b))
#endif
-int get_number(char *prompt);
+int get_number(const char *prompt);
PtTimestamp previous_callback_time = 0;
@@ -116,7 +116,7 @@ void pt_callback(PtTimestamp timestamp, void *userData)
/* send a note on/off if user requested it */
if (test_out && (iteration % output_period == 0)) {
PmEvent buffer[1];
- buffer[0].timestamp = Pt_Time(NULL);
+ buffer[0].timestamp = Pt_Time();
if (note_on) {
/* note off */
buffer[0].message = Pm_Message(0x90, 60, 0);
@@ -157,7 +157,6 @@ void pt_callback(PtTimestamp timestamp, void *userData)
int main()
{
- char line[STRING_MAX];
int i;
int len;
int choice;
@@ -231,17 +230,17 @@ int main()
}
}
- printf("%s%s", "Latency measurements will start in 5 seconds. ",
- "Type return to stop: ");
+ printf("Latency measurements will start in 5 seconds. "
+ "Type return to stop: ");
Pt_Start(period, &pt_callback, 0);
- fgets(line, STRING_MAX, stdin);
+ 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(NULL);
+ buffer[0].timestamp = Pt_Time();
buffer[0].message = Pm_Message(0x90, 60, 0);
Pm_Write(out, buffer, 1);
}
@@ -260,7 +259,7 @@ int main()
printf("\nNote that due to rounding, actual latency can be 1ms higher\n");
printf("than the numbers reported here.\n");
printf("Type return to exit...");
- fgets(line, STRING_MAX, stdin);
+ while (getchar() != '\n') ;
if(choice == 2)
Pm_Close(in);
@@ -276,15 +275,13 @@ int main()
/* read a number from console */
-int get_number(char *prompt)
-{
- char line[STRING_MAX];
+int get_number(const char *prompt)
+{
int n = 0, i;
- printf(prompt);
+ fputs(prompt, stdout);
while (n != 1) {
n = scanf("%d", &i);
- fgets(line, STRING_MAX, stdin);
-
+ while (getchar() != '\n') ;
}
return i;
}
diff --git a/3rdparty/portmidi/pm_test/latency.vcproj b/3rdparty/portmidi/pm_test/latency.vcproj
deleted file mode 100644
index 9a79300abdc..00000000000
--- a/3rdparty/portmidi/pm_test/latency.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="latency"
- ProjectGUID="{41D78CBF-B04B-4561-BA4A-AC238C40633D}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="latency.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/latency.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\latency.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/latency.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\latency.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="latency.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/latency.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\latency.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/latency.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\latency.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\latency.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/midiclock.c b/3rdparty/portmidi/pm_test/midiclock.c
index 60fcf7a9aad..f0a68974a1c 100644
--- a/3rdparty/portmidi/pm_test/midiclock.c
+++ b/3rdparty/portmidi/pm_test/midiclock.c
@@ -24,7 +24,7 @@ typedef int boolean;
#define OUTPUT_BUFFER_SIZE 0
#define DRIVER_INFO NULL
-#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
+#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 */
@@ -163,15 +163,13 @@ void timer_poll(PtTimestamp timestamp, void *userData)
/* read a number from console */
/**/
-int get_number(char *prompt)
+int get_number(const char *prompt)
{
- char line[STRING_MAX];
int n = 0, i;
- printf(prompt);
+ fputs(prompt, stdout);
while (n != 1) {
n = scanf("%d", &i);
- fgets(line, STRING_MAX, stdin);
-
+ while (getchar() != '\n') ;
}
return i;
}
@@ -236,7 +234,6 @@ private void doascii(char c)
*/
int main(int argc, char **argv)
{
- char s[STRING_MAX]; /* console input */
int outp;
PmError err;
int i;
@@ -256,22 +253,20 @@ int main(int argc, char **argv)
err = Pm_OpenOutput(&midi, outp, DRIVER_INFO, OUTPUT_BUFFER_SIZE,
TIME_PROC, TIME_INFO, LATENCY);
if (err) {
- printf(Pm_GetErrorText(err));
+ puts(Pm_GetErrorText(err));
goto error_exit_no_device;
}
active = true;
- printf("Type RETURN to start MIDI CLOCK:\n");
- if (!fgets(s, STRING_MAX, stdin)) goto error_exit;
+ printf("Type ENTER to start MIDI CLOCK:\n");
+ while (getchar() != '\n') ;
send_start_stop = true; /* send START and then CLOCKs */
while (!done) {
- if (fgets(s, STRING_MAX, stdin)) {
- doascii(s[0]);
- }
+ doascii(getchar());
+ while (getchar() != '\n') ;
}
- error_exit:
active = false;
Pt_Sleep(2); /* this is to allow callback to complete -- it's
real time, so it's either ok and it runs on
diff --git a/3rdparty/portmidi/pm_test/midiclock.vcproj b/3rdparty/portmidi/pm_test/midiclock.vcproj
deleted file mode 100644
index 2c9cf02e9c5..00000000000
--- a/3rdparty/portmidi/pm_test/midiclock.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="midiclock"
- ProjectGUID="{9B448D22-EC7E-4BD8-A552-B268D843CC3C}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="midiclock.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/midiclock.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\midiclock.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/midiclock.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\midiclock.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="midiclock.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/midiclock.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\midiclock.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/midiclock.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\midiclock.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\midiclock.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/midithread.c b/3rdparty/portmidi/pm_test/midithread.c
index fab9794f2da..ea0613bc5eb 100644
--- a/3rdparty/portmidi/pm_test/midithread.c
+++ b/3rdparty/portmidi/pm_test/midithread.c
@@ -164,22 +164,36 @@ void process_midi(PtTimestamp timestamp, void *userData)
void exit_with_message(char *msg)
{
- char line[STRING_MAX];
printf("%s\n", msg);
- fgets(line, STRING_MAX, stdin);
+ while (getchar() != '\n') ;
exit(1);
}
-int main()
+int main(int argc, char *argv[])
{
- int id;
int32_t n;
const PmDeviceInfo *info;
char line[STRING_MAX];
int spin;
int done = FALSE;
-
- /* determine what type of test to run */
+ 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
@@ -221,32 +235,32 @@ int main()
Pm_Initialize();
- id = Pm_GetDefaultOutputDeviceID();
- info = Pm_GetDeviceInfo(id);
+ output = (output < 0 ? Pm_GetDefaultOutputDeviceID() : output);
+ info = Pm_GetDeviceInfo(output);
if (info == NULL) {
- printf("Could not open default output device (%d).", id);
+ 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,
- id,
+ Pm_OpenOutput(&midi_out,
+ output,
DRIVER_INFO,
OUTPUT_BUFFER_SIZE,
TIME_PROC,
TIME_INFO,
LATENCY);
- id = Pm_GetDefaultInputDeviceID();
- info = Pm_GetDeviceInfo(id);
+ input = (input < 0 ? Pm_GetDefaultInputDeviceID() : input);
+ info = Pm_GetDeviceInfo(input);
if (info == NULL) {
- printf("Could not open default input device (%d).", id);
+ 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,
- id,
+ input,
DRIVER_INFO,
INPUT_BUFFER_SIZE,
TIME_PROC,
@@ -257,18 +271,17 @@ int main()
this simple assignment is safe */
printf("Enter midi input; it will be transformed as specified by...\n");
- printf("%s\n%s\n%s\n",
- "Type 'q' to quit, 'm' to monitor next pitch, t to toggle thru or",
- "type a number to specify transposition.",
- "Must terminate with [ENTER]");
+ 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;
- fgets(line, STRING_MAX, stdin);
+ if (!fgets(line, STRING_MAX, stdin)) break; /* no stdin? */
/* remove the newline: */
- len = strlen(line);
+ len = (int) strlen(line);
if (len > 0) line[len - 1] = 0; /* overwrite the newline char */
if (strcmp(line, "q") == 0) {
msg = QUIT_MSG;
@@ -323,7 +336,8 @@ int main()
Pm_Close(midi_in);
Pm_Close(midi_out);
- printf("finished portMidi multithread test...enter any character to quit [RETURN]...");
- fgets(line, STRING_MAX, stdin);
+ fputs("finished portMidi multithread test.\n"
+ "type ENTER to quit:", stdout);
+ while (getchar() != '\n') ;
return 0;
}
diff --git a/3rdparty/portmidi/pm_test/midithread.vcproj b/3rdparty/portmidi/pm_test/midithread.vcproj
deleted file mode 100644
index 83c82a7bec0..00000000000
--- a/3rdparty/portmidi/pm_test/midithread.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="midithread"
- ProjectGUID="{EED7440D-04E3-4948-92DB-C85B4ADB1D82}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="midithread.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/midithread.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\midithread.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/midithread.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\midithread.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="midithread.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/midithread.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\midithread.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/midithread.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\midithread.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\midithread.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/midithru.c b/3rdparty/portmidi/pm_test/midithru.c
index 8ad723138e4..a9df5ccf5e6 100644
--- a/3rdparty/portmidi/pm_test/midithru.c
+++ b/3rdparty/portmidi/pm_test/midithru.c
@@ -1,18 +1,21 @@
/* midithru.c -- example program implementing background thru processing */
-/* suppose you want low-latency midi-thru processing, but your application
- wants to take advantage of the input buffer and timestamped data so that
- it does not have to operate with very low latency.
-
- This program illustrates how to use a timer callback from PortTime to
- implement a low-latency process that handles midi thru, including correctly
- merging midi data from the application with midi data from the input port.
-
- The main application, which runs in the main program thread, will use an
- interface similar to that of PortMidi, but since PortMidi does not allow
- concurrent threads to share access to a stream, the application will
- call private methods that transfer MIDI messages to and from the timer
- thread. All PortMidi API calls are made from the timer thread.
+/* 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
@@ -78,11 +81,14 @@ global variable current_timestamp.
#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 */
+/* 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 */
-int process_midi_exit_flag;
+/* 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;
@@ -92,12 +98,43 @@ PmStream *midi_out;
#define OUT_QUEUE_SIZE 1024
PmQueue *in_queue;
PmQueue *out_queue;
-PmTimestamp current_timestamp = 0;
+/* 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)
{
@@ -117,8 +154,6 @@ void process_midi(PtTimestamp timestamp, void *userData)
PmEvent buffer; /* just one message at a time */
current_timestamp++; /* update every millisecond */
- /* if (current_timestamp % 1000 == 0)
- printf("time %d\n", current_timestamp); */
/* do nothing until initialization completes */
if (!active) {
@@ -222,14 +257,13 @@ void process_midi(PtTimestamp timestamp, void *userData)
void exit_with_message(char *msg)
{
#define STRING_MAX 80
- char line[STRING_MAX];
printf("%s\nType ENTER...", msg);
- fgets(line, STRING_MAX, stdin);
+ while (getchar() != '\n') ;
exit(1);
}
-void initialize()
+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
@@ -246,7 +280,6 @@ void initialize()
*/
const PmDeviceInfo *info;
- int id;
/* make the message queues */
in_queue = Pm_QueueCreate(IN_QUEUE_SIZE, sizeof(PmEvent));
@@ -260,36 +293,63 @@ void initialize()
Pm_Initialize();
- id = Pm_GetDefaultOutputDeviceID();
- info = Pm_GetDeviceInfo(id);
- if (info == NULL) {
- printf("Could not open default output device (%d).", id);
- exit_with_message("");
+ if (output < 0) {
+ if (!virtual) {
+ output = Pm_GetDefaultOutputDeviceID();
+ }
}
- printf("Opening output device %s %s\n", info->interf, info->name);
-
- /* use zero latency because we want output to be immediate */
- Pm_OpenOutput(&midi_out,
- id,
- NULL /* driver info */,
- OUT_QUEUE_SIZE,
- &midithru_time_proc,
- NULL /* time info */,
- 0 /* Latency */);
-
- id = Pm_GetDefaultInputDeviceID();
- info = Pm_GetDeviceInfo(id);
- if (info == NULL) {
- printf("Could not open default input device (%d).", id);
- exit_with_message("");
+ 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));
}
- printf("Opening input device %s %s\n", info->interf, info->name);
- Pm_OpenInput(&midi_in,
- id,
- NULL /* driver info */,
- 0 /* use default input size */,
- &midithru_time_proc,
- NULL /* time info */);
/* Note: if you set a filter here, then this will filter what goes
to the MIDI THRU port. You may not want to do this.
*/
@@ -330,15 +390,42 @@ int main(int argc, char *argv[])
{
PmTimestamp last_time = 0;
PmEvent buffer;
-
- /* determine what type of test to run */
+ 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(); /* set up and start midi processing */
+ initialize(input, output, virtual); /* set up and start midi processing */
- printf("%s\n%s\n",
- "This program will run for 60 seconds, or until you play middle C,",
- "echoing all input with a 2 second delay.");
+ 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,
@@ -350,11 +437,13 @@ int main(int argc, char *argv[])
while (Pm_Dequeue(in_queue, &buffer) == 1) {
/* printf("timestamp %d\n", buffer.timestamp); */
/* printf("message %x\n", buffer.message); */
- buffer.timestamp = buffer.timestamp + 2000; /* delay */
- Pm_Enqueue(out_queue, &buffer);
- /* play middle C to break out of loop */
+ if (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) == 60) {
+ Pm_MessageData1(buffer.message) == 59) {
goto quit_now;
}
}
diff --git a/3rdparty/portmidi/pm_test/midithru.vcproj b/3rdparty/portmidi/pm_test/midithru.vcproj
deleted file mode 100644
index cf6dfdffe6c..00000000000
--- a/3rdparty/portmidi/pm_test/midithru.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="midithru"
- ProjectGUID="{80193DD1-2C02-4A4C-BDF8-49623AD6F556}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="midithru.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/midithru.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\midithru.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/midithru.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\midithru.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="midithru.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/midithru.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\midithru.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/midithru.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\midithru.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\midithru.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/mm.c b/3rdparty/portmidi/pm_test/mm.c
index 0f2a52ee267..8fe5358b591 100644
--- a/3rdparty/portmidi/pm_test/mm.c
+++ b/3rdparty/portmidi/pm_test/mm.c
@@ -110,20 +110,18 @@ private void showhelp();
private void showbytes(PmMessage data, int len, boolean newline);
private void showstatus(boolean flag);
private void doascii(char c);
-private int get_number(char *prompt);
+private int get_number(const char *prompt);
/* read a number from console */
/**/
-int get_number(char *prompt)
+int get_number(const char *prompt)
{
- char line[STRING_MAX];
int n = 0, i;
- printf(prompt);
+ fputs(prompt, stdout);
while (n != 1) {
n = scanf("%d", &i);
- fgets(line, STRING_MAX, stdin);
-
+ while (getchar() != '\n') ;
}
return i;
}
@@ -136,7 +134,7 @@ void receive_poll(PtTimestamp timestamp, void *userData)
if (!active) return;
while ((count = Pm_Read(midi_in, &event, 1))) {
if (count == 1) output(event.message);
- else printf(Pm_GetErrorText(count));
+ else puts(Pm_GetErrorText(count));
}
}
@@ -160,7 +158,7 @@ int main(int argc, char **argv)
/* use porttime callback to empty midi queue and print */
Pt_Start(1, receive_poll, 0);
/* list device information */
- printf("MIDI input devices:\n");
+ 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);
@@ -168,7 +166,7 @@ int main(int argc, char **argv)
inp = get_number("Type input device number: ");
err = Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL);
if (err) {
- printf(Pm_GetErrorText(err));
+ puts(Pm_GetErrorText(err));
Pt_Stop();
mmexit(1);
}
@@ -177,10 +175,8 @@ int main(int argc, char **argv)
printf("Midi Monitor ready.\n");
active = true;
while (!done) {
- char s[100];
- if (fgets(s, 100, stdin)) {
- doascii(s[0]);
- }
+ doascii(getchar());
+ while (getchar() != '\n') ;
}
active = false;
Pm_Close(midi_in);
@@ -484,8 +480,8 @@ private int put_pitch(int p)
"gs", "a", "bf", "b" };
/* note octave correction below */
sprintf(result, "%s%d", ptos[p % 12], (p / 12) - 1);
- printf(result);
- return strlen(result);
+ fputs(result, stdout);
+ return (int) strlen(result);
}
@@ -534,7 +530,8 @@ private void showhelp()
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(" 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");
@@ -568,5 +565,5 @@ private void showhelp()
private void showstatus(boolean flag)
{
- printf(", now %s\n", flag ? "ON" : "OFF" );
+ printf(", now %s\n", flag ? "ON" : "OFF");
}
diff --git a/3rdparty/portmidi/pm_test/mm.vcproj b/3rdparty/portmidi/pm_test/mm.vcproj
deleted file mode 100644
index 78baa9f95ad..00000000000
--- a/3rdparty/portmidi/pm_test/mm.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="mm"
- ProjectGUID="{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="mm.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/mm.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\mm.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/mm.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\mm.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="mm.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/mm.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\mm.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/mm.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\mm.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\mm.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/multivirtual.c b/3rdparty/portmidi/pm_test/multivirtual.c
new file mode 100644
index 00000000000..059bc50e4f9
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/multivirtual.c
@@ -0,0 +1,224 @@
+/* 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];
+ PmTimestamp timestamp;
+ 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/3rdparty/portmidi/pm_test/pmlist.c b/3rdparty/portmidi/pm_test/pmlist.c
new file mode 100644
index 00000000000..5e3d1dbc359
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/pmlist.c
@@ -0,0 +1,63 @@
+/* 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<ret> 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/3rdparty/portmidi/pm_test/qtest.vcproj b/3rdparty/portmidi/pm_test/qtest.vcproj
deleted file mode 100644
index 70a8025b98d..00000000000
--- a/3rdparty/portmidi/pm_test/qtest.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="qtest"
- ProjectGUID="{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="qtest.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/qtest.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\qtest.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/qtest.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\qtest.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="qtest.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/qtest.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\qtest.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/qtest.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\qtest.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\qtest.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/recvvirtual.c b/3rdparty/portmidi/pm_test/recvvirtual.c
new file mode 100644
index 00000000000..8ac97bed54c
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/recvvirtual.c
@@ -0,0 +1,125 @@
+#include "portmidi.h"
+#include "porttime.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+#include "assert.h"
+
+#define INPUT_BUFFER_SIZE 100
+#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 */
+
+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("portmidi", NULL, DRIVER_INFO));
+ checkerror(Pm_OpenInput(&midi, id, NULL, 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] [n]\n use -h for this message,\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;
+
+ if (argc > 2) {
+ show_usage();
+ } else if (argc == 2) {
+ if (strcmp(argv[1], "-h") == 0) {
+ show_usage();
+ } else {
+ num = atoi(argv[1]);
+ if (num <= 0) {
+ show_usage();
+ }
+ }
+ }
+
+ main_test_input(num);
+
+ printf("finished portMidi test...type ENTER to quit...");
+ while (getchar() != '\n') ;
+ return 0;
+}
diff --git a/3rdparty/portmidi/pm_test/sendvirtual.c b/3rdparty/portmidi/pm_test/sendvirtual.c
new file mode 100644
index 00000000000..14c6e9ea658
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/sendvirtual.c
@@ -0,0 +1,148 @@
+/* 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 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;
+}
+
+
+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("portmidi", NULL, DEVICE_INFO));
+ checkerror(Pm_OpenOutput(&midi, id, DRIVER_INFO, OUTPUT_BUFFER_SIZE,
+ TIME_PROC, TIME_INFO, latency));
+
+ printf("Midi Output Virtual Device \"portmidi\" created.\n");
+ 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] [n]\n"
+ " -h for this message,\n"
+ " -l ms designates latency for precise timing (default 0),\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;
+ 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_output(num);
+
+ printf("finished sendvirtual test...type ENTER to quit...");
+ while (getchar() != '\n') ;
+ return 0;
+}
diff --git a/3rdparty/portmidi/pm_test/sysex.c b/3rdparty/portmidi/pm_test/sysex.c
index 7bbcf0eedfd..81964961670 100644
--- a/3rdparty/portmidi/pm_test/sysex.c
+++ b/3rdparty/portmidi/pm_test/sysex.c
@@ -21,6 +21,11 @@
#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
@@ -35,15 +40,13 @@ int latency = 0;
/* read a number from console */
/**/
-int get_number(char *prompt)
+int get_number(const char *prompt)
{
- char line[STRING_MAX];
int n = 0, i;
- printf(prompt);
+ fputs(prompt, stdout);
while (n != 1) {
n = scanf("%d", &i);
- fgets(line, STRING_MAX, stdin);
-
+ while (getchar() != '\n') ;
}
return i;
}
@@ -58,7 +61,6 @@ void loopback_test()
PmStream *midi_in;
PmStream *midi_out;
unsigned char msg[1024];
- char line[80];
int32_t len;
int i;
int data;
@@ -90,7 +92,7 @@ void loopback_test()
srand((unsigned int) Pt_Time()); /* seed for random numbers */
begin_time = Pt_Time();
- while (1) {
+ while (total_bytes < 100000) {
PmError count;
int32_t start_time;
int error_position = -1; /* 0; -1; -1 for continuous */
@@ -100,9 +102,11 @@ void loopback_test()
/* 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: ");
- fgets(line, STRING_MAX, stdin);
- if (line[0] == 'q') goto cleanup;
+ while ((c = getchar()) != '\n') {
+ if (c == 'q') goto cleanup;
+ }
}
/* compose the message */
@@ -125,17 +129,38 @@ void loopback_test()
printf("Before sending anything, a MIDI message was found in\n");
printf("the input buffer. Please try again.\n");
break;
- }
+ }
- /* send the message */
- printf("Sending %d byte sysex message.\n", len + 2);
- Pm_WriteSysEx(midi_out, 0, msg);
+ /* 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()) {
@@ -144,10 +169,10 @@ void loopback_test()
Sleep(1); /* be nice: give some CPU time to the system */
continue; /* continue polling for input */
}
-
- /* printf("read %lx ", event.message);
- fflush(stdout); */
-
+ 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;
@@ -160,18 +185,20 @@ void loopback_test()
}
}
if (error_position >= 0) {
- printf("Error at byte %d: sent %x recd %x.\n", error_position,
- expected, actual);
+ 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: byte %d not received.\n", i);
+ 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;
+ if (seconds == 0) seconds = 1;
printf("Correctly received %d byte sysex message.\n", i);
- total_bytes += i;
- printf("Cummulative bytes/sec: %d\n", total_bytes / seconds);
+ total_bytes += i;
+ printf("Cummulative bytes/sec: %d, %d%% done.\n",
+ (int) (total_bytes / seconds),
+ (int) (100 * total_bytes / 100000));
}
}
cleanup:
@@ -378,7 +405,7 @@ void receive_sysex()
printf("Midi Input opened, type file for sysex data: ");
/* open file */
- fgets(line, STRING_MAX, stdin);
+ 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");
@@ -443,7 +470,7 @@ void send_sysex()
printf("Midi Output opened, type file with sysex data: ");
/* open file */
- fgets(line, STRING_MAX, stdin);
+ 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");
@@ -487,7 +514,6 @@ void send_sysex()
int main()
{
int i;
- char line[80];
/* list device information */
for (i = 0; i < Pm_CountDevices(); i++) {
@@ -498,11 +524,13 @@ int main()
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: ");
- fgets(line, STRING_MAX, stdin);
- switch (line[0]) {
+ cmd = getchar();
+ while (getchar() != '\n') ;
+ switch (cmd) {
case 'r':
receive_sysex();
break;
diff --git a/3rdparty/portmidi/pm_test/sysex.vcproj b/3rdparty/portmidi/pm_test/sysex.vcproj
deleted file mode 100644
index dabeecb255c..00000000000
--- a/3rdparty/portmidi/pm_test/sysex.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="sysex"
- ProjectGUID="{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="sysex.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/sysex.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\sysex.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/sysex.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\sysex.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="sysex.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/sysex.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\sysex.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/sysex.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\sysex.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\sysex.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/test.vcproj b/3rdparty/portmidi/pm_test/test.vcproj
deleted file mode 100644
index 7458c31e865..00000000000
--- a/3rdparty/portmidi/pm_test/test.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="test"
- ProjectGUID="{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="test.dir\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- ExceptionHandling="0"
- InlineFunctionExpansion="0"
- Optimization="0"
- RuntimeLibrary="1"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- AssemblerListingLocation="Debug"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Debug/test.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Debug\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Debug\test.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Debug/test.pdb"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- ImportLibrary="..\pm_test\Debug\test.lib"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="test.dir\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions=" /Zm1000"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- CompileAs="1"
- ExceptionHandling="0"
- InlineFunctionExpansion="2"
- Optimization="2"
- RuntimeLibrary="0"
- WarningLevel="3"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- AssemblerListingLocation="Release"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="../pm_test/Release/test.pdb"
-/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- AdditionalIncludeDirectories="..\pm_common;..\porttime;"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
- MkTypLibCompatible="FALSE"
- TargetEnvironment="1"
- GenerateStublessProxies="TRUE"
- TypeLibraryName="$(InputName).tlb"
- OutputDirectory="$(IntDir)"
- HeaderFileName="$(InputName).h"
- DLLDataFileName=""
- InterfaceIdentifierFileName="$(InputName)_i.c"
- ProxyFileName="$(InputName)_p.c"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions=" /STACK:10000000 /machine:I386"
- AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib ..\Release\portmidi_s.lib winmm.lib "
- OutputFile="..\pm_test\Release\test.exe"
- Version="0.0"
- GenerateManifest="TRUE"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""
- ProgramDataBaseFile="../pm_test/Release/test.pdb"
- SubSystem="1"
- ImportLibrary="..\pm_test\Release\test.lib"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="..\pm_test\test.c">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/3rdparty/portmidi/pm_test/test.c b/3rdparty/portmidi/pm_test/testio.c
index 03d6331adef..c71ae087307 100644
--- a/3rdparty/portmidi/pm_test/test.c
+++ b/3rdparty/portmidi/pm_test/testio.c
@@ -12,9 +12,10 @@
#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 */
+#define WAIT_FOR_ENTER while (getchar() != '\n') ;
int32_t latency = 0;
+int verbose = FALSE;
/* crash the program to test whether midi ports are closed */
/**/
@@ -33,15 +34,13 @@ void doSomethingStupid() {
/* read a number from console */
/**/
-int get_number(char *prompt)
+int get_number(const char *prompt)
{
- char line[STRING_MAX];
int n = 0, i;
- printf(prompt);
+ fputs(prompt, stdout);
while (n != 1) {
n = scanf("%d", &i);
- fgets(line, STRING_MAX, stdin);
-
+ WAIT_FOR_ENTER
}
return i;
}
@@ -83,10 +82,10 @@ void main_test_input(unsigned int somethingStupid) {
while (i < num) {
status = Pm_Poll(midi);
if (status == TRUE) {
- length = Pm_Read(midi,buffer, 1);
+ length = Pm_Read(midi, buffer, 1);
if (length > 0) {
- printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
- i,
+ 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),
@@ -113,9 +112,9 @@ void main_test_input(unsigned int somethingStupid) {
-void main_test_output() {
+void main_test_output(int isochronous_test)
+{
PmStream * midi;
- char line[80];
int32_t off_time;
int chord[] = { 60, 67, 76, 83, 90 };
#define chord_size 5
@@ -142,65 +141,100 @@ void main_test_output() {
printf("Midi Output opened with %ld ms latency.\n", (long) latency);
/* output note on/off w/latency offset; hold until user prompts */
- printf("ready to send program 1 change... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
+ 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 = TIME_PROC(TIME_INFO);
+ 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);
- printf("ready to note-on... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
- buffer[0].timestamp = TIME_PROC(TIME_INFO);
- buffer[0].message = Pm_Message(0x90, 60, 100);
- Pm_Write(midi, buffer, 1);
- printf("ready to note-off... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
- buffer[0].timestamp = TIME_PROC(TIME_INFO);
- buffer[0].message = Pm_Message(0x90, 60, 0);
- Pm_Write(midi, buffer, 1);
-
- /* output short note on/off w/latency offset; hold until user prompts */
- printf("ready to note-on (short form)... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
- Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
- Pm_Message(0x90, 60, 100));
- printf("ready to note-off (short form)... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
- Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
- Pm_Message(0x90, 60, 0));
-
- /* output several note on/offs to test timing.
- Should be 1s between notes */
- printf("chord will arpeggiate if latency > 0\n");
- printf("ready to chord-on/chord-off... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
- timestamp = TIME_PROC(TIME_INFO);
- for (i = 0; i < chord_size; i++) {
- buffer[i].timestamp = timestamp + 1000 * i;
- buffer[i].message = Pm_Message(0x90, chord[i], 100);
- }
- Pm_Write(midi, buffer, chord_size);
-
- off_time = timestamp + 1000 + chord_size * 1000;
- while (TIME_PROC(TIME_INFO) < off_time)
- /* busy wait */;
- for (i = 0; i < chord_size; i++) {
- buffer[i].timestamp = timestamp + 1000 * i;
- buffer[i].message = Pm_Message(0x90, chord[i], 0);
+ 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 {
+ printf("ready to note-on... (type ENTER):");
+ WAIT_FOR_ENTER
+ buffer[0].timestamp = Pt_Time();
+ buffer[0].message = Pm_Message(0x90, 60, 100);
+ Pm_Write(midi, buffer, 1);
+ printf("ready to note-off... (type ENTER):");
+ WAIT_FOR_ENTER
+ buffer[0].timestamp = Pt_Time();
+ buffer[0].message = Pm_Message(0x90, 60, 0);
+ Pm_Write(midi, buffer, 1);
+
+ /* output short note on/off w/latency offset; hold until user prompts */
+ printf("ready to note-on (short form)... (type 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)
+ Pt_Sleep(10); /* 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);
}
- Pm_Write(midi, buffer, chord_size);
/* close device (this not explicitly needed in most implementations) */
- printf("ready to close and terminate... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
+ printf("ready to close and terminate... (type ENTER):");
+ WAIT_FOR_ENTER
Pm_Close(midi);
Pm_Terminate();
@@ -215,7 +249,7 @@ void main_test_both()
PmStream * midi, * midiOut;
PmEvent buffer[1];
PmError status, length;
- int num = 10;
+ int num = 11;
in = get_number("Type input number: ");
out = get_number("Type output number: ");
@@ -238,7 +272,7 @@ void main_test_both()
INPUT_BUFFER_SIZE,
TIME_PROC,
TIME_INFO);
- printf("Midi Input opened. Reading %d Midi messages...\n",num);
+ 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 */
@@ -252,8 +286,8 @@ void main_test_both()
length = Pm_Read(midi,buffer,1);
if (length > 0) {
Pm_Write(midiOut, buffer, 1);
- printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
- i,
+ 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),
@@ -264,6 +298,8 @@ void main_test_both()
}
}
}
+ /* allow time for last message to go out */
+ Pt_Sleep(100 + latency);
/* close midi devices */
Pm_Close(midi);
@@ -281,19 +317,18 @@ void main_test_both()
*/
void main_test_stream() {
PmStream * midi;
- char line[80];
PmEvent buffer[16];
/* determine which output device to use */
int i = get_number("Type output number: ");
- latency = 500; /* ignore LATENCY for this test and
+ 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 */
+ /* open output device */
Pm_OpenOutput(&midi,
i,
DRIVER_INFO,
@@ -304,66 +339,66 @@ void main_test_stream() {
printf("Midi Output opened with %ld ms latency.\n", (long) latency);
/* output note on/off w/latency offset; hold until user prompts */
- printf("ready to send output... (type RETURN):");
- fgets(line, STRING_MAX, stdin);
+ 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 = TIME_PROC(TIME_INFO);
+ 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);
+ buffer[1].timestamp = buffer[0].timestamp;
+ buffer[1].message = Pm_Message(0x90, 60, 100);
+ buffer[2].timestamp = buffer[0].timestamp + 1000;
+ buffer[2].message = Pm_Message(0x90, 62, 100);
+ buffer[3].timestamp = buffer[0].timestamp + 2000;
+ buffer[3].message = Pm_Message(0x90, 64, 100);
+ buffer[4].timestamp = buffer[0].timestamp + 3000;
+ buffer[4].message = Pm_Message(0x90, 66, 100);
+ buffer[5].timestamp = buffer[0].timestamp + 4000;
+ buffer[5].message = Pm_Message(0x90, 60, 0);
+ buffer[6].timestamp = buffer[0].timestamp + 4000;
+ buffer[6].message = Pm_Message(0x90, 62, 0);
+ buffer[7].timestamp = buffer[0].timestamp + 4000;
+ buffer[7].message = Pm_Message(0x90, 64, 0);
+ buffer[8].timestamp = buffer[0].timestamp + 4000;
+ buffer[8].message = Pm_Message(0x90, 66, 0);
Pm_Write(midi, buffer, 9);
#ifdef SEND8
- /* Now, we're ready for the real test.
- Play 4 notes at now, now+500, now+1000, and now+1500
- Then wait until now+2000.
- Play 4 more notes as before.
- We should hear 8 evenly spaced notes. */
- now = TIME_PROC(TIME_INFO);
- for (i = 0; i < 4; i++) {
- buffer[i * 2].timestamp = now + (i * 500);
- buffer[i * 2].message = Pm_Message(0x90, 60, 100);
- buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
- buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
- }
+ /* 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)
- /* busy wait */;
- /* now we are 500 ms behind schedule, but since the latency
- is 500, the delay should not be audible */
- now += 2000;
- for (i = 0; i < 4; i++) {
- buffer[i * 2].timestamp = now + (i * 500);
- buffer[i * 2].message = Pm_Message(0x90, 60, 100);
- buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
- buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
- }
+ 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 RETURN):");
- fgets(line, STRING_MAX, stdin);
-
+ printf("ready to close and terminate... (type ENTER):");
+ WAIT_FOR_ENTER
+
Pm_Close(midi);
Pm_Terminate();
printf("done closing and terminating...\n");
@@ -372,8 +407,10 @@ void main_test_stream() {
void show_usage()
{
- printf("Usage: test [-h] [-l latency-in-ms]\n");
- exit(0);
+ printf("Usage: test [-h] [-l latency-in-ms] [-v]\n"
+ " -h for this help message (only)\n"
+ " -l for latency\n"
+ " -v for verbose (enables more output)\n");
}
int main(int argc, char *argv[])
@@ -381,11 +418,12 @@ int main(int argc, char *argv[])
int default_in;
int default_out;
int i = 0, n = 0;
- char line[STRING_MAX];
int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0;
+ int 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)
@@ -393,14 +431,18 @@ int main(int argc, char *argv[])
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0) {
- show_usage();
+ exit(0);
} 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);
}
}
@@ -409,21 +451,21 @@ int main(int argc, char *argv[])
printf("Latency in ms: ");
if (scanf("%d", &lat) == 1) {
latency = (int32_t) lat; // coerce from "%d" to known size
- latency_valid = TRUE;
+ latency_valid = TRUE;
}
}
/* determine what type of test to run */
printf("begin portMidi test...\n");
- printf("%s%s%s%s%s",
- "enter your choice...\n 1: test input\n",
- " 2: test input (fail w/assert)\n",
- " 3: test input (fail w/NULL assign)\n",
- " 4: test output\n 5: test both\n",
- " 6: stream test\n");
+ 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);
- fgets(line, STRING_MAX, stdin);
+ WAIT_FOR_ENTER
switch(i) {
case 1:
test_input = 1;
@@ -442,9 +484,13 @@ int main(int argc, char *argv[])
case 5:
test_both = 1;
break;
- case 6:
- stream_test = 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;
@@ -478,12 +524,12 @@ int main(int argc, char *argv[])
} else if (test_input) {
main_test_input(somethingStupid);
} else if (test_output) {
- main_test_output();
+ main_test_output(isochronous_test);
} else if (test_both) {
main_test_both();
}
printf("finished portMidi test...type ENTER to quit...");
- fgets(line, STRING_MAX, stdin);
+ WAIT_FOR_ENTER
return 0;
}
diff --git a/3rdparty/portmidi/pm_test/virttest.c b/3rdparty/portmidi/pm_test/virttest.c
new file mode 100644
index 00000000000..1aeb09b8c54
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/virttest.c
@@ -0,0 +1,339 @@
+/* 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;
+}