//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// 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 <string.h>
#include <math.h>
#include <ctype.h>
// 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<int> attackkeys; // for control key attack numbers
CircularBuffer<int> attacktimes; // for control key attack times
CircularBuffer<int> durations; // for control key attack times
CircularBuffer<int> iois; // for inter-onset time intervals
Array<int> 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 datadouble 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) {
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]