summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/portmidi/pm_test/mm.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portmidi/pm_test/mm.c')
-rw-r--r--3rdparty/portmidi/pm_test/mm.c572
1 files changed, 572 insertions, 0 deletions
diff --git a/3rdparty/portmidi/pm_test/mm.c b/3rdparty/portmidi/pm_test/mm.c
new file mode 100644
index 00000000000..0f2a52ee267
--- /dev/null
+++ b/3rdparty/portmidi/pm_test/mm.c
@@ -0,0 +1,572 @@
+/* mm.c -- midi monitor */
+
+/*****************************************************************************
+* Change Log
+* Date | Change
+*-----------+-----------------------------------------------------------------
+* 7-Apr-86 | Created changelog
+* 31-Jan-90 | GWL : use new cmdline
+* 5-Apr-91 | JDW : Further changes
+* 16-Feb-92 | GWL : eliminate label mmexit:; add error recovery
+* 18-May-92 | GWL : continuous clocks, etc.
+* 17-Jan-94 | GWL : option to display notes
+* 20-Nov-06 | RBD : port mm.c from CMU Midi Toolkit to PortMidi
+* | mm.c -- revealing MIDI secrets for over 20 years!
+*****************************************************************************/
+
+#include "stdlib.h"
+#include "ctype.h"
+#include "string.h"
+#include "stdio.h"
+#include "porttime.h"
+#include "portmidi.h"
+
+#define STRING_MAX 80
+
+#define MIDI_CODE_MASK 0xf0
+#define MIDI_CHN_MASK 0x0f
+/*#define MIDI_REALTIME 0xf8
+ #define MIDI_CHAN_MODE 0xfa */
+#define MIDI_OFF_NOTE 0x80
+#define MIDI_ON_NOTE 0x90
+#define MIDI_POLY_TOUCH 0xa0
+#define MIDI_CTRL 0xb0
+#define MIDI_CH_PROGRAM 0xc0
+#define MIDI_TOUCH 0xd0
+#define MIDI_BEND 0xe0
+
+#define MIDI_SYSEX 0xf0
+#define MIDI_Q_FRAME 0xf1
+#define MIDI_SONG_POINTER 0xf2
+#define MIDI_SONG_SELECT 0xf3
+#define MIDI_TUNE_REQ 0xf6
+#define MIDI_EOX 0xf7
+#define MIDI_TIME_CLOCK 0xf8
+#define MIDI_START 0xfa
+#define MIDI_CONTINUE 0xfb
+#define MIDI_STOP 0xfc
+#define MIDI_ACTIVE_SENSING 0xfe
+#define MIDI_SYS_RESET 0xff
+
+#define MIDI_ALL_SOUND_OFF 0x78
+#define MIDI_RESET_CONTROLLERS 0x79
+#define MIDI_LOCAL 0x7a
+#define MIDI_ALL_OFF 0x7b
+#define MIDI_OMNI_OFF 0x7c
+#define MIDI_OMNI_ON 0x7d
+#define MIDI_MONO_ON 0x7e
+#define MIDI_POLY_ON 0x7f
+
+
+#define private static
+
+#ifndef false
+#define false 0
+#define true 1
+#endif
+
+typedef int boolean;
+
+int debug = false; /* never set, but referenced by userio.c */
+PmStream *midi_in; /* midi input */
+boolean active = false; /* set when midi_in is ready for reading */
+boolean in_sysex = false; /* we are reading a sysex message */
+boolean inited = false; /* suppress printing during command line parsing */
+boolean done = false; /* when true, exit */
+boolean notes = true; /* show notes? */
+boolean controls = true; /* show continuous controllers */
+boolean bender = true; /* record pitch bend etc.? */
+boolean excldata = true; /* record system exclusive data? */
+boolean verbose = true; /* show text representation? */
+boolean realdata = true; /* record real time messages? */
+boolean clksencnt = true; /* clock and active sense count on */
+boolean chmode = true; /* show channel mode messages */
+boolean pgchanges = true; /* show program changes */
+boolean flush = false; /* flush all pending MIDI data */
+
+uint32_t filter = 0; /* remember state of midi filter */
+
+uint32_t clockcount = 0; /* count of clocks */
+uint32_t actsensecount = 0; /* cout of active sensing bytes */
+uint32_t notescount = 0; /* #notes since last request */
+uint32_t notestotal = 0; /* total #notes */
+
+char val_format[] = " Val %d\n";
+
+/*****************************************************************************
+* Imported variables
+*****************************************************************************/
+
+extern int abort_flag;
+
+/*****************************************************************************
+* Routines local to this module
+*****************************************************************************/
+
+private void mmexit(int code);
+private void output(PmMessage data);
+private int put_pitch(int p);
+private void showhelp();
+private void showbytes(PmMessage data, int len, boolean newline);
+private void showstatus(boolean flag);
+private void doascii(char c);
+private int get_number(char *prompt);
+
+
+/* read a number from console */
+/**/
+int get_number(char *prompt)
+{
+ char line[STRING_MAX];
+ int n = 0, i;
+ printf(prompt);
+ while (n != 1) {
+ n = scanf("%d", &i);
+ fgets(line, STRING_MAX, stdin);
+
+ }
+ return i;
+}
+
+
+void receive_poll(PtTimestamp timestamp, void *userData)
+{
+ PmEvent event;
+ int count;
+ if (!active) return;
+ while ((count = Pm_Read(midi_in, &event, 1))) {
+ if (count == 1) output(event.message);
+ else printf(Pm_GetErrorText(count));
+ }
+}
+
+
+/****************************************************************************
+* main
+* Effect: prompts for parameters, starts monitor
+****************************************************************************/
+
+int main(int argc, char **argv)
+{
+ char *argument;
+ int inp;
+ PmError err;
+ int i;
+ if (argc > 1) { /* first arg can change defaults */
+ argument = argv[1];
+ while (*argument) doascii(*argument++);
+ }
+ showhelp();
+ /* use porttime callback to empty midi queue and print */
+ Pt_Start(1, receive_poll, 0);
+ /* list device information */
+ printf("MIDI input devices:\n");
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ if (info->input) printf("%d: %s, %s\n", i, info->interf, info->name);
+ }
+ inp = get_number("Type input device number: ");
+ err = Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL);
+ if (err) {
+ printf(Pm_GetErrorText(err));
+ Pt_Stop();
+ mmexit(1);
+ }
+ Pm_SetFilter(midi_in, filter);
+ inited = true; /* now can document changes, set filter */
+ printf("Midi Monitor ready.\n");
+ active = true;
+ while (!done) {
+ char s[100];
+ if (fgets(s, 100, stdin)) {
+ doascii(s[0]);
+ }
+ }
+ active = false;
+ Pm_Close(midi_in);
+ Pt_Stop();
+ Pm_Terminate();
+ mmexit(0);
+ return 0; // make the compiler happy be returning a value
+}
+
+
+/****************************************************************************
+* doascii
+* Inputs:
+* char c: input character
+* Effect: interpret to revise flags
+****************************************************************************/
+
+private void doascii(char c)
+{
+ if (isupper(c)) c = tolower(c);
+ if (c == 'q') done = true;
+ else if (c == 'b') {
+ bender = !bender;
+ filter ^= PM_FILT_PITCHBEND;
+ if (inited)
+ printf("Pitch Bend, etc. %s\n", (bender ? "ON" : "OFF"));
+ } else if (c == 'c') {
+ controls = !controls;
+ filter ^= PM_FILT_CONTROL;
+ if (inited)
+ printf("Control Change %s\n", (controls ? "ON" : "OFF"));
+ } else if (c == 'h') {
+ pgchanges = !pgchanges;
+ filter ^= PM_FILT_PROGRAM;
+ if (inited)
+ printf("Program Changes %s\n", (pgchanges ? "ON" : "OFF"));
+ } else if (c == 'n') {
+ notes = !notes;
+ filter ^= PM_FILT_NOTE;
+ if (inited)
+ printf("Notes %s\n", (notes ? "ON" : "OFF"));
+ } else if (c == 'x') {
+ excldata = !excldata;
+ filter ^= PM_FILT_SYSEX;
+ if (inited)
+ printf("System Exclusive data %s\n", (excldata ? "ON" : "OFF"));
+ } else if (c == 'r') {
+ realdata = !realdata;
+ filter ^= (PM_FILT_PLAY | PM_FILT_RESET | PM_FILT_TICK | PM_FILT_UNDEFINED);
+ if (inited)
+ printf("Real Time messages %s\n", (realdata ? "ON" : "OFF"));
+ } else if (c == 'k') {
+ clksencnt = !clksencnt;
+ filter ^= PM_FILT_CLOCK;
+ if (inited)
+ printf("Clock and Active Sense Counting %s\n", (clksencnt ? "ON" : "OFF"));
+ if (!clksencnt) clockcount = actsensecount = 0;
+ } else if (c == 's') {
+ if (clksencnt) {
+ if (inited)
+ printf("Clock Count %ld\nActive Sense Count %ld\n",
+ (long) clockcount, (long) actsensecount);
+ } else if (inited) {
+ printf("Clock Counting not on\n");
+ }
+ } else if (c == 't') {
+ notestotal+=notescount;
+ if (inited)
+ printf("This Note Count %ld\nTotal Note Count %ld\n",
+ (long) notescount, (long) notestotal);
+ notescount=0;
+ } else if (c == 'v') {
+ verbose = !verbose;
+ if (inited)
+ printf("Verbose %s\n", (verbose ? "ON" : "OFF"));
+ } else if (c == 'm') {
+ chmode = !chmode;
+ if (inited)
+ printf("Channel Mode Messages %s", (chmode ? "ON" : "OFF"));
+ } else {
+ if (inited) {
+ if (c == ' ') {
+ PmEvent event;
+ while (Pm_Read(midi_in, &event, 1)) ; /* flush midi input */
+ printf("...FLUSHED MIDI INPUT\n\n");
+ } else showhelp();
+ }
+ }
+ if (inited) Pm_SetFilter(midi_in, filter);
+}
+
+
+
+private void mmexit(int code)
+{
+ /* if this is not being run from a console, maybe we should wait for
+ * the user to read error messages before exiting
+ */
+ exit(code);
+}
+
+
+/****************************************************************************
+* output
+* Inputs:
+* data: midi message buffer holding one command or 4 bytes of sysex msg
+* Effect: format and print midi data
+****************************************************************************/
+
+char vel_format[] = " Vel %d\n";
+
+private void output(PmMessage data)
+{
+ int command; /* the current command */
+ int chan; /* the midi channel of the current event */
+ int len; /* used to get constant field width */
+
+ /* printf("output data %8x; ", data); */
+
+ command = Pm_MessageStatus(data) & MIDI_CODE_MASK;
+ chan = Pm_MessageStatus(data) & MIDI_CHN_MASK;
+
+ if (in_sysex || Pm_MessageStatus(data) == MIDI_SYSEX) {
+#define sysex_max 16
+ int i;
+ PmMessage data_copy = data;
+ in_sysex = true;
+ /* look for MIDI_EOX in first 3 bytes
+ * if realtime messages are embedded in sysex message, they will
+ * be printed as if they are part of the sysex message
+ */
+ for (i = 0; (i < 4) && ((data_copy & 0xFF) != MIDI_EOX); i++)
+ data_copy >>= 8;
+ if (i < 4) {
+ in_sysex = false;
+ i++; /* include the EOX byte in output */
+ }
+ showbytes(data, i, verbose);
+ if (verbose) printf("System Exclusive\n");
+ } else if (command == MIDI_ON_NOTE && Pm_MessageData2(data) != 0) {
+ notescount++;
+ if (notes) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ printf("NoteOn Chan %2d Key %3d ", chan, Pm_MessageData1(data));
+ len = put_pitch(Pm_MessageData1(data));
+ printf(vel_format + len, Pm_MessageData2(data));
+ }
+ }
+ } else if ((command == MIDI_ON_NOTE /* && Pm_MessageData2(data) == 0 */ ||
+ command == MIDI_OFF_NOTE) && notes) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ printf("NoteOff Chan %2d Key %3d ", chan, Pm_MessageData1(data));
+ len = put_pitch(Pm_MessageData1(data));
+ printf(vel_format + len, Pm_MessageData2(data));
+ }
+ } else if (command == MIDI_CH_PROGRAM && pgchanges) {
+ showbytes(data, 2, verbose);
+ if (verbose) {
+ printf(" ProgChg Chan %2d Prog %2d\n", chan, Pm_MessageData1(data) + 1);
+ }
+ } else if (command == MIDI_CTRL) {
+ /* controls 121 (MIDI_RESET_CONTROLLER) to 127 are channel
+ * mode messages. */
+ if (Pm_MessageData1(data) < MIDI_ALL_SOUND_OFF) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ printf("CtrlChg Chan %2d Ctrl %2d Val %2d\n",
+ chan, Pm_MessageData1(data), Pm_MessageData2(data));
+ }
+ } else /* channel mode */ if (chmode) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ switch (Pm_MessageData1(data)) {
+ case MIDI_ALL_SOUND_OFF:
+ printf("All Sound Off, Chan %2d\n", chan);
+ break;
+ case MIDI_RESET_CONTROLLERS:
+ printf("Reset All Controllers, Chan %2d\n", chan);
+ break;
+ case MIDI_LOCAL:
+ printf("LocCtrl Chan %2d %s\n",
+ chan, Pm_MessageData2(data) ? "On" : "Off");
+ break;
+ case MIDI_ALL_OFF:
+ printf("All Off Chan %2d\n", chan);
+ break;
+ case MIDI_OMNI_OFF:
+ printf("OmniOff Chan %2d\n", chan);
+ break;
+ case MIDI_OMNI_ON:
+ printf("Omni On Chan %2d\n", chan);
+ break;
+ case MIDI_MONO_ON:
+ printf("Mono On Chan %2d\n", chan);
+ if (Pm_MessageData2(data))
+ printf(" to %d received channels\n", Pm_MessageData2(data));
+ else
+ printf(" to all received channels\n");
+ break;
+ case MIDI_POLY_ON:
+ printf("Poly On Chan %2d\n", chan);
+ break;
+ }
+ }
+ }
+ } else if (command == MIDI_POLY_TOUCH && bender) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ printf("P.Touch Chan %2d Key %2d ", chan, Pm_MessageData1(data));
+ len = put_pitch(Pm_MessageData1(data));
+ printf(val_format + len, Pm_MessageData2(data));
+ }
+ } else if (command == MIDI_TOUCH && bender) {
+ showbytes(data, 2, verbose);
+ if (verbose) {
+ printf(" A.Touch Chan %2d Val %2d\n", chan, Pm_MessageData1(data));
+ }
+ } else if (command == MIDI_BEND && bender) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ printf("P.Bend Chan %2d Val %2d\n", chan,
+ (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7)));
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_SONG_POINTER) {
+ showbytes(data, 3, verbose);
+ if (verbose) {
+ printf(" Song Position %d\n",
+ (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7)));
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_SONG_SELECT) {
+ showbytes(data, 2, verbose);
+ if (verbose) {
+ printf(" Song Select %d\n", Pm_MessageData1(data));
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_TUNE_REQ) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" Tune Request\n");
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_Q_FRAME && realdata) {
+ showbytes(data, 2, verbose);
+ if (verbose) {
+ printf(" Time Code Quarter Frame Type %d Values %d\n",
+ (Pm_MessageData1(data) & 0x70) >> 4, Pm_MessageData1(data) & 0xf);
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_START && realdata) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" Start\n");
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_CONTINUE && realdata) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" Continue\n");
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_STOP && realdata) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" Stop\n");
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_SYS_RESET && realdata) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" System Reset\n");
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_TIME_CLOCK) {
+ if (clksencnt) clockcount++;
+ else if (realdata) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" Clock\n");
+ }
+ }
+ } else if (Pm_MessageStatus(data) == MIDI_ACTIVE_SENSING) {
+ if (clksencnt) actsensecount++;
+ else if (realdata) {
+ showbytes(data, 1, verbose);
+ if (verbose) {
+ printf(" Active Sensing\n");
+ }
+ }
+ } else showbytes(data, 3, verbose);
+ fflush(stdout);
+}
+
+
+/****************************************************************************
+* put_pitch
+* Inputs:
+* int p: pitch number
+* Effect: write out the pitch name for a given number
+****************************************************************************/
+
+private int put_pitch(int p)
+{
+ char result[8];
+ static char *ptos[] = {
+ "c", "cs", "d", "ef", "e", "f", "fs", "g",
+ "gs", "a", "bf", "b" };
+ /* note octave correction below */
+ sprintf(result, "%s%d", ptos[p % 12], (p / 12) - 1);
+ printf(result);
+ return strlen(result);
+}
+
+
+/****************************************************************************
+* showbytes
+* Effect: print hex data, precede with newline if asked
+****************************************************************************/
+
+char nib_to_hex[] = "0123456789ABCDEF";
+
+private void showbytes(PmMessage data, int len, boolean newline)
+{
+ int count = 0;
+ int i;
+
+/* if (newline) {
+ putchar('\n');
+ count++;
+ } */
+ for (i = 0; i < len; i++) {
+ putchar(nib_to_hex[(data >> 4) & 0xF]);
+ putchar(nib_to_hex[data & 0xF]);
+ count += 2;
+ if (count > 72) {
+ putchar('.');
+ putchar('.');
+ putchar('.');
+ break;
+ }
+ data >>= 8;
+ }
+ putchar(' ');
+}
+
+
+
+/****************************************************************************
+* showhelp
+* Effect: print help text
+****************************************************************************/
+
+private void showhelp()
+{
+ printf("\n");
+ printf(" Item Reported Range Item Reported Range\n");
+ printf(" ------------- ----- ------------- -----\n");
+ printf(" Channels 1 - 16 Programs 1 - 128\n");
+ printf(" Controllers 0 - 127 After Touch 0 - 127\n");
+ printf(" Loudness 0 - 127 Pitch Bend 0 - 16383, center = 8192\n");
+ printf(" Pitches 0 - 127, 60 = c4 = middle C\n");
+ printf(" \n");
+ printf("n toggles notes");
+ showstatus(notes);
+ printf("t displays noteon count since last t\n");
+ printf("b toggles pitch bend, aftertouch");
+ showstatus(bender);
+ printf("c toggles continuous control");
+ showstatus(controls);
+ printf("h toggles program changes");
+ showstatus(pgchanges);
+ printf("x toggles system exclusive");
+ showstatus(excldata);
+ printf("k toggles clock and sense counting only");
+ showstatus(clksencnt);
+ printf("r toggles other real time messages & SMPTE");
+ showstatus(realdata);
+ printf("s displays clock and sense count since last k\n");
+ printf("m toggles channel mode messages");
+ showstatus(chmode);
+ printf("v toggles verbose text");
+ showstatus(verbose);
+ printf("q quits\n");
+ printf("\n");
+}
+
+/****************************************************************************
+* showstatus
+* Effect: print status of flag
+****************************************************************************/
+
+private void showstatus(boolean flag)
+{
+ printf(", now %s\n", flag ? "ON" : "OFF" );
+}