// // Programmer: Craig Stuart Sapp // Creation Date: Wed Apr 20 20:47:40 PDT 2011 // Last Modified: Sun Jan 8 18:58:40 PST 2012 (added -s option) // Filename: ...sig/examples/all/noficta.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/noficta.cpp // Syntax: C++; museinfo // // Description: Remove ficta marks from **kern data // #include "humdrum.h" #include "PerlRegularExpression.h" #include #include #include #include #include using namespace std; // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void usage (const char* command); void getFictaChar (char* ficta, HumdrumFile& infile); void processFile (HumdrumFile& infile); void processFileSuppress(HumdrumFile& infile); void processFileSwitch (HumdrumFile& infile); void removeFicta (HumdrumFile& infile, int line, int spine, const char* ficta); void removeFictaSuppress(HumdrumFile& infile, int line, int spine, const char* ficta); void processNote (HumdrumFile& infile, int i, int j, vector& diatonicstate); void processTrack (int ttrack, HumdrumFile& infile); void parseKeySignature (vector& keysig, const char* keyinfo); // global variables: Options options; // database for command-line arguments int numinputs; // the total number of input files int debugQ = 0; // used with --debug option int suppressQ = 0; // used with -S option int switchQ = 0; // used with -s option char FICTA[1024] = {0}; // used with getFictaChar(). string Tiehead = ""; // used for keeping track musica ficta on // tied notes int Notecounter = 0; ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { HumdrumFile infile; // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process numinputs = options.getArgCount(); string filename = ""; for (int i=0; i ktracks; infile.getTracksByExInterp(ktracks, "**kern"); for (i=0; i<(int)ktracks.size(); i++) { if (debugQ) { cout << "!!PROCESSING TRACK " << ktracks[i] << endl; } processTrack(ktracks[i], infile); } cout << infile; } ////////////////////////////// // // processTrack -- currently assuming that editorial accidentals // are not found in chords. // void processTrack(int ttrack, HumdrumFile& infile) { int i, j; int ptrack; PerlRegularExpression pre; vector diatonicstate(7, 0); Tiehead = ""; Notecounter = 0; vector keysignature(7, 0); for (i=0; i& diatonicstate) { if (strcmp(infile[i][j], ".") == 0) { // ignore null tokens return; } if (strchr(infile[i][j], 'r') != NULL) { // ignore rests return; } int diatonic = Convert::kernToDiatonicPitchClassNumeric(infile[i][j]); int accidental = Convert::kernToDiatonicAlteration(infile[i][j]); int tieQ = 0; if (strchr(infile[i][j], ']') != NULL) { tieQ = 1; } else if (strchr(infile[i][j], '_') != NULL) { tieQ = 1; } //if ((strcmp(Tiehead, "") != 0) && ((strchr(infile[i][j], ']') != NULL) || // (strchr(infile[i][j], '_') != NULL))) { if ((Notecounter == 0) && tieQ) { // Have a tied note which started with a pitch which used to have // and editorial accidental. Match the chromatic pitch of the // prevailing diatonic state. // int accidentalT = Convert::kernToDiatonicAlteration(Tiehead); // int diatonicT = Convert::kernToDiatonicPitchClassNumeric(Tiehead); PerlRegularExpression preT; string dataT = infile[i][j]; // deal with haning tie: if (Tiehead.empty()) { Tiehead = dataT; } // int differenceT = diatonicstate[diatonic] - accidental; // int base40T = Convert::kernToBase40(dataT.c_str()); int base40T = Convert::kernToBase40(Tiehead.c_str()); // base40T += differenceT; char pitchbuffer[64] = {0}; Convert::base40ToKern(pitchbuffer, base40T); PerlRegularExpression preZ; preZ.sar(dataT, "[A-G]+[n#-]*", pitchbuffer, "i"); preZ.sar(dataT, "n", "", ""); // don't need/want natural sign preZ.sar(dataT, FICTA, "", ""); // don't keep editorial accidental infile[i].changeField(j, dataT.c_str()); // diatonicstate[diatonicT] = accidentalT; if (strchr(infile[i][j], ']') != NULL) { Tiehead = ""; } return; } // Tiehead should no longer be needed, so set it to empty Tiehead = ""; Notecounter++; if (debugQ) { // cout << "!!Diatonicstate: " << diatonicstate << endl; } if (debugQ) { cout << "!!kern = " << infile[i][j] << " DIATONIC : " << diatonic << "\taccidental: " << accidental << endl; } if (strstr(infile[i][j], FICTA) == NULL) { // update the diatonic state if no editorial accidental diatonicstate[diatonic] = accidental; if (debugQ) { cout << "!!UPDATING DIATONIC STATE for " << diatonic << " to " << diatonicstate[diatonic] << endl; // cout << "!!\t" << diatonicstate << endl; } if (strchr(infile[i][j], '[') != NULL) { Tiehead = infile[i][j]; } return; } // at this point there is an editorial accidental. The accidental // must be changed so that it is not printed in the score (with a // score writing program which uses modern accidental syles). string data = infile[i][j]; PerlRegularExpression pre; if (accidental == diatonicstate[diatonic]) { // the editorial accidental matches the current diatonic // state. This is desirable for hiding in printed music, // since an accidental will not be printed into the notation, // so just get rid of the editorial accidental marker. pre.sar(data, FICTA, "", ""); } else { // the editorial accidental does not match the current // diatonic state. This is undesirable, since the notation // program will print a correcting accididental. So insert the // current accidental for that diatonic pitch class and then // remove the editorial accidental marker. int difference = diatonicstate[diatonic] - accidental; int base40 = Convert::kernToBase40(data.c_str()); base40 += difference; char outbuffer[64] = {0}; Convert::base40ToKern(outbuffer, base40); if (debugQ) { cout << "!!ACCIDENTAL = " << accidental << endl; cout << "!!DIATONIC = " << diatonic << endl; cout << "!!DIATONIC STATE = " << diatonicstate[diatonic] << endl; cout << "!!DIFFERENCE = " << difference << endl; cout << "!!GOING to convert " << data << " TO " << outbuffer << endl; } pre.sar(data, "[A-G]+[n#-]*", outbuffer, "i"); } pre.sar(data, "n", "", ""); // don't need/want natural sign pre.sar(data, FICTA, "", ""); // match diatonic state: // insert the token back into the data file. infile[i].changeField(j, data.c_str()); // store the tie head string if (strchr(infile[i][j], '[') != NULL) { Tiehead = infile[i][j]; } } ////////////////////////////// // // parseKeySignature -- // b-e-a-d- => C=0, D=-1, E=-1, F=0, etc. // void parseKeySignature(vector& keysig, const char* keyinfo) { fill(keysig.begin(), keysig.end(), 0); PerlRegularExpression pre; if (pre.search(keyinfo, "c-", "i")) { keysig[0] = -1; } if (pre.search(keyinfo, "d-", "i")) { keysig[1] = -1; } if (pre.search(keyinfo, "e-", "i")) { keysig[2] = -1; } if (pre.search(keyinfo, "f-", "i")) { keysig[3] = -1; } if (pre.search(keyinfo, "g-", "i")) { keysig[4] = -1; } if (pre.search(keyinfo, "a-", "i")) { keysig[5] = -1; } if (pre.search(keyinfo, "b-", "i")) { keysig[6] = -1; } if (pre.search(keyinfo, "c#", "i")) { keysig[0] = +1; } if (pre.search(keyinfo, "d#", "i")) { keysig[1] = +1; } if (pre.search(keyinfo, "e#", "i")) { keysig[2] = +1; } if (pre.search(keyinfo, "f#", "i")) { keysig[3] = +1; } if (pre.search(keyinfo, "g#", "i")) { keysig[4] = +1; } if (pre.search(keyinfo, "a#", "i")) { keysig[5] = +1; } if (pre.search(keyinfo, "b#", "i")) { keysig[6] = +1; } } ////////////////////////////// // // processFile -- // void processFile(HumdrumFile& infile) { int i, j; char ficta[1024] = {0}; getFictaChar(ficta, infile); PerlRegularExpression pre; for (i=0; i=0; i--) { if (!infile[i].isBibliographic()) { continue; } if (pre.search(infile[i][0], "^!!!RDF\\*\\*kern\\s*:\\s*([^\\s=]+)\\s*=.*ficta", "")) { strcpy(ficta, pre.getSubmatch(1)); return; } } // presume "i" as ficta if no RDF marker strcpy(ficta, "i"); } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("s|switch=b", "switch editorial accidentals"); opts.define("S|suppress=b", "suppress display of editorial accidentals"); opts.define("debug=b"); // debugging mode opts.define("author=b"); // author of program opts.define("version=b"); // compilation info opts.define("example=b"); // example usages opts.define("h|help=b"); // short description opts.process(argc, argv); // handle basic options: if (opts.getBoolean("author")) { cout << "Written by Craig Stuart Sapp, " << "craig@ccrma.stanford.edu, April 2011" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 20 April 2011" << endl; cout << "compiled: " << __DATE__ << endl; cout << MUSEINFO_VERSION << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand().c_str()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } suppressQ = opts.getBoolean("suppress"); switchQ = opts.getBoolean("switch"); debugQ = opts.getBoolean("debug"); } ////////////////////////////// // // example -- example usage of the quality program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // usage -- gives the usage statement for the meter program // void usage(const char* command) { cout << " \n" << endl; } // md5sum: d7ad0d528c891ed59d0e3dec48230aad noficta.cpp [20160320]