From d54a565f8c2c57c6dd1c321b07172656004070e8 Mon Sep 17 00:00:00 2001 From: Craig Stuart Sapp Date: Tue, 10 Dec 2024 20:19:11 +0900 Subject: [PATCH 01/16] Humlib updates. --- include/hum/humlib.h | 53 ++--- src/hum/humlib.cpp | 527 ++++++++++++++++++++++--------------------- 2 files changed, 296 insertions(+), 284 deletions(-) diff --git a/include/hum/humlib.h b/include/hum/humlib.h index db788fbafa..77490888c8 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: Wed Nov 13 13:08:51 PST 2024 +// Last Modified: Tue Dec 10 14:37:55 JST 2024 // Filename: min/humlib.h // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.h // Syntax: C++11 @@ -5957,31 +5957,6 @@ class Tool_autostem : public HumTool { }; -class Tool_bardash : public HumTool { - - public: - Tool_bardash (void); - ~Tool_bardash() {}; - - bool run (HumdrumFileSet& infiles); - bool run (HumdrumFile& infile); - bool run (const std::string& indata, std::ostream& out); - bool run (HumdrumFile& infile, std::ostream& out); - - protected: - void initialize (void); - void processFile (HumdrumFile& infile); - void removeBarStylings(HumdrumFile& infile); - void removeBarStylings(HTp spine); - void applyBarStylings(HumdrumFile& infile); - void applyBarStylings(HTp spine); - - private: - bool m_removeQ = false; // used with -r option - -}; - - class Tool_binroll : public HumTool { public: Tool_binroll (void); @@ -6005,6 +5980,31 @@ class Tool_binroll : public HumTool { }; +class Tool_bstyle : public HumTool { + + public: + Tool_bstyle (void); + ~Tool_bstyle() {}; + + bool run (HumdrumFileSet& infiles); + bool run (HumdrumFile& infile); + bool run (const std::string& indata, std::ostream& out); + bool run (HumdrumFile& infile, std::ostream& out); + + protected: + void initialize (void); + void processFile (HumdrumFile& infile); + void removeBarStylings(HumdrumFile& infile); + void removeBarStylings(HTp spine); + void applyBarStylings(HumdrumFile& infile); + void applyBarStylings(HTp spine); + + private: + bool m_removeQ = false; // used with -r option + +}; + + class Tool_chantize : public HumTool { public: Tool_chantize (void); @@ -10856,6 +10856,7 @@ class Tool_shed : public HumTool { protected: void processFile (HumdrumFile& infile); + void processExpression (HumdrumFile& infile); void searchAndReplaceInterpretation (HumdrumFile& infile); void searchAndReplaceExinterp (HumdrumFile& infile); void searchAndReplaceData (HumdrumFile& infile); diff --git a/src/hum/humlib.cpp b/src/hum/humlib.cpp index b513566285..1c914a2120 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: Wed Nov 13 13:08:51 PST 2024 +// Last Modified: Tue Dec 10 14:37:55 JST 2024 // Filename: min/humlib.cpp // URL: https://github.com/craigsapp/humlib/blob/master/min/humlib.cpp // Syntax: C++11 @@ -58774,10 +58774,229 @@ void Tool_autostem::countBeamStuff(const string& token, int& start, int& stop, ///////////////////////////////// // -// Tool_bardash::Tool_bardash -- Set the recognized options for the tool. +// Tool_binroll::Tool_binroll -- Set the recognized options for the tool. +// + +Tool_binroll::Tool_binroll(void) { + // add options here + define("t|timebase=s:16", "timebase to do analysis at"); +} + + + +///////////////////////////////// +// +// Tool_binroll::run -- Do the main work of the tool. +// + +bool Tool_binroll::run(HumdrumFileSet& infiles) { + bool status = true; + for (int i=0; i> output; + output.resize(128); + int count = (infile.getScoreDuration() / m_duration).getInteger() + 1; + for (int i=0; i<(int)output.size(); i++) { + output[i].resize(count); + std::fill(output[i].begin(), output[i].end(), 0); + } + + int strandcount = infile.getStrandCount(); + for (int i=0; iisKern()) { + continue; + } + HTp ending = infile.getStrandEnd(i); + processStrand(output, starting, ending); + } + + printAnalysis(infile, output); + +} + + + +////////////////////////////// +// +// Tool_binroll::printAnalysis -- +// + +void Tool_binroll::printAnalysis(HumdrumFile& infile, + vector>& roll) { + HumRegex hre; + + for (int i=0; i=0; i--) { + if (infile[i].isManipulator()) { + startindex = i+1; + break; + } + startindex = i; + } + + for (int i=startindex; i>& roll, HTp starting, + HTp ending) { + HTp current = starting; + int base12; + HumNum starttime; + HumNum duration; + int startindex; + int endindex; + while (current && (current != ending)) { + if (!current->isNonNullData()) { + current = current->getNextToken(); + continue; + } + if (current->isRest()) { + current = current->getNextToken(); + continue; + } + + if (current->isChord()) { + int stcount = current->getSubtokenCount(); + starttime = current->getDurationFromStart(); + startindex = (starttime / m_duration).getInteger(); + for (int s=0; sgetSubtoken(s); + base12 = Convert::kernToMidiNoteNumber(tok); + if ((base12 < 0) || (base12 > 127)) { + continue; + } + duration = Convert::recipToDuration(tok); + endindex = ((starttime+duration) / m_duration).getInteger(); + roll[base12][startindex] = 2; + for (int i=startindex+1; i 127)) { + current = current->getNextToken(); + continue; + } + starttime = current->getDurationFromStart(); + duration = current->getDuration(); + startindex = (starttime / m_duration).getInteger(); + endindex = ((starttime+duration) / m_duration).getInteger(); + roll[base12][startindex] = 2; + for (int i=startindex+1; igetNextToken(); + } +} + + + + + + +///////////////////////////////// +// +// Tool_bstyle::Tool_bstyle -- Set the recognized options for the tool. +// + +Tool_bstyle::Tool_bstyle(void) { define("r|remove=b", "remove any dot/dash/invisible barline stylings"); } @@ -58785,10 +59004,10 @@ Tool_bardash::Tool_bardash(void) { /////////////////////////////// // -// Tool_bardash::run -- Primary interfaces to the tool. +// Tool_bstyle::run -- Primary interfaces to the tool. // -bool Tool_bardash::run(HumdrumFileSet& infiles) { +bool Tool_bstyle::run(HumdrumFileSet& infiles) { bool status = true; for (int i=0; i kstarts = infile.getKernSpineStartList(); for (int i=0; i<(int)kstarts.size(); i++) { removeBarStylings(kstarts.at(i)); @@ -58862,10 +59081,10 @@ void Tool_bardash::removeBarStylings(HumdrumFile& infile) { ////////////////////////////// // -// Tool_bardash::removeBarStylings -- +// Tool_bstyle::removeBarStylings -- // -void Tool_bardash::removeBarStylings(HTp spine) { +void Tool_bstyle::removeBarStylings(HTp spine) { HTp current = spine->getNextToken(); bool activeQ = false; @@ -58875,7 +59094,7 @@ void Tool_bardash::removeBarStylings(HTp spine) { HumRegex hre; while (current) { if (current->isInterpretation()) { - if (hre.search(current, "^\\*bar:")) { + if (hre.search(current, "^\\*bstyle:")) { if (hre.search(current, "stop")) { activeQ = false; dashQ = false; @@ -58883,15 +59102,15 @@ void Tool_bardash::removeBarStylings(HTp spine) { invisQ = false; } else { activeQ = true; - if (hre.search(current, "^\\*bar:.*dash=(\\d+)")) { + if (hre.search(current, "^\\*bstyle:.*dash=(\\d+)")) { dashQ = true; dotQ = false; invisQ = false; - } else if (hre.search(current, "^\\*bar:.*dot=(\\d+)")) { + } else if (hre.search(current, "^\\*bstyle:.*dot=(\\d+)")) { dashQ = false; dotQ = true; invisQ = false; - } else if (hre.search(current, "^\\*bar:.*invis=(\\d+)")) { + } else if (hre.search(current, "^\\*bstyle:.*invis=(\\d+)")) { dashQ = false; dotQ = false; invisQ = true; @@ -58936,10 +59155,10 @@ void Tool_bardash::removeBarStylings(HTp spine) { ////////////////////////////// // -// Tool_bardash::applyBarStylings -- +// Tool_bstyle::applyBarStylings -- // -void Tool_bardash::applyBarStylings(HumdrumFile& infile) { +void Tool_bstyle::applyBarStylings(HumdrumFile& infile) { vector kstarts = infile.getKernSpineStartList(); for (int i=0; i<(int)kstarts.size(); i++) { applyBarStylings(kstarts.at(i)); @@ -58950,10 +59169,10 @@ void Tool_bardash::applyBarStylings(HumdrumFile& infile) { ////////////////////////////// // -// Tool_bardash::applyBarStylings -- +// Tool_bstyle::applyBarStylings -- // -void Tool_bardash::applyBarStylings(HTp spine) { +void Tool_bstyle::applyBarStylings(HTp spine) { HTp current = spine->getNextToken(); bool activeQ = false; @@ -58967,7 +59186,7 @@ void Tool_bardash::applyBarStylings(HTp spine) { HumRegex hre; while (current) { if (current->isInterpretation()) { - if (hre.search(current, "^\\*bar:")) { + if (hre.search(current, "^\\*bstyle:")) { if (hre.search(current, "stop")) { activeQ = false; dashQ = false; @@ -58978,19 +59197,19 @@ void Tool_bardash::applyBarStylings(HTp spine) { invis = 0; } else { activeQ = true; - if (hre.search(current, "^\\*bar:.*dash=(\\d+)")) { + if (hre.search(current, "^\\*bstyle:.*dash=(\\d+)")) { dashQ = true; dotQ = false; invisQ = false; dash = hre.getMatchInt(1); counter = 0; - } else if (hre.search(current, "^\\*bar:.*dot=(\\d+)")) { + } else if (hre.search(current, "^\\*bstyle:.*dot=(\\d+)")) { dashQ = false; dotQ = true; invisQ = false; dot = hre.getMatchInt(1); counter = 0; - } else if (hre.search(current, "^\\*bar:.*invis=(\\d+)")) { + } else if (hre.search(current, "^\\*bstyle:.*invis=(\\d+)")) { dashQ = false; dotQ = false; invisQ = true; @@ -59071,225 +59290,6 @@ void Tool_bardash::applyBarStylings(HTp spine) { -///////////////////////////////// -// -// Tool_binroll::Tool_binroll -- Set the recognized options for the tool. -// - -Tool_binroll::Tool_binroll(void) { - // add options here - define("t|timebase=s:16", "timebase to do analysis at"); -} - - - -///////////////////////////////// -// -// Tool_binroll::run -- Do the main work of the tool. -// - -bool Tool_binroll::run(HumdrumFileSet& infiles) { - bool status = true; - for (int i=0; i> output; - output.resize(128); - int count = (infile.getScoreDuration() / m_duration).getInteger() + 1; - for (int i=0; i<(int)output.size(); i++) { - output[i].resize(count); - std::fill(output[i].begin(), output[i].end(), 0); - } - - int strandcount = infile.getStrandCount(); - for (int i=0; iisKern()) { - continue; - } - HTp ending = infile.getStrandEnd(i); - processStrand(output, starting, ending); - } - - printAnalysis(infile, output); - -} - - - -////////////////////////////// -// -// Tool_binroll::printAnalysis -- -// - -void Tool_binroll::printAnalysis(HumdrumFile& infile, - vector>& roll) { - HumRegex hre; - - for (int i=0; i=0; i--) { - if (infile[i].isManipulator()) { - startindex = i+1; - break; - } - startindex = i; - } - - for (int i=startindex; i>& roll, HTp starting, - HTp ending) { - HTp current = starting; - int base12; - HumNum starttime; - HumNum duration; - int startindex; - int endindex; - while (current && (current != ending)) { - if (!current->isNonNullData()) { - current = current->getNextToken(); - continue; - } - if (current->isRest()) { - current = current->getNextToken(); - continue; - } - - if (current->isChord()) { - int stcount = current->getSubtokenCount(); - starttime = current->getDurationFromStart(); - startindex = (starttime / m_duration).getInteger(); - for (int s=0; sgetSubtoken(s); - base12 = Convert::kernToMidiNoteNumber(tok); - if ((base12 < 0) || (base12 > 127)) { - continue; - } - duration = Convert::recipToDuration(tok); - endindex = ((starttime+duration) / m_duration).getInteger(); - roll[base12][startindex] = 2; - for (int i=startindex+1; i 127)) { - current = current->getNextToken(); - continue; - } - starttime = current->getDurationFromStart(); - duration = current->getDuration(); - startindex = (starttime / m_duration).getInteger(); - endindex = ((starttime+duration) / m_duration).getInteger(); - roll[base12][startindex] = 2; - for (int i=startindex+1; igetNextToken(); - } -} - - - - - - ///////////////////////////////// // // Tool_chantize::Tool_chantize -- Set the recognized options for the tool. @@ -87253,8 +87253,8 @@ bool Tool_filter::run(HumdrumFileSet& infiles) { RUNTOOL(autobeam, infile, commands[i].second, status); } else if (commands[i].first == "autostem") { RUNTOOL(autostem, infile, commands[i].second, status); - } else if (commands[i].first == "bardash") { - RUNTOOL(bardash, infile, commands[i].second, status); + } else if (commands[i].first == "bstyle") { + RUNTOOL(bstyle, infile, commands[i].second, status); } else if (commands[i].first == "binroll") { RUNTOOL(binroll, infile, commands[i].second, status); } else if (commands[i].first == "chantize") { @@ -120419,8 +120419,10 @@ void Tool_prange::assignHorizontalPosition(vector<_VoiceInfo>& voiceInfo, int mi } vector hpos(count, 0); - hpos[0] = maxval; - hpos.back() = minval; + if (count >= 2) { + hpos[0] = maxval; + hpos.back() = minval; + } if (hpos.size() > 2) { for (int i=1; i<(int)hpos.size()-1; i++) { @@ -126363,10 +126365,7 @@ bool Tool_shed::run(HumdrumFile& infile) { cerr << "Error: -e option is required" << endl; return false; } - for (int i=0; i<(int)m_options.size(); i++) { - prepareSearch(i); - processFile(infile); - } + processFile(infile); return true; } @@ -126658,6 +126657,21 @@ vector Tool_shed::addToExInterpList(void) { // void Tool_shed::processFile(HumdrumFile& infile) { + for (int i=0; i<(int)m_options.size(); i++) { + prepareSearch(i); + processExpression(infile); + } + m_humdrum_text << infile; +} + + + +////////////////////////////// +// +// Tool_shed::processExpression -- +// + +void Tool_shed::processExpression(HumdrumFile& infile) { if (m_search == "") { // nothing to do return; @@ -126703,9 +126717,6 @@ void Tool_shed::processFile(HumdrumFile& infile) { if (m_modified) { infile.createLinesFromTokens(); } - - // needed only for command-line version of tool?: - m_humdrum_text << infile; } From 91e95add8f4b35d33fd824da946d38b9c7806a5d Mon Sep 17 00:00:00 2001 From: Yinan Zhou Date: Wed, 27 Nov 2024 20:37:56 -0500 Subject: [PATCH 02/16] fix: change default octave to c4 when adjusting pitch refs: https://github.com/DDMAL/Neon/issues/1246 --- src/editortoolkit_neume.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/editortoolkit_neume.cpp b/src/editortoolkit_neume.cpp index 08e110a978..b29dfd18f8 100644 --- a/src/editortoolkit_neume.cpp +++ b/src/editortoolkit_neume.cpp @@ -4252,11 +4252,10 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) LogError("Clef %s does not have valid shape. Shape is %s", clef->GetID().c_str(), clef->GetShape()); return false; } - pi->SetOct(3); - // The default octave = 3, but the actual octave is calculated by + // The default octave = 4, but the actual octave is calculated by // taking into account the displacement of the clef - int octave = 3; + int octave = 4; if (clef->GetDis() && clef->GetDisPlace()) { octave += (clef->GetDisPlace() == STAFFREL_basic_above ? 1 : -1) * (clef->GetDis() / 7); } @@ -4323,9 +4322,9 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) assert(pi); pi->SetPname(pname); - // The default octave = 3, but the actual octave is calculated by + // The default octave = 4, but the actual octave is calculated by // taking into account the displacement of the clef - int octave = 3; + int octave = 4; if (clef->GetDis() && clef->GetDisPlace()) { octave += (clef->GetDisPlace() == STAFFREL_basic_above ? 1 : -1) * (clef->GetDis() / 7); } From 11ddd346e29417c5f077395b054c8049c39d89cc Mon Sep 17 00:00:00 2001 From: Yinan Zhou Date: Sat, 30 Nov 2024 15:07:16 -0500 Subject: [PATCH 03/16] fix: add clef offset in `AdjustPitchFromPosition` refs: https://github.com/DDMAL/Neon/issues/1248 --- src/editortoolkit_neume.cpp | 46 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/editortoolkit_neume.cpp b/src/editortoolkit_neume.cpp index b29dfd18f8..114348a41b 100644 --- a/src/editortoolkit_neume.cpp +++ b/src/editortoolkit_neume.cpp @@ -4236,22 +4236,23 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) } } - assert(clef); + data_PITCHNAME pname; + const int staffSize = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); + Staff *clefStaff = dynamic_cast(clef->GetFirstAncestor(STAFF)); + assert(clefStaff); + const int clefOffset = round((double)(clefStaff->GetDrawingY() + - clefStaff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(clef->GetZone()->GetUlx())) + - m_view->ToLogicalY(clef->GetZone()->GetUly()))); - // Reset pitch to be "on clef" - if (clef->GetShape() == CLEFSHAPE_C) { - pi->SetPname(PITCHNAME_c); - } - else if (clef->GetShape() == CLEFSHAPE_F) { - pi->SetPname(PITCHNAME_f); - } - else if (clef->GetShape() == CLEFSHAPE_G) { - pi->SetPname(PITCHNAME_g); - } - else { - LogError("Clef %s does not have valid shape. Shape is %s", clef->GetID().c_str(), clef->GetShape()); - return false; + switch (clef->GetShape()) { + case CLEFSHAPE_C: pname = PITCHNAME_c; break; + case CLEFSHAPE_F: pname = PITCHNAME_f; break; + case CLEFSHAPE_G: pname = PITCHNAME_g; break; + default: + LogError("Clef %s does not have valid shape. Shape is %s", clef->GetID().c_str(), clef->GetShape()); + return false; } + pi->SetPname(pname); // The default octave = 4, but the actual octave is calculated by // taking into account the displacement of the clef @@ -4261,12 +4262,10 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) } pi->SetOct(octave); - const int staffSize = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - const int pitchDifference = round((double)((staff->GetDrawingY() - staff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(fi->GetZone()->GetUlx())) - - m_view->ToLogicalY(fi->GetZone()->GetUly()))) + - m_view->ToLogicalY(fi->GetZone()->GetUly()) - clefOffset)) / (double)(staffSize)); pi->AdjustPitchByOffset(-pitchDifference); return true; @@ -4284,7 +4283,6 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) LogWarning("Syllable/neume had no pitched children to reorder for syllable/neume %s", obj->GetID().c_str()); return true; } - if (clef == NULL) { ClassIdComparison ac(CLEF); clef = dynamic_cast(m_doc->GetDrawingPage()->FindPreviousChild(&ac, obj)); @@ -4298,6 +4296,13 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) assert(clef); data_PITCHNAME pname; + const int staffSize = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); + Staff *clefStaff = dynamic_cast(clef->GetFirstAncestor(STAFF)); + assert(clefStaff); + const int clefOffset = round((double)(clefStaff->GetDrawingY() + - clefStaff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(clef->GetZone()->GetUlx())) + - m_view->ToLogicalY(clef->GetZone()->GetUly()))); + switch (clef->GetShape()) { case CLEFSHAPE_C: pname = PITCHNAME_c; break; case CLEFSHAPE_F: pname = PITCHNAME_f; break; @@ -4307,8 +4312,6 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) return false; } - const int staffSize = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - for (auto it = pitchedChildren.begin(); it != pitchedChildren.end(); ++it) { if ((*it)->Is(LIQUESCENT)) continue; @@ -4333,8 +4336,9 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) const int pitchDifference = round((double)((staff->GetDrawingY() - staff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(fi->GetZone()->GetUlx())) - - m_view->ToLogicalY(fi->GetZone()->GetUly()))) + - m_view->ToLogicalY(fi->GetZone()->GetUly()) - clefOffset)) / (double)(staffSize)); + pi->AdjustPitchByOffset(-pitchDifference); } From 766692a74b9817693c7311689080bf9367f00fcf Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 2 Dec 2024 19:08:21 +0100 Subject: [PATCH 04/16] Fix ledger line regression. Fixes #3872 * Test-suite evaluated locally --- src/staff.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/staff.cpp b/src/staff.cpp index eee4fc0a3e..26de629c67 100644 --- a/src/staff.cpp +++ b/src/staff.cpp @@ -318,9 +318,8 @@ void LedgerLine::AddDash(int left, int right, int extension, const Object *event iter = m_dashes.begin(); ++iter; while (iter != m_dashes.end()) { - if (previous->m_x1 > iter->m_x1 + 1.5 * extension) { + if (previous->m_x2 > iter->m_x1 + 1.5 * extension) { previous->MergeWith(*iter); - previous->m_x2 = std::max(iter->m_x2, previous->m_x2); iter = m_dashes.erase(iter); } else { From f726dcf37a169fc1bc66132e4dcde173cd9250f1 Mon Sep 17 00:00:00 2001 From: Yinan Zhou Date: Tue, 3 Dec 2024 15:29:37 -0500 Subject: [PATCH 05/16] fix: handle no-clef in `AdjustPitchFromPosition` - When there is no previous clef found, use the default clef defined in ``, instead of using clef found later on the staff refs: https://github.com/DDMAL/Neon/issues/1248#issuecomment-2510263075 --- src/editortoolkit_neume.cpp | 43 ++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/editortoolkit_neume.cpp b/src/editortoolkit_neume.cpp index 114348a41b..576e4c3549 100644 --- a/src/editortoolkit_neume.cpp +++ b/src/editortoolkit_neume.cpp @@ -4226,24 +4226,31 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) return false; } + int clefOffset = 0; if (clef == NULL) { ClassIdComparison ac(CLEF); clef = dynamic_cast(m_doc->GetDrawingPage()->FindPreviousChild(&ac, obj)); + int clefOffset = 0; if (clef == NULL) { - Layer *layer = vrv_cast(staff->FindDescendantByType(LAYER)); - assert(layer); - clef = layer->GetCurrentClef(); + ClassIdComparison ac(CLEF); + clef = dynamic_cast(m_doc->GetDrawingPage()->FindPreviousChild(&ac, obj)); + if (clef == NULL) { + Layer *layer = vrv_cast(staff->FindDescendantByType(LAYER)); + assert(layer); + clef = layer->GetCurrentClef(); + } + else { + Staff *clefStaff = dynamic_cast(clef->GetFirstAncestor(STAFF)); + assert(clefStaff); + clefOffset = round((double)(clefStaff->GetDrawingY() + - clefStaff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(clef->GetZone()->GetUlx())) + - m_view->ToLogicalY(clef->GetZone()->GetUly()))); + } } } data_PITCHNAME pname; const int staffSize = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - Staff *clefStaff = dynamic_cast(clef->GetFirstAncestor(STAFF)); - assert(clefStaff); - const int clefOffset = round((double)(clefStaff->GetDrawingY() - - clefStaff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(clef->GetZone()->GetUlx())) - - m_view->ToLogicalY(clef->GetZone()->GetUly()))); - switch (clef->GetShape()) { case CLEFSHAPE_C: pname = PITCHNAME_c; break; case CLEFSHAPE_F: pname = PITCHNAME_f; break; @@ -4283,6 +4290,8 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) LogWarning("Syllable/neume had no pitched children to reorder for syllable/neume %s", obj->GetID().c_str()); return true; } + + int clefOffset = 0; if (clef == NULL) { ClassIdComparison ac(CLEF); clef = dynamic_cast(m_doc->GetDrawingPage()->FindPreviousChild(&ac, obj)); @@ -4291,17 +4300,17 @@ bool EditorToolkitNeume::AdjustPitchFromPosition(Object *obj, Clef *clef) assert(layer); clef = layer->GetCurrentClef(); } + else { + Staff *clefStaff = dynamic_cast(clef->GetFirstAncestor(STAFF)); + assert(clefStaff); + clefOffset = round((double)(clefStaff->GetDrawingY() + - clefStaff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(clef->GetZone()->GetUlx())) + - m_view->ToLogicalY(clef->GetZone()->GetUly()))); + } } - assert(clef); - - data_PITCHNAME pname; + data_PITCHNAME pname = PITCHNAME_c; const int staffSize = m_doc->GetDrawingUnit(staff->m_drawingStaffSize); - Staff *clefStaff = dynamic_cast(clef->GetFirstAncestor(STAFF)); - assert(clefStaff); - const int clefOffset = round((double)(clefStaff->GetDrawingY() - - clefStaff->GetDrawingRotationOffsetFor(m_view->ToLogicalX(clef->GetZone()->GetUlx())) - - m_view->ToLogicalY(clef->GetZone()->GetUly()))); switch (clef->GetShape()) { case CLEFSHAPE_C: pname = PITCHNAME_c; break; From 5ffa19dc82cd6913b089a8d6985e4efe58caa678 Mon Sep 17 00:00:00 2001 From: Yinan Zhou Date: Tue, 3 Dec 2024 15:55:15 -0500 Subject: [PATCH 06/16] fix: update octave change in `AdjustPitchForNewClef` refs: https://github.com/DDMAL/Neon/issues/1248#issuecomment-2513344698 --- src/pitchinterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pitchinterface.cpp b/src/pitchinterface.cpp index 893e928d57..e7d08596f5 100644 --- a/src/pitchinterface.cpp +++ b/src/pitchinterface.cpp @@ -109,13 +109,13 @@ void PitchInterface::AdjustPitchForNewClef(const Clef *oldClef, const Clef *newC int pitchDiff = -2 * (newClef->GetLine() - oldClef->GetLine()); if (oldClef->GetShape() == CLEFSHAPE_F) { - pitchDiff -= 3; + pitchDiff += 4; } else if (oldClef->GetShape() == CLEFSHAPE_G) { pitchDiff -= 4; } if (newClef->GetShape() == CLEFSHAPE_F) { - pitchDiff += 3; + pitchDiff -= 4; } else if (newClef->GetShape() == CLEFSHAPE_G) { pitchDiff += 4; From 85f991808b10444d7c8c79b91658edaa46565f5b Mon Sep 17 00:00:00 2001 From: withSang Date: Wed, 4 Dec 2024 20:13:59 +0900 Subject: [PATCH 07/16] Fix c++ flags for Java / Android --- bindings/android/jni/Application.mk | 2 +- bindings/java/build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/android/jni/Application.mk b/bindings/android/jni/Application.mk index 4ed813e6bf..c57e6beb95 100755 --- a/bindings/android/jni/Application.mk +++ b/bindings/android/jni/Application.mk @@ -1,6 +1,6 @@ # only build armeabi-v7a, if required add 'armeabi' or 'x86' APP_ABI := armeabi-v7a -APP_CPPFLAGS += -fexceptions -frtti -std=c++17 +APP_CPPFLAGS += -fexceptions -frtti -std=c++20 APP_OPTIM := release APP_STL := c++_shared APP_MODULES := verovio-android diff --git a/bindings/java/build.sh b/bindings/java/build.sh index 37b6c01435..6b9e72c0f5 100755 --- a/bindings/java/build.sh +++ b/bindings/java/build.sh @@ -24,7 +24,7 @@ FILES="$SRCFILES \ ../../src/json/jsonxx.cc \ ../../src/crc/crc.cpp" -CXXOPTS="-g -fpic -std=c++17 -I../../include -I../../include/vrv -I../../include/json -I../../include/hum -I../../include/crc -I../../include/midi -I../../include/pugi -I../../include/zip -I../../libmei/addons -I../../libmei/dist -I/opt/local/include/ " +CXXOPTS="-g -fpic -std=c++20 -I../../include -I../../include/vrv -I../../include/json -I../../include/hum -I../../include/crc -I../../include/midi -I../../include/pugi -I../../include/zip -I../../libmei/addons -I../../libmei/dist -I/opt/local/include/ " PATHS="" unamestr=$(uname) From 23d6cec3eb6298cec02f3e3eb5d0dc006031a8a8 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 9 Dec 2024 11:31:02 +0100 Subject: [PATCH 08/16] Add const overload to GetTstampStaves --- include/vrv/timeinterface.h | 5 ++++- src/timeinterface.cpp | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/vrv/timeinterface.h b/include/vrv/timeinterface.h index ed723564bf..e569d1a6c0 100644 --- a/include/vrv/timeinterface.h +++ b/include/vrv/timeinterface.h @@ -87,7 +87,10 @@ class TimePointInterface : public Interface, public AttStaffIdent, public AttSta /** * Return a vector of staves looking at the @staff attribute or at the parent staff or the @startid */ - std::vector GetTstampStaves(Measure *measure, Object *object); + ///@{ + std::vector GetTstampStaves(const Measure *measure, const Object *object) const; + std::vector GetTstampStaves(const Measure *measure, const Object *object); + ///@} /** * Return true if the interface owner is encoded in the measure of its start element diff --git a/src/timeinterface.cpp b/src/timeinterface.cpp index 3a8ed6e1ab..6ccc04ac1c 100644 --- a/src/timeinterface.cpp +++ b/src/timeinterface.cpp @@ -108,17 +108,26 @@ bool TimePointInterface::IsOnStaff(int n) const return false; } -std::vector TimePointInterface::GetTstampStaves(Measure *measure, Object *object) +std::vector TimePointInterface::GetTstampStaves(const Measure *measure, const Object *object) +{ + std::vector staves = std::as_const(*this).GetTstampStaves(measure, object); + std::vector stavesCasted; + std::transform(staves.begin(), staves.end(), std::back_inserter(stavesCasted), + [](const Staff *staff) { return const_cast(staff); }); + return stavesCasted; +} + +std::vector TimePointInterface::GetTstampStaves(const Measure *measure, const Object *object) const { assert(measure); assert(object); - std::vector staves; + std::vector staves; std::vector staffList; // For within without @staff we try to get the @staff from the ancestor if (object->Is(FIGURE) && !this->HasStaff()) { - Harm *harm = vrv_cast(object->GetFirstAncestor(HARM)); + const Harm *harm = vrv_cast(object->GetFirstAncestor(HARM)); if (harm) { staffList = harm->GetStaff(); } @@ -127,7 +136,7 @@ std::vector TimePointInterface::GetTstampStaves(Measure *measure, Objec bool isInBetween = false; // limit between support to some elements? if (object->Is({ DYNAM, DIR, HAIRPIN, TEMPO })) { - AttPlacementRelStaff *att = dynamic_cast(object); + const AttPlacementRelStaff *att = dynamic_cast(object); assert(att); isInBetween = (att->GetPlace() == STAFFREL_between); } @@ -141,18 +150,18 @@ std::vector TimePointInterface::GetTstampStaves(Measure *measure, Objec } } else if (m_start && !m_start->Is({ BARLINE, TIMESTAMP_ATTR })) { - Staff *staff = m_start->GetAncestorStaff(); + const Staff *staff = m_start->GetAncestorStaff(); staffList.push_back(staff->GetN()); } else if (measure->GetChildCount(STAFF) == 1) { // If we have no @staff or startid but only one staff child assume it is the first one - Staff *staff = vrv_cast(measure->GetFirst(STAFF)); + const Staff *staff = vrv_cast(measure->GetFirst(STAFF)); staffList.push_back(staff->GetN()); } for (int staffN : staffList) { AttNIntegerComparison comparison(STAFF, staffN); - Staff *staff = vrv_cast(measure->FindDescendantByComparison(&comparison, 1)); + const Staff *staff = vrv_cast(measure->FindDescendantByComparison(&comparison, 1)); if (!staff) { // LogDebug("Staff with @n '%d' not found in measure '%s'", *iter, measure->GetID().c_str()); continue; From d4d2bf8cf29f842551b07e6be14eb352801238a7 Mon Sep 17 00:00:00 2001 From: David Bauer <63608463+brdvd@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:49:49 +0100 Subject: [PATCH 09/16] Update include/vrv/timeinterface.h Co-authored-by: Klaus Rettinghaus --- include/vrv/timeinterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/vrv/timeinterface.h b/include/vrv/timeinterface.h index e569d1a6c0..d405044677 100644 --- a/include/vrv/timeinterface.h +++ b/include/vrv/timeinterface.h @@ -85,7 +85,7 @@ class TimePointInterface : public Interface, public AttStaffIdent, public AttSta bool IsOnStaff(int n) const; /** - * Return a vector of staves looking at the @staff attribute or at the parent staff or the @startid + * Return a vector of staves looking at the @staff attribute or at the parent staff of the @startid */ ///@{ std::vector GetTstampStaves(const Measure *measure, const Object *object) const; From 25d5362848573f4998a3a9da4a147bb4e2bcd2c8 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 9 Dec 2024 08:48:04 +0100 Subject: [PATCH 10/16] Apply filters when processing pedals * const_cast should be avoided, but needs refactoring of GetTstampStaves --- src/midifunctor.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 1ba9f2df13..128fa5dd5f 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -717,6 +717,19 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) { if (!pedal->HasDir()) return FUNCTOR_CONTINUE; + // Check if the pedal applies to the staff filtered + if (this->GetFilters()) { + Pedal *nonConstPedal = const_cast(pedal); + Measure *measure = vrv_cast(nonConstPedal->GetFirstAncestor(MEASURE)); + assert(measure); + std::vector staffList = nonConstPedal->GetTstampStaves(measure, nonConstPedal); + bool applies = false; + for (Staff *staff : staffList) { + applies = (applies || this->GetFilters()->Apply(staff)); + } + if (!applies) return FUNCTOR_CONTINUE; + } + double pedalTime = pedal->GetStart()->GetAlignment()->GetTime().ToDouble() * SCORE_TIME_UNIT; double startTime = m_totalTime + pedalTime; int tpq = m_midiFile->getTPQ(); From 23282f0585d8752d5e54075574b4570febd60230 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 9 Dec 2024 12:56:58 +0100 Subject: [PATCH 11/16] Add a flag to process pedals only once --- include/vrv/midifunctor.h | 3 +++ src/doc.cpp | 8 ++++++-- src/midifunctor.cpp | 22 ++++++++++++---------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/include/vrv/midifunctor.h b/include/vrv/midifunctor.h index 9e883a83d1..050a9fae72 100644 --- a/include/vrv/midifunctor.h +++ b/include/vrv/midifunctor.h @@ -299,6 +299,7 @@ class GenerateMIDIFunctor : public ConstFunctor { void SetTempoEventTicks(const std::set &ticks) { m_tempoEventTicks = ticks; } void SetTrack(int track) { m_midiTrack = track; } void SetTransSemi(int transSemi) { m_transSemi = transSemi; } + void SetControlEvents(bool controlEvents) { m_controlEvents = controlEvents; } ///@} /* @@ -372,6 +373,8 @@ class GenerateMIDIFunctor : public ConstFunctor { bool m_cueExclusion; // Tablature held notes indexed by (course - 1) std::vector m_heldNotes; + // A flag indicating we want to process control events + bool m_controlEvents; }; //---------------------------------------------------------------------------- diff --git a/src/doc.cpp b/src/doc.cpp index 83fefeb500..92f991fd1f 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -522,8 +522,12 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) GenerateMIDIFunctor generateScoreDefMIDI(midiFile); generateScoreDefMIDI.SetChannel(midiChannel); generateScoreDefMIDI.SetTrack(midiTrack); + scoreDef->Process(generateScoreDefMIDI); + GenerateMIDIFunctor generateMIDI(midiFile); + generateMIDI.SetControlEvents(true); + for (auto &layers : staves.second.child) { filters.Clear(); // Create ad comparison object for each type / @n @@ -531,8 +535,6 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) AttNIntegerComparison matchLayer(LAYER, layers.first); filters.Add(&matchStaff); filters.Add(&matchLayer); - - GenerateMIDIFunctor generateMIDI(midiFile); generateMIDI.SetFilters(&filters); generateMIDI.SetChannel(midiChannel); @@ -548,6 +550,8 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) this->Process(generateMIDI); tempoEventTicks = generateMIDI.GetTempoEventTicks(); + // Process them only once per staff + generateMIDI.SetControlEvents(false); } } midiFile->sortTracks(); diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 128fa5dd5f..0135703859 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -368,6 +368,7 @@ GenerateMIDIFunctor::GenerateMIDIFunctor(smf::MidiFile *midiFile) : ConstFunctor m_lastNote = NULL; m_accentedGraceNote = false; m_cueExclusion = false; + m_controlEvents = false; } FunctorCode GenerateMIDIFunctor::VisitBeatRpt(const BeatRpt *beatRpt) @@ -717,18 +718,19 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) { if (!pedal->HasDir()) return FUNCTOR_CONTINUE; + // Check the functor flag - filters should always be there, but just in case we can the call + if (!m_controlEvents || !this->GetFilters()) return FUNCTOR_CONTINUE; + // Check if the pedal applies to the staff filtered - if (this->GetFilters()) { - Pedal *nonConstPedal = const_cast(pedal); - Measure *measure = vrv_cast(nonConstPedal->GetFirstAncestor(MEASURE)); - assert(measure); - std::vector staffList = nonConstPedal->GetTstampStaves(measure, nonConstPedal); - bool applies = false; - for (Staff *staff : staffList) { - applies = (applies || this->GetFilters()->Apply(staff)); - } - if (!applies) return FUNCTOR_CONTINUE; + Pedal *nonConstPedal = const_cast(pedal); + Measure *measure = vrv_cast(nonConstPedal->GetFirstAncestor(MEASURE)); + assert(measure); + std::vector staffList = nonConstPedal->GetTstampStaves(measure, nonConstPedal); + bool applies = false; + for (Staff *staff : staffList) { + applies = (applies || this->GetFilters()->Apply(staff)); } + if (!applies) return FUNCTOR_CONTINUE; double pedalTime = pedal->GetStart()->GetAlignment()->GetTime().ToDouble() * SCORE_TIME_UNIT; double startTime = m_totalTime + pedalTime; From 3d459badad072e848b10a3ccb2cd9d7b9da6b2e7 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 9 Dec 2024 13:09:46 +0100 Subject: [PATCH 12/16] Remove const_cast --- src/midifunctor.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 0135703859..e4819ffefe 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -722,12 +722,11 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) if (!m_controlEvents || !this->GetFilters()) return FUNCTOR_CONTINUE; // Check if the pedal applies to the staff filtered - Pedal *nonConstPedal = const_cast(pedal); - Measure *measure = vrv_cast(nonConstPedal->GetFirstAncestor(MEASURE)); + const Measure *measure = vrv_cast(pedal->GetFirstAncestor(MEASURE)); assert(measure); - std::vector staffList = nonConstPedal->GetTstampStaves(measure, nonConstPedal); + std::vector staffList = pedal->GetTstampStaves(measure, pedal); bool applies = false; - for (Staff *staff : staffList) { + for (const Staff *staff : staffList) { applies = (applies || this->GetFilters()->Apply(staff)); } if (!applies) return FUNCTOR_CONTINUE; From c0307ebe3baf62890064ea9e4e5f523bd2919438 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 9 Dec 2024 17:33:21 +0100 Subject: [PATCH 13/16] Keep functor variable within layer loop --- src/doc.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/doc.cpp b/src/doc.cpp index 92f991fd1f..c7d562d941 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -525,8 +525,7 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) scoreDef->Process(generateScoreDefMIDI); - GenerateMIDIFunctor generateMIDI(midiFile); - generateMIDI.SetControlEvents(true); + bool controlEvents = true; for (auto &layers : staves.second.child) { filters.Clear(); @@ -535,6 +534,8 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) AttNIntegerComparison matchLayer(LAYER, layers.first); filters.Add(&matchStaff); filters.Add(&matchLayer); + + GenerateMIDIFunctor generateMIDI(midiFile); generateMIDI.SetFilters(&filters); generateMIDI.SetChannel(midiChannel); @@ -545,13 +546,14 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) generateMIDI.SetCurrentTempo(tempo); generateMIDI.SetDeferredNotes(initMIDI.GetDeferredNotes()); generateMIDI.SetCueExclusion(this->GetOptions()->m_midiNoCue.GetValue()); + generateMIDI.SetControlEvents(controlEvents); // LogDebug("Exporting track %d ----------------", midiTrack); this->Process(generateMIDI); tempoEventTicks = generateMIDI.GetTempoEventTicks(); // Process them only once per staff - generateMIDI.SetControlEvents(false); + controlEvents = false; } } midiFile->sortTracks(); From 36a7c609c755a28ca0c4e193122d3959d060dcc6 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 9 Dec 2024 17:36:38 +0100 Subject: [PATCH 14/16] Fix formatting --- src/doc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc.cpp b/src/doc.cpp index c7d562d941..51f45825ac 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -534,7 +534,7 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) AttNIntegerComparison matchLayer(LAYER, layers.first); filters.Add(&matchStaff); filters.Add(&matchLayer); - + GenerateMIDIFunctor generateMIDI(midiFile); generateMIDI.SetFilters(&filters); From e43e4b6acd638c157dbb976cb3efbdf23be26fb8 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 9 Dec 2024 17:57:48 +0100 Subject: [PATCH 15/16] Correct comment --- src/midifunctor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index e4819ffefe..6cc697cf00 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -718,7 +718,7 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) { if (!pedal->HasDir()) return FUNCTOR_CONTINUE; - // Check the functor flag - filters should always be there, but just in case we can the call + // Check the functor flag - filters should always be there, but just in case we change how it is calle if (!m_controlEvents || !this->GetFilters()) return FUNCTOR_CONTINUE; // Check if the pedal applies to the staff filtered From 066360bafde074b782555419bde3168d7c5b8843 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Tue, 10 Dec 2024 11:13:33 +0100 Subject: [PATCH 16/16] Update src/midifunctor.cpp Co-authored-by: Andrew Hankinson --- src/midifunctor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 6cc697cf00..149d75fc31 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -718,7 +718,7 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) { if (!pedal->HasDir()) return FUNCTOR_CONTINUE; - // Check the functor flag - filters should always be there, but just in case we change how it is calle + // Check the functor flag - filters should always be there, but just in case we change how it is called if (!m_controlEvents || !this->GetFilters()) return FUNCTOR_CONTINUE; // Check if the pedal applies to the staff filtered