// // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 11 13:26:47 PDT 2012 // Last Modified: Sat Aug 11 13:26:51 PDT 2012 // Filename: ...sig/examples/all/scr2hum.cpp // Web Address: http://sig.sapp.org/examples/museinfo/score/scr2hum.cpp // Syntax: C++; museinfo // // Description: Display staff information for a SCORE page file. // #include "ScorePageSet.h" #include "Options.h" #include "Convert.h" #include "HumdrumFile.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 makeBarline (ScorePageSet& work, int i, HumdrumRecord& barline); void setBarlineStyle (HumdrumRecord& barline, int staffidx, ScoreRecord& arecord); void printStartingBar (ScorePageSet& work, HumdrumRecord& barline, HumdrumFile& newfile); void printMeter (ScorePageSet& work, HumdrumRecord& meter, HumdrumFile& newfile, int objidx, double hpos, Array& kernstart); void printTempoNear (ScorePageSet& work, HumdrumRecord& tempoline, HumdrumFile& newfile, int objidx, double hpos, Array& kernstart); void convertScoreMeterToKernMeter(char* buffer, ScoreRecord& srecord); void printKeySignature (ScorePageSet& work, HumdrumRecord& keysigline, HumdrumFile& newfile, int objidx, double hpos, Array& keysig, Array& kernstart); int convertScoreKeysigToKernKeysig(char* buffer, ScoreRecord& srecord); void convertScoreClefToKernClef(char* buffer, ScoreRecord& srecord); void printClef (ScorePageSet& work, HumdrumRecord& clefline, HumdrumFile& newfile, int objidx, double hpos, Array >& clefs, Array& kernstart); void printTitle (ScorePageSet& work, HumdrumFile& newfile); void printComposer (ScorePageSet& work, HumdrumFile& newfile); void printInstruments (ScorePageSet& work, HumdrumFile& newfile, HumdrumRecord& instruments, Array& kernstart); void getInstrumentCode (Array& code, Array& name); void getInstrumentAbbreviation(Array& code, Array& name); int getPrettyScoreText (Array& textdata, ScoreRecord& arecord); int getPrettyScoreText (Array& textdata); void setHeaderRecord (HumdrumRecord& header, Array& kernstart, Array& kerncount, Array& dynamstart, Array& dynamcount, Array& versestart, Array& versecount); void setStaffAssignmentRecord(HumdrumRecord& staffassignment, Array& kernstart, Array& kerncount, Array& dynamstart, Array& dynamcount, Array& versestart, Array& versecount); void extractLyrics (ScorePageSet& work, int item, HumdrumRecord& dataline, Array& versestart, Array& versecount); void getNoteVerseLinks (Array& verses, ScorePageSet& work, int witem); // interface variables: Options options; int verboseQ = 0; // used with -v option int debugQ = 0; // used with --debug option int invisibleQ = 1; // used with -I option int stemQ = 1; // used with --no-stems int plainQ = 0; // used with -p option int htmlQ = 1; int lyricsQ = 1; // used with -L option int dynamQ = 0; // not used yet ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { checkOptions(options, argc, argv); int i; ScorePageSet work; for (i=1; i<=options.getArgCount(); i++) { work.appendRead(options.getArg(i), verboseQ); } work.analyzeContent(); char buffer[1024] = {0}; HumdrumFile newfile; HumdrumRecord header; HumdrumRecord staffassignment; HumdrumRecord trailer; HumdrumRecord barline; HumdrumRecord dataline; HumdrumRecord meterline; HumdrumRecord tempoline; HumdrumRecord keysigline; HumdrumRecord clefline; HumdrumRecord instruments; int sysstaffcount = work.getSystemStaffCount(); int sysStaffIdx; int versesum = 0; Array versecount(sysstaffcount); versecount.setAll(0); if (lyricsQ) { for (i=0; i dynamcount(sysstaffcount); dynamcount.setAll(0); Array dynamstart(sysstaffcount); dynamstart.setAll(-1); // starting spine index for start of track's dynams Array versestart(sysstaffcount); versestart.setAll(-1); // starting spine index for start of track's verses int kernsum = sysstaffcount; Array kerncount(sysstaffcount); kerncount.setAll(1); // not allowing spine splits for now... Array kernstart(sysstaffcount); kernstart.setAll(-1); // starting spine index for start of track's notes int allsum = versesum + dynamsum + kernsum; int currtrack = 0; for (i=0; i keysig(sysstaffcount); keysig.setAll(-100); Array > clefs(allsum); for (i=0; i 0) && (strncmp(newfile[newfile.getNumLines()-1][0], "=", 1) != 0)) { newfile.appendLine(barline); } barline.setAllFields("="); emmitbarline = 0; } lastbarbeat = absBeat; } if ((fabs(hpos - lastkeysighpos) > 0.01) && (work.getItem(i).isKeysigItem())) { printKeySignature(work, keysigline, newfile, i, hpos, keysig, kernstart); lastkeysighpos = hpos; } // why is this after keysig? if ((fabs(hpos - lastclefhpos) > 0.01) && (work.getItem(i).isClefItem())) { printClef(work, clefline, newfile, i, hpos, clefs, kernstart); lastclefhpos = hpos; } if ((fabs(hpos - lastmeterhpos) > 0.01) && (work.getItem(i).isMeterItem())) { printMeter(work, meterline, newfile, i, hpos, kernstart); printTempoNear(work, tempoline, newfile, i, hpos, kernstart); lastmeterhpos = hpos; } if (!(work.getItem(i).hasDuration())) { continue; } lastmeterhpos = -1; lastkeysighpos = -1; lastclefhpos = -1; if (!dataQ) { printStartingBar(work, barline, newfile); dataQ = 1; } if ((absBeat != lastAbsBeat) && (lastAbsBeat >= 0)) { if (!(dataline.equalFieldsQ() && (strcmp(dataline[0], ".") == 0))) { newfile.appendLine(dataline); } if (emmitbarline) { if (work.isAtEnd(i)) { barline.setAllFields("=="); } newfile.appendLine(barline); emmitbarline = 0; barline.setAllFields("="); } dataline.setAllFields("."); } lastAbsBeat = absBeat; token[0] = '\0'; sysStaffIdx = work.getSystemStaffIndex(i); if (work.getItem(i).hasTieStart()) { strcat(token, "["); } Convert::durationToKernRhythm(buffer, work.getItem(i).getDuration()); strcat(token, buffer); if (work.getItem(i).getPitch() <= 0) { strcat(token, "r"); } else { Convert::base40ToKern(buffer, work.getItem(i).getPitch()); strcat(token, buffer); } // if the note has a printed accidental which is predictable even if // the printed accidental was there or not, then it is a cautionary // accidental. The pitch analysis stage marks cautionary accidentals // by setting the named parameter "cautionary" to non-zero (1). if (work.getItem(i).hasCautionary()) { strcat(token, "X"); } // print articulations p11 = work.getItem(i).getValue(P11); if (abs(p11) == 1) { // editorial flat if (strchr(token, '-') == NULL) { strcat(token, "-"); } strcat(token, "i"); haseditorial = 1; } else if (abs(p11) == 2) { // editorial sharp if (strchr(token, '#') == NULL) { strcat(token, "#"); } strcat(token, "i"); haseditorial = 1; } else if (abs(p11) == 3) { // editorial natural if (strchr(token, 'n') == NULL) { strcat(token, "n"); } strcat(token, "i"); haseditorial = 1; } else if (abs(p11) == 14) { // fermata strcat(token, ";"); } if (stemQ) { stemdir = work.getItem(i).getStemDirection(); if (stemdir > 0) { strcat(token, "/"); } else if (stemdir < 0) { strcat(token, "\\"); } } if (work.getItem(i).hasTieEnd()) { strcat(token, "]"); } else if (work.getItem(i).hasTieContinue()) { strcat(token, "_"); } dataline.changeField(kernstart[sysStaffIdx], token); if (lyricsQ) { extractLyrics(work, i, dataline, versestart, versecount); } } if (emmitbarline) { // no longer active barline.setAllFields("=="); newfile.appendLine(barline); emmitbarline = 0; } newfile.appendLine(trailer); if (haseditorial) { newfile.appendLine("!!!RDF**kern: i=editorial accidental"); } cout << newfile; return 0; } ////////////////////////////// // // printStartingBar -- // void printStartingBar(ScorePageSet& work, HumdrumRecord& barline, HumdrumFile& newfile) { // check to see if a pickup measure, if so, then don't print anything // otherwise, print an invisible barline // for now, just print an invisible barline all of the time. barline.setAllFields("=-"); newfile.appendLine(barline); } ////////////////////////////// // // makeBarline -- // void makeBarline(ScorePageSet& work, int index, HumdrumRecord& barline) { // just do a simple barline for now without any style adjustments barline.setAllFields("="); int i; double absbeat = work.getAbsBeat(index); for (i=index; i=0; i--) { if (work.getAbsBeat(i) != absbeat) { break; } if (!work.getItem(i).isBarlineItem()) { continue; } setBarlineStyle(barline, work.getSystemStaffIndex(i), work.getItem(i)); } } ////////////////////////////// // // setBarlineStyle -- // void setBarlineStyle(HumdrumRecord& barline, int staffidx, ScoreRecord& arecord) { int partialQ = 0; int barnum = -1; if ((arecord.getValue(P10) > 3) && (arecord.getValue(P11) < 11)) { partialQ = 1; } if (arecord.hasValue("barnum")) { barnum = arecord.getValue("barnum"); } char buffer[1024] = {0}; if (barnum >=0) { sprintf(buffer, "=%d", barnum); } else { strcat(buffer, "="); } if (partialQ) { strcat(buffer, "'"); } barline.changeField(staffidx, buffer); } ////////////////////////////// // // printClef -- // void printClef(ScorePageSet& work, HumdrumRecord& clefline, HumdrumFile& newfile, int objidx, double hpos, Array >& clefs, Array& kernstart) { clefline.setAllFields("*"); int staffidx; int i; int foundQ = 0; double h; char buffer[1024] = {0}; for (i=objidx; i& keysig, Array& kernstart) { keysigline.setAllFields("*"); int staffidx; int i; int foundQ = 0; double h; int keystate; char buffer[1024] = {0}; for (i=objidx; i 1.0) { // if key sigantures are not vertically aligned enough, they will // be printed on separte lines. continue; } staffidx = work.getItem(i).getSystemStaffIndex(); keystate = convertScoreKeysigToKernKeysig(buffer, work.getItem(i)); if (keysig[staffidx] == keystate) { // the new key signature is the same as the previous one // so ignore the new key signature (since it is probably at // the start of a new system). continue; } else { keysig[staffidx] = keystate; } if (strcmp(buffer, "*") != 0) { foundQ = 1; } keysigline.changeField(kernstart[staffidx], buffer); } if (foundQ) { for (i=0; i& kernstart) { int ssidx = work.getItem(objidx).getPageSystemIndex(); int tssidx; int thpos; ScoreRecord* srecord = NULL; double limiting = 20.0; // maximum before/after search range on staff to look for tempo double tempofound = -1; double tempohpos = -1; int i; // search forward for a tempo indication on page for (i=objidx; igetPageSystemIndex(); if (tssidx != ssidx) { break; } thpos = srecord->getHpos(); if (fabs(thpos - hpos) > limiting) { break; } if (!srecord->isTextItem()) { continue; } if (srecord->getValue("tempo") > 0.0) { tempofound = i; tempohpos = thpos; break; } } // search backward for a tempo indication on page for (i=objidx; i>=0; i--) { srecord = &(work.getItem(i)); tssidx = srecord->getPageSystemIndex(); if (tssidx != ssidx) { break; } thpos = srecord->getHpos(); if (fabs(thpos - hpos) > limiting) { break; } if (!srecord->isTextItem()) { continue; } if (srecord->getValue("tempo") > 0.0) { if (fabs(thpos - hpos) < fabs(tempohpos - hpos)) { tempofound = i; tempohpos = thpos; } break; } } if (tempofound <= 0) { return; } char buffer[1024] = {0}; tempoline.setAllFields("*"); sprintf(buffer, "*MM%d", (int)work.getItem(tempofound).getValue("tempo")); for (i=0; i& kernstart) { meter.setAllFields("*"); int staffidx; int i; int foundQ = 0; double h; char buffer[1024] = {0}; for (i=objidx; i 1.0) { // if time sigantures are not vertically aligned enough, they will be printed on // separte lines. continue; } staffidx = work.getItem(i).getSystemStaffIndex(); convertScoreMeterToKernMeter(buffer, work.getItem(i)); if (strcmp(buffer, "*") != 0) { foundQ = 1; } meter.changeField(kernstart[staffidx], buffer); } if (foundQ) { newfile.appendLine(meter); } } ////////////////////////////// // // convertScoreClefToKernClef -- not dealing with all P4!=0 possibilities yet. // void convertScoreClefToKernClef(char* buffer, ScoreRecord& srecord) { int p5int = srecord.getValue(P5); double frac = srecord.getValue(P5) - p5int; if (frac < 0) { frac = -frac; } int octave = int(frac * 10.0 + 0.490); int p4 = srecord.getValue(P4); strcpy(buffer, ""); if (octave == 0) { switch (p5int) { case 0: strcpy(buffer, "*clefG2"); return; case 1: if (p4 == 0) { strcpy(buffer, "*clefF4"); // bass clef } else if (p4==-2) { strcpy(buffer, "*clefF3"); // bariton clef } return; case 2: if (p4 == 0) { strcpy(buffer, "*clefC3"); // alto clef } else if (p4 == -4) { strcpy(buffer, "*clefC1"); // soprano clef } else if (p4 == -2) { strcpy(buffer, "*clefC2"); // mezzo-soprano clef } return; case 3: strcpy(buffer, "*clefC4"); return; // tenor clef case 4: strcpy(buffer, "*clefX"); return; } } else { switch (p5int) { case 0: strcpy(buffer, "*clefGv2"); // vocal tenor clef return; case 1: strcpy(buffer, "*clefFv2"); // bass down clef return; } } } ////////////////////////////// // // convertScoreKeysigToKernKeysig -- // int convertScoreKeysigToKernKeysig(char* buffer, ScoreRecord& srecord) { int p5 = srecord.getValue(P5); if ((p5 > 100) || (p5 <= -100)) { // ignoring cancellation key signatures for now... strcpy(buffer, "*"); return 0; } switch (p5) { case 0: strcpy(buffer, "*k[]"); return 0; case 1: strcpy(buffer, "*k[f#]"); return 1; case 2: strcpy(buffer, "*k[f#c#]"); return 2; case 3: strcpy(buffer, "*k[f#c#g#]"); return 3; case 4: strcpy(buffer, "*k[f#c#g#d#]"); return 4; case 5: strcpy(buffer, "*k[f#c#g#d#a#]"); return 5; case 6: strcpy(buffer, "*k[f#c#g#d#a#e#]"); return 6; case 7: strcpy(buffer, "*k[f#c#g#d#a#e#b#]"); return 7; case -1: strcpy(buffer, "*k[b-]"); return -1; case -2: strcpy(buffer, "*k[b-e-]"); return -2; case -3: strcpy(buffer, "*k[b-e-a-]"); return -3; case -4: strcpy(buffer, "*k[b-e-a-d-]"); return -4; case -5: strcpy(buffer, "*k[b-e-a-d-g-]"); return -5; case -6: strcpy(buffer, "*k[b-e-a-d-g-c-]"); return -6; case -7: strcpy(buffer, "*k[b-e-a-d-g-c-f-]"); return -7; } // shouldn't get here strcpy(buffer, "*"); return 0; } ////////////////////////////// // // convertScoreMeterToKernMeter -- // void convertScoreMeterToKernMeter(char* buffer, ScoreRecord& srecord) { int p5 = srecord.getValue(P5); int p6 = srecord.getValue(P6); int p8 = srecord.getValue(P8); int p9 = srecord.getValue(P9); if (p8 != 0) { if (p9 != 0) { sprintf(buffer, "*M%d/%d/+%d/%d", p5, p6, p8, p9); return; } else { sprintf(buffer, "*M%d+%d/%d", p5, p8, p6); return; } } if ((p5==99) && (p6==1)) { strcpy(buffer, "*met(c)"); return; } if ((p5==98) && (p6==1)) { strcpy(buffer, "*met(c|)"); return; } if ((p5!=0) && (p6!=0)) { sprintf(buffer, "*M%d/%d", p5, p6); return; } if ((p5==0) && (p6!=0)) { sprintf(buffer, "*M%d", p6); return; } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("v|verbose=b", "verbose display of information"); opts.define("I|no-invisible=b", "do not dispay invisible rests"); opts.define("S|no-stems=b", "do not dispay note stems"); opts.define("p|plain=b", "display SCORE text as plain ASCII"); opts.define("L|no-lyrics=b", "do not display lyrcs"); opts.define("debug=b"); // determine bad input line num 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, Jul 2012" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 29 Jul 2012" << endl; cout << "compiled: " << __DATE__ << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } verboseQ = opts.getBoolean("verbose"); debugQ = opts.getBoolean("debug"); invisibleQ = !opts.getBoolean("no-invisible"); stemQ = !opts.getBoolean("no-stems"); plainQ = opts.getBoolean("plain"); lyricsQ = !opts.getBoolean("no-lyrics"); htmlQ = !plainQ; } ////////////////////////////// // // 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; } ////////////////////////////// // // printTitle -- // void printTitle(ScorePageSet& work, HumdrumFile& newfile) { Array title; work.getTitle(title); getPrettyScoreText(title); PerlRegularExpression pre; char buffer[1024] = {0}; if (title.getSize() > 1) { strcpy(buffer, "!!!OTL: "); pre.sar(title, "_\\d\\d", "", "g"); strcat(buffer, title.getBase()); newfile.appendLine(buffer); } } ////////////////////////////// // // printComposer -- // void printComposer(ScorePageSet& work, HumdrumFile& newfile) { Array composer; work.getComposer(composer); PerlRegularExpression pre; pre.sar(composer, "^\\s+", ""); pre.sar(composer, "\\s+$", ""); pre.sar(composer, "\\s+", " "); int spacecount = 0; int commacount = 0; int i; for (i=0; i 1) { pre.sar(composer, "_\\d\\d", "", "g"); if (pre.search(composer, "\\?\\s*$")) { strcpy(buffer, "!!!COA: "); pre.sar(composer, "\\?\\s*$", ""); } else { strcpy(buffer, "!!!COM: "); } if (strcmp(composer.getBase(), "Guillaume Du Fay") == 0) { strcat(buffer, "Du Fay, Guillaume"); } else { strcat(buffer, composer.getBase()); } newfile.appendLine(buffer); if (pre.search(composer, "Du\\s*Fay", "i")) { newfile.appendLine("!!!CDT: ~1397/08/05/-1474/11/27/"); } } } ////////////////////////////// // // printInstruments -- // void printInstruments(ScorePageSet& work, HumdrumFile& newfile, HumdrumRecord& instruments, Array& kernstart) { int staffcount = work.getSystemStaffCount(); instruments.setAllFields("*"); char buffer[1024] = {0}; Array > instrumentnames(staffcount); Array > abbreviations(staffcount); Array > instrumentcodes(staffcount); int instrumentsQ = 0; int i; for (i=0; i 1) { instrumentsQ = 1; } abbreviations[i].setSize(1); abbreviations[i][0] = '\0'; getInstrumentAbbreviation(abbreviations[i], instrumentnames[i]); instrumentcodes[i].setSize(1); instrumentcodes[i][0] = '\0'; getInstrumentCode(instrumentcodes[i], instrumentnames[i]); } if (!instrumentsQ) { return; } for (i=0; i 1) { strcpy(buffer, "*I\""); strcat(buffer, instrumentnames[i].getBase()); instruments.changeField(kernstart[i], buffer); } else { instruments.changeField(kernstart[i], "*"); } } newfile.appendLine(instruments); for (i=0; i 1) { strcpy(buffer, abbreviations[i].getBase()); instruments.changeField(kernstart[i], buffer); } else { instruments.changeField(kernstart[i], "*"); } } newfile.appendLine(instruments); } ////////////////////////////// // // getInstrumentAbbreviation -- // void getInstrumentAbbreviation(Array& code, Array& name) { code.setSize(1); code[0] = '\0'; char buffer[1024] = {0}; char buffer2[1024] = {0}; PerlRegularExpression pre; if (pre.search(name, "^\\s$")) { return; } else if (pre.search(name, "^Superius", "i")) { strcpy(buffer, "*I'S"); } else if (pre.search(name, "^Soprano", "i")) { strcpy(buffer, "*I'S"); } else if (pre.search(name, "^Discantus", "i")) { strcpy(buffer, "*I'D"); } else if (pre.search(name, "^Altus", "i")) { strcpy(buffer, "*I'A"); } else if (pre.search(name, "^Alto", "i")) { strcpy(buffer, "*I'A"); } else if (pre.search(name, "^Tenor", "i")) { strcpy(buffer, "*I'T"); } else if (pre.search(name, "^Tenore", "i")) { strcpy(buffer, "*I'T"); } else if (pre.search(name, "^Contratenor", "i")) { strcpy(buffer, "*I'Ct"); } else if (pre.search(name, "^Contra", "i")) { strcpy(buffer, "*I'C"); } else if (pre.search(name, "^Bassus", "i")) { strcpy(buffer, "*I'B"); } else if (pre.search(name, "^Bass", "i")) { strcpy(buffer, "*I'B"); } else if (pre.search(name, "^Vagans", "i")) { strcpy(buffer, "*I'V"); } else if (pre.search(name, "^Cantus", "i")) { strcpy(buffer, "*I'Ca"); } else { // unknown instrument, put in a dummy strcpy(buffer, "*I'XXX"); } if (pre.search(name, "(\\d+)")) { strcpy(buffer2, pre.getSubmatch(1)); strcat(buffer, buffer2); } int len = strlen(buffer); code.setSize(len+1); strcpy(code.getBase(), buffer); } ////////////////////////////// // // getInstrumentCode -- // void getInstrumentCode(Array& code, Array& name) { } ////////////////////////////// // // getPrettyScoreText -- returns the number of charcters printed // int getPrettyScoreText(Array& textdata, ScoreRecord& arecord) { arecord.getTextDataWithoutFonts(textdata); return getPrettyScoreText(textdata); } ////////////////////////////// // // getPrettyScoreText -- returns the number of charcters printed // int getPrettyScoreText(Array& textdata) { if (plainQ) { ScoreRecord::convertScoreTextToPlainText(textdata); } else if (htmlQ) { ScoreRecord::convertScoreTextToHtmlText(textdata); } return strlen(textdata.getBase()); } ////////////////////////////// // // setStaffAssignmentRecord -- // void setStaffAssignmentRecord(HumdrumRecord& staffassignment, Array& kernstart, Array& kerncount, Array& dynamstart, Array& dynamcount, Array& versestart, Array& versecount) { int current = 0; int i, j; int staffnum; char buffer[1024] = {0}; for (i=0; i& kernstart, Array& kerncount, Array& dynamstart, Array& dynamcount, Array& versestart, Array& versecount) { int current = 0; int i, j; for (i=0; i& versestart, Array& versecount) { PerlRegularExpression pre; int sysstaffidx = work.getSysStaffIndex(item); int j; Array buffer; Array verses(versecount[sysstaffidx]); verses.setAll(-1); getNoteVerseLinks(verses, work, item); for (j=0; j& verses, ScorePageSet& work, int witem) { verses.setAll(-1); int pageidx = work.getItemPage(witem); ScorePage& page = work.getPage(pageidx); int pitem = work.getItemPageIndex(witem); double hpos = page.getItem(pitem).getHpos(); double nextnotehpos = page.getNextNotePositionOnStaff(pitem); double prevnotehpos = page.getPreviousNotePositionOnStaff(pitem); double nextcut = (hpos + nextnotehpos) / 2.0; double prevcut = (hpos + prevnotehpos) / 2.0; // Collect all verse syllables within 1/2 of the distance to the // next/previous note/rest. Only taking the closest syllable from // each verse, however (not all of them). int versenum; int sysidx = page.getSystemIndex(pitem); int staffidx = page.getSystemStaffIndex(pitem); int ssitem = page.getSystemStaffItemIndex(pitem); double thpos; ScoreRecord* srecord; int i; int pstaff = (int)page.getItem(pitem).getValue(P2); int tstaff; Array backwarditem(verses.getSize()); backwarditem.setAll(-1); Array backwardhpos(verses.getSize()); backwardhpos.setAll(-1.0); // search for lyric syllables to the left of a note. for (i=ssitem-1; i>=0; i--) { srecord = &(page.getSysStaffItem(sysidx, staffidx, i)); // check that the staff number has not changed; exit loop otherwise. tstaff = (int)srecord->getValue(P2); if (tstaff != pstaff) { break; } // get horizontal position of item. thpos = srecord->getHpos(); // if it is less than the cutoff horizontal position, exit the loop. if (thpos < prevcut) { break; } // ignore item if it is not a lyric syllable. if (!srecord->isVerse()) { continue; } // if there is an undefined verse number for some strange reason skip it: versenum = srecord->getVerseIndex(); if (versenum < 0) { continue; } // if the verse number is larger than expectd, skip over it as well: if (versenum > verses.getSize()-1) { // strange error continue; } // only keep track of the closest syllable of each verse if (backwarditem[versenum] < 0) { backwarditem[versenum] = srecord->getSetIndex(); backwardhpos[versenum] = thpos; } } Array forwarditem(verses.getSize()); forwarditem.setAll(-1); Array forwardhpos(verses.getSize()); forwardhpos.setAll(-1.0); // search for lyric syllables to the right of a note. for (i=ssitem+1; igetValue(P2); if (tstaff != pstaff) { break; } // get horizontal position of item. thpos = srecord->getHpos(); // if it is greater than the cutoff horizontal position, exit the loop. if (thpos > nextcut) { break; } // ignore item if it is not a lyric syllable. if (!srecord->isVerse()) { continue; } // if there is an undefined verse number for some strange reason skip it: versenum = srecord->getVerseIndex(); if (versenum < 0) { continue; } // if the verse number is larger than expectd, skip over it as well: if (versenum > verses.getSize()-1) { // strange error: verse number larger than expected. continue; } // only keep track of the closest syllable of each verse if (forwarditem[versenum] < 0) { forwarditem[versenum] = srecord->getSetIndex(); forwardhpos[versenum] = thpos; } } double backdist; double foredist; for (i=0; i 0)) { verses[i] = forwarditem[i]; continue; } else if ((backwarditem[i] > 0) && (forwarditem[i] < 0)) { verses[i] = backwarditem[i]; continue; } else if ((backwarditem[i] < 0) && (forwarditem[i] < 0)) { continue; } backdist = fabs(backwardhpos[i] - hpos); foredist = fabs(forwardhpos[i] - hpos); if (backdist < foredist) { verses[i] = backwarditem[i]; } else { verses[i] = forwarditem[i]; } } } // md5sum: 513e0ca6f0325103ff902791bc811bbe scr2hum.cpp [20130206]