mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-07-23 03:05:48 +03:00
http://portmedia.sourceforge.net/ PortMidi is a platform independent library for MIDI input/output.
1001 lines
32 KiB
Diff
1001 lines
32 KiB
Diff
--- a/pm_test/CMakeLists.txt
|
|
+++ b/pm_test/CMakeLists.txt
|
|
@@ -12,11 +12,11 @@
|
|
|
|
macro(make_a_test name)
|
|
add_executable(${name} ${name}.c)
|
|
- target_link_libraries(${name} portmidi-static ${PM_NEEDED_LIBS})
|
|
- add_dependencies(${name} portmidi-static)
|
|
+ target_link_libraries(${name} portmidi-dynamic ${PM_NEEDED_LIBS})
|
|
+ add_dependencies(${name} portmidi-dynamic)
|
|
endmacro(make_a_test)
|
|
|
|
-make_a_test(test)
|
|
+make_a_test(simple_test)
|
|
make_a_test(midithread)
|
|
make_a_test(midithru)
|
|
make_a_test(sysex)
|
|
--- /dev/null
|
|
+++ b/pm_test/simple_test.c
|
|
@@ -0,0 +1,489 @@
|
|
+#include "portmidi.h"
|
|
+#include "porttime.h"
|
|
+#include "stdlib.h"
|
|
+#include "stdio.h"
|
|
+#include "string.h"
|
|
+#include "assert.h"
|
|
+
|
|
+#define INPUT_BUFFER_SIZE 100
|
|
+#define OUTPUT_BUFFER_SIZE 0
|
|
+#define DRIVER_INFO NULL
|
|
+#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
|
|
+#define TIME_INFO NULL
|
|
+#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
|
|
+
|
|
+#define STRING_MAX 80 /* used for console input */
|
|
+
|
|
+int32_t latency = 0;
|
|
+
|
|
+/* crash the program to test whether midi ports are closed */
|
|
+/**/
|
|
+void doSomethingReallyStupid() {
|
|
+ int * tmp = NULL;
|
|
+ *tmp = 5;
|
|
+}
|
|
+
|
|
+
|
|
+/* exit the program without any explicit cleanup */
|
|
+/**/
|
|
+void doSomethingStupid() {
|
|
+ assert(0);
|
|
+}
|
|
+
|
|
+
|
|
+/* read a number from console */
|
|
+/**/
|
|
+int get_number(char *prompt)
|
|
+{
|
|
+ char line[STRING_MAX];
|
|
+ int n = 0, i;
|
|
+ printf("%s\n", prompt);
|
|
+ while (n != 1) {
|
|
+ n = scanf("%d", &i);
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+
|
|
+ }
|
|
+ return i;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * the somethingStupid parameter can be set to simulate a program crash.
|
|
+ * We want PortMidi to close Midi ports automatically in the event of a
|
|
+ * crash because Windows does not (and this may cause an OS crash)
|
|
+ */
|
|
+void main_test_input(unsigned int somethingStupid) {
|
|
+ PmStream * midi;
|
|
+ PmError status, length;
|
|
+ PmEvent buffer[1];
|
|
+ int num = 10;
|
|
+ int i = get_number("Type input number: ");
|
|
+ /* It is recommended to start timer before Midi; otherwise, PortMidi may
|
|
+ start the timer with its (default) parameters
|
|
+ */
|
|
+ TIME_START;
|
|
+
|
|
+ /* open input device */
|
|
+ Pm_OpenInput(&midi,
|
|
+ i,
|
|
+ DRIVER_INFO,
|
|
+ INPUT_BUFFER_SIZE,
|
|
+ TIME_PROC,
|
|
+ TIME_INFO);
|
|
+
|
|
+ printf("Midi Input opened. Reading %d Midi messages...\n", num);
|
|
+ Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
|
|
+ /* empty the buffer after setting filter, just in case anything
|
|
+ got through */
|
|
+ while (Pm_Poll(midi)) {
|
|
+ Pm_Read(midi, buffer, 1);
|
|
+ }
|
|
+ /* now start paying attention to messages */
|
|
+ i = 0; /* count messages as they arrive */
|
|
+ while (i < num) {
|
|
+ status = Pm_Poll(midi);
|
|
+ if (status == TRUE) {
|
|
+ length = Pm_Read(midi,buffer, 1);
|
|
+ if (length > 0) {
|
|
+ printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
|
|
+ i,
|
|
+ (long) buffer[0].timestamp,
|
|
+ (long) Pm_MessageStatus(buffer[0].message),
|
|
+ (long) Pm_MessageData1(buffer[0].message),
|
|
+ (long) Pm_MessageData2(buffer[0].message));
|
|
+ i++;
|
|
+ } else {
|
|
+ assert(0);
|
|
+ }
|
|
+ }
|
|
+ /* simulate crash if somethingStupid is 1 or 2 */
|
|
+ if ((i > (num/2)) && (somethingStupid == 1)) {
|
|
+ doSomethingStupid();
|
|
+ } else if ((i > (num/2)) && (somethingStupid == 2)) {
|
|
+ doSomethingReallyStupid();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* close device (this not explicitly needed in most implementations) */
|
|
+ printf("ready to close...");
|
|
+
|
|
+ Pm_Close(midi);
|
|
+ printf("done closing...");
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+void main_test_output() {
|
|
+ PmStream * midi;
|
|
+ char line[80];
|
|
+ int32_t off_time;
|
|
+ int chord[] = { 60, 67, 76, 83, 90 };
|
|
+ #define chord_size 5
|
|
+ PmEvent buffer[chord_size];
|
|
+ PmTimestamp timestamp;
|
|
+
|
|
+ /* determine which output device to use */
|
|
+ int i = get_number("Type output number: ");
|
|
+
|
|
+ /* It is recommended to start timer before PortMidi */
|
|
+ TIME_START;
|
|
+
|
|
+ /* open output device -- since PortMidi avoids opening a timer
|
|
+ when latency is zero, we will pass in a NULL timer pointer
|
|
+ for that case. If PortMidi tries to access the time_proc,
|
|
+ we will crash, so this test will tell us something. */
|
|
+ Pm_OpenOutput(&midi,
|
|
+ i,
|
|
+ DRIVER_INFO,
|
|
+ OUTPUT_BUFFER_SIZE,
|
|
+ (latency == 0 ? NULL : TIME_PROC),
|
|
+ (latency == 0 ? NULL : TIME_INFO),
|
|
+ latency);
|
|
+ printf("Midi Output opened with %ld ms latency.\n", (long) latency);
|
|
+
|
|
+ /* output note on/off w/latency offset; hold until user prompts */
|
|
+ printf("ready to send program 1 change... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ /* if we were writing midi for immediate output, we could always use
|
|
+ timestamps of zero, but since we may be writing with latency, we
|
|
+ will explicitly set the timestamp to "now" by getting the time.
|
|
+ The source of timestamps should always correspond to the TIME_PROC
|
|
+ and TIME_INFO parameters used in Pm_OpenOutput(). */
|
|
+ buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
+ /* Send a program change to increase the chances we will hear notes */
|
|
+ /* Program 0 is usually a piano, but you can change it here: */
|
|
+#define PROGRAM 0
|
|
+ buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
|
|
+ Pm_Write(midi, buffer, 1);
|
|
+
|
|
+ printf("ready to note-on... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
+ buffer[0].message = Pm_Message(0x90, 60, 100);
|
|
+ Pm_Write(midi, buffer, 1);
|
|
+ printf("ready to note-off... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
+ buffer[0].message = Pm_Message(0x90, 60, 0);
|
|
+ Pm_Write(midi, buffer, 1);
|
|
+
|
|
+ /* output short note on/off w/latency offset; hold until user prompts */
|
|
+ printf("ready to note-on (short form)... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
|
|
+ Pm_Message(0x90, 60, 100));
|
|
+ printf("ready to note-off (short form)... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
|
|
+ Pm_Message(0x90, 60, 0));
|
|
+
|
|
+ /* output several note on/offs to test timing.
|
|
+ Should be 1s between notes */
|
|
+ printf("chord will arpeggiate if latency > 0\n");
|
|
+ printf("ready to chord-on/chord-off... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ timestamp = TIME_PROC(TIME_INFO);
|
|
+ for (i = 0; i < chord_size; i++) {
|
|
+ buffer[i].timestamp = timestamp + 1000 * i;
|
|
+ buffer[i].message = Pm_Message(0x90, chord[i], 100);
|
|
+ }
|
|
+ Pm_Write(midi, buffer, chord_size);
|
|
+
|
|
+ off_time = timestamp + 1000 + chord_size * 1000;
|
|
+ while (TIME_PROC(TIME_INFO) < off_time)
|
|
+ /* busy wait */;
|
|
+ for (i = 0; i < chord_size; i++) {
|
|
+ buffer[i].timestamp = timestamp + 1000 * i;
|
|
+ buffer[i].message = Pm_Message(0x90, chord[i], 0);
|
|
+ }
|
|
+ Pm_Write(midi, buffer, chord_size);
|
|
+
|
|
+ /* close device (this not explicitly needed in most implementations) */
|
|
+ printf("ready to close and terminate... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+
|
|
+ Pm_Close(midi);
|
|
+ Pm_Terminate();
|
|
+ printf("done closing and terminating...\n");
|
|
+}
|
|
+
|
|
+
|
|
+void main_test_both()
|
|
+{
|
|
+ int i = 0;
|
|
+ int in, out;
|
|
+ PmStream * midi, * midiOut;
|
|
+ PmEvent buffer[1];
|
|
+ PmError status, length;
|
|
+ int num = 10;
|
|
+
|
|
+ in = get_number("Type input number: ");
|
|
+ out = get_number("Type output number: ");
|
|
+
|
|
+ /* In is recommended to start timer before PortMidi */
|
|
+ TIME_START;
|
|
+
|
|
+ Pm_OpenOutput(&midiOut,
|
|
+ out,
|
|
+ DRIVER_INFO,
|
|
+ OUTPUT_BUFFER_SIZE,
|
|
+ TIME_PROC,
|
|
+ TIME_INFO,
|
|
+ latency);
|
|
+ printf("Midi Output opened with %ld ms latency.\n", (long) latency);
|
|
+ /* open input device */
|
|
+ Pm_OpenInput(&midi,
|
|
+ in,
|
|
+ DRIVER_INFO,
|
|
+ INPUT_BUFFER_SIZE,
|
|
+ TIME_PROC,
|
|
+ TIME_INFO);
|
|
+ printf("Midi Input opened. Reading %d Midi messages...\n",num);
|
|
+ Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK);
|
|
+ /* empty the buffer after setting filter, just in case anything
|
|
+ got through */
|
|
+ while (Pm_Poll(midi)) {
|
|
+ Pm_Read(midi, buffer, 1);
|
|
+ }
|
|
+ i = 0;
|
|
+ while (i < num) {
|
|
+ status = Pm_Poll(midi);
|
|
+ if (status == TRUE) {
|
|
+ length = Pm_Read(midi,buffer,1);
|
|
+ if (length > 0) {
|
|
+ Pm_Write(midiOut, buffer, 1);
|
|
+ printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
|
|
+ i,
|
|
+ (long) buffer[0].timestamp,
|
|
+ (long) Pm_MessageStatus(buffer[0].message),
|
|
+ (long) Pm_MessageData1(buffer[0].message),
|
|
+ (long) Pm_MessageData2(buffer[0].message));
|
|
+ i++;
|
|
+ } else {
|
|
+ assert(0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* close midi devices */
|
|
+ Pm_Close(midi);
|
|
+ Pm_Close(midiOut);
|
|
+ Pm_Terminate();
|
|
+}
|
|
+
|
|
+
|
|
+/* main_test_stream exercises windows winmm API's stream mode */
|
|
+/* The winmm stream mode is used for latency>0, and sends
|
|
+ timestamped messages. The timestamps are relative (delta)
|
|
+ times, whereas PortMidi times are absolute. Since peculiar
|
|
+ things happen when messages are not always sent in advance,
|
|
+ this function allows us to exercise the system and test it.
|
|
+ */
|
|
+void main_test_stream() {
|
|
+ PmStream * midi;
|
|
+ char line[80];
|
|
+ PmEvent buffer[16];
|
|
+
|
|
+ /* determine which output device to use */
|
|
+ int i = get_number("Type output number: ");
|
|
+
|
|
+ latency = 500; /* ignore LATENCY for this test and
|
|
+ fix the latency at 500ms */
|
|
+
|
|
+ /* It is recommended to start timer before PortMidi */
|
|
+ TIME_START;
|
|
+
|
|
+ /* open output device */
|
|
+ Pm_OpenOutput(&midi,
|
|
+ i,
|
|
+ DRIVER_INFO,
|
|
+ OUTPUT_BUFFER_SIZE,
|
|
+ TIME_PROC,
|
|
+ TIME_INFO,
|
|
+ latency);
|
|
+ printf("Midi Output opened with %ld ms latency.\n", (long) latency);
|
|
+
|
|
+ /* output note on/off w/latency offset; hold until user prompts */
|
|
+ printf("ready to send output... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+
|
|
+ /* if we were writing midi for immediate output, we could always use
|
|
+ timestamps of zero, but since we may be writing with latency, we
|
|
+ will explicitly set the timestamp to "now" by getting the time.
|
|
+ The source of timestamps should always correspond to the TIME_PROC
|
|
+ and TIME_INFO parameters used in Pm_OpenOutput(). */
|
|
+ buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
+ buffer[0].message = Pm_Message(0xC0, 0, 0);
|
|
+ buffer[1].timestamp = buffer[0].timestamp;
|
|
+ buffer[1].message = Pm_Message(0x90, 60, 100);
|
|
+ buffer[2].timestamp = buffer[0].timestamp + 1000;
|
|
+ buffer[2].message = Pm_Message(0x90, 62, 100);
|
|
+ buffer[3].timestamp = buffer[0].timestamp + 2000;
|
|
+ buffer[3].message = Pm_Message(0x90, 64, 100);
|
|
+ buffer[4].timestamp = buffer[0].timestamp + 3000;
|
|
+ buffer[4].message = Pm_Message(0x90, 66, 100);
|
|
+ buffer[5].timestamp = buffer[0].timestamp + 4000;
|
|
+ buffer[5].message = Pm_Message(0x90, 60, 0);
|
|
+ buffer[6].timestamp = buffer[0].timestamp + 4000;
|
|
+ buffer[6].message = Pm_Message(0x90, 62, 0);
|
|
+ buffer[7].timestamp = buffer[0].timestamp + 4000;
|
|
+ buffer[7].message = Pm_Message(0x90, 64, 0);
|
|
+ buffer[8].timestamp = buffer[0].timestamp + 4000;
|
|
+ buffer[8].message = Pm_Message(0x90, 66, 0);
|
|
+
|
|
+ Pm_Write(midi, buffer, 9);
|
|
+#ifdef SEND8
|
|
+ /* Now, we're ready for the real test.
|
|
+ Play 4 notes at now, now+500, now+1000, and now+1500
|
|
+ Then wait until now+2000.
|
|
+ Play 4 more notes as before.
|
|
+ We should hear 8 evenly spaced notes. */
|
|
+ now = TIME_PROC(TIME_INFO);
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ buffer[i * 2].timestamp = now + (i * 500);
|
|
+ buffer[i * 2].message = Pm_Message(0x90, 60, 100);
|
|
+ buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
|
|
+ buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
|
|
+ }
|
|
+ Pm_Write(midi, buffer, 8);
|
|
+
|
|
+ while (Pt_Time() < now + 2500)
|
|
+ /* busy wait */;
|
|
+ /* now we are 500 ms behind schedule, but since the latency
|
|
+ is 500, the delay should not be audible */
|
|
+ now += 2000;
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ buffer[i * 2].timestamp = now + (i * 500);
|
|
+ buffer[i * 2].message = Pm_Message(0x90, 60, 100);
|
|
+ buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
|
|
+ buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
|
|
+ }
|
|
+ Pm_Write(midi, buffer, 8);
|
|
+#endif
|
|
+ /* close device (this not explicitly needed in most implementations) */
|
|
+ printf("ready to close and terminate... (type RETURN):");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+
|
|
+ Pm_Close(midi);
|
|
+ Pm_Terminate();
|
|
+ printf("done closing and terminating...\n");
|
|
+}
|
|
+
|
|
+
|
|
+void show_usage()
|
|
+{
|
|
+ printf("Usage: test [-h] [-l latency-in-ms]\n");
|
|
+ exit(0);
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ int default_in;
|
|
+ int default_out;
|
|
+ int i = 0, n = 0;
|
|
+ char line[STRING_MAX];
|
|
+ int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0;
|
|
+ int stream_test = 0;
|
|
+ int latency_valid = FALSE;
|
|
+
|
|
+ if (sizeof(void *) == 8)
|
|
+ printf("Apparently this is a 64-bit machine.\n");
|
|
+ else if (sizeof(void *) == 4)
|
|
+ printf ("Apparently this is a 32-bit machine.\n");
|
|
+
|
|
+ for (i = 1; i < argc; i++) {
|
|
+ if (strcmp(argv[i], "-h") == 0) {
|
|
+ show_usage();
|
|
+ } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
|
|
+ i = i + 1;
|
|
+ latency = atoi(argv[i]);
|
|
+ printf("Latency will be %ld\n", (long) latency);
|
|
+ latency_valid = TRUE;
|
|
+ } else {
|
|
+ show_usage();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (!latency_valid) {
|
|
+ int lat; // declared int to match "%d"
|
|
+ printf("Latency in ms: ");
|
|
+ if (scanf("%d", &lat) == 1) {
|
|
+ latency = (int32_t) lat; // coerce from "%d" to known size
|
|
+ latency_valid = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* determine what type of test to run */
|
|
+ printf("begin portMidi test...\n");
|
|
+ printf("%s%s%s%s%s",
|
|
+ "enter your choice...\n 1: test input\n",
|
|
+ " 2: test input (fail w/assert)\n",
|
|
+ " 3: test input (fail w/NULL assign)\n",
|
|
+ " 4: test output\n 5: test both\n",
|
|
+ " 6: stream test\n");
|
|
+ while (n != 1) {
|
|
+ n = scanf("%d", &i);
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ switch(i) {
|
|
+ case 1:
|
|
+ test_input = 1;
|
|
+ break;
|
|
+ case 2:
|
|
+ test_input = 1;
|
|
+ somethingStupid = 1;
|
|
+ break;
|
|
+ case 3:
|
|
+ test_input = 1;
|
|
+ somethingStupid = 2;
|
|
+ break;
|
|
+ case 4:
|
|
+ test_output = 1;
|
|
+ break;
|
|
+ case 5:
|
|
+ test_both = 1;
|
|
+ break;
|
|
+ case 6:
|
|
+ stream_test = 1;
|
|
+ break;
|
|
+ default:
|
|
+ printf("got %d (invalid input)\n", n);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* list device information */
|
|
+ default_in = Pm_GetDefaultInputDeviceID();
|
|
+ default_out = Pm_GetDefaultOutputDeviceID();
|
|
+ for (i = 0; i < Pm_CountDevices(); i++) {
|
|
+ char *deflt;
|
|
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
|
|
+ if (((test_input | test_both) & info->input) |
|
|
+ ((test_output | test_both | stream_test) & info->output)) {
|
|
+ printf("%d: %s, %s", i, info->interf, info->name);
|
|
+ if (info->input) {
|
|
+ deflt = (i == default_in ? "default " : "");
|
|
+ printf(" (%sinput)", deflt);
|
|
+ }
|
|
+ if (info->output) {
|
|
+ deflt = (i == default_out ? "default " : "");
|
|
+ printf(" (%soutput)", deflt);
|
|
+ }
|
|
+ printf("\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* run test */
|
|
+ if (stream_test) {
|
|
+ main_test_stream();
|
|
+ } else if (test_input) {
|
|
+ main_test_input(somethingStupid);
|
|
+ } else if (test_output) {
|
|
+ main_test_output();
|
|
+ } else if (test_both) {
|
|
+ main_test_both();
|
|
+ }
|
|
+
|
|
+ printf("finished portMidi test...type ENTER to quit...");
|
|
+ fgets(line, STRING_MAX, stdin);
|
|
+ return 0;
|
|
+}
|
|
--- a/pm_test/test.c
|
|
+++ /dev/null
|
|
@@ -1,489 +0,0 @@
|
|
-#include "portmidi.h"
|
|
-#include "porttime.h"
|
|
-#include "stdlib.h"
|
|
-#include "stdio.h"
|
|
-#include "string.h"
|
|
-#include "assert.h"
|
|
-
|
|
-#define INPUT_BUFFER_SIZE 100
|
|
-#define OUTPUT_BUFFER_SIZE 0
|
|
-#define DRIVER_INFO NULL
|
|
-#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
|
|
-#define TIME_INFO NULL
|
|
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
|
|
-
|
|
-#define STRING_MAX 80 /* used for console input */
|
|
-
|
|
-int32_t latency = 0;
|
|
-
|
|
-/* crash the program to test whether midi ports are closed */
|
|
-/**/
|
|
-void doSomethingReallyStupid() {
|
|
- int * tmp = NULL;
|
|
- *tmp = 5;
|
|
-}
|
|
-
|
|
-
|
|
-/* exit the program without any explicit cleanup */
|
|
-/**/
|
|
-void doSomethingStupid() {
|
|
- assert(0);
|
|
-}
|
|
-
|
|
-
|
|
-/* read a number from console */
|
|
-/**/
|
|
-int get_number(char *prompt)
|
|
-{
|
|
- char line[STRING_MAX];
|
|
- int n = 0, i;
|
|
- printf(prompt);
|
|
- while (n != 1) {
|
|
- n = scanf("%d", &i);
|
|
- fgets(line, STRING_MAX, stdin);
|
|
-
|
|
- }
|
|
- return i;
|
|
-}
|
|
-
|
|
-
|
|
-/*
|
|
- * the somethingStupid parameter can be set to simulate a program crash.
|
|
- * We want PortMidi to close Midi ports automatically in the event of a
|
|
- * crash because Windows does not (and this may cause an OS crash)
|
|
- */
|
|
-void main_test_input(unsigned int somethingStupid) {
|
|
- PmStream * midi;
|
|
- PmError status, length;
|
|
- PmEvent buffer[1];
|
|
- int num = 10;
|
|
- int i = get_number("Type input number: ");
|
|
- /* It is recommended to start timer before Midi; otherwise, PortMidi may
|
|
- start the timer with its (default) parameters
|
|
- */
|
|
- TIME_START;
|
|
-
|
|
- /* open input device */
|
|
- Pm_OpenInput(&midi,
|
|
- i,
|
|
- DRIVER_INFO,
|
|
- INPUT_BUFFER_SIZE,
|
|
- TIME_PROC,
|
|
- TIME_INFO);
|
|
-
|
|
- printf("Midi Input opened. Reading %d Midi messages...\n", num);
|
|
- Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
|
|
- /* empty the buffer after setting filter, just in case anything
|
|
- got through */
|
|
- while (Pm_Poll(midi)) {
|
|
- Pm_Read(midi, buffer, 1);
|
|
- }
|
|
- /* now start paying attention to messages */
|
|
- i = 0; /* count messages as they arrive */
|
|
- while (i < num) {
|
|
- status = Pm_Poll(midi);
|
|
- if (status == TRUE) {
|
|
- length = Pm_Read(midi,buffer, 1);
|
|
- if (length > 0) {
|
|
- printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
|
|
- i,
|
|
- (long) buffer[0].timestamp,
|
|
- (long) Pm_MessageStatus(buffer[0].message),
|
|
- (long) Pm_MessageData1(buffer[0].message),
|
|
- (long) Pm_MessageData2(buffer[0].message));
|
|
- i++;
|
|
- } else {
|
|
- assert(0);
|
|
- }
|
|
- }
|
|
- /* simulate crash if somethingStupid is 1 or 2 */
|
|
- if ((i > (num/2)) && (somethingStupid == 1)) {
|
|
- doSomethingStupid();
|
|
- } else if ((i > (num/2)) && (somethingStupid == 2)) {
|
|
- doSomethingReallyStupid();
|
|
- }
|
|
- }
|
|
-
|
|
- /* close device (this not explicitly needed in most implementations) */
|
|
- printf("ready to close...");
|
|
-
|
|
- Pm_Close(midi);
|
|
- printf("done closing...");
|
|
-}
|
|
-
|
|
-
|
|
-
|
|
-void main_test_output() {
|
|
- PmStream * midi;
|
|
- char line[80];
|
|
- int32_t off_time;
|
|
- int chord[] = { 60, 67, 76, 83, 90 };
|
|
- #define chord_size 5
|
|
- PmEvent buffer[chord_size];
|
|
- PmTimestamp timestamp;
|
|
-
|
|
- /* determine which output device to use */
|
|
- int i = get_number("Type output number: ");
|
|
-
|
|
- /* It is recommended to start timer before PortMidi */
|
|
- TIME_START;
|
|
-
|
|
- /* open output device -- since PortMidi avoids opening a timer
|
|
- when latency is zero, we will pass in a NULL timer pointer
|
|
- for that case. If PortMidi tries to access the time_proc,
|
|
- we will crash, so this test will tell us something. */
|
|
- Pm_OpenOutput(&midi,
|
|
- i,
|
|
- DRIVER_INFO,
|
|
- OUTPUT_BUFFER_SIZE,
|
|
- (latency == 0 ? NULL : TIME_PROC),
|
|
- (latency == 0 ? NULL : TIME_INFO),
|
|
- latency);
|
|
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
|
|
-
|
|
- /* output note on/off w/latency offset; hold until user prompts */
|
|
- printf("ready to send program 1 change... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- /* if we were writing midi for immediate output, we could always use
|
|
- timestamps of zero, but since we may be writing with latency, we
|
|
- will explicitly set the timestamp to "now" by getting the time.
|
|
- The source of timestamps should always correspond to the TIME_PROC
|
|
- and TIME_INFO parameters used in Pm_OpenOutput(). */
|
|
- buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
- /* Send a program change to increase the chances we will hear notes */
|
|
- /* Program 0 is usually a piano, but you can change it here: */
|
|
-#define PROGRAM 0
|
|
- buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
|
|
- Pm_Write(midi, buffer, 1);
|
|
-
|
|
- printf("ready to note-on... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
- buffer[0].message = Pm_Message(0x90, 60, 100);
|
|
- Pm_Write(midi, buffer, 1);
|
|
- printf("ready to note-off... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
- buffer[0].message = Pm_Message(0x90, 60, 0);
|
|
- Pm_Write(midi, buffer, 1);
|
|
-
|
|
- /* output short note on/off w/latency offset; hold until user prompts */
|
|
- printf("ready to note-on (short form)... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
|
|
- Pm_Message(0x90, 60, 100));
|
|
- printf("ready to note-off (short form)... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
|
|
- Pm_Message(0x90, 60, 0));
|
|
-
|
|
- /* output several note on/offs to test timing.
|
|
- Should be 1s between notes */
|
|
- printf("chord will arpeggiate if latency > 0\n");
|
|
- printf("ready to chord-on/chord-off... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- timestamp = TIME_PROC(TIME_INFO);
|
|
- for (i = 0; i < chord_size; i++) {
|
|
- buffer[i].timestamp = timestamp + 1000 * i;
|
|
- buffer[i].message = Pm_Message(0x90, chord[i], 100);
|
|
- }
|
|
- Pm_Write(midi, buffer, chord_size);
|
|
-
|
|
- off_time = timestamp + 1000 + chord_size * 1000;
|
|
- while (TIME_PROC(TIME_INFO) < off_time)
|
|
- /* busy wait */;
|
|
- for (i = 0; i < chord_size; i++) {
|
|
- buffer[i].timestamp = timestamp + 1000 * i;
|
|
- buffer[i].message = Pm_Message(0x90, chord[i], 0);
|
|
- }
|
|
- Pm_Write(midi, buffer, chord_size);
|
|
-
|
|
- /* close device (this not explicitly needed in most implementations) */
|
|
- printf("ready to close and terminate... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
-
|
|
- Pm_Close(midi);
|
|
- Pm_Terminate();
|
|
- printf("done closing and terminating...\n");
|
|
-}
|
|
-
|
|
-
|
|
-void main_test_both()
|
|
-{
|
|
- int i = 0;
|
|
- int in, out;
|
|
- PmStream * midi, * midiOut;
|
|
- PmEvent buffer[1];
|
|
- PmError status, length;
|
|
- int num = 10;
|
|
-
|
|
- in = get_number("Type input number: ");
|
|
- out = get_number("Type output number: ");
|
|
-
|
|
- /* In is recommended to start timer before PortMidi */
|
|
- TIME_START;
|
|
-
|
|
- Pm_OpenOutput(&midiOut,
|
|
- out,
|
|
- DRIVER_INFO,
|
|
- OUTPUT_BUFFER_SIZE,
|
|
- TIME_PROC,
|
|
- TIME_INFO,
|
|
- latency);
|
|
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
|
|
- /* open input device */
|
|
- Pm_OpenInput(&midi,
|
|
- in,
|
|
- DRIVER_INFO,
|
|
- INPUT_BUFFER_SIZE,
|
|
- TIME_PROC,
|
|
- TIME_INFO);
|
|
- printf("Midi Input opened. Reading %d Midi messages...\n",num);
|
|
- Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK);
|
|
- /* empty the buffer after setting filter, just in case anything
|
|
- got through */
|
|
- while (Pm_Poll(midi)) {
|
|
- Pm_Read(midi, buffer, 1);
|
|
- }
|
|
- i = 0;
|
|
- while (i < num) {
|
|
- status = Pm_Poll(midi);
|
|
- if (status == TRUE) {
|
|
- length = Pm_Read(midi,buffer,1);
|
|
- if (length > 0) {
|
|
- Pm_Write(midiOut, buffer, 1);
|
|
- printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
|
|
- i,
|
|
- (long) buffer[0].timestamp,
|
|
- (long) Pm_MessageStatus(buffer[0].message),
|
|
- (long) Pm_MessageData1(buffer[0].message),
|
|
- (long) Pm_MessageData2(buffer[0].message));
|
|
- i++;
|
|
- } else {
|
|
- assert(0);
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- /* close midi devices */
|
|
- Pm_Close(midi);
|
|
- Pm_Close(midiOut);
|
|
- Pm_Terminate();
|
|
-}
|
|
-
|
|
-
|
|
-/* main_test_stream exercises windows winmm API's stream mode */
|
|
-/* The winmm stream mode is used for latency>0, and sends
|
|
- timestamped messages. The timestamps are relative (delta)
|
|
- times, whereas PortMidi times are absolute. Since peculiar
|
|
- things happen when messages are not always sent in advance,
|
|
- this function allows us to exercise the system and test it.
|
|
- */
|
|
-void main_test_stream() {
|
|
- PmStream * midi;
|
|
- char line[80];
|
|
- PmEvent buffer[16];
|
|
-
|
|
- /* determine which output device to use */
|
|
- int i = get_number("Type output number: ");
|
|
-
|
|
- latency = 500; /* ignore LATENCY for this test and
|
|
- fix the latency at 500ms */
|
|
-
|
|
- /* It is recommended to start timer before PortMidi */
|
|
- TIME_START;
|
|
-
|
|
- /* open output device */
|
|
- Pm_OpenOutput(&midi,
|
|
- i,
|
|
- DRIVER_INFO,
|
|
- OUTPUT_BUFFER_SIZE,
|
|
- TIME_PROC,
|
|
- TIME_INFO,
|
|
- latency);
|
|
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
|
|
-
|
|
- /* output note on/off w/latency offset; hold until user prompts */
|
|
- printf("ready to send output... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
-
|
|
- /* if we were writing midi for immediate output, we could always use
|
|
- timestamps of zero, but since we may be writing with latency, we
|
|
- will explicitly set the timestamp to "now" by getting the time.
|
|
- The source of timestamps should always correspond to the TIME_PROC
|
|
- and TIME_INFO parameters used in Pm_OpenOutput(). */
|
|
- buffer[0].timestamp = TIME_PROC(TIME_INFO);
|
|
- buffer[0].message = Pm_Message(0xC0, 0, 0);
|
|
- buffer[1].timestamp = buffer[0].timestamp;
|
|
- buffer[1].message = Pm_Message(0x90, 60, 100);
|
|
- buffer[2].timestamp = buffer[0].timestamp + 1000;
|
|
- buffer[2].message = Pm_Message(0x90, 62, 100);
|
|
- buffer[3].timestamp = buffer[0].timestamp + 2000;
|
|
- buffer[3].message = Pm_Message(0x90, 64, 100);
|
|
- buffer[4].timestamp = buffer[0].timestamp + 3000;
|
|
- buffer[4].message = Pm_Message(0x90, 66, 100);
|
|
- buffer[5].timestamp = buffer[0].timestamp + 4000;
|
|
- buffer[5].message = Pm_Message(0x90, 60, 0);
|
|
- buffer[6].timestamp = buffer[0].timestamp + 4000;
|
|
- buffer[6].message = Pm_Message(0x90, 62, 0);
|
|
- buffer[7].timestamp = buffer[0].timestamp + 4000;
|
|
- buffer[7].message = Pm_Message(0x90, 64, 0);
|
|
- buffer[8].timestamp = buffer[0].timestamp + 4000;
|
|
- buffer[8].message = Pm_Message(0x90, 66, 0);
|
|
-
|
|
- Pm_Write(midi, buffer, 9);
|
|
-#ifdef SEND8
|
|
- /* Now, we're ready for the real test.
|
|
- Play 4 notes at now, now+500, now+1000, and now+1500
|
|
- Then wait until now+2000.
|
|
- Play 4 more notes as before.
|
|
- We should hear 8 evenly spaced notes. */
|
|
- now = TIME_PROC(TIME_INFO);
|
|
- for (i = 0; i < 4; i++) {
|
|
- buffer[i * 2].timestamp = now + (i * 500);
|
|
- buffer[i * 2].message = Pm_Message(0x90, 60, 100);
|
|
- buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
|
|
- buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
|
|
- }
|
|
- Pm_Write(midi, buffer, 8);
|
|
-
|
|
- while (Pt_Time() < now + 2500)
|
|
- /* busy wait */;
|
|
- /* now we are 500 ms behind schedule, but since the latency
|
|
- is 500, the delay should not be audible */
|
|
- now += 2000;
|
|
- for (i = 0; i < 4; i++) {
|
|
- buffer[i * 2].timestamp = now + (i * 500);
|
|
- buffer[i * 2].message = Pm_Message(0x90, 60, 100);
|
|
- buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
|
|
- buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
|
|
- }
|
|
- Pm_Write(midi, buffer, 8);
|
|
-#endif
|
|
- /* close device (this not explicitly needed in most implementations) */
|
|
- printf("ready to close and terminate... (type RETURN):");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
-
|
|
- Pm_Close(midi);
|
|
- Pm_Terminate();
|
|
- printf("done closing and terminating...\n");
|
|
-}
|
|
-
|
|
-
|
|
-void show_usage()
|
|
-{
|
|
- printf("Usage: test [-h] [-l latency-in-ms]\n");
|
|
- exit(0);
|
|
-}
|
|
-
|
|
-int main(int argc, char *argv[])
|
|
-{
|
|
- int default_in;
|
|
- int default_out;
|
|
- int i = 0, n = 0;
|
|
- char line[STRING_MAX];
|
|
- int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0;
|
|
- int stream_test = 0;
|
|
- int latency_valid = FALSE;
|
|
-
|
|
- if (sizeof(void *) == 8)
|
|
- printf("Apparently this is a 64-bit machine.\n");
|
|
- else if (sizeof(void *) == 4)
|
|
- printf ("Apparently this is a 32-bit machine.\n");
|
|
-
|
|
- for (i = 1; i < argc; i++) {
|
|
- if (strcmp(argv[i], "-h") == 0) {
|
|
- show_usage();
|
|
- } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
|
|
- i = i + 1;
|
|
- latency = atoi(argv[i]);
|
|
- printf("Latency will be %ld\n", (long) latency);
|
|
- latency_valid = TRUE;
|
|
- } else {
|
|
- show_usage();
|
|
- }
|
|
- }
|
|
-
|
|
- while (!latency_valid) {
|
|
- int lat; // declared int to match "%d"
|
|
- printf("Latency in ms: ");
|
|
- if (scanf("%d", &lat) == 1) {
|
|
- latency = (int32_t) lat; // coerce from "%d" to known size
|
|
- latency_valid = TRUE;
|
|
- }
|
|
- }
|
|
-
|
|
- /* determine what type of test to run */
|
|
- printf("begin portMidi test...\n");
|
|
- printf("%s%s%s%s%s",
|
|
- "enter your choice...\n 1: test input\n",
|
|
- " 2: test input (fail w/assert)\n",
|
|
- " 3: test input (fail w/NULL assign)\n",
|
|
- " 4: test output\n 5: test both\n",
|
|
- " 6: stream test\n");
|
|
- while (n != 1) {
|
|
- n = scanf("%d", &i);
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- switch(i) {
|
|
- case 1:
|
|
- test_input = 1;
|
|
- break;
|
|
- case 2:
|
|
- test_input = 1;
|
|
- somethingStupid = 1;
|
|
- break;
|
|
- case 3:
|
|
- test_input = 1;
|
|
- somethingStupid = 2;
|
|
- break;
|
|
- case 4:
|
|
- test_output = 1;
|
|
- break;
|
|
- case 5:
|
|
- test_both = 1;
|
|
- break;
|
|
- case 6:
|
|
- stream_test = 1;
|
|
- break;
|
|
- default:
|
|
- printf("got %d (invalid input)\n", n);
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- /* list device information */
|
|
- default_in = Pm_GetDefaultInputDeviceID();
|
|
- default_out = Pm_GetDefaultOutputDeviceID();
|
|
- for (i = 0; i < Pm_CountDevices(); i++) {
|
|
- char *deflt;
|
|
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
|
|
- if (((test_input | test_both) & info->input) |
|
|
- ((test_output | test_both | stream_test) & info->output)) {
|
|
- printf("%d: %s, %s", i, info->interf, info->name);
|
|
- if (info->input) {
|
|
- deflt = (i == default_in ? "default " : "");
|
|
- printf(" (%sinput)", deflt);
|
|
- }
|
|
- if (info->output) {
|
|
- deflt = (i == default_out ? "default " : "");
|
|
- printf(" (%soutput)", deflt);
|
|
- }
|
|
- printf("\n");
|
|
- }
|
|
- }
|
|
-
|
|
- /* run test */
|
|
- if (stream_test) {
|
|
- main_test_stream();
|
|
- } else if (test_input) {
|
|
- main_test_input(somethingStupid);
|
|
- } else if (test_output) {
|
|
- main_test_output();
|
|
- } else if (test_both) {
|
|
- main_test_both();
|
|
- }
|
|
-
|
|
- printf("finished portMidi test...type ENTER to quit...");
|
|
- fgets(line, STRING_MAX, stdin);
|
|
- return 0;
|
|
-}
|