From 98a9f2df3b3b493120670b983e87ee246516a6e1 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sat, 2 Sep 2023 11:15:25 +0200 Subject: [PATCH 001/108] Fix for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/833 --- src/iohumdrum.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 801556e9b85..044d89454b0 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -24658,7 +24658,13 @@ template void HumdrumInput::convertVerses(ELEMENT element, hum:: hre.replaceDestructive(value, "ü", "u2", "g"); // u-umlaut hre.replaceDestructive(value, "ä", "a2", "g"); // a-umlaut hre.replaceDestructive(value, "ö", "o2", "g"); // o-umlaut - vtexts.push_back(value); + hre.replaceDestructive(value, "\\s+$", ""); // trailing spaces + hre.replaceDestructive(value, "^\\s+", ""); // leading spaces + hre.replaceDestructive(value, "-", "\\s+-$"); // trailing space before hyphen + hre.replaceDestructive(value, "-", "^-\\s+"); // leaning spaces after hyphen + if (!value.empty()) { + vtexts.push_back(value); + } } else { vtoks.push_back(token); @@ -24666,7 +24672,13 @@ template void HumdrumInput::convertVerses(ELEMENT element, hum:: if (value.empty()) { value = *token; } - vtexts.push_back(value); + hre.replaceDestructive(value, "", "\\s+$"); // trailing spaces + hre.replaceDestructive(value, "", "^\\s+"); // leading spaces + hre.replaceDestructive(value, "-", "\\s+-$"); // trailing space before hyphen + hre.replaceDestructive(value, "-", "^-\\s+"); // leaning spaces after hyphen + if (!value.empty()) { + vtexts.push_back(value); + } } if (vvdataQ) { splitSyllableBySpaces(vtexts); From 3796eacead074e5d2332e4274e988e4171e85612 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Fri, 15 Sep 2023 20:37:17 -0700 Subject: [PATCH 002/108] Allow time signatures to be invisible (implicit). --- src/iohumdrum.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 044d89454b0..9ded85124c6 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -6753,6 +6753,9 @@ void HumdrumInput::setTimeSig(StaffDef *part, const std::string ×ig, const vrvmeter->SetVisible(BOOLEAN_false); } } + if (timetok->find("yy") != std::string::npos) { + vrvmeter->SetVisible(BOOLEAN_false); + } // Don't store time signature if there is a mensuration to show // (verivio will display both mensuration and time signature. From 888b56567edce0a2d9b56a14a8c71b952ae592da Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sat, 16 Sep 2023 15:39:33 -0700 Subject: [PATCH 003/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/834 --- include/vrv/iohumdrum.h | 4 ++-- src/iohumdrum.cpp | 45 +++++++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/vrv/iohumdrum.h b/include/vrv/iohumdrum.h index b0c6bb6a1d5..dc079878f95 100644 --- a/include/vrv/iohumdrum.h +++ b/include/vrv/iohumdrum.h @@ -804,8 +804,8 @@ class HumdrumInput : public vrv::Input { void analyzeHarmInterpretations(hum::HTp starttok); void analyzeDegreeInterpretations(hum::HTp starttok); void analyzeTextInterpretation(hum::HTp starttok); - void addHarmLabel( - hum::HumNum timestamp, const std::string &label, const std::string &n, const std::string &place, int staffNum); + void addHarmLabel(hum::HumNum timestamp, const std::string &label, const std::string &labelStyle, + const std::string &n, const std::string &place, int staffNum); std::u32string getMoveableDoName(hum::HTp token, int degree, int semitones); void setFontsizeForHarm(Harm *harm, const std::string &fontsize); void setFontStyleForHarm(Harm *harm, const std::string &style); diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 9ded85124c6..8718349bc95 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -1186,6 +1186,7 @@ void HumdrumInput::analyzeHarmInterpretations(hum::HTp starttok) aboveQ = true; } hum::HTp keydesig = NULL; + hum::HTp verselabel = NULL; hum::HTp current = starttok; std::string initialLabel = ""; if (hre.search(current->getDataType(), "^\\*\\*[ab]data-(.*)")) { @@ -1204,14 +1205,27 @@ void HumdrumInput::analyzeHarmInterpretations(hum::HTp starttok) if (keydesig && !keydesig->empty()) { std::string label = keydesig->substr(1); if (!label.empty()) { - current->setValue("auto", "keylabel", label); + current->setValue("auto", "keyLabel", label); } keydesig = NULL; + verselabel = NULL; + } + else if (verselabel) { + if (hre.search(verselabel, "^\\*v([ib]*):(.+)$")) { + string style = hre.getMatch(1); + string label = hre.getMatch(2); + current->setValue("auto", "keyLabel", label); + if (!style.empty()) { + current->setValue("auto", "keyLabelStyle", style); + } + } + keydesig = NULL; + verselabel = NULL; } else if (!initialLabel.empty()) { std::string label = initialLabel; label += ":"; - current->setValue("auto", "keylabel", label); + current->setValue("auto", "keyLabel", label); initialLabel.clear(); } } @@ -1227,6 +1241,9 @@ void HumdrumInput::analyzeHarmInterpretations(hum::HTp starttok) else if (current->isKeyDesignation()) { keydesig = current; } + else if (hre.search(current, "^\\*v[bi]*:")) { + verselabel = current; + } } } @@ -1352,7 +1369,7 @@ void HumdrumInput::analyzeDegreeInterpretations(hum::HTp starttok) if (keydesig) { // add key designation as a label on the next // scale degree found in the data - current->setValue("auto", "keylabel", keydesig->substr(1)); + current->setValue("auto", "keyLabel", keydesig->substr(1)); keydesig = NULL; } if (minorQ) { @@ -8815,9 +8832,10 @@ void HumdrumInput::addHarmFloatsForMeasure(int startline, int endline) // Add key label (for harm/rhrm/deg/degree data) if (isCData || isHarm || isDegree) { - std::string keylabel = token->getValue("auto", "keylabel"); - if (!keylabel.empty()) { - addHarmLabel(tstamp, keylabel, tracktext, place, xstaffindex + 1); + std::string keyLabel = token->getValue("auto", "keyLabel"); + std::string keyLabelStyle = token->getValue("auto", "keyLabelStyle"); + if (!keyLabel.empty()) { + addHarmLabel(tstamp, keyLabel, keyLabelStyle, tracktext, place, xstaffindex + 1); } } @@ -9009,8 +9027,8 @@ void HumdrumInput::setFontsizeForHarm(Harm *harm, const std::string &fontsize) // HumdrumInput::addHarmLabel -- // -void HumdrumInput::addHarmLabel( - hum::HumNum timestamp, const std::string &label, const std::string &n, const std::string &place, int staffNum) +void HumdrumInput::addHarmLabel(hum::HumNum timestamp, const std::string &label, const std::string &labelStyle, + const std::string &n, const std::string &place, int staffNum) { if (label.empty()) { return; @@ -9052,6 +9070,17 @@ void HumdrumInput::addHarmLabel( // output += U"\u00a0"; // non-breaking space text->SetText(output); + // Add italic/bold styling if needed: + if (labelStyle.find("i") != std::string::npos) { + rend->SetFontstyle(FONTSTYLE_italic); + } + if (labelStyle.find("b") != std::string::npos) { + rend->SetFontweight(FONTWEIGHT_bold); + } + else if (labelStyle.find("B") != std::string::npos) { + rend->SetFontweight(FONTWEIGHT_bold); + } + // add some extra space to separate from chord: Text *stext = new Text(); rend->AddChild(stext); From 693883274b2793f096debb9bea811a2ced321b48 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sun, 17 Sep 2023 02:03:37 -0700 Subject: [PATCH 004/108] Temporary fix related to issue https://github.com/rism-digital/verovio/issues/3515 --- src/iohumdrum.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 8718349bc95..5cc9a46c6c5 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -17975,7 +17975,10 @@ hum::HumNum HumdrumInput::getMeasureTstamp(hum::HTp token, int staffindex, hum:: // what is this for? Causes problems with pedal markings. // qbeat += fract * token->getDuration().getAbs(); } - hum::HumNum mfactor = ss[staffindex].meter_bottom / 4; + // Below is temporary fix for issue https://github.com/rism-digital/verovio/issues/3515 + hum::HumNum mfactor = ss.back().meter_bottom / 4; + // hum::HumNum mfactor = ss[staffindex].meter_bottom / 4; + // if (ss[staffindex].meter_bottom == 0) { // mfactor = 1; // mfactor /= 8; From 4030f531e86e351ec6b0da79741b85aca7ef034f Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Mon, 18 Sep 2023 21:19:34 -0700 Subject: [PATCH 005/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/835 --- src/iohumdrum.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 5cc9a46c6c5..22aba8af8ff 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -11859,6 +11859,11 @@ bool HumdrumInput::fillContentsOfLayer(int track, int startline, int endline, in insertMidMeasureKeySignature(staffindex, elements, pointers, token); } + bool isTimeSignature = layerdata[i]->isTimeSignature(); + if (notAtStart && isTimeSignature) { + insertMeterSigElement(elements, pointers, layerdata, i); + } + bool forceClefChange = false; if (token->isClef() || (*token == "*")) { if (!(token->isMensLike() && notAtStart)) { @@ -11974,9 +11979,7 @@ bool HumdrumInput::fillContentsOfLayer(int track, int startline, int endline, in } } if (token->isTimeSignature()) { - // Now done at the measure level. This location might - // be good for time signatures which change in the - // middle of measures. + // Now done further above. // insertMeterSigElement(elements, pointers, layerdata, i); processDirections(token, staffindex); } From b8527fd4c0541b9f281559ef710f908fd6624942 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sun, 24 Sep 2023 15:50:28 -0700 Subject: [PATCH 006/108] Humlib updates. --- include/hum/humlib.h | 184 ++- src/hum/humlib.cpp | 2847 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 3026 insertions(+), 5 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index e54c967dfb7..8ee9b86f573 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 Aug 22 22:41:40 CEST 2023 +// Last Modified: Sat Sep 23 22:51:29 PDT 2023 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 @@ -4116,6 +4116,9 @@ class Convert { static double coefficientOfVariationPopulation(const std::vector& x); static double nPvi (const std::vector& x); + // instrument related functions defined in Convert-instrument.cpp + static std::vector> getInstrumentList(void); + // Reference record functions defined in Convert-reference.cpp static std::string getReferenceKeyMeaning(HTp token); static std::string getReferenceKeyMeaning(const std::string& token); @@ -8349,6 +8352,62 @@ class Tool_mens2kern : public HumTool { }; +class Tool_meter : public HumTool { + + public: + Tool_meter (void); + ~Tool_meter () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const string& indata, std::ostream& out); + bool run (HumdrumFile& infile, std::ostream& out); + + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void getMeterData (HumdrumFile& infile); + void processLine (HumdrumLine& line, + std::vector& curNum, + std::vector& curDen, + std::vector& curBeat, + std::vector& curBarTime); + void printMeterData (HumdrumFile& infile); + void printHumdrumLine (HumdrumLine& line, bool printLabels); + int printKernAndAnalysisSpine(HumdrumLine& line, int index, bool printLabels, bool forceInterpretation = false); + HumNum getHumNum (HTp token, const std::string& parameter); + std::string getHumNumString(HumNum input); + bool searchForLabels (HumdrumLine& line); + void printLabelLine (HumdrumLine& line); + void analyzePickupMeasures(HumdrumFile& infile); + void analyzePickupMeasures(HTp sstart); + HumNum getTimeSigDuration(HTp tsig); + void markPickupContent (HTp stok, HTp etok); + + private: + + bool m_commaQ = false; + bool m_debugQ = false; + bool m_denominatorQ = false; + bool m_eighthQ = false; + bool m_floatQ = false; + bool m_halfQ = false; + bool m_joinQ = false; + bool m_nobeatQ = false; + bool m_nolabelQ = false; + bool m_numeratorQ = false; + bool m_quarterQ = false; + bool m_restQ = false; + bool m_sixteenthQ = false; + bool m_tsigQ = false; + bool m_wholeQ = false; + bool m_zeroQ = false; + int m_digits = 0; + +}; + + class Tool_metlev : public HumTool { public: Tool_metlev (void); @@ -9282,6 +9341,45 @@ class Tool_myank : public HumTool { }; +class Tool_nproof : public HumTool { + + public: + Tool_nproof (void); + ~Tool_nproof () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const string& indata, std::ostream& out); + bool run (HumdrumFile& infile, std::ostream& out); + + void checkForBlankLines(HumdrumFile& infile); + void checkInstrumentInformation(HumdrumFile& infile); + void checkKeyInformation(HumdrumFile& infile); + void checkSpineTerminations(HumdrumFile& infile); + void checkForValidInstrumentCode(HTp token, vector>& instrumentList); + void checkReferenceRecords(HumdrumFile& infile); + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + + private: + int m_errorCount = 0; + std::string m_errorList; + std::string m_errorHtml; + + bool m_noblankQ = false; + bool m_noinstrumentQ = false; + bool m_nokeyQ = false; + bool m_noreferenceQ = false; + bool m_noterminationQ = false; + + bool m_fileQ = false; + bool m_rawQ = false; + +}; + + class Tool_ordergps : public HumTool { public: Tool_ordergps (void); @@ -9446,6 +9544,38 @@ class Tool_phrase : public HumTool { +class Tool_pline : public HumTool { + public: + Tool_pline (void); + ~Tool_pline () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const string& indata, ostream& out); + bool run (HumdrumFile& infile, ostream& out); + + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void getPlineInterpretations(HumdrumFile& infile, vector& tokens); + void plineToColor (HumdrumFile& infile, vector& tokens); + void markRests (HumdrumFile& infile); + void markSpineRests (HTp spineStop); + void fillLineInfo (HumdrumFile& infile, std::vector>& lineInfo); + + private: + bool m_colorQ = false; // used with -c option + // bool m_overlapQ = false; // used with -o option + + std::vector m_colors; + std::vector m_ptokens; + std::vector> m_lineInfo; + + +}; + + class Tool_pnum : public HumTool { public: Tool_pnum (void); @@ -10102,6 +10232,58 @@ class Tool_tassoize : public HumTool { }; +class Tool_textdur : public HumTool { + public: + Tool_textdur (void); + ~Tool_textdur () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const string& indata, ostream& out); + bool run (HumdrumFile& infile, ostream& out); + + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void printMelismas (HumdrumFile& infile); + void printDurations (HumdrumFile& infile); + void getTextSpineStarts(HumdrumFile& infile, vector& starts); + void processTextSpine (vector& starts, int index); + int getMelisma (HTp tok1, HTp tok2); + HumNum getDuration (HTp tok1, HTp tok2); + HTp getTandemKernToken(HTp token); + void printInterleaved (HumdrumFile& infile); + void printInterleavedLine(HumdrumLine& line, vector& textTrack); + void printTokenAnalysis(HTp token); + void printAnalysis (void); + void printDurationAverage(void); + void printMelismaAverage(void); + void printHtmlContent (void); + void printMelismaHtmlHistogram(void); + void printMelismaHtmlHistogram(int index, int maxVal); + void printDurationHtmlHistogram(void); + void fillInstrumentNameInfo(void); + std::string getColumnName (HTp token); + + private: + std::vector m_textStarts; + std::vector m_track2column; + std::vector m_columnName; + + std::vector> m_syllables; // List of syllables in **text/**sylba + std::vector> m_durations; // List of durations excluding trailing rests + std::vector> m_melismas; // List of note counts for syllable + + bool m_analysisQ = false; // used with -a option + bool m_melismaQ = false; // used with -m option + bool m_durationQ = true; // used with -m, -d option + bool m_interleaveQ = false; // used with -i option + HumNum m_RhythmFactor = 1; // uwed with -1, -2, -8, and later -f # + +}; + + class Tool_thru : public HumTool { public: Tool_thru (void); diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index ec6a0d78e78..15494811bc6 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 Aug 22 22:41:40 CEST 2023 +// Last Modified: Sat Sep 23 22:51:29 PDT 2023 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 @@ -444,6 +444,243 @@ vector Convert::harmToBase40(const string& harm, int keyroot, int keymode) +////////////////////////////// +// +// Convert::getInstrumentList -- List from https://bit.ly/humdrum-instrument-codes +// + +vector > Convert::getInstrumentList(void) { + return vector > { + {"accor", "klav"}, + {"alto", "vox"}, + {"anvil", "idio"}, + {"archl", "str"}, + {"armon", "ww"}, + {"arpa", "str"}, + {"bagpI", "ww"}, + {"bagpS", "ww"}, + {"banjo", "str"}, + {"bansu", "ww"}, + {"barit", "vox"}, + {"baset", "ww"}, + {"bass", "vox"}, + {"bdrum", "idio"}, + {"bguit", "str"}, + {"biwa", "str"}, + {"brush", "idio"}, + {"bscan", "vox"}, + {"bspro", "vox"}, + {"bugle", "bras"}, + {"calam", "ww"}, + {"calpe", "ww"}, + {"calto", "vox"}, + {"campn", "idio"}, + {"cangl", "ww"}, + {"canto", "vox"}, + {"caril", "idio"}, + {"castr", "vox"}, + {"casts", "idio"}, + {"cbass", "str"}, + {"cello", "str"}, + {"cemba", "klav"}, + {"cetra", "str"}, + {"chain", "idio"}, + {"chcym", "idio"}, + {"chime", "idio"}, + {"chlma", "ww"}, + {"chlms", "ww"}, + {"chlmt", "ww"}, + {"clap", "idio"}, + {"clara", "ww"}, + {"clarb", "ww"}, + {"claro", "ww"}, + {"clarp", "ww"}, + {"clars", "ww"}, + {"clave", "idio"}, + {"clavi", "klav"}, + {"clest", "klav"}, + {"clrno", "bras"}, + {"colsp", "vox"}, + {"conga", "idio"}, + {"cor", "bras"}, + {"cornm", "ww"}, + {"corno", "ww"}, + {"cornt", "bras"}, + {"coro", "vox"}, + {"crshc", "idio"}, + {"ctenor", "vox"}, + {"ctina", "klav"}, + {"drmsp", "vox"}, + {"drum", "idio"}, + {"drumP", "idio"}, + {"dulc", "str"}, + {"eguit", "str"}, + {"fag_c", "ww"}, + {"fagot", "ww"}, + {"false", "vox"}, + {"fdrum", "idio"}, + {"feme", "vox"}, + {"fife", "ww"}, + {"fingc", "idio"}, + {"flex", "idio"}, + {"flt", "ww"}, + {"flt_a", "ww"}, + {"flt_b", "ww"}, + {"fltda", "ww"}, + {"fltdb", "ww"}, + {"fltdn", "ww"}, + {"fltds", "ww"}, + {"fltdt", "ww"}, + {"flugh", "bras"}, + {"forte", "klav"}, + {"gen", "gen"}, + {"genB", "gen"}, + {"genT", "gen"}, + {"glock", "idio"}, + {"gong", "idio"}, + {"guitr", "str"}, + {"hammd", "klav"}, + {"hbell", "idio"}, + {"heck", "ww"}, + {"heltn", "vox"}, + {"hichi", "ww"}, + {"hurdy", "str"}, + {"kitv", "str"}, + {"klav", "klav"}, + {"kokyu", "str"}, + {"komun", "str"}, + {"koto", "str"}, + {"kruma", "ww"}, + {"krumb", "ww"}, + {"krums", "ww"}, + {"krumt", "ww"}, + {"lion", "idio"}, + {"liuto", "str"}, + {"lyrsp", "vox"}, + {"lyrtn", "vox"}, + {"male", "vox"}, + {"mando", "str"}, + {"marac", "idio"}, + {"marim", "idio"}, + {"mbari", "vox"}, + {"mezzo", "vox"}, + {"nfant", "vox"}, + {"nokan", "ww"}, + {"oboe", "ww"}, + {"oboeD", "ww"}, + {"ocari", "ww"}, + {"ondes", "klav"}, + {"ophic", "bras"}, + {"organ", "klav"}, + {"oud", "str"}, + {"paila", "idio"}, + {"panpi", "ww"}, + {"pbell", "idio"}, + {"pguit", "str"}, + {"physh", "klav"}, + {"piano", "klav"}, + {"piatt", "idio"}, + {"picco", "ww"}, + {"pipa", "str"}, + {"piri", "ww"}, + {"porta", "klav"}, + {"psalt", "str"}, + {"qin", "str"}, + {"quinto", "vox"}, + {"quitr", "str"}, + {"rackt", "ww"}, + {"ratch", "idio"}, + {"ratl", "idio"}, + {"rebec", "str"}, + {"recit", "vox"}, + {"reedo", "klav"}, + {"rhode", "klav"}, + {"ridec", "idio"}, + {"sarod", "str"}, + {"sarus", "ww"}, + {"saxA", "ww"}, + {"saxB", "ww"}, + {"saxC", "ww"}, + {"saxN", "ww"}, + {"saxR", "ww"}, + {"saxS", "ww"}, + {"saxT", "ww"}, + {"sbell", "idio"}, + {"sdrum", "idio"}, + {"serp", "bras"}, + {"sesto", "vox"}, + {"shaku", "ww"}, + {"shami", "str"}, + {"sheng", "ww"}, + {"sho", "ww"}, + {"siren", "idio"}, + {"sitar", "str"}, + {"slap", "idio"}, + {"soprn", "vox"}, + {"spok", "vox"}, + {"spokF", "vox"}, + {"spokM", "vox"}, + {"spshc", "idio"}, + {"steel", "idio"}, + {"stim", "vox"}, + {"stimA", "vox"}, + {"stimB", "vox"}, + {"stimC", "vox"}, + {"stimR", "vox"}, + {"stimS", "vox"}, + {"strdr", "idio"}, + {"sxhA", "bras"}, + {"sxhB", "bras"}, + {"sxhC", "bras"}, + {"sxhR", "bras"}, + {"sxhS", "bras"}, + {"sxhT", "bras"}, + {"synth", "klav"}, + {"tabla", "idio"}, + {"tambn", "idio"}, + {"tambu", "str"}, + {"tanbr", "str"}, + {"tblok", "idio"}, + {"tdrum", "idio"}, + {"tenor", "vox"}, + {"timpa", "idio"}, + {"tiorb", "str"}, + {"tom", "idio"}, + {"trngl", "idio"}, + {"tromP", "bras"}, + {"troma", "bras"}, + {"tromb", "bras"}, + {"tromp", "bras"}, + {"tromt", "bras"}, + {"trumB", "bras"}, + {"tuba", "bras"}, + {"tubaB", "bras"}, + {"tubaC", "bras"}, + {"tubaT", "bras"}, + {"tubaU", "bras"}, + {"ukule", "str"}, + {"vibra", "idio"}, + {"vina", "str"}, + {"viola", "str"}, + {"violb", "str"}, + {"viold", "str"}, + {"viole", "str"}, + {"violn", "str"}, + {"violp", "str"}, + {"viols", "str"}, + {"violt", "str"}, + {"vox", "vox"}, + {"wblok", "idio"}, + {"xylo", "idio"}, + {"zithr", "str"}, + {"zurna", "ww"} + }; +} + + + + + ////////////////////////////// // // Convert::isKernRest -- Returns true if the input string represents @@ -4411,6 +4648,7 @@ string Convert::getLanguageName(const string& abbreviation) { + ////////////////////////////// // // Convert::recipToDuration -- Convert **recip rhythmic values into @@ -9349,7 +9587,9 @@ int HumGrid::getPartCount(void) { ////////////////////////////// // -// HumGrid::getStaffCount -- +// HumGrid::getStaffCount -- Get the number of staves in a +// given part. Most parts will be single staff, but grand staff +// parts with have two staves. Organ may have 3 staves. // int HumGrid::getStaffCount(int partindex) { @@ -9361,7 +9601,8 @@ int HumGrid::getStaffCount(int partindex) { return 0; } - return (int)this->at(0)->back()->at(partindex)->size(); + return (int)this->at(0)->front()->at(partindex)->size(); + // return (int)this->at(0)->back()->at(partindex)->size(); } @@ -79271,16 +79512,22 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(melisma, infile, commands[i].second, status); } else if (commands[i].first == "mens2kern") { RUNTOOL(mens2kern, infile, commands[i].second, status); + } else if (commands[i].first == "meter") { + RUNTOOL(meter, infile, commands[i].second, status); } else if (commands[i].first == "metlev") { RUNTOOL(metlev, infile, commands[i].second, status); } else if (commands[i].first == "modori") { RUNTOOL(modori, infile, commands[i].second, status); } else if (commands[i].first == "msearch") { RUNTOOL(msearch, infile, commands[i].second, status); + } else if (commands[i].first == "nproof") { + 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 == "phrase") { RUNTOOL(phrase, infile, commands[i].second, status); + } else if (commands[i].first == "pline") { + RUNTOOL(pline, infile, commands[i].second, status); } else if (commands[i].first == "recip") { RUNTOOL(recip, infile, commands[i].second, status); } else if (commands[i].first == "restfill") { @@ -79313,6 +79560,8 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(tassoize, infile, commands[i].second, status); } else if (commands[i].first == "tasso") { RUNTOOL(tassoize, infile, commands[i].second, status); + } else if (commands[i].first == "textdur") { + RUNTOOL(textdur, infile, commands[i].second, status); } else if (commands[i].first == "tie") { RUNTOOL(tie, infile, commands[i].second, status); } else if (commands[i].first == "tspos") { @@ -92741,6 +92990,849 @@ string Tool_mens2kern::mens2kernRhythm(const string& rhythm, bool altera, bool p +///////////////////////////////// +// +// Tool_meter::Tool_meter -- Set the recognized options for the tool. +// + +Tool_meter::Tool_meter(void) { + + define("c|comma=b", "display decimal points as commas"); + define("d|denominator=b", "display denominator spine"); + define("e|eighth=b", "metric positions in eighth notes rather than beats"); + define("f|float=b", "floating-point beat values instead of rational numbers"); + define("h|half=b", "metric positions in half notes rather than beats"); + define("j|join=b", "join time signature information and metric positions into a single token"); + define("n|numerator=b", "display numerator spine"); + define("q|quarter=b", "metric positions in quarter notes rather than beats"); + define("r|rest=b", "add meteric positions of rests"); + define("s|sixteenth=b", "metric positions in sixteenth notes rather than beats"); + define("t|time-signature|tsig|m|meter=b", "display active time signature for each note"); + define("w|whole=b", "metric positions in whole notes rather than beats"); + define("z|zero=b", "start of measure is beat 0 rather than beat 1"); + + define("B|no-beat=b", "Do not display metric positions (beats)"); + define("D|digits=i:0", "number of digits after decimal point"); + define("L|no-label=b", "do not add labels to analysis spines"); + +} + + + +///////////////////////////////// +// +// Tool_meter::run -- Do the main work of the tool. +// + +bool Tool_meter::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; i 15) { + m_digits = 15; + } + + if (m_joinQ && !(m_tsigQ || m_numeratorQ || m_denominatorQ)) { + m_tsigQ = true; + } + if (m_joinQ) { + m_nobeatQ = false; + } + if (m_joinQ && m_numeratorQ && m_denominatorQ) { + m_tsigQ = true; + } + + if (m_tsigQ) { + m_numeratorQ = true; + m_denominatorQ = true; + } + + // Only one fix-width metric position allowed, prioritize + // largest given duration: + if (m_wholeQ) { + m_halfQ = false; + m_quarterQ = false; + m_eighthQ = false; + m_sixteenthQ = false; + } else if (m_halfQ) { + m_wholeQ = false; + m_quarterQ = false; + m_eighthQ = false; + m_sixteenthQ = false; + } else if (m_quarterQ) { + m_wholeQ = false; + m_halfQ = false; + m_eighthQ = false; + m_sixteenthQ = false; + } else if (m_eighthQ) { + m_wholeQ = false; + m_halfQ = false; + m_quarterQ = false; + m_sixteenthQ = false; + } else if (m_sixteenthQ) { + m_wholeQ = false; + m_halfQ = false; + m_quarterQ = false; + m_eighthQ = false; + } + +} + + + +////////////////////////////// +// +// Tool_meter::processFile -- +// + +void Tool_meter::processFile(HumdrumFile& infile) { + analyzePickupMeasures(infile); + getMeterData(infile); + printMeterData(infile); +} + + +////////////////////////////// +// +// Tool_meter::analyzePickupMeasures -- +// + +void Tool_meter::analyzePickupMeasures(HumdrumFile& infile) { + vector sstarts; + infile.getKernSpineStartList(sstarts); + for (int i=0; i<(int)sstarts.size(); i++) { + analyzePickupMeasures(sstarts[i]); + } +} + + +void Tool_meter::analyzePickupMeasures(HTp sstart) { + // First dimension are visible barlines. + // Second dimension are time signature(s) within the barlines. + vector> barandtime; + barandtime.reserve(1000); + barandtime.resize(1); + barandtime[0].push_back(sstart); + HTp current = sstart->getNextToken(); + while (current) { + if (current->isTimeSignature()) { + barandtime.back().push_back(current); + } else if (current->isBarline()) { + if (current->find("-") != std::string::npos) { + current = current->getNextToken(); + continue; + } + barandtime.resize(barandtime.size() + 1); + barandtime.back().push_back(current); + } else if (*current == "*-") { + barandtime.resize(barandtime.size() + 1); + barandtime.back().push_back(current); + break; + } + current = current->getNextToken(); + } + + // Extract the actual duration of measures: + vector bardur(barandtime.size(), 0); + for (int i=0; i<(int)barandtime.size() - 1; i++) { + HumNum starttime = barandtime[i][0]->getDurationFromStart(); + HumNum endtime = barandtime.at(i+1)[0]->getDurationFromStart(); + HumNum duration = endtime - starttime; + bardur.at(i) = duration; + } + + // Extract the expected duration of measures: + vector tsigdur(barandtime.size(), 0); + int firstmeasure = -1; + HumNum active = 0; + for (int i=0; i<(int)barandtime.size() - 1; i++) { + if (firstmeasure < 0) { + if (bardur.at(i) > 0) { + firstmeasure = i; + } + } + if (barandtime[i].size() < 2) { + tsigdur.at(i) = active; + continue; + } + active = getTimeSigDuration(barandtime.at(i).at(1)); + tsigdur.at(i) = active; + } + + vector pickup(barandtime.size(), false); + for (int i=0; i<(int)barandtime.size() - 1; i++) { + if (tsigdur.at(i) == bardur.at(i)) { + // actual and expected are the same + continue; + } + if (tsigdur.at(i) == tsigdur.at(i+1)) { + if (bardur.at(i) + bardur.at(i+1) == tsigdur.at(i)) { + pickup.at(i+1) = true; + i++; + continue; + } + } + } + + // check for first-measure pickup + if (firstmeasure >= 0) { + if (bardur.at(firstmeasure) < tsigdur.at(firstmeasure)) { + pickup.at(firstmeasure) = true; + } + } + + if (m_debugQ) { + cerr << "============================" << endl; + for (int i=0; i<(int)barandtime.size(); i++) { + cerr << pickup.at(i); + cerr << "\t"; + cerr << bardur.at(i); + cerr << "\t"; + cerr << tsigdur.at(i); + cerr << "\t"; + for (int j=0; j<(int)barandtime[i].size(); j++) { + cerr << barandtime.at(i).at(j) << "\t"; + } + cerr << endl; + } + cerr << endl; + } + + // Markup pickup measure notes/rests + for (int i=0; i<(int)pickup.size() - 1; i++) { + if (!pickup[i]) { + continue; + } + markPickupContent(barandtime.at(i).at(0), barandtime.at(i+1).at(0)); + } + + // Pickup/incomplete measures covering three or more barlines are not considered + // (these could be used with dashed barlines or similar). + +} + + + +////////////////////////////// +// +// Tool_meter::markPickupContent -- +// + +void Tool_meter::markPickupContent(HTp stok, HTp etok) { + int endline = etok->getLineIndex(); + HTp current = stok; + while (current) { + int line = current->getLineIndex(); + if (line > endline) { + break; + } + if (current->isData()) { + HTp field = current; + int track = field->getTrack(); + while (field) { + int ttrack = field->getTrack(); + if (ttrack != track) { + break; + } + if (field->isNull()) { + field = field->getNextFieldToken(); + continue; + } + field->setValue("auto", "pickup", 1); + HumNum nbt = etok->getDurationFromStart() - field->getDurationFromStart(); + stringstream ntime; + ntime.str(""); + ntime << nbt.getNumerator() << "/" << nbt.getDenominator(); + field->setValue("auto", "nextBarTime", ntime.str()); + field = field->getNextFieldToken(); + } + } + if (current == etok) { + break; + } + current = current->getNextToken(); + } +} + + + +////////////////////////////// +// +// Tool_meter::getTimeSigDuration -- +// + +HumNum Tool_meter::getTimeSigDuration(HTp tsig) { + HumNum output = 0; + HumRegex hre; + if (hre.search(tsig, "^\\*M(\\d+)/(\\d+%?\\d*)")) { + int top = hre.getMatchInt(1); + string bot = hre.getMatch(2); + HumNum botdur = Convert::recipToDuration(bot); + output = botdur * top; + } + return output; +} + + + +////////////////////////////// +// +// Tool_meter::printMeterData -- +// + +void Tool_meter::printMeterData(HumdrumFile& infile) { + bool foundLabel = false; + bool foundData = false; + + for (int i=0; iisKern()) { + i = printKernAndAnalysisSpine(line, i, printLabels, forceInterpretation); + } else { + m_humdrum_text << "*"; + } + if (i < line.getFieldCount() - 1) { + m_humdrum_text << "\t"; + } + } + m_humdrum_text << "\n"; +} + + + +////////////////////////////// +// +// Tool_meter::printHumdrumLine -- +// + +void Tool_meter::printHumdrumLine(HumdrumLine& line, bool printLabels) { + + for (int i=0; iisKern()) { + i = printKernAndAnalysisSpine(line, i, printLabels); + } else { + m_humdrum_text << token; + } + if (i < line.getFieldCount() - 1) { + m_humdrum_text << "\t"; + } + } + m_humdrum_text << "\n"; +} + + + +////////////////////////////// +// +// Tool_meter::searchForLabels -- +// + +bool Tool_meter::searchForLabels(HumdrumLine& line) { + if (!line.isInterpretation()) { + return false; + } + HumRegex hre; + for (int i=0; igetValue("auto", parameter); + if (hre.search(value, "(\\d+)/(\\d+)")) { + output = hre.getMatchInt(1); + output /= hre.getMatchInt(2); + } else if (hre.search(value, "(\\d+)")) { + output = hre.getMatchInt(1); + } + return output; +} + + + +////////////////////////////// +// +// Tool_meter::getHumNumString -- +// + +string Tool_meter::getHumNumString(HumNum input) { + stringstream tem; + input.printTwoPart(tem); + return tem.str(); +} + + + +////////////////////////////// +// +// Tool_meter::printKernAndAnalysisSpine -- +// + +int Tool_meter::printKernAndAnalysisSpine(HumdrumLine& line, int index, bool printLabels, bool forceInterpretation) { + HTp starttok = line.token(index); + int track = starttok->getTrack(); + int counter = 0; + + string analysis = "."; + string numerator = "."; + string denominator = "."; + string meter = "."; + bool hasNote = false; + bool hasRest = false; + + for (int i=index; igetTrack(); + if (ttrack != track) { + break; + } + if (counter > 0) { + m_humdrum_text << "\t"; + } + counter++; + if (forceInterpretation) { + m_humdrum_text << "*"; + } else { + m_humdrum_text << token; + } + + if (line.isData() && !forceInterpretation) { + if (token->isNull()) { + // analysis = "."; + } else if (token->isRest() && !m_restQ) { + // analysis = "."; + } else if ((!token->isNoteAttack()) && !(m_restQ && token->isRest())) { + // analysis = "."; + } else if ((analysis == ".") && (token->getValueBool("auto", "hasData"))) { + string data = token->getValue("auto", "zeroBeat"); + if (m_restQ) { + if (token->isRest()) { + hasRest = true; + } else { + hasNote = true; + } + } + HumNum value; + HumNum nvalue; + HumNum dvalue; + if (!data.empty()) { + value = getHumNum(token, "zeroBeat"); + if (m_numeratorQ) { + nvalue = getHumNum(token, "numerator"); + numerator = getHumNumString(nvalue); + } + if (m_denominatorQ) { + dvalue = getHumNum(token, "denominator"); + denominator = getHumNumString(dvalue); + } + if (m_tsigQ) { + meter = numerator; + meter += "/"; + meter += denominator; + } + } + if (!m_zeroQ) { + value += 1; + } + if (m_floatQ) { + stringstream tem; + if (m_digits) { + tem << std::setprecision(m_digits + 1) << value.getFloat(); + } else { + tem << value.getFloat(); + } + analysis = tem.str(); + if (m_commaQ) { + HumRegex hre; + hre.replaceDestructive(analysis, ",", "\\."); + } + } else { + analysis = getHumNumString(value); + } + } + } else if (line.isInterpretation() || forceInterpretation) { + if (token->compare(0, 2, "**") == 0) { + analysis = "**cdata-beat"; + if (m_tsigQ) { + meter = "**cdata-tsig"; + } + if (m_numeratorQ) { + numerator = "**cdata-num"; + } + if (m_denominatorQ) { + denominator = "**cdata-den"; + } + } else if (*token == "*-") { + analysis = "*-"; + numerator = "*-"; + denominator = "*-"; + meter = "*-"; + } else if (token->isTimeSignature()) { + analysis = *token; + } else { + analysis = "*"; + numerator = "*"; + denominator = "*"; + meter = "*"; + if (printLabels) { + if (m_quarterQ) { + analysis = "*vi:4ths:"; + } else if (m_eighthQ) { + analysis = "*vi:8ths:"; + } else if (m_halfQ) { + analysis = "*vi:half:"; + } else if (m_wholeQ) { + analysis = "*vi:whole:"; + } else if (m_sixteenthQ) { + analysis = "*vi:16ths:"; + } else { + analysis = "*vi:beat:"; + } + numerator = "*vi:top:"; + denominator = "*vi:bot:"; + meter = "*vi:tsig:"; + if (m_joinQ) { + numerator = ""; + denominator = ""; + meter = ""; + } + } + } + } else if (line.isBarline()) { + analysis = *token; + numerator = *token; + denominator = *token; + meter = *token; + } else if (line.isCommentLocal()) { + analysis = "!"; + numerator = "!"; + denominator = "!"; + meter = "!"; + } else { + cerr << "STRANGE LINE: " << line << endl; + } + } + + if (m_joinQ) { + if (line.isData() && !forceInterpretation) { + if (m_tsigQ) { + m_humdrum_text << "\t" << meter; + } else { + if (m_numeratorQ) { + m_humdrum_text << "\t" << numerator; + } + if (m_denominatorQ) { + m_humdrum_text << "\t" << denominator; + } + } + } + if (!m_nobeatQ) { + if (line.isData() && !forceInterpretation) { + m_humdrum_text << ":"; + } else { + m_humdrum_text << "\t"; + } + m_humdrum_text << analysis; + if (line.isData() && hasRest && !hasNote) { + m_humdrum_text << "r"; + } + } + } else { + if (!m_nobeatQ) { + m_humdrum_text << "\t" << analysis; + if (line.isData() && hasRest && !hasNote) { + m_humdrum_text << "r"; + } + } + if (m_tsigQ) { + m_humdrum_text << "\t" << meter; + } else { + if (m_numeratorQ) { + m_humdrum_text << "\t" << numerator; + } + if (m_denominatorQ) { + m_humdrum_text << "\t" << denominator; + } + } + + } + + return index + counter - 1; +} + + + +////////////////////////////// +// +// Tool_meter::getMeterData -- +// + +void Tool_meter::getMeterData(HumdrumFile& infile) { + + int maxtrack = infile.getMaxTrack(); + vector curNum(maxtrack + 1, 0); + vector curDen(maxtrack + 1, 0); + vector curBeat(maxtrack + 1, 0); + vector curBarTime(maxtrack + 1, 0); + + for (int i=0; i& curNum, + vector& curDen, vector& curBeat, + vector& curBarTime) { + + int fieldCount = line.getFieldCount(); + + if (!line.hasSpines()) { + return; + } + + HumRegex hre; + if (line.isBarline()) { + for (int i=0; iisKern()) { + continue; + } + if (hre.search(token, "-")) { + // invisible barline: ignore + continue; + } + int track = token->getTrack(); + HumNum curTime = token->getDurationFromStart(); + curBarTime.at(track) = curTime; + } + return; + } + + if (line.isInterpretation()) { + // check for time signatures + for (int i=0; iisKern()) { + continue; + } + if (hre.search(token, "^\\*M(\\d+)/(\\d+)")) { + int top = hre.getMatchInt(1); + int bot = hre.getMatchInt(2); + int track = token->getTrack(); + curNum.at(track) = top; + curDen.at(track) = bot; + curBeat.at(track) = 0; + } else if (hre.search(token, "^\\*beat:\\s*([\\d.%]+)\\s*$")) { + int track = token->getTrack(); + string recip = hre.getMatch(1); + curBeat.at(track) = Convert::recipToDuration(recip); + } + } + return; + } + + if (line.isData()) { + // check for time signatures + for (int i=0; iisKern()) { + continue; + } + if (token->isNull()) { + continue; + } + if ((!m_restQ) && token->isRest()) { + continue; + } + if (!token->isNoteAttack() && !(m_restQ && token->isRest())) { + continue; + } + int pickup = token->getValueInt("auto", "pickup"); + int track = token->getTrack(); + stringstream value; + value.str(""); + value << curNum.at(track); + token->setValue("auto", "numerator", value.str()); + value.str(""); + value << curDen.at(track); + token->setValue("auto", "denominator", value.str()); + HumNum curTime = token->getDurationFromStart(); + HumNum q; + if (pickup) { + HumNum meterDur = curNum.at(track); + meterDur /= curDen.at(track); + meterDur *= 4; + HumNum nbt = getHumNum(token, "nextBarTime"); + q = meterDur - nbt; + } else { + q = curTime - curBarTime.at(track); + } + value.str(""); + value << q; + token->setValue("auto", "q", value.str()); + bool compound = false; + int multiple = curNum.at(track).getNumerator() / 3; + int remainder = curNum.at(track).getNumerator() % 3; + int bottom = curDen.at(track).getNumerator(); + if ((curBeat.at(track) == 0) && (bottom >= 8) && (multiple > 1) && (remainder == 0)) { + compound = true; + } + + HumNum qq = q; + if (m_quarterQ) { + // do nothing (prior calculations are done in quarter notes) + } else if (m_halfQ) { + qq /= 2; + } else if (m_wholeQ) { + qq /= 4; + } else if (m_eighthQ) { + qq *= 2; + } else if (m_sixteenthQ) { + qq *= 4; + } else { + // convert quarter note metric positions into beat positions + if (compound) { + qq *= curDen.at(track); + qq /= 4; + qq /= 3; + } else if (curBeat.at(track) > 0) { + qq /= curBeat.at(track); + } else { + qq *= curDen.at(track); + qq /= 4; + } + } + + value.str(""); + value << qq; + token->setValue("auto", "zeroBeat", value.str()); + token->setValue("auto", "hasData", 1); + + } + return; + } +} + + + + ///////////////////////////////// // // Tool_gridtest::Tool_metlev -- Set the recognized options for the tool. @@ -94572,7 +95664,7 @@ Tool_msearch::Tool_msearch(void) { define("c|color=s", "highlight color"); define("m|mark|marker=s:@", "marking character"); define("M|no-mark|no-marker=b", "do not mark matches"); - define("Q|quiet=b", "quite mode: do not summarize matches"); + define("Q|quiet=b", "quiet mode: do not summarize matches"); } @@ -105156,6 +106248,669 @@ void Tool_myank::usage(const string& ommand) { +///////////////////////////////// +// +// Tool_nproof::Tool_nproof -- Set the recognized options for the tool. +// + +Tool_nproof::Tool_nproof(void) { + define("B|no-blank|no-blanks=b", "Do not check for blank lines.\n"); + define("b|only-blank|only-blanks=b", "Only check for blank lines.\n"); + + define("I|no-instrument|no-instruments=b", "Do not check instrument interpretations.\n"); + define("i|only-instrument|only-instruments=b", "Only check instrument interpretations.\n"); + + define("K|no-key=b", "Do not check for !!!key: manual initial key designation.\n"); + define("k|only-key=b", "Only check for !!!key: manual initial key designation.\n"); + + define("R|no-reference=b", "Do not check for reference records.\n"); + define("r|only-reference=b", "Only check for reference records.\n"); + + define("T|no-termination|no-terminations=b", "Do not check spine terminations.\n"); + define("t|only-termination|only-terminations=b", "Only check spine terminations.\n"); + + define("file|filename=b", "Print filename with raw count (if available).\n"); + define("raw=b", "Only print error count.\n"); +} + + + +///////////////////////////////// +// +// Tool_nproof::run -- Do the main work of the tool. +// + +bool Tool_nproof::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; i 0) { + m_humdrum_text << m_errorList; + m_humdrum_text << "!!!TOOL-nproof-error-count: " << m_errorCount << endl; + m_humdrum_text << "!!@@BEGIN: PREHTML\n"; + m_humdrum_text << "!!@TOOL: nproof\n"; + m_humdrum_text << "!!@CONTENT:\n"; + m_humdrum_text << "!!

@{TOOL-nproof-error-count} problem"; + if (m_errorCount != 1) { + m_humdrum_text << "s"; + } + m_humdrum_text << " detected

\n"; + m_humdrum_text << "!!
    \n"; + m_humdrum_text << m_errorHtml; + m_humdrum_text << "!!
\n"; + m_humdrum_text << "!!@@END: PREHTML\n"; + } else { + m_humdrum_text << "!!@@BEGIN: PREHTML\n"; + m_humdrum_text << "!!@TOOL: nproof\n"; + m_humdrum_text << "!!@CONTENT:\n"; + m_humdrum_text << "!!

No problems detected

\n"; + m_humdrum_text << "!!@@END: PREHTML\n"; + } +} + + + +////////////////////////////// +// +// Tool_nproof::checkForBlankLines -- +// + +void Tool_nproof::checkForBlankLines(HumdrumFile& infile) { + vector blanks; + // -1: Not checking for a blank line at the very end of the score. + for (int i=0; i\n"; +} + + + +////////////////////////////// +// +// Tool_nproof::checkForValidInstrumentCode -- +// + +void Tool_nproof::checkForValidInstrumentCode(HTp token, + vector>& instrumentList) { + + if ((token->find("&") == string::npos) && (token->find("|") == string::npos)) { + string code = token->substr(2); + for (int i=0; i<(int)instrumentList.size(); i++) { + if (instrumentList[i].first == code) { + return; + } + } + + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Unknown instrument code \"" + code + "\" on line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ". See list of codes at https://bit.ly/humdrum-instrument-codes.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + return; + } + + bool found1 = false; + bool found2 = false; + string inst1; + string inst2; + HumRegex hre; + if (hre.match(token, "^\\*I(.*)[&|](I.*)")) { + inst1 = hre.getMatch(1); + inst2 = hre.getMatch(2); + + for (int i=0; i<(int)instrumentList.size(); i++) { + if (instrumentList[i].first == inst1) { + found1 = true; + } + if (instrumentList[i].first == inst2) { + found2 = true; + } + } + } + + if (!found1) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Unknown instrument code \"" + inst1 + "\" in token " + *token + "on line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ". See list of codes at https://bit.ly/humdrum-instrument-codes.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + + if (!found2) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Unknown instrument code \"" + inst2 + "\" in token " + *token + "on line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ". See list of codes at https://bit.ly/humdrum-instrument-codes.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + +} + + + +////////////////////////////// +// +// Tool_nproof::checkInstrumentInformation -- +// + +void Tool_nproof::checkInstrumentInformation(HumdrumFile& infile) { + int codeLine = -1; + int classLine = -1; + HumRegex hre; + + vector> instrumentList = Convert::getInstrumentList(); + + for (int i=0; iisKern()) { + continue; + } + if (token->compare(0, 3, "*IC") == 0) { + if (classLine < 0) { + classLine = i; + } + } else if (hre.search(token, "^\\*I[a-z]")) { + if (codeLine < 0) { + codeLine = i; + } + } + } + } + + if (codeLine < 0) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": No instrument code line.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } else { + for (int i=0; iisKern()) { + if (!hre.search(token, "^\\*I[a-z]")) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": expected instrument code on line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } else { + checkForValidInstrumentCode(token, instrumentList); + } + } else { + if (*token != "*") { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Expected null interpretation on instrument code line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + } + } + + if (classLine < 0) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": No instrument class line.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } else { + for (int i=0; iisKern()) { + if (!hre.search(token, "^\\*IC[a-z]")) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": expected instrument class on line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } else { + if (*token != "*") { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Expected null interpretation on instrument class line " + to_string(token->getLineNumber()) + ", field " + to_string(token->getFieldNumber()) + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + } + } +} + + + +////////////////////////////// +// +// Tool_nproof::checkReferenceRecords -- +// + +void Tool_nproof::checkReferenceRecords(HumdrumFile& infile) { + vector foundENC; // Musescore encoder's name + vector foundEND; // Musescore encdoer's date + vector foundEED; // VHV editor's name + vector foundEEV; // VHV editor's date + + HumRegex hre; + for (int i=0; i\n"; + } + } + if (hre.search(key, "^EEV\\d*$")) { + if (key == "EEV") { + foundEEV.push_back(i);; + } + string value = infile[i].getReferenceValue(); + if (!hre.search(value, "^\\d\\d\\d\\d-\\d\\d-\\d\\d")) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": For EEV (ElEctronic Version) record on line " + to_string(i+1) + ", found a name rather than a date (or invalid date): " + value + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + if (hre.search(key, "^ENC\\d*(-modern|-iiif)?$")) { + string value = infile[i].getReferenceValue(); + if (hre.search(value, "^\\d\\d\\d\\d-\\d\\d-\\d\\d")) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": For ENC (Electronic eNCoder) record on line " + to_string(i+1) + ", found a date rather than a name: " + value + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + if (hre.search(key, "^END\\d*(-modern|-iiif)?$")) { + string value = infile[i].getReferenceValue(); + if (!hre.search(value, "^\\d\\d\\d\\d-\\d\\d-\\d\\d")) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": For END (Electronic eNcoding Date) record on line " + to_string(i+1) + ", found a name rather than a date (or an invalid date): " + value + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + if (hre.search(key, "^ENC(\\d*.*)$")) { + if (key == "ENC") { + foundENC.push_back(i); + } + } + if (hre.search(key, "^ENC-(\\d+.*)$")) { + string newvalue = "ENC" + hre.getMatch(1); + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": " + key + " reference record on line " + to_string(i+1) + " should not include a dash and instead be: " + newvalue + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (hre.search(key, "END(\\d*.*)")) { + if (key == "END") { + foundEND.push_back(i); + } + } + if (hre.search(key, "^END-(\\d+.*)$")) { + string newvalue = "END" + hre.getMatch(1); + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": " + key + " reference record on line " + to_string(i+1) + " should not include a dash and instead be: " + newvalue + ".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (key == "filter-") { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": \"filter-\" reference record on line " + to_string(i+1) + " should probably be \"filter-modern\" instead.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (key == "ENC-mod") { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": ENC-mod reference record on line " + to_string(i+1) + " should be ENC-modern instead.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (key == "END-mod") { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": END-mod reference record on line " + to_string(i+1) + " should be END-modern instead.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (key == "AIN-mod") { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": AIN-mod reference record on line " + to_string(i+1) + " should be AIN-modern instead.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (hre.search(key, "^(.*)-ori$")) { + string piece = hre.getMatch(1); + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": " + key + " reference record on line " + to_string(i+1) + " should not be used (either use " + piece + "-mod or don't add -ori qualifier to " + piece + ").\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + + // vector foundENC; // Musescore encoder's name + // vector foundEND; // Musescore encdoer's date + // vector foundEED; // VHV editor's name + // vector foundEEV; // VHV editor's date + + if (foundENC.empty()) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Missing ENC (initial encoder's name) reference record.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (foundEND.empty()) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Missing END (initial encoding date) reference record.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (foundEED.empty()) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Missing EED (Humdrum electronic editor's name) reference record.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + if (foundEEV.empty()) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Missing EEV (Humdrum electronic edition date) reference record.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + + if ((foundENC.size() == 1) && (foundEED.size() == 1)) { + if (foundENC[0] > foundEED[0]) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": ENC reference record on line " + to_string(foundENC[0]+1) + " should come before EED reference record on line " + to_string(foundEED[0]+1) + "\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + + if ((foundEND.size() == 1) && (foundEEV.size() == 1)) { + if (foundEND[0] > foundEEV[0]) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": END reference record on line " + to_string(foundEND[0]+1) + " should come before EEV reference record on line " + to_string(foundEEV[0]+1) + "\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + + + if ((foundENC.size() == 2) && (foundEED.size() == 0)) { + string date1; + string date2; + if (foundEND.size() == 2) { + date1 = infile[foundEND[0]].getReferenceValue(); + date2 = infile[foundEND[1]].getReferenceValue(); + hre.replaceDestructive(date1, "", "-", "g"); + hre.replaceDestructive(date2, "", "-", "g"); + int number1 = 0; + int number2 = 0; + if (hre.search(date1, "^(20\\d{6})$")) { + number1 = hre.getMatchInt(1); + } + if (hre.search(date2, "^(20\\d{6})$")) { + number2 = hre.getMatchInt(1); + } + if ((number1 > 0) && (number2 > 0)) { + if (number1 > number2) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Second ENC reference record on line " + to_string(foundENC[1]+1) + " should probably be changed to EED reference record (and second END reference record on line " + to_string(foundEND[1]+1) + " changed to EEV).\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + } else { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": There are two ENC records on lines " + to_string(foundENC[0]+1) + " and " + to_string(foundENC[1]+1) + ". The Humdrum editor's name should be changed to EED, and the editing date should be changed from END to EEV if necessary.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } + +} + + + +////////////////////////////// +// +// Tool_nproof::checkKeyInformation -- +// + +void Tool_nproof::checkKeyInformation(HumdrumFile& infile) { + int foundKey = -1; + for (int i=0; icompare(0, 7, "!!!key:") == 0) { + foundKey = i; + break; + } + } + + if (foundKey < 0) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": No !!!key: reference record.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + return; + } + + string value = infile[foundKey].getReferenceValue(); + if (value.empty()) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": !!!key: reference record on line " + to_string(foundKey+1) + " should not be empty. If no key, then use \"none\".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + return; + } + + HumRegex hre; + if (hre.search(value, "^([a-gA-G][#-n]?):(dor|phr|lyd|mix|aeo|loc|ion)$")) { + string tonic = hre.getMatch(1); + string mode = hre.getMatch(2); + int major = 0; + if ((mode == "lyd") || (mode == "mix") || (mode == "ion")) { + major = 1; + } + int uppercase = isupper(tonic[0]); + if ((major == 1) && (uppercase == 0)) { + tonic[0] = toupper(tonic[0]); + string correct = tonic + ":" + mode; + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": !!!key: reference record on line " + to_string(foundKey + 1) + " should be \"" + correct + "\".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } else if ((major == 0) && (uppercase == 1)) { + tonic[0] = tolower(tonic[0]); + string correct = tonic + ":" + mode; + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": !!!key: reference record on line " + to_string(foundKey + 1) + " should be \"" + correct + "\".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + } else if (hre.search(value, "([a-gA-G][#-n]?):(.+)")) { + string mode = hre.getMatch(2); + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Unknown mode in !!!key: reference record contents on line " + to_string(foundKey + 1) + ": \"" + mode + "\".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } else if (!hre.search(value, "([a-gA-G][#-n]?):?")) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Unknown key designation in !!!key: reference record contents on line " + to_string(foundKey + 1) + ": \"" + value + "\".\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + } + +} + + + +////////////////////////////// +// +// Tool_nproof::checkSpineTerminations -- +// + +void Tool_nproof::checkSpineTerminations(HumdrumFile& infile) { + int foundTerminal = 0; + for (int i=infile.getLineCount() - 1; i>0; i--) { + if (!infile[i].isInterpretation()) { + continue; + } + HTp token = infile.token(i, 0); + if (*token == "*-") { + foundTerminal = i; + break; + } + } + + if (!foundTerminal) { + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": No spine terminators.\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; + return; + } + + bool problem = false; + for (int i=0; igetSpineInfo(); + if (value.find(" ") != string::npos) { + problem = true; + break; + } + } + + if (!problem) { + return; + } + + m_errorCount++; + m_errorList += "!!!TOOL-nproof-error-" + to_string(m_errorCount) + ": Incorrect spine merger(s): "; + for (int i=0; igetSpineInfo() + ">"; + if (i < infile[foundTerminal].getFieldCount() - 1) { + m_errorList += " "; + } + } + m_errorList += "\n"; + m_errorHtml += "!!
  • @{TOOL-nproof-error-" + to_string(m_errorCount) + "}
  • \n"; +} + + + + + ///////////////////////////////// // // Tool_ordergps::Tool_ordergps -- Set the recognized options for the tool. @@ -107242,6 +108997,276 @@ bool Tool_phrase::hasPhraseMarks(HTp start) { +///////////////////////////////// +// +// Tool_pline::Tool_pline -- Set the recognized options for the tool. +// + +Tool_pline::Tool_pline(void) { + define("c|color=b", "color poetic lines (currently only by notes)"); + define("o|overlap=b", "do overlap analysis/markup"); +} + + + +///////////////////////////////// +// +// Tool_pline::run -- Do the main work of the tool. +// + +bool Tool_pline::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; i spinestops; + infile.getSpineStopList(spinestops); + for (int i=0; i<(int)spinestops.size(); i++) { + if (!spinestops[i]->isKern()) { + continue; + } + markSpineRests(spinestops[i]); + } +} + + +////////////////////////////// +// +// Tool_pline::markSpineRests -- +// + +void Tool_pline::markSpineRests(HTp spineStop) { + string marker = "😀"; + int track = spineStop->getTrack(); + int lastValue = -1; + HTp current = spineStop->getPreviousToken(); + int line; + int cvalue; + while (current) { + if (!current->isData()) { + current = current->getPreviousToken(); + continue; + } + if (current->isNull()) { + current = current->getPreviousToken(); + continue; + } + + line = current->getLineIndex(); + cvalue = m_lineInfo.at(line).at(track); + + if (current->isRest() && (cvalue != lastValue)) { + string text = *current; + text += marker; + current->setText(text); + } else { + lastValue = cvalue; + string text = *current; + text += "@" + to_string(cvalue); + current->setText(text); + } + current = current->getPreviousToken(); + } +} + + + +////////////////////////////// +// +// Tool_pline::fillLineInfo -- +// + +void Tool_pline::fillLineInfo(HumdrumFile& infile, vector>& lineinfo) { + lineinfo.clear(); + lineinfo.resize(infile.getLineCount()); + int maxtrack = infile.getMaxTrack(); + HumRegex hre; + for (int i=0; igetTrack(); + lineinfo[i][track] = digit; + } + } + } + + for (int i=1; i<(int)lineinfo.size() - 1; i++) { + for (int j=1; j<=maxtrack; j++) { + if (lineinfo.at(i).at(j)) { + continue; + } else { + lineinfo.at(i).at(j) = lineinfo.at(i-1).at(j); + } + } + } + + // for (int i=0; i<(int)lineinfo.size() - 1; i++) { + // for (int j=1; j<=maxtrack; j++) { + // cerr << lineinfo[i][j] << "\t"; + // } + // cerr << endl; + // } + +} + + + +////////////////////////////// +// +// Tool_pline::plineToColor -- +// + +void Tool_pline::plineToColor(HumdrumFile& infile, vector& tokens) { + HumRegex hre; + markRests(infile); + for (int i=0; i<(int)tokens.size(); i++) { + if (!hre.search(tokens[i], "^\\*pline:\\s*(\\d+)")) { + continue; + } + int lineNum = hre.getMatchInt(1); + int colorIndex = (lineNum - 1) % m_colors.size(); + string color = m_colors.at(colorIndex); + string text = "*color:"; + text += color; + tokens[i]->setText(text); + } +} + + + +////////////////////////////// +// +// Tool_pline::getPlineInterpretations -- +// + +void Tool_pline::getPlineInterpretations(HumdrumFile& infile, vector& tokens) { + HumRegex hre; + for (int i=0; iisKern()) { + continue; + } + if (hre.search(token, "^\\*pline:\\s*(\\d+)")) { + tokens.push_back(token); + } + } + } +} + + + + + ///////////////////////////////// // // Tool_gridtest::Tool_pnum -- Set the recognized options for the tool. @@ -114017,6 +116042,820 @@ string Tool_tassoize::getDate(void) { +///////////////////////////////// +// +// Tool_textdur::Tool_textdur -- Set the recognized options for the tool. +// + +Tool_textdur::Tool_textdur(void) { + // add command-line options here + define("a|analysis=b", "calculate and display analyses"); + define("m|melisma=b", "Count number of notes for each syllable"); + define("d|duration=b", "Duration of each syllable"); + define("i|interleave=b", "Preserve original text, and place analyses below text"); +} + + + +///////////////////////////////// +// +// Tool_textdur::run -- Do the main work of the tool. +// + +bool Tool_textdur::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; isetText(text); + } + } + + if (!m_interleaveQ) { + if (m_melismaQ) { + printMelismas(infile); + } else { + printDurations(infile); + } + } else { + printInterleaved(infile); + } + + if (m_analysisQ) { + printAnalysis(); + } + +} + + + +////////////////////////////// +// +// Tool_textdur::fillInstrumentNameInfo -- +// + +void Tool_textdur::fillInstrumentNameInfo(void) { + m_columnName.clear(); + m_columnName.resize(m_textStarts.size()); + for (int i=0; i<(int)m_columnName.size(); i++) { + m_columnName[i] = getColumnName(m_textStarts[i]); + } +} + + + +////////////////////////////// +// +// Tool_textdur::getColumnName -- +// + +string Tool_textdur::getColumnName(HTp token) { + HTp kerntok = getTandemKernToken(token); + if (!kerntok) { + return "unknown"; + } + int track = kerntok->getTrack(); + string output = "Track "; + output += to_string(track); + + HTp current = kerntok->getNextToken(); + HumRegex hre; + while (current) { + if (current->isData()) { + break; + } + if (hre.search(current, "^\\*I\\\"(.*)\\s*$")) { + output = hre.getMatch(1); + break; + } + current = current->getNextToken(); + } + return output; +} + + + + +////////////////////////////// +// +// Tool_textdur::printAnalysis -- +// + +void Tool_textdur::printAnalysis(void) { + if (m_melismaQ) { + printMelismaAverage(); + } + if (m_durationQ) { + printDurationAverage(); + } + printHtmlContent(); +} + + + +////////////////////////////// +// +// Tool_textdur::printHtmlContent -- +// + +void Tool_textdur::printHtmlContent(void) { + + m_humdrum_text << "!!@@BEGIN: PREHTML" << endl; + m_humdrum_text << "!!@CONTENT: " << endl; + m_humdrum_text << "!!

    Syllable length analysis

    " << endl; + + m_humdrum_text << "!!
    " << endl; + m_humdrum_text << "!!

    Number of syllables: @{TOOL-textdur-total-syllables}

    " << endl; + m_humdrum_text << "!!
    " << endl; + m_humdrum_text << "!! " << endl; + + int sum = 0; + for (int i=0; i<(int)m_melismas.size(); i++) { + sum += (int)m_melismas[i].size(); + } + + for (int i=(int)m_melismas.size() - 1; i>=0; i--) { + double percent = 1.0 * m_melismas.at(i).size() / sum; + percent = int(percent * 10000.0 + 0.5) / 100.0; + m_humdrum_text << "!! " + << "" << endl; + } + m_humdrum_text << "!!
    " << m_columnName.at(i) << "" << m_melismas.at(i).size() + << " (" << percent << "%)
    " << endl; + m_humdrum_text << "!!
    " << endl; + + if (m_melismaQ) { + m_humdrum_text << "!!

    Average syllable note length: @{TOOL-textdur-average-notes-per-syllable}

    " << endl; + m_humdrum_text << "!!
    " << endl; + printMelismaHtmlHistogram(); + m_humdrum_text << "!! " << endl; + } + if (m_durationQ) { + m_humdrum_text << "!!
    " << endl; + m_humdrum_text << "!!

    Average syllable duration: @{TOOL-textdur-average-syllable-duration} quarter notes

    " << endl; + printDurationHtmlHistogram(); + } + m_humdrum_text << "!!@@END: PREHTML" << endl; + +} + + +////////////////////////////// +// +// Tool_textdur::printDurationHtmlHistogram -- +// + +void Tool_textdur::printDurationHtmlHistogram(void) { + + map durinfo; + double total = 0; + for (int i=0; i<(int)m_durations.size(); i++) { + // -1 on next line for *- terminator? + for (int j=0; j<(int)m_durations[i].size() -1 ; j++) { + HumNum dur = m_durations[i][j]; + int value = durinfo[dur]; + durinfo[dur] = value + 1; + total += 1.0; + } + } + + double maxlen = 0; + for (auto it = durinfo.begin(); it != durinfo.end(); it++) { + if (it->second > maxlen) { + maxlen = it->second; + } + } + + m_humdrum_text << "!! " << endl; + m_humdrum_text << "!! " << endl; + stringstream value; + for (auto it = durinfo.begin(); it != durinfo.end(); it++) { + double length = 1.0 * it->second / maxlen * 400; + double percent = 1.0 * it->second / total * 100.0; + percent = (int)(percent * 100.0 + 0.5) / 100.0; + value.str(""); + it->first.printMixedFraction(value, "+"); + m_humdrum_text << "!! " << endl; + } + m_humdrum_text << "!!
    Duration (quarter notes) Syllable count
    " << value.str() << ""; + m_humdrum_text << "  "; + m_humdrum_text << " " << it->second << " (" << percent << "%)
    " << endl; +} + + + + + + +////////////////////////////// +// +// Tool_textdur::printMelismaHtmlHistogram -- +// default value = -1 (meaning all voices); +// + +void Tool_textdur::printMelismaHtmlHistogram(void) { + + map melinfo; + double total = 0; + for (int i=0; i<(int)m_melismas.size(); i++) { + // -1 on next line for *- terminator? + for (int j=0; j<(int)m_melismas[i].size() -1 ; j++) { + int count = m_melismas[i][j]; + int value = melinfo[count]; + melinfo[count] = value + 1; + total += 1.0; + } + } + + double maxlen = 0; + for (auto it = melinfo.begin(); it != melinfo.end(); it++) { + if (it->second > maxlen) { + maxlen = it->second; + } + } + + m_humdrum_text << "!! " << endl; + m_humdrum_text << "!! " << endl; + for (auto it = melinfo.begin(); it != melinfo.end(); it++) { + double length = 1.0 * it->second / maxlen * 400; + double percent = 1.0 * it->second / total * 100.0; + percent = (int)(percent * 100.0 + 0.5) / 100.0; + m_humdrum_text << "!! " << endl; + } + m_humdrum_text << "!!
    Syllable notes Syllable count
    " << it->first << ""; + m_humdrum_text << "  "; + m_humdrum_text << " " << it->second << " (" << percent << "%)
    " << endl; +} + + +// Print individual histograms for each voice: + +void printMelismaHtmlHistogram(int index, int maxVal) { + +/* + map melinfo; + double total = maxVal; + double maxlen = maxVal; + +// ggg + + m_humdrum_text << "!! " << endl; + m_humdrum_text << "!! " << endl; + for (auto it = melinfo.begin(); it != melinfo.end(); it++) { + double length = 1.0 * it->second / maxlen * 400; + double percent = 1.0 * it->second / total * 100.0; + percent = (int)(percent * 100.0 + 0.5) / 100.0; + m_humdrum_text << "!! " << endl; + } + m_humdrum_text << "!!
    Syllable notes Syllable count
    " << it->first << ""; + m_humdrum_text << "  "; + m_humdrum_text << " " << it->second << " (" << percent << "%)
    " << endl; +} + +*/ + +} + + + +////////////////////////////// +// +// printMelismaAverage -- +// + +void Tool_textdur::printMelismaAverage() { + double sum = 0.0; + int counter = 0; + for (int i=0; i<(int)m_melismas.size(); i++) { + // -1 on next line for *- terminator? + for (int j=0; j<(int)m_melismas[i].size() - 1; j++) { + sum += m_melismas.at(i).at(j); + counter++; + } + } + if (!counter) { + return; + } + double average = sum / counter; + average = int(average * 100.0 + 0.5) / 100.0; + m_humdrum_text << "!!!TOOL-textdur-average-notes-per-syllable: " << average << endl; + m_humdrum_text << "!!!TOOL-textdur-total-syllables: " << counter << endl; +} + + + +////////////////////////////// +// +// printDurationAverage -- +// + +void Tool_textdur::printDurationAverage(void) { + HumNum sum = 0; + int counter = 0; + for (int i=0; i<(int)m_durations.size(); i++) { + // -1 on next line for *- terminator? + for (int j=0; j<(int)m_durations[i].size() - 1; j++) { + sum += m_durations.at(i).at(j); + counter++; + } + } + if (!counter) { + return; + } + double average = sum.getFloat() / counter; + average = int(average * 100.0 + 0.5) / 100.0; + m_humdrum_text << "!!!TOOL-textdur-average-syllable-duration: " << average << endl; +} + + +////////////////////////////// +// +// Tool_textdur::printInterleaved -- +// + +void Tool_textdur::printInterleaved(HumdrumFile& infile) { + vector textTrack(infile.getMaxTrack() + 1, false); + for (int i=0; i<(int)m_textStarts.size(); i++) { + int track = m_textStarts[i]->getTrack(); + textTrack.at(track) = true; + } + + + for (int i=0; i& textTrack) { + for (int i=0; igetTrack(); + m_humdrum_text << token; + if (textTrack.at(track)) { + printTokenAnalysis(token); + } + if (i < line.getFieldCount() - 1) { + m_humdrum_text << "\t"; + } + } + m_humdrum_text << "\n"; +} + + + +////////////////////////////// +// +// Tool_textdur::printTokenAnalysis -- +// + +void Tool_textdur::printTokenAnalysis(HTp token) { + if (token->compare(0, 2, "**") == 0) { + if (m_melismaQ) { + m_humdrum_text << "\t**text-melisma"; + } + if (m_durationQ) { + m_humdrum_text << "\t**text-duration"; + } + return; + } + + if (*token == "*-") { + if (m_melismaQ) { + m_humdrum_text << "\t*-"; + } + if (m_durationQ) { + m_humdrum_text << "\t*-"; + } + return; + } + + if (token->compare(0, 1, "*") == 0) { + + HTp tandem = getTandemKernToken(token); + if (tandem->compare(0, 3, "*I\"") == 0) { + if (m_melismaQ) { + m_humdrum_text << "\t*v:mel:"; + } + if (m_durationQ) { + m_humdrum_text << "\t*v:dur:"; + } + return; + } + + if (m_melismaQ) { + m_humdrum_text << "\t*"; + } + if (m_durationQ) { + m_humdrum_text << "\t*"; + } + return; + } + + if (token->compare(0, 1, "!") == 0) { + if (m_melismaQ) { + m_humdrum_text << "\t!"; + } + if (m_durationQ) { + m_humdrum_text << "\t!"; + } + return; + } + + if (token->compare(0, 1, "=") == 0) { + if (m_melismaQ) { + m_humdrum_text << "\t" << token; + } + if (m_durationQ) { + m_humdrum_text << "\t" << token; + } + return; + } + + if (*token == ".") { + if (m_melismaQ) { + m_humdrum_text << "\t."; + } + if (m_durationQ) { + m_humdrum_text << "\t."; + } + return; + } + + if (!token->isData()) { + cerr << "WARNING: DATA TOKEN IS NOT DATA: " << token << endl; + return; + } + + int index = -1; + if (token->isDefined("auto", "index")) { + index = token->getValueInt("auto", "index"); + } else { + if (m_melismaQ) { + m_humdrum_text << "\t."; + } + if (m_durationQ) { + m_humdrum_text << "\t."; + } + return; + } + + // Have data analysis to print: + + int track = token->getTrack(); + int column = m_track2column.at(track); + + if (m_melismaQ) { + int melisma = m_melismas.at(column).at(index); + m_humdrum_text << "\t" << melisma; + } + if (m_durationQ) { + HumNum duration = m_durations.at(column).at(index); + m_humdrum_text << "\t" << duration; + } +} + + + +////////////////////////////// +// +// Tool_textdur::printMelismas -- +// + +void Tool_textdur::printMelismas(HumdrumFile& infile) { + // replace text with melisma data: + for (int i=0; i<(int)m_syllables.size(); i++) { + // -1 on next line for *- placeholder at end of spine. + for (int j=0; j<(int)m_syllables.at(i).size() - 1; j++) { + HTp token = m_syllables.at(i).at(j); + int jj = token->getValueInt("auto", "index"); + string replacement = to_string(m_melismas.at(i).at(jj)); + token->setText(replacement); + } + } + + infile.createLinesFromTokens(); + m_humdrum_text << infile; +} + + + +////////////////////////////// +// +// Tool_textdur::printDurations -- +// + +void Tool_textdur::printDurations(HumdrumFile& infile) { + // replace text with duration data: + stringstream replacement; + for (int i=0; i<(int)m_syllables.size(); i++) { + // -1 on next line for *- placeholder at end of spine. + for (int j=0; j<(int)m_syllables.at(i).size() - 1; j++) { + HTp token = m_syllables.at(i).at(j); + int jj = token->getValueInt("auto", "index"); + replacement << m_durations.at(i).at(jj); + token->setText(replacement.str()); + replacement.str(""); + } + } + + infile.createLinesFromTokens(); + m_humdrum_text << infile; +} + + + +////////////////////////////// +// +// Tool_textdur::getTextSpineStarts -- +// + +void Tool_textdur::getTextSpineStarts(HumdrumFile& infile, vector& starts) { + starts.clear(); + vector allSpineStarts; + infile.getSpineStartList(allSpineStarts); + for (int i=0; i<(int)allSpineStarts.size(); i++) { + HTp token = allSpineStarts.at(i); + if (*token == "**text") { + starts.push_back(token); + token->setValue("auto", "index", i); + } else if (*token == "**sylba") { + starts.push_back(token); + token->setValue("auto", "index", i); + } + } + + // Setup m_track2column + m_track2column.resize(infile.getMaxTrack() + 1); + fill(m_track2column.begin(), m_track2column.end(), -1); + for (int i=0; i<(int)starts.size(); i++) { + int track = starts[i]->getTrack(); + m_track2column.at(track) = i; + } +} + + + +////////////////////////////// +// +// Tool_textdur::processTextSpine -- +// + +void Tool_textdur::processTextSpine(vector& starts, int index) { + HTp current = starts.at(index); + current->getNextToken(); + while (current) { + if (!current->isData()) { + if (*current == "*-") { + // store data terminator (for calculating duration of last note): + current->setValue("auto", "index", to_string(m_syllables.at(index).size())); + m_syllables.at(index).push_back(current); + m_durations.at(index).push_back(-1000); + m_melismas.at(index).push_back(-1000); + break; + } + current = current->getNextToken(); + continue; + } + + if (current->isNull()) { + current = current->getNextToken(); + continue; + } + + current->setValue("auto", "index", to_string(m_syllables.at(index).size())); + m_syllables.at(index).push_back(current); + m_durations.at(index).push_back(-1); // store dummy duration + m_melismas.at(index).push_back(-1); // store dummy melisma + + + current = current->getNextToken(); + } + + for (int i=0; i<(int)m_syllables.size(); i++) { + for (int j=0; j<(int)m_syllables[i].size() - 1; j++) { + if (m_melismaQ) { + m_melismas.at(i).at(j) = getMelisma(m_syllables.at(i).at(j), m_syllables.at(i).at(j+1)); + } + if (m_durationQ) { + m_durations.at(i).at(j) = getDuration(m_syllables.at(i).at(j), m_syllables.at(i).at(j+1)); + } + } + } +} + + + +////////////////////////////// +// +// Tool_textdur::getMelisma -- Not counting syllable starts on secondary tied notes. +// + +int Tool_textdur::getMelisma(HTp tok1, HTp tok2) { + int stopIndex = tok2->getLineIndex(); + HTp current = getTandemKernToken(tok1); + if (!current) { + return 0; + } + if (current->isNull()) { + cerr << "Strange case for syllable " << tok1 << " on line " << tok1->getLineNumber(); + cerr << ", field " << tok1->getFieldNumber() <<" which does not start on a note" << endl; + return 0; + } + int cline = current->getLineIndex(); + int counter = 0; + while (current && cline < stopIndex) { + if (!current->isData()) { + current = current->getNextToken(); + if (current) { + cline = current->getLineIndex(); + } + continue; + } + if (current->isNull()) { + current = current->getNextToken(); + if (current) { + cline = current->getLineIndex(); + } + continue; + } + if (current->isNoteAttack()) { + counter++; + } + current = current->getNextToken(); + if (current) { + cline = current->getLineIndex(); + } + } + + return counter; +} + + + +////////////////////////////// +// +// Tool_textdur::getTandemKernToken -- Search to the left for the +// first **kern spine. Returns NULL if none found. +// + +HTp Tool_textdur::getTandemKernToken(HTp token) { + HTp current = token->getPreviousFieldToken(); + while (current && !current->isKern()) { + current = current->getPreviousFieldToken(); + } + return current; +} + + + +////////////////////////////// +// +// Tool_textdur::getDuration -- Not counting rests at end of first syllable. +// + +HumNum Tool_textdur::getDuration(HTp tok1, HTp tok2) { + int startIndex = tok1->getLineIndex(); + HTp current = getTandemKernToken(tok2); + if (!current) { + return 0; + } + if (current->isNull()) { + cerr << "Strange case for syllable " << tok1 << " on line " << tok1->getLineNumber(); + cerr << ", field " << tok1->getFieldNumber() <<" which does not start on a note" << endl; + return 0; + } + HTp lastNoteEnd = current; + current = current->getPreviousToken(); + int cline = current->getLineIndex(); + while (current && cline > startIndex) { + if (!current->isData()) { + current = current->getPreviousToken(); + continue; + } + if (current->isNull()) { + current = current->getPreviousToken(); + continue; + } + cline = current->getLineIndex(); + if (!current->isRest()) { + break; + } else { + lastNoteEnd = current; + } + current = current->getPreviousToken(); + } + + if (!lastNoteEnd) { + return 0; + } + + HumNum duration = lastNoteEnd->getDurationFromStart() - tok1->getDurationFromStart(); + + return duration; +} + + + + + ///////////////////////////////// // // Tool_thru::Tool_thru -- Set the recognized options for the tool. From 7d7569aa824d4f730e6715eff41a7b6d2b17842c Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sun, 24 Sep 2023 16:38:56 -0700 Subject: [PATCH 007/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/839 --- src/iohumdrum.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 22aba8af8ff..9633e944745 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -5604,13 +5604,16 @@ void HumdrumInput::fillStaffInfo(hum::HTp staffstart, int staffnumber, int staff if (part->compare(0, 5, "*clef") == 0) { if (cleftok) { if (clef == *part) { - // there is already a clef found, and it is the same + // There is already a clef found, and it is the same // as this one, so ignore the second one. } else { - // mark clef as a clef change to print in the layer - part->setValue("auto", "clefChange", 1); - markOtherClefsAsChange(part); + // Mark clef as a clef change to print in the layer: + if (part->isKern()) { + // Don't mark as clef change in **mens. + part->setValue("auto", "clefChange", 1); + markOtherClefsAsChange(part); + } } part = part->getNextToken(); continue; @@ -5621,7 +5624,7 @@ void HumdrumInput::fillStaffInfo(hum::HTp staffstart, int staffnumber, int staff cleftok = part; } else if (part->find("clefX") != std::string::npos) { - // allow percussion clef to not have a line number since it is unpitched. + // Allow percussion clef to not have a line number since it is unpitched. clef = *part; cleftok = part; } @@ -29392,7 +29395,6 @@ void HumdrumInput::markAdjacentNullsWithClef(hum::HTp clef) void HumdrumInput::markOtherClefsAsChange(hum::HTp clef) { - int ctrack = clef->getTrack(); int track; From cb41210d074dd2cdcdc411a3852b8396f46396fa Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sun, 24 Sep 2023 20:57:42 -0700 Subject: [PATCH 008/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/840 --- include/hum/humlib.h | 10 +++--- src/hum/humlib.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++- src/iohumdrum.cpp | 12 +++++-- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index 8ee9b86f573..cc4c4383696 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: Sat Sep 23 22:51:29 PDT 2023 +// Last Modified: Sun Sep 24 17:52:16 PDT 2023 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 @@ -7914,9 +7914,10 @@ class Tool_kern2mens : public HumTool { bool run (HumdrumFile& infile, ostream& out); protected: - void convertToMens (HumdrumFile& infile); - string convertKernTokenToMens (HTp token); - void printBarline (HumdrumFile& infile, int line); + void convertToMens (HumdrumFile& infile); + std::string convertKernTokenToMens(HTp token); + void printBarline (HumdrumFile& infile, int line); + std::string getClefConversion (HTp token); private: bool m_numbersQ = true; // used with -N option @@ -8344,6 +8345,7 @@ class Tool_mens2kern : public HumTool { int brevis_def, int semibrevis_def); void getMensuralInfo (HTp token, int& maximodus, int& modus, int& tempus, int& prolatio); + std::string getClefConversion(HTp token); private: bool m_debugQ; diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index 15494811bc6..6bc49f32329 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: Sat Sep 23 22:51:29 PDT 2023 +// Last Modified: Sun Sep 24 17:52:16 PDT 2023 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 @@ -86326,6 +86326,9 @@ string Tool_kern2mens::convertKernTokenToMens(HTp token) { data += m_clef; return data; } + } else if (hre.search(token, "^\\*[mo]?clef")) { + string value = getClefConversion(token); + return value; } } if (!token->isData()) { @@ -86446,6 +86449,78 @@ void Tool_kern2mens::printBarline(HumdrumFile& infile, int line) { +////////////////////////////// +// +// Tool_kern2mens::getClefConversion -- +// If token is *oclef and there is an adjacent *clef, +// convert *oclef to *clef and *clef to *mclef; otherwise, +// return the given clef. +// +// + +string Tool_kern2mens::getClefConversion(HTp token) { + + vector clefs; + vector oclefs; + vector mclefs; + + HumRegex hre; + + HTp current = token->getNextToken(); + while (current) { + if (current->isData()) { + break; + } + if (current->compare(0, 5, "*clef") == 0) { + clefs.push_back(current); + } + if (current->compare(0, 6, "*oclef") == 0) { + oclefs.push_back(current); + } + if (current->compare(0, 6, "*mclef") == 0) { + mclefs.push_back(current); + } + current = current->getNextToken(); + } + + current = token->getPreviousToken(); + while (current) { + if (current->isData()) { + break; + } + if (current->compare(0, 5, "*clef") == 0) { + clefs.push_back(current); + } + if (current->compare(0, 6, "*oclef") == 0) { + oclefs.push_back(current); + } + if (current->compare(0, 6, "*mclef") == 0) { + mclefs.push_back(current); + } + current = current->getPreviousToken(); + } + + if (token->compare(0, 5, "*clef") == 0) { + if (oclefs.size() > 0) { + string value = *token; + hre.replaceDestructive(value, "mclef", "clef"); + return value; + } + } + + if (token->compare(0, 6, "*oclef") == 0) { + if (clefs.size() > 0) { + string value = *token; + hre.replaceDestructive(value, "clef", "oclef"); + return value; + } + } + + return *token; +} + + + ///////////////////////////////// // diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 9633e944745..b861cf19d1e 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -5729,7 +5729,7 @@ void HumdrumInput::fillStaffInfo(hum::HTp staffstart, int staffnumber, int staff ss[staffindex].meter_bottom = bot; ss[staffindex].meter_top = top; if (bot == 0) { - // Can't to breve meters, so switch to semibreve meter (whole notes). + // Can't do breve meters, so switch to semibreve meter (whole notes). ss[staffindex].meter_bottom = 1; ss[staffindex].meter_top *= 2; } @@ -5785,7 +5785,10 @@ void HumdrumInput::fillStaffInfo(hum::HTp staffstart, int staffnumber, int staff // short-circuit *met with *omet for **mens data if (staffstart->isMensLike()) { if ((!m_omet.empty()) && (staffnumber == m_omet.back().first)) { - metersig = *m_omet.back().second; + auto ploc = m_omet.back().second->rfind(")"); + if (ploc != std::string::npos) { + metersig = m_omet.back().second->substr(6, ploc - 6); + } metertok = m_omet.back().second; } } @@ -11886,7 +11889,10 @@ bool HumdrumInput::fillContentsOfLayer(int track, int startline, int endline, in } } if (m_mens) { - if (token->isMensurationSymbol()) { + if (token->compare(0, 6, "*omet(") == 0) { + setMensurationSymbol(m_layer, *token, staffindex, token); + } + else if (token->isMensurationSymbol()) { // add mensuration change to layer. setMensurationSymbol(m_layer, *token, staffindex, token); } From 7518ccb9de57de39aa5d8c0aab2979fc13ed7171 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Sun, 24 Sep 2023 21:35:07 -0700 Subject: [PATCH 009/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/842 --- src/iohumdrum.cpp | 82 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 15 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index b861cf19d1e..14421571ef5 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -23663,15 +23663,30 @@ void HumdrumInput::convertNote(Note *note, hum::HTp token, int staffadj, int sta bool editorialQ = false; std::string edittype; - if (!m_signifiers.editacc.empty()) { - for (int x = 0; x < (int)m_signifiers.editacc.size(); ++x) { - if (tstring.find(m_signifiers.editacc[x]) != std::string::npos) { - editorialQ = true; - edittype = m_signifiers.edittype[x]; - break; + + if (token->isKern()) { + if (!m_signifiers.editaccKern.empty()) { + for (int x = 0; x < (int)m_signifiers.editaccKern.size(); ++x) { + if (tstring.find(m_signifiers.editaccKern[x]) != std::string::npos) { + editorialQ = true; + edittype = m_signifiers.edittypeKern[x]; + break; + } + } + } + } + else if (token->isMens()) { + if (!m_signifiers.editaccMens.empty()) { + for (int x = 0; x < (int)m_signifiers.editaccMens.size(); ++x) { + if (tstring.find(m_signifiers.editaccMens[x]) != std::string::npos) { + editorialQ = true; + edittype = m_signifiers.edittypeMens[x]; + break; + } } } } + std::string edittype2 = token->getLayoutParameter("A", "edit", subtoken); if (edittype.empty() && !edittype2.empty()) { editorialQ = true; @@ -23679,8 +23694,15 @@ void HumdrumInput::convertNote(Note *note, hum::HTp token, int staffadj, int sta // default editorial accidental type edittype = ""; // use the first editorial accidental RDF style in file if present - if (!m_signifiers.editacc.empty()) { - edittype = m_signifiers.edittype[0]; + if (token->isKern()) { + if (!m_signifiers.editaccKern.empty()) { + edittype = m_signifiers.edittypeKern[0]; + } + } + else if (token->isMens()) { + if (!m_signifiers.editaccMens.empty()) { + edittype = m_signifiers.edittypeMens[0]; + } } } else { @@ -28580,6 +28602,36 @@ void HumdrumInput::parseSignifiers(hum::HumdrumFile &infile) } } + if (key == "RDF**mens") { + + // editorial accidentals: + if (value.find("editorial accidental", equals) != std::string::npos) { + m_signifiers.editaccMens.push_back(signifier); + if (value.find("brack") != std::string::npos) { + if (value.find("up") != std::string::npos) { + m_signifiers.edittypeMens.push_back("brack-up"); + } + else { + m_signifiers.edittypeMens.push_back("brack"); + } + } + else if (value.find("paren") != std::string::npos) { + if (value.find("up") != std::string::npos) { + m_signifiers.edittypeMens.push_back("paren-up"); + } + else { + m_signifiers.edittypeMens.push_back("paren"); + } + } + else if (value.find("none") != std::string::npos) { + m_signifiers.edittypeMens.push_back("none"); + } + else { + m_signifiers.edittypeMens.push_back(""); + } + } + } + if (key != "RDF**kern") { continue; } @@ -28656,28 +28708,28 @@ void HumdrumInput::parseSignifiers(hum::HumdrumFile &infile) // editorial accidentals: if (value.find("editorial accidental", equals) != std::string::npos) { - m_signifiers.editacc.push_back(signifier); + m_signifiers.editaccKern.push_back(signifier); if (value.find("brack") != std::string::npos) { if (value.find("up") != std::string::npos) { - m_signifiers.edittype.push_back("brack-up"); + m_signifiers.edittypeKern.push_back("brack-up"); } else { - m_signifiers.edittype.push_back("brack"); + m_signifiers.edittypeKern.push_back("brack"); } } else if (value.find("paren") != std::string::npos) { if (value.find("up") != std::string::npos) { - m_signifiers.edittype.push_back("paren-up"); + m_signifiers.edittypeKern.push_back("paren-up"); } else { - m_signifiers.edittype.push_back("paren"); + m_signifiers.edittypeKern.push_back("paren"); } } else if (value.find("none") != std::string::npos) { - m_signifiers.edittype.push_back("none"); + m_signifiers.edittypeKern.push_back("none"); } else { - m_signifiers.edittype.push_back(""); + m_signifiers.edittypeKern.push_back(""); } } From c83a1fe51a766df29908d64d8572aa06584f2a00 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Tue, 26 Sep 2023 10:37:06 -0700 Subject: [PATCH 010/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/845 --- include/vrv/iohumdrum.h | 7 +++-- src/iohumdrum.cpp | 60 ++++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/include/vrv/iohumdrum.h b/include/vrv/iohumdrum.h index dc079878f95..82d5f3f43d7 100644 --- a/include/vrv/iohumdrum.h +++ b/include/vrv/iohumdrum.h @@ -370,8 +370,11 @@ class HumdrumSignifiers { char cuesize = '\0'; // !!!RDF**kern: @ = cue size char terminallong = '\0'; // !!!RDF**kern: l = terminal long char terminalbreve = '\0'; // !!!RDF**kern: l = terminal breve - std::vector editacc; // !!!RDF**kern: i = editorial accidental - std::vector edittype; // !!!RDF**kern: i = editoral accidental, brack[ets]/paren[theses] + + std::vector editaccKern; // !!!RDF**kern: i = editorial accidental + std::vector editaccMens; // !!!RDF**mens: z = editorial accidental + std::vector edittypeKern; // !!!RDF**kern: i = editoral accidental, brack[ets]/paren[theses] + std::vector edittypeMens; // !!!RDF**mens: z = editoral accidental, brack[ets]/paren[theses] // for **dynam: std::string cresctext; // !!!RDF**kern: > = "cresc." diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 14421571ef5..008f16ffa7c 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -6482,7 +6482,11 @@ void HumdrumInput::setMensurationSymbol( if (mensurtok) { setLocationId(vrvmensur, mensurtok); } - if (metersig == "*met(C)" || metersig == "C") { + + string metdata = metersig; + hre.replaceDestructive(metdata, "$1", "^\\*o?met\\((.*)\\)"); + + if (metdata == "C") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_2); @@ -6492,7 +6496,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 2; prolatio = 2; } - else if (metersig == "*met(C3)" || metersig == "C3") { + else if (metdata == "C3") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_2); @@ -6502,7 +6506,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 2; } - else if (metersig == "*met(C|)" || metersig == "C|") { + else if (metdata == "C|") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_2); @@ -6513,7 +6517,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 2; prolatio = 2; } - else if (metersig == "*met(C|3)" || metersig == "C|3") { + else if (metdata == "C|3") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_2); @@ -6525,7 +6529,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 2; prolatio = 2; } - else if (metersig == "*met(O)" || metersig == "O") { + else if (metdata == "O") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_3); vrvmensur->SetProlatio(PROLATIO_2); @@ -6535,7 +6539,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 2; } - else if (metersig == "*met(O3)" || metersig == "O3") { + else if (metdata == "O3") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_3); vrvmensur->SetProlatio(PROLATIO_2); @@ -6545,7 +6549,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 2; } - else if (metersig == "*met(O|)" || metersig == "O|") { + else if (metdata == "O|") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_3); vrvmensur->SetProlatio(PROLATIO_2); @@ -6556,7 +6560,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 2; } - else if (metersig == "*met(O|3)" || metersig == "O|3") { + else if (metdata == "O|3") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_3); vrvmensur->SetProlatio(PROLATIO_2); @@ -6567,7 +6571,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 2; } - else if (metersig == "*met(O.)" || metersig == "O.") { + else if (metdata == "O.") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_3); vrvmensur->SetProlatio(PROLATIO_3); @@ -6577,7 +6581,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 3; } - else if (metersig == "*met(O.|)" || metersig == "O.|") { + else if (metdata == "O.|") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_3); vrvmensur->SetProlatio(PROLATIO_3); @@ -6588,7 +6592,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 3; prolatio = 3; } - else if (metersig == "*met(C.)" || metersig == "C.") { + else if (metdata == "C.") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_3); @@ -6598,7 +6602,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 2; prolatio = 3; } - else if (metersig == "*met(C.|)" || metersig == "C.|") { + else if (metdata == "C.|") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_3); @@ -6609,7 +6613,7 @@ void HumdrumInput::setMensurationSymbol( tempus = 2; prolatio = 3; } - else if (metersig == "*met(C|3/2)" || metersig == "C|3/2") { + else if (metdata == "C|3/2") { if (m_mens) { vrvmensur->SetTempus(TEMPUS_2); vrvmensur->SetProlatio(PROLATIO_2); @@ -6621,55 +6625,55 @@ void HumdrumInput::setMensurationSymbol( prolatio = 2; } - if (metersig.find('C') != std::string::npos) { + if (metdata.find('C') != std::string::npos) { vrvmensur->SetSign(MENSURATIONSIGN_C); - if (metersig.find("3/2") != std::string::npos) { + if (metdata.find("3/2") != std::string::npos) { vrvmensur->SetNum(3); vrvmensur->SetNumbase(2); } - else if (metersig.find("C2") != std::string::npos) { + else if (metdata.find("C2") != std::string::npos) { vrvmensur->SetNum(2); } - else if (metersig.find("C3") != std::string::npos) { + else if (metdata.find("C3") != std::string::npos) { vrvmensur->SetNum(3); } } - else if (metersig.find('O') != std::string::npos) { + else if (metdata.find('O') != std::string::npos) { vrvmensur->SetSign(MENSURATIONSIGN_O); - if (metersig.find("3/2") != std::string::npos) { + if (metdata.find("3/2") != std::string::npos) { vrvmensur->SetNum(3); vrvmensur->SetNumbase(2); } - else if (metersig.find("O2") != std::string::npos) { + else if (metdata.find("O2") != std::string::npos) { vrvmensur->SetNum(2); } - else if (metersig.find("O3") != std::string::npos) { + else if (metdata.find("O3") != std::string::npos) { vrvmensur->SetNum(3); } } else { - std::cerr << "Warning: do not understand mensuration " << metersig << std::endl; + std::cerr << "Warning: do not understand mensuration " << metdata << std::endl; return; } - if (metersig.find('|') != std::string::npos) { + if (metdata.find('|') != std::string::npos) { vrvmensur->SetSlash(1); } - if (metersig.find('.') != std::string::npos) { + if (metdata.find('.') != std::string::npos) { vrvmensur->SetDot(BOOLEAN_true); } - if (metersig.find('r') != std::string::npos) { + if (metdata.find('r') != std::string::npos) { vrvmensur->SetOrient(ORIENTATION_reversed); } - if (hre.search(metersig, "(\\d+)/(\\d+)")) { + if (hre.search(metdata, "(\\d+)/(\\d+)")) { vrvmensur->SetNum(hre.getMatchInt(1)); vrvmensur->SetNumbase(hre.getMatchInt(2)); } - else if (hre.search(metersig, "/(\\d+)")) { + else if (hre.search(metdata, "/(\\d+)")) { vrvmensur->SetNumbase(hre.getMatchInt(1)); } - else if (hre.search(metersig, "(\\d+).*\\)")) { + else if (hre.search(metdata, "(\\d+).*\\)")) { vrvmensur->SetNum(hre.getMatchInt(1)); } From 26c8144939d12f931abb1b01c7270f790b1ddbc6 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Tue, 26 Sep 2023 21:12:04 -0700 Subject: [PATCH 011/108] Implementation for issue https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/846 --- src/iohumdrum.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 008f16ffa7c..fe75b683bcd 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -5524,7 +5524,8 @@ void HumdrumInput::addMidiTempo(ScoreDef *scoreDef, hum::HTp kernpart, int top, void HumdrumInput::addDefaultTempo(ScoreDef *scoreDef) { if (m_mens) { - scoreDef->SetMidiBpm(400.0 * m_globalTempoScaling); + // mensural tempo is not in quarter note units? + scoreDef->SetMidiBpm(200.0 * m_globalTempoScaling); return; } double sum = 0.0; @@ -24142,7 +24143,6 @@ void HumdrumInput::convertNote(Note *note, hum::HTp token, int staffadj, int sta } } - // alterted notes (MEI 5): if (mensit) { addMensuralQuality(note, token); } @@ -24313,7 +24313,7 @@ bool HumdrumInput::checkForJoin(Note *note, hum::HTp token) ////////////////////////////// // // HumdrumInput::addMensuralQuality -- Add explicit @num and @numbase for mensural notes -// that doe not match the mensuration. This can be removed later when verovio does +// that do not match the mensuration. This can be removed later when verovio does // this on its own. // // maximodus splits maxima into 2 or 3 longas @@ -24340,15 +24340,16 @@ void HumdrumInput::addMensuralQuality(Note *note, hum::HTp token) bool longa = token->find("L") == std::string::npos ? false : true; bool breve = token->find("S") == std::string::npos ? false : true; bool semibreve = token->find("s") == std::string::npos ? false : true; + bool minima = token->find("M") == std::string::npos ? false : true; + bool semiminima = token->find("m") == std::string::npos ? false : true; + bool fusa = token->find("U") == std::string::npos ? false : true; + bool semifusa = token->find("u") == std::string::npos ? false : true; - if (!(maxima || longa || breve || semibreve)) { - // minim, semiminim, fusa, and semifusa should always be imperfect - return; - } - - // Do not put @num/@numbase on notes/rests that match the mensuration: + // Do not put @dur.quality on notes/rests that match the mensuration: int staffindex = m_currentstaff - 1; + humaux::StaffStateVariables &ss = m_staffstates.at(staffindex); + if (maxima && perfect && (ss.maximodus == 3)) { return; } @@ -24373,19 +24374,26 @@ void HumdrumInput::addMensuralQuality(Note *note, hum::HTp token) else if (semibreve && imperfect && (ss.prolatio == 2)) { return; } + else if (minima && imperfect) { + return; + } + else if (semiminima && imperfect) { + return; + } + else if (fusa && imperfect) { + return; + } + else if (semifusa) { + // not allowed to be perfected + return; + } // Mark note/rest as perfect/imperfect: if (token->find("i") != std::string::npos) { note->SetDurQuality(DURQUALITY_mensural_imperfecta); - // imperfect time adjustment: - note->SetNum(3); - note->SetNumbase(2); } if (token->find("p") != std::string::npos) { note->SetDurQuality(DURQUALITY_mensural_perfecta); - // perfect time adjustment: - note->SetNum(2); - note->SetNumbase(3); } } From ae5513696f4f52d22bf33b9f1cf75052d8c1b19f Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Wed, 27 Sep 2023 01:09:52 -0700 Subject: [PATCH 012/108] Implementation for issug https://github.com/humdrum-tools/verovio-humdrum-viewer/issues/847 --- src/iohumdrum.cpp | 48 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index fe75b683bcd..05549938fef 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -23669,6 +23669,8 @@ void HumdrumInput::convertNote(Note *note, hum::HTp token, int staffadj, int sta std::string edittype; + bool doubleQ = false; // Used for mensural editorial+visual accidentals. + if (token->isKern()) { if (!m_signifiers.editaccKern.empty()) { for (int x = 0; x < (int)m_signifiers.editaccKern.size(); ++x) { @@ -23681,11 +23683,18 @@ void HumdrumInput::convertNote(Note *note, hum::HTp token, int staffadj, int sta } } else if (token->isMens()) { + string doubleSignifier; if (!m_signifiers.editaccMens.empty()) { for (int x = 0; x < (int)m_signifiers.editaccMens.size(); ++x) { + doubleSignifier = m_signifiers.editaccMens[x]; + doubleSignifier += m_signifiers.editaccMens[x]; if (tstring.find(m_signifiers.editaccMens[x]) != std::string::npos) { editorialQ = true; edittype = m_signifiers.edittypeMens[x]; + if (tstring.find(doubleSignifier) != std::string::npos) { + // Show accidental as regular and editorial. + doubleQ = true; + } break; } } @@ -23910,33 +23919,42 @@ void HumdrumInput::convertNote(Note *note, hum::HTp token, int staffadj, int sta break; } } - else { + + if ((!editorialQ) || doubleQ) { + + Accid *myaccid = accid; + if (doubleQ) { + myaccid = new Accid; + appendElement(note, myaccid); + } switch (accidCount) { - case +3: accid->SetAccid(ACCIDENTAL_WRITTEN_xs); break; - case +2: accid->SetAccid(ACCIDENTAL_WRITTEN_x); break; - case +1: accid->SetAccid(ACCIDENTAL_WRITTEN_s); break; + case +3: myaccid->SetAccid(ACCIDENTAL_WRITTEN_xs); break; + case +2: myaccid->SetAccid(ACCIDENTAL_WRITTEN_x); break; + case +1: myaccid->SetAccid(ACCIDENTAL_WRITTEN_s); break; case 0: // mensural music does not have a natural sign // and accidentals are relative switch (diatonic % 7) { - case 0: accid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // C# -> Cn - case 1: accid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // D# -> Dn - case 2: accid->SetAccid(ACCIDENTAL_WRITTEN_s); break; // E- -> En - case 3: accid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // F# -> Fn - case 4: accid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // G# -> Gn - case 5: accid->SetAccid(ACCIDENTAL_WRITTEN_s); break; // A- -> An - case 6: accid->SetAccid(ACCIDENTAL_WRITTEN_s); break; // B- -> Bn + case 0: myaccid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // C# -> Cn + case 1: myaccid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // D# -> Dn + case 2: myaccid->SetAccid(ACCIDENTAL_WRITTEN_s); break; // E- -> En + case 3: myaccid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // F# -> Fn + case 4: myaccid->SetAccid(ACCIDENTAL_WRITTEN_f); break; // G# -> Gn + case 5: myaccid->SetAccid(ACCIDENTAL_WRITTEN_s); break; // A- -> An + case 6: myaccid->SetAccid(ACCIDENTAL_WRITTEN_s); break; // B- -> Bn } + myaccid->SetAccidGes(ACCIDENTAL_GESTURAL_n); break; - case -1: accid->SetAccid(ACCIDENTAL_WRITTEN_f); break; - case -2: accid->SetAccid(ACCIDENTAL_WRITTEN_ff); break; - case -3: accid->SetAccid(ACCIDENTAL_WRITTEN_tf); break; + break; + case -1: myaccid->SetAccid(ACCIDENTAL_WRITTEN_f); break; + case -2: myaccid->SetAccid(ACCIDENTAL_WRITTEN_ff); break; + case -3: myaccid->SetAccid(ACCIDENTAL_WRITTEN_tf); break; default: std::cerr << "Do not know how to convert accidental: " << accidCount << endl; } if (accidlevel != 0) { - accid->SetFunc(accidLog_FUNC_edit); + myaccid->SetFunc(accidLog_FUNC_edit); } } } From 11296c4f4254080bf9d50c67d4a8003eecbe9c96 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Fri, 29 Sep 2023 07:20:40 -0700 Subject: [PATCH 013/108] Humlib updates. --- include/hum/humlib.h | 48 ++++- src/hum/humlib.cpp | 404 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 434 insertions(+), 18 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index cc4c4383696..0ef86b24a50 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 Sep 24 17:52:16 PDT 2023 +// Last Modified: Wed Sep 27 21:52:41 PDT 2023 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 @@ -5499,6 +5499,35 @@ class HumdrumFileSet { +class Tool_addic : public HumTool { + public: + Tool_addic (void); + ~Tool_addic () {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const string& indata, ostream& out); + bool run (HumdrumFile& infile, ostream& out); + + int getInstrumentCodeIndex(HumdrumFile& infile); + int getInstrumentClassIndex(HumdrumFile& infile); + void updateInstrumentClassLine(HumdrumFile& infile, int codeIndex, int classIndex); + std::string makeClassLine(HumdrumFile& infile, int codeIndex); + std::string getInstrumentClass(const string& code); + + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + + private: + std::vector> m_instrumentList; + bool m_fixQ = false; // used with -f option: fix incorrect instrument classes + + +}; + + class Tool_autoaccid : public HumTool { public: Tool_autoaccid (void); @@ -7918,13 +7947,20 @@ class Tool_kern2mens : public HumTool { std::string convertKernTokenToMens(HTp token); void printBarline (HumdrumFile& infile, int line); std::string getClefConversion (HTp token); + void storeKernEditorialAccidental(HumdrumFile& infile); + void addVerovioStyling (HumdrumFile& infile); private: - bool m_numbersQ = true; // used with -N option - bool m_measuresQ = true; // used with -M option - bool m_invisibleQ = true; // used with -I option - bool m_doublebarQ = true; // used with -D option - string m_clef; // used with -c option + bool m_numbersQ = true; // used with -N option + bool m_measuresQ = true; // used with -M option + bool m_invisibleQ = true; // used with -I option + bool m_doublebarQ = true; // used with -D option + bool m_noverovioQ = false; // used with -V option + std::string m_clef; // used with -c option + + std::string m_kernEditorialAccidental; // used with !!!RDF**kern: + int m_kernEdAccLineIndex = -1; + std::string m_mensEdAccLine; }; diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index 6bc49f32329..90613488069 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 Sep 24 17:52:16 PDT 2023 +// Last Modified: Wed Sep 27 21:52:41 PDT 2023 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 @@ -704,6 +704,9 @@ bool Convert::isKernRest(const string& kerndata) { // bool Convert::isKernNote(const string& kerndata) { + if (isKernRest(kerndata)) { + return false; + } char ch; for (int i=0; i < (int)kerndata.size(); i++) { ch = std::tolower(kerndata[i]); @@ -52240,6 +52243,310 @@ ostream& operator<<(ostream& out, PixelColor apixel) { +///////////////////////////////// +// +// Tool_addic::Tool_addic -- Set the recognized options for the tool. +// + +Tool_addic::Tool_addic(void) { + define("f|fix=b", "Fix instrument class values if different from expected for instrument code."); +} + + + +///////////////////////////////// +// +// Tool_addic::run -- Do the main work of the tool. +// + +bool Tool_addic::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; isetText(text); + } + infile[classIndex].createLineFromTokens(); +} + + + +////////////////////////////// +// +// Tool_addic::getInstrumentCodeIndex -- +// + +int Tool_addic::getInstrumentCodeIndex(HumdrumFile& infile) { + HumRegex hre; + for (int i=0; i > commands; getCommandList(commands, infile); for (int i=0; i<(int)commands.size(); i++) { - if (commands[i].first == "autoaccid") { + if (commands[i].first == "addic") { + RUNTOOL(addic, infile, commands[i].second, status); + } else if (commands[i].first == "autoaccid") { RUNTOOL(autoaccid, infile, commands[i].second, status); } else if (commands[i].first == "autobeam") { RUNTOOL(autobeam, infile, commands[i].second, status); @@ -86215,9 +86523,10 @@ int Tool_imitation::compareSequences(vector& attack1, Tool_kern2mens::Tool_kern2mens(void) { define("N|no-measure-numbers=b", "remove measure numbers"); define("M|no-measures=b", "remove measures "); - define("I|not-invisible=b", "keep measures visible"); - define("D|no-double-bar=b", "keep thick final barlines"); - define("c|clef=s", "clef to use in mensural notation"); + define("I|not-invisible=b", "keep measures visible"); + define("D|no-double-bar=b", "keep thick final barlines"); + define("c|clef=s", "clef to use in mensural notation"); + define("V|no-verovio=b", "don't add verovio styling"); } @@ -86263,7 +86572,9 @@ bool Tool_kern2mens::run(HumdrumFile& infile) { m_measuresQ = !getBoolean("no-measures"); m_invisibleQ = !getBoolean("not-invisible"); m_doublebarQ = !getBoolean("no-double-bar"); - m_clef = getString("clef"); + m_noverovioQ = getBoolean("no-verovio"); + m_clef = getString("clef"); + storeKernEditorialAccidental(infile); convertToMens(infile); return true; } @@ -86283,7 +86594,11 @@ void Tool_kern2mens::convertToMens(HumdrumFile& infile) { continue; } if (!infile[i].hasSpines()) { - m_humdrum_text << infile[i] << "\n"; + if (i == m_kernEdAccLineIndex) { + m_humdrum_text << m_mensEdAccLine; + } else { + m_humdrum_text << infile[i] << "\n"; + } continue; } if ((maxtrack == 1) && infile[i].isAllNull()) { @@ -86298,6 +86613,29 @@ void Tool_kern2mens::convertToMens(HumdrumFile& infile) { } m_humdrum_text << "\n"; } + if (!m_noverovioQ) { + addVerovioStyling(infile); + } +} + + + +////////////////////////////// +// +// Tool_kern2mens::addVerovioStyling -- +// + +void Tool_kern2mens::addVerovioStyling(HumdrumFile& infile) { + HumRegex hre; + for (int i=0; ifind(m_kernEditorialAccidental) != string::npos) { + hre.replaceDestructive(data, "$1z", "([#-n]+)", "g"); + } + } return data; } @@ -86521,6 +86866,41 @@ string Tool_kern2mens::getClefConversion(HTp token) { +////////////////////////////// +// +// Tool_kern2mens::storeKernEditorialAccidental -- +// + +void Tool_kern2mens::storeKernEditorialAccidental(HumdrumFile& infile) { + for (int i=infile.getLineCount() - 1; i>= 0; i--) { + if (infile[i].hasSpines()) { + continue; + } + if (!infile[i].isReferenceRecord()) { + continue; + } + string key = infile[i].getReferenceKey(); + if (key != "RDF**kern") { + continue; + } + HumRegex hre; + string value = infile[i].getReferenceValue(); + if (hre.search(value, "^\\s*([^\\s]+)\\s*=\\s*(.*)\\s*$")) { + string signifier = hre.getMatch(1); + string definition = hre.getMatch(2); + if (hre.search(definition, "editorial\\s+accidental")) { + m_kernEditorialAccidental = signifier; + m_kernEdAccLineIndex = i; + m_mensEdAccLine = "!!!RDF**mens: z = "; + m_mensEdAccLine += definition; + break; + } + } + } +} + + + ///////////////////////////////// // From 2d0a1665ac8c2b8c9ed2dc02fff2b018741cd9a0 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Tue, 12 Sep 2023 13:43:35 +0200 Subject: [PATCH 014/108] Store list of scores in Doc --- include/vrv/doc.h | 21 ++++++++++++++++----- src/doc.cpp | 27 +++++++++++++++------------ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/include/vrv/doc.h b/include/vrv/doc.h index d1cfdc7a7af..099a5e90702 100644 --- a/include/vrv/doc.h +++ b/include/vrv/doc.h @@ -121,11 +121,6 @@ class Doc : public Object { */ bool HasPage(int pageIdx) const; - /** - * Get all the Score in the visible Mdiv. - */ - std::list GetScores(); - /** * Get the Pages in the visible Mdiv. * Will find it only when having read a pages-based MEI file, @@ -141,6 +136,11 @@ class Doc : public Object { */ int GetPageCount() const; + /** + * Get all scores + */ + std::list GetScores() { return m_scores; } + /** * Return true if the MIDI generation is already done */ @@ -477,6 +477,11 @@ class Doc : public Object { */ void PrepareMeasureIndices(); + /** + * Determine all scores + */ + void CollectScores(); + public: Page *m_selectionPreceding; Page *m_selectionFollowing; @@ -545,6 +550,12 @@ class Doc : public Object { */ Resources m_resources; + /** + * The list of all scores + * Used in Doc::GetScoreDefFor to quickly determine the corresponding score for an object + */ + std::list m_scores; + /** * @name Holds a pointer to the current score/scoreDef. * Set by Doc::GetCurrentScoreDef or explicitly through Doc::SetCurrentScoreDef diff --git a/src/doc.cpp b/src/doc.cpp index 3fd5b393d28..7fd1c9e1501 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -574,6 +574,10 @@ void Doc::PrepareData() this->PrepareMeasureIndices(); + /************ Collect all scores ************/ + + this->CollectScores(); + /************ Store default durations ************/ PrepareDurationFunctor prepareDuration; @@ -1446,18 +1450,6 @@ bool Doc::HasPage(int pageIdx) const return ((pageIdx >= 0) && (pageIdx < pages->GetChildCount())); } -std::list Doc::GetScores() -{ - std::list scores; - ListOfObjects objects = this->FindAllDescendantsByType(SCORE, false, 3); - for (const auto object : objects) { - Score *score = vrv_cast(object); - assert(score); - scores.push_back(score); - } - return scores; -} - Pages *Doc::GetPages() { return vrv_cast(this->FindDescendantByType(PAGES)); @@ -1474,6 +1466,17 @@ int Doc::GetPageCount() const return ((pages) ? pages->GetChildCount() : 0); } +void Doc::CollectScores() +{ + m_scores.clear(); + ListOfObjects objects = this->FindAllDescendantsByType(SCORE, false, 3); + for (Object *object : objects) { + Score *score = vrv_cast(object); + assert(score); + m_scores.push_back(score); + } +} + int Doc::GetGlyphHeight(char32_t code, int staffSize, bool graceSize) const { int x, y, w, h; From d1ae0b5c623c7f9162c069a79140cf536acc883e Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 14 Sep 2023 17:08:37 +0200 Subject: [PATCH 015/108] Replace current scoreDef in import/export --- include/vrv/doc.h | 8 ++++++++ include/vrv/iomei.h | 2 +- src/doc.cpp | 14 ++++++++++++++ src/ioabc.cpp | 2 +- src/iodarms.cpp | 2 +- src/iohumdrum.cpp | 34 +++++++++++++++++----------------- src/iomei.cpp | 19 ++++++++++--------- src/iomusxml.cpp | 10 +++++----- src/iopae.cpp | 18 +++++++++--------- 9 files changed, 66 insertions(+), 43 deletions(-) diff --git a/include/vrv/doc.h b/include/vrv/doc.h index 099a5e90702..a41b88558da 100644 --- a/include/vrv/doc.h +++ b/include/vrv/doc.h @@ -141,6 +141,14 @@ class Doc : public Object { */ std::list GetScores() { return m_scores; } + /** + * Get the first scoreDef + */ + ///@{ + ScoreDef *GetFirstScoreDef(); + const ScoreDef *GetFirstScoreDef() const; + ///@} + /** * Return true if the MIDI generation is already done */ diff --git a/include/vrv/iomei.h b/include/vrv/iomei.h index e162f386646..6b0d7800119 100644 --- a/include/vrv/iomei.h +++ b/include/vrv/iomei.h @@ -306,7 +306,7 @@ class MEIOutput : public Output { * Scoredef manipulation */ ///@{ - void WriteCustomScoreDef(); + void WriteCustomScoreDef(ScoreDef *scoreDef); void AdjustStaffDef(StaffDef *staffDef, Measure *measure); bool AdjustLabel(Label *label); ///@} diff --git a/src/doc.cpp b/src/doc.cpp index 7fd1c9e1501..7be35f4dac1 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -1466,6 +1466,20 @@ int Doc::GetPageCount() const return ((pages) ? pages->GetChildCount() : 0); } +ScoreDef *Doc::GetFirstScoreDef() +{ + return const_cast(std::as_const(*this).GetFirstScoreDef()); +} + +const ScoreDef *Doc::GetFirstScoreDef() const +{ + // Use precalculated list of scores, if possible + const Score *score + = m_scores.empty() ? vrv_cast(this->FindDescendantByType(SCORE, 3)) : m_scores.front(); + + return score ? score->GetScoreDef() : NULL; +} + void Doc::CollectScores() { m_scores.clear(); diff --git a/src/ioabc.cpp b/src/ioabc.cpp index 5ce7bdae43d..a7473bdae60 100644 --- a/src/ioabc.cpp +++ b/src/ioabc.cpp @@ -224,7 +224,7 @@ int ABCInput::SetBarLine(const std::string &musicCode, int i) void ABCInput::CalcUnitNoteLength() { - MeterSig *meterSig = vrv_cast(m_doc->GetCurrentScoreDef()->FindDescendantByType(METERSIG)); + MeterSig *meterSig = vrv_cast(m_doc->GetFirstScoreDef()->FindDescendantByType(METERSIG)); if (!meterSig || !meterSig->HasUnit() || double(meterSig->GetTotalCount()) / double(meterSig->GetUnit()) >= 0.75) { m_unitDur = 8; m_durDefault = DURATION_8; diff --git a/src/iodarms.cpp b/src/iodarms.cpp index 36082e95284..debf3f3181a 100644 --- a/src/iodarms.cpp +++ b/src/iodarms.cpp @@ -521,7 +521,7 @@ bool DarmsInput::Import(const std::string &data_str) StaffDef *staffDef = new StaffDef(); staffDef->SetN(1); staffGrp->AddChild(staffDef); - m_doc->GetCurrentScoreDef()->AddChild(staffGrp); + m_doc->GetFirstScoreDef()->AddChild(staffGrp); m_doc->ConvertToPageBasedDoc(); diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index 05549938fef..f078aada028 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -3428,7 +3428,7 @@ void HumdrumInput::prepareStaffGroups(int top, int bot) const std::vector &staffstarts = m_staffstarts; if (staffstarts.size() > 0) { - addMidiTempo(m_doc->GetCurrentScoreDef(), staffstarts[0], top, bot); + addMidiTempo(m_doc->GetFirstScoreDef(), staffstarts[0], top, bot); } hum::HumRegex hre; for (int i = 0; i < (int)staffstarts.size(); ++i) { @@ -3462,7 +3462,7 @@ void HumdrumInput::prepareStaffGroups(int top, int bot) // If there is one staff, then no extra decoration. else if (staffstarts.size() == 1) { StaffGrp *sg = new StaffGrp(); - m_doc->GetCurrentScoreDef()->AddChild(sg); + m_doc->GetFirstScoreDef()->AddChild(sg); sg->AddChild(m_staffdef[0]); } // do something if there is no staff in the score? @@ -3471,7 +3471,7 @@ void HumdrumInput::prepareStaffGroups(int top, int bot) bool status = processStaffDecoration(decoration); if (!status) { StaffGrp *sg = new StaffGrp(); - m_doc->GetCurrentScoreDef()->AddChild(sg); + m_doc->GetFirstScoreDef()->AddChild(sg); sg->SetBarThru(BOOLEAN_false); // setGroupSymbol(sg, staffGroupingSym_SYMBOL_bracket); for (int i = 0; i < (int)m_staffdef.size(); ++i) { @@ -3498,7 +3498,7 @@ void HumdrumInput::prepareStaffGroups(int top, int bot) void HumdrumInput::promoteInstrumentNamesToGroup() { - ScoreDef *sdf = m_doc->GetCurrentScoreDef(); + ScoreDef *sdf = m_doc->GetFirstScoreDef(); int count = sdf->GetChildCount(); for (int i = 0; i < count; ++i) { Object *obj = sdf->GetChild(i); @@ -3572,7 +3572,7 @@ void HumdrumInput::promoteInstrumentsForStaffGroup(StaffGrp *group) void HumdrumInput::promoteInstrumentAbbreviationsToGroup() { - ScoreDef *sdf = m_doc->GetCurrentScoreDef(); + ScoreDef *sdf = m_doc->GetFirstScoreDef(); int count = sdf->GetChildCount(); for (int i = 0; i < count; ++i) { @@ -4024,14 +4024,14 @@ bool HumdrumInput::processStaffDecoration(const std::string &decoration) // There is no barline across the staves in this case. root = new StaffGrp(); root->SetBarThru(BOOLEAN_false); - m_doc->GetCurrentScoreDef()->AddChild(root); + m_doc->GetFirstScoreDef()->AddChild(root); } else if (d[0] == '(') { // The outer group is not bracketed, but bar goes all of // the way through system. root = new StaffGrp(); root->SetBarThru(BOOLEAN_true); - m_doc->GetCurrentScoreDef()->AddChild(root); + m_doc->GetFirstScoreDef()->AddChild(root); } else if (pairing.back() == 0) { skipfirst = true; @@ -4047,7 +4047,7 @@ bool HumdrumInput::processStaffDecoration(const std::string &decoration) else if (d[0] == '[') { setGroupSymbol(root, staffGroupingSym_SYMBOL_bracket); } - m_doc->GetCurrentScoreDef()->AddChild(root); + m_doc->GetFirstScoreDef()->AddChild(root); } std::vector spine; // kernstart index @@ -4288,7 +4288,7 @@ bool HumdrumInput::processStaffDecoration(const std::string &decoration) root->AddChild(sg); } else { - m_doc->GetCurrentScoreDef()->AddChild(sg); + m_doc->GetFirstScoreDef()->AddChild(sg); } for (int i = 0; i < (int)m_staffdef.size(); ++i) { sg->AddChild(m_staffdef[i]); @@ -4311,7 +4311,7 @@ bool HumdrumInput::processStaffDecoration(const std::string &decoration) root->AddChild(sg); } else { - m_doc->GetCurrentScoreDef()->AddChild(sg); + m_doc->GetFirstScoreDef()->AddChild(sg); } } @@ -4388,7 +4388,7 @@ bool HumdrumInput::processStaffDecoration(const std::string &decoration) } else { root_sg = new StaffGrp(); - m_doc->GetCurrentScoreDef()->AddChild(root_sg); + m_doc->GetFirstScoreDef()->AddChild(root_sg); root_sg->SetBarThru(BOOLEAN_false); } for (int i = 0; i < (int)newgroups.size(); ++i) { @@ -4874,7 +4874,7 @@ bool HumdrumInput::prepareFooter( // std::cout << "MEI CONTENT " << meicontent << std::endl; AttFormeworkComparison comparison(PGFOOT, PGFUNC_first); - Object *pgfoot = tempdoc.GetCurrentScoreDef()->FindDescendantByComparison(&comparison); + Object *pgfoot = tempdoc.GetFirstScoreDef()->FindDescendantByComparison(&comparison); if (pgfoot == NULL) { return false; } @@ -4892,10 +4892,10 @@ bool HumdrumInput::prepareFooter( return false; } - m_doc->GetCurrentScoreDef()->AddChild(pgfoot); + m_doc->GetFirstScoreDef()->AddChild(pgfoot); AttFormeworkComparison comparison2(PGFOOT, PGFUNC_all); - Object *pgfoot2 = tempdoc.GetCurrentScoreDef()->FindDescendantByComparison(&comparison2); + Object *pgfoot2 = tempdoc.GetFirstScoreDef()->FindDescendantByComparison(&comparison2); if (pgfoot2 == NULL) { return true; } @@ -4913,7 +4913,7 @@ bool HumdrumInput::prepareFooter( return true; } - m_doc->GetCurrentScoreDef()->AddChild(pgfoot2); + m_doc->GetFirstScoreDef()->AddChild(pgfoot2); return true; } @@ -5049,7 +5049,7 @@ bool HumdrumInput::prepareHeader( // std::string meicontent = meioutput.GetOutput(); // std::cout << "MEI CONTENT " << meicontent << std::endl; - Object *pghead = tempdoc.GetCurrentScoreDef()->FindDescendantByType(ClassId::PGHEAD); + Object *pghead = tempdoc.GetFirstScoreDef()->FindDescendantByType(ClassId::PGHEAD); if (pghead == NULL) { return false; } @@ -5067,7 +5067,7 @@ bool HumdrumInput::prepareHeader( return false; } - m_doc->GetCurrentScoreDef()->AddChild(pghead); + m_doc->GetFirstScoreDef()->AddChild(pghead); return true; } diff --git a/src/iomei.cpp b/src/iomei.cpp index 9f3e2b6c52f..e11544cc1c2 100644 --- a/src/iomei.cpp +++ b/src/iomei.cpp @@ -914,12 +914,13 @@ bool MEIOutput::WriteObjectInternal(Object *object, bool useCustomScoreDef) if (this->IsTreeObject(object)) m_nodeStack.push_back(m_currentNode); if (object->Is(SCORE)) { + ScoreDef *scoreDef = vrv_cast(object)->GetScoreDef(); if (useCustomScoreDef) { - this->WriteCustomScoreDef(); + this->WriteCustomScoreDef(scoreDef); } else { // Save the main scoreDef - m_doc->GetCurrentScoreDef()->SaveObject(this, this->GetBasic()); + scoreDef->SaveObject(this, this->GetBasic()); } } @@ -1278,7 +1279,7 @@ void MEIOutput::WriteStackedObjectsEnd() [this](Object *object) { this->WriteObjectInternalEnd(object); }); } -void MEIOutput::WriteCustomScoreDef() +void MEIOutput::WriteCustomScoreDef(ScoreDef *scoreDef) { // Determine the first measure with respect to the first filter match Measure *measure = NULL; @@ -1305,8 +1306,8 @@ void MEIOutput::WriteCustomScoreDef() if (measure && refScoreDef) { // Create a copy of the reference scoredef and adjust it to keep track of clef changes, key signature changes, // etc. - ScoreDef *scoreDef = vrv_cast(refScoreDef->Clone()); - ListOfObjects staffDefs = scoreDef->FindAllDescendantsByType(STAFFDEF); + ScoreDef *customScoreDef = vrv_cast(refScoreDef->Clone()); + ListOfObjects staffDefs = customScoreDef->FindAllDescendantsByType(STAFFDEF); for (Object *staffDef : staffDefs) { this->AdjustStaffDef(vrv_cast(staffDef), measure); } @@ -1319,7 +1320,7 @@ void MEIOutput::WriteCustomScoreDef() } if (!drawLabels) { // If not, replace labels by abbreviation or delete them - ListOfObjects labels = scoreDef->FindAllDescendantsByType(LABEL); + ListOfObjects labels = customScoreDef->FindAllDescendantsByType(LABEL); for (Object *label : labels) { if (!this->AdjustLabel(vrv_cast