From fbbfe3db2245159b3a848335d761d82549aee2ae Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Tue, 30 Jul 2024 01:38:12 -0700 Subject: [PATCH 1/7] Update humlib. --- include/hum/humlib.h | 170 +++-- src/hum/humlib.cpp | 1398 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 1401 insertions(+), 167 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index 6dd3ce528cb..374d43cb064 100644 --- a/include/hum/humlib.h +++ b/include/hum/humlib.h @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Sun Jun 30 19:51:54 WEST 2024 +// Last Modified: Mon Jul 29 23:24:23 PDT 2024 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 @@ -5431,6 +5431,7 @@ int main(int argc, char** argv) { \ infile.readNoRhythm(std::cin); \ } \ int status = interface.run(infile, std::cout); \ + interface.finally(); \ if (interface.hasWarning()) { \ interface.getWarning(std::cerr); \ return 0; \ @@ -5439,7 +5440,6 @@ int main(int argc, char** argv) { \ interface.getError(std::cerr); \ return -1; \ } \ - interface.finally(); \ return !status; \ } @@ -5463,24 +5463,24 @@ int main(int argc, char** argv) { \ bool status = true; \ while (instream.readSingleSegment(infiles)) { \ status &= interface.run(infiles); \ - if (interface.hasWarning()) { \ - interface.getWarning(std::cerr); \ - } \ - if (interface.hasAnyText()) { \ - interface.getAllText(std::cout); \ - } \ - if (interface.hasError()) { \ - interface.getError(std::cerr); \ - return -1; \ - } \ - if (!interface.hasAnyText()) { \ - for (int i=0; i(interface)); \ bool status = interface.run(instream); \ + interface.finally(); \ if (interface.hasWarning()) { \ interface.getWarning(std::cerr); \ } \ @@ -5512,7 +5513,6 @@ int main(int argc, char** argv) { \ interface.getError(std::cerr); \ return -1; \ } \ - interface.finally(); \ interface.clearOutput(); \ return !status; \ } @@ -5536,6 +5536,7 @@ int main(int argc, char** argv) { \ hum::HumdrumFileSet infiles; \ instream.read(infiles); \ bool status = interface.run(infiles); \ + interface.finally(); \ if (interface.hasWarning()) { \ interface.getWarning(std::cerr); \ } \ @@ -5551,7 +5552,6 @@ int main(int argc, char** argv) { \ std::cout << infiles[i]; \ } \ } \ - interface.finally(); \ interface.clearOutput(); \ return !status; \ } @@ -7536,27 +7536,28 @@ class Tool_extract : public HumTool { void fillFieldDataByNoRest (std::vector& field, std::vector& subfield, std::vector& model, const std::string& searchstring, HumdrumFile& infile, int state); + void printInterpretationForKernSpine(HumdrumFile& infile, int index); private: // global variables - int excludeQ = 0; // used with -x option - int expandQ = 0; // used with -e option - std::string expandInterp = ""; // used with -E option - int interpQ = 0; // used with -i option - std::string interps = ""; // used with -i option - int debugQ = 0; // used with --debug option - int kernQ = 0; // used with -k option - int rkernQ = 0; // used with -K option - int fieldQ = 0; // used with -f or -p option - std::string fieldstring = ""; // used with -f or -p option + bool excludeQ = false; // used with -x option + bool expandQ = false; // used with -e option + std::string expandInterp = ""; // used with -E option + bool interpQ = false; // used with -i option + std::string interps = ""; // used with -i option + bool debugQ = false; // used with --debug option + bool kernQ = false; // used with -k option + bool rkernQ = false; // used with -K option + bool fieldQ = false; // used with -f or -p option + std::string fieldstring = ""; // used with -f or -p option std::vector field; // used with -f or -p option std::vector subfield; // used with -f or -p option std::vector model; // used with -p, or -e options and similar - int countQ = 0; // used with -C option - int traceQ = 0; // used with -t option - std::string tracefile = ""; // used with -t option - int reverseQ = 0; // used with -r option + bool countQ = false; // used with -C option + bool traceQ = false; // used with -t option + std::string tracefile = ""; // used with -t option + bool reverseQ = false; // used with -r option std::string reverseInterp = "**kern"; // used with -r and -R options. // sub-spine "b" expansion model: how to generate data for a secondary // spine if the primary spine is not divided. Models are: @@ -7566,17 +7567,18 @@ class Tool_extract : public HumTool { // data. 'n' will be used for non-kern spines when 'r' is used. int submodel = 'd'; // used with -m option std::string editorialInterpretation = "yy"; - std::string cointerp = "**kern"; // used with -c option - int comodel = 0; // used with -M option + std::string cointerp = "**kern"; // used with -c option + int comodel = 0; // used with -M option std::string subtokenseparator = " "; // used with a future option - int interpstate = 0; // used -I or with -i - int grepQ = 0; // used with -g option - std::string grepString = ""; // used with -g option + int interpstate = 0; // used -I or with -i + bool grepQ = false; // used with -g option + std::string grepString = ""; // used with -g option std::string blankName = "**blank"; // used with -n option - int noEmptyQ = 0; // used with --no-empty option - int emptyQ = 0; // used with --empty option - int spineListQ = 0; // used with --spine option - int removerestQ = 0; // used with --no-rest option + bool addRestsQ = false; // used with -n option + bool noEmptyQ = false; // used with --no-empty option + bool emptyQ = false; // used with --empty option + bool spineListQ = false; // used with --spine option + bool removerestQ = false; // used with --no-rest option }; @@ -9869,6 +9871,32 @@ class Tool_ordergps : public HumTool { }; +class Tool_pbar : public HumTool { + public: + Tool_pbar (void); + ~Tool_pbar () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const std::string& indata, std::ostream& out); + bool run (HumdrumFile& infile, std::ostream& out); + + protected: + void processFile (HumdrumFile& infile); + void initialize (void); + void processSpine (HTp spineStart); + void printDataLine (HumdrumFile& infile, int index); + void printLocalCommentLine (HumdrumFile& infile, int index); + void addBarLineToFollowingNoteOrRest (HTp token); + void printInvisibleBarlines (HumdrumFile& infile, int index); + void printBarLine (HumdrumFile& infile, int index); + + private: + bool m_invisibleQ = false; // used with -i option + +}; + + class Tool_pccount : public HumTool { public: @@ -10293,6 +10321,62 @@ class Tool_rid : public HumTool { }; +class Tool_rphrase : public HumTool { + public: + + class VoiceInfo { + public: + std::string name; + std::vector restsBefore; + std::vector phraseDurs; + std::vector barStarts; + std::vector phraseStartToks; + }; + + Tool_rphrase (void); + ~Tool_rphrase () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const std::string& indata, std::ostream& out); + bool run (HumdrumFile& infile, std::ostream& out); + void finally (void); + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void fillVoiceInfo (std::vector& voiceInfo, std::vector& kstarts, HumdrumFile& infile); + void fillVoiceInfo (Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart, HumdrumFile& infile); + void fillCollapseInfo (Tool_rphrase::VoiceInfo& collapseInfo, HumdrumFile& infile); + void printVoiceInfo (std::vector& voiceInfo); + void printVoiceInfo (Tool_rphrase::VoiceInfo& voiceInfo); + void getCompositeStates(std::vector& noteStates, HumdrumFile& infile); + std::string getCompositeLabel(HumdrumFile& infile); + void markPhraseStartsInScore(HumdrumFile& infile, Tool_rphrase::VoiceInfo& voiceInfo); + void outputMarkedFile (HumdrumFile& infile); + void printDataLine (HumdrumFile& infile, int index); + void markLongaDurations(HumdrumFile& infile); + + private: + bool m_averageQ = false; // for -a option + bool m_allAverageQ = false; // for -A option + bool m_barlineQ = false; // for -m option + bool m_collapseQ = false; // for -c option + bool m_longaQ = false; // for -l option + bool m_filenameQ = false; // for -f option + bool m_fullFilenameQ = false; // for -F option + std::string m_filename; // for -f or -F option + bool m_sortQ = false; // for -s option + bool m_reverseSortQ = false; // for -S option + int m_pcount = 0; // for -a option + double m_sum = 0.0; // for -a option + int m_pcountCollapse= 0; // for -c option + double m_sumCollapse = 0.0; // for -c option + bool m_markQ = false; // for --mark option + +}; + + class Tool_ruthfix : public HumTool { public: Tool_ruthfix (void); diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index 227c5637403..38eb3f94e01 100644 --- a/src/hum/humlib.cpp +++ b/src/hum/humlib.cpp @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Sun Jun 30 19:51:54 WEST 2024 +// Last Modified: Mon Jul 29 23:24:23 PDT 2024 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 @@ -24163,7 +24163,7 @@ void HumdrumFileContent::markBeamSpanMembers(HTp beamstart, HTp beamend) { bool HumdrumFileContent::doHandAnalysis(bool attacksOnlyQ) { HumdrumFileContent& infile = *this; vector kstarts = infile.getKernSpineStartList(); - bool status = 0; + bool status = 0; for (int i=0; i<(int)kstarts.size(); i++) { status |= doHandAnalysis(kstarts[i], attacksOnlyQ); } @@ -24426,7 +24426,7 @@ void HumdrumFileContent::fillMidiInfo(vector>>>& tr // // HumdrumFileContent::processStrandNotesForMidi -- store strand tokens/subtokens by MIDI note // in the midi track entry. -// +// // First index if track info is the MIDI note number, second is a list // of tokens for that note number, with the second value of the pair // giving the subtoken index of the note in the token. @@ -39785,7 +39785,7 @@ void MuseData::linkMusicDirections(void) { // // MuseData::getMeasureNumber -- If index == 0, return the next barnumber // minus 1. If on a measure record, return the number on that line. -// If neither, then search backwards for the last measure line (or 0 +// If neither, then search backwards for the last measure line (or 0 // index) and return the measure number for that barline (or 0 index). // @@ -39819,7 +39819,7 @@ string MuseData::getMeasureNumber(int index) { string number = md[i].getMeasureNumber(); return number; } else { - // first measure is not numbered, so return next + // first measure is not numbered, so return next // measure number minus 1. for (int j=index; j terminate) { m_error << "Error: missing option argument" << endl; + m_error << "ARGV count: " << m_argv.size() << endl; + m_error << "terminate: " << terminate << endl; + m_error << "tcount: " << tcount << endl; break; } if (isOption(m_argv[i], i)) { @@ -80160,7 +80163,7 @@ void Tool_extract::fillFieldDataByNoRest(vector& field, vector& subfie } // Go back and mark any empty spines as non-empty if they - // are in a part that contains multiple staves. I.e., only + // are in a part that contains multiple staves. I.e., only // delete a staff if all staves for the part are empty. // There should be a single *part# line at the start of the // score. @@ -80397,12 +80400,8 @@ void Tool_extract::expandSpines(vector& field, vector& subfield, vecto model.reserve(infile.getMaxTrack()*2); model.resize(0); - int allQ = 0; - if (interp.size() == 0) { - allQ = 1; - } + bool allQ = interp.empty(); - // ggg vector dummyfield; vector dummysubfield; vector dummymodel; @@ -80606,25 +80605,25 @@ void Tool_extract::processFieldEntry(vector& field, if ((firstone < 1) && (firstone != 0)) { m_error_text << "Error: range token: \"" << astring << "\"" - << " contains too small a number at start: " << firstone << endl; + << " contains too small a number at start: " << firstone << endl; m_error_text << "Minimum number allowed is " << 1 << endl; return; } if ((lastone < 1) && (lastone != 0)) { m_error_text << "Error: range token: \"" << astring << "\"" - << " contains too small a number at end: " << lastone << endl; + << " contains too small a number at end: " << lastone << endl; m_error_text << "Minimum number allowed is " << 1 << endl; return; } if (firstone > maxtrack) { m_error_text << "Error: range token: \"" << astring << "\"" - << " contains number too large at start: " << firstone << endl; + << " contains number too large at start: " << firstone << endl; m_error_text << "Maximum number allowed is " << maxtrack << endl; return; } if (lastone > maxtrack) { m_error_text << "Error: range token: \"" << astring << "\"" - << " contains number too large at end: " << lastone << endl; + << " contains number too large at end: " << lastone << endl; m_error_text << "Maximum number allowed is " << maxtrack << endl; return; } @@ -80667,13 +80666,13 @@ void Tool_extract::processFieldEntry(vector& field, if ((value < 1) && (value != 0)) { m_error_text << "Error: range token: \"" << astring << "\"" - << " contains too small a number at end: " << value << endl; + << " contains too small a number at end: " << value << endl; m_error_text << "Minimum number allowed is " << 1 << endl; return; } if (value > maxtrack) { m_error_text << "Error: range token: \"" << astring << "\"" - << " contains number too large at start: " << value << endl; + << " contains number too large at start: " << value << endl; m_error_text << "Maximum number allowed is " << maxtrack << endl; return; } @@ -80698,11 +80697,10 @@ void Tool_extract::processFieldEntry(vector& field, vector trackstarts; infile.getTrackStartList(trackstarts); - int i, j; int spine; // convert kern tracks into spine tracks: - for (i=finitsize; i<(int)field.size(); i++) { + for (int i=finitsize; i<(int)field.size(); i++) { if (field[i] > 0) { spine = ktracks[field[i]-1]->getTrack(); field[i] = spine; @@ -80710,7 +80708,7 @@ void Tool_extract::processFieldEntry(vector& field, } int startspineindex, stopspineindex; - for (i=0; i<(int)field.size(); i++) { + for (int i=0; i<(int)field.size(); i++) { newfield.push_back(field[i]); // copy **kern spine index into new list newsubfield.push_back(subfield[i]); newmodel.push_back(model[i]); @@ -80718,7 +80716,7 @@ void Tool_extract::processFieldEntry(vector& field, // search for non **kern spines after specified **kern spine: startspineindex = field[i] + 1 - 1; stopspineindex = maxtrack; - for (j=startspineindex; jisKern()) { break; } @@ -80818,6 +80816,7 @@ void Tool_extract::extractFields(HumdrumFile& infile, vector& field, int subtarget; int modeltarget; string spat; + bool foundBarline = true; for (int i=0; i& field, continue; } + if (infile[i].isBarline()) { + foundBarline = true; + } + start = 0; for (int t=0; t<(int)field.size(); t++) { target = field[t]; @@ -80837,17 +80840,17 @@ void Tool_extract::extractFields(HumdrumFile& infile, vector& field, modeltarget = model[t]; if (modeltarget == 0) { switch (subtarget) { - case 'a': - case 'b': - modeltarget = submodel; - break; - case 'c': - modeltarget = comodel; + case 'a': + case 'b': + modeltarget = submodel; + break; + case 'c': + modeltarget = comodel; } } if (target == 0) { if (start != 0) { - m_humdrum_text << '\t'; + m_humdrum_text << '\t'; } start = 1; if (!infile[i].isManipulator()) { @@ -80856,66 +80859,91 @@ void Tool_extract::extractFields(HumdrumFile& infile, vector& field, } else if (infile[i].isBarline()) { m_humdrum_text << infile[i].token(0); } else if (infile[i].isData()) { - m_humdrum_text << "."; - // interpretations handled in dealWithSpineManipulators() - // [obviously not, so adding a blank one here + if (foundBarline) { + if (addRestsQ) { + HumNum dur = infile[i].getDurationToBarline(); + m_humdrum_text << Convert::durationToRecip(dur); + } else { + m_humdrum_text << "."; + } + } else { + m_humdrum_text << "."; + } + // interpretations handled in dealWithSpineManipulators() + // [obviously not, so adding a blank one here } else if (infile[i].isInterpretation()) { - m_humdrum_text << "*"; - } + HTp token = infile.token(i, 0); + if (token->isExpansionLabel()) { + m_humdrum_text << token; + } else if (token->isExpansionList()) { + m_humdrum_text << token; + } else { + if (addRestsQ) { + printInterpretationForKernSpine(infile, i); + } else { + m_humdrum_text << "*"; + } + } + } } } else { for (int j=0; jgetTrack() != target) { - continue; - } - switch (subtarget) { - case 'a': - getSearchPat(spat, target, "a"); - if (hre.search(infile.token(i,j)->getSpineInfo(), spat) || - !hre.search(infile.token(i, j)->getSpineInfo(), "\\(")) { - if (start != 0) { - m_humdrum_text << '\t'; - } - start = 1; - m_humdrum_text << infile.token(i, j); - } - break; - case 'b': - getSearchPat(spat, target, "b"); - if (hre.search(infile.token(i, j)->getSpineInfo(), spat)) { - if (start != 0) { - m_humdrum_text << '\t'; - } - start = 1; - m_humdrum_text << infile.token(i, j); - } else if (!hre.search(infile.token(i, j)->getSpineInfo(), - "\\(")) { - if (start != 0) { - m_humdrum_text << '\t'; - } - start = 1; - dealWithSecondarySubspine(field, subfield, model, t, - infile, i, j, modeltarget); - } - break; - case 'c': - if (start != 0) { - m_humdrum_text << '\t'; - } - start = 1; - dealWithCospine(field, subfield, model, t, infile, i, j, - modeltarget, modeltarget, cointerp); - break; - default: - if (start != 0) { - m_humdrum_text << '\t'; - } - start = 1; - m_humdrum_text << infile.token(i, j); - } + if (infile[i].token(j)->getTrack() != target) { + continue; + } + switch (subtarget) { + case 'a': + getSearchPat(spat, target, "a"); + if (hre.search(infile.token(i,j)->getSpineInfo(), spat) || + !hre.search(infile.token(i, j)->getSpineInfo(), "\\(")) { + if (start != 0) { + m_humdrum_text << '\t'; + } + start = 1; + m_humdrum_text << infile.token(i, j); + } + break; + case 'b': + getSearchPat(spat, target, "b"); + if (hre.search(infile.token(i, j)->getSpineInfo(), spat)) { + if (start != 0) { + m_humdrum_text << '\t'; + } + start = 1; + m_humdrum_text << infile.token(i, j); + } else if (!hre.search(infile.token(i, j)->getSpineInfo(), + "\\(")) { + if (start != 0) { + m_humdrum_text << '\t'; + } + start = 1; + dealWithSecondarySubspine(field, subfield, model, t, + infile, i, j, modeltarget); + } + break; + case 'c': + if (start != 0) { + m_humdrum_text << '\t'; + } + start = 1; + dealWithCospine(field, subfield, model, t, infile, i, j, + modeltarget, modeltarget, cointerp); + break; + default: + if (start != 0) { + m_humdrum_text << '\t'; + } + start = 1; + m_humdrum_text << infile.token(i, j); + } } } } + + if (infile[i].isData()) { + foundBarline = false; + } + if (start != 0) { m_humdrum_text << endl; } @@ -80924,6 +80952,66 @@ void Tool_extract::extractFields(HumdrumFile& infile, vector& field, +////////////////////////////// +// +// Tool_extract::printInterpretationForKernSpine -- +// + +void Tool_extract::printInterpretationForKernSpine(HumdrumFile& infile, int index) { + HTp kerntok = NULL; + for (int j=0; jisKern()) { + continue; + } + kerntok = token; + break; + } + + if (kerntok == NULL) { + m_humdrum_text << "*"; + return; + } + + if (*kerntok == "*") { + m_humdrum_text << kerntok; + return; + } + + if (kerntok->isKeySignature()) { + m_humdrum_text << kerntok; + return; + } + if (kerntok->isKeyDesignation()) { + m_humdrum_text << kerntok; + return; + } + if (kerntok->isTimeSignature()) { + m_humdrum_text << kerntok; + return; + } + if (kerntok->isMensurationSymbol()) { + m_humdrum_text << kerntok; + return; + } + if (kerntok->isTempo()) { + m_humdrum_text << kerntok; + return; + } + if (kerntok->isInstrumentName()) { + m_humdrum_text << "*I\""; + return; + } + if (kerntok->isInstrumentAbbreviation()) { + m_humdrum_text << "*I'"; + return; + } + + m_humdrum_text << "*"; +} + + + ////////////////////////////// // // Tool_extract::dealWithCospine -- extract the required token(s) from a co-spine. @@ -81024,7 +81112,7 @@ void Tool_extract::dealWithCospine(vector& field, vector& subfield, ve if ((strchr(infile.token(line, j)->getSpineInfo().c_str(), '(') == NULL) || (infile.token(line, j)->getSpineInfo().find(buff) != string::npos)) { printCotokenInfo(start, infile, line, j, cotokens, spineindex, - subspineindex); + subspineindex); } } else if (subfield[i] == 'b') { // this section may need more work... @@ -81032,7 +81120,7 @@ void Tool_extract::dealWithCospine(vector& field, vector& subfield, ve if ((strchr(infile.token(line, j)->getSpineInfo().c_str(), '(') == NULL) || (strstr(infile.token(line, j)->getSpineInfo().c_str(), buff.c_str()) != NULL)) { printCotokenInfo(start, infile, line, j, cotokens, spineindex, - subspineindex); + subspineindex); } } else { printCotokenInfo(start, infile, line, j, cotokens, spineindex, @@ -81306,18 +81394,18 @@ void Tool_extract::dealWithSpineManipulators(HumdrumFile& infile, int line, if (infile[line].token(j)->getTrack() != target) { continue; } - // filter by subfield - if (subtarget == 'a') { - getSearchPat(spat, target, "b"); - if (hre.search(infile.token(line, j)->getSpineInfo(), spat)) { + // filter by subfield + if (subtarget == 'a') { + getSearchPat(spat, target, "b"); + if (hre.search(infile.token(line, j)->getSpineInfo(), spat)) { continue; - } - } else if (subtarget == 'b') { - getSearchPat(spat, target, "a"); - if (hre.search(infile.token(line, j)->getSpineInfo(), spat)) { - continue; - } - } + } + } else if (subtarget == 'b') { + getSearchPat(spat, target, "a"); + if (hre.search(infile.token(line, j)->getSpineInfo(), spat)) { + continue; + } + } switch (subtarget) { case 'a': @@ -81338,14 +81426,14 @@ void Tool_extract::dealWithSpineManipulators(HumdrumFile& infile, int line, (spinepat == spat)) { storeToken(tempout, "*"); } else { - getSearchPat(spat, target, "b"); - if ((spinepat == spat) && - (*infile.token(line, j) == "*v")) { - // do nothing - suppress = 1; - } else { - storeToken(tempout, *infile.token(line, j)); - } + getSearchPat(spat, target, "b"); + if ((spinepat == spat) && + (*infile.token(line, j) == "*v")) { + // do nothing + suppress = 1; + } else { + storeToken(tempout, *infile.token(line, j)); + } } } @@ -81354,9 +81442,9 @@ void Tool_extract::dealWithSpineManipulators(HumdrumFile& infile, int line, if (!hre.search(infile.token(line, j)->getSpineInfo(), "\\(")) { if (*infile.token(line, j) == "*^") { - storeToken(tempout, "*"); + storeToken(tempout, "*"); } else { - storeToken(tempout, *infile.token(line, j)); + storeToken(tempout, *infile.token(line, j)); } } else { getSearchPat(spat, target, "b"); @@ -81365,17 +81453,17 @@ void Tool_extract::dealWithSpineManipulators(HumdrumFile& infile, int line, hre.replaceDestructive(spinepat, "\\)", "\\)", "g"); if ((*infile.token(line, j) == "*v") && - (spinepat == spat)) { - storeToken(tempout, "*"); + (spinepat == spat)) { + storeToken(tempout, "*"); } else { - getSearchPat(spat, target, "a"); - if ((spinepat == spat) && - (*infile.token(line, j) == "*v")) { - // do nothing - suppress = 1; - } else { - storeToken(tempout, *infile.token(line, j)); - } + getSearchPat(spat, target, "a"); + if ((spinepat == spat) && + (*infile.token(line, j) == "*v")) { + // do nothing + suppress = 1; + } else { + storeToken(tempout, *infile.token(line, j)); + } } } @@ -81878,19 +81966,19 @@ void Tool_extract::initialize(HumdrumFile& infile) { } if (interpQ) { - fieldQ = 1; + fieldQ = true; } if (emptyQ) { - fieldQ = 1; + fieldQ = true; } if (noEmptyQ) { - fieldQ = 1; + fieldQ = true; } if (expandQ) { - fieldQ = 1; + fieldQ = true; expandInterp = getString("expand-interp"); } @@ -81902,7 +81990,7 @@ void Tool_extract::initialize(HumdrumFile& infile) { } if (reverseQ) { - fieldQ = 1; + fieldQ = true; } if (excludeQ) { @@ -81911,15 +81999,15 @@ void Tool_extract::initialize(HumdrumFile& infile) { fieldstring = getString("f"); } else if (kernQ) { fieldstring = getString("k"); - fieldQ = 1; + fieldQ = true; } else if (rkernQ) { fieldstring = getString("K"); - fieldQ = 1; + fieldQ = true; fieldstring = reverseFieldString(fieldstring, infile.getMaxTrack()); } spineListQ = getBoolean("spine-list"); - grepQ = getBoolean("grep"); + grepQ = getBoolean("grep"); grepString = getString("grep"); if (getBoolean("name")) { @@ -81933,6 +82021,9 @@ void Tool_extract::initialize(HumdrumFile& infile) { blankName = "*" + blankName; } } + if (blankName == "**kern") { + addRestsQ = true; + } } } @@ -83159,6 +83250,8 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(nproof, infile, commands[i].second, status); } else if (commands[i].first == "ordergps") { RUNTOOL(ordergps, infile, commands[i].second, status); + } else if (commands[i].first == "pbar") { + RUNTOOL(pbar, infile, commands[i].second, status); } else if (commands[i].first == "phrase") { RUNTOOL(phrase, infile, commands[i].second, status); } else if (commands[i].first == "pline") { @@ -112712,6 +112805,274 @@ void Tool_ordergps::printStaffLine(HumdrumFile& infile) { +///////////////////////////////// +// +// Tool_pbar::Tool_pbar -- Set the recognized options for the tool. +// + +Tool_pbar::Tool_pbar(void) { + define("i|invisible-barlines=b", "make barlines invisible"); +} + + + +////////////////////////////// +// +// Tool_pbar::initialize -- Initializations that only have to be done once +// for all HumdrumFile segments. +// + +void Tool_pbar::initialize(void) { + m_invisibleQ = getBoolean("invisible-barlines"); +} + + + +///////////////////////////////// +// +// Tool_pbar::run -- Do the main work of the tool. +// + +bool Tool_pbar::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; i kstarts = infile.getKernSpineStartList(); + for (int i=0; i<(int)kstarts.size(); i++) { + processSpine(kstarts[i]); + } + + for (int i=0; igetValue("auto", "pbar"); + if (value == "true") { + hasBarline = true; + break; + } + } + + if (hasBarline) { + for (int j=0; jgetValue("auto", "pbar"); + if (value == "true") { + m_humdrum_text << "*bar"; + } else { + m_humdrum_text << "*"; + } + if (j < infile[index].getFieldCount() - 1) { + m_humdrum_text << "\t"; + } + } + m_humdrum_text << "\n"; + } +} + + + +/////////////////////////////// +// +// Tool_pbar::printLocalCommentLine -- +// + +void Tool_pbar::printLocalCommentLine(HumdrumFile& infile, int index) { + HumRegex hre; + bool hasKp = false; + bool hasOther = false; + for (int i=0; iisLocalComment()) { + current = current->getNextToken(); + continue; + } + if (hre.search(current, "kreska\\s*pseudotaktowa")) { + addBarLineToFollowingNoteOrRest(current); + } + current = current->getNextToken(); + } +} + + + +////////////////////////////// +// +// Tool_pbar::addBarLineToFollowingNoteOrRest -- +// + +void Tool_pbar::addBarLineToFollowingNoteOrRest(HTp token) { + HTp current = token->getNextToken(); + int counter = 0; + while (current) { + if (!current->isBarline()) { + if (!current->isData() || current->isNull()) { + current = current->getNextToken(); + continue; + } + } + counter++; + if (counter == 2) { + current->setValue("auto", "pbar", "true"); + break; + } + current = current->getNextToken(); + } +} + + + + ///////////////////////////////// // // Tool_gridtest::Tool_pccount -- Set the recognized options for the tool. @@ -117735,6 +118096,795 @@ void Tool_rid::processFile(HumdrumFile& infile) { +///////////////////////////////// +// +// Tool_rphrase::Tool_rphrase -- Set the recognized options for the tool. +// + +Tool_rphrase::Tool_rphrase(void) { + // add command-line options here + define("a|average=b", "calculate average length of rest-phrases by score"); + define("A|all-average=b", "calculate average length of rest-phrases for all scores"); + define("c|composite|collapse=b", "collapse all voices into single part"); + define("f|filename=b", "include filename in output analysis"); + define("F|full-filename=b", "include full filename location in output analysis"); + define("l|longa=b", "display minim length of longas"); + define("m|b|measure|barline=b", "include barline numbers in output analysis"); + define("mark=b", "mark starts of phrases in score"); + define("s|sort=b", "sort phrases by short to long length"); + define("S|reverse-sort=b", "sort phrases by long to short length"); +} + + + +///////////////////////////////// +// +// Tool_rphrase::run -- Do the main work of the tool. +// + +bool Tool_rphrase::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; i kernStarts = infile.getKernSpineStartList(); + vector voiceInfo(kernStarts.size()); + Tool_rphrase::VoiceInfo collapseInfo; + + if (m_collapseQ) { + fillCollapseInfo(collapseInfo, infile); + } else { + fillVoiceInfo(voiceInfo, kernStarts, infile); + } + + + if (m_longaQ) { + markLongaDurations(infile); + } + + if (!m_allAverageQ) { + if (m_collapseQ) { + printVoiceInfo(collapseInfo); + } else { + printVoiceInfo(voiceInfo); + } + } + + if (m_markQ) { + outputMarkedFile(infile); + } + +} + + + +////////////////////////// +// +// Tool_rphrase::markLongaDuratios -- +// + +void Tool_rphrase::markLongaDurations(HumdrumFile& infile) { + string longrdf; + for (int i=0; iisKern()) { + continue; + } + if (token->find(longrdf) != string::npos) { + HumNum duration = token->getTiedDuration(); + stringstream value; + value.str(""); + value << duration.getFloat() / 2.0; + token->setValue("auto", "rphrase-longa", value.str()); + } + } + } +} + + + +////////////////////////////// +// +// Tool_rphrase::outputMarkedFile -- +// + +void Tool_rphrase::outputMarkedFile(HumdrumFile& infile) { + m_free_text.clear(); + m_free_text.str(""); + for (int i=0; iisKern()) { + continue; + } + string lotext = token->getValue("auto", "rphrase-longa"); + if (!lotext.empty()) { + hasLonga = true; + break; + } + } + } + + + bool hasLo = false; + for (int j=0; jisKern()) { + continue; + } + string lotext = token->getValue("auto", "rphrase-start"); + if (!lotext.empty()) { + hasLo = true; + break; + } + } + + if (hasLonga) { + for (int j=0; jisKern()) { + m_humdrum_text << "!"; + } else { + string value = token->getValue("auto", "rphrase-longa"); + if (value.empty()) { + m_humdrum_text << "!"; + } else { + m_humdrum_text << "!LO:TX:a:B:color=silver:t=" << value; + } + } + if (j < infile[index].getFieldCount() - 1) { + m_humdrum_text << "\t"; + } + } + m_humdrum_text << endl; + } + + if (hasLo) { + for (int j=0; jisKern()) { + m_humdrum_text << "!"; + } else { + string value = token->getValue("auto", "rphrase-start"); + if (value.empty()) { + m_humdrum_text << "!"; + } else { + m_humdrum_text << "!LO:TX:a:B:color=red:t=" << value; + } + } + if (j < infile[index].getFieldCount() - 1) { + m_humdrum_text << "\t"; + } + } + m_humdrum_text << endl; + } + + m_humdrum_text << infile[index] << endl; +} + + + +////////////////////////////// +// +// Tool_rphrase::getCompositeStates -- +// + +void Tool_rphrase::getCompositeStates(vector& noteStates, HumdrumFile& infile) { + noteStates.resize(infile.getLineCount()); + fill(noteStates.begin(), noteStates.end(), -1); + for (int i=0; iisKern()) { + continue; + } + if (token->isRest()) { + continue; + } else if (token->isNull()) { + HTp resolve = token->resolveNull(); + if (!resolve) { + continue; + } else if (resolve->isRest()) { + continue; + } else { + value = 1; + break; + } + } else { + value = 1; + break; + } + } + noteStates[i] = value; + } +} + + + +////////////////////////////// +// +// Tool_rphrase::printVoiceInfo -- +// + +void Tool_rphrase::printVoiceInfo(vector& voiceInfo) { + for (int i=(int)voiceInfo.size() - 1; i>=0; i--) { + printVoiceInfo(voiceInfo[i]); + } +} + + +void Tool_rphrase::printVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo) { + if (m_filenameQ) { + m_free_text << m_filename << "\t"; + } + m_free_text << voiceInfo.name << "\t"; + + if (m_averageQ) { + double sum = 0; + int count = 0; + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + count++; + sum += voiceInfo.phraseDurs.at(i); + } + m_free_text << int(sum / count * 100.0 + 0.5)/100.0 << "\t"; + } + + if (m_sortQ || m_reverseSortQ) { + vector> sortList; + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + sortList.emplace_back(voiceInfo.phraseDurs[i], i); + } + if (m_sortQ) { + sort(sortList.begin(), sortList.end(), + [](const std::pair& a, const std::pair& b) { + return a.first < b.first; + }); + } else if (m_reverseSortQ) { + sort(sortList.begin(), sortList.end(), + [](const std::pair& a, const std::pair& b) { + return a.first > b.first; + }); + } + + for (int i=0; i<(int)sortList.size(); i++) { + int ii = sortList[i].second; + if (m_barlineQ) { + m_free_text << "m" << voiceInfo.barStarts.at(ii) << ":"; + } + m_free_text << voiceInfo.phraseDurs.at(ii); + if (i < (int)sortList.size() - 1) { + m_free_text << " "; + } + } + } else { + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + if (voiceInfo.restsBefore.at(i) > 0) { + m_free_text << "r:" << voiceInfo.restsBefore.at(i) << " "; + } + if (m_barlineQ) { + m_free_text << "m" << voiceInfo.barStarts.at(i) << ":"; + } + m_free_text << voiceInfo.phraseDurs.at(i); + if (i < (int)voiceInfo.phraseDurs.size() - 1) { + m_free_text << " "; + } + } + } + + m_free_text << endl; +} + + + +////////////////////////////// +// +// Tool_rphrase::fillCollapseInfo -- +// + +void Tool_rphrase::fillCollapseInfo(Tool_rphrase::VoiceInfo& collapseInfo, HumdrumFile& infile) { + collapseInfo.name = getCompositeLabel(infile); + vector noteStates; + getCompositeStates(noteStates, infile); + + bool inPhraseQ = false; + int currentBarline = 0; + int startBarline = 1; + HumNum startTime = 0; + + HumNum restBefore = 0; + HumNum startTimeRest = 0; + + HumNum scoreDur = infile.getScoreDuration(); + + for (int i=0; ifind("||") != string::npos) { + HumNum tdur = token->getDurationFromStart(); + if (tdur != scoreDur) { + // Only process if double barline is not at the end of the score. + + if (inPhraseQ) { + // In phrase, so continue if still notes, otherwise + // if a rest, then record the currently active phrase + // that has ended. + + // ending a phrase + HumNum endTime = infile[i].getDurationFromStart(); + HumNum duration = endTime - startTime; + startTime = -1; + inPhraseQ = false; + collapseInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + collapseInfo.barStarts.push_back(startBarline); + m_sumCollapse += duration.getFloat() / 2.0; + m_pcountCollapse++; + collapseInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + + // record rest start + startTimeRest = endTime; + } else { + // Not in phrase, so not splitting a rest region. + // This case should be rare (starting a medial cadence + // with rests and potentially starting new section with rests. + } + + } + } + } + + if (infile[i].isBarline()) { + HTp token = infile.token(i, 0); + HumRegex hre; + if (hre.search(token, "(\\d+)")) { + currentBarline = hre.getMatchInt(1); + continue; + } + } + + + if (!infile[i].isData()) { + continue; + } + + if (inPhraseQ) { + // In phrase, so continue if still notes, otherwise + // if a rest, then record the currently active phrase + // that has ended. + if (noteStates[i] == 0) { + // ending a phrase + HumNum endTime = infile[i].getDurationFromStart(); + HumNum duration = endTime - startTime; + startTime = -1; + inPhraseQ = false; + collapseInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + collapseInfo.barStarts.push_back(startBarline); + m_sumCollapse += duration.getFloat() / 2.0; + m_pcountCollapse++; + collapseInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + // record rest start + startTimeRest = endTime; + } else { + // continuing a phrase, so do nothing + } + } else { + // Not in phrase, so continue if rest; otherwise, + // if a note, then record a phrase start. + if (noteStates[i] == 0) { + // continuing a non-phrase, so do nothing + } else { + // starting a phrase + startTime = infile[i].getDurationFromStart(); + startBarline = currentBarline; + inPhraseQ = true; + // check if there are rests before the phrase + // The rest duration will be stored when the + // end of the next phrase is encountered. + if (startTimeRest >= 0) { + restBefore = startTime - startTimeRest; + } else { + restBefore = 0; + } + } + } + + } + + if (inPhraseQ) { + // process last phrase + HumNum endTime = infile.getScoreDuration(); + HumNum duration = endTime - startTime; + collapseInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + collapseInfo.barStarts.push_back(startBarline); + m_sumCollapse += duration.getFloat() / 2.0; + m_pcountCollapse++; + collapseInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + } +} + + + +////////////////////////////// +// +// Tool_rphrase::getCompositeLabel -- +// + +string Tool_rphrase::getCompositeLabel(HumdrumFile& infile) { + string voices; + for (int i=0; i kstarts = infile.getKernSpineStartList(); + + string output = "composite "; + output += voices; + + + HumRegex hre; + + if (hre.search(voices, "^\\d+$")) { + int vint = stoi(voices); + if (vint != (int)kstarts.size()) { + output += "("; + output += to_string(kstarts.size()); + output += ")"; + } + } else { + output += "("; + output += to_string(kstarts.size()); + output += ")"; + } + + return output; +} + + + +////////////////////////////// +// +// Tool_rphrase::fillVoiceInfo -- +// + +void Tool_rphrase::fillVoiceInfo(vector& voiceInfo, + vector& kstarts, HumdrumFile& infile) { + for (int i=0; i<(int)kstarts.size(); i++) { + fillVoiceInfo(voiceInfo.at(i), kstarts.at(i), infile); + } +} + + + +void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart, HumdrumFile& infile) { + HTp current = kstart; + + bool inPhraseQ = false; + int currentBarline = 0; + int startBarline = 1; + HumNum startTime = 0; + + HumNum restBefore = 0; + HumNum startTimeRest = 0; + + HumNum scoreDur = infile.getScoreDuration(); + HTp phraseStartTok = NULL; + + while (current) { + + // Split phrases at double barlines (medial cadences): + if (infile[current->getLineIndex()].isBarline()) { + HTp token = infile.token(current->getLineIndex(), 0); + if (token->find("||") != string::npos) { + HumNum tdur = token->getDurationFromStart(); + if (tdur != scoreDur) { + // Only process if double barline is not at the end of the score. + + if (inPhraseQ) { + // In phrase, so continue if still notes, otherwise + // if a rest, then record the currently active phrase + // that has ended. + + HumNum endTime = current->getDurationFromStart(); + HumNum duration = endTime - startTime; + startTime = -1; + inPhraseQ = false; + voiceInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + voiceInfo.barStarts.push_back(startBarline); + voiceInfo.phraseStartToks.push_back(phraseStartTok); + phraseStartTok = NULL; + m_sum += duration.getFloat() / 2.0; + m_pcount++; + voiceInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + + // record rest start + startTimeRest = endTime; + } else { + // Not in phrase, so not splitting a rest region. + // This case should be rare (starting a medial cadence + // with rests and potentially starting new section with rests. + } + + } + } + } + + if (current->isBarline()) { + HumRegex hre; + if (hre.search(current, "(\\d+)")) { + currentBarline = hre.getMatchInt(1); + current = current->getNextToken(); + continue; + } + } + + if (current->isInstrumentName()) { + voiceInfo.name = current->substr(3); + } + if (!current->isData()) { + current = current->getNextToken(); + continue; + } + if (current->isNull()) { + current = current->getNextToken(); + continue; + } + + if (inPhraseQ) { + // In phrase, so continue if still notes, otherwise + // if a rest, then record the currently active phrase + // that has ended. + if (current->isRest()) { + // ending a phrase + HumNum endTime = current->getDurationFromStart(); + HumNum duration = endTime - startTime; + startTime = -1; + inPhraseQ = false; + voiceInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + voiceInfo.barStarts.push_back(startBarline); + voiceInfo.phraseStartToks.push_back(phraseStartTok); + phraseStartTok = NULL; + m_sum += duration.getFloat() / 2.0; + m_pcount++; + voiceInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + // record rest start + startTimeRest = endTime; + } else { + // continuing a phrase, so do nothing + } + } else { + // Not in phrase, so continue if rest; otherwise, + // if a note, then record a phrase start. + if (current->isRest()) { + // continuing a non-phrase, so do nothing + } else { + // starting a phrase + startTime = current->getDurationFromStart(); + startBarline = currentBarline; + inPhraseQ = true; + // check if there are rests before the phrase + // The rest duration will be stored when the + // end of the next phrase is encountered. + if (startTimeRest >= 0) { + restBefore = startTime - startTimeRest; + } else { + restBefore = 0; + } + phraseStartTok = current; + } + } + + current = current->getNextToken(); + } + if (inPhraseQ) { + // process last phrase + HumNum endTime = kstart->getLine()->getOwner()->getScoreDuration(); + HumNum duration = endTime - startTime; + voiceInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + voiceInfo.barStarts.push_back(startBarline); + voiceInfo.phraseStartToks.push_back(phraseStartTok); + m_sum += duration.getFloat() / 2.0; + m_pcount++; + voiceInfo.restsBefore.push_back(0.0); + voiceInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + } + + if (m_markQ) { + markPhraseStartsInScore(infile, voiceInfo); + } +} + + +////////////////////////////// +// +// Tool_rphrase::markPhraseStartsInScore -- +// + +void Tool_rphrase::markPhraseStartsInScore(HumdrumFile& infile, Tool_rphrase::VoiceInfo& voiceInfo) { + stringstream buffer; + for (int i=0; i<(int)voiceInfo.phraseStartToks.size(); i++) { + HTp tok = voiceInfo.phraseStartToks.at(i); + string measure = ""; + if (m_barlineQ) { + measure = to_string(voiceInfo.barStarts.at(i)); + } + double duration = voiceInfo.phraseDurs.at(i); + buffer.str(""); + if (!measure.empty()) { + buffer << "m" << measure << ":"; + } + buffer << duration; + tok->setValue("auto", "rphrase-start", buffer.str()); + } +} + + + + ///////////////////////////////// // // Tool_ruthfix::Tool_ruthfix -- Set the recognized options for the tool. From 24be976d6801298c74103c8bf90bfc8a1d417494 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Tue, 30 Jul 2024 01:38:21 -0700 Subject: [PATCH 2/7] Add more instrument to automatic humdrum instrument names for staves. --- include/vrv/iohumdrum.h | 1 + src/iohumdrum.cpp | 329 +++++++++++++++++++++++++++++++--------- 2 files changed, 262 insertions(+), 68 deletions(-) diff --git a/include/vrv/iohumdrum.h b/include/vrv/iohumdrum.h index 92795b20182..98d356f904e 100644 --- a/include/vrv/iohumdrum.h +++ b/include/vrv/iohumdrum.h @@ -900,6 +900,7 @@ class HumdrumInput : public vrv::Input { bool checkIfReversedSpineOrder(std::vector &staffstarts); bool hasOmdText(int startline, int endline); void processMeiOptions(hum::HumdrumFile &infile); + std::string getInstrumentNumber(hum::HTp icode); // header related functions: /////////////////////////////////////////// void createHeader(); diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 2c833b4a887..3d6247b9b96 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -8070,76 +8070,238 @@ bool HumdrumInput::isBlackNotation(hum::HTp starting) std::string HumdrumInput::getLabelFromInstrumentCode(hum::HTp icode, const std::string &transpose) { - std::string output; - std::string name = icode->substr(2); - if (name == "piano") { - output = "Piano"; - } - else if (name == "flt") { - output = "Flute"; - } - else if (name == "picco") { - output = "Piccolo"; - } - else if (name == "oboe") { - output = "Oboe"; - } - else if (name == "clars") { - output = "Clarinet"; - } - else if (name == "clara") { - output = "Alto Clarinet"; - } - else if (name == "clarb") { - output = "Bass Clarinet"; - } - else if (name == "fagot") { - output = "Bassoon"; - } - else if (name == "fagot") { - output = "Bassoon"; - } - else if (name == "tromp") { - output = "Trumpet"; - } - else if (name == "tromb") { - output = "Trombone"; - } - else if (name == "violin") { - // Deal with Violin 1 versus Violin 2, but need more info to do that. - output = "Violin"; - } - else if (name == "viola") { - output = "Viola"; - } - else if (name == "cello") { - output = "Violoncello"; - } - else if (name == "cemba") { - output = "Harpsichord"; - } - else if (name == "organ") { - output = "Organ"; - } - else if (name == "clavi") { - output = "Clavichord"; - } - else if (name == "forte") { - output = "Fortepiano"; - } - else if (name == "guitr") { - output = "Guitar"; - } - else if (name == "cbass") { - output = "Contrabass"; - } - else if (name == "koto") { - output = "Koto"; - } + static std::map codeToLabel; + if (codeToLabel.empty()) { + codeToLabel["piano"] = "Piano"; + codeToLabel["accor"] = "Accordion"; + codeToLabel["alto"] = "Alto"; + codeToLabel["anvil"] = "Anvil"; + codeToLabel["archl"] = "Archlute"; + codeToLabel["armon"] = "Harmonic"; + codeToLabel["arpa"] = "Harp"; + codeToLabel["bagpI"] = "Irish bagpipe"; + codeToLabel["bagpS"] = "Scottish bagpipe"; + codeToLabel["banjo"] = "Banjo"; + codeToLabel["bansu"] = "Bansuri"; + codeToLabel["barit"] = "Baritone"; + codeToLabel["mbari"] = "High baritone"; + codeToLabel["baset"] = "Bassett horn"; + codeToLabel["bass"] = "Bass"; + codeToLabel["bdrum"] = "Bass drum"; + codeToLabel["bongo"] = "Bongo"; + codeToLabel["bguit"] = "Bass guitar"; + codeToLabel["biwa"] = "Biwa"; + codeToLabel["bscan"] = "Singing bass"; + codeToLabel["bspro"] = "Basso profondo"; + codeToLabel["brush"] = "Brush"; + codeToLabel["calam"] = "Chalumeau"; + codeToLabel["calpe"] = "Calliope"; + codeToLabel["calto"] = "Contralto"; + codeToLabel["campn"] = "Bells"; + codeToLabel["cangl"] = "English horn"; + codeToLabel["canto"] = "Canto"; + codeToLabel["caril"] = "Carillon"; + codeToLabel["castr"] = "Castrato"; + codeToLabel["casts"] = "Castanets"; + codeToLabel["cbass"] = "Contrabass"; + codeToLabel["cello"] = "Violoncello"; + codeToLabel["cemba"] = "Harpsichord"; + codeToLabel["cetra"] = "Cittern"; + codeToLabel["chain"] = "Chain"; + codeToLabel["chime"] = "Tubular bells"; + codeToLabel["chcym"] = "China cymbal"; + codeToLabel["chlma"] = "Soprano shawm"; + codeToLabel["chlmt"] = "Tenor shawm"; + codeToLabel["clap"] = "Hand clap"; + codeToLabel["clara"] = "Alto Clarinet"; + codeToLabel["clarb"] = "Bass Clarinet"; + codeToLabel["claro"] = "Sopranino clarinet"; + codeToLabel["clarp"] = "Piccolo clarinet"; + codeToLabel["clars"] = "Clarinet"; + codeToLabel["clave"] = "Claves"; + codeToLabel["clavi"] = "Clavichord"; + codeToLabel["clest"] = "Celesta"; + codeToLabel["clrno"] = "Clarino"; + codeToLabel["colsp"] = "Coloratura soprano"; + codeToLabel["conga"] = "Conga"; + codeToLabel["cor"] = "Horn"; + codeToLabel["cornm"] = "Cornemuse"; + codeToLabel["corno"] = "Cornett"; + codeToLabel["cornt"] = "Cornet"; + codeToLabel["coro"] = "Chorus"; + codeToLabel["crshc"] = "Crash cymbal"; + codeToLabel["ctenor"] = "Contratenor"; + codeToLabel["ctina"] = "concertina"; + codeToLabel["drmsp"] = "Dramatic soprano"; + codeToLabel["drum"] = "Drum"; + codeToLabel["drumP"] = "Small drum"; + codeToLabel["dulc"] = "Dulcimer"; + codeToLabel["eguit"] = "Electric guitar"; + codeToLabel["fag_c"] = "Contrabassoon"; + codeToLabel["fagot"] = "Bassoon"; + codeToLabel["false"] = "Falsetto"; + codeToLabel["feme"] = "Female voice"; + codeToLabel["fife"] = "Fife"; + codeToLabel["fingc"] = "Finger Cymbals"; + codeToLabel["flex"] = "Flexatone"; + codeToLabel["flt"] = "Flute"; + codeToLabel["flt_a"] = "Alto flute"; + codeToLabel["flt_b"] = "Bass flute"; + codeToLabel["fltda"] = "Alto recorder"; + codeToLabel["fltdb"] = "Bass recorder"; + codeToLabel["fltdn"] = "Sopranino recorder"; + codeToLabel["fltds"] = "Soprano recorder"; + codeToLabel["fltdt"] = "Tenor recorder"; + codeToLabel["flugh"] = "Flugelhorn"; + codeToLabel["forte"] = "Fortepiano"; + codeToLabel["glock"] = "Glockenspiel"; + codeToLabel["gen"] = "Generic instrument"; + codeToLabel["genT"] = "Generic treble instrument"; + codeToLabel["genB"] = "Generic bass instrument"; + codeToLabel["gong"] = "Gong"; + codeToLabel["guitr"] = "Guitar"; + codeToLabel["hammd"] = "Hammond eletronic organ"; + codeToLabel["hbell"] = "Hand bells"; + codeToLabel["heck"] = "Heckelphone"; + codeToLabel["heltn"] = "Heroic tenor"; + codeToLabel["hichi"] = "Hichiriki"; + codeToLabel["hurdy"] = "Hurdy-gurdy"; + codeToLabel["kitv"] = "Kit violin"; + codeToLabel["klav"] = "Generic keyboard"; + codeToLabel["kokyu"] = "Kokyu"; + codeToLabel["komun"] = "Koumngo"; + codeToLabel["koto"] = "Koto"; + codeToLabel["kruma"] = "Alto crumhorn"; + codeToLabel["krumb"] = "Bass crumhorn"; + codeToLabel["krums"] = "Crumhorn"; + codeToLabel["krumt"] = "Tenor crumhorn"; + codeToLabel["lion"] = "Lion's roar"; + codeToLabel["liuto"] = "Lute"; + codeToLabel["lyrsp"] = "Lyric soprano"; + codeToLabel["lyrtn"] = "Lyric tenor"; + codeToLabel["male"] = "Male voice"; + codeToLabel["mando"] = "Mandolin"; + codeToLabel["marac"] = "Maracas"; + codeToLabel["marim"] = "Marimba"; + codeToLabel["mezzo"] = "Mezzo soprano"; + codeToLabel["nfant"] = "Child's voice"; + codeToLabel["nokan"] = "Nokan"; + codeToLabel["oboe"] = "Oboe"; + codeToLabel["oboeD"] = "Oboe d'amore"; + codeToLabel["ocari"] = "Ocarina"; + codeToLabel["ondes"] = "Ondes Martenot"; + codeToLabel["ophic"] = "Ophicleide"; + codeToLabel["organ"] = "Organ"; + codeToLabel["oud"] = "Oud"; + codeToLabel["panpi"] = "Panpipes"; + codeToLabel["paila"] = "Timbales"; + codeToLabel["pbell"] = "Bell plate"; + codeToLabel["pguit"] = "Portuguese guitar"; + codeToLabel["physh"] = "Physharmonica"; + codeToLabel["piano"] = "Piano"; + codeToLabel["piatt"] = "Cymbales"; + codeToLabel["picco"] = "Piccolo"; + codeToLabel["pipa"] = "Pipa"; + codeToLabel["piri"] = "Piri"; + codeToLabel["porta"] = "Portative organ"; + codeToLabel["psalt"] = "Psaltery"; + codeToLabel["qin"] = "Qin"; + codeToLabel["quinto"] = "Quinto"; + codeToLabel["quitr"] = "Gittern"; + codeToLabel["rackt"] = "Rackett"; + codeToLabel["ratch"] = "Ratchet"; + codeToLabel["ratl"] = "Rattle"; + codeToLabel["rebec"] = "Rebec"; + codeToLabel["recit"] = "Recitativo"; + codeToLabel["reedo"] = "Reed organ"; + codeToLabel["rhode"] = "Rhodes piano"; + codeToLabel["ridec"] = "Ride cymbal"; + codeToLabel["sarod"] = "Sarod"; + codeToLabel["sarus"] = "Sarrusophone"; + codeToLabel["saxA"] = "Alto saxophone"; + codeToLabel["saxB"] = "Bass saxophone"; + codeToLabel["saxN"] = "Sopranino saxophone"; + codeToLabel["saxR"] = "Baritone saxophone"; + codeToLabel["saxS"] = "Saxophone"; + codeToLabel["saxT"] = "Tenor saxophone"; + codeToLabel["sbell"] = "Sleigh bells"; + codeToLabel["sdrum"] = "Snare drum"; + codeToLabel["serp"] = "Serpent"; + codeToLabel["sesto"] = "Sesto"; + codeToLabel["shaku"] = "Shakuhachi"; + codeToLabel["shami"] = "Shamisen"; + codeToLabel["sheng"] = "Sheng"; + codeToLabel["sho"] = "Sho"; + codeToLabel["siren"] = "Siren"; + codeToLabel["sitar"] = "Sitar"; + codeToLabel["slap"] = "Slapstick"; + codeToLabel["soprn"] = "Soprano"; + codeToLabel["spshc"] = "Splash cymbal"; + codeToLabel["spok"] = "Spoken voice"; + codeToLabel["spokF"] = "Female spoken voice"; + codeToLabel["spokM"] = "Male spoken voice"; + codeToLabel["steel"] = "Steel drum"; + codeToLabel["stim"] = "Sprechstimme"; + codeToLabel["stimS"] = "Soprano Sprechstimme"; + codeToLabel["stimA"] = "Alto Sprechstimme"; + codeToLabel["stimC"] = "Contralto Sprechstimme"; + codeToLabel["stimR"] = "Baritone Sprechstimme"; + codeToLabel["stimB"] = "Bass Sprechstimme"; + codeToLabel["strdr"] = "String drum"; + codeToLabel["sxhA"] = "Alto saxhorn"; + codeToLabel["sxhB"] = "Bass saxhorn"; + codeToLabel["sxhC"] = "Contrabass saxhorn"; + codeToLabel["sxhR"] = "Baritons saxhorn"; + codeToLabel["sxhS"] = "Saxhorn"; + codeToLabel["sxhT"] = "Tenor saxhorn"; + codeToLabel["synth"] = "Synthesizer"; + codeToLabel["tabla"] = "Tabla"; + codeToLabel["tambn"] = "Tambourine"; + codeToLabel["tambu"] = "Tambura"; + codeToLabel["tambr"] = "Tambur"; + codeToLabel["tblok"] = "Temple blocks"; + codeToLabel["tdrum"] = "Tenor drum"; + codeToLabel["tenor"] = "Tenor"; + codeToLabel["timpa"] = "Timpani"; + codeToLabel["tiorb"] = "Theorbo"; + codeToLabel["tom"] = "Tom-tom"; + codeToLabel["trngl"] = "Triangle"; + codeToLabel["troma"] = "Alto trombone"; + codeToLabel["tromb"] = "Bass trombone"; + codeToLabel["tromp"] = "Trumpet"; + codeToLabel["tromP"] = "Piccolo trumpet"; + codeToLabel["tromB"] = "Bass trumpet"; + codeToLabel["tromt"] = "Trombone"; + codeToLabel["tuba"] = "Tuba"; + codeToLabel["tubaB"] = "Bass Tuba"; + codeToLabel["tubaC"] = "Contrabass Tuba"; + codeToLabel["tubaT"] = "Tenor Tuba"; + codeToLabel["tubaU"] = "Subcontrabass Tuba"; + codeToLabel["ukule"] = "Ukulele"; + codeToLabel["vibra"] = "Vibraphone"; + codeToLabel["vina"] = "Vina"; + codeToLabel["viola"] = "Viola"; + codeToLabel["violb"] = "Bass viola da gamba"; + codeToLabel["viold"] = "Viola d'amore"; + codeToLabel["viole"] = "violone"; + codeToLabel["violn"] = "Violin"; + codeToLabel["violp"] = "Piccolo violin"; + codeToLabel["viols"] = "Viola da gamba"; + codeToLabel["violt"] = "Tenor viola da gamba"; + codeToLabel["vox"] = "Voice"; + codeToLabel["wblok"] = "Woodblock"; + codeToLabel["xylo"] = "Xylophone"; + codeToLabel["zithr"] = "Zither"; + codeToLabel["zurna"] = "Zurna"; + } + + std::string code = icode->substr(2); + + std::string output = codeToLabel[code]; if (output.empty()) { - // could not find an automatic name for the instrument. + // Could not find an automatic name for the instrument. return output; } @@ -8158,13 +8320,44 @@ std::string HumdrumInput::getLabelFromInstrumentCode(hum::HTp icode, const std:: else if (transpose == "*ITrd-5c-9") { output += " in E-flat"; } + // Add other keys here. + + // Add instrument number + string number = getInstrumentNumber(icode); + if (!number.empty()) { + output += " "; + output += number; + } return output; } ////////////////////////////// // -// hasIndent -- true if *indent tandem interpretation before first data token. +// HumdrumInput::getInstrumentNumber -- search until data has been found +// for an interpretation in the form *I#4 for instrument 4. +// + +std::string HumdrumInput::getInstrumentNumber(hum::HTp icode) +{ + hum::HTp current = icode->getNextToken(); + while (current && !current->isData()) { + if (!current->isInterpretation()) { + current = current->getNextToken(); + continue; + } + hum::HumRegex hre; + if (hre.search(current, "^\\*I#(\\d+)")) { + return hre.getMatch(1); + } + current = current->getNextToken(); + } + return ""; +} + +////////////////////////////// +// +// HumdrumInput::hasIndent -- true if *indent tandem interpretation before first data token. // bool HumdrumInput::hasIndent(hum::HTp tok) From 464b2cef14ae089251d2220d72f3d797ae830396 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Wed, 31 Jul 2024 20:04:41 -0700 Subject: [PATCH 3/7] Allow verse labels for **silbe spines. --- include/hum/humlib.h | 2 +- src/hum/humlib.cpp | 2 +- src/iohumdrum.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index 374d43cb064..a0e6a56448a 100644 --- a/include/hum/humlib.h +++ b/include/hum/humlib.h @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Mon Jul 29 23:24:23 PDT 2024 +// Last Modified: Tue Jul 30 20:12:26 PDT 2024 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index 38eb3f94e01..1a089b2d485 100644 --- a/src/hum/humlib.cpp +++ b/src/hum/humlib.cpp @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Mon Jul 29 23:24:23 PDT 2024 +// Last Modified: Tue Jul 30 20:12:26 PDT 2024 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 3d6247b9b96..ed4bffdf391 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -13682,7 +13682,7 @@ void HumdrumInput::checkForVerseLabels(hum::HTp token) current = current->getNextFieldToken(); } while (current && !current->isStaff()) { - if (!(current->isDataTypeLike("**text") || current->isDataTypeLike("**vdata"))) { + if (!(current->isDataTypeLike("**text") || current->isDataTypeLike("**silbe") || current->isDataTypeLike("**vdata"))) { current = current->getNextFieldToken(); continue; } From 8ada6eb95741761ef3630d3f0a21cc86722bf632 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Fri, 16 Aug 2024 11:29:20 -0700 Subject: [PATCH 4/7] Humlib updates. --- include/hum/humlib.h | 60 ++-- src/hum/humlib.cpp | 754 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 729 insertions(+), 85 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index a0e6a56448a..5dfe597853f 100644 --- a/include/hum/humlib.h +++ b/include/hum/humlib.h @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Tue Jul 30 20:12:26 PDT 2024 +// Last Modified: Thu Aug 8 21:55:11 PDT 2024 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 @@ -8386,9 +8386,12 @@ class Tool_kernify : public HumTool { void generateDummyKernSpine (HumdrumFile& infile); std::string makeNullLine (HumdrumLine& line); std::string makeReverseLine (HumdrumLine& line); + bool prepareDataSpines (HumdrumFile& infile); + bool prepareDataSpine (HTp spinestart); private: bool m_forceQ = false; // used with -f option + bool m_hasDataInterpretations = false; }; @@ -10347,32 +10350,53 @@ class Tool_rphrase : public HumTool { void processFile (HumdrumFile& infile); void fillVoiceInfo (std::vector& voiceInfo, std::vector& kstarts, HumdrumFile& infile); void fillVoiceInfo (Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart, HumdrumFile& infile); - void fillCollapseInfo (Tool_rphrase::VoiceInfo& collapseInfo, HumdrumFile& infile); + void fillCompositeInfo (Tool_rphrase::VoiceInfo& collapseInfo, HumdrumFile& infile); void printVoiceInfo (std::vector& voiceInfo); void printVoiceInfo (Tool_rphrase::VoiceInfo& voiceInfo); + + void printEmbeddedVoiceInfo(std::vector& voiceInfo, Tool_rphrase::VoiceInfo& collapseInfo, HumdrumFile& infile); + void printEmbeddedIndividualVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HumdrumFile& infile); + void printEmbeddedCompositeInfo(Tool_rphrase::VoiceInfo& compositeInfo, HumdrumFile& infile); + void getCompositeStates(std::vector& noteStates, HumdrumFile& infile); std::string getCompositeLabel(HumdrumFile& infile); void markPhraseStartsInScore(HumdrumFile& infile, Tool_rphrase::VoiceInfo& voiceInfo); - void outputMarkedFile (HumdrumFile& infile); + void markCompositePhraseStartsInScore(HumdrumFile& infile, Tool_rphrase::VoiceInfo& collapseInfo); + void outputMarkedFile (HumdrumFile& infile, std::vector& voiceInfo, + Tool_rphrase::VoiceInfo& compositeInfo); void printDataLine (HumdrumFile& infile, int index); void markLongaDurations(HumdrumFile& infile); + std::string getVoiceInfo(HumdrumFile& infile); + void printEmbeddedVoiceInfoSummary(std::vector& voiceInfo, HumdrumFile& infile); + double twoDigitRound(double input); + void printHyperlink(const std::string& urlType); private: - bool m_averageQ = false; // for -a option - bool m_allAverageQ = false; // for -A option - bool m_barlineQ = false; // for -m option - bool m_collapseQ = false; // for -c option - bool m_longaQ = false; // for -l option - bool m_filenameQ = false; // for -f option - bool m_fullFilenameQ = false; // for -F option - std::string m_filename; // for -f or -F option - bool m_sortQ = false; // for -s option - bool m_reverseSortQ = false; // for -S option - int m_pcount = 0; // for -a option - double m_sum = 0.0; // for -a option - int m_pcountCollapse= 0; // for -c option - double m_sumCollapse = 0.0; // for -c option - bool m_markQ = false; // for --mark option + bool m_averageQ = false; // for -a option + bool m_allAverageQ = false; // for -A option + bool m_breathQ = true; // for -B option + bool m_barlineQ = false; // for -m option + bool m_compositeQ = false; // for -c option + bool m_longaQ = false; // for -l option + bool m_filenameQ = false; // for -f option + bool m_fullFilenameQ = false; // for -F option + std::string m_filename; // for -f or -F option + bool m_sortQ = false; // for -s option + bool m_reverseSortQ = false; // for -S option + int m_pcount = 0; // for -a option + double m_sum = 0.0; // for -a option + int m_pcountComposite = 0; // for -c option + double m_sumComposite = 0.0; // for -c option + bool m_markQ = false; // for --mark option + double m_durUnit = 2.0; // for -d option + bool m_infoQ = false; // for -i option (when --mark is active) + bool m_squeezeQ = false; // for -z option + bool m_closeQ = false; // for --close option + std::string m_urlType; // for -u option + + int m_line = 1; + std::string m_voiceLengthColor = "crimson"; + std::string m_compositeLengthColor = "limegreen"; }; diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index 1a089b2d485..1b5e14d1d75 100644 --- a/src/hum/humlib.cpp +++ b/src/hum/humlib.cpp @@ -1,7 +1,7 @@ // // Programmer: Craig Stuart Sapp // Creation Date: Sat Aug 8 12:24:49 PDT 2015 -// Last Modified: Tue Jul 30 20:12:26 PDT 2024 +// Last Modified: Thu Aug 8 21:55:11 PDT 2024 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 @@ -83262,6 +83262,8 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(recip, infile, commands[i].second, status); } else if (commands[i].first == "restfill") { RUNTOOL(restfill, infile, commands[i].second, status); + } else if (commands[i].first == "rphrase") { + RUNTOOL(rphrase, infile, commands[i].second, status); } else if (commands[i].first == "sab2gs") { RUNTOOL(sab2gs, infile, commands[i].second, status); } else if (commands[i].first == "scordatura") { @@ -91672,6 +91674,7 @@ bool Tool_kernify::run(HumdrumFile& infile, ostream& out) { bool Tool_kernify::run(HumdrumFile& infile) { initialize(); + m_hasDataInterpretations = prepareDataSpines(infile); processFile(infile); return true; } @@ -91703,6 +91706,71 @@ void Tool_kernify::processFile(HumdrumFile& infile) { +////////////////////////////// +// +// Tool_kernify::prepareDataSpines -- +// + +bool Tool_kernify::prepareDataSpines(HumdrumFile& infile) { + vector spinestarts; + infile.getSpineStartList(spinestarts); + bool output = false; + for (int i=0; i<(int)spinestarts.size(); i++) { + output |= prepareDataSpine(spinestarts[i]); + } + return output; +} + + + +////////////////////////////// +// +// Tool_kernify::prepareDataSpine -- check to see if *[abcv]data interpretation and if so process +// and return true; +// + +bool Tool_kernify::prepareDataSpine(HTp spinestart) { + HumRegex hre; + if (hre.search(spinestart, "^\\*\\*[abcv]data-")) { + return false; + } + + string prefix; + HTp current = spinestart->getNextToken(); + while (current && !current->isData()) { + if (current->isInterpretation()) { + if (*current == "*adata") { + prefix = "adata"; + break; + } else if (*current == "*bdata") { + prefix = "bdata"; + break; + } else if (*current == "*cdata") { + prefix = "cdata"; + break; + } else if (*current == "*vdata") { + prefix = "vdata"; + break; + } + } + current = current->getNextToken(); + } + + if (prefix.empty()) { + return false; + } + + string text = "**"; + text += prefix; + text += "-"; + text += spinestart->substr(2); + spinestart->setText(text); + + return true; +} + + + ////////////////////////////// // // Tool_kernify::generateDummyKernSpine -- @@ -91776,18 +91844,22 @@ void Tool_kernify::generateDummyKernSpine(HumdrumFile& infile) { } else if (token->find("**kern") != std::string::npos) { string value = *token; hre.replaceDestructive(value, "nrek", "kern", "g"); - hre.replaceDestructive(value, "**cdata-", "^\\*\\*"); + hre.replaceDestructive(value, "**zcdata-", "^\\*\\*"); m_humdrum_text << "\t" << value; } else if (token->find("**mens") != std::string::npos) { string value = *token; hre.replaceDestructive(value, "snem", "mens", "g"); - hre.replaceDestructive(value, "**cdata-", "^\\*\\*"); + hre.replaceDestructive(value, "**ycdata-", "^\\*\\*"); m_humdrum_text << "\t" << value; } else if (token->find("**cdata") == std::string::npos) { - string value = token->substr(2); - hre.replaceDestructive(value, "nrek", "kern", "g"); - hre.replaceDestructive(value, "snem", "snem", "g"); - m_humdrum_text << "\t**cdata-" << value; + if (!m_hasDataInterpretations) { + string value = token->substr(2); + hre.replaceDestructive(value, "nrek", "kern", "g"); + hre.replaceDestructive(value, "snem", "snem", "g"); + m_humdrum_text << "\t**xcdata-" << value; + } else { + m_humdrum_text << "\t" << token; + } } else { m_humdrum_text << "\t" << token; } @@ -91842,7 +91914,12 @@ void Tool_kernify::generateDummyKernSpine(HumdrumFile& infile) { m_humdrum_text << "*clefXyy" << "\t" << makeReverseLine(infile[i]); clefIndex = -1; } else { - m_humdrum_text << "*" << "\t" << makeReverseLine(infile[i]); + HTp token = infile[i].token(0); + if (token->compare(0, 2, "*>") == 0) { + m_humdrum_text << token << "\t" << makeReverseLine(infile[i]); + } else { + m_humdrum_text << "*" << "\t" << makeReverseLine(infile[i]); + } } } else { m_humdrum_text << "!!UNKNONWN LINE TYPE FOR LINE " << i+1 << ":\t" << infile[i]; @@ -118102,17 +118179,22 @@ void Tool_rid::processFile(HumdrumFile& infile) { // Tool_rphrase::Tool_rphrase(void) { - // add command-line options here define("a|average=b", "calculate average length of rest-phrases by score"); define("A|all-average=b", "calculate average length of rest-phrases for all scores"); + define("B|no-breath=b", "ignore breath interpretations"); define("c|composite|collapse=b", "collapse all voices into single part"); + define("d|duration-unit=d:2.0", "duration units, default: 2.0 (minims/half notes)"); define("f|filename=b", "include filename in output analysis"); define("F|full-filename=b", "include full filename location in output analysis"); + define("I|no-info=b", "do not display summary info"); define("l|longa=b", "display minim length of longas"); define("m|b|measure|barline=b", "include barline numbers in output analysis"); define("mark=b", "mark starts of phrases in score"); define("s|sort=b", "sort phrases by short to long length"); define("S|reverse-sort=b", "sort phrases by long to short length"); + define("u|url-type=s", "URL type (jrp, 1520s) for hyperlink"); + define("z|squeeze=b", "squeeze notation"); + define("close=b", "close details element initially"); } @@ -118170,8 +118252,8 @@ bool Tool_rphrase::run(HumdrumFile& infile) { void Tool_rphrase::finally(void) { if (!m_markQ) { if (m_allAverageQ) { - if (m_collapseQ) { - double average = m_sumCollapse / m_pcountCollapse; + if (m_compositeQ) { + double average = m_sumComposite / m_pcountComposite; m_free_text << "Composite average phrase length: " << average << " minims" << endl; } else { double average = m_sum / m_pcount; @@ -118189,25 +118271,27 @@ void Tool_rphrase::finally(void) { // void Tool_rphrase::initialize(void) { - m_averageQ = getBoolean("average"); m_barlineQ = getBoolean("measure"); m_allAverageQ = getBoolean("all-average"); - #ifndef __EMSCRIPTEN__ - m_collapseQ = !getBoolean("collapse"); - #else - m_collapseQ = getBoolean("collapse"); - #endif + m_breathQ = !getBoolean("no-breath"); + m_compositeQ = getBoolean("collapse"); m_filenameQ = getBoolean("filename"); m_fullFilenameQ = getBoolean("full-filename"); + m_urlType = getString("url-type"); m_longaQ = getBoolean("longa"); #ifndef __EMSCRIPTEN__ m_markQ = getBoolean("mark"); + m_averageQ = getBoolean("average"); #else m_markQ = !getBoolean("mark"); + m_averageQ = !getBoolean("average"); #endif m_sortQ = getBoolean("sort"); m_reverseSortQ = getBoolean("reverse-sort"); - m_longaQ = getBoolean("longa"); + m_durUnit = getDouble("duration-unit"); + m_infoQ = !getDouble("no-info"); + m_squeezeQ = getBoolean("squeeze"); + m_closeQ = getBoolean("close"); } @@ -118228,29 +118312,64 @@ void Tool_rphrase::processFile(HumdrumFile& infile) { } vector kernStarts = infile.getKernSpineStartList(); vector voiceInfo(kernStarts.size()); - Tool_rphrase::VoiceInfo collapseInfo; + Tool_rphrase::VoiceInfo compositeInfo; - if (m_collapseQ) { - fillCollapseInfo(collapseInfo, infile); + if (m_compositeQ) { + fillCompositeInfo(compositeInfo, infile); } else { fillVoiceInfo(voiceInfo, kernStarts, infile); } - if (m_longaQ) { markLongaDurations(infile); } - if (!m_allAverageQ) { - if (m_collapseQ) { - printVoiceInfo(collapseInfo); + if ((!m_allAverageQ) && (!m_markQ)) { + if (m_line == 1) { + if (m_compositeQ) { + m_free_text << "Filename"; + if (!m_urlType.empty()) { + m_free_text << "\tVHV"; + } + m_free_text << "\tVoice"; + m_free_text << "\tComp seg count"; + if (m_averageQ) { + m_free_text << "\tAvg comp seg dur"; + } + m_free_text << "\tComposite seg durs"; + m_free_text << endl; + } else { + m_free_text << "Filename"; + if (!m_urlType.empty()) { + m_free_text << "\tVHV"; + } + m_free_text << "\tVoice"; + m_free_text << "\tSounding dur"; + m_free_text << "\tResting dur"; + m_free_text << "\tTotal dur"; + m_free_text << "\tSeg count"; + if (m_averageQ) { + m_free_text << "\tSeg dur average"; + } + m_free_text << "\tSegment durs"; + m_free_text << endl; + } + } + if (m_compositeQ) { + if (m_compositeQ) { + m_line++; + } + printVoiceInfo(compositeInfo); } else { printVoiceInfo(voiceInfo); } } if (m_markQ) { - outputMarkedFile(infile); + outputMarkedFile(infile, voiceInfo, compositeInfo); + if (m_squeezeQ) { + m_humdrum_text << "!!!verovio: evenNoteSpacing" << endl; + } } } @@ -118303,7 +118422,7 @@ void Tool_rphrase::markLongaDurations(HumdrumFile& infile) { HumNum duration = token->getTiedDuration(); stringstream value; value.str(""); - value << duration.getFloat() / 2.0; + value << duration.getFloat() / m_durUnit; token->setValue("auto", "rphrase-longa", value.str()); } } @@ -118317,7 +118436,8 @@ void Tool_rphrase::markLongaDurations(HumdrumFile& infile) { // Tool_rphrase::outputMarkedFile -- // -void Tool_rphrase::outputMarkedFile(HumdrumFile& infile) { +void Tool_rphrase::outputMarkedFile(HumdrumFile& infile, vector& voiceInfo, + Tool_rphrase::VoiceInfo& compositeInfo) { m_free_text.clear(); m_free_text.str(""); for (int i=0; i 0.0) { + sounding += voiceInfo.phraseDurs[i]; + } + if (voiceInfo.restsBefore[i] > 0.0) { + resting += voiceInfo.restsBefore[i]; + } + } + double total = sounding + resting; + // double sounding_percent = int (sounding/total * 100.0 + 0.5); + // double resting_percent = int (sounding/total * 100.0 + 0.5); + + m_free_text << twoDigitRound(sounding) << "\t"; + m_free_text << twoDigitRound(resting) << "\t"; + m_free_text << twoDigitRound(total) << "\t"; + } + + m_free_text << voiceInfo.phraseDurs.size() << "\t"; + if (m_averageQ) { double sum = 0; int count = 0; @@ -118503,7 +118712,7 @@ void Tool_rphrase::printVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo) { if (m_barlineQ) { m_free_text << "m" << voiceInfo.barStarts.at(ii) << ":"; } - m_free_text << voiceInfo.phraseDurs.at(ii); + m_free_text << twoDigitRound(voiceInfo.phraseDurs.at(ii)); if (i < (int)sortList.size() - 1) { m_free_text << " "; } @@ -118511,12 +118720,15 @@ void Tool_rphrase::printVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo) { } else { for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { if (voiceInfo.restsBefore.at(i) > 0) { - m_free_text << "r:" << voiceInfo.restsBefore.at(i) << " "; + m_free_text << "r:" << twoDigitRound(voiceInfo.restsBefore.at(i)) << " "; + } else if (i > 0) { + // force display r:0 for section boundaries. + m_free_text << "r:" << twoDigitRound(voiceInfo.restsBefore.at(i)) << " "; } if (m_barlineQ) { m_free_text << "m" << voiceInfo.barStarts.at(i) << ":"; } - m_free_text << voiceInfo.phraseDurs.at(i); + m_free_text << twoDigitRound(voiceInfo.phraseDurs.at(i)); if (i < (int)voiceInfo.phraseDurs.size() - 1) { m_free_text << " "; } @@ -118530,11 +118742,362 @@ void Tool_rphrase::printVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo) { ////////////////////////////// // -// Tool_rphrase::fillCollapseInfo -- +// Tool_rphrase::printEmbeddedVoiceInfo -- +// + +void Tool_rphrase::printEmbeddedVoiceInfo(vector& voiceInfo, Tool_rphrase::VoiceInfo& compositeInfo, HumdrumFile& infile) { + + m_humdrum_text << "!!@@BEGIN: PREHTML" << endl;; + + m_humdrum_text << "!!@SCRIPT:" << endl; + m_humdrum_text << "!! function rphraseGotoMeasure(measure) {" << endl; + m_humdrum_text << "!! let target = `svg .measure.m-${measure}`;" << endl; + m_humdrum_text << "!! let element = document.querySelector(target);" << endl; + m_humdrum_text << "!! if (element) {" << endl; + m_humdrum_text << "!! element.scrollIntoViewIfNeeded({ behavior: 'smooth' });" << endl; + m_humdrum_text << "!! }" << endl; + m_humdrum_text << "!! }" << endl; + + m_humdrum_text << "!!@CONTENT:\n"; + if (m_compositeQ) { + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + } else { + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + } + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + + if (m_compositeQ) { + m_humdrum_text << "!!Composite rest phrasing\n"; + } else { + m_humdrum_text << "!!Voice rest phrasing\n"; + } + if (m_compositeQ) { + printEmbeddedCompositeInfo(compositeInfo, infile); + } else { + if (voiceInfo.size() > 0) { + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!" << endl; + for (int i=(int)voiceInfo.size() - 1; i>=0; i--) { + printEmbeddedIndividualVoiceInfo(voiceInfo[i], infile); + } + m_humdrum_text << "!!
VoiceSoundingRestingSegmentsAverageSegment durations
" << endl; + printEmbeddedVoiceInfoSummary(voiceInfo, infile); + } + } + m_humdrum_text << "!!" << endl; + m_humdrum_text << "!!@@END: PREHTML" << endl; +} + + + +////////////////////////////// +// +// Tool_rphrase::printEmbeddedCompositeInfo -- // -void Tool_rphrase::fillCollapseInfo(Tool_rphrase::VoiceInfo& collapseInfo, HumdrumFile& infile) { - collapseInfo.name = getCompositeLabel(infile); +void Tool_rphrase::printEmbeddedCompositeInfo(Tool_rphrase::VoiceInfo& compositeInfo, HumdrumFile& infile) { + + m_humdrum_text << "!!
" << endl; + m_humdrum_text << "!!
    " << endl; + m_humdrum_text << "!!
  • Composite segment count: " << compositeInfo.phraseDurs.size() << "
  • " << endl; + + if (!compositeInfo.phraseDurs.empty()) { + m_humdrum_text << "!!
  • Composite segment duration"; + if (compositeInfo.phraseDurs.size() != 1) { + m_humdrum_text << "s"; + } + m_humdrum_text << ": "; + if (m_sortQ || m_reverseSortQ) { + vector> sortList; + for (int i=0; i<(int)compositeInfo.phraseDurs.size(); i++) { + sortList.emplace_back(compositeInfo.phraseDurs[i], i); + } + if (m_sortQ) { + sort(sortList.begin(), sortList.end(), + [](const std::pair& a, const std::pair& b) { + return a.first < b.first; + }); + } else if (m_reverseSortQ) { + sort(sortList.begin(), sortList.end(), + [](const std::pair& a, const std::pair& b) { + return a.first > b.first; + }); + } + + for (int i=0; i<(int)sortList.size(); i++) { + int ii = sortList[i].second; + if (m_barlineQ) { + m_humdrum_text << "m" << compositeInfo.barStarts.at(ii) << ":"; + } + m_humdrum_text << "" << twoDigitRound(compositeInfo.phraseDurs.at(ii)) << ""; + if (i < (int)sortList.size() - 1) { + m_humdrum_text << " "; + } + } + } else { + for (int i=0; i<(int)compositeInfo.phraseDurs.size(); i++) { + if (compositeInfo.restsBefore.at(i) > 0) { + m_humdrum_text << "" << twoDigitRound(compositeInfo.restsBefore.at(i)) << " "; + } else if (i > 0) { + // force display r:0 for section boundaries. + m_humdrum_text << "" << twoDigitRound(compositeInfo.restsBefore.at(i)) << " "; + } + if (m_barlineQ) { + m_humdrum_text << "m" << compositeInfo.barStarts.at(i) << ":"; + } + m_humdrum_text << "" << twoDigitRound(compositeInfo.phraseDurs.at(i)) << ""; + if (i < (int)compositeInfo.phraseDurs.size() - 1) { + m_humdrum_text << " "; + } + } + } + m_humdrum_text << "
  • " << endl; + + if (m_averageQ && (compositeInfo.phraseDurs.size() > 1)) { + double sum = 0; + int count = 0; + for (int i=0; i<(int)compositeInfo.phraseDurs.size(); i++) { + count++; + sum += compositeInfo.phraseDurs.at(i); + } + double average = int(sum / count * 100.0 + 0.5)/100.0; + m_humdrum_text << "!!
  • Average composite segment durations: " << average << "
  • " << endl; + } + + m_humdrum_text << "!!
  • Voices: " << getVoiceInfo(infile) << "
  • " << endl; + + if (m_durUnit != 2.0) { + m_humdrum_text << "!!
  • Duration unit: " << m_durUnit << "
  • " << endl; + } + } + + m_humdrum_text << "!!
" << endl; + m_humdrum_text << "!!
" << endl; +} + + + +////////////////////////////// +// +// Tool_rphrase::getVoiceInfo -- +// + +string Tool_rphrase::getVoiceInfo(HumdrumFile& infile) { + vector kspines = infile.getKernSpineStartList(); + string vcount = to_string(kspines.size()); + string ocount; + for (int i=0; i& voiceInfo, HumdrumFile& infile) { + m_humdrum_text << "!!
    " << endl; + + double total = 0.0; + for (int i=0; i<(int)voiceInfo[0].phraseDurs.size(); i++) { + if (voiceInfo[0].phraseDurs[i] > 0.0) { + total += voiceInfo[0].phraseDurs[i]; + } + if (voiceInfo[0].restsBefore[i] > 0.0) { + total += voiceInfo[0].restsBefore[i]; + } + } + m_humdrum_text << "!!
  • Score duration: " << twoDigitRound(total) << "
  • " << endl; + + int countSum = 0; + for (int i=0; i<(int)voiceInfo.size(); i++) { + countSum += (int)voiceInfo[i].phraseDurs.size(); + } + m_humdrum_text << "!!
  • Total segments: " << countSum << "
  • " << endl; + + double averageCount = countSum / (double)voiceInfo.size(); + averageCount = (int)(averageCount * 10 + 0.5) / 10.0; + m_humdrum_text << "!!
  • Average voice segments: " << averageCount << "
  • " << endl; + + double durSum = 0.0; + for (int i=0; i<(int)voiceInfo.size(); i++) { + for (int j=0; j<(int)voiceInfo[i].phraseDurs.size(); j++) { + durSum += voiceInfo[i].phraseDurs[j]; + } + } + double averageDur = durSum / countSum; + averageDur = (int)(averageDur * 10 + 0.5) / 10.0; + m_humdrum_text << "!!
  • Average segment duration: " << averageDur << "
  • " << endl; + + m_humdrum_text << "!!
  • Voices: " << getVoiceInfo(infile) << "
  • " << endl; + + m_humdrum_text << "!!
" << endl; +} + + + +////////////////////////////// +// +// Tool_rphrase::printEmbeddedIndividualVoiceInfo -- +// + +void Tool_rphrase::printEmbeddedIndividualVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HumdrumFile& infile) { + m_humdrum_text << "!!" << endl; + + m_humdrum_text << "!!" << voiceInfo.name << "" << endl; + + double sounding = 0.0; + double resting = 0.0; + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + if (voiceInfo.phraseDurs[i] > 0.0) { + sounding += voiceInfo.phraseDurs[i]; + } + if (voiceInfo.restsBefore[i] > 0.0) { + resting += voiceInfo.restsBefore[i]; + } + } + double total = sounding + resting; + double spercent = int(sounding/total * 100.0 + 0.5); + double rpercent = int(resting/total * 100.0 + 0.5); + m_humdrum_text << "!!" << sounding << "(" << spercent << "%)" << endl; + m_humdrum_text << "!!" << resting << "(" << rpercent << "%)" << endl; + + // Segment count + m_humdrum_text << "!!"; + m_humdrum_text << voiceInfo.phraseDurs.size(); + m_humdrum_text << "" << endl; + + // Segment duration average + m_humdrum_text << "!!"; + double sum = 0; + int count = 0; + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + count++; + sum += voiceInfo.phraseDurs.at(i); + } + double average = int(sum / count * 100.0 + 0.5)/100.0; + m_humdrum_text << average; + m_humdrum_text << "" << endl; + + // Segments + m_humdrum_text << "!!"; + if (m_sortQ || m_reverseSortQ) { + vector> sortList; + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + sortList.emplace_back(voiceInfo.phraseDurs[i], i); + } + if (m_sortQ) { + sort(sortList.begin(), sortList.end(), + [](const std::pair& a, const std::pair& b) { + return a.first < b.first; + }); + } else if (m_reverseSortQ) { + sort(sortList.begin(), sortList.end(), + [](const std::pair& a, const std::pair& b) { + return a.first > b.first; + }); + } + for (int i=0; i<(int)sortList.size(); i++) { + int ii = sortList[i].second; + if (m_barlineQ) { + m_humdrum_text << "m" << voiceInfo.barStarts.at(ii) << ":"; + } + m_humdrum_text << "" << twoDigitRound(voiceInfo.phraseDurs.at(ii)) << ""; + if (i < (int)sortList.size() - 1) { + m_humdrum_text << " "; + } + } + } else { + for (int i=0; i<(int)voiceInfo.phraseDurs.size(); i++) { + if (voiceInfo.restsBefore.at(i) > 0) { + m_humdrum_text << "" << twoDigitRound(voiceInfo.restsBefore.at(i)) << " "; + } else if (i > 0) { + // force display r:0 for section boundaries. + m_humdrum_text << "" << twoDigitRound(voiceInfo.restsBefore.at(i)) << " "; + } + if (m_barlineQ) { + m_humdrum_text << "m" << voiceInfo.barStarts.at(i) << ":"; + } + m_humdrum_text << "" << twoDigitRound(voiceInfo.phraseDurs.at(i)) << ""; + if (i < (int)voiceInfo.phraseDurs.size() - 1) { + m_humdrum_text << " "; + } + } + } + + m_humdrum_text << "" << endl; + m_humdrum_text << "!!" << endl; +} + + + +////////////////////////////// +// +// Tool_rphrase::fillCompositeInfo -- +// + +void Tool_rphrase::fillCompositeInfo(Tool_rphrase::VoiceInfo& compositeInfo, HumdrumFile& infile) { + compositeInfo.name = getCompositeLabel(infile); vector noteStates; getCompositeStates(noteStates, infile); @@ -118542,11 +119105,10 @@ void Tool_rphrase::fillCollapseInfo(Tool_rphrase::VoiceInfo& collapseInfo, Humdr int currentBarline = 0; int startBarline = 1; HumNum startTime = 0; - HumNum restBefore = 0; HumNum startTimeRest = 0; - - HumNum scoreDur = infile.getScoreDuration(); + HumNum scoreDur = infile.getScoreDuration(); + HTp phraseStartTok = NULL; for (int i=0; i& voiceInfo, } - void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart, HumdrumFile& infile) { HTp current = kstart; @@ -118753,13 +119330,15 @@ void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart HumNum duration = endTime - startTime; startTime = -1; inPhraseQ = false; - voiceInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + double value = duration.getFloat() / m_durUnit; + voiceInfo.phraseDurs.push_back(value); voiceInfo.barStarts.push_back(startBarline); voiceInfo.phraseStartToks.push_back(phraseStartTok); phraseStartTok = NULL; - m_sum += duration.getFloat() / 2.0; + m_sum += duration.getFloat() / m_durUnit; m_pcount++; - voiceInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + double rvalue = restBefore.getFloat() / m_durUnit; + voiceInfo.restsBefore.push_back(rvalue); // record rest start startTimeRest = endTime; @@ -118785,7 +119364,7 @@ void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart if (current->isInstrumentName()) { voiceInfo.name = current->substr(3); } - if (!current->isData()) { + if (!(current->isData() || (m_breathQ && (*current == "*breath")))) { current = current->getNextToken(); continue; } @@ -118798,19 +119377,21 @@ void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart // In phrase, so continue if still notes, otherwise // if a rest, then record the currently active phrase // that has ended. - if (current->isRest()) { + if (current->isRest() || (*current == "*breath")) { // ending a phrase HumNum endTime = current->getDurationFromStart(); HumNum duration = endTime - startTime; startTime = -1; inPhraseQ = false; - voiceInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + double value = duration.getFloat() / m_durUnit; + voiceInfo.phraseDurs.push_back(value); voiceInfo.barStarts.push_back(startBarline); voiceInfo.phraseStartToks.push_back(phraseStartTok); phraseStartTok = NULL; - m_sum += duration.getFloat() / 2.0; + m_sum += duration.getFloat() / m_durUnit; m_pcount++; - voiceInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + double rvalue = restBefore.getFloat() / m_durUnit; + voiceInfo.restsBefore.push_back(rvalue); // record rest start startTimeRest = endTime; } else { @@ -118819,7 +119400,7 @@ void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart } else { // Not in phrase, so continue if rest; otherwise, // if a note, then record a phrase start. - if (current->isRest()) { + if (current->isRest() || (*current == "*breath")) { // continuing a non-phrase, so do nothing } else { // starting a phrase @@ -118844,13 +119425,14 @@ void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart // process last phrase HumNum endTime = kstart->getLine()->getOwner()->getScoreDuration(); HumNum duration = endTime - startTime; - voiceInfo.phraseDurs.push_back(duration.getFloat() / 2.0); + double value = duration.getFloat() / m_durUnit; + voiceInfo.phraseDurs.push_back(value); voiceInfo.barStarts.push_back(startBarline); voiceInfo.phraseStartToks.push_back(phraseStartTok); - m_sum += duration.getFloat() / 2.0; + m_sum += duration.getFloat() / m_durUnit; m_pcount++; - voiceInfo.restsBefore.push_back(0.0); - voiceInfo.restsBefore.push_back(restBefore.getFloat() / 2.0); + double rvalue = restBefore.getFloat() / m_durUnit; + voiceInfo.restsBefore.push_back(rvalue); } if (m_markQ) { @@ -118859,6 +119441,44 @@ void Tool_rphrase::fillVoiceInfo(Tool_rphrase::VoiceInfo& voiceInfo, HTp& kstart } + +////////////////////////////// +// +// Tool_rphrase::markCompositePhraseStartsInScore -- +// + +void Tool_rphrase::markCompositePhraseStartsInScore(HumdrumFile& infile, Tool_rphrase::VoiceInfo& compositeInfo) { + stringstream buffer; + for (int i=0; i<(int)compositeInfo.phraseStartToks.size(); i++) { + HTp tok = compositeInfo.phraseStartToks.at(i); + string measure = ""; + if (m_barlineQ) { + measure = to_string(compositeInfo.barStarts.at(i)); + } + double duration = compositeInfo.phraseDurs.at(i); + buffer.str(""); + if (!measure.empty()) { + buffer << "m" << measure << ":"; + } + buffer << twoDigitRound(duration); + int lineIndex = tok->getLineIndex(); + infile[lineIndex].setValue("auto", "rphrase-composite-start", buffer.str()); + } +} + + + +////////////////////////////// +// +// Tool_rphrase::twoDigitRound -- +// + +double Tool_rphrase::twoDigitRound(double input) { + return int(input * 100.0 + 0.499999) / 100.0; +} + + + ////////////////////////////// // // Tool_rphrase::markPhraseStartsInScore -- From de956056fe0fbd0546e27804b6b1a950c34bbdc2 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Wed, 21 Aug 2024 03:56:50 -0700 Subject: [PATCH 5/7] Allow newines and symbols mixing on staff labels. --- src/iohumdrum.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index ed4bffdf391..70c8a2b4131 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -13682,7 +13682,8 @@ void HumdrumInput::checkForVerseLabels(hum::HTp token) current = current->getNextFieldToken(); } while (current && !current->isStaff()) { - if (!(current->isDataTypeLike("**text") || current->isDataTypeLike("**silbe") || current->isDataTypeLike("**vdata"))) { + if (!(current->isDataTypeLike("**text") || current->isDataTypeLike("**silbe") + || current->isDataTypeLike("**vdata"))) { current = current->getNextFieldToken(); continue; } @@ -18263,11 +18264,11 @@ bool HumdrumInput::setLabelContent(Label *label, const std::string &name) } if (symbol.empty()) { - addTextElement(label, name2); + insertTextWithNewlines(label, name2); } else { if (!prestring.empty()) { - addTextElement(label, prestring); + insertTextWithNewlines(label, prestring); } Rend *rend = new Rend(); Text *text = new Text(); @@ -18276,7 +18277,7 @@ bool HumdrumInput::setLabelContent(Label *label, const std::string &name) label->AddChild(rend); rend->SetGlyphAuth("smufl"); if (!poststring.empty()) { - addTextElement(label, poststring); + insertTextWithNewlines(label, poststring); } // verovio probably eats the space surronding the // rend, so may need to force to be non-breaking space. @@ -18285,6 +18286,30 @@ bool HumdrumInput::setLabelContent(Label *label, const std::string &name) return true; } +////////////////////////////// +// +// HumdrumInput::insertTextWithNewlines -- +// + +void HumdrumInput::insertTextWithNewlines(Label *label, const std::string &text) +{ + vector pieces; + hum::HumRegex hre; + hre.split(pieces, text, "\\\\n"); + if (pieces.size() == 1) { + addTextElement(label, text); + } + else { + for (int i = 0; i < (int)pieces.size(); i++) { + addTextElement(label, pieces.at(i)); + if (i < (int)pieces.size() - 1) { + Lb *lb = new Lb(); + label->AddChild(lb); + } + } + } +} + ////////////////////////////// // // HumdrumInput::setTempoContent -- From a94213390bd7a73d3c86e09c6b092d9bdcdc31a9 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Wed, 21 Aug 2024 04:10:32 -0700 Subject: [PATCH 6/7] Allow rz accents/dynamics. --- src/iohumdrum.cpp | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 70c8a2b4131..15137e742f3 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -19340,7 +19340,7 @@ void HumdrumInput::processDynamics(hum::HTp token, int staffindex) ////////////////////////////// // -// HumdrumInput::addDynamicsMark -- Add dynamics marks such as p, f, sfz, rfz. +// HumdrumInput::addDynamicsMark -- Add dynamics marks such as p, f, sfz, rz, rfz. // The dynamics marking will be added at a tstamp rather than a startid. // @@ -19386,6 +19386,9 @@ void HumdrumInput::addDynamicsMark(hum::HTp dyntok, hum::HTp token, hum::HLp lin else if (hre.search(letters, "^s?f+z?p+$")) { dynamic = letters; } + else if (letters == "rz") { + dynamic = letters; + } if (!dynamic.empty()) { int staffadj = ss[si].m_dynamstaffadj; @@ -19633,9 +19636,14 @@ void HumdrumInput::addDynamicsMark(hum::HTp dyntok, hum::HTp token, hum::HLp lin ////////////////////////////// // // HumdrumInput::addSforzandoToNote -- A "z" on a note/chord indicates -// a sforzando mark ("sf", or use "zz" for "sfz"). This will be -// inserted into the floating elements as a with a @startid -// pointing to the note/chord. Other dynamics are placed using @tstamp. +// a sforzando mark. Repeated z's will choose one of the following accents: +// z = sf +// zz = sfz +// zzz = rz +// zzzz = rfz +// This accent be inserted into the floating elements as a with +// a @startid pointing to the note/chord. Other dynamics are placed +// using @tstamp. // void HumdrumInput::addSforzandoToNote(hum::HTp token, int staffindex) @@ -19767,7 +19775,13 @@ void HumdrumInput::addSforzandoToNote(hum::HTp token, int staffindex) data_FONTSIZE fs; fs.SetTerm(FONTSIZETERM_large); rend->SetFontsize(fs); - if (token->find("zz") != std::string::npos) { + if (token->find("zzzz") != std::string::npos) { + addTextElement(rend, "rfz "); + } + else if (token->find("zzzz") != std::string::npos) { + addTextElement(rend, "rz "); + } + else if (token->find("zz") != std::string::npos) { addTextElement(rend, "sfz "); } else { @@ -19784,7 +19798,13 @@ void HumdrumInput::addSforzandoToNote(hum::HTp token, int staffindex) } } else { - if (token->find("zz") != std::string::npos) { + if (token->find("zzzz") != std::string::npos) { + addTextElement(dynam, "rfz"); + } + else if (token->find("zzz") != std::string::npos) { + addTextElement(dynam, "rz"); + } + else if (token->find("zz") != std::string::npos) { addTextElement(dynam, "sfz"); } else { From 6e49bf709a2373d2dcfd3d4c57b5d0e47955b65a Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Wed, 21 Aug 2024 04:11:06 -0700 Subject: [PATCH 7/7] Commit header with updates for staff labels. --- include/vrv/iohumdrum.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/vrv/iohumdrum.h b/include/vrv/iohumdrum.h index 98d356f904e..b36fee2b2e7 100644 --- a/include/vrv/iohumdrum.h +++ b/include/vrv/iohumdrum.h @@ -901,6 +901,7 @@ class HumdrumInput : public vrv::Input { bool hasOmdText(int startline, int endline); void processMeiOptions(hum::HumdrumFile &infile); std::string getInstrumentNumber(hum::HTp icode); + void insertTextWithNewlines(Label *label, const std::string &text); // header related functions: /////////////////////////////////////////// void createHeader();