// // Programmer: Craig Stuart Sapp // Creation Date: Sat Mar 10 11:55:09 PST 2001 // Last Modified: Thu Jan 31 18:12:02 PST 2002 (minor adjustments, improve key) // Filename: ...sig/doc/examples/sig/sigControl/kernin.cpp // Syntax: C++; improv 2.2 // #include "improv.h" #include "Convert.h" #include "LineDisplay.h" #include #include #include // command-line options variables: Options options; // for command-line processing const char* filename = NULL; // file name to write data to fstream outfile; // for writing output data int transpose = 0; // -t option for transposition // MIDI keyboard variables: MidiIO midi; // MIDI I/O interface int keystates[128] = {0}; // 0 = note off, 1 = note on int keydurations[128] = {0}; // duration from last note state int keyaction[128] = {0}; // time the note was turned on/off int keylastaction[128] = {0}; // last time the note was turned on/off double stepDur = 1.0; // step record duration double currDur = 1.0; // duration of the current note int octave = 0; // octave adjustment int controlOctave = -1; // placement of the control octave int keyoncount = 0; // number of data keys being pressed int chordkeys[128] = {0}; // for displaying chord keys int currentKey = 0; // Computer keyboard variables: KeyboardInput keyboard; // computer keyboard I/O interface CircularBuffer attackkeys; // for control key attack numbers CircularBuffer attacktimes; // for control key attack times CircularBuffer durations; // for control key attack times CircularBuffer iois; // for inter-onset time intervals Array actiontimes; // when note was last turned on/off double speed = 70.0; // shift keys Morse speed int interpreted = 0; // for interpreting shift keys // screen display variables: LineDisplay display; // screen display object char displayBuffer[1024] = {0}; // display buffer int displayIndex = 0; // how many characters are being displayed int initData = 0; // for adding **kern/*- symbols to the data double meterduration = 0; // for auto display of measure lines double maxmeterduration = 4.0; // for auto display of measure lines int measurenumber = 1; // for display of measure number // function declarations void checkOptions (Options& opts); void example (void); void usage (const char* command); void processComputerKeyboardInput (void); void processMidiKeyboardInput (void); void processNoteKey (int key, int vel, int mtime); void processControlKey (int key, int vel, int mtime); int generateCommand (int key, int vel, int mtime); void statusMessage (const char* string); void storeCommandEvent (int key, int vel, int mtime); char interpretShiftEvent (void); char convertShiftEvent (const char* string); int generateShiftCommand (int shiftkey, int event, int controlkey, int vel); void executeCommand (int command, int p1 = 0); void checkInitialization (void); int convertMIDIToBase40 (int note, int key = 0); // Command enumerations: #define C_IGNORE -1 #define C_UNKNOWN 0 #define C_SETINCREMENTWHOLENOTE 1 #define C_SETINCREMENTHALFNOTE 2 #define C_SETINCREMENTQUARTERNOTE 3 #define C_SETINCREMENTEIGHTHNOTE 4 #define C_SETINCREMENTSIXTEENTHNOTE 5 #define C_SETINCREMENT32NDNOTE 6 #define C_KEYSIGCMAJOR 7 #define C_KEYSIGFMAJOR 8 #define C_KEYSIGBFLATMAJOR 9 #define C_KEYSIGEFLATMAJOR 10 #define C_KEYSIGAFLATMAJOR 11 #define C_KEYSIGDFLATMAJOR 12 #define C_KEYSIGGFLATMAJOR 13 #define C_KEYSIGCFLATMAJOR 14 #define C_KEYSIGGMAJOR 15 #define C_KEYSIGDMAJOR 16 #define C_KEYSIGAMAJOR 17 #define C_KEYSIGEMAJOR 18 #define C_KEYSIGBMAJOR 19 #define C_KEYSIGFSHARPMAJOR 20 #define C_KEYSIGCSHARPMAJOR 21 #define C_WRITEMEASURE 22 #define C_REDISPLAYCURRENTNOTES 23 #define C_UPDATECURRENTDURATION 24 #define C_DISPLAYNEWNOTE 25 #define C_WRITEORPARSECURRNETLINE 26 #define C_WRITEREST 27 #define C_ENHARMONIC 28 #define C_ENHARMONICDOUBLEFLAT 29 #define C_ENHARMONICDOUBLESHARP 30 // MIDI keyboard defines: // rhythm: #define K_SETINCREMENTWHOLENOTE 0 #define K_SETINCREMENTHALFNOTE 2 #define K_SETINCREMENTQUARTERNOTE 4 #define K_SETINCREMENTEIGHTHNOTE 5 #define K_SETINCREMENTSIXTEENTHNOTE 7 #define K_SETINCREMENT32NDNOTE 9 #define K_REST 11 #define K_MEASURE 12 #define K_ENHARMONIC 1 // numbers #define K_NUMBER0 8 #define K_NUMBER1 0 #define K_NUMBER2 2 #define K_NUMBER3 4 #define K_NUMBER4 5 #define K_NUMBER5 7 #define K_NUMBER6 9 #define K_NUMBER7 11 #define K_NUMBER8 12 #define K_NUMBER9 10 // shift keys #define K_SHIFT1 3 #define K_SHIFT2 6 /////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { options.setOptions(argc, argv); checkOptions(options); attacktimes.setSize(1000); attackkeys.setSize(1000); durations.setSize(1000); iois.setSize(1000); attacktimes.reset(); attackkeys.reset(); durations.reset(); iois.reset(); actiontimes.setSize(128); actiontimes.zero(); actiontimes.allowGrowth(0); statusMessage(">>> Press ESC to finish data entry."); statusMessage(">>> Press a MIDI key to place the control Octave."); while (1) { while (midi.getCount() > 0) { processMidiKeyboardInput(); } if (keyboard.hit()) { processComputerKeyboardInput(); } millisleep(1); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // statusMessage -- display a status message, then redisplay the // contents of the data line; // void statusMessage(const char* string) { static char oldstring[1024] = {0}; strcpy(oldstring, display.getLine()); display.setLine(string); display.newline(); display.display(oldstring); } ////////////////////////////// // // echoMessage -- echo MIDI input to MIDI output // void echoMessage(MidiMessage message) { int count = message.getArgCount() + 1; unsigned char array[4]; array[0] = message.p0(); array[1] = message.p1(); array[2] = message.p2(); array[3] = message.p3(); midi.rawsend(array, count); } ////////////////////////////// // // processMidiKeyboardInput -- interpret messages from the MIDI // keyboard. // void processMidiKeyboardInput(void) { MidiMessage message = midi.extract(); int key = 0; int vel = 0; if ((message.p0() & 0xf0) == 0x90 || (message.p0() & 0xf0) == 0x80) { key = message.p1(); vel = message.p2(); if ((message.p0() & 0xf0) == 0x80) { vel = 0; } } else { echoMessage(message); return; } // set the control octave if it is not yet set if (vel != 0 && controlOctave < 0) { return; } if (vel == 0 && controlOctave < 0) { controlOctave = key / 12; cout << ">>> Control octave set to " << controlOctave << endl; return; } // determine if the key is in the control octave or not int control = 0; if (key >= controlOctave * 12 && key <= controlOctave * 12 + 12) { control = 1; } else { control = 0; } if (control) { processControlKey(key, vel, message.time); } else { if (vel == 0) { keystates[key] = 0; keyoncount--; if (keyoncount < 0) { keyoncount = 0; } } else { keystates[key] = 1; keyoncount++; } echoMessage(message); processNoteKey(key, vel, message.time); } } ////////////////////////////// // // processNoteKey -- handle a data entry note message // void processNoteKey(int key, int vel, int mtime) { int i; if (vel == 0 && keyoncount == 0) { for (i=0; i<128; i++) { chordkeys[i] = 0; } } if (keyoncount != 0) { chordkeys[key] = 1; } checkInitialization(); keylastaction[key] = keyaction[key]; keyaction[key] = mtime; keydurations[key] = keyaction[key] - keylastaction[key]; if (keyoncount == 1 && vel != 0) { executeCommand(C_DISPLAYNEWNOTE, key); } else if (keyoncount > 1 && vel != 0) { executeCommand(C_REDISPLAYCURRENTNOTES); } currDur = stepDur; } ////////////////////////////// // // processControlKey -- // void processControlKey(int key, int vel, int mtime) { storeCommandEvent(key, vel, mtime); int command = generateCommand(key, vel, mtime); executeCommand(command); } ////////////////////////////// // // executeCommand -- // void executeCommand(int command, int p1) { switch(command) { case C_SETINCREMENTWHOLENOTE: statusMessage(">>> Setting step duration to whole note"); stepDur = 4.0; if (keyoncount == 0) { currDur = stepDur; } break; case C_SETINCREMENTHALFNOTE: statusMessage(">>> Setting step duration to half note"); stepDur = 2.0; if (keyoncount == 0) { currDur = stepDur; } break; case C_SETINCREMENTQUARTERNOTE: statusMessage(">>> Setting step duration to quarter note"); stepDur = 1.0; if (keyoncount == 0) { currDur = stepDur; } break; case C_SETINCREMENTEIGHTHNOTE: statusMessage(">>> Setting step duration to eighth note"); stepDur = 0.5; if (keyoncount == 0) { currDur = stepDur; } break; case C_SETINCREMENTSIXTEENTHNOTE: statusMessage(">>> Setting step duration to sixteenth note"); stepDur = 0.25; if (keyoncount == 0) { currDur = stepDur; } break; case C_SETINCREMENT32NDNOTE: statusMessage(">>> Setting step duration to 32nd note"); stepDur = 0.125; if (keyoncount == 0) { currDur = stepDur; } break; case C_UNKNOWN: statusMessage(">>> Unknown command"); break; case C_WRITEMEASURE: if (strncmp(display.getLine(), "!", 1) == 0 || strncmp(display.getLine(), "*", 1) == 0) { display.display("="); } else { if (strcmp(display.getLine(), "") != 0) { executeCommand(C_WRITEORPARSECURRNETLINE); display.display("="); } } break; case C_KEYSIGCMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[]"); currentKey = 0; break; case C_KEYSIGFMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-]"); currentKey = -1; break; case C_KEYSIGBFLATMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-e-]"); currentKey = -2; break; case C_KEYSIGEFLATMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-e-a-]"); currentKey = -3; break; case C_KEYSIGAFLATMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-e-a-d-]"); currentKey = -4; break; case C_KEYSIGDFLATMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-e-a-d-g-]"); currentKey = -5; break; case C_KEYSIGGFLATMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-e-a-d-g-c-]"); currentKey = -6; break; case C_KEYSIGCFLATMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[b-e-a-d-g-c-f-]"); currentKey = -7; break; case C_KEYSIGGMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#]"); currentKey = +1; break; case C_KEYSIGDMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#c#]"); currentKey = +2; break; case C_KEYSIGAMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#c#g#]"); currentKey = +3; break; case C_KEYSIGEMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#c#g#d#]"); currentKey = +4; break; case C_KEYSIGBMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#c#g#d#a#]"); currentKey = +5; break; case C_KEYSIGFSHARPMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#c#g#d#a#e#]"); currentKey = +6; break; case C_KEYSIGCSHARPMAJOR: checkInitialization(); executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*k[f#c#g#d#a#e#b#]"); currentKey = +7; break; case C_UPDATECURRENTDURATION: // add current step increment to current duration and redisplay currDur += stepDur; meterduration += stepDur; executeCommand(C_REDISPLAYCURRENTNOTES); break; case C_REDISPLAYCURRENTNOTES: { static char buffer1[1024] = {0}; display.eraseline(); int count = 0; for (int i=0; i<128; i++) { if (chordkeys[i] != 0) { if (count != 0) { display.display(" "); } display.display(Convert::durationToKernRhythm(buffer1, currDur)); display.display(Convert::base12ToKern(buffer1, i)); count++; } } } break; case C_WRITEREST: { static char buffer1[1024] = {0}; if (strcmp("", display.getLine()) != 0) { executeCommand(C_WRITEORPARSECURRNETLINE); meterduration += currDur; if (fabs(meterduration - maxmeterduration) < 0.01) { // cout << "Meter duration: " << meterduration // << "\tmaxmeterdur: " << maxmeterduration << endl; display.display("="); measurenumber++; // statically fixed for now sprintf(buffer1, "%d", measurenumber); display.display(buffer1); executeCommand(C_WRITEORPARSECURRNETLINE); meterduration = 0.0; } else if (meterduration - maxmeterduration > 0) { display.display("="); measurenumber++; // statically fixed for now sprintf(buffer1, "%d", measurenumber); display.display(buffer1); executeCommand(C_WRITEORPARSECURRNETLINE); meterduration -= maxmeterduration; } } display.display(Convert::durationToKernRhythm(buffer1, currDur)); display.display("r"); } break; case C_DISPLAYNEWNOTE: { static char buffer1[1024] = {0}; if (strcmp("", display.getLine()) != 0) { executeCommand(C_WRITEORPARSECURRNETLINE); meterduration += currDur; if (fabs(meterduration - maxmeterduration) < 0.01) { // cout << "Meter duration: " << meterduration // << "\tmaxmeterdur: " << maxmeterduration << endl; display.display("="); measurenumber++; // statically fixed for now sprintf(buffer1, "%d", measurenumber); display.display(buffer1); executeCommand(C_WRITEORPARSECURRNETLINE); meterduration = 0.0; } else if (meterduration - maxmeterduration > 0) { display.display("="); measurenumber++; // statically fixed for now sprintf(buffer1, "%d", measurenumber); display.display(buffer1); executeCommand(C_WRITEORPARSECURRNETLINE); meterduration -= maxmeterduration; } } display.display(Convert::durationToKernRhythm(buffer1, currDur)); p1 = convertMIDIToBase40(p1 + transpose, currentKey); display.display(Convert::base40ToKern(buffer1, p1)); } break; case C_WRITEORPARSECURRNETLINE: { static char buffer1[1024] = {0}; strncpy(buffer1, display.getLine(), 512); if (strcmp(buffer1, "") == 0) { // ignore line update if a blank line return; } // check for a meter signature if (strncmp(buffer1, "*M", 2) == 0 && isdigit(buffer1[2])) { int top = 0; int bottom=0; sscanf(buffer1, "*M%d/%d", &top, &bottom); maxmeterduration = top * 4.0/bottom; statusMessage(">>> Meter signature read"); } // check for a measure line if (strncmp(buffer1, "=", 1) == 0 && isdigit(buffer1[1])) { int mno = 0; sscanf(buffer1, "=%d", &mno); if (measurenumber != mno) { measurenumber = mno; statusMessage(">>> Changing measure numbering"); } meterduration = 0.0; } if (strncmp(">>>", display.getLine(), 3) != 0) { // don't save command directives from the user outfile << "\n" << display.getLine(); } else { double newbeat = 0.0; if (sscanf(display.getLine(), ">> beat %lf", &newbeat)) { stepDur = 4.0/newbeat; currDur = stepDur; statusMessage(">>> Beat increment set"); } else if (sscanf(display.getLine(), ">>> beat %lf", &newbeat)) { stepDur = 4.0/newbeat; currDur = stepDur; statusMessage(">>> Beat increment set"); } } display.newline(); } default: break; } } /////////////////////////////// // // checkInitialization -- // void checkInitialization(void) { if (initData == 0) { if (strcmp("", display.getLine()) == 0) { display.display("**kern"); outfile << "!! data"; } else { executeCommand(C_WRITEORPARSECURRNETLINE); display.display("**kern"); } initData =1; } } ////////////////////////////// // // checkForShiftKey -- determines if a shift key has been pressed // int checkForShiftKey(void) { if (attackkeys[0] != K_SHIFT1 && attackkeys[1] == K_SHIFT1) { return 1; } if (attackkeys[0] != K_SHIFT2 && attackkeys[1] == K_SHIFT2) { return 2; } return 0; } ////////////////////////////// // // generateCommand -- figure out what command to do. // int generateCommand(int key, int vel, int mtime) { if (vel == 0) { return C_IGNORE; } int controlkey = key - controlOctave * 12; int shiftkey = checkForShiftKey(); if (shiftkey) { return generateShiftCommand(shiftkey, interpretShiftEvent(), controlkey, vel); } // process update to the durations of current notes if (vel > 0 && keyoncount > 0) { return C_UPDATECURRENTDURATION; } // process changes in the step duration if (vel > 0) { switch (controlkey) { case K_SETINCREMENTWHOLENOTE: return C_SETINCREMENTWHOLENOTE; break; case K_SETINCREMENTHALFNOTE: return C_SETINCREMENTHALFNOTE; break; case K_SETINCREMENTQUARTERNOTE: return C_SETINCREMENTQUARTERNOTE; break; case K_SETINCREMENTEIGHTHNOTE: return C_SETINCREMENTEIGHTHNOTE; break; case K_SETINCREMENTSIXTEENTHNOTE: return C_SETINCREMENTSIXTEENTHNOTE; break; case K_SETINCREMENT32NDNOTE: return C_SETINCREMENT32NDNOTE; break; case K_MEASURE: return C_WRITEMEASURE; break; case K_REST: return C_WRITEREST; break; default: return C_IGNORE; } } return C_IGNORE; } ////////////////////////////// // // generateShiftCommand -- // int generateShiftCommand(int shiftkey, int event, int controlkey, int vel) { if (event == 'K' && shiftkey == 1) { switch (controlkey) { case K_ENHARMONIC: return C_ENHARMONICDOUBLEFLAT; case K_NUMBER0: return C_KEYSIGCMAJOR; case K_NUMBER1: return C_KEYSIGFMAJOR; case K_NUMBER2: return C_KEYSIGBFLATMAJOR; case K_NUMBER3: return C_KEYSIGEFLATMAJOR; case K_NUMBER4: return C_KEYSIGAFLATMAJOR; case K_NUMBER5: return C_KEYSIGDFLATMAJOR; case K_NUMBER6: return C_KEYSIGGFLATMAJOR; case K_NUMBER7: return C_KEYSIGCFLATMAJOR; } } if (event == 'K' && shiftkey == 2) { switch (controlkey) { case K_ENHARMONIC: return C_ENHARMONICDOUBLESHARP; case K_NUMBER0: return C_KEYSIGCMAJOR; case K_NUMBER1: return C_KEYSIGGMAJOR; case K_NUMBER2: return C_KEYSIGDMAJOR; case K_NUMBER3: return C_KEYSIGAMAJOR; case K_NUMBER4: return C_KEYSIGEMAJOR; case K_NUMBER5: return C_KEYSIGBMAJOR; case K_NUMBER6: return C_KEYSIGFSHARPMAJOR; case K_NUMBER7: return C_KEYSIGCSHARPMAJOR; } } return C_UNKNOWN; } ////////////////////////////// // // processComputerKeyboardInput -- // void processComputerKeyboardInput(void) { int keych = keyboard.getch(); switch (keych) { case 27: // escape key if (initData == 1) { if (strcmp("", display.getLine()) != 0) { executeCommand(C_WRITEORPARSECURRNETLINE); display.display("*-"); executeCommand(C_WRITEORPARSECURRNETLINE); outfile << endl; } else { display.display("*-"); executeCommand(C_WRITEORPARSECURRNETLINE); outfile << endl; } outfile.close(); initData = 0; } keyboard.deinitialize(); exit(0); break; case 0x08: // backspace key case 0x7f: // delete key display.backspace(); break; case 0x0a: // enter key only executeCommand(C_WRITEORPARSECURRNETLINE); break; case 13: // line feed break; case 0x0c: // ^L key (redraw input) break; case '=': // measure line key (probably) executeCommand(C_WRITEMEASURE); meterduration = -currDur; break; default: // normal key { char tempbuffer[2] = {0}; tempbuffer[0] = (char)keych; display.display(tempbuffer); } } } ////////////////////////////// // // checkOptions -- process the command-line options // void checkOptions(Options& opts) { // options are: opts.define("inport=i:0", "MIDI input port to use"); opts.define("outport=i:0", "MIDI output port to use"); opts.define("t|transpose=i:0", "MIDI transposition to use"); 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, March 2001" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << "kernin, version 1.0 (10 March 2001)\n" "compiled: " << __DATE__ << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } midi.setInputPort(opts.getInteger("inport")); midi.setOutputPort(opts.getInteger("outport")); transpose = opts.getInteger("transpose"); if (opts.getArgCount() != 1) { usage(opts.getCommand()); exit(1); } filename = opts.getArg(1); cout << ">>> Saving data to: " << filename << endl; #ifndef OLDCPP outfile.open(filename, ios::out); #else outfile.open(filename, ios::out | ios::noreplace); #endif if (!outfile.is_open()) { cout << "Error: cannot open file for writing." << endl; cout << "Perhaps it already exists?" << endl; exit(1); } } ////////////////////////////// // // example -- shows various command-line option calls to program. // void example(void) { cout << "\n" << endl; } ////////////////////////////// // // usage -- how to run this program from the command-line. // void usage(const char* command) { cout << "\n" "Data entry for Humdrum **kern.\n" "\n" "Usage: " << command << " [-i num][-o num] output-file\n" "\n" "Options:\n" " -i port = use the specified MIDI input port\n" " -o port = use the specified MIDI output port\n" " --options = list all options, default values, and aliases\n" "\n" << endl; } ////////////////////////////// // // storeCommandEvent -- // void storeCommandEvent (int key, int vel, int mtime) { if (vel > 0 && attacktimes.getSize() > 0) { iois.insert(mtime - attacktimes[0]); } if (vel > 0) { attacktimes.insert(mtime); attackkeys.insert(key - controlOctave * 12); } else { durations.insert(mtime - actiontimes[key]); actiontimes[key] = mtime; } interpreted = 0; } ////////////////////////////// // // interpretShiftEvent -- // char interpretShiftEvent(void) { static char buffer[1024] = {0}; int eventcount = 1; int ioicount = iois.getCount(); int i = 0; while (i < ioicount && i < iois.getCount()) { if (iois[i] < 6 * speed) { eventcount++; } else { break; } i++; } // cout << "Number of events = " << eventcount << endl; if (eventcount < 1 || eventcount > 100) { // nothing to do interpreted = 1; buffer[0] = '\0'; return convertShiftEvent(buffer); } // event count keeps track of how many events occurred, now // now identify each event as a dot or a dash. buffer[0] = '\0'; for (i=eventcount; i>0; i--) { if (i-1 < iois.getSize() && iois[i-1] < speed * 3) { strcat(buffer, "."); } else { strcat(buffer, "-"); } } if (durations.getCount() == 0) { // cout << "Duration size is zero" << endl; return convertShiftEvent(buffer); } else { // cout << "Duration = " << durations[0] << endl; } return convertShiftEvent(buffer); } ////////////////////////////// // // convertShiftEvent -- // char convertShiftEvent(const char* string) { if (strcmp(string, ".-" ) == 0) return 'A'; if (strcmp(string, "-...") == 0) return 'B'; if (strcmp(string, "-.-.") == 0) return 'C'; if (strcmp(string, "-.." ) == 0) return 'D'; if (strcmp(string, "." ) == 0) return 'E'; if (strcmp(string, "..-.") == 0) return 'F'; if (strcmp(string, "--." ) == 0) return 'G'; if (strcmp(string, "....") == 0) return 'H'; if (strcmp(string, ".." ) == 0) return 'I'; if (strcmp(string, ".---") == 0) return 'J'; if (strcmp(string, "-.-" ) == 0) return 'K'; if (strcmp(string, ".-..") == 0) return 'L'; if (strcmp(string, "--" ) == 0) return 'M'; if (strcmp(string, "-." ) == 0) return 'N'; if (strcmp(string, "---" ) == 0) return 'O'; if (strcmp(string, ".--.") == 0) return 'P'; if (strcmp(string, "--.-") == 0) return 'Q'; if (strcmp(string, ".-." ) == 0) return 'R'; if (strcmp(string, "..." ) == 0) return 'S'; if (strcmp(string, "-" ) == 0) return 'T'; if (strcmp(string, "..-" ) == 0) return 'U'; if (strcmp(string, "...-") == 0) return 'V'; if (strcmp(string, ".--" ) == 0) return 'W'; if (strcmp(string, "-..-") == 0) return 'X'; if (strcmp(string, "-.--") == 0) return 'Y'; if (strcmp(string, "--..") == 0) return 'Z'; return '\0'; } ////////////////////////////// // // convertMIDIToBase40 -- print the most likely spelling for the note // when in the given key. Optimized for Major keys only. // Default value: key = 0; // int convertMIDIToBase40(int note, int key) { if (key > 7) key = 7; if (key < -7) key = -7; int base[12] = {0, 1, 6, 11, 12, 17, 18, 23, 24, 29, 34, 35}; int keyt[15] = {-1, 22, 5, 28, 11, 34, 17, 0, 23, 6, 29, 12, 35, 18, 1}; int keym[15] = {-1, 6, 1, 8, 3, 10, 5, 0, 7, 2, 9, 4, 11, 6, 1}; int pc = (note - keym[key + 7]) % 12; int octave = (note - keym[key + 7]) / 12 - 1; int output = base[pc] + keyt[key + 7] + 40 * octave + 2; return output; } // md5sum: e4c48e8a621b9d1f810303b17908dcaa kernin.cpp [20050403]