// // Programmer: Craig Stuart Sapp // Creation Date: Tue Mar 1 18:07:39 PST 2011 // Last Modified: Tue Mar 1 18:07:44 PST 2011 // // Filename: ...sig/examples/all/hum2cmme.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/hum2cmme.cpp // Syntax: C++; museinfo // // Description: Converts Humdrum files into MEI data // (monophonic spines only allowed at the moment). // #include #ifndef OLDCPP #include #include #define SSTREAM stringstream #define CSTRING str().c_str() using namespace std; #else #include #ifdef VISUAL #include #else #include #endif #define SSTREAM strstream #define CSTRING str() #endif #include "string.h" #include "humdrum.h" #include "PerlRegularExpression.h" #define BAR_NONE (0) #define BAR_SINGLE (1) #define BAR_END (2) #define BAR_RPTSTART (3) #define BAR_RPTEND (4) #define BAR_RPTBOTH (5) #define BAR_INVIS (6) #define BAR_DBL (7) #define XML_SCOPE "xml:" ////////////////////////////////////////////////////////////////////////// // function declarations: void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); int validateHumdurmFile (HumdrumFile& infile); void convertHumdrumToCmme (int indent, SSTREAM& out, HumdrumFile& infile); void createGeneralData (int indent, SSTREAM& out, HumdrumFile& infile); void createVoiceData (int indent, SSTREAM& out, HumdrumFile& infile); void createVoiceDataBody (int indent, SSTREAM& out, HumdrumFile& infile); void createVoiceDataBodyMdiv(int indent, SSTREAM& out, HumdrumFile& infile); void createVoiceDataBodyMdivScore(int indent, SSTREAM& out, HumdrumFile& infile); void Indent (SSTREAM& out, int indent, const char* string = NULL); void printTitle (int indent, SSTREAM& out, HumdrumFile& infile); void printComposer (int indent, SSTREAM& out, HumdrumFile& infile); void printEditor (int indent, SSTREAM& out, HumdrumFile& infile); void printAsCdata (SSTREAM& out, const char* string); void printMdivScoreScoredef(int indent, SSTREAM& out, HumdrumFile& infile); void printInitialKeySignature(SSTREAM& out, HumdrumFile& infile); void printInitialMeterSignature(SSTREAM& out, HumdrumFile& infile); int getMidiTicksPerQuarterNote(HumdrumFile& infile); void printScoredefStaffgrp(int indent, SSTREAM& out, HumdrumFile& infile); void getStaffCount (Array& primarytracks, HumdrumFile& infile); void printStaffgrpStaffdef(int indent, SSTREAM& out, HumdrumFile& infile, Array& tracks, int index); void printInitialClef (SSTREAM& out, HumdrumFile& infile, int ptrack); void printBibliographicRecords(int indent, SSTREAM& out, HumdrumFile& infile); void getSectionInfo (Array& sections, HumdrumFile& infile); void printScoreSection (int indent, SSTREAM& out, HumdrumFile& infile, Array& sections, int sindex); void printSingleSection (int indent, SSTREAM& out, HumdrumFile& infile, int startline, int stopline); void printMeasure (int indent, SSTREAM& out, HumdrumFile& infile, Array& measures, int mindex, int startsection, int stopsection, Array& ptrack); void getMeasureInfoForSection(Array& measures, HumdrumFile& infile, int startline, int stopline); void generateMeasureInfo (Array& minfo, HumdrumFile& infile); void printBarlineStyle (SSTREAM& out, int stylecode); void calculateLayerInformation(Array& minfo, HumdrumFile& infile, Array& ptrack); void printMeasureStaff (int indent, SSTREAM& out, HumdrumFile& infile, Array& minfo, int mindex, int startsection, int stopsection, Array& ptrack, int staffindex); void printStaffLayer (int indent, SSTREAM& out, HumdrumFile& infile, Array& minfo, int mindex, int startsection, int stopsection, Array& ptrack, int staffindex, int layerindex); int getLayerCountInMeasure(Array& minfo, int mindex, int startsection, int stopsection, int staffindex); int getLayerFieldIndex (int primary, int lindex, int line, HumdrumFile& infile); void addElementToList (Array >& layeritems, int lindex, int line, int spine); void getLayerItems (Array >& layeritems, HumdrumFile& infile, int staffindex, Array& ptrack, int layerindex, Array& minfo, int mindex, int start, int stop); void printLayerItems (int indent, SSTREAM& out, Array >& layeritems, HumdrumFile& infile, Array& minfo, int mindex, int start, int stop, int layerindex); int getStartOfData (HumdrumFile& infile); int getBeamAdjustment (const char* token); void printNote (int indent, SSTREAM& out, const char* string, int i, int j, int k, int layerindex); void printRest (int indent, SSTREAM& out, const char* string, int i, int j, int k, int layerindex); void printKernData (int indent, SSTREAM& out, HumdrumFile& infile, int row, int col, int layerindex); void printTempExpandRules (int indent, SSTREAM& out, HumdrumFile& infile); void printDtdAlterations (ostream& out); void initializeGlobalVariables(HumdrumFile& infile); void printProfiledescLangusage(int indent, SSTREAM& out, HumdrumFile& infile, Array langs); void printMeiKeySignatureAttributes(SSTREAM& out, const char* keysig); void printMeiKeyAttributes(SSTREAM& out, const char* key); void printMeiMeterSymbolAttributes (SSTREAM& out, const char* metstring); void printMeiMeterSignatureAttributes(SSTREAM& out, const char* metersig); void checkForTimeAndOrKeyChange(int indent, SSTREAM& out, HumdrumFile& infile, Array& measures, int mindex, Array& ptrack, Array& minfo); // User interface variables: Options options; int debugQ = 0; // used with --debug option int verboseQ = 0; // used with -v option ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { HumdrumFile infile; // initial processing of the command-line options checkOptions(options, argc, argv); if (options.getArgCount() < 1) { infile.read(cin); } else { infile.read(options.getArg(1)); } infile.analyzeRhythm("4"); int validation = validateHumdurmFile(infile); if (validation == 0) { cerr << "This humdrum file cannot be processed." << endl; cerr << "Only files with monophonic **kern spines are allowed." << endl; exit(1); } int indent = 0; SSTREAM cmmedata; convertHumdrumToCmme(indent, cmmedata, infile); Indent(cmmedata, indent); cmmedata << ends; cout << cmmedata.CSTRING; return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // getStartOfData -- the index of the first line with data on it in the file. // int getStartOfData(HumdrumFile& infile) { int i; for (i=0; i\n"; createGeneralData(indent+1, out, infile); createVoiceData(indent+1, out, infile); Indent(out, indent); out << "\n"; } ////////////////////////////// // // createGeneralData -- Fill in the , <Composer> and <Editor> // fields // void createGeneralData(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "<GeneralData>\n"; printTitle(indent+1, out, infile); printComposer(indent+1, out, infile); printEditor(indent+1, out, infile); printBibliographicRecords(indent+1, out, infile); Indent(out, indent); out << "</GeneralData>\n"; } ////////////////////////////// // // printBibliographicRecords -- // // Version 1.9.1b convert stored raw Humdrum reference records like this: // <!-- Humdrum Bibliographic Records: // <bib key="COM" meaning="Composer's name" value="Bach, Johann Sebastian"/> // End Humdrum Bibliographic Records --> // // For the MEI 2010-05 converter, a more eleagant method is used using // XML processing instructions for a theoretical Humdrum processor: // <?Humdrum type="bib" key="COM" value="Bach, Johann Sebastian" // meaning="Composer's name"?> // void printBibliographicRecords(int indent, SSTREAM& out, HumdrumFile& infile) { char buffer[1024] = {0}; Array<char> keymeaning(1); keymeaning[0] = '\0'; // int found = 0; int i; for (i=0; i<infile.getNumLines(); i++) { if (!infile[i].isBibliographic()) { continue; } // Used in MEI 1.9.1b conversion: // if (found == 0) { // found = 1; // Indent(out, indent); // out << "<!-- Humdrum Bibliographic Records:\n"; // } Indent(out, indent); out << "<?Humdrum type=\"bib\""; out << " key=\""; printAsCdata(out, infile[i].getBibKey(buffer, 1024)); out << "\""; out << " value=\""; printAsCdata(out, infile[i].getBibValue(buffer, 1024)); out << "\""; HumdrumRecord::getBibliographicMeaning(keymeaning, infile[i].getBibKey(buffer, 1024)); if (keymeaning.getSize() > 1) { out << " meaning=\""; printAsCdata(out, keymeaning.getBase()); out << "\""; //Indent(out, indent+1); } out << "?>\n"; } // Used in MEI 1.9.1b conversion: //if (found) { // Indent(out, indent); // out << "End Humdrum Bibliographic Records -->\n"; //} } ////////////////////////////// // // printTitle -- Fill in the <Title> section of <GeneralData> // void printTitle(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "<Title>"; PerlRegularExpression pre; int i; for (i=0; i<infile.getNumLines(); i++) { if (!infile[i].isBibliographic()) { continue; } if (pre.search(infile[i][0], "^!!!OTL:\\s*(.*)\\s*$", "")) { printAsCdata(out, pre.getSubmatch(1)); } } out << "\n"; } ////////////////////////////// // // printComposer -- Fill in the section of // Perhaps switch around the last name and firstname... // void printComposer(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << ""; PerlRegularExpression pre; int i; for (i=0; i\n"; } ////////////////////////////// // // printEditor -- Fill in the section of // void printEditor(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << ""; PerlRegularExpression pre; int i; for (i=0; i\n"; } ////////////////////////////// // // createVoiceData -- Fill in the section of // // // (facsimile*, ((front?, (body | group)?, back?))) // // void createVoiceData(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "\n"; createVoiceDataBody(indent+1, out, infile); Indent(out, indent); out << "\n"; } ////////////////////////////// // // createVoiceDataBody -- // // // mdiv+ // void createVoiceDataBody(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "\n"; createVoiceDataBodyMdiv(indent+1, out, infile); Indent(out, indent); out << "\n"; } ////////////////////////////// // // createVoiceDataBodyMdiv -- // // // ((score?, parts?) | mdiv*) // void createVoiceDataBodyMdiv(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "\n"; generateMeasureInfo(MINFO, infile); createVoiceDataBodyMdivScore(indent+1, out, infile); Indent(out, indent); out << "\n"; } ////////////////////////////// // // generateMeterInfo -- // void generateMeterInfo(Array& measuredur, HumdrumFile& infile) { Array& md = measuredur; md.setSize(infile.getNumLines()); md.allowGrowth(0); md.setAll(0.0); int i, j; PerlRegularExpression pre; for (i=0; i 0) { md[i] = md[i-1]; } if (!infile[i].isInterpretation()) { continue; } for (j=0; j=0; i--) { if (md[i] == 0.0) { md[i] = md[i+1]; } } } ////////////////////////////// // // generateMeasureInfo -- // int right; // visual style of right-side barline of meas. // int left; // visual style of left-side barline of meas. // int num; // measure number // int nextbar; // index of next barline // int lastbar; // index of last barline // char letter; // sub measure enumeration // char complete; // c = complete, i = underfull, o = overfull // char pickupbefore; // true if pickup measure preceeds this // char ispickup; // true if this measure is a pickup measure // char valid; // true if index represents a real barline // Array layers; // number of layers for each staff on line // void generateMeasureInfo(Array& minfo, HumdrumFile& infile) { int i; Array measuredur; generateMeterInfo(measuredur, infile); minfo.setSize(infile.getNumLines()); minfo.allowGrowth(0); PerlRegularExpression pre; for (i=0; i\n" << endl; } } else { minfo[i].left = BAR_SINGLE; } // store the complete marker: // c = matches time signature // i = incomplete, underfull // o = overfull if (fabs(infile[i].getBeat()) == measuredur[i]) { minfo[i].complete = 'c'; } else if (fabs(infile[i].getBeat()) > measuredur[i]) { minfo[i].complete = 'o'; } else if (fabs(infile[i].getBeat()) < measuredur[i]) { minfo[i].complete = 'i'; } // store measure number of a pickup beat: if (infile[i].getBeat() < 0) { minfo[i].pickupbefore = 1; } } // store the right-side barline style int tempnext = -1; for (i=minfo.getSize()-1; i>=0; i--) { minfo[i].nextbar = tempnext; if (minfo[i].valid) { if (tempnext >= 0) { minfo[i].right = minfo[tempnext].left; } tempnext = i; } } int templast = -1; for (i=0; i= 0) { if (minfo[minfo[i].nextbar].pickupbefore) { minfo[i].ispickup = 1; minfo[i].left = BAR_INVIS; minfo[i].right = minfo[minfo[i].nextbar].left; minfo[i].complete = 'i'; if (minfo[minfo[i].nextbar].num == 1) { minfo[i].num = 0; } } } } // check for intermediate barlines between two // barlines with consecutive numbers for (i=0; i= 0) { continue; } if (minfo[i].nextbar < 0) { continue; } if (minfo[i].lastbar < 0) { continue; } if (minfo[minfo[i].lastbar].num == minfo[minfo[i].nextbar].num - 1) { // also should check if the first two bars duration sum // to the prevailing meter. minfo[i].num = minfo[minfo[i].lastbar].num; minfo[i].letter = 'b'; minfo[minfo[i].lastbar].letter = 'a'; } } calculateLayerInformation(minfo, infile, PTRACK); if (debugQ) { cout << "\n"; } } ////////////////////////////// // // calculateLayerInformation -- Calculate the number of layers // for each staff to be processed for each line of the Humdrum file. // void calculateLayerInformation(Array& minfo, HumdrumFile& infile, Array& ptrack) { Array reverselookup; reverselookup.setSize(infile.getMaxTracks()+10); reverselookup.setAll(-1); Array& rl = reverselookup; int i, j; for (i=0; i= 0) { minfo[i].layers[tval]++; } } } } ////////////////////////////// // // createVoiceDataBodyMdivScore -- // // // ((app | div | pb | sb | scoredef | staffdef | // staffgrp | annot | curve | line | symbol // | anchoredtext | choice | handshift | gap | // subst | add | corr | damage | del | orig | reg | // restore | sic | supplied | unclear)*, ((section // | ending), (app | div | pb | sb | scoredef | // staffdef | staffgrp | annot | curve | line | // symbol | anchoredtext | choice | handshift | // gap | subst | add | corr | damage | del | orig | // reg | restore | sic | supplied | unclear)*)*) // // Full score view of the mdiv. Since the measure element is // optional, a score may consist entirely of pagebreaks, each of // which points to a page image. Div elements are allowed preceding // and following sections of music data in order to accommodate // blocks of explanatory text. // void createVoiceDataBodyMdivScore(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "\n"; // printMdivScoreScoredef(indent+1, out, infile); // sections Array sections; getSectionInfo(sections, infile); if (sections.getSize() == 1) { printSingleSection(indent+1, out, infile, sections[0], infile.getNumLines()-1); } else { int i; for (i=0; i\n"; } ////////////////////////////// // // printSingleSection -- print a section of music // void printSingleSection(int indent, SSTREAM& out, HumdrumFile& infile, int startline, int stopline) { Array measures; getMeasureInfoForSection(measures, infile, startline, stopline); int i; for (i=0; i& measures, HumdrumFile& infile, int startline, int stopline) { measures.setSize(10000); measures.setSize(0); measures.setGrowth(10000); int i; int barinsection = 0; for (i=startline; i<=stopline; i++) { if (infile[i].isData()) { break; } if (infile[i].isMeasure()) { barinsection = 1; break; } } int backdata = 0; if (barinsection == 0) { for (i=startline-1; i>=0; i--) { if (infile[i].isData()) { backdata = 1; } if (infile[i].isMeasure()) { barinsection = i - startline; break; } } } if (barinsection > 0) { measures.append(barinsection); } else { barinsection = startline + barinsection; measures.append(barinsection); } int start = barinsection + 1; if (start < startline) { start = startline; } for (i=start; i<=stopline; i++) { if (infile[i].isMeasure()) { measures.append(i); } } // if there is no data after last measure in section, then don't // process it: int enddata = 0; for (i=measures[measures.getSize()-1]; i element, but after one is finished and before another // is started. // void checkForTimeAndOrKeyChange(int indent, SSTREAM& out, HumdrumFile& infile, Array& measures, int mindex, Array& ptrack, Array& minfo) { if (minfo[measures[mindex]].valid == 0) { // measure does not start data section (only allows at start of music) // so don't try to print anything. Initial signatures are handled // elsewhere. return; } int keysigline = -1; int meterline = -1; int metline = -1; int keysigspine = -1; int meterspine = -1; int metspine = -1; // not printing key information for now. PerlRegularExpression pre; int i, j; for (i=measures[mindex]; i= 0) { printMeiKeySignatureAttributes(out, infile[keysigline][keysigspine]); } if (meterline >= 0) { printMeiMeterSignatureAttributes(out, infile[meterline][meterspine]); } if (metline >= 0) { printMeiMeterSymbolAttributes(out, infile[metline][metspine]); } out << "/>\n"; } ////////////////////////////// // // printMeasure -- // // void printMeasure(int indent, SSTREAM& out, HumdrumFile& infile, Array& measures, int mindex, int startsection, int stopsection, Array& ptrack) { checkForTimeAndOrKeyChange(indent, out, infile, measures, mindex, ptrack, MINFO); Indent(out, indent); out << "= 0) { out << " n=\""; out << MINFO[measures[mindex]].num; if (letter != 0) { if (letter > 'a') { out << letter; } } out << "\""; } // measure/@id: out << " " << xmlscope << "id=\""; out << "m"; // mark an "x" if the line in the file being used as a barline // does not contain a barline. if (MINFO[measures[mindex]].valid == 0) { out << "x"; } out << "_" << IDMARKER << "_" << measures[mindex]; out << "\""; if (MINFO[measures[mindex]].left != BAR_NONE) { if (verboseQ || (MINFO[measures[mindex]].lastbar == -1)) { if (verboseQ || (MINFO[measures[mindex]].left != BAR_SINGLE)) { out << " left=\""; printBarlineStyle(out, MINFO[measures[mindex]].left); out << "\""; } } } if (MINFO[measures[mindex]].right != BAR_NONE) { if (verboseQ || (MINFO[measures[mindex]].right != BAR_SINGLE)) { out << " right=\""; printBarlineStyle(out, MINFO[measures[mindex]].right); out << "\""; } } // print mesure/@complete if specified: switch (MINFO[measures[mindex]].complete) { case 'c': if (verboseQ) { out << " complete=\"c\""; } break; case 'i': out << " complete=\"i\""; break; case 'o': out << " complete=\"o\""; break; } if (MINFO[measures[mindex]].num >= 0) { if ((letter == 'a') && (MINFO[measures[mindex]].nextbar >= 0)) { out << " join=\"" << "m_" << IDMARKER << "_" << MINFO[measures[mindex]].nextbar << "\""; } else if ((letter == 'b') && (MINFO[measures[mindex]].lastbar >= 0)) { out << " join=\"" << "m_" << IDMARKER << "_" << MINFO[measures[mindex]].lastbar << "\""; } } // All barlines are assumed to be MEI "control" barlines. // It is possible to have "non-control" barlines in Humdrum files, // but the HumdrumFile class currently does not permit them. if (verboseQ) { out << " control=\"true\""; } out << ">\n"; int i; for (i=0; i\n"; } ////////////////////////////// // // printMeasureStaff -- Print a particular staff for a particular measure. // // void printMeasureStaff(int indent, SSTREAM& out, HumdrumFile& infile, Array& minfo, int mindex, int startsection, int stopsection, Array& ptrack, int staffindex) { Indent(out, indent); out << "\n"; int layercount = getLayerCountInMeasure(minfo, mindex, startsection, stopsection, staffindex); int i; for (i=0; i\n"; } ////////////////////////////// // // getLayerCountInMeasure -- return the maximum number of layers in the // int getLayerCountInMeasure(Array& minfo, int mindex, int startsection, int stopsection, int staffindex) { int maxcount = 0; int i; int start; if (minfo[mindex].valid) { start = mindex + 1; } else { start = mindex; } for (i=start; i maxcount) { maxcount = minfo[i].layers[staffindex]; } } return maxcount; } ////////////////////////////// // // printStaffLayer -- // void printStaffLayer(int indent, SSTREAM& out, HumdrumFile& infile, Array& minfo, int mindex, int startsection, int stopsection, Array& ptrack, int staffindex, int layerindex) { Indent(out, indent); out << "\n"; int start = mindex; if (mindex < startsection) { start = startsection; } int stop = minfo[mindex].nextbar; if ((stop < 0) || (stop > stopsection)) { stop = stopsection; } if (start < DATASTART) { start = DATASTART; } if (stop < start) { out << "" << endl; int tempval = stop; stop = start; start = tempval; } Array > layeritems; getLayerItems(layeritems, infile, staffindex, ptrack, layerindex, minfo, mindex, start, stop); printLayerItems(indent+1, out, layeritems, infile, minfo, mindex, start, stop, layerindex); Indent(out, indent); out << "\n"; } ////////////////////////////// // // printLayerItems -- // void printLayerItems(int indent, SSTREAM& out, Array >& layeritems, HumdrumFile& infile, Array& minfo, int mindex, int start, int stop, int layerindex) { int bindent = 0; int oldbeamstate = 0; int newbeamstate = 0; int oldgracebeamstate = 0; int newgracebeamstate = 0; int graceQ = 0; // true if a grace note rhythm int lastgraceQ = 0; PerlRegularExpression pre; int li; int i, j; for (li=0; li\n"; } switch (infile[i].getType()) { case E_humrec_data: // deal with containers lastgraceQ = graceQ; graceQ = pre.search(infile[i][j], "Q", "i"); if ((graceQ == 0) && (lastgraceQ != 0) && (newgracebeamstate != 0)) { // turn of a hanging gracenote beam Indent(out, indent + --bindent); out << "\n"; } if (graceQ) { // grace note or rest oldgracebeamstate = newgracebeamstate; newgracebeamstate += getBeamAdjustment(infile[i][j]); if (newgracebeamstate < 0) { newgracebeamstate = 0; } if ((newbeamstate > 0) && (oldbeamstate == 0)) { Indent(out, indent + bindent++); out << "\n"; } printKernData(indent + bindent, out, infile, i, j, layerindex); if ((newbeamstate == 0) && (oldbeamstate > 0)) { Indent(out, indent + --bindent); out << "\n"; } } else { // regular note or rest oldbeamstate = newbeamstate; newbeamstate += getBeamAdjustment(infile[i][j]); if (newbeamstate < 0) { newbeamstate = 0; } if ((newbeamstate > 0) && (oldbeamstate == 0)) { Indent(out, indent + bindent++); out << "\n"; } printKernData(indent + bindent, out, infile, i, j, layerindex); if ((newbeamstate == 0) && (oldbeamstate > 0)) { Indent(out, indent + --bindent); out << "\n"; } } break; case E_humrec_interpretation: if (strstr(infile[i][j], "*clef") != NULL) { out << "\n"; } else if (strstr(infile[i][j], "*k[") != NULL) { // out << "\n"; } else if (pre.search(infile[i][j], "^\\*M\\d+/\\d+")) { out << "\n"; } break; default: Indent(out, indent); out << "\n"; } } if (newbeamstate != 0) { Indent(out, indent); out << "\n"; Indent(out, --indent); out << "\n"; } if (newgracebeamstate != 0) { Indent(out, indent); out << "\n"; Indent(out, --indent); out << "\n"; } } ////////////////////////////// // // printKernData -- print a note, a chord, or a rest // void printKernData(int indent, SSTREAM& out, HumdrumFile& infile, int row, int col, int layerindex) { int k; int subcount; char buffer[128] = {0}; if (strchr(infile[row][col], 'r') != NULL) { printRest(indent, out, infile[row][col], row, col, -1, layerindex); } else if (strchr(infile[row][col], ' ') != NULL) { Indent(out, indent++); out << "\n"; subcount = infile[row].getTokenCount(col); for (k=0; k\n"; } else { printNote(indent, out, infile[row][col], row, col, -1, layerindex); } } ////////////////////////////// // // printRest -- convert a Humdrum **kern rest in to an MEI rest. // void printRest(int indent, SSTREAM& out, const char* string, int i, int j, int k, int layerindex) { if (string == NULL) { return; } if (debugQ) { Indent(out, indent); out << "\n"; } Indent(out, indent); out << "= 0) { out << "_" << k; } out << "\""; // print rhythm information ///////////////////////////////////////// PerlRegularExpression pre; if (pre.search(string, "Q", "i")) { // deal with grace note identification here } if (pre.search(string, "(\\d+)")) { int durval = strtol(pre.getSubmatch(1), NULL, 10); if (strcmp(pre.getSubmatch(), "0") == 0) { out << " dur=\"breve\""; } else if (strcmp(pre.getSubmatch(), "00") == 0) { out << " dur=\"long\""; } else if (durval > 0) { //int visdur = int(pow(2.0, // (int(log((double)durval)/log(2.0))+0.00000001))); int visdur = int(pow(2.0, int(log((double)durval)/log(2.0)+0.001) )); out << " dur=\"" << visdur << "\""; } } if (pre.search(string, "(\\.)")) { int dotcount = strlen(pre.getSubmatch(1)); if ((dotcount >= 0) && (dotcount <= 4)) { // allowed range for dots in MEI 1.9b out << " dots=\"" << dotcount << "\""; } } out << "/>\n"; } ////////////////////////////// // // printNote -- convert a Humdrum **kern note in to an MEI note. // void printNote(int indent, SSTREAM& out, const char* string, int i, int j, int k, int layerindex) { if (string == NULL) { return; } if (strcmp(string, ".") == 0) { return; } if (debugQ) { Indent(out, indent); out << "\n"; } Indent(out, indent++); out << "= 0) { out << "_" << k; } out << "\""; PerlRegularExpression pre; char pname = 'c'; if (pre.search(string, "([A-G])", "i")) { pname = tolower(pre.getSubmatch(1)[0]); } else { // kern data can contains rhythms with no pitches, but // disallow this case for now Indent(out, indent); out << "\n"; return; } // print pname (diatonic pitch class) attribute out << " pname=\"" << pname << "\""; // print accidental attribute: if (pre.search(string, "([#-n]+)")) { if (strcmp(pre.getSubmatch(1), "##") == 0) { out << " accid=\"ss\""; } else if (strcmp(pre.getSubmatch(), "#") == 0) { out << " accid=\"s\""; } else if (strcmp(pre.getSubmatch(), "--") == 0) { out << " accid=\"ff\""; } else if (strcmp(pre.getSubmatch(), "-") == 0) { out << " accid=\"f\""; } else if (strcmp(pre.getSubmatch(), "n") == 0) { out << " accid=\"n\""; } } // print octave attribute: int octave = Convert::kernToBase40(string) / 40; if (octave >= 0) { out << " oct=\"" << octave << "\""; } // print rhythm information ///////////////////////////////////////// if (pre.search(string, "Q", "i")) { // deal with grace note identification here } if (pre.search(string, "(\\d+)")) { int durval = strtol(pre.getSubmatch(1), NULL, 10); if (strcmp(pre.getSubmatch(), "0") == 0) { out << " dur=\"breve\""; } else if (strcmp(pre.getSubmatch(), "00") == 0) { out << " dur=\"long\""; } else if (durval > 0) { int visdur = int(pow(2.0, int(log((double)durval)/log(2.0)+0.001) )); out << " dur=\"" << visdur << "\""; } } if (pre.search(string, "(\\.)")) { int dotcount = strlen(pre.getSubmatch(1)); if ((dotcount >= 0) && (dotcount <= 4)) { // allowed range for dots in MEI 1.9b out << " dots=\"" << dotcount << "\""; } } //////////////////////////////////////////////////////////////////// // print tie information if (strchr(string, '[') != NULL) { out << " tie=\"i\""; } else if (strchr(string, '_') != NULL) { out << " tie=\"m\""; } else if (strchr(string, ']') != NULL) { out << " tie=\"t\""; } // print fermata attribute: if (strchr(string, ';') != NULL) { if (layerindex == 0) { out << " fermata=\"above\""; } else { out << " fermata=\"below\""; } } int articulationQ = 0; // print articulation marks here, such as staccato if (articulationQ == 0) { out << "/>\n"; indent--; } else { Indent(out, --indent); out << "\n"; } } ////////////////////////////// // // getBeamAdjustment -- counts the difference in L and J beam start/end // markers. // int getBeamAdjustment(const char* token) { int output = 0; if (token == NULL) { return output; } int i = 0; while (token[i] != '\0') { switch (token[i]) { case 'L': output++; break; case 'J': output--; break; } i++; } return output; } ////////////////////////////// // // getLayerItems -- // void getLayerItems(Array >& layeritems, HumdrumFile& infile, int staffindex, Array& ptrack, int layerindex, Array& minfo, int mindex, int start, int stop) { layeritems.setSize(1000); layeritems.setGrowth(1000); layeritems.allowGrowth(1); int lindex = 0; PerlRegularExpression pre; int i, j; int lcounter; for (i=start; i<=stop; i++) { lcounter = 0; // global comments stored only in first staff, first layer if (infile[i].isGlobalComment() && (layerindex == 0) && (staffindex == 0)) { addElementToList(layeritems, lindex++, i, 0); continue; } if (infile[i].isBibliographic()) { // bibliographic records should already have been processed. continue; } // don't search current line for layer information if it has // already been determined that there is no layer information // on that line (excluding null tokens). if (layerindex < minfo[i].layers[staffindex]-1) { continue; } // tandem interpretations only stored on first layer of staff if (infile[i].isInterpretation() && (layerindex == 0)) { j = getLayerFieldIndex(ptrack[staffindex], layerindex, i, infile); if (j < 0) { continue; } if (pre.search(infile[i][j], "^\\*clef")) { // store a clef change addElementToList(layeritems, lindex++, i, j); } else if (pre.search(infile[i][j], "^\\*k\\[.*\\]")) { // store key change addElementToList(layeritems, lindex++, i, j); } continue; } if (infile[i].isLocalComment()) { j = getLayerFieldIndex(ptrack[staffindex], layerindex, i, infile); if (j < 0) { continue; } if (!pre.search(infile[i][j], "^!\\s*$")) { // store a non-empty local comment for the layer addElementToList(layeritems, lindex++, i, j); } } if (infile[i].isData()) { j = getLayerFieldIndex(ptrack[staffindex], layerindex, i, infile); if (j < 0) { continue; } if (strcmp(infile[i][j], ".") == 0) { continue; } else { addElementToList(layeritems, lindex++, i, j); } } } layeritems.setSize(lindex); layeritems.allowGrowth(0); } ////////////////////////////// // // getLayerFieldIndex -- return the spine index on the given line // in the Humdrum file which matches the primary track and layer index. // Returns -1 if the requested track/layer was not found. // int getLayerFieldIndex(int primary, int lindex, int line, HumdrumFile& infile) { int layercounter = 0; int j; for (j=0; j >& layeritems, int lindex, int line, int spine) { layeritems[lindex].setSize(2); layeritems[lindex].allowGrowth(0); layeritems[lindex][0] = line; layeritems[lindex][1] = spine; } ////////////////////////////// // // printBarlineStyle -- // BAR_NONE // BAR_SINGLE single // BAR_END end // BAR_RPTSTART rptstart // BAR_RPTEND rptend // BAR_RPTBOTH rptboth // BAR_INVIS invis // BAR_DBL dbl // void printBarlineStyle(SSTREAM& out, int stylecode) { switch (stylecode) { case BAR_SINGLE: out << "single" ;break; case BAR_END: out << "end" ;break; case BAR_RPTSTART: out << "rptstart" ;break; case BAR_RPTEND: out << "rptend" ;break; case BAR_RPTBOTH: out << "rptboth" ;break; case BAR_INVIS: out << "invis" ;break; case BAR_DBL: out << "dbl" ;break; } } ////////////////////////////// // // printScoreSection -- // //
// section/@id = name of section // void printScoreSection(int indent, SSTREAM& out, HumdrumFile& infile, Array& sections, int sindex) { Indent(out, indent); out << "\\s*([^\\[\\]]+)\\s*$")) { out << " " << xmlscope << "id=\""; printAsCdata(out, pre.getSubmatch(1)); out << "\""; } out << ">\n"; int startline = sections[sindex]; int stopline = -1; if (sindex >= sections.getSize()-1) { stopline = infile.getNumLines()-1; } else { stopline = sections[sindex+1]-1; } printSingleSection(indent+1, out, infile, startline, stopline); Indent(out, indent); out << "
\n"; } ////////////////////////////// // // getSectionInfo -- identify labeled segments in the music. // If no labeled segements, then there is a single segment // for all of the music (and that single segment should not // be placed inside of a marker. // void getSectionInfo(Array& sections, HumdrumFile& infile) { int i; int dataline = -1; PerlRegularExpression pre; sections.setSize(100); sections.setSize(0); sections.setGrowth(100); for (i=0; i[^\\[\\]]+$")) { sections.append(i); } } } ////////////////////////////// // // printMdivScoreScoredef -- // // // (timeline*, chordtable?, symboltable?, keysig?, pghead1?, // pghead2?, pgfoot1?, pgfoot2?, (staffgrp? | staffdef?)) // // Container for score meta-information. // // Score-level encoding strategies for: // // a) alternating meter sig, e.g. 2/4 3/4 in alternating measures (Read, // p. 164-165) and combined meters (Read, p.166-168): explicitly // encode meters, make them invisible, display both meter sigs at the // start of the section // b) compound meter sig, e.g. 2+3+2/4 (Read, p. 168-170): set // meter.count=2+3+2 // c) polymeters, e.g. different simultaneous meters (Read, p. 170-173): // 1. where barlines coincide, use beaming to elucidate the polymeter // 2. where barlines sometimes coincide, break into measures // according to a common unit of time, draw barlines where visually // required // 3. where barlines never coincide, encode as parts only // d) mixed meter sig, e.g. 2/4 + 3/16 in the same measure (Read, p. // 173-174): encode in common time base, e.g. 11/16, make meter // invisible, display both meter sigs at the start of the measure // e) fractional meter sig, e.g. 3.5/4 (Read, p. 175-177): // set meter.count=3.5 // The beat count may be displayed as a fraction or as its decimal // equivalent. // // // Attribute Type Value // beam.group CDATA #IMPLIED // beam.rests true|false #IMPLIED // clef.line CDATA #IMPLIED // clef.shape G|GG|F|C|perc|TAB #IMPLIED // clef.trans 8va|8vb|15va #IMPLIED // dur.default long|breve|1|2|4|8|16|32|64|128|256|512|1024|2048 // |maxima|longa|brevis|semibrevis|minima|semiminima| // fusa|semifusa #IMPLIED // id ID #IMPLIED // key.accid s|f|ss|ff|n #IMPLIED // key.mode major|minor|dorian|phrygian|lydian| // mixolydian|aeolian|locrian #IMPLIED // key.pname a|b|c|d|e|f|g #IMPLIED // key.sig.mixed CDATA #IMPLIED // key.sig 7f|6f|5f|4f|3f|2f|1f|0|1s|2s|3s|4s|5s|6s|7s|mixed // #IMPLIED // meter.count CDATA #IMPLIED // meter.sym common|cut #IMPLIED // meter.unit CDATA #IMPLIED // modusmaior [2-3] #IMPLIED // modusminor [2-3] #IMPLIED // n NMTOKEN #IMPLIED // num CDATA #IMPLIED // numbase CDATA #IMPLIED // octave.default [0-9] #IMPLIED // prolatio [2-3] #IMPLIED // proport.num CDATA #IMPLIED // proport.numbase CDATA #IMPLIED // source IDREFS #IMPLIED // tempus [2-3] #IMPLIED // trans.diat CDATA #IMPLIED // trans.semi CDATA #IMPLIED // void printMdivScoreScoredef(int indent, SSTREAM& out, HumdrumFile& infile) { Indent(out, indent); out << "\n"; printScoredefStaffgrp(indent+1, out, infile); printTempExpandRules(indent+1, out, infile); Indent(out, indent); out << "\n"; } /////////////////////////////// // // printTempExpandRules -- print section expansion rules // void printTempExpandRules(int indent, SSTREAM& out, HumdrumFile& infile) { int i; PerlRegularExpression pre; Array buffer; int len; for (i=0; i([^\\[]*)\\[([^\\]]+)\\]$")) { Indent(out, indent); out << "\n"; } } } ////////////////////////////// // // printScoredefStaffgrp -- list of staves found in the music. // staffgrp/@barthru = true if a barline goes through all staves // staffgrp/@symbol = brace // staffgrp/@lable.full = string to place to left of first staff on // first system. // void printScoredefStaffgrp(int indent, SSTREAM& out, HumdrumFile& infile) { if (PTRACK.getSize() < 1) { return; } Indent(out, indent); out << "\n"; int i; for (i=0; i\n"; } ////////////////////////////// // // getStaffCount -- count the number of **kern spines on // the first instance of exclusive interpretations. // void getStaffCount(Array& primarytracks, HumdrumFile& infile) { primarytracks.setSize(100); primarytracks.setSize(0); primarytracks.setGrowth(100); int i, j; int track; for (i=0; i& pt = primarytracks; int tempval; for (i=0; i& tracks, int index) { Indent(out, indent); out << "\n"; } ////////////////////////////// // // printIntialClef -- print the initial clef of the // specified primary track spine. // clef.line = what staffline the cleff is on // clef.shape = G, GG, F, C, perc, TAB // clef.trans = 8va, 8vb, 15va // // Types of **kern *clef's: // G G clef (as used, for example in the treble staff) // F F clef (as used, for example in the bass staff) // C C clef (as used, for example in the alto staff) // X percussion clef // - explicit indication that clef is absent // 1 first (lowest) line is designated by the pitch of the clef // 2 second (from bottom) line is designated by the pitch of the clef // 3 third (from bottom) line is designated by the pitch of the clef // 4 fourth (from bottom) line is designated by the pitch of the clef // 5 fifth (highest) line is designated by the pitch of the clef // v = 8va bassa (played one octave higher) // ^ = 8va treble (played one octave lower) // ^^ double octave treble (played two octaves higher) // vv double octave bass (played two octaves lower) // void printInitialClef(SSTREAM& out, HumdrumFile& infile, int ptrack) { int i, j; const char* clef = NULL; PerlRegularExpression pre; for (i=0; i. // Attributes which describe the musical key are: // @pname = diatonic pitch name // @accid = accidental to apply to pitch name // @mode = mode of key: major, minor, other mode // void printMeiKeyAttributes(SSTREAM& out, const char* key) { if (key != NULL) { PerlRegularExpression pre; pre.search(key, "^\\*([A-G])([#-]?):(.*)", "i"); char pname = pre.getSubmatch(1)[0]; out << " key.pname=\"" << (char)tolower(pname) << "\""; char accid = pre.getSubmatch(2)[0]; switch (accid) { case '#': accid = 's'; break; case '-': accid = 'f'; break; default: accid = 'n'; } out << " key.accid=\"" << accid << "\""; char mode[32] = {0}; if (strlen(pre.getSubmatch(3)) == 3) { if (strcmp(pre.getSubmatch(), "mix") == 0) { strcpy(mode, "mixolydian"); } else if (strcmp(pre.getSubmatch(), "dor") == 0) { strcpy(mode, "dorian"); } else if (strcmp(pre.getSubmatch(), "phr") == 0) { strcpy(mode, "phrygian"); } else if (strcmp(pre.getSubmatch(), "lyd") == 0) { strcpy(mode, "lydian"); } else if (strcmp(pre.getSubmatch(), "aeo") == 0) { strcpy(mode, "aeolian"); } else if (strcmp(pre.getSubmatch(), "loc") == 0) { strcpy(mode, "locrian"); } else if (isupper(pname)) { strcpy(mode, "major"); } else { strcpy(mode, "minor"); } } else { if (isupper(pname)) { strcpy(mode, "major"); } else { strcpy(mode, "minor"); } } out << " key.mode=\"" << mode << "\""; } } ////////////////////////////// // // printMeiKeySignatureAttributes -- convert **kern signature into // and MEI key signature. Assumes that the order of the pitches // in *k[] are standard and consecutive. // void printMeiKeySignatureAttributes(SSTREAM& out, const char* keysig) { if (keysig != NULL) { int count = 0; int len = strlen(keysig); int i; for (i=0; i 0) { out << "s"; } else if (count < 0) { out << "f"; } out << "\""; } } ////////////////////////////// // // printInitialMeterSignature -- // @meter.count == numerator of key signature // @meter.unit == demoninator of key signature // @meter.sym == cut time or common time symbol // void printInitialMeterSignature(SSTREAM& out, HumdrumFile& infile) { int i, j; const char* metersig = NULL; const char* metstring = NULL; PerlRegularExpression pre; for (i=0; i limit) { return; } for (i=0; i': out << ">"; break; case '<': out << "<"; break; case '\"': out << """; break; // case '\'': out << "'"; break; default: out << string[i]; } i++; } } ////////////////////////////// // // example -- example function calls to the program. // void example(void) { } ////////////////////////////// // // usage -- command-line usage description and brief summary // void usage(const char* command) { } /* <Composer> <Editor> <VoiceData> <NumVoices> <Voice> <Name> <EventList> <Clef> <Mensuration> <OriginalText> <Note> <Type> <Length> <LetterName> <OctaveNum> <ModernText> <Syllable> <WordEnd> <Dot> <StaffLoc> <Rest> <Type> <Length> <BottomStaffLine> <NumSpaces> <Custos> <LineEnd> <MiscItem> <Barline> */ // md5sum: d26c3f0616d08f3b00d920ae33fe611c hum2cmme.cpp [20110304]