// // Programmer: Craig Stuart Sapp // Creation Date: Sun Jul 27 11:57:21 PDT 2003 // Last Modified: Thu Jul 31 22:00:31 PDT 2003 // Last Modified: Sun May 2 22:26:31 PDT 2010 (added **recip rhythm spec.) // Filename: ...sig/examples/all/harm2root.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/harm2root.cpp // Syntax: C++; museinfo // // Description: Convert a Humdrum **harm spine into a **root spine // #include "humdrum.h" #include "PerlRegularExpression.h" #include #include #include // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void usage (const char* command); void generateAnalysis (HumdrumFile& infile, Array& durs); void doRhythmAnalysis (HumdrumFile& infile, Array& durs); int makeRootInterval (const char* harmdata, int keyroot, int keymode); void getChordPitches (Array& pitches, const char* token, int root, int keyroot, int keymode); void printChordInfo (const char* token, int rootinterval, int keyroot, int keymode, double duration); int getInversion (const char* token); int getScaleDegree (const char* harm); int adjustKeyMode (int keymode, int keyroot, const char* lastpart); int getRecipField (int line, HumdrumFile& infile, int recip); double getRecipDuration (HumdrumFile& infile, int line, int primarySpine); int checkForKeyDesignation(HumdrumFile& infile, int line); int checkForTimeSignature(HumdrumFile& infile, int line); // global variables Options options; // database for command-line arguments int debugQ = 0; // used with --debug option int appendQ = 0; // used with -a option int octave = 2; // used with -o option int boctave = 3; // used with -O option int rhythmQ = 1; // used with --RR option int rootQ = 1; // used with -r option int bassQ = 0; // used with -b option int recip = -1; // used with -R option int recipField = -1; // used with -R option string instrument = ""; // used with -I option string Prefix = ""; // used with -P option int prefixQ = 0; // used with -P option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { checkOptions(options, argc, argv); HumdrumFileSet infiles; infiles.read(options); Array durs; for (int i=0; i& durs) { int i, j; infile.analyzeRhythm(); durs.setSize(infile.getNumLines()); durs.setSize(0); double lastbeat = 0.0; double beat = 0.0; double duration = 0.0; for (i=0; i=0; j--) { if (strcmp(infile[i].getExInterp(j), "**harm") == 0) { if (strcmp(infile[i][j], ".") != 0) { lastbeat = beat; beat = infile[i].getAbsBeat(); duration = beat - lastbeat; durs.append(duration); } } } } } for (i=0; i 0) { duration = infile[infile.getNumLines()-1].getAbsBeat() - beat; durs[durs.getSize()-1] = duration; } } ////////////////////////////// // // generateAnalysis -- // void generateAnalysis(HumdrumFile& infile, Array& durs) { int i, j; int length; int keyroot = 2; int keymode = 0; // 0 = major, 1 = minor int rootinterval = 0; int testpitch = 0; char buffer[128] = {0}; int rindex = 0; double rdur; for (i=0; i 0) { Convert::durationToKernRhythm(buffer, durs[rindex++]); if (rhythmQ && buffer[0] != '-') { cout << buffer; } } if (rootinterval >= 0) { cout << Convert::base40ToKern(buffer, (keyroot + rootinterval) % 40 + octave * 40); } else { cout << "r"; } if (strchr(infile[i][j], ';') != NULL) { cout << ';'; } } else if (bassQ) { int inversion = getInversion(infile[i][j]); Array pitches; getChordPitches(pitches, infile[i][j], rootinterval, keyroot, keymode); int bass = pitches[inversion] % 40 + boctave * 40; //cerr << "Pitch IS " << pitches[inversion] << " FOR " << infile[i][j] << endl; if (durs.getSize() > 0) { Convert::durationToKernRhythm(buffer, durs[rindex++]); if (rhythmQ && buffer[0] != '-') { cout << buffer; } } if (rootinterval >= 0) { //cout << Convert::base40ToKern(buffer, // (keyroot + rootinterval) % 40 + boctave * 40); cout << Convert::base40ToKern(buffer, bass); } else { cout << "r"; } if (strchr(infile[i][j], ';') != NULL) { cout << ';'; } } else { // print entire chord if ((recipField <= 0) && (durs.getSize() > 0)) { printChordInfo(infile[i][j], rootinterval, keyroot, keymode, durs[rindex++]); } else if (recipField > 0) { rdur = getRecipDuration(infile, i, recipField); printChordInfo(infile[i][j], rootinterval, keyroot, keymode, rdur); } else { printChordInfo(infile[i][j], rootinterval, keyroot, keymode, -1); } } } else { cout << "."; } } } } else if(infile[i].isInterpretation()) { if (appendQ) { cout << "\t"; } length = strlen(infile[i][0]); if (infile[i][0][length-1] == ':') { testpitch = Convert::kernToBase40(infile[i][0]); if (testpitch >= 0) { cout << infile[i][0]; keyroot = testpitch % 40; keymode = std::islower(infile[i][0][1]) ? 1 : 0; } } else if (strncmp(infile[i][0], "**", 2) == 0) { if (rootQ) { cout << "**root"; } else if (bassQ) { cout << "**bass"; } else { cout << "**kern"; } if (recip >= 0) { recipField = getRecipField(i, infile, recip); } } else if (strncmp(infile[i][0], "*I", 2) == 0) { if (instrument[0] == '\0') { cout << "*"; } else { cout << "*I" << instrument; } } else if (infile[i].equalFieldsQ()) { if (strcmp(infile[i][0], "*+") == 0) { cout << "*"; } else if (strcmp(infile[i][0], "*^") == 0) { cout << "*"; } else if (strcmp(infile[i][0], "*v") == 0) { cout << "*"; } else if (strcmp(infile[i][0], "*x") == 0) { cout << "*"; } else { cout << infile[i][0]; } } else { int status = 0; status = checkForKeyDesignation(infile, i); if (status == 0) { status = checkForTimeSignature(infile, i); } if (status == 0) { cout << "*"; } } } else if (infile[i].isMeasure()) { if (appendQ) { cout << "\t"; } cout << infile[i][0]; } else if (infile[i].isLocalComment()) { if (appendQ) { cout << "\t"; } cout << '!'; } else if (infile[i].isGlobalComment() && !appendQ) { cout << infile[i]; } else if (infile[i].isBibliographic() && !appendQ) { cout << infile[i]; } if (appendQ) { cout << "\n"; } else { cout << "\n"; } } } ////////////////////////////// // // checkForKeyDesignation -- look for a key designation on the current // line, and echo it in the output spine. // int checkForKeyDesignation(HumdrumFile& infile, int line) { if (!infile[line].isInterpretation()) { return 0; } PerlRegularExpression pre; int j; for (j=0; j 0) { output = 1; } return output; } ////////////////////////////// // // printChordInfo -- // void printChordInfo(const char* token, int root, int keyroot, int keymode, double duration) { int i; char dbuffer[1024] = {0}; char pbuffer[1024] = {0}; if (duration > 0) { Convert::durationToKernRhythm(dbuffer, duration); } if (!rhythmQ) { dbuffer[0] = '\0'; } if (prefixQ) { strcat(dbuffer, Prefix.c_str()); } Array pitches; if (root >= 0) { getChordPitches(pitches, token, root, keyroot, keymode); for (i=0; i 0) { cout << dbuffer; } cout << "r"; if (strchr(token, ';') != NULL) { cout << ';'; } } } ////////////////////////////// // // getChordPitches -- // void getChordPitches(Array& pitches, const char* token, int root, int keyroot, int keymode) { int oct = octave + 2; int inversion = getInversion(token); pitches.setSize(0); // store the root pitch int pitch = (root + keyroot) % 40 + oct * 40; int base = pitch; if (inversion == 0) { pitch = pitch - 40; } pitches.append(pitch); char firstpart[128] = {0}; char lastpart[128] = {0}; strcpy(firstpart, token); int i; int length = strlen(firstpart); for (i=0; i 40) && (pitches[2]/40 > 3)) { pitches[3] -= 40; } else if ((pitches[3] - pitches[1] > 40) && (pitches[1]/40 > 3)) { pitches[3] -= 40; } // put 3rd inversions in the octave below middle C if (inversion == 3) { pitches[3] = pitches[3] % 40 + 40 * (oct - 1); } } ////////////////////////////// // // adjustKeyMode -- // int adjustKeyMode(int keymode, int keyroot, const char* lastpart) { char string[128] = {0}; strcpy(string, lastpart); const char* ptr = lastpart; if (strchr(string, '/') != NULL) { ptr = strchr(string, '/') + 1; } if (strchr(ptr, 'v') != NULL) { keymode = 1; } else if (strchr(ptr, 'i') != NULL) { keymode = 1; } else if (strchr(ptr, 'V') != NULL) { keymode = 0; } else if (strchr(ptr, 'I') != NULL) { keymode = 0; } else { // don't know the key so assume major keymode = 0; } return keymode; } ////////////////////////////// // // getScaleDegree -- // int getScaleDegree(const char* harm) { if (strstr(harm, "VII") != NULL) { return 6; } if (strstr(harm, "vii") != NULL) { return 6; } if (strstr(harm, "VI") != NULL) { return 5; } if (strstr(harm, "vi") != NULL) { return 5; } if (strstr(harm, "IV") != NULL) { return 3; } if (strstr(harm, "iv") != NULL) { return 3; } if (strstr(harm, "V") != NULL) { return 4; } if (strstr(harm, "v") != NULL) { return 4; } if (strstr(harm, "III") != NULL) { return 2; } if (strstr(harm, "iii") != NULL) { return 2; } if (strstr(harm, "II") != NULL) { return 1; } if (strstr(harm, "ii") != NULL) { return 1; } if (strstr(harm, "I") != NULL) { return 0; } if (strstr(harm, "i") != NULL) { return 0; } if (strstr(harm, "Fr") != NULL) { return 5; } if (strstr(harm, "Gn") != NULL) { return 5; } if (strstr(harm, "Lt") != NULL) { return 5; } if (strstr(harm, "N") != NULL) { return 1; } return 0; } ////////////////////////////// // // getInversion -- // int getInversion(const char* token) { if (strchr(token, 'b') != NULL) { return 1; } if (strchr(token, 'c') != NULL) { return 2; } if (strchr(token, 'd') != NULL) { return 3; } return 0; } ////////////////////////////// // // makeRootInterval -- // int makeRootInterval(const char* harmdata, int keyroot, int keymode) { int slashcount = 0; int i; int output = 0; int length = strlen(harmdata); char abuffer[128] = {0}; strcpy(abuffer, harmdata); for (i=0; i= 1) { const char* ptr = strchr(harmdata, '/') + 1; offset = makeRootInterval(ptr, keyroot, keymode); } if (keymode) { // minor mode (harmonic minor) if (strstr(abuffer, "vii") != 0) { output = E_base40_maj7; } else if (strstr(abuffer, "VII") != 0) { output = E_base40_maj7; } else if (strstr(abuffer, "vi") != 0) { output = E_base40_min6; } else if (strstr(abuffer, "VI") != 0) { output = E_base40_min6; } else if (strstr(abuffer, "iv") != 0) { output = E_base40_per4; } else if (strstr(abuffer, "IV") != 0) { output = E_base40_per4; } else if (strstr(abuffer, "iii") != 0) { output = E_base40_min3; } else if (strstr(abuffer, "III") != 0) { output = E_base40_min3; } else if (strstr(abuffer, "ii") != 0) { output = E_base40_maj2; } else if (strstr(abuffer, "II") != 0) { output = E_base40_maj2; } else if (strstr(abuffer, "N") != 0) { output = E_base40_min2; } else if (strstr(abuffer, "v") != 0) { output = E_base40_per5; } else if (strstr(abuffer, "V") != 0) { output = E_base40_per5; } else if (strstr(abuffer, "i") != 0) { output = E_base40_per1; } else if (strstr(abuffer, "I") != 0) { output = E_base40_per1; } else if (strstr(abuffer, "Lt") != 0) { output = E_base40_aug4; } else if (strstr(abuffer, "Gn") != 0) { output = E_base40_aug4; } else if (strstr(abuffer, "Fr") != 0) { output = E_base40_aug4; } else { output = E_base40_rest; } } else { // major mode if (strstr(abuffer, "vii") != 0) { output = E_base40_maj7; } else if (strstr(abuffer, "VII") != 0) { output = E_base40_maj7; } else if (strstr(abuffer, "vi") != 0) { output = E_base40_maj6; } else if (strstr(abuffer, "VI") != 0) { output = E_base40_maj6; } else if (strstr(abuffer, "iv") != 0) { output = E_base40_per4; } else if (strstr(abuffer, "IV") != 0) { output = E_base40_per4; } else if (strstr(abuffer, "iii") != 0) { output = E_base40_maj3; } else if (strstr(abuffer, "III") != 0) { output = E_base40_maj3; } else if (strstr(abuffer, "ii") != 0) { output = E_base40_maj2; } else if (strstr(abuffer, "II") != 0) { output = E_base40_maj2; } else if (strstr(abuffer, "N") != 0) { output = E_base40_min2; } else if (strstr(abuffer, "v") != 0) { output = E_base40_per5; } else if (strstr(abuffer, "V") != 0) { output = E_base40_per5; } else if (strstr(abuffer, "i") != 0) { output = E_base40_per1; } else if (strstr(abuffer, "I") != 0) { output = E_base40_per1; } else if (strstr(abuffer, "Lt") != 0) { output = E_base40_aug4; } else if (strstr(abuffer, "Gn") != 0) { output = E_base40_aug4; } else if (strstr(abuffer, "Fr") != 0) { output = E_base40_aug4; } else { output = E_base40_rest; } } int flatcount = 0; int sharpcount = 0; int slen = strlen(abuffer); for (int i=0; i