diff options
Diffstat (limited to '3rdparty/portmidi/pm_test/mm.c')
-rw-r--r-- | 3rdparty/portmidi/pm_test/mm.c | 572 |
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" ); +} |