Goto: [ Program Documentation ]
// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: 22 Nov 1998 // Last Modified: Sun Jan 10 00:05:07 PST 1999 // Last Modified: Mon Jun 28 15:22:08 PDT 1999 (added sysex display capability) // Last Modified: Fri Jul 2 18:10:43 PDT 1999 (added keyboard commands) // Last Modified: Fri Nov 2 14:07:19 PST 2001 (added midi.open() before while) // Last Modified: Sun Nov 20 02:09:20 PST 2005 (added cpu speed display) // Filename: ...sig/doc/examples/improv/improv/cinmidi.cpp // Syntax: C++; improv 2.2 // #include "improv.h" #include <ctype.h> #include <string.h> // Here is the syntax of a header comment: #define HEADER_START ";; " // abbreviated general MIDI instrument names for the patch change // interpretation display. General MIDI instruments are standardized // by the numbers 0-127. If your instruments are not General MIDI, or // you are using a instrument bank other than bank 0, then the names // do not have any meaning. These names are modified from the source: // ftp://ftp.linpeople.org/pub/People/nathan/playmidi-2.4.tar.gz // const char *GMinstrument[128] = { "acpiano", "britepno", "synpiano", "honkytonk", "epiano1", "epiano2", "hrpschrd", "clavinet", "celeste", "glocken", "musicbox", "vibes", "marimba", "xylophon", "tubebell", "santur", "homeorg", "percorg", "rockorg", "churchorg", "reedorg", "accordn", "harmonica", "concrtna", "nyguitar", "acguitar", "jazzgtr", "cleangtr", "mutegtr", "odguitar", "distgtr", "gtrharm", "acbass", "fngrbass", "pickbass", "fretless", "slapbas1", "slapbas2", "synbass1", "synbass2", "violin", "viola", "cello", "contraba", "marcato", "pizzcato", "harp", "timpani", "marcato", "slowstr", "synstr1", "synstr2", "choir", "doo", "voices", "orchhit", "trumpet", "trombone", "tuba", "mutetrum", "frenchorn", "hitbrass", "synbras1", "synbras2", "sprnosax", "altosax", "tenorsax", "barisax", "oboe", "englhorn", "bassoon", "clarinet", "piccolo", "flute", "recorder", "woodflut", "bottle", "shakazul", "whistle", "ocarina", "sqrwave", "sawwave", "calliope", "chiflead", "charang", "voxlead", "lead5th", "basslead", "fantasia", "warmpad", "polysyn", "ghostie", "bowglass", "metalpad", "halopad", "sweeper", "aurora", "soundtrk", "crystal", "atmosphr", "freshair", "unicorn", "sweeper", "startrak", "sitar", "banjo", "shamisen", "koto", "kalimba", "bagpipes", "fiddle", "shannai", "carillon", "agogo", "steeldrum", "woodblock", "taiko", "toms", "syntom", "revcymb", "fx-fret", "fx-blow", "seashore", "jungle", "telephone", "helicptr", "applause", "ringwhsl" }; // global variables for command-line options: Options options; // for command-line processing int absoluteQ = 0; // for -a command-line option (time display) int interpretQ = 1; // for -i command-line option (interpret input) int bytesQ = 1; // no longer used, set to 1 int style = 0; // for -d, -x, and -2 command-line options int secondsQ = 0; // for -s command-line option int keyboardQ = 1; // for -k command-line option int activeSensingQ = 1; // for -A command-line option int fileQ = 0; // for -o command-line option int suppressOffQ = 0; // for -n command-line option int filter[8] = {0}; // for -f command-line option int cfilter[16] = {0}; // for -c command-line option fstream outputfile; // for -o command-line option #define MAX_KEY_BUFF (1024) char inputBuffer[MAX_KEY_BUFF+1] = {0}; // for keyboard input buffer int bufferIndex = 0; // for keyboard input buffer // function declarations void checkOptions(Options& opts); void displayMessage(ostream& out, MidiMessage message, int style); void displayHeader(ostream& out); void examineInputForCommand(const char* inputBuffer); void example(void); const char* getGmInst(int number); char* getKey(int keynum); void interpret(ostream& out, MidiMessage message); void interpretSysex(ostream& out, MidiMessage message); float makePitchBend(int lsb, int msb); void printbyte(ostream& out, int value, int location, int style); void usage(const char* command); void userCommandSend(const char* arguments); MidiIO midi; // MIDI I/O interface SigTimer sigtimer; // timing control /////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { options.setOptions(argc, argv); checkOptions(options); displayHeader(cout); if (fileQ) { displayHeader(outputfile); } KeyboardInput keyboard; // for typing comments into output file char keych; // character from keyboard MidiMessage message; int lastTime = -1; midi.open(); while (1) { while (midi.getCount() > 0) { message = midi.extract(); // filter any specified message types if (suppressOffQ && ((message.p0() & 0xf0) == 0x90) && (message.p2() == 0)) { continue; } else if (filter[(message.p0() >> 4) - 8]) { continue; } else if (cfilter[message.p0() & 0x0f]) { continue; } // adjust message time to delta time if necessary if (!absoluteQ) { if (lastTime == -1) { lastTime = message.time; message.time = 0; } else { int temp = message.time; message.time = message.time - lastTime; lastTime = temp; } } displayMessage(cout, message, style); if (fileQ) { displayMessage(outputfile, message, style); } } if (keyboardQ && keyboard.hit()) { keych = keyboard.getch(); switch (keych) { case 27: // escape key if (fileQ && bufferIndex != 0 && bufferIndex < MAX_KEY_BUFF) { inputBuffer[bufferIndex] = '\0'; outputfile << inputBuffer; } keyboard.deinitialize(); exit(0); break; case 0x08: // backspace key case 0x7f: // delete key if (bufferIndex > 0) { cout << "\b \b" << flush; bufferIndex--; } break; case 0x0a: // enter key only #ifdef VISUAL break; #endif case 13: // line feed cout << endl; if (bufferIndex < MAX_KEY_BUFF) { inputBuffer[bufferIndex] = '\0'; if (fileQ) { outputfile << inputBuffer << '\n'; } examineInputForCommand(inputBuffer); } bufferIndex = 0; break; case 0x0c: // ^L key (redraw input) cout << endl; if (bufferIndex < MAX_KEY_BUFF) { inputBuffer[bufferIndex] = '\0'; cout << inputBuffer << flush; } break; default: // normal key cout << keych << flush; if (bufferIndex < MAX_KEY_BUFF) { inputBuffer[bufferIndex++] = keych; } else { // buffer is WAY to long: kill it bufferIndex = 0; } } } millisleep(1); // sleep for 1 millisec for multi-tasking courtesy } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // checkOptions -- process the command-line options // void checkOptions(Options& opts) { opts.define("a|absolute=b"); // boolean for absoute time display opts.define("i|interpret=b"); // boolean for interpreting messages opts.define("p|port|inport=i:0"); // MIDI input port selection opts.define("t|outport=i:0"); // MIDI output port selection opts.define("l|list=b"); // boolean for displaying possible inputs opts.define("d|dec|decimal=b"); // boolean for printing bytes as decimal opts.define("x|hex|hexadecimal=b"); // boolean for printing bytes as hex opts.define("2|bin|binary=b"); // boolean for printing bytes as binary opts.define("o|output=s"); // for duplicating stdout to file opts.define("n|nooffs=b"); // boolean for suppressing note-offs opts.define("f|filter=s:"); // for filtering out various commands opts.define("c|chan-filter=s:"); // for filtering out various channels opts.define("u|user=s"); // for displaying in header info opts.define("s|seconds=b"); // for displaying time info in seconds opts.define("k|keyboard=b"); // for handling computer keyboard opts.define("A|no-active-sensing=b");// for displaying active sensing 0xfe opts.define("cpu=d:0.0"); // for setting the CPU speed opts.define("author=b"); opts.define("version=b"); opts.define("example=b"); opts.define("h|help=b"); opts.process(); if (opts.getBoolean("author")) { cout << "Written by Craig Stuart Sapp, " "craig@ccrma.stanford.edu, November 1998" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << "cinmidi, version 1.2 (2 Jul 1999)\n" "compiled: " << __DATE__ << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } if (opts.getBoolean("cpu")) { sigtimer.setCpuSpeed((int64bits)(opts.getDouble("cpu") * 1000000.0)); } if (opts.getBoolean("list")) { // display the possible MIDI inputs to use with -p option cout << "\nMidi Input ports: " << MidiInput::getNumPorts() << endl; for (int i=0; i<MidiInput::getNumPorts(); i++) { cout << "\t" << i << ": " << MidiInput::getName(i) << '\n'; } cout << endl; exit(0); } if (opts.getBoolean("absolute")) { absoluteQ = 1; } if (opts.getBoolean("interpret")) { interpretQ = 0; } if (opts.getBoolean("decimal")) { style = 10; } else if (opts.getBoolean("hexadecimal")) { style = 16; } else if (opts.getBoolean("binary")) { style = 2; } else { style = 0; } if (style != 0) { bytesQ = 1; } if (opts.getBoolean("nooffs")) { suppressOffQ = 1; } if (opts.getBoolean("seconds")) { secondsQ = 1; } if (opts.getBoolean("keyboard")) { keyboardQ = 0; } const char *filterString = opts.getString("filter"); char current; for (int i=0; i<(int)strlen(filterString); i++) { current = filterString[i]; switch (tolower(current)) { case '8': filter[0] = 1; break; case '9': filter[1] = 1; break; default: if (!isdigit(current) && isxdigit(current)) { if (current-'a'+2 >= 8 || current-'a'+2 < 0) { cerr << "Error in filter string" << endl; exit(1); } else { filter[current - 'a' + 2] = 1; } } } } const char *cfilterString = opts.getString("chan-filter"); char stringc [2] = {0}; int cindex; for (int j=0; j<(int)strlen(cfilterString); j++) { if (isxdigit(cfilterString[j])) { stringc[0] = cfilterString[j]; cindex = strtol(stringc, NULL, 16); if (cindex < 0 || cindex > 15) { cout << "Error in channel string: " << cfilterString << endl; exit(1); } else { cfilter[cindex] = 1; } } } if (opts.getBoolean("output")) { fileQ = 1; outputfile.open(opts.getString("output"), ios::out); if (!outputfile.is_open()) { cout << "Error: cannot open file: "<< opts.getString("output") << endl; exit(1); } } midi.setInputPort(opts.getInteger("inport")); midi.setOutputPort(opts.getInteger("outport")); midi.openInput(); midi.openOutput(); if (opts.getArgCount() != 0) { usage(opts.getCommand()); exit(1); } activeSensingQ = !opts.getBoolean("no-active-sensing"); } ////////////////////////////// // // displayHeader -- display data formatting information // void displayHeader(ostream& out) { out << HEADER_START << "\n"; if (options.getBoolean("user")) { out << HEADER_START << "Recorded by: "; out << options.getString("user") << endl; } out << HEADER_START << "Style: "; switch (style) { case 10: out << "decimal\n"; break; case 16: out << "hexadecimal\n"; break; case 2: out << "binary\n"; break; default: out << "default\n"; } out << HEADER_START << "Timing: "; if (absoluteQ) { out << "absolute"; if (secondsQ) { out << " seconds\n"; } else { out << " milliseconds\n"; } out << HEADER_START << "Message format: received-time, command-byte," " parameter-byte(s)\n"; } else { out << "delta"; if (secondsQ) { out << " seconds\n"; } else { out << " milliseconds\n"; } out << HEADER_START << "Message format: delta-time, MIDI command-byte, " "MIDI parameter-byte(s)\n"; } out << HEADER_START << "Format: asciimidi 1.0\n"; out << HEADER_START << "Command-line: " << options.getCommandLine() << '\n'; out << HEADER_START << "Input Port: " << options.getInteger("inport") << ": " << MidiInput::getName(options.getInteger("inport")) << '\n'; out << HEADER_START << "Cpu Speed: " << (double)sigtimer.getCpuSpeed() / 1000000.0 << " MHz" << '\n'; out << HEADER_START << '\n'; out << endl; } ////////////////////////////// // // displayMessage -- displays the MIDI input message in the style // specified on the command-line // void displayMessage(ostream& out, MidiMessage message, int style) { if ((!activeSensingQ) && (message.p0() == 0xfe)) { // don't display incoming active-sensing messages return; } if (secondsQ) { out << dec << message.time / 1000.0 << "\t"; } else { out << dec << message.time << "\t"; } if (bytesQ) { printbyte(out, (int)message[0], 0, style); if (message.p0() == 0xf0) { int byteCount = midi.getSysexSize((int)message.p1()); uchar* sysexmessage = midi.getSysex((int)message.p1()); for (int k=1; k<byteCount-1; k++) { out << " "; printbyte(out, (int)sysexmessage[k], k, style); } out << " "; printbyte(out, (int)sysexmessage[byteCount-1], 0, style); } else { // not a system exclusive int parameterCount = message.getParameterCount(); for (int i=0; i<parameterCount; i++) { out << " "; printbyte(out, (int)message[i+1], i+1, style); } } } if (bytesQ && interpretQ && (style == 2)) { if (message.getParameterCount() <= 1) { out << '\t'; } out << "\t ; "; } else if (bytesQ && interpretQ) { if (message.getParameterCount() <= 1) { out << '\t'; } out << "\t\t; "; } if (interpretQ) { interpret(out, message); } out << endl; } ////////////////////////////// // // examineInputForCommand -- Look for a command embedded in user // computer keyboard input. // void examineInputForCommand(const char* string) { if (strncmp(HEADER_START, string, 3) != 0) { // not a possible command string return; } int length = strlen(string); int i; for (i=0; i<length+1; i++) { if (string[i] == ':') { goto command_found; } } return; // some commands are: // ";; Send: bytes = send these MIDI bytes on MIDI output // ";; Filter On: x or xx // ";; Filter Off: x or xx command_found: char* buffer = new char[length + 1]; char* arguments = new char[length + 1]; strcpy(buffer, string); char* command = strtok(buffer, ";: \t"); int j = 0; while (command[j] != '\0') { command[j] = tolower(command[j]); j++; } if (strcmp(command, "send") == 0) { strncpy(arguments, strtok(NULL, ""), length); userCommandSend(arguments); } delete [] buffer; delete [] arguments; } ////////////////////////////// // // example -- shows various command-line option calls to program. // void example(void) { cout << "# display MIDI input data in binary form:\n" "cinmidi -2\n" "\n" "# don't display note-off messages:\n" "cinmidi -n\n" "\n" "# don't display pitchbend data:\n" "cinmidi -fe\n" "\n" "# display only pitchbend data:\n" "cinmidi -f 89abcdf\n" "\n" "# display only note-on messages:\n" "cinmidi -n -f 8abcdef\n" "\n" << endl; } ////////////////////////////// // // getGmInst -- the General MIDI instrument name. // const char* getGmInst(int number) { return GMinstrument[number % 0x80]; } ////////////////////////////// // // getKey -- return the key name of the specified MIDI key number. // char* getKey(int keynum) { static char name[16] = {0}; static char temp[16] = {0}; int octave = keynum / 12 - 1; switch (keynum % 12) { case 0: strcpy(name, "C"); break; case 1: strcpy(name, "C#"); break; case 2: strcpy(name, "D"); break; case 3: strcpy(name, "Eb"); break; case 4: strcpy(name, "E"); break; case 5: strcpy(name, "F"); break; case 6: strcpy(name, "F#"); break; case 7: strcpy(name, "G"); break; case 8: strcpy(name, "Ab"); break; case 9: strcpy(name, "A"); break; case 10: strcpy(name, "Bb"); break; case 11: strcpy(name, "B"); break; default: strcpy(name, ""); } sprintf(temp, "%d", octave); strcat(name, temp); return name; } ////////////////////////////// // // interpret -- convert a MIDI message to English. // void interpret(ostream& out, MidiMessage message) { out << dec; // set output to decimal notation switch (message.p0() & 0xf0) { case 0x80: // NOTE OFF out << "NOTEOFF chan: " << (int)(message.p0() & 0x0f) + 1 << " key:" << getKey(message.p1()) << " vel: " << (int)message.p2(); break; case 0x90: // NOTE ON out << "NOTE chan:" << (int)(message.p0() & 0x0f) + 1 << " key:" << getKey(message.p1()) << " vel:" << (int)message.p2(); if (message.p2() == 0) { out << " OFF"; } break; case 0xa0: // AFTERTOUCH out << "AFTERTOUCH chan:" << (int)(message.p0() & 0x0f) + 1 << " key:" << getKey(message.p1()) << " val:" << (int)message.p2(); break; case 0xb0: out << "CONTROL chan:" << (int)(message.p0() & 0x0f) + 1 << " #:" << (int)message.p1() << " val:" << (int)message.p2(); switch (message.p1()) { case 7: out << " (volume)"; break; case 64: out << " (sustain)"; break; } break; case 0xc0: // PATCH CHANGE out << "PATCH chan:" << (int)(message.p0() & 0x0f) + 1 << " inst:" << (int)message.p1() << " (" << getGmInst(message.p1()) << ")"; break; case 0xd0: // CHANNEL PRESSURE out << "PRESSURE chan:" << (int)(message.p0() & 0x0f) + 1 << " val:" << (int)message.p1(); break; case 0xe0: // PITCH BEND out << "PITCHBEND chan:" << (int)(message.p0() & 0x0f) + 1 << " val:" << makePitchBend(message.p1(), message.p2()); break; case 0xf0: switch (message.p0()) { // system common messages case 0xf0: out << "SYSEX"; interpretSysex(out, message); break; case 0xf1: out << "MIDI Time Code Quarter Frame"; break; case 0xf2: out << "Song Position Pointer"; break; case 0xf3: out << "Song Select"; break; case 0xf4: out << "Undefined sys com msg"; break; case 0xf5: out << "Undefined sys com msg"; break; case 0xf6: out << "Tune Request"; break; // system real time messages case 0xf8: out << "Timing Clock"; break; case 0xf9: out << "Undefined sys realtime msg"; break; case 0xfa: out << "Start"; break; case 0xfb: out << "Continue"; break; case 0xfc: out << "Stop"; break; case 0xfd: out << "Undefined"; break; case 0xfe: out << "Active Sensing"; break; case 0xff: out << "System Reset"; break; } break; } } ////////////////////////////// // // interpretSysex -- try to identify the system exclusive message // void interpretSysex(ostream& out, MidiMessage message) { if (message.p0() != 0xf0) { cout << "Error: interpretSysex needed a sysex message" " but got: " << hex << (int)message.p0() << dec << endl; exit(1); } uchar* sysex = midi.getSysex(message.p1()); int length = midi.getSysexSize(message.p1()); // check for Currently defined Universal System Exclusive Messages // first the non-real time messages where sysex[1] == 0x7e if (length >= 5 && sysex[1] == 0x7e) { out << ": UNIV"; if (sysex[3] == 0x01) { out << ": Sample Dump Header"; return; } else if (sysex[3] == 0x02) { out << ": Sample Data Packet"; return; } else if (sysex[3] == 0x03) { out << ": Sample Dump Request"; return; } else if (sysex[3] == 0x04) { out << ": MIDI Time Code"; switch (sysex[4]) { case 0x00: out << ": Special"; break; case 0x01: out << ": Punch In Points"; break; case 0x02: out << ": Punch Out Points"; break; case 0x03: out << ": Delete Punch In Point"; break; case 0x04: out << ": Delete Punch Out Point"; break; case 0x05: out << ": Event Start Point"; break; case 0x06: out << ": Event Stop Point"; break; case 0x07: out << ": Event Start Points + add. info"; break; case 0x08: out << ": Event Stop Points + add. info"; break; case 0x09: out << ": Delete Event Start Point"; break; case 0x0a: out << ": Delete Event Stop Point"; break; case 0x0b: out << ": Cue Points"; break; case 0x0c: out << ": Cue Points with add. info"; break; case 0x0d: out << ": Delete Cue Point"; break; case 0x0e: out << ": Event Name in add. info"; break; } return; } else if (sysex[3] == 0x05) { out << ": Sample Dump Extensions"; switch (sysex[4]) { case 0x01: out << ": Multiple Loop Points"; break; case 0x02: out << ": Loop Points Request"; break; } return; } else if (sysex[3] == 0x06) { out << ": General Information"; switch (sysex[4]) { case 0x01: out << ": Identity Request"; break; case 0x02: out << ": Identity Reply"; break; } return; } else if (sysex[3] == 0x07) { out << ": File Dump"; switch (sysex[4]) { case 0x01: out << ": Header"; break; case 0x02: out << ": Data Packet"; break; case 0x03: out << ": Request"; break; } return; } else if (sysex[3] == 0x08) { out << ": MIDI Tuning Standard"; switch (sysex[4]) { case 0x01: out << ": Bulk Dump Request"; break; case 0x02: out << ": Bulk Dump Reply"; break; } return; } else if (sysex[3] == 0x09) { out << ": General MIDI"; switch (sysex[4]) { case 0x01: out << ": On"; break; case 0x02: out << ": Off"; break; } return; } else if (sysex[3] == 0x7b) { out << ": End Of File"; return; } else if (sysex[3] == 0x7c) { out << ": Wait"; return; } else if (sysex[3] == 0x7d) { out << ": Cancel"; return; } else if (sysex[3] == 0x7e) { out << ": NAK (bad transfer)"; return; } else if (sysex[3] == 0x7f) { out << ": ACK (good transfer)"; return; } } // check for Currently defined Universal System Exclusive Messages // now the non-real time messages where sysex[1] == 0x7f if (length >= 5 && sysex[1] == 0x7f) { out << ": UNIV"; if (sysex[3] == 0x01) { out << ": MIDI Time Code"; switch (sysex[4]) { case 0x01: out << ": Full Message"; break; case 0x02: out << ": User Bits"; break; } return; } else if (sysex[3] == 0x02) { out << ": MIDI Show Control"; switch (sysex[4]) { case 0x00: out << ": Extensions"; break; default: out << ": Commands"; break; } return; } else if (sysex[3] == 0x03) { out << ": Notation Info"; switch (sysex[4]) { case 0x01: out << ": Bar Number"; break; case 0x02: out << ": Time Sig. (Immediate)"; break; case 0x42: out << ": Time Sig. (Delayed)"; break; } return; } else if (sysex[3] == 0x04) { out << ": Device Control"; switch (sysex[4]) { case 0x01: out << ": Master Volume"; break; case 0x02: out << ": Master Balance"; break; } return; } else if (sysex[3] == 0x05) { out << ": Real Time MTC Cueing"; switch (sysex[4]) { case 0x00: out << ": Special"; break; case 0x01: out << ": Punch In Points"; break; case 0x02: out << ": Punch Out Points"; break; case 0x03: out << ": Reserved"; break; case 0x04: out << ": Reserved"; break; case 0x05: out << ": Event Start Points"; break; case 0x06: out << ": Event Stop Points"; break; case 0x07: out << ": Event Start Points + add. info"; break; case 0x08: out << ": Event Stop Points + add. info"; break; case 0x09: out << ": Reserved"; break; case 0x0a: out << ": Reserved"; break; case 0x0b: out << ": Cue Points"; break; case 0x0c: out << ": Cue Points with add. info"; break; case 0x0d: out << ": Reserved"; break; case 0x0e: out << ": Event Name in add. info"; break; } return; } else if (sysex[3] == 0x06) { out << ": MIDI Maching Control Commands"; return; } else if (sysex[3] == 0x07) { out << ": MIDI Maching Control Response"; return; } else if (sysex[3] == 0x08) { out << ": MIDI Tuning Standard"; switch (sysex[4]) { case 0x02: out << ": Note Change"; } return; } } // If gotten to this point, the sysex starts with a // manufacturer's ID number. if (sysex[1] == 0x7f) { out << ": MANF=non-commercial"; return; } if (sysex[1] >= 0x01 && sysex[1] <= 0x1f) { out << ": MANF=American1"; return; } if (sysex[1] >= 0x20 && sysex[1] <= 0x3f) { out << ": MANF=European1"; return; } if (sysex[1] >= 0x40 && sysex[1] <= 0x5f) { out << ": MANF=Japanese1"; return; } if (sysex[1] >= 0x60 && sysex[1] <= 0x7c) { out << ": MANF=other1"; return; } // must be a three byte sysex if get here if (sysex[1] == 0) { if (sysex[2] >= 0x20 && sysex[2] <= 0x3f) { out << ": MANF=European3"; return; } if (sysex[2] >= 0x40 && sysex[2] <= 0x5f) { out << ": MANF=Japanese3"; return; } if (sysex[2] >= 0x60 && sysex[2] <= 0x7F) { out << ": MANF=Other3"; return; } else { out << ": MANF=American3"; return; } } } ////////////////////////////// // // makePitchBend -- create a number in range -1 to 1. // float makePitchBend(int lsb, int msb) { int value = (msb << 7) | lsb; float output = (float)((2.0 * value / 0x3fff) - 1.0); if ((output < 0.0001) && (output > -0.0001)) { return 0.0; } else { output = (float)(((int)(output * 1000.0))/1000.0); return output; } } ////////////////////////////// // // printbyte -- display a byte according to specified style and location. // void printbyte(ostream& out, int value, int location, int style) { int i; switch (style) { case 10: if (value < 100) { out << ' '; } if (value < 10) { out << ' '; } out << dec << value; break; case 16: if (value < 0x10) { out << ' '; } out << hex << value; break; case 2: for (i=0; i<8; i++) { if (value & (1 << (7-i))) { out << '1'; } else { out << '0'; } } break; default: if (location == 0) { out << "0x"; printbyte(out, value, 0, 16); } else { printbyte(out, value, location, 10); } } } ////////////////////////////// // // usage -- how to run this program from the command-line. // void usage(const char* command) { cout << "\n" "Display/Record MIDI input data.\n" "\n" "Usage: " << command << " [-a][-i][-x|-d|-2] [-o output][-p port]\n" "\n" "Options:\n" " -a = display MIDI timing in absolute time instead of delta time\n" " -i = don't display interpretation of MIDI message as comments\n" " -d = display MIDI bytes in decimal form\n" " -x = display MIDI bytes in hexadecimal form\n" " -2 = display MIDI bytes in binary form\n" " -n = do not display note-off messages\n" " -f string = filter out specified MIDI commands (e.g. \"bc\" will\n" " filter out control change and patch change messages)\n" " -c string = filter out specified MIDI channels, offset zero\n" " (e.g., \"09AF\", filters channels 1, 10, 11, and 16)\n" " -p port = use the specified MIDI input port\n" " -l = list MIDI input ports and then exit\n" " -o filename = send display to file as well as to screen\n" " -u string = specify a user name for the header information\n" " -s = display time values in seconds\n" " -k = disable keyboard input\n" " -A = don't display incoming active-sensing messages\n" " --options = list all options, default values, and aliases\n" "\n" << endl; } ////////////////////////////// // // userCommandSend -- send some midi data out the MIDI out port. // currently only allows decimal data. // void userCommandSend(const char* midibytes) { char* buffer = new char[strlen(midibytes)+1]; strcpy(buffer, midibytes); Array<uchar> midiinfo(0); uchar inputdata; char* data = strtok(buffer, " \t"); int number; while (data != NULL && isdigit(data[0])) { sscanf(data, "%d", &number); inputdata = (uchar)number; midiinfo.append(inputdata); data = strtok(NULL, " \t"); } midi.rawsend(midiinfo.getBase(), midiinfo.getSize()); } // md5sum: d16ae16ba1368adc6c0f112b54b7ae86 cinmidi.cpp [20130206]