From 45aa54a0d4a2acb6182af37a6709338357b1690f Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 16 Sep 2024 17:13:50 +0200 Subject: [PATCH 001/105] Add iocmme.h/cpp --- Verovio.xcodeproj/project.pbxproj | 16 +++++++++ include/vrv/iocmme.h | 44 +++++++++++++++++++++++++ src/iocmme.cpp | 55 +++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 include/vrv/iocmme.h create mode 100644 src/iocmme.cpp diff --git a/Verovio.xcodeproj/project.pbxproj b/Verovio.xcodeproj/project.pbxproj index 0f0b7a4035c..4ad7bd2ea3c 100644 --- a/Verovio.xcodeproj/project.pbxproj +++ b/Verovio.xcodeproj/project.pbxproj @@ -326,6 +326,12 @@ 4D64137E2035F68600BB630E /* mdiv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D64137D2035F68600BB630E /* mdiv.cpp */; }; 4D64137F2035F68600BB630E /* mdiv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D64137D2035F68600BB630E /* mdiv.cpp */; }; 4D6413802035F68600BB630E /* mdiv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D64137D2035F68600BB630E /* mdiv.cpp */; }; + 4D6479372C9881B800CD9539 /* iocmme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D6479362C9881B800CD9539 /* iocmme.cpp */; }; + 4D6479392C98825900CD9539 /* iocmme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D6479362C9881B800CD9539 /* iocmme.cpp */; }; + 4D64793A2C98825A00CD9539 /* iocmme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D6479362C9881B800CD9539 /* iocmme.cpp */; }; + 4D64793B2C98825A00CD9539 /* iocmme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D6479362C9881B800CD9539 /* iocmme.cpp */; }; + 4D64793C2C98826600CD9539 /* iocmme.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D6479382C9881DB00CD9539 /* iocmme.h */; }; + 4D64793D2C98826600CD9539 /* iocmme.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D6479382C9881DB00CD9539 /* iocmme.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4D674B3F255F40AC008AEF4C /* plica.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D674B3E255F40AC008AEF4C /* plica.h */; }; 4D674B40255F40AC008AEF4C /* plica.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D674B3E255F40AC008AEF4C /* plica.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4D674B46255F40B7008AEF4C /* plica.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4D674B45255F40B7008AEF4C /* plica.cpp */; }; @@ -1871,6 +1877,8 @@ 4D6413772035F58200BB630E /* pages.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pages.cpp; path = src/pages.cpp; sourceTree = "<group>"; }; 4D64137B2035F67C00BB630E /* mdiv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mdiv.h; path = include/vrv/mdiv.h; sourceTree = "<group>"; }; 4D64137D2035F68600BB630E /* mdiv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mdiv.cpp; path = src/mdiv.cpp; sourceTree = "<group>"; }; + 4D6479362C9881B800CD9539 /* iocmme.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iocmme.cpp; path = src/iocmme.cpp; sourceTree = "<group>"; }; + 4D6479382C9881DB00CD9539 /* iocmme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iocmme.h; path = include/vrv/iocmme.h; sourceTree = "<group>"; }; 4D674B3E255F40AC008AEF4C /* plica.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = plica.h; path = include/vrv/plica.h; sourceTree = "<group>"; }; 4D674B45255F40B7008AEF4C /* plica.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = plica.cpp; path = src/plica.cpp; sourceTree = "<group>"; }; 4D6DF9F420E1071E00C12BBD /* subst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = subst.cpp; path = src/subst.cpp; sourceTree = "<group>"; }; @@ -2877,6 +2885,8 @@ 8F59291718854BF800FE51AD /* iobase.h */, 402197931F2E09DA00182DF1 /* ioabc.cpp */, 402197921F2E09CB00182DF1 /* ioabc.h */, + 4D6479382C9881DB00CD9539 /* iocmme.h */, + 4D6479362C9881B800CD9539 /* iocmme.cpp */, 8F086EC1188539540037FD8E /* iodarms.cpp */, 8F59291818854BF800FE51AD /* iodarms.h */, 4DA20ED01D0F151900706C4A /* iohumdrum.cpp */, @@ -3440,6 +3450,7 @@ E7901659298BCA97008FDB4E /* calcalignmentxposfunctor.h in Headers */, BDEF9ECC26725248008A3A47 /* caesura.h in Headers */, E7ADB3AB29D1921300825D5D /* adjustarticfunctor.h in Headers */, + 4D64793C2C98826600CD9539 /* iocmme.h in Headers */, E73E86252A069C640089DF74 /* transposefunctor.h in Headers */, 4DEC4DD921C8295700D1D273 /* rdg.h in Headers */, 4DB3D8D01F83D11800B5FC2B /* mordent.h in Headers */, @@ -3561,6 +3572,7 @@ 4D4CDEA82C079026005621E9 /* adjustneumexfunctor.h in Headers */, BB4C4B5222A932D7001F6AF0 /* ftrem.h in Headers */, E7E9C11329B0A1E200CFCE2F /* adjustaccidxfunctor.h in Headers */, + 4D64793D2C98826600CD9539 /* iocmme.h in Headers */, 4D88AD0B289673F50006D7DA /* symbol.h in Headers */, 4D1EB6A72A2A40CB00AF2F98 /* textlayoutelement.h in Headers */, 4D2E759022BC2B71004C51F0 /* course.h in Headers */, @@ -4084,6 +4096,7 @@ 40C2E4222052A6F60003625F /* pb.cpp in Sources */, 4DA0EAF322BB77C300A7EBEB /* facsimileinterface.cpp in Sources */, 4D1694241E3A44F300569BF4 /* positioninterface.cpp in Sources */, + 4D6479392C98825900CD9539 /* iocmme.cpp in Sources */, 4D1694251E3A44F300569BF4 /* timestamp.cpp in Sources */, 4D1694261E3A44F300569BF4 /* MidiEventList.cpp in Sources */, 4DA0EAC822BB779400A7EBEB /* facsimile.cpp in Sources */, @@ -4422,6 +4435,7 @@ 4D79642126C167100026288B /* pagemilestone.cpp in Sources */, 4D2073FB22A3BCE000E0765F /* tabgrp.cpp in Sources */, 4DEC4DBA21C8288900D1D273 /* choice.cpp in Sources */, + 4D6479372C9881B800CD9539 /* iocmme.cpp in Sources */, 4DACC9882990F29A00B55913 /* atts_mei.cpp in Sources */, 4D2073F522A3BCE000E0765F /* tuning.cpp in Sources */, 8F086F06188539540037FD8E /* view_beam.cpp in Sources */, @@ -4661,6 +4675,7 @@ 8F3DD35418854B2E0051330C /* slur.cpp in Sources */, 40C2E4232052A6F70003625F /* pb.cpp in Sources */, 4D64137A2035F58200BB630E /* pages.cpp in Sources */, + 4D64793A2C98825A00CD9539 /* iocmme.cpp in Sources */, 4D1694741E3A455200569BF4 /* humlib.cpp in Sources */, 4DB3D8C31F83D0EF00B5FC2B /* anchoredtext.cpp in Sources */, 4DB3D8E71F83D16A00B5FC2B /* ftrem.cpp in Sources */, @@ -4950,6 +4965,7 @@ BB4C4B6122A932D7001F6AF0 /* mrpt.cpp in Sources */, BB4C4AE722A932BC001F6AF0 /* damage.cpp in Sources */, 4DA0EACA22BB779400A7EBEB /* facsimile.cpp in Sources */, + 4D64793B2C98825A00CD9539 /* iocmme.cpp in Sources */, BB4C4B4B22A932D7001F6AF0 /* custos.cpp in Sources */, BB4C4BB822A932FC001F6AF0 /* Binasc.cpp in Sources */, BB4C4B7B22A932D7001F6AF0 /* tuplet.cpp in Sources */, diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h new file mode 100644 index 00000000000..43aa6e2a4e6 --- /dev/null +++ b/include/vrv/iocmme.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: iocmme.h +// Author: Laurent Pugin +// Created: 2024 +// Copyright (c) Authors and others. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef __VRV_IOCMME_H__ +#define __VRV_IOCMME_H__ + +#include <string> +#include <vector> + +//---------------------------------------------------------------------------- + +#include "iobase.h" +#include "pugixml.hpp" +#include "vrvdef.h" + +namespace vrv { + +//---------------------------------------------------------------------------- +// CmmeInput +//---------------------------------------------------------------------------- + +class CmmeInput : public Input { +public: + // constructors and destructors + CmmeInput(Doc *doc); + virtual ~CmmeInput(); + + bool Import(const std::string &cmme) override; + +private: + // +public: + // +private: + // +}; + +} // namespace vrv + +#endif diff --git a/src/iocmme.cpp b/src/iocmme.cpp new file mode 100644 index 00000000000..c097a318b16 --- /dev/null +++ b/src/iocmme.cpp @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: iocmme.cpp +// Author: Laurent Pugin +// Created: 2024 +// Copyright (c) Authors and others. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#include "iocmme.h" + +//---------------------------------------------------------------------------- + +#include <cassert> +#include <fstream> +#include <sstream> +#include <string> + +//---------------------------------------------------------------------------- + +#include "barline.h" +#include "clef.h" +#include "doc.h" +#include "layer.h" +#include "mdiv.h" +#include "measure.h" +#include "note.h" +#include "score.h" +#include "section.h" +#include "staff.h" +#include "staffdef.h" +#include "staffgrp.h" +#include "vrv.h" + +//---------------------------------------------------------------------------- + +namespace vrv { + +//---------------------------------------------------------------------------- +// CmmeInput +//---------------------------------------------------------------------------- + +CmmeInput::CmmeInput(Doc *doc) : Input(doc) {} + +CmmeInput::~CmmeInput() {} + +////////////////////////////////////////////////////////////////////////// + +bool CmmeInput::Import(const std::string &cmme) +{ + m_doc->Reset(); + m_doc->SetType(Raw); + + return true; +} + +} // namespace vrv From ce7c7406f775657b002c160eb1e432ce69bb1168 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 15:25:20 +0200 Subject: [PATCH 002/105] Enable cmme inputFrom --- include/vrv/toolkitdef.h | 1 + src/options.cpp | 3 ++- src/toolkit.cpp | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/vrv/toolkitdef.h b/include/vrv/toolkitdef.h index 246a4c1bc74..254c8449809 100644 --- a/include/vrv/toolkitdef.h +++ b/include/vrv/toolkitdef.h @@ -19,6 +19,7 @@ enum FileFormat { HUMMIDI, PAE, ABC, + CMME, DARMS, VOLPIANO, MUSICXML, diff --git a/src/options.cpp b/src/options.cpp index ba0265ef74a..d4ec5dc44f4 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -914,7 +914,8 @@ Options::Options() m_baseOptions.AddOption(&m_allPages); m_inputFrom.SetInfo("Input from", - "Select input format from: \"abc\", \"darms\", \"esac\", \"humdrum\", \"mei\", \"pae\", \"volpiano\", \"xml\" " + "Select input format from: \"abc\", \"cmme.xml\", \"darms\", \"esac\", \"humdrum\", \"mei\", \"pae\", " + "\"volpiano\", \"xml\" " "(musicxml), \"musicxml-hum\" (musicxml via humdrum)"); m_inputFrom.Init("mei"); m_inputFrom.SetKey("inputFrom"); diff --git a/src/toolkit.cpp b/src/toolkit.cpp index a81a8c61034..086562628d1 100644 --- a/src/toolkit.cpp +++ b/src/toolkit.cpp @@ -24,6 +24,7 @@ #include "filereader.h" #include "findfunctor.h" #include "ioabc.h" +#include "iocmme.h" #include "iodarms.h" #include "iohumdrum.h" #include "iomei.h" @@ -206,6 +207,9 @@ bool Toolkit::SetInputFrom(std::string const &inputFrom) else if (inputFrom == "volpiano") { m_inputFrom = VOLPIANO; } + else if (inputFrom == "cmme.xml") { + m_inputFrom = CMME; + } else if ((inputFrom == "humdrum") || (inputFrom == "hum")) { m_inputFrom = HUMDRUM; } @@ -548,6 +552,9 @@ bool Toolkit::LoadData(const std::string &data, bool resetLogBuffer) else if (inputFormat == VOLPIANO) { input = new VolpianoInput(&m_doc); } + else if (inputFormat == CMME) { + input = new CmmeInput(&m_doc); + } #ifndef NO_HUMDRUM_SUPPORT else if (inputFormat == HUMDRUM) { // LogInfo("Importing Humdrum data"); From ebcdc1de9068f9f04e42f46dcb93d78fe7011615 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 15:25:53 +0200 Subject: [PATCH 003/105] Basic implementation (WIP) --- include/vrv/iocmme.h | 35 ++++- src/iocmme.cpp | 321 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 352 insertions(+), 4 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 43aa6e2a4e6..4ae04a4cb3f 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -19,6 +19,15 @@ namespace vrv { +class Clef; +class Layer; +class Measure; +class Score; + +namespace cmme { + +} + //---------------------------------------------------------------------------- // CmmeInput //---------------------------------------------------------------------------- @@ -32,11 +41,35 @@ class CmmeInput : public Input { bool Import(const std::string &cmme) override; private: - // + void MakeSection(pugi::xml_node musicSectionNode); + + void MakeStaff(pugi::xml_node voiceNode); + + void MakeClef(pugi::xml_node clefNode); + void MakeDot(pugi::xml_node dotNode); + void MakeMensuration(pugi::xml_node mensurationNode); + void MakeOriginalText(pugi::xml_node originalTextNode); + void MakeNote(pugi::xml_node noteNode); + void MakeRest(pugi::xml_node restNode); + + data_DURATION ReadDuration(pugi::xml_node durationNode, int &num, int &numbase); + // std::pair<int, int> ReadNumNumbase(pugi::xml_node durationNode); + + std::string AsString(const pugi::xml_node node) const; + std::string ChildAsString(const pugi::xml_node node, const std::string &child) const; + int AsInt(const pugi::xml_node node) const; + int ChildAsInt(const pugi::xml_node node, const std::string &child) const; + public: // private: // + Score *m_score; + Measure *m_currentSection; + Layer *m_currentLayer; + + int m_numVoices; + std::vector<std::string> m_voices; }; } // namespace vrv diff --git a/src/iocmme.cpp b/src/iocmme.cpp index c097a318b16..63116ac4e4f 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -19,10 +19,12 @@ #include "barline.h" #include "clef.h" #include "doc.h" +#include "dot.h" #include "layer.h" #include "mdiv.h" #include "measure.h" #include "note.h" +#include "rest.h" #include "score.h" #include "section.h" #include "staff.h" @@ -38,7 +40,12 @@ namespace vrv { // CmmeInput //---------------------------------------------------------------------------- -CmmeInput::CmmeInput(Doc *doc) : Input(doc) {} +CmmeInput::CmmeInput(Doc *doc) : Input(doc) +{ + m_score = NULL; + m_currentSection = NULL; + m_currentLayer = NULL; +} CmmeInput::~CmmeInput() {} @@ -46,10 +53,318 @@ CmmeInput::~CmmeInput() {} bool CmmeInput::Import(const std::string &cmme) { - m_doc->Reset(); - m_doc->SetType(Raw); + try { + m_doc->Reset(); + m_doc->SetType(Raw); + pugi::xml_document doc; + doc.load_string(cmme.c_str(), (pugi::parse_comments | pugi::parse_default) & ~pugi::parse_eol); + pugi::xml_node root = doc.first_child(); + + // The mDiv + Mdiv *mdiv = new Mdiv(); + mdiv->m_visibility = Visible; + m_doc->AddChild(mdiv); + // The score + m_score = new Score(); + mdiv->AddChild(m_score); + + pugi::xpath_node_set voices = root.select_nodes("/Piece/VoiceData/Voice"); + + for (pugi::xpath_node voiceNode : voices) { + m_numVoices++; + std::string name = ChildAsString(voiceNode.node(), "Name"); + m_voices.push_back(name); + } + + pugi::xpath_node_set musicSections = root.select_nodes("/Piece/MusicSection/*"); + + for (pugi::xpath_node musicSectionNode : musicSections) { + MakeSection(musicSectionNode.node()); + } + + // add minimal scoreDef + StaffGrp *staffGrp = new StaffGrp(); + for (int i = 0; i < m_numVoices; ++i) { + StaffDef *staffDef = new StaffDef(); + staffDef->SetN(i + 1); + staffDef->SetLines(5); + staffGrp->AddChild(staffDef); + } + + m_score->GetScoreDef()->AddChild(staffGrp); + + m_doc->ConvertToPageBasedDoc(); + // return this->ReadDoc(root); + } + catch (char *str) { + LogError("%s", str); + return false; + } return true; } +void CmmeInput::MakeSection(pugi::xml_node musicSectionNode) +{ + assert(m_score); + + std::string sectionType = musicSectionNode.name(); + + // the section + Section *section = new Section(); + section->SetType(sectionType); + m_score->AddChild(section); + + m_currentSection = new Measure(UNMEASURED, 1); + section->AddChild(m_currentSection); + + pugi::xpath_node_set voices = musicSectionNode.select_nodes("./Voice"); + + for (int i = 0; i < m_numVoices; ++i) { + std::string xpath = StringFormat("./Voice[VoiceNum[text()='%d']]", i + 1); + pugi::xpath_node voice = musicSectionNode.select_node(xpath.c_str()); + if (voice) { + MakeStaff(voice.node()); + } + else { + Staff *staff = new Staff(i + 1); + staff->SetVisible(BOOLEAN_false); + m_currentSection->AddChild(staff); + } + } +} + +void CmmeInput::MakeStaff(pugi::xml_node voiceNode) +{ + assert(m_currentSection); + + int numVoice = this->ChildAsInt(voiceNode, "VoiceNum"); + + Staff *staff = new Staff(numVoice); + m_currentLayer = new Layer(); + m_currentLayer->SetN(1); + + pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); + + for (pugi::xpath_node event : events) { + pugi::xml_node eventNode = event.node(); + std::string name = eventNode.name(); + if (name == "Clef") { + if (eventNode.select_node("./Signature")) { + } + else { + MakeClef(eventNode); + } + } + else if (name == "Dot") { + MakeDot(eventNode); + } + else if (name == "Mensuration") { + MakeMensuration(eventNode); + } + else if (name == "Note") { + MakeNote(eventNode); + } + else if (name == "OriginalText") { + MakeOriginalText(eventNode); + } + else if (name == "Rest") { + MakeRest(eventNode); + } + else { + LogWarning("Unsupported event '%s'", name.c_str()); + } + } + + staff->AddChild(m_currentLayer); + m_currentSection->AddChild(staff); +} + +void CmmeInput::MakeClef(pugi::xml_node clefNode) +{ + static const std::map<std::string, data_CLEFSHAPE> shapeMap{ + { "C", CLEFSHAPE_C }, // + { "F", CLEFSHAPE_F }, // + { "G", CLEFSHAPE_G }, // + { "Frnd", CLEFSHAPE_F }, // + }; + + std::string appearance = this->ChildAsString(clefNode, "Appearance"); + if (!shapeMap.contains(appearance)) { + LogWarning("Unknown clef '%s", appearance.c_str()); + return; + } + + Clef *clef = new Clef(); + int staffLoc = this->ChildAsInt(clefNode, "StaffLoc"); + staffLoc = (staffLoc + 1) / 2; + clef->SetLine(staffLoc); + + data_CLEFSHAPE shape = shapeMap.at(appearance); + clef->SetShape(shape); + + m_currentLayer->AddChild(clef); + + return; +} + +void CmmeInput::MakeDot(pugi::xml_node dotNode) +{ + Dot *dot = new Dot(); + m_currentLayer->AddChild(dot); + + return; +} + +void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) +{ + return; +} + +void CmmeInput::MakeNote(pugi::xml_node noteNode) +{ + static const std::map<std::string, data_PITCHNAME> Step2PitchName{ + { "C", PITCHNAME_c }, // + { "D", PITCHNAME_d }, // + { "E", PITCHNAME_e }, // + { "F", PITCHNAME_f }, // + { "G", PITCHNAME_g }, // + { "A", PITCHNAME_a }, // + { "B", PITCHNAME_b } // + }; + + Note *note = new Note(); + std::string step = this->ChildAsString(noteNode, "LetterName"); + data_PITCHNAME pname = Step2PitchName.contains(step) ? Step2PitchName.at(step) : PITCHNAME_c; + note->SetPname(pname); + + int num; + int numbase; + data_DURATION duration = this->ReadDuration(noteNode, num, numbase); + note->SetDur(duration); + if (num != VRV_UNSET && numbase != VRV_UNSET) { + note->SetNumbase(num); + note->SetNum(numbase); + } + + int oct = this->ChildAsInt(noteNode, "OctaveNum"); + if ((pname != PITCHNAME_a) && (pname != PITCHNAME_b)) oct += 1; + note->SetOct(oct); + + if (noteNode.child("Colored")) { + note->SetColored(BOOLEAN_true); + } + + m_currentLayer->AddChild(note); + + return; +} + +void CmmeInput::MakeOriginalText(pugi::xml_node originalTextNode) +{ + return; +} + +void CmmeInput::MakeRest(pugi::xml_node restNode) +{ + Rest *rest = new Rest(); + int num; + int numbase; + rest->SetDur(this->ReadDuration(restNode, num, numbase)); + if (num != VRV_UNSET && numbase != VRV_UNSET) { + rest->SetNumbase(num); + rest->SetNum(numbase); + } + + m_currentLayer->AddChild(rest); + + return; +} + +data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) +{ + static const std::map<std::string, data_DURATION> durationMap{ + { "Maxima", DURATION_maxima }, // + { "Longa", DURATION_longa }, // + { "Brevis", DURATION_brevis }, // + { "Semibrevis", DURATION_semibrevis }, // + { "Minima", DURATION_minima }, // + { "Semiminima", DURATION_semiminima }, // + { "Fusa", DURATION_fusa }, // + { "Semifusa", DURATION_semifusa } // + }; + + std::string type = this->ChildAsString(durationNode, "Type"); + data_DURATION duration = durationMap.contains(type) ? durationMap.at(type) : DURATION_brevis; + + num = VRV_UNSET; + numbase = VRV_UNSET; + + static const std::map<std::string, std::pair<int, int>> fractionMap{ + { "Maxima", { 16, 1 } }, // + { "Longa", { 8, 1 } }, // + { "Brevis", { 4, 1 } }, // + { "Semibrevis", { 2, 1 } }, // + { "Minima", { 1, 1 } }, // + { "Semiminima", { 1, 2 } }, // + { "Fusa", { 1, 4 } }, // + { "Semifusa", { 1, 8 } } // + }; + + if (durationNode.child("Length")) { + num = this->ChildAsInt(durationNode.child("Length"), "Num"); + numbase = this->ChildAsInt(durationNode.child("Length"), "Den"); + + auto ratio = fractionMap.at(type); + if (ratio.first != num || ratio.second != numbase) { + num *= ratio.second; + numbase *= ratio.first; + } + else { + num = VRV_UNSET; + numbase = VRV_UNSET; + } + } + + return duration; +} + +std::string CmmeInput::AsString(const pugi::xml_node node) const +{ + assert(node); + + if (node.text()) { + return std::string(node.text().as_string()); + } + return ""; +} + +std::string CmmeInput::ChildAsString(const pugi::xml_node node, const std::string &child) const +{ + pugi::xpath_node childNode = node.select_node(child.c_str()); + if (childNode.node()) { + return this->AsString(childNode.node()); + } + return ""; +} + +int CmmeInput::AsInt(const pugi::xml_node node) const +{ + assert(node); + + if (node.text()) { + return (node.text().as_int()); + } + return VRV_UNSET; +} + +int CmmeInput::ChildAsInt(const pugi::xml_node node, const std::string &child) const +{ + pugi::xpath_node childNode = node.select_node(child.c_str()); + if (childNode.node()) { + return this->AsInt(childNode.node()); + } + return VRV_UNSET; +} + } // namespace vrv From 73527eb5f9d58c04b952d4d2b5ec696f8a39aacc Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 17:54:35 +0200 Subject: [PATCH 004/105] Proper handling of durations --- include/vrv/iocmme.h | 11 ++++++- src/iocmme.cpp | 78 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 4ae04a4cb3f..794d10df798 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -26,7 +26,14 @@ class Score; namespace cmme { -} + struct mensuration { + int prolatio = 2; + int tempus = 2; + int modusminor = 2; + int modusmaior = 2; + }; + +} // namespace cmme //---------------------------------------------------------------------------- // CmmeInput @@ -67,6 +74,8 @@ class CmmeInput : public Input { Score *m_score; Measure *m_currentSection; Layer *m_currentLayer; + std::vector<cmme::mensuration> m_mensurations; + cmme::mensuration *m_currentMensuration; int m_numVoices; std::vector<std::string> m_voices; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 63116ac4e4f..ba233ab666f 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -23,6 +23,7 @@ #include "layer.h" #include "mdiv.h" #include "measure.h" +#include "mensur.h" #include "note.h" #include "rest.h" #include "score.h" @@ -45,6 +46,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_score = NULL; m_currentSection = NULL; m_currentLayer = NULL; + m_currentMensuration = NULL; } CmmeInput::~CmmeInput() {} @@ -75,6 +77,7 @@ bool CmmeInput::Import(const std::string &cmme) std::string name = ChildAsString(voiceNode.node(), "Name"); m_voices.push_back(name); } + m_mensurations.resize(m_numVoices); pugi::xpath_node_set musicSections = root.select_nodes("/Piece/MusicSection/*"); @@ -88,7 +91,15 @@ bool CmmeInput::Import(const std::string &cmme) StaffDef *staffDef = new StaffDef(); staffDef->SetN(i + 1); staffDef->SetLines(5); + staffDef->SetNotationtype(NOTATIONTYPE_mensural); staffGrp->AddChild(staffDef); + // Default mensur with everything binary in CMME + Mensur *mensur = new Mensur(); + mensur->SetProlatio(PROLATIO_2); + mensur->SetTempus(TEMPUS_2); + mensur->SetModusminor(MODUSMINOR_2); + mensur->SetModusmaior(MODUSMAIOR_2); + staffDef->AddChild(mensur); } m_score->GetScoreDef()->AddChild(staffGrp); @@ -144,6 +155,8 @@ void CmmeInput::MakeStaff(pugi::xml_node voiceNode) m_currentLayer = new Layer(); m_currentLayer->SetN(1); + m_currentMensuration = &m_mensurations.at(numVoice - 1); + pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); for (pugi::xpath_node event : events) { @@ -218,6 +231,30 @@ void CmmeInput::MakeDot(pugi::xml_node dotNode) void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) { + pugi::xml_node mensInfo = mensurationNode.child("MensInfo"); + if (mensInfo) { + m_currentMensuration->prolatio = this->ChildAsInt(mensInfo, "Prolatio"); + m_currentMensuration->tempus = this->ChildAsInt(mensInfo, "Tempus"); + m_currentMensuration->modusminor = this->ChildAsInt(mensInfo, "ModusMinor"); + m_currentMensuration->modusmaior = this->ChildAsInt(mensInfo, "ModusMaior"); + } + + Mensur *mensur = new Mensur(); + data_PROLATIO prolatio = (m_currentMensuration->prolatio == 3) ? PROLATIO_3 : PROLATIO_2; + mensur->SetProlatio(prolatio); + data_TEMPUS tempus = (m_currentMensuration->tempus == 3) ? TEMPUS_3 : TEMPUS_2; + mensur->SetTempus(tempus); + data_MODUSMINOR modusminor = (m_currentMensuration->modusminor == 3) ? MODUSMINOR_3 : MODUSMINOR_2; + mensur->SetModusminor(modusminor); + data_MODUSMAIOR modusmaior = (m_currentMensuration->modusmaior == 3) ? MODUSMAIOR_3 : MODUSMAIOR_2; + mensur->SetModusmaior(modusmaior); + data_MENSURATIONSIGN sign = (m_currentMensuration->tempus == 3) ? MENSURATIONSIGN_O : MENSURATIONSIGN_C; + mensur->SetSign(sign); + data_BOOLEAN dot = (m_currentMensuration->prolatio == 3) ? BOOLEAN_true : BOOLEAN_false; + mensur->SetDot(dot); + + m_currentLayer->AddChild(mensur); + return; } @@ -270,7 +307,8 @@ void CmmeInput::MakeRest(pugi::xml_node restNode) Rest *rest = new Rest(); int num; int numbase; - rest->SetDur(this->ReadDuration(restNode, num, numbase)); + data_DURATION duration = this->ReadDuration(restNode, num, numbase); + rest->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { rest->SetNumbase(num); rest->SetNum(numbase); @@ -300,22 +338,36 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int num = VRV_UNSET; numbase = VRV_UNSET; - static const std::map<std::string, std::pair<int, int>> fractionMap{ - { "Maxima", { 16, 1 } }, // - { "Longa", { 8, 1 } }, // - { "Brevis", { 4, 1 } }, // - { "Semibrevis", { 2, 1 } }, // - { "Minima", { 1, 1 } }, // - { "Semiminima", { 1, 2 } }, // - { "Fusa", { 1, 4 } }, // - { "Semifusa", { 1, 8 } } // - }; - if (durationNode.child("Length")) { num = this->ChildAsInt(durationNode.child("Length"), "Num"); numbase = this->ChildAsInt(durationNode.child("Length"), "Den"); - auto ratio = fractionMap.at(type); + std::pair<int, int> ratio = { 1, 1 }; + + if (type == "Maxima") { + ratio.first *= m_currentMensuration->modusmaior * m_currentMensuration->modusminor + * m_currentMensuration->tempus * m_currentMensuration->prolatio; + } + else if (type == "Longa") { + ratio.first + *= m_currentMensuration->modusminor * m_currentMensuration->tempus * m_currentMensuration->prolatio; + } + else if (type == "Brevis") { + ratio.first *= m_currentMensuration->tempus * m_currentMensuration->prolatio; + } + else if (type == "Semibrevis") { + ratio.first *= m_currentMensuration->prolatio; + } + else if (type == "Semiminima") { + ratio.second = 2; + } + else if (type == "Fusa") { + ratio.second = 4; + } + else if (type == "Semifusa") { + ratio.second = 8; + } + if (ratio.first != num || ratio.second != numbase) { num *= ratio.second; numbase *= ratio.first; From ec1072fd53c0ea546ab57ab8c08d25f2b4b72095 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 21:37:53 +0200 Subject: [PATCH 005/105] Add label --- include/vrv/iocmme.h | 5 +++-- src/iocmme.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 794d10df798..b83ffb282ed 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -49,7 +49,6 @@ class CmmeInput : public Input { private: void MakeSection(pugi::xml_node musicSectionNode); - void MakeStaff(pugi::xml_node voiceNode); void MakeClef(pugi::xml_node clefNode); @@ -60,8 +59,10 @@ class CmmeInput : public Input { void MakeRest(pugi::xml_node restNode); data_DURATION ReadDuration(pugi::xml_node durationNode, int &num, int &numbase); - // std::pair<int, int> ReadNumNumbase(pugi::xml_node durationNode); + /** + * Helper methods for accessing and converting text in elements + */ std::string AsString(const pugi::xml_node node) const; std::string ChildAsString(const pugi::xml_node node, const std::string &child) const; int AsInt(const pugi::xml_node node) const; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index ba233ab666f..7fe22ff3241 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -20,6 +20,7 @@ #include "clef.h" #include "doc.h" #include "dot.h" +#include "label.h" #include "layer.h" #include "mdiv.h" #include "measure.h" @@ -31,6 +32,7 @@ #include "staff.h" #include "staffdef.h" #include "staffgrp.h" +#include "text.h" #include "vrv.h" //---------------------------------------------------------------------------- @@ -74,6 +76,7 @@ bool CmmeInput::Import(const std::string &cmme) for (pugi::xpath_node voiceNode : voices) { m_numVoices++; + // Get the voice name if any std::string name = ChildAsString(voiceNode.node(), "Name"); m_voices.push_back(name); } @@ -87,12 +90,23 @@ bool CmmeInput::Import(const std::string &cmme) // add minimal scoreDef StaffGrp *staffGrp = new StaffGrp(); + GrpSym *grpSym = new GrpSym(); + grpSym->SetSymbol(staffGroupingSym_SYMBOL_bracket); + staffGrp->AddChild(grpSym); for (int i = 0; i < m_numVoices; ++i) { StaffDef *staffDef = new StaffDef(); staffDef->SetN(i + 1); staffDef->SetLines(5); staffDef->SetNotationtype(NOTATIONTYPE_mensural); staffGrp->AddChild(staffDef); + // Label + if (!m_voices.at(i).empty()) { + Label *label = new Label(); + Text *text = new Text(); + text->SetText(UTF8to32(m_voices.at(i))); + label->AddChild(text); + staffDef->AddChild(label); + } // Default mensur with everything binary in CMME Mensur *mensur = new Mensur(); mensur->SetProlatio(PROLATIO_2); From 2facfd049dda8cc5e17847c0aea5fee6454021cf Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 21:42:17 +0200 Subject: [PATCH 006/105] Asserts and checks --- src/iocmme.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 7fe22ff3241..2fdb97e5926 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -216,6 +216,8 @@ void CmmeInput::MakeClef(pugi::xml_node clefNode) { "Frnd", CLEFSHAPE_F }, // }; + assert(m_currentLayer); + std::string appearance = this->ChildAsString(clefNode, "Appearance"); if (!shapeMap.contains(appearance)) { LogWarning("Unknown clef '%s", appearance.c_str()); @@ -237,6 +239,8 @@ void CmmeInput::MakeClef(pugi::xml_node clefNode) void CmmeInput::MakeDot(pugi::xml_node dotNode) { + assert(m_currentLayer); + Dot *dot = new Dot(); m_currentLayer->AddChild(dot); @@ -245,6 +249,9 @@ void CmmeInput::MakeDot(pugi::xml_node dotNode) void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) { + assert(m_currentLayer); + assert(m_currentMensuration); + pugi::xml_node mensInfo = mensurationNode.child("MensInfo"); if (mensInfo) { m_currentMensuration->prolatio = this->ChildAsInt(mensInfo, "Prolatio"); @@ -284,6 +291,8 @@ void CmmeInput::MakeNote(pugi::xml_node noteNode) { "B", PITCHNAME_b } // }; + assert(m_currentLayer); + Note *note = new Note(); std::string step = this->ChildAsString(noteNode, "LetterName"); data_PITCHNAME pname = Step2PitchName.contains(step) ? Step2PitchName.at(step) : PITCHNAME_c; @@ -318,6 +327,8 @@ void CmmeInput::MakeOriginalText(pugi::xml_node originalTextNode) void CmmeInput::MakeRest(pugi::xml_node restNode) { + assert(m_currentLayer); + Rest *rest = new Rest(); int num; int numbase; @@ -346,6 +357,8 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int { "Semifusa", DURATION_semifusa } // }; + assert(m_currentMensuration); + std::string type = this->ChildAsString(durationNode, "Type"); data_DURATION duration = durationMap.contains(type) ? durationMap.at(type) : DURATION_brevis; @@ -397,7 +410,7 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int std::string CmmeInput::AsString(const pugi::xml_node node) const { - assert(node); + if (!node) return ""; if (node.text()) { return std::string(node.text().as_string()); @@ -407,6 +420,8 @@ std::string CmmeInput::AsString(const pugi::xml_node node) const std::string CmmeInput::ChildAsString(const pugi::xml_node node, const std::string &child) const { + if (!node) return ""; + pugi::xpath_node childNode = node.select_node(child.c_str()); if (childNode.node()) { return this->AsString(childNode.node()); @@ -416,7 +431,7 @@ std::string CmmeInput::ChildAsString(const pugi::xml_node node, const std::strin int CmmeInput::AsInt(const pugi::xml_node node) const { - assert(node); + if (!node) return VRV_UNSET; if (node.text()) { return (node.text().as_int()); @@ -426,6 +441,8 @@ int CmmeInput::AsInt(const pugi::xml_node node) const int CmmeInput::ChildAsInt(const pugi::xml_node node, const std::string &child) const { + if (!node) return VRV_UNSET; + pugi::xpath_node childNode = node.select_node(child.c_str()); if (childNode.node()) { return this->AsInt(childNode.node()); From c7022b8a460c232435ad337b8dd36e7236f047cd Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 21:43:37 +0200 Subject: [PATCH 007/105] Rename variable --- src/iocmme.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 2fdb97e5926..3c6b2b21ac4 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -281,7 +281,7 @@ void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) void CmmeInput::MakeNote(pugi::xml_node noteNode) { - static const std::map<std::string, data_PITCHNAME> Step2PitchName{ + static const std::map<std::string, data_PITCHNAME> pitchMap{ { "C", PITCHNAME_c }, // { "D", PITCHNAME_d }, // { "E", PITCHNAME_e }, // @@ -295,7 +295,7 @@ void CmmeInput::MakeNote(pugi::xml_node noteNode) Note *note = new Note(); std::string step = this->ChildAsString(noteNode, "LetterName"); - data_PITCHNAME pname = Step2PitchName.contains(step) ? Step2PitchName.at(step) : PITCHNAME_c; + data_PITCHNAME pname = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; note->SetPname(pname); int num; From 784ee5d3ba550b1efaafdbc16d56052a0a9ff98e Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 22:05:55 +0200 Subject: [PATCH 008/105] Add function to check if node is clef --- include/vrv/iocmme.h | 9 +++--- src/iocmme.cpp | 67 ++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index b83ffb282ed..a4f88ecefca 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -26,7 +26,7 @@ class Score; namespace cmme { - struct mensuration { + struct mensInfo { int prolatio = 2; int tempus = 2; int modusminor = 2; @@ -58,7 +58,8 @@ class CmmeInput : public Input { void MakeNote(pugi::xml_node noteNode); void MakeRest(pugi::xml_node restNode); - data_DURATION ReadDuration(pugi::xml_node durationNode, int &num, int &numbase); + data_DURATION ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) const; + bool IsClef(pugi::xml_node clefNode) const; /** * Helper methods for accessing and converting text in elements @@ -75,8 +76,8 @@ class CmmeInput : public Input { Score *m_score; Measure *m_currentSection; Layer *m_currentLayer; - std::vector<cmme::mensuration> m_mensurations; - cmme::mensuration *m_currentMensuration; + std::vector<cmme::mensInfo> m_mensInfos; + cmme::mensInfo *m_mensInfo; int m_numVoices; std::vector<std::string> m_voices; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 3c6b2b21ac4..320b8bda8f0 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -9,6 +9,7 @@ //---------------------------------------------------------------------------- +#include <algorithm> #include <cassert> #include <fstream> #include <sstream> @@ -48,7 +49,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_score = NULL; m_currentSection = NULL; m_currentLayer = NULL; - m_currentMensuration = NULL; + m_mensInfo = NULL; } CmmeInput::~CmmeInput() {} @@ -80,7 +81,7 @@ bool CmmeInput::Import(const std::string &cmme) std::string name = ChildAsString(voiceNode.node(), "Name"); m_voices.push_back(name); } - m_mensurations.resize(m_numVoices); + m_mensInfos.resize(m_numVoices); pugi::xpath_node_set musicSections = root.select_nodes("/Piece/MusicSection/*"); @@ -169,7 +170,7 @@ void CmmeInput::MakeStaff(pugi::xml_node voiceNode) m_currentLayer = new Layer(); m_currentLayer->SetN(1); - m_currentMensuration = &m_mensurations.at(numVoice - 1); + m_mensInfo = &m_mensInfos.at(numVoice - 1); pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); @@ -177,10 +178,10 @@ void CmmeInput::MakeStaff(pugi::xml_node voiceNode) pugi::xml_node eventNode = event.node(); std::string name = eventNode.name(); if (name == "Clef") { - if (eventNode.select_node("./Signature")) { + if (this->IsClef(eventNode)) { + MakeClef(eventNode); } else { - MakeClef(eventNode); } } else if (name == "Dot") { @@ -214,22 +215,18 @@ void CmmeInput::MakeClef(pugi::xml_node clefNode) { "F", CLEFSHAPE_F }, // { "G", CLEFSHAPE_G }, // { "Frnd", CLEFSHAPE_F }, // + { "Fsqr", CLEFSHAPE_F }, // }; assert(m_currentLayer); - std::string appearance = this->ChildAsString(clefNode, "Appearance"); - if (!shapeMap.contains(appearance)) { - LogWarning("Unknown clef '%s", appearance.c_str()); - return; - } - Clef *clef = new Clef(); int staffLoc = this->ChildAsInt(clefNode, "StaffLoc"); staffLoc = (staffLoc + 1) / 2; clef->SetLine(staffLoc); - data_CLEFSHAPE shape = shapeMap.at(appearance); + std::string appearance = this->ChildAsString(clefNode, "Appearance"); + data_CLEFSHAPE shape = shapeMap.contains(appearance) ? shapeMap.at(appearance) : CLEFSHAPE_C; clef->SetShape(shape); m_currentLayer->AddChild(clef); @@ -250,28 +247,28 @@ void CmmeInput::MakeDot(pugi::xml_node dotNode) void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) { assert(m_currentLayer); - assert(m_currentMensuration); + assert(m_mensInfo); pugi::xml_node mensInfo = mensurationNode.child("MensInfo"); if (mensInfo) { - m_currentMensuration->prolatio = this->ChildAsInt(mensInfo, "Prolatio"); - m_currentMensuration->tempus = this->ChildAsInt(mensInfo, "Tempus"); - m_currentMensuration->modusminor = this->ChildAsInt(mensInfo, "ModusMinor"); - m_currentMensuration->modusmaior = this->ChildAsInt(mensInfo, "ModusMaior"); + m_mensInfo->prolatio = this->ChildAsInt(mensInfo, "Prolatio"); + m_mensInfo->tempus = this->ChildAsInt(mensInfo, "Tempus"); + m_mensInfo->modusminor = this->ChildAsInt(mensInfo, "ModusMinor"); + m_mensInfo->modusmaior = this->ChildAsInt(mensInfo, "ModusMaior"); } Mensur *mensur = new Mensur(); - data_PROLATIO prolatio = (m_currentMensuration->prolatio == 3) ? PROLATIO_3 : PROLATIO_2; + data_PROLATIO prolatio = (m_mensInfo->prolatio == 3) ? PROLATIO_3 : PROLATIO_2; mensur->SetProlatio(prolatio); - data_TEMPUS tempus = (m_currentMensuration->tempus == 3) ? TEMPUS_3 : TEMPUS_2; + data_TEMPUS tempus = (m_mensInfo->tempus == 3) ? TEMPUS_3 : TEMPUS_2; mensur->SetTempus(tempus); - data_MODUSMINOR modusminor = (m_currentMensuration->modusminor == 3) ? MODUSMINOR_3 : MODUSMINOR_2; + data_MODUSMINOR modusminor = (m_mensInfo->modusminor == 3) ? MODUSMINOR_3 : MODUSMINOR_2; mensur->SetModusminor(modusminor); - data_MODUSMAIOR modusmaior = (m_currentMensuration->modusmaior == 3) ? MODUSMAIOR_3 : MODUSMAIOR_2; + data_MODUSMAIOR modusmaior = (m_mensInfo->modusmaior == 3) ? MODUSMAIOR_3 : MODUSMAIOR_2; mensur->SetModusmaior(modusmaior); - data_MENSURATIONSIGN sign = (m_currentMensuration->tempus == 3) ? MENSURATIONSIGN_O : MENSURATIONSIGN_C; + data_MENSURATIONSIGN sign = (m_mensInfo->tempus == 3) ? MENSURATIONSIGN_O : MENSURATIONSIGN_C; mensur->SetSign(sign); - data_BOOLEAN dot = (m_currentMensuration->prolatio == 3) ? BOOLEAN_true : BOOLEAN_false; + data_BOOLEAN dot = (m_mensInfo->prolatio == 3) ? BOOLEAN_true : BOOLEAN_false; mensur->SetDot(dot); m_currentLayer->AddChild(mensur); @@ -344,7 +341,7 @@ void CmmeInput::MakeRest(pugi::xml_node restNode) return; } -data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) +data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) const { static const std::map<std::string, data_DURATION> durationMap{ { "Maxima", DURATION_maxima }, // @@ -357,7 +354,7 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int { "Semifusa", DURATION_semifusa } // }; - assert(m_currentMensuration); + assert(m_mensInfo); std::string type = this->ChildAsString(durationNode, "Type"); data_DURATION duration = durationMap.contains(type) ? durationMap.at(type) : DURATION_brevis; @@ -372,18 +369,16 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int std::pair<int, int> ratio = { 1, 1 }; if (type == "Maxima") { - ratio.first *= m_currentMensuration->modusmaior * m_currentMensuration->modusminor - * m_currentMensuration->tempus * m_currentMensuration->prolatio; + ratio.first *= m_mensInfo->modusmaior * m_mensInfo->modusminor * m_mensInfo->tempus * m_mensInfo->prolatio; } else if (type == "Longa") { - ratio.first - *= m_currentMensuration->modusminor * m_currentMensuration->tempus * m_currentMensuration->prolatio; + ratio.first *= m_mensInfo->modusminor * m_mensInfo->tempus * m_mensInfo->prolatio; } else if (type == "Brevis") { - ratio.first *= m_currentMensuration->tempus * m_currentMensuration->prolatio; + ratio.first *= m_mensInfo->tempus * m_mensInfo->prolatio; } else if (type == "Semibrevis") { - ratio.first *= m_currentMensuration->prolatio; + ratio.first *= m_mensInfo->prolatio; } else if (type == "Semiminima") { ratio.second = 2; @@ -408,6 +403,16 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int return duration; } +bool CmmeInput::IsClef(const pugi::xml_node clefNode) const +{ + static std::vector<std::string> clefs = { "C", "F", "Fsqr", "Frnd", "G" }; + + if (clefNode.select_node("./Signature")) return false; + + std::string appearance = this->ChildAsString(clefNode, "Appearance"); + return (std::find(clefs.begin(), clefs.end(), appearance) != clefs.end()); +} + std::string CmmeInput::AsString(const pugi::xml_node node) const { if (!node) return ""; From 26e997c999273df2d2ae606c382674be15ab031b Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 22:09:39 +0200 Subject: [PATCH 009/105] Rename methods --- include/vrv/iocmme.h | 18 +++++++++--------- src/iocmme.cpp | 32 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index a4f88ecefca..7cc33ff071e 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -48,15 +48,15 @@ class CmmeInput : public Input { bool Import(const std::string &cmme) override; private: - void MakeSection(pugi::xml_node musicSectionNode); - void MakeStaff(pugi::xml_node voiceNode); - - void MakeClef(pugi::xml_node clefNode); - void MakeDot(pugi::xml_node dotNode); - void MakeMensuration(pugi::xml_node mensurationNode); - void MakeOriginalText(pugi::xml_node originalTextNode); - void MakeNote(pugi::xml_node noteNode); - void MakeRest(pugi::xml_node restNode); + void CreateSection(pugi::xml_node musicSectionNode); + void CreateStaff(pugi::xml_node voiceNode); + + void CreateClef(pugi::xml_node clefNode); + void CreateDot(pugi::xml_node dotNode); + void CreateMensuration(pugi::xml_node mensurationNode); + void CreateOriginalText(pugi::xml_node originalTextNode); + void CreateNote(pugi::xml_node noteNode); + void CreateRest(pugi::xml_node restNode); data_DURATION ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) const; bool IsClef(pugi::xml_node clefNode) const; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 320b8bda8f0..75fa6fa06c3 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -86,7 +86,7 @@ bool CmmeInput::Import(const std::string &cmme) pugi::xpath_node_set musicSections = root.select_nodes("/Piece/MusicSection/*"); for (pugi::xpath_node musicSectionNode : musicSections) { - MakeSection(musicSectionNode.node()); + CreateSection(musicSectionNode.node()); } // add minimal scoreDef @@ -130,7 +130,7 @@ bool CmmeInput::Import(const std::string &cmme) return true; } -void CmmeInput::MakeSection(pugi::xml_node musicSectionNode) +void CmmeInput::CreateSection(pugi::xml_node musicSectionNode) { assert(m_score); @@ -150,7 +150,7 @@ void CmmeInput::MakeSection(pugi::xml_node musicSectionNode) std::string xpath = StringFormat("./Voice[VoiceNum[text()='%d']]", i + 1); pugi::xpath_node voice = musicSectionNode.select_node(xpath.c_str()); if (voice) { - MakeStaff(voice.node()); + CreateStaff(voice.node()); } else { Staff *staff = new Staff(i + 1); @@ -160,7 +160,7 @@ void CmmeInput::MakeSection(pugi::xml_node musicSectionNode) } } -void CmmeInput::MakeStaff(pugi::xml_node voiceNode) +void CmmeInput::CreateStaff(pugi::xml_node voiceNode) { assert(m_currentSection); @@ -179,25 +179,25 @@ void CmmeInput::MakeStaff(pugi::xml_node voiceNode) std::string name = eventNode.name(); if (name == "Clef") { if (this->IsClef(eventNode)) { - MakeClef(eventNode); + CreateClef(eventNode); } else { } } else if (name == "Dot") { - MakeDot(eventNode); + CreateDot(eventNode); } else if (name == "Mensuration") { - MakeMensuration(eventNode); + CreateMensuration(eventNode); } else if (name == "Note") { - MakeNote(eventNode); + CreateNote(eventNode); } else if (name == "OriginalText") { - MakeOriginalText(eventNode); + CreateOriginalText(eventNode); } else if (name == "Rest") { - MakeRest(eventNode); + CreateRest(eventNode); } else { LogWarning("Unsupported event '%s'", name.c_str()); @@ -208,7 +208,7 @@ void CmmeInput::MakeStaff(pugi::xml_node voiceNode) m_currentSection->AddChild(staff); } -void CmmeInput::MakeClef(pugi::xml_node clefNode) +void CmmeInput::CreateClef(pugi::xml_node clefNode) { static const std::map<std::string, data_CLEFSHAPE> shapeMap{ { "C", CLEFSHAPE_C }, // @@ -234,7 +234,7 @@ void CmmeInput::MakeClef(pugi::xml_node clefNode) return; } -void CmmeInput::MakeDot(pugi::xml_node dotNode) +void CmmeInput::CreateDot(pugi::xml_node dotNode) { assert(m_currentLayer); @@ -244,7 +244,7 @@ void CmmeInput::MakeDot(pugi::xml_node dotNode) return; } -void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) +void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) { assert(m_currentLayer); assert(m_mensInfo); @@ -276,7 +276,7 @@ void CmmeInput::MakeMensuration(pugi::xml_node mensurationNode) return; } -void CmmeInput::MakeNote(pugi::xml_node noteNode) +void CmmeInput::CreateNote(pugi::xml_node noteNode) { static const std::map<std::string, data_PITCHNAME> pitchMap{ { "C", PITCHNAME_c }, // @@ -317,12 +317,12 @@ void CmmeInput::MakeNote(pugi::xml_node noteNode) return; } -void CmmeInput::MakeOriginalText(pugi::xml_node originalTextNode) +void CmmeInput::CreateOriginalText(pugi::xml_node originalTextNode) { return; } -void CmmeInput::MakeRest(pugi::xml_node restNode) +void CmmeInput::CreateRest(pugi::xml_node restNode) { assert(m_currentLayer); From 69e64c794377bfafe01611b799b59dbe04b84bb6 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 22:15:53 +0200 Subject: [PATCH 010/105] Add comment --- src/iocmme.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 75fa6fa06c3..808fde0291a 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -141,6 +141,7 @@ void CmmeInput::CreateSection(pugi::xml_node musicSectionNode) section->SetType(sectionType); m_score->AddChild(section); + // the current section is a invisible measure m_currentSection = new Measure(UNMEASURED, 1); section->AddChild(m_currentSection); From 7420f7e7943ccd6e01562e0006a647b771a2625b Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Tue, 17 Sep 2024 22:32:31 +0200 Subject: [PATCH 011/105] Add syllables --- include/vrv/iocmme.h | 4 ++++ src/iocmme.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 7cc33ff071e..aa86d4a44f9 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -22,6 +22,7 @@ namespace vrv { class Clef; class Layer; class Measure; +class Note; class Score; namespace cmme { @@ -58,6 +59,8 @@ class CmmeInput : public Input { void CreateNote(pugi::xml_node noteNode); void CreateRest(pugi::xml_node restNode); + void CreateVerse(pugi::xml_node verseNode); + data_DURATION ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) const; bool IsClef(pugi::xml_node clefNode) const; @@ -76,6 +79,7 @@ class CmmeInput : public Input { Score *m_score; Measure *m_currentSection; Layer *m_currentLayer; + Note *m_currentNote; std::vector<cmme::mensInfo> m_mensInfos; cmme::mensInfo *m_mensInfo; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 808fde0291a..3dbebe2894a 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -33,7 +33,9 @@ #include "staff.h" #include "staffdef.h" #include "staffgrp.h" +#include "syl.h" #include "text.h" +#include "verse.h" #include "vrv.h" //---------------------------------------------------------------------------- @@ -49,6 +51,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_score = NULL; m_currentSection = NULL; m_currentLayer = NULL; + m_currentNote = NULL; m_mensInfo = NULL; } @@ -313,6 +316,12 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) note->SetColored(BOOLEAN_true); } + if (noteNode.child("ModernText")) { + m_currentNote = note; + CreateVerse(noteNode.child("ModernText")); + m_currentNote = NULL; + } + m_currentLayer->AddChild(note); return; @@ -342,6 +351,21 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) return; } +void CmmeInput::CreateVerse(pugi::xml_node verseNode) +{ + assert(m_currentNote); + + Verse *verse = new Verse(); + verse->SetN(1); + Syl *syl = new Syl(); + Text *text = new Text(); + std::string sylText = this->ChildAsString(verseNode, "Syllable"); + text->SetText(UTF8to32(sylText)); + syl->AddChild(text); + verse->AddChild(syl); + m_currentNote->AddChild(verse); +} + data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int &numbase) const { static const std::map<std::string, data_DURATION> durationMap{ From bb5fe592b21bd8a5c40c37a0e0606c0a5e47feae Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 08:10:51 +0200 Subject: [PATCH 012/105] Document the code --- include/vrv/iocmme.h | 14 ++++++++++++-- src/iocmme.cpp | 20 +++++++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index aa86d4a44f9..258f81b28c4 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -65,25 +65,35 @@ class CmmeInput : public Input { bool IsClef(pugi::xml_node clefNode) const; /** - * Helper methods for accessing and converting text in elements + * Helper methods for accessing and converting text in elements. + * Return "" or VRV_UNSET if the node is NULL or the node or the text not found */ + ///@{ std::string AsString(const pugi::xml_node node) const; std::string ChildAsString(const pugi::xml_node node, const std::string &child) const; int AsInt(const pugi::xml_node node) const; int ChildAsInt(const pugi::xml_node node, const std::string &child) const; + ///@} public: // private: - // + /** The current score (only one) */ Score *m_score; + /** The current un-measured measure acting a a MEI section */ Measure *m_currentSection; + /** The current layer (or container) to which the layer elements have to be added */ Layer *m_currentLayer; + /** The current note */ Note *m_currentNote; + /** The mensural infos for all voices */ std::vector<cmme::mensInfo> m_mensInfos; + /** The mensural info for the current voice */ cmme::mensInfo *m_mensInfo; + /** The number of voices as given in the general data */ int m_numVoices; + /** The name of the voices - if any */ std::vector<std::string> m_voices; }; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 3dbebe2894a..8476f64188a 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -76,14 +76,15 @@ bool CmmeInput::Import(const std::string &cmme) m_score = new Score(); mdiv->AddChild(m_score); + // We asssume that there is always as many Voice elements than given in NumVoices pugi::xpath_node_set voices = root.select_nodes("/Piece/VoiceData/Voice"); - for (pugi::xpath_node voiceNode : voices) { m_numVoices++; // Get the voice name if any std::string name = ChildAsString(voiceNode.node(), "Name"); m_voices.push_back(name); } + // Allocatate the mensural infos initialized with everything binary m_mensInfos.resize(m_numVoices); pugi::xpath_node_set musicSections = root.select_nodes("/Piece/MusicSection/*"); @@ -123,7 +124,6 @@ bool CmmeInput::Import(const std::string &cmme) m_score->GetScoreDef()->AddChild(staffGrp); m_doc->ConvertToPageBasedDoc(); - // return this->ReadDoc(root); } catch (char *str) { LogError("%s", str); @@ -139,17 +139,17 @@ void CmmeInput::CreateSection(pugi::xml_node musicSectionNode) std::string sectionType = musicSectionNode.name(); - // the section + // Create a new section Section *section = new Section(); + // Add the section type (MensuralMusic, Plainchant) to `@type` section->SetType(sectionType); m_score->AddChild(section); - // the current section is a invisible measure + // Set the current section to an invisible unmeasured measure m_currentSection = new Measure(UNMEASURED, 1); section->AddChild(m_currentSection); - pugi::xpath_node_set voices = musicSectionNode.select_nodes("./Voice"); - + // Loop through the number of voices and parse Voice or create an empty staff if not given for (int i = 0; i < m_numVoices; ++i) { std::string xpath = StringFormat("./Voice[VoiceNum[text()='%d']]", i + 1); pugi::xpath_node voice = musicSectionNode.select_node(xpath.c_str()); @@ -174,10 +174,11 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) m_currentLayer = new Layer(); m_currentLayer->SetN(1); + // (Re)-set the current mens info to the corresponding voice m_mensInfo = &m_mensInfos.at(numVoice - 1); + // Loop through the event lists pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); - for (pugi::xpath_node event : events) { pugi::xml_node eventNode = event.node(); std::string name = eventNode.name(); @@ -230,6 +231,7 @@ void CmmeInput::CreateClef(pugi::xml_node clefNode) clef->SetLine(staffLoc); std::string appearance = this->ChildAsString(clefNode, "Appearance"); + // Default clef to C data_CLEFSHAPE shape = shapeMap.contains(appearance) ? shapeMap.at(appearance) : CLEFSHAPE_C; clef->SetShape(shape); @@ -296,6 +298,7 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) Note *note = new Note(); std::string step = this->ChildAsString(noteNode, "LetterName"); + // Default pitch to C data_PITCHNAME pname = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; note->SetPname(pname); @@ -382,6 +385,7 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int assert(m_mensInfo); std::string type = this->ChildAsString(durationNode, "Type"); + // Default duration to brevis data_DURATION duration = durationMap.contains(type) ? durationMap.at(type) : DURATION_brevis; num = VRV_UNSET; @@ -432,8 +436,10 @@ bool CmmeInput::IsClef(const pugi::xml_node clefNode) const { static std::vector<std::string> clefs = { "C", "F", "Fsqr", "Frnd", "G" }; + // Checking this is not enough since it is somethimes missing in CMME files if (clefNode.select_node("./Signature")) return false; + // Also check the clef appearance std::string appearance = this->ChildAsString(clefNode, "Appearance"); return (std::find(clefs.begin(), clefs.end(), appearance) != clefs.end()); } From df88b743cdf5331e888d6b3c85ec58bf08bcdfb9 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 09:50:07 +0200 Subject: [PATCH 013/105] Add syllable connectors --- include/vrv/iocmme.h | 2 ++ src/iocmme.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 258f81b28c4..7cefb1377f1 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -86,6 +86,8 @@ class CmmeInput : public Input { Layer *m_currentLayer; /** The current note */ Note *m_currentNote; + /** The syllable is not the first */ + bool m_isInSyllable; /** The mensural infos for all voices */ std::vector<cmme::mensInfo> m_mensInfos; /** The mensural info for the current voice */ diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 8476f64188a..e24fb6ca4ab 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -52,6 +52,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_currentSection = NULL; m_currentLayer = NULL; m_currentNote = NULL; + m_isInSyllable = false; m_mensInfo = NULL; } @@ -176,6 +177,8 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) // (Re)-set the current mens info to the corresponding voice m_mensInfo = &m_mensInfos.at(numVoice - 1); + // Reset the syllable position + m_isInSyllable = false; // Loop through the event lists pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); @@ -364,6 +367,22 @@ void CmmeInput::CreateVerse(pugi::xml_node verseNode) Text *text = new Text(); std::string sylText = this->ChildAsString(verseNode, "Syllable"); text->SetText(UTF8to32(sylText)); + + if (verseNode.child("WordEnd")) { + syl->SetWordpos(sylLog_WORDPOS_t); + m_isInSyllable = false; + } + else { + if (m_isInSyllable) { + syl->SetWordpos(sylLog_WORDPOS_m); + } + else { + syl->SetWordpos(sylLog_WORDPOS_i); + } + m_isInSyllable = true; + syl->SetCon(sylLog_CON_d); + } + syl->AddChild(text); verse->AddChild(syl); m_currentNote->AddChild(verse); From 88cbc16dca50d2bf78cd6ba24b7a5e2ee9ddfc8e Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 11:03:24 +0200 Subject: [PATCH 014/105] Add key signatures --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 7cefb1377f1..132be0b66ae 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -54,6 +54,7 @@ class CmmeInput : public Input { void CreateClef(pugi::xml_node clefNode); void CreateDot(pugi::xml_node dotNode); + void CreateKeySig(pugi::xml_node keyNode); void CreateMensuration(pugi::xml_node mensurationNode); void CreateOriginalText(pugi::xml_node originalTextNode); void CreateNote(pugi::xml_node noteNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index e24fb6ca4ab..eeb161712c3 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -21,6 +21,8 @@ #include "clef.h" #include "doc.h" #include "dot.h" +#include "keyaccid.h" +#include "keysig.h" #include "label.h" #include "layer.h" #include "mdiv.h" @@ -190,6 +192,7 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) CreateClef(eventNode); } else { + CreateKeySig(eventNode); } } else if (name == "Dot") { @@ -253,6 +256,49 @@ void CmmeInput::CreateDot(pugi::xml_node dotNode) return; } +void CmmeInput::CreateKeySig(pugi::xml_node keyNode) +{ + assert(m_currentLayer); + + static const std::map<std::string, data_ACCIDENTAL_WRITTEN> shapeMap{ + { "Bmol", ACCIDENTAL_WRITTEN_f }, // + { "BmolDouble", ACCIDENTAL_WRITTEN_f }, // + { "Bqua", ACCIDENTAL_WRITTEN_n }, // + { "Diesis", ACCIDENTAL_WRITTEN_s }, // + }; + + KeySig *keysig = new KeySig(); + KeyAccid *keyaccid = new KeyAccid(); + std::string appearance = this->ChildAsString(keyNode, "Appearance"); + data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; + keyaccid->SetAccid(accid); + + static const std::map<std::string, data_PITCHNAME> pitchMap{ + { "C", PITCHNAME_c }, // + { "D", PITCHNAME_d }, // + { "E", PITCHNAME_e }, // + { "F", PITCHNAME_f }, // + { "G", PITCHNAME_g }, // + { "A", PITCHNAME_a }, // + { "B", PITCHNAME_b } // + }; + + std::string step = this->ChildAsString(keyNode, "Pitch/LetterName"); + // Default pitch to C + data_PITCHNAME pname = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; + keyaccid->SetPname(pname); + + int oct = this->ChildAsInt(keyNode, "Pitch/OctaveNum"); + if ((pname != PITCHNAME_a) && (pname != PITCHNAME_b)) oct += 1; + keyaccid->SetOct(oct); + + int staffLoc = this->ChildAsInt(keyNode, "StaffLoc"); + keyaccid->SetLoc(staffLoc - 1); + + m_currentLayer->AddChild(keysig); + keysig->AddChild(keyaccid); +} + void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) { assert(m_currentLayer); From 2f9eead00d13ac61029ff4c73232c38a4a8cff7d Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 11:27:43 +0200 Subject: [PATCH 015/105] Add fermata support for CMME --- src/iocmme.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index e24fb6ca4ab..a909af03fc3 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -327,6 +327,10 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) CreateVerse(noteNode.child("ModernText")); m_currentNote = NULL; } + + if (noteNode.child("Corona")) { + note->SetFermata(STAFFREL_basic_above); + } m_currentLayer->AddChild(note); From 49553d8a137a011c947e9bc7ae3d919b9a553063 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 11:37:17 +0200 Subject: [PATCH 016/105] Add support for accids --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 62 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 132be0b66ae..a0def5be56a 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -52,6 +52,7 @@ class CmmeInput : public Input { void CreateSection(pugi::xml_node musicSectionNode); void CreateStaff(pugi::xml_node voiceNode); + void CreateAccid(pugi::xml_node accidNode); void CreateClef(pugi::xml_node clefNode); void CreateDot(pugi::xml_node dotNode); void CreateKeySig(pugi::xml_node keyNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index eeb161712c3..ec5ee25b68d 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -191,9 +191,12 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) if (this->IsClef(eventNode)) { CreateClef(eventNode); } - else { + else if (eventNode.select_node("./Signature")) { CreateKeySig(eventNode); } + else { + CreateAccid(eventNode); + } } else if (name == "Dot") { CreateDot(eventNode); @@ -219,6 +222,47 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) m_currentSection->AddChild(staff); } +void CmmeInput::CreateAccid(pugi::xml_node accidNode) +{ + static const std::map<std::string, data_ACCIDENTAL_WRITTEN> shapeMap{ + { "Bmol", ACCIDENTAL_WRITTEN_f }, // + { "BmolDouble", ACCIDENTAL_WRITTEN_f }, // + { "Bqua", ACCIDENTAL_WRITTEN_n }, // + { "Diesis", ACCIDENTAL_WRITTEN_s }, // + }; + + static const std::map<std::string, data_PITCHNAME> pitchMap{ + { "C", PITCHNAME_c }, // + { "D", PITCHNAME_d }, // + { "E", PITCHNAME_e }, // + { "F", PITCHNAME_f }, // + { "G", PITCHNAME_g }, // + { "A", PITCHNAME_a }, // + { "B", PITCHNAME_b } // + }; + + assert(m_currentLayer); + + Accid *accidElement = new Accid(); + std::string appearance = this->ChildAsString(accidNode, "Appearance"); + data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; + accidElement->SetAccid(accid); + + std::string step = this->ChildAsString(accidNode, "Pitch/LetterName"); + // Default pitch to C + data_PITCHNAME ploc = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; + accidElement->SetPloc(ploc); + + int oct = this->ChildAsInt(accidNode, "Pitch/OctaveNum"); + if ((ploc != PITCHNAME_a) && (ploc != PITCHNAME_b)) oct += 1; + accidElement->SetOloc(oct); + + int staffLoc = this->ChildAsInt(accidNode, "StaffLoc"); + accidElement->SetLoc(staffLoc - 1); + + m_currentLayer->AddChild(accidElement); +} + void CmmeInput::CreateClef(pugi::xml_node clefNode) { static const std::map<std::string, data_CLEFSHAPE> shapeMap{ @@ -258,8 +302,6 @@ void CmmeInput::CreateDot(pugi::xml_node dotNode) void CmmeInput::CreateKeySig(pugi::xml_node keyNode) { - assert(m_currentLayer); - static const std::map<std::string, data_ACCIDENTAL_WRITTEN> shapeMap{ { "Bmol", ACCIDENTAL_WRITTEN_f }, // { "BmolDouble", ACCIDENTAL_WRITTEN_f }, // @@ -267,12 +309,6 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) { "Diesis", ACCIDENTAL_WRITTEN_s }, // }; - KeySig *keysig = new KeySig(); - KeyAccid *keyaccid = new KeyAccid(); - std::string appearance = this->ChildAsString(keyNode, "Appearance"); - data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; - keyaccid->SetAccid(accid); - static const std::map<std::string, data_PITCHNAME> pitchMap{ { "C", PITCHNAME_c }, // { "D", PITCHNAME_d }, // @@ -283,6 +319,14 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) { "B", PITCHNAME_b } // }; + assert(m_currentLayer); + + KeySig *keysig = new KeySig(); + KeyAccid *keyaccid = new KeyAccid(); + std::string appearance = this->ChildAsString(keyNode, "Appearance"); + data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; + keyaccid->SetAccid(accid); + std::string step = this->ChildAsString(keyNode, "Pitch/LetterName"); // Default pitch to C data_PITCHNAME pname = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; From b138848eb21e8dd601109966017deb8a1d631713 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 11:40:39 +0200 Subject: [PATCH 017/105] Skip accidental adjustment when not descendant of a note --- src/adjustaccidxfunctor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/adjustaccidxfunctor.cpp b/src/adjustaccidxfunctor.cpp index 7bc8b01512d..d33a6038e56 100644 --- a/src/adjustaccidxfunctor.cpp +++ b/src/adjustaccidxfunctor.cpp @@ -60,6 +60,9 @@ FunctorCode AdjustAccidXFunctor::VisitAlignmentReference(AlignmentReference *ali for (Accid *accid : accids) { // Skip any accid that was already adjusted if (m_adjustedAccids.count(accid) > 0) continue; + // Skip accid not descendant of a note (e.g., mensural) + if (!accid->GetFirstAncestor(NOTE)) continue; + auto range = octaveEquivalence.equal_range(accid); // Handle at least two octave accids without unisons int octaveAccidCount = 0; From 155c81b5a9c197c4952acb934229496bb057f46e Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 11:53:45 +0200 Subject: [PATCH 018/105] Add support for CMME modern accidentals --- src/iocmme.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index a909af03fc3..ddfd17c9327 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -17,6 +17,7 @@ //---------------------------------------------------------------------------- +#include "accid.h" #include "barline.h" #include "clef.h" #include "doc.h" @@ -297,6 +298,16 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) { "B", PITCHNAME_b } // }; + static const std::map<int, data_ACCIDENTAL_WRITTEN> accidMap{ + { -3, ACCIDENTAL_WRITTEN_tf }, // + { -2, ACCIDENTAL_WRITTEN_ff }, // + { -1, ACCIDENTAL_WRITTEN_f }, // + { 0, ACCIDENTAL_WRITTEN_n }, // + { 1, ACCIDENTAL_WRITTEN_s }, // + { 2, ACCIDENTAL_WRITTEN_ss }, // + { 3, ACCIDENTAL_WRITTEN_sx }, // + }; + assert(m_currentLayer); Note *note = new Note(); @@ -327,11 +338,23 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) CreateVerse(noteNode.child("ModernText")); m_currentNote = NULL; } - + if (noteNode.child("Corona")) { note->SetFermata(STAFFREL_basic_above); } + if (noteNode.child("ModernAccidental")) { + Accid *accid = new Accid(); + int offset = this->ChildAsInt(noteNode.child("ModernAccidental"), "PitchOffset"); + offset = std::min(3, offset); + offset = std::max(-3, offset); + // Default pitch to C + data_ACCIDENTAL_WRITTEN accidWritten = accidMap.contains(offset) ? accidMap.at(offset) : ACCIDENTAL_WRITTEN_n; + accid->SetAccid(accidWritten); + accid->SetFunc(accidLog_FUNC_edit); + note->AddChild(accid); + } + m_currentLayer->AddChild(note); return; From b723eabcc90844e4d0d89af0d7dbf611c4841e0f Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 12:03:23 +0200 Subject: [PATCH 019/105] Add support for stem direction and position in CMME --- src/iocmme.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index ddfd17c9327..9fed096b9c6 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -308,6 +308,13 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) { 3, ACCIDENTAL_WRITTEN_sx }, // }; + static const std::map<std::string, data_STEMDIRECTION> stemDirMap{ + { "Up", STEMDIRECTION_up }, // + { "Down", STEMDIRECTION_down }, // + { "Left", STEMDIRECTION_left }, // + { "Right", STEMDIRECTION_right }, // + }; + assert(m_currentLayer); Note *note = new Note(); @@ -355,6 +362,23 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) note->AddChild(accid); } + if (noteNode.child("Stem")) { + std::string dir = this->ChildAsString(noteNode.child("Stem"), "Dir"); + if (dir == "Barline") { + LogWarning("Unsupported 'Barline' stem direction"); + } + data_STEMDIRECTION stemDir = stemDirMap.contains(dir) ? stemDirMap.at(dir) : STEMDIRECTION_NONE; + note->SetStemDir(STEMDIRECTION_down); + + std::string side = this->ChildAsString(noteNode.child("Stem"), "Side"); + if (side == "Left") { + note->SetStemPos(STEMPOSITION_left); + } + else if (side == "Right") { + note->SetStemPos(STEMPOSITION_right); + } + } + m_currentLayer->AddChild(note); return; From cdad08508b61f296cb07534bfadd53a29e802428 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 12:04:11 +0200 Subject: [PATCH 020/105] Add support for signatures with multiple components in cmme --- include/vrv/iocmme.h | 3 +++ src/iocmme.cpp | 19 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index a0def5be56a..1e5ce08bad7 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -20,6 +20,7 @@ namespace vrv { class Clef; +class KeySig; class Layer; class Measure; class Note; @@ -86,6 +87,8 @@ class CmmeInput : public Input { Measure *m_currentSection; /** The current layer (or container) to which the layer elements have to be added */ Layer *m_currentLayer; + /** The current key signature to which extra flats might be added */ + KeySig *m_currentSignature; /** The current note */ Note *m_currentNote; /** The syllable is not the first */ diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 21731046d05..dca15cafde1 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -53,6 +53,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_score = NULL; m_currentSection = NULL; m_currentLayer = NULL; + m_currentSignature = NULL; m_currentNote = NULL; m_isInSyllable = false; m_mensInfo = NULL; @@ -181,6 +182,8 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) m_mensInfo = &m_mensInfos.at(numVoice - 1); // Reset the syllable position m_isInSyllable = false; + bool keySigFound = false; + m_currentSignature = NULL; // Loop through the event lists pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); @@ -192,6 +195,7 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) CreateClef(eventNode); } else if (eventNode.select_node("./Signature")) { + keySigFound = true; CreateKeySig(eventNode); } else { @@ -216,6 +220,10 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) else { LogWarning("Unsupported event '%s'", name.c_str()); } + if (!keySigFound) { + m_currentSignature = NULL; + } + keySigFound = false; } staff->AddChild(m_currentLayer); @@ -321,7 +329,11 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) assert(m_currentLayer); - KeySig *keysig = new KeySig(); + if (!m_currentSignature) { + m_currentSignature = new KeySig(); + m_currentLayer->AddChild(m_currentSignature); + } + KeyAccid *keyaccid = new KeyAccid(); std::string appearance = this->ChildAsString(keyNode, "Appearance"); data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; @@ -339,8 +351,7 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) int staffLoc = this->ChildAsInt(keyNode, "StaffLoc"); keyaccid->SetLoc(staffLoc - 1); - m_currentLayer->AddChild(keysig); - keysig->AddChild(keyaccid); + m_currentSignature->AddChild(keyaccid); } void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) @@ -417,7 +428,7 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) CreateVerse(noteNode.child("ModernText")); m_currentNote = NULL; } - + if (noteNode.child("Corona")) { note->SetFermata(STAFFREL_basic_above); } From 27ee36f529da9b4dad559bf50d175708d23d6f29 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 12:04:43 +0200 Subject: [PATCH 021/105] Fix formatting in src/adjustaccidxfunctor.cpp --- src/adjustaccidxfunctor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adjustaccidxfunctor.cpp b/src/adjustaccidxfunctor.cpp index d33a6038e56..cd57103adee 100644 --- a/src/adjustaccidxfunctor.cpp +++ b/src/adjustaccidxfunctor.cpp @@ -62,7 +62,7 @@ FunctorCode AdjustAccidXFunctor::VisitAlignmentReference(AlignmentReference *ali if (m_adjustedAccids.count(accid) > 0) continue; // Skip accid not descendant of a note (e.g., mensural) if (!accid->GetFirstAncestor(NOTE)) continue; - + auto range = octaveEquivalence.equal_range(accid); // Handle at least two octave accids without unisons int octaveAccidCount = 0; From d97dae2acc4979701a8c696d18bf13bb5c3b781e Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 12:17:35 +0200 Subject: [PATCH 022/105] Add support for fermata below in CMME --- src/iocmme.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 07bfc2a6360..36556e004fc 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -448,7 +448,11 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) } if (noteNode.child("Corona")) { - note->SetFermata(STAFFREL_basic_above); + data_STAFFREL_basic position = STAFFREL_basic_above; + if (noteNode.select_node("Corona/Orientation[text()='Down']")) { + position = STAFFREL_basic_below; + } + note->SetFermata(position); } if (noteNode.child("ModernAccidental")) { From 9f769f7b3bfce740b533b5a75f75a132c15dad18 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 12:18:19 +0200 Subject: [PATCH 023/105] Add support for multi-event signatures in cmme --- src/iocmme.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index dca15cafde1..fdadf760432 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -208,6 +208,20 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) else if (name == "Mensuration") { CreateMensuration(eventNode); } + else if (name == "MultiEvent") { + /// Assuming that a multievent contains a key signature, all events are key signatures + if (eventNode.select_node("./Clef/Signature")) { + m_currentSignature = NULL; + pugi::xpath_node_set clefs = eventNode.select_nodes("./Clef"); + for (pugi::xpath_node clef : clefs) { + pugi::xml_node clefNode = clef.node(); + CreateKeySig(clefNode); + } + } + else { + LogWarning("Unsupported event '%s'", name.c_str()); + } + } else if (name == "Note") { CreateNote(eventNode); } @@ -225,7 +239,6 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) } keySigFound = false; } - staff->AddChild(m_currentLayer); m_currentSection->AddChild(staff); } From be293d079287cc76f6ee2207ad5d735793bc4bbd Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 12:31:09 +0200 Subject: [PATCH 024/105] Add custos from cmme file --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 1e5ce08bad7..1ea88672c95 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -55,6 +55,7 @@ class CmmeInput : public Input { void CreateAccid(pugi::xml_node accidNode); void CreateClef(pugi::xml_node clefNode); + void CreateCustos(pugi::xml_node custosNode); void CreateDot(pugi::xml_node dotNode); void CreateKeySig(pugi::xml_node keyNode); void CreateMensuration(pugi::xml_node mensurationNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index fdadf760432..ef238552168 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -19,6 +19,7 @@ #include "barline.h" #include "clef.h" +#include "custos.h" #include "doc.h" #include "dot.h" #include "keyaccid.h" @@ -202,6 +203,9 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) CreateAccid(eventNode); } } + else if (name == "Custos") { + CreateCustos(eventNode); + } else if (name == "Dot") { CreateDot(eventNode); } @@ -311,6 +315,35 @@ void CmmeInput::CreateClef(pugi::xml_node clefNode) return; } +void CmmeInput::CreateCustos(pugi::xml_node custosNode) +{ + static const std::map<std::string, data_PITCHNAME> pitchMap{ + { "C", PITCHNAME_c }, // + { "D", PITCHNAME_d }, // + { "E", PITCHNAME_e }, // + { "F", PITCHNAME_f }, // + { "G", PITCHNAME_g }, // + { "A", PITCHNAME_a }, // + { "B", PITCHNAME_b } // + }; + + assert(m_currentLayer); + + Custos *custos = new Custos(); + std::string step = this->ChildAsString(custosNode, "LetterName"); + // Default pitch to C + data_PITCHNAME pname = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; + custos->SetPname(pname); + + int oct = this->ChildAsInt(custosNode, "OctaveNum"); + if ((pname != PITCHNAME_a) && (pname != PITCHNAME_b)) oct += 1; + custos->SetOct(oct); + + m_currentLayer->AddChild(custos); + + return; +} + void CmmeInput::CreateDot(pugi::xml_node dotNode) { assert(m_currentLayer); From a66f8b7eadbc05c328224ec6fbc2d51af652ce6b Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 13:29:21 +0200 Subject: [PATCH 025/105] Add ligature support for CMME --- include/vrv/iocmme.h | 2 +- src/iocmme.cpp | 64 +++++++++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 1e5ce08bad7..2cca4ab2e7e 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -86,7 +86,7 @@ class CmmeInput : public Input { /** The current un-measured measure acting a a MEI section */ Measure *m_currentSection; /** The current layer (or container) to which the layer elements have to be added */ - Layer *m_currentLayer; + Object *m_currentContainer; /** The current key signature to which extra flats might be added */ KeySig *m_currentSignature; /** The current note */ diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 36556e004fc..163b2a5eaf6 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -26,6 +26,7 @@ #include "keysig.h" #include "label.h" #include "layer.h" +#include "ligature.h" #include "mdiv.h" #include "measure.h" #include "mensur.h" @@ -53,7 +54,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) { m_score = NULL; m_currentSection = NULL; - m_currentLayer = NULL; + m_currentContainer = NULL; m_currentSignature = NULL; m_currentNote = NULL; m_isInSyllable = false; @@ -176,8 +177,9 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) int numVoice = this->ChildAsInt(voiceNode, "VoiceNum"); Staff *staff = new Staff(numVoice); - m_currentLayer = new Layer(); - m_currentLayer->SetN(1); + Layer *layer = new Layer(); + layer->SetN(1); + m_currentContainer = layer; // (Re)-set the current mens info to the corresponding voice m_mensInfo = &m_mensInfos.at(numVoice - 1); @@ -227,7 +229,7 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) keySigFound = false; } - staff->AddChild(m_currentLayer); + staff->AddChild(m_currentContainer); m_currentSection->AddChild(staff); } @@ -250,7 +252,7 @@ void CmmeInput::CreateAccid(pugi::xml_node accidNode) { "B", PITCHNAME_b } // }; - assert(m_currentLayer); + assert(m_currentContainer); Accid *accidElement = new Accid(); std::string appearance = this->ChildAsString(accidNode, "Appearance"); @@ -269,7 +271,7 @@ void CmmeInput::CreateAccid(pugi::xml_node accidNode) int staffLoc = this->ChildAsInt(accidNode, "StaffLoc"); accidElement->SetLoc(staffLoc - 1); - m_currentLayer->AddChild(accidElement); + m_currentContainer->AddChild(accidElement); } void CmmeInput::CreateClef(pugi::xml_node clefNode) @@ -282,7 +284,7 @@ void CmmeInput::CreateClef(pugi::xml_node clefNode) { "Fsqr", CLEFSHAPE_F }, // }; - assert(m_currentLayer); + assert(m_currentContainer); Clef *clef = new Clef(); int staffLoc = this->ChildAsInt(clefNode, "StaffLoc"); @@ -294,17 +296,17 @@ void CmmeInput::CreateClef(pugi::xml_node clefNode) data_CLEFSHAPE shape = shapeMap.contains(appearance) ? shapeMap.at(appearance) : CLEFSHAPE_C; clef->SetShape(shape); - m_currentLayer->AddChild(clef); + m_currentContainer->AddChild(clef); return; } void CmmeInput::CreateDot(pugi::xml_node dotNode) { - assert(m_currentLayer); + assert(m_currentContainer); Dot *dot = new Dot(); - m_currentLayer->AddChild(dot); + m_currentContainer->AddChild(dot); return; } @@ -328,11 +330,11 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) { "B", PITCHNAME_b } // }; - assert(m_currentLayer); + assert(m_currentContainer); if (!m_currentSignature) { m_currentSignature = new KeySig(); - m_currentLayer->AddChild(m_currentSignature); + m_currentContainer->AddChild(m_currentSignature); } KeyAccid *keyaccid = new KeyAccid(); @@ -357,7 +359,7 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) { - assert(m_currentLayer); + assert(m_currentContainer); assert(m_mensInfo); pugi::xml_node mensInfo = mensurationNode.child("MensInfo"); @@ -382,7 +384,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) data_BOOLEAN dot = (m_mensInfo->prolatio == 3) ? BOOLEAN_true : BOOLEAN_false; mensur->SetDot(dot); - m_currentLayer->AddChild(mensur); + m_currentContainer->AddChild(mensur); return; } @@ -416,7 +418,7 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) { "Right", STEMDIRECTION_right }, // }; - assert(m_currentLayer); + assert(m_currentContainer); Note *note = new Note(); std::string step = this->ChildAsString(noteNode, "LetterName"); @@ -473,7 +475,7 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) LogWarning("Unsupported 'Barline' stem direction"); } data_STEMDIRECTION stemDir = stemDirMap.contains(dir) ? stemDirMap.at(dir) : STEMDIRECTION_NONE; - note->SetStemDir(STEMDIRECTION_down); + note->SetStemDir(stemDir); std::string side = this->ChildAsString(noteNode.child("Stem"), "Side"); if (side == "Left") { @@ -484,7 +486,31 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) } } - m_currentLayer->AddChild(note); + if (noteNode.child("Lig")) { + std::string lig = this->ChildAsString(noteNode, "Lig"); + if (lig == "Retrorsum") { + LogWarning("Unsupported 'Retrorsum' ligature"); + } + data_LIGATUREFORM form = (lig == "Obliqua") ? LIGATUREFORM_obliqua : LIGATUREFORM_recta; + // First note of the ligature, create the ligature element + if (!m_currentContainer->Is(LIGATURE)) { + Ligature *ligature = new Ligature(); + ligature->SetForm(form); + m_currentContainer->AddChild(ligature); + m_currentContainer = ligature; + } + // Otherwise simply add the `@lig` to the note + else { + note->SetLig(form); + } + } + + m_currentContainer->AddChild(note); + + // We have processed the last note of a ligature + if (m_currentContainer->Is(LIGATURE) && !noteNode.child("Lig")) { + m_currentContainer = m_currentContainer->GetParent(); + } return; } @@ -496,7 +522,7 @@ void CmmeInput::CreateOriginalText(pugi::xml_node originalTextNode) void CmmeInput::CreateRest(pugi::xml_node restNode) { - assert(m_currentLayer); + assert(m_currentContainer); Rest *rest = new Rest(); int num; @@ -508,7 +534,7 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) rest->SetNum(numbase); } - m_currentLayer->AddChild(rest); + m_currentContainer->AddChild(rest); return; } From e0f6e981b77c66f2cc3223d734cff04dd4b62cc7 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 14:36:09 +0200 Subject: [PATCH 026/105] Pull develop-cmme --- include/vrv/iocmme.h | 4 +++ src/iocmme.cpp | 78 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 08fddf9573f..a6660198c59 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -52,6 +52,10 @@ class CmmeInput : public Input { private: void CreateSection(pugi::xml_node musicSectionNode); void CreateStaff(pugi::xml_node voiceNode); + void CreateApp(pugi::xml_node appNode); + void CreateLemOrRdg(pugi::xml_node lemOrRdgNode, bool isFirst); + + void ReadEvents(pugi::xml_node eventsNode); void CreateAccid(pugi::xml_node accidNode); void CreateClef(pugi::xml_node clefNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 9f17a8ca1b2..afb6c2cf0dd 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -18,6 +18,7 @@ //---------------------------------------------------------------------------- #include "accid.h" +#include "app.h" #include "barline.h" #include "clef.h" #include "custos.h" @@ -27,11 +28,13 @@ #include "keysig.h" #include "label.h" #include "layer.h" +#include "lem.h" #include "ligature.h" #include "mdiv.h" #include "measure.h" #include "mensur.h" #include "note.h" +#include "rdg.h" #include "rest.h" #include "score.h" #include "section.h" @@ -186,11 +189,75 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) m_mensInfo = &m_mensInfos.at(numVoice - 1); // Reset the syllable position m_isInSyllable = false; - bool keySigFound = false; m_currentSignature = NULL; // Loop through the event lists - pugi::xpath_node_set events = voiceNode.select_nodes("./EventList/*"); + ReadEvents(voiceNode.child("EventList")); + + staff->AddChild(m_currentContainer); + m_currentSection->AddChild(staff); +} + +void CmmeInput::CreateApp(pugi::xml_node appNode) +{ + assert(m_currentContainer); + + App *app = new App(EDITORIAL_LAYER); + m_currentContainer->AddChild(app); + m_currentContainer = app; + + // Loop through the event lists + pugi::xpath_node_set lemOrRdgs = appNode.select_nodes("./Reading"); + bool isFirst = true; + for (pugi::xpath_node lemOrRdg : lemOrRdgs) { + pugi::xml_node lemOrRdgNode = lemOrRdg.node(); + this->CreateLemOrRdg(lemOrRdgNode, isFirst); + isFirst = false; + } + + m_currentContainer = m_currentContainer->GetParent(); +} + +void CmmeInput::CreateLemOrRdg(pugi::xml_node lemOrRdgNode, bool isFirst) +{ + assert(m_currentContainer); + std::string versionId = this->ChildAsString(lemOrRdgNode, "VariantVersionID"); + + EditorialElement *lemOrRdg = NULL; + if (isFirst && (lemOrRdgNode.child("PreferredReading") || (versionId == "DEFAULT"))) { + lemOrRdg = new Lem(); + } + else { + lemOrRdg = new Rdg(); + } + lemOrRdg->m_visibility = (isFirst) ? Visible : Hidden; + + if (lemOrRdg->Is(RDG)) lemOrRdg->SetLabel(versionId); + + if (lemOrRdgNode.child("Error")) { + lemOrRdg->SetType("Error"); + } + else if (lemOrRdgNode.child("Lacuna")) { + lemOrRdg->SetType("Lacuna"); + } + + m_currentContainer->AddChild(lemOrRdg); + + m_currentContainer = lemOrRdg; + + ReadEvents(lemOrRdgNode.child("Music")); + + m_currentContainer = m_currentContainer->GetParent(); +} + +void CmmeInput::ReadEvents(pugi::xml_node eventsNode) +{ + assert(m_currentContainer); + + bool keySigFound = false; + + // Loop through the event lists + pugi::xpath_node_set events = eventsNode.select_nodes("./*"); for (pugi::xpath_node event : events) { pugi::xml_node eventNode = event.node(); std::string name = eventNode.name(); @@ -238,6 +305,9 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) else if (name == "Rest") { CreateRest(eventNode); } + else if (name == "VariantReadings") { + CreateApp(eventNode); + } else { LogWarning("Unsupported event '%s'", name.c_str()); } @@ -246,10 +316,6 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) } keySigFound = false; } - - staff->AddChild(m_currentContainer); - - m_currentSection->AddChild(staff); } void CmmeInput::CreateAccid(pugi::xml_node accidNode) From 8ac88cddc1079dd6ea2f3829356f2d47ad2f7579 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 15:05:13 +0200 Subject: [PATCH 027/105] Add support for cmme barlines --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 1ea88672c95..19f5bd03a67 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -54,6 +54,7 @@ class CmmeInput : public Input { void CreateStaff(pugi::xml_node voiceNode); void CreateAccid(pugi::xml_node accidNode); + void CreateBarline(pugi::xml_node barlineNode); void CreateClef(pugi::xml_node clefNode); void CreateCustos(pugi::xml_node custosNode); void CreateDot(pugi::xml_node dotNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index ef238552168..14a03519e67 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -212,6 +212,13 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) else if (name == "Mensuration") { CreateMensuration(eventNode); } + else if (name == "MiscItem") { + /// Assuming that a MiscItem contains only one child + if (eventNode.select_node("./Barline")) { + pugi::xml_node barlineNode = eventNode.select_node("./Barline").node(); + CreateBarline(barlineNode); + } + } else if (name == "MultiEvent") { /// Assuming that a multievent contains a key signature, all events are key signatures if (eventNode.select_node("./Clef/Signature")) { @@ -288,6 +295,40 @@ void CmmeInput::CreateAccid(pugi::xml_node accidNode) m_currentLayer->AddChild(accidElement); } +void CmmeInput::CreateBarline(pugi::xml_node barlineNode) +{ + assert(m_currentLayer); + + BarLine *barline = new BarLine(); + + /// Determine the barLine/@form based on the CMME <Barline>'s <NumLines> and <RepeatSign> + int formNumLines = this->ChildAsInt(barlineNode, "NumLines"); + if (formNumLines == 1) { + barline->SetForm(BARRENDITION_single); + } + else if (formNumLines == 2) { + barline->SetForm(BARRENDITION_dbl); + } + else if (formNumLines != VRV_UNSET) { + LogWarning("Unsupported barline (with more than 2 lines)"); + } ///@form is overwritten to 'rptboth' when <RepeatSign> is used + if (barlineNode.select_node("./RepeatSign")) { + barline->SetForm(BARRENDITION_rptboth); + } + /// Determine the barLine/@place + int bottomLine = this->ChildAsInt(barlineNode, "BottomStaffLine"); + if (bottomLine != VRV_UNSET) { + int place = bottomLine * 2; + barline->SetPlace(place); + } + /// Determine the barLine/@len + int numSpaces = this->ChildAsInt(barlineNode, "NumSpaces"); + if (numSpaces != VRV_UNSET) { + barline->SetLen(numSpaces * 2); + } + m_currentLayer->AddChild(barline); +} + void CmmeInput::CreateClef(pugi::xml_node clefNode) { static const std::map<std::string, data_CLEFSHAPE> shapeMap{ From 43bff2048a7fcda3df8dbf1d7f97e513da112547 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 15:12:39 +0200 Subject: [PATCH 028/105] Add support for annot (editorial commentary) in CMME --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 70 ++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index a6660198c59..96aa928b09c 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -56,6 +56,7 @@ class CmmeInput : public Input { void CreateLemOrRdg(pugi::xml_node lemOrRdgNode, bool isFirst); void ReadEvents(pugi::xml_node eventsNode); + void ReadEditorialCommentary(pugi::xml_node evenNode, Object *object); void CreateAccid(pugi::xml_node accidNode); void CreateClef(pugi::xml_node clefNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index afb6c2cf0dd..dc7dc953fc6 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -18,6 +18,7 @@ //---------------------------------------------------------------------------- #include "accid.h" +#include "annot.h" #include "app.h" #include "barline.h" #include "clef.h" @@ -191,11 +192,11 @@ void CmmeInput::CreateStaff(pugi::xml_node voiceNode) m_isInSyllable = false; m_currentSignature = NULL; - // Loop through the event lists - ReadEvents(voiceNode.child("EventList")); - staff->AddChild(m_currentContainer); m_currentSection->AddChild(staff); + + // Loop through the event lists + ReadEvents(voiceNode.child("EventList")); } void CmmeInput::CreateApp(pugi::xml_node appNode) @@ -318,6 +319,22 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) } } +void CmmeInput::ReadEditorialCommentary(pugi::xml_node eventNode, Object *object) +{ + std::string commentary = this->ChildAsString(eventNode, "EditorialCommentary"); + + if (!commentary.empty()) { + Annot *annot = new Annot(); + Text *text = new Text(); + text->SetText(UTF8to32(commentary)); + annot->AddChild(text); + xsdAnyURI_List list; + list.push_back("#" + object->GetID()); + annot->SetPlist(list); + m_currentSection->AddChild(annot); + } +} + void CmmeInput::CreateAccid(pugi::xml_node accidNode) { static const std::map<std::string, data_ACCIDENTAL_WRITTEN> shapeMap{ @@ -339,24 +356,27 @@ void CmmeInput::CreateAccid(pugi::xml_node accidNode) assert(m_currentContainer); - Accid *accidElement = new Accid(); + Accid *accid = new Accid(); std::string appearance = this->ChildAsString(accidNode, "Appearance"); - data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; - accidElement->SetAccid(accid); + data_ACCIDENTAL_WRITTEN accidWritten + = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; + accid->SetAccid(accidWritten); std::string step = this->ChildAsString(accidNode, "Pitch/LetterName"); // Default pitch to C data_PITCHNAME ploc = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; - accidElement->SetPloc(ploc); + accid->SetPloc(ploc); int oct = this->ChildAsInt(accidNode, "Pitch/OctaveNum"); if ((ploc != PITCHNAME_a) && (ploc != PITCHNAME_b)) oct += 1; - accidElement->SetOloc(oct); + accid->SetOloc(oct); int staffLoc = this->ChildAsInt(accidNode, "StaffLoc"); - accidElement->SetLoc(staffLoc - 1); + accid->SetLoc(staffLoc - 1); + + this->ReadEditorialCommentary(accidNode, accid); - m_currentContainer->AddChild(accidElement); + m_currentContainer->AddChild(accid); } void CmmeInput::CreateClef(pugi::xml_node clefNode) @@ -381,6 +401,8 @@ void CmmeInput::CreateClef(pugi::xml_node clefNode) data_CLEFSHAPE shape = shapeMap.contains(appearance) ? shapeMap.at(appearance) : CLEFSHAPE_C; clef->SetShape(shape); + this->ReadEditorialCommentary(clefNode, clef); + m_currentContainer->AddChild(clef); return; @@ -398,7 +420,7 @@ void CmmeInput::CreateCustos(pugi::xml_node custosNode) { "B", PITCHNAME_b } // }; - assert(m_currentLayer); + assert(m_currentContainer); Custos *custos = new Custos(); std::string step = this->ChildAsString(custosNode, "LetterName"); @@ -410,7 +432,9 @@ void CmmeInput::CreateCustos(pugi::xml_node custosNode) if ((pname != PITCHNAME_a) && (pname != PITCHNAME_b)) oct += 1; custos->SetOct(oct); - m_currentLayer->AddChild(custos); + this->ReadEditorialCommentary(custosNode, custos); + + m_currentContainer->AddChild(custos); return; } @@ -422,6 +446,8 @@ void CmmeInput::CreateDot(pugi::xml_node dotNode) Dot *dot = new Dot(); m_currentContainer->AddChild(dot); + this->ReadEditorialCommentary(dotNode, dot); + return; } @@ -451,24 +477,26 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) m_currentContainer->AddChild(m_currentSignature); } - KeyAccid *keyaccid = new KeyAccid(); + KeyAccid *keyAccid = new KeyAccid(); std::string appearance = this->ChildAsString(keyNode, "Appearance"); data_ACCIDENTAL_WRITTEN accid = shapeMap.contains(appearance) ? shapeMap.at(appearance) : ACCIDENTAL_WRITTEN_f; - keyaccid->SetAccid(accid); + keyAccid->SetAccid(accid); std::string step = this->ChildAsString(keyNode, "Pitch/LetterName"); // Default pitch to C data_PITCHNAME pname = pitchMap.contains(step) ? pitchMap.at(step) : PITCHNAME_c; - keyaccid->SetPname(pname); + keyAccid->SetPname(pname); int oct = this->ChildAsInt(keyNode, "Pitch/OctaveNum"); if ((pname != PITCHNAME_a) && (pname != PITCHNAME_b)) oct += 1; - keyaccid->SetOct(oct); + keyAccid->SetOct(oct); int staffLoc = this->ChildAsInt(keyNode, "StaffLoc"); - keyaccid->SetLoc(staffLoc - 1); + keyAccid->SetLoc(staffLoc - 1); + + this->ReadEditorialCommentary(keyNode, keyAccid); - m_currentSignature->AddChild(keyaccid); + m_currentSignature->AddChild(keyAccid); } void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) @@ -498,6 +526,8 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) data_BOOLEAN dot = (m_mensInfo->prolatio == 3) ? BOOLEAN_true : BOOLEAN_false; mensur->SetDot(dot); + this->ReadEditorialCommentary(mensurationNode, mensur); + m_currentContainer->AddChild(mensur); return; @@ -619,6 +649,8 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) } } + this->ReadEditorialCommentary(noteNode, note); + m_currentContainer->AddChild(note); // We have processed the last note of a ligature @@ -648,6 +680,8 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) rest->SetNum(numbase); } + this->ReadEditorialCommentary(restNode, rest); + m_currentContainer->AddChild(rest); return; From eb3bef151ad4d301508668afb915c2ec5a5d883e Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 15:40:15 +0200 Subject: [PATCH 029/105] Fixing m_currentLayer name change and cosmetic variable renaming --- src/iocmme.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 8a9e8abe24b..2c8799291b3 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -388,36 +388,39 @@ void CmmeInput::CreateAccid(pugi::xml_node accidNode) void CmmeInput::CreateBarline(pugi::xml_node barlineNode) { - assert(m_currentLayer); + assert(m_currentContainer); - BarLine *barline = new BarLine(); + BarLine *barLine = new BarLine(); - /// Determine the barLine/@form based on the CMME <Barline>'s <NumLines> and <RepeatSign> + // Determine the barLine/@form based on the CMME <Barline>'s <NumLines> and <RepeatSign> int formNumLines = this->ChildAsInt(barlineNode, "NumLines"); if (formNumLines == 1) { - barline->SetForm(BARRENDITION_single); + barLine->SetForm(BARRENDITION_single); } else if (formNumLines == 2) { - barline->SetForm(BARRENDITION_dbl); + barLine->SetForm(BARRENDITION_dbl); } else if (formNumLines != VRV_UNSET) { LogWarning("Unsupported barline (with more than 2 lines)"); - } ///@form is overwritten to 'rptboth' when <RepeatSign> is used + } + + // `@form` is overwritten to 'rptboth' when <RepeatSign> is used if (barlineNode.select_node("./RepeatSign")) { - barline->SetForm(BARRENDITION_rptboth); + barLine->SetForm(BARRENDITION_rptboth); } - /// Determine the barLine/@place + // Determine the barLine/@place int bottomLine = this->ChildAsInt(barlineNode, "BottomStaffLine"); if (bottomLine != VRV_UNSET) { int place = bottomLine * 2; - barline->SetPlace(place); + barLine->SetPlace(place); } - /// Determine the barLine/@len + // Determine the barLine/@len int numSpaces = this->ChildAsInt(barlineNode, "NumSpaces"); if (numSpaces != VRV_UNSET) { - barline->SetLen(numSpaces * 2); + barLine->SetLen(numSpaces * 2); } - m_currentLayer->AddChild(barline); + + m_currentContainer->AddChild(barLine); } void CmmeInput::CreateClef(pugi::xml_node clefNode) From 750a3e82cf2c45685b6d0c0e34ffaf07433c0580 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 16:26:44 +0200 Subject: [PATCH 030/105] Formatting with clang-format 18.1.8 --- include/vrv/beam.h | 2 +- include/vrv/boundingbox.h | 4 ++-- include/vrv/devicecontext.h | 2 +- include/vrv/devicecontextbase.h | 2 +- include/vrv/docselection.h | 2 +- include/vrv/floatingobject.h | 4 ++-- include/vrv/functorinterface.h | 4 ++-- include/vrv/interface.h | 4 ++-- include/vrv/iobase.h | 2 +- include/vrv/options.h | 4 ++-- include/vrv/resources.h | 4 ++-- include/vrv/textelement.h | 2 +- include/vrv/transposition.h | 2 +- 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/vrv/beam.h b/include/vrv/beam.h index 6f6b56482c0..fc10fce8b19 100644 --- a/include/vrv/beam.h +++ b/include/vrv/beam.h @@ -225,7 +225,7 @@ class BeamSegment { class BeamSpanSegment : public BeamSegment { public: BeamSpanSegment(); - virtual ~BeamSpanSegment(){}; + virtual ~BeamSpanSegment() {}; /** * Set/get methods for member variables diff --git a/include/vrv/boundingbox.h b/include/vrv/boundingbox.h index 20a437657c5..9b04e512297 100644 --- a/include/vrv/boundingbox.h +++ b/include/vrv/boundingbox.h @@ -37,7 +37,7 @@ class BoundingBox { */ ///@{ BoundingBox(); - virtual ~BoundingBox(){}; + virtual ~BoundingBox() {}; virtual ClassId GetClassId() const = 0; bool Is(ClassId classId) const { return (this->GetClassId() == classId); } bool Is(const std::vector<ClassId> &classIds) const; @@ -342,7 +342,7 @@ class SegmentedLine { */ ///@{ SegmentedLine(int start, int end); - virtual ~SegmentedLine(){}; + virtual ~SegmentedLine() {}; ///@} /** diff --git a/include/vrv/devicecontext.h b/include/vrv/devicecontext.h index 95c62a81208..05b1ee7a94a 100644 --- a/include/vrv/devicecontext.h +++ b/include/vrv/devicecontext.h @@ -92,7 +92,7 @@ class DeviceContext { m_pushBack = false; m_viewBoxFactor = (double)DEFINITION_FACTOR; } - virtual ~DeviceContext(){}; + virtual ~DeviceContext() {}; ClassId GetClassId() const { return m_classId; } bool Is(ClassId classId) const { return (m_classId == classId); } ///@} diff --git a/include/vrv/devicecontextbase.h b/include/vrv/devicecontextbase.h index faa51c6d05d..2a2cf7e1054 100644 --- a/include/vrv/devicecontextbase.h +++ b/include/vrv/devicecontextbase.h @@ -144,7 +144,7 @@ class FontInfo { m_widthToHeightRatio = 1.0; m_smuflFont = SMUFL_NONE; } - virtual ~FontInfo(){}; + virtual ~FontInfo() {}; // accessors and modifiers for the font elements int GetPointSize() const { return m_pointSize; } diff --git a/include/vrv/docselection.h b/include/vrv/docselection.h index 5bd30339161..9949347ff8e 100644 --- a/include/vrv/docselection.h +++ b/include/vrv/docselection.h @@ -29,7 +29,7 @@ class DocSelection { */ ///@{ DocSelection(); - virtual ~DocSelection(){}; + virtual ~DocSelection() {}; ///@} /** diff --git a/include/vrv/floatingobject.h b/include/vrv/floatingobject.h index f6cd1f450a3..5b0321c3edc 100644 --- a/include/vrv/floatingobject.h +++ b/include/vrv/floatingobject.h @@ -167,7 +167,7 @@ class FloatingPositioner : public BoundingBox { public: // constructors and destructors FloatingPositioner(FloatingObject *object, StaffAlignment *alignment, char spanningType); - virtual ~FloatingPositioner(){}; + virtual ~FloatingPositioner() {}; ClassId GetClassId() const override { return FLOATING_POSITIONER; } virtual void ResetPositioner(); @@ -485,7 +485,7 @@ class CurveSpannedElement { m_discarded = false; m_isBelow = true; } - virtual ~CurveSpannedElement(){}; + virtual ~CurveSpannedElement() {}; Point m_rotatedPoints[4]; const BoundingBox *m_boundingBox; diff --git a/include/vrv/functorinterface.h b/include/vrv/functorinterface.h index 38424282880..452df9a0fc7 100644 --- a/include/vrv/functorinterface.h +++ b/include/vrv/functorinterface.h @@ -156,7 +156,7 @@ class FunctorInterface { * @name Constructors, destructors */ ///@{ - FunctorInterface(){}; + FunctorInterface() {}; virtual ~FunctorInterface() = default; ///@} @@ -513,7 +513,7 @@ class ConstFunctorInterface { * @name Constructors, destructors */ ///@{ - ConstFunctorInterface(){}; + ConstFunctorInterface() {}; virtual ~ConstFunctorInterface() = default; ///@} diff --git a/include/vrv/interface.h b/include/vrv/interface.h index 7b389b85424..a957e63abe2 100644 --- a/include/vrv/interface.h +++ b/include/vrv/interface.h @@ -37,8 +37,8 @@ class Interface { * Reset method reset all attribute classes */ ///@{ - Interface(){}; - virtual ~Interface(){}; + Interface() {}; + virtual ~Interface() {}; ///@} /** diff --git a/include/vrv/iobase.h b/include/vrv/iobase.h index e5cfc903acc..8dcab892fe3 100644 --- a/include/vrv/iobase.h +++ b/include/vrv/iobase.h @@ -33,7 +33,7 @@ class Output { // constructors and destructors Output(Doc *doc, std::string filename); Output(Doc *doc); - Output(){}; + Output() {}; virtual ~Output(); /** diff --git a/include/vrv/options.h b/include/vrv/options.h index 0e9160240a7..a525e216fbd 100644 --- a/include/vrv/options.h +++ b/include/vrv/options.h @@ -417,8 +417,8 @@ class OptionIntMap : public Option { class OptionStaffrel : public Option { public: // constructors and destructors - OptionStaffrel(){}; - virtual ~OptionStaffrel(){}; + OptionStaffrel() {}; + virtual ~OptionStaffrel() {}; void CopyTo(Option *option) override; // Alternate type style cannot have a restricted list of possible values void Init(data_STAFFREL defaultValue); diff --git a/include/vrv/resources.h b/include/vrv/resources.h index 7988fb1faf4..94224baa8ee 100644 --- a/include/vrv/resources.h +++ b/include/vrv/resources.h @@ -136,8 +136,8 @@ class Resources { class LoadedFont { public: - LoadedFont(const std::string &name, bool isFallback) : m_name(name), m_isFallback(isFallback){}; - ~LoadedFont(){}; + LoadedFont(const std::string &name, bool isFallback) : m_name(name), m_isFallback(isFallback) {}; + ~LoadedFont() {}; const std::string GetName() const { return m_name; }; const GlyphTable &GetGlyphTable() const { return m_glyphTable; }; GlyphTable &GetGlyphTableForModification() { return m_glyphTable; }; diff --git a/include/vrv/textelement.h b/include/vrv/textelement.h index 2c334275484..c11bc8472ef 100644 --- a/include/vrv/textelement.h +++ b/include/vrv/textelement.h @@ -105,7 +105,7 @@ class TextDrawingParams { m_enclose = TEXTRENDITION_NONE; m_textEnclose = ENCLOSURE_NONE; } - virtual ~TextDrawingParams(){}; + virtual ~TextDrawingParams() {}; int m_x; int m_y; diff --git a/include/vrv/transposition.h b/include/vrv/transposition.h index 9359ab0e5f0..505ab7b1d48 100644 --- a/include/vrv/transposition.h +++ b/include/vrv/transposition.h @@ -43,7 +43,7 @@ class TransPitch { // octave number of pitch: 4 = middle-C octave int m_oct; - TransPitch(){}; + TransPitch() {}; TransPitch(int aPname, int anAccid, int anOct); TransPitch(data_PITCHNAME pname, data_ACCIDENTAL_GESTURAL accidG, data_ACCIDENTAL_WRITTEN accidW, int oct); TransPitch(const TransPitch &pitch); From f55b6ede44b51750a55a68fbc4c8130c72e3d302 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 16:46:38 +0200 Subject: [PATCH 031/105] Revert formatting --- include/vrv/beam.h | 2 +- include/vrv/boundingbox.h | 4 ++-- include/vrv/devicecontext.h | 12 ++++++------ include/vrv/devicecontextbase.h | 2 +- include/vrv/docselection.h | 2 +- include/vrv/floatingobject.h | 4 ++-- include/vrv/functorinterface.h | 4 ++-- include/vrv/interface.h | 4 ++-- include/vrv/iobase.h | 2 +- include/vrv/layerelement.h | 2 +- include/vrv/options.h | 4 ++-- include/vrv/resources.h | 4 ++-- include/vrv/textelement.h | 2 +- include/vrv/transposition.h | 2 +- include/vrv/view.h | 2 +- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/include/vrv/beam.h b/include/vrv/beam.h index fc10fce8b19..6f6b56482c0 100644 --- a/include/vrv/beam.h +++ b/include/vrv/beam.h @@ -225,7 +225,7 @@ class BeamSegment { class BeamSpanSegment : public BeamSegment { public: BeamSpanSegment(); - virtual ~BeamSpanSegment() {}; + virtual ~BeamSpanSegment(){}; /** * Set/get methods for member variables diff --git a/include/vrv/boundingbox.h b/include/vrv/boundingbox.h index 9b04e512297..20a437657c5 100644 --- a/include/vrv/boundingbox.h +++ b/include/vrv/boundingbox.h @@ -37,7 +37,7 @@ class BoundingBox { */ ///@{ BoundingBox(); - virtual ~BoundingBox() {}; + virtual ~BoundingBox(){}; virtual ClassId GetClassId() const = 0; bool Is(ClassId classId) const { return (this->GetClassId() == classId); } bool Is(const std::vector<ClassId> &classIds) const; @@ -342,7 +342,7 @@ class SegmentedLine { */ ///@{ SegmentedLine(int start, int end); - virtual ~SegmentedLine() {}; + virtual ~SegmentedLine(){}; ///@} /** diff --git a/include/vrv/devicecontext.h b/include/vrv/devicecontext.h index 05b1ee7a94a..fde5c18875d 100644 --- a/include/vrv/devicecontext.h +++ b/include/vrv/devicecontext.h @@ -92,7 +92,7 @@ class DeviceContext { m_pushBack = false; m_viewBoxFactor = (double)DEFINITION_FACTOR; } - virtual ~DeviceContext() {}; + virtual ~DeviceContext(){}; ClassId GetClassId() const { return m_classId; } bool Is(ClassId classId) const { return (m_classId == classId); } ///@} @@ -211,7 +211,7 @@ class DeviceContext { * Special method for forcing bounding boxes to be updated * Used for invisible elements (e.g., <space>) that needs to be take into account in spacing */ - virtual void DrawPlaceholder(int x, int y) {}; + virtual void DrawPlaceholder(int x, int y){}; /** * @name Method for starting and ending a text @@ -262,14 +262,14 @@ class DeviceContext { * For example, the method can be used for grouping shapes in <g></g> in SVG */ ///@{ - virtual void StartCustomGraphic(const std::string &name, std::string gClass = "", std::string gId = "") {}; - virtual void EndCustomGraphic() {}; + virtual void StartCustomGraphic(const std::string &name, std::string gClass = "", std::string gId = ""){}; + virtual void EndCustomGraphic(){}; ///@} /** * Method for changing the color of a custom graphic */ - virtual void SetCustomGraphicColor(const std::string &color) {}; + virtual void SetCustomGraphicColor(const std::string &color){}; /** * @name Methods for re-starting and ending a graphic for objects drawn in separate steps @@ -312,7 +312,7 @@ class DeviceContext { * @name Method for adding description element */ ///@{ - virtual void AddDescription(const std::string &text) {}; + virtual void AddDescription(const std::string &text){}; ///@} /** diff --git a/include/vrv/devicecontextbase.h b/include/vrv/devicecontextbase.h index 2a2cf7e1054..faa51c6d05d 100644 --- a/include/vrv/devicecontextbase.h +++ b/include/vrv/devicecontextbase.h @@ -144,7 +144,7 @@ class FontInfo { m_widthToHeightRatio = 1.0; m_smuflFont = SMUFL_NONE; } - virtual ~FontInfo() {}; + virtual ~FontInfo(){}; // accessors and modifiers for the font elements int GetPointSize() const { return m_pointSize; } diff --git a/include/vrv/docselection.h b/include/vrv/docselection.h index 9949347ff8e..5bd30339161 100644 --- a/include/vrv/docselection.h +++ b/include/vrv/docselection.h @@ -29,7 +29,7 @@ class DocSelection { */ ///@{ DocSelection(); - virtual ~DocSelection() {}; + virtual ~DocSelection(){}; ///@} /** diff --git a/include/vrv/floatingobject.h b/include/vrv/floatingobject.h index 5b0321c3edc..f6cd1f450a3 100644 --- a/include/vrv/floatingobject.h +++ b/include/vrv/floatingobject.h @@ -167,7 +167,7 @@ class FloatingPositioner : public BoundingBox { public: // constructors and destructors FloatingPositioner(FloatingObject *object, StaffAlignment *alignment, char spanningType); - virtual ~FloatingPositioner() {}; + virtual ~FloatingPositioner(){}; ClassId GetClassId() const override { return FLOATING_POSITIONER; } virtual void ResetPositioner(); @@ -485,7 +485,7 @@ class CurveSpannedElement { m_discarded = false; m_isBelow = true; } - virtual ~CurveSpannedElement() {}; + virtual ~CurveSpannedElement(){}; Point m_rotatedPoints[4]; const BoundingBox *m_boundingBox; diff --git a/include/vrv/functorinterface.h b/include/vrv/functorinterface.h index 452df9a0fc7..38424282880 100644 --- a/include/vrv/functorinterface.h +++ b/include/vrv/functorinterface.h @@ -156,7 +156,7 @@ class FunctorInterface { * @name Constructors, destructors */ ///@{ - FunctorInterface() {}; + FunctorInterface(){}; virtual ~FunctorInterface() = default; ///@} @@ -513,7 +513,7 @@ class ConstFunctorInterface { * @name Constructors, destructors */ ///@{ - ConstFunctorInterface() {}; + ConstFunctorInterface(){}; virtual ~ConstFunctorInterface() = default; ///@} diff --git a/include/vrv/interface.h b/include/vrv/interface.h index a957e63abe2..7b389b85424 100644 --- a/include/vrv/interface.h +++ b/include/vrv/interface.h @@ -37,8 +37,8 @@ class Interface { * Reset method reset all attribute classes */ ///@{ - Interface() {}; - virtual ~Interface() {}; + Interface(){}; + virtual ~Interface(){}; ///@} /** diff --git a/include/vrv/iobase.h b/include/vrv/iobase.h index 8dcab892fe3..e5cfc903acc 100644 --- a/include/vrv/iobase.h +++ b/include/vrv/iobase.h @@ -33,7 +33,7 @@ class Output { // constructors and destructors Output(Doc *doc, std::string filename); Output(Doc *doc); - Output() {}; + Output(){}; virtual ~Output(); /** diff --git a/include/vrv/layerelement.h b/include/vrv/layerelement.h index 4740e64373b..6b1491e5e74 100644 --- a/include/vrv/layerelement.h +++ b/include/vrv/layerelement.h @@ -296,7 +296,7 @@ class LayerElement : public Object, /** * Helper function to set shortening for elements with beam interface */ - virtual void SetElementShortening(int shortening) {}; + virtual void SetElementShortening(int shortening){}; /** * Get the stem mod for the element (if any) diff --git a/include/vrv/options.h b/include/vrv/options.h index a525e216fbd..0e9160240a7 100644 --- a/include/vrv/options.h +++ b/include/vrv/options.h @@ -417,8 +417,8 @@ class OptionIntMap : public Option { class OptionStaffrel : public Option { public: // constructors and destructors - OptionStaffrel() {}; - virtual ~OptionStaffrel() {}; + OptionStaffrel(){}; + virtual ~OptionStaffrel(){}; void CopyTo(Option *option) override; // Alternate type style cannot have a restricted list of possible values void Init(data_STAFFREL defaultValue); diff --git a/include/vrv/resources.h b/include/vrv/resources.h index 94224baa8ee..7988fb1faf4 100644 --- a/include/vrv/resources.h +++ b/include/vrv/resources.h @@ -136,8 +136,8 @@ class Resources { class LoadedFont { public: - LoadedFont(const std::string &name, bool isFallback) : m_name(name), m_isFallback(isFallback) {}; - ~LoadedFont() {}; + LoadedFont(const std::string &name, bool isFallback) : m_name(name), m_isFallback(isFallback){}; + ~LoadedFont(){}; const std::string GetName() const { return m_name; }; const GlyphTable &GetGlyphTable() const { return m_glyphTable; }; GlyphTable &GetGlyphTableForModification() { return m_glyphTable; }; diff --git a/include/vrv/textelement.h b/include/vrv/textelement.h index c11bc8472ef..2c334275484 100644 --- a/include/vrv/textelement.h +++ b/include/vrv/textelement.h @@ -105,7 +105,7 @@ class TextDrawingParams { m_enclose = TEXTRENDITION_NONE; m_textEnclose = ENCLOSURE_NONE; } - virtual ~TextDrawingParams() {}; + virtual ~TextDrawingParams(){}; int m_x; int m_y; diff --git a/include/vrv/transposition.h b/include/vrv/transposition.h index 505ab7b1d48..9359ab0e5f0 100644 --- a/include/vrv/transposition.h +++ b/include/vrv/transposition.h @@ -43,7 +43,7 @@ class TransPitch { // octave number of pitch: 4 = middle-C octave int m_oct; - TransPitch() {}; + TransPitch(){}; TransPitch(int aPname, int anAccid, int anOct); TransPitch(data_PITCHNAME pname, data_ACCIDENTAL_GESTURAL accidG, data_ACCIDENTAL_WRITTEN accidW, int oct); TransPitch(const TransPitch &pitch); diff --git a/include/vrv/view.h b/include/vrv/view.h index e7faedd7ad1..82719ece3c2 100644 --- a/include/vrv/view.h +++ b/include/vrv/view.h @@ -122,7 +122,7 @@ class View { virtual void DoRefresh() {} virtual void DoResize() {} virtual void DoReset() {} - virtual void OnPageChange() {}; + virtual void OnPageChange() {} ///@} /** From f68b557c3316395caf357cc1fb1bdaf1d005f3b3 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 17:07:51 +0200 Subject: [PATCH 032/105] Add mensuration signs and dots for cmme --- src/iocmme.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 2c8799291b3..61ec05e527f 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -565,10 +565,22 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->SetModusminor(modusminor); data_MODUSMAIOR modusmaior = (m_mensInfo->modusmaior == 3) ? MODUSMAIOR_3 : MODUSMAIOR_2; mensur->SetModusmaior(modusmaior); - data_MENSURATIONSIGN sign = (m_mensInfo->tempus == 3) ? MENSURATIONSIGN_O : MENSURATIONSIGN_C; - mensur->SetSign(sign); - data_BOOLEAN dot = (m_mensInfo->prolatio == 3) ? BOOLEAN_true : BOOLEAN_false; - mensur->SetDot(dot); + + pugi::xml_node signNode = mensurationNode.child("Sign"); + std::string signValue = this->ChildAsString(signNode, "MainSymbol"); + if (signValue == "O") { + mensur->SetSign(MENSURATIONSIGN_O); + } else if (signValue == "C") { + mensur->SetSign(MENSURATIONSIGN_C); + } else { + LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); + } + pugi::xml_node dotNode = signNode.child("Dot"); + if (dotNode) { + mensur->SetDot(BOOLEAN_true); + } else { + mensur->SetDot(BOOLEAN_false); + } this->ReadEditorialCommentary(mensurationNode, mensur); From 12431023e8cd4120e2e43cf3a9f09ab933df23a4 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 17:10:05 +0200 Subject: [PATCH 033/105] Fix formatting --- src/iocmme.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 61ec05e527f..3efcad197b9 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -565,20 +565,23 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->SetModusminor(modusminor); data_MODUSMAIOR modusmaior = (m_mensInfo->modusmaior == 3) ? MODUSMAIOR_3 : MODUSMAIOR_2; mensur->SetModusmaior(modusmaior); - + pugi::xml_node signNode = mensurationNode.child("Sign"); std::string signValue = this->ChildAsString(signNode, "MainSymbol"); if (signValue == "O") { mensur->SetSign(MENSURATIONSIGN_O); - } else if (signValue == "C") { + } + else if (signValue == "C") { mensur->SetSign(MENSURATIONSIGN_C); - } else { + } + else { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } pugi::xml_node dotNode = signNode.child("Dot"); if (dotNode) { mensur->SetDot(BOOLEAN_true); - } else { + } + else { mensur->SetDot(BOOLEAN_false); } From 63a463df08ad5dc2bb02acb04328b758057587b5 Mon Sep 17 00:00:00 2001 From: "Martha E. Thomae" <thomaemartha@gmail.com> Date: Wed, 18 Sep 2024 17:39:58 +0200 Subject: [PATCH 034/105] Update src/iocmme.cpp Co-authored-by: Laurent Pugin <lxpugin@gmail.com> --- src/iocmme.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 3efcad197b9..40af5ae2114 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -577,7 +577,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } - pugi::xml_node dotNode = signNode.child("Dot"); + pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); if (dotNode) { mensur->SetDot(BOOLEAN_true); } From 17e82fd405b90db3e356eaec6c8af684679276ca Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 18 Sep 2024 18:37:07 +0200 Subject: [PATCH 035/105] Reduce if / else to conditional ? --- src/iocmme.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 40af5ae2114..4ef16b40aa8 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -577,13 +577,9 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } + pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); - if (dotNode) { - mensur->SetDot(BOOLEAN_true); - } - else { - mensur->SetDot(BOOLEAN_false); - } + mensur->SetDot(((dotNode) ? BOOLEAN_true : BOOLEAN_false)); this->ReadEditorialCommentary(mensurationNode, mensur); From b0a5dd5753c9c5ab9e84a4903868015a5fd149c5 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 08:17:27 +0200 Subject: [PATCH 036/105] Auto-detect cmme xml --- src/toolkit.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/toolkit.cpp b/src/toolkit.cpp index 086562628d1..fccf857f48e 100644 --- a/src/toolkit.cpp +++ b/src/toolkit.cpp @@ -300,6 +300,9 @@ FileFormat Toolkit::IdentifyInputFrom(const std::string &data) if (std::regex_search(initial, std::regex("<(!DOCTYPE )?(score-partwise|opus|score-timewise)[\\s\\n>]"))) { return musicxmlDefault; } + if (std::regex_search(initial, std::regex("<(Piece xmlns=\"http://www.cmme.org\")[\\s\\n>]"))) { + return CMME; + } LogWarning("Warning: Trying to load unknown XML data which cannot be identified."); return UNKNOWN; } From 022d1a5b09795c827d9659da29de551bc0cc358a Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 09:00:21 +0200 Subject: [PATCH 037/105] Add distinct alignment position for custos --- include/vrv/horizontalaligner.h | 1 + src/alignfunctor.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index 73f8e09c03d..0ace9f9cbfe 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -43,6 +43,7 @@ enum AlignmentType { ALIGNMENT_MENSUR, ALIGNMENT_METERSIG, ALIGNMENT_DOT, + ALIGNMENT_CUSTOS, ALIGNMENT_ACCID, ALIGNMENT_GRACENOTE, ALIGNMENT_BARLINE, diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index c3877c156ee..e709222563c 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -253,6 +253,9 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme type = ALIGNMENT_DOT; } } + else if (layerElement->Is(CUSTOS)) { + type = ALIGNMENT_CUSTOS; + } else if (layerElement->Is(ACCID)) { // accid within note was already taken into account by noteParent type = ALIGNMENT_ACCID; From b8694181d2971865ada38c298cd30476c8c1bac4 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 09:41:42 +0200 Subject: [PATCH 038/105] Add orientation for mensuration signs in cmme --- src/iocmme.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 4ef16b40aa8..8090c2d17b6 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -556,6 +556,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) m_mensInfo->modusmaior = this->ChildAsInt(mensInfo, "ModusMaior"); } + /// Mensuration: logical domain Mensur *mensur = new Mensur(); data_PROLATIO prolatio = (m_mensInfo->prolatio == 3) ? PROLATIO_3 : PROLATIO_2; mensur->SetProlatio(prolatio); @@ -566,6 +567,8 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) data_MODUSMAIOR modusmaior = (m_mensInfo->modusmaior == 3) ? MODUSMAIOR_3 : MODUSMAIOR_2; mensur->SetModusmaior(modusmaior); + /// Mensuration: visual domain + /// Sign/MainSymbol to @sign pugi::xml_node signNode = mensurationNode.child("Sign"); std::string signValue = this->ChildAsString(signNode, "MainSymbol"); if (signValue == "O") { @@ -577,9 +580,28 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } - + /// Sign/Dot to @dot pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); mensur->SetDot(((dotNode) ? BOOLEAN_true : BOOLEAN_false)); + /// Sign/Strokes to @slash + int strokes = this->ChildAsInt(signNode, "Strokes"); + if (strokes != VRV_UNSET) { + mensur->SetSlash(strokes); + } + /// Sign/Orientation to @orient + std::string orientation = this->ChildAsString(signNode, "Orientation"); + if (orientation == "Reversed") { + mensur->SetOrient(ORIENTATION_reversed); + } + else if (orientation == "90CW") { + mensur->SetOrient(ORIENTATION_90CW); + } + else if (orientation == "90CCW") { + mensur->SetOrient(ORIENTATION_90CCW); + } + else { + LogWarning("Unsupported mesuration orientation in CMME (not 'Reversed' or '90CW' or '90CCW')"); + } this->ReadEditorialCommentary(mensurationNode, mensur); From 7bc738a209b0e8c1996fb58c1d4397c600896bda Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 10:10:22 +0200 Subject: [PATCH 039/105] Fix for cases where there is no mensuration sign or orientation --- src/iocmme.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 8090c2d17b6..8e5c073995f 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -577,7 +577,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else if (signValue == "C") { mensur->SetSign(MENSURATIONSIGN_C); } - else { + else if (signValue != "") { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } /// Sign/Dot to @dot @@ -599,7 +599,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else if (orientation == "90CCW") { mensur->SetOrient(ORIENTATION_90CCW); } - else { + else if (orientation != "") { LogWarning("Unsupported mesuration orientation in CMME (not 'Reversed' or '90CW' or '90CCW')"); } From 45b80ecc25605d2dbe2fcb93cfa8dd83edcc466b Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 10:10:46 +0200 Subject: [PATCH 040/105] Add support for cmme chords --- include/vrv/iocmme.h | 2 ++ src/iocmme.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 88d8bb78001..14292361100 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -19,6 +19,7 @@ namespace vrv { +class Chord; class Clef; class KeySig; class Layer; @@ -60,6 +61,7 @@ class CmmeInput : public Input { void CreateAccid(pugi::xml_node accidNode); void CreateBarline(pugi::xml_node barlineNode); + void CreateChord(pugi::xml_node chordNode); void CreateClef(pugi::xml_node clefNode); void CreateCustos(pugi::xml_node custosNode); void CreateDot(pugi::xml_node dotNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 8e5c073995f..584f244f501 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -21,6 +21,7 @@ #include "annot.h" #include "app.h" #include "barline.h" +#include "chord.h" #include "clef.h" #include "custos.h" #include "doc.h" @@ -300,6 +301,10 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) CreateKeySig(clefNode); } } + else if (eventNode.select_node("./Note")) { + // Assuming that this only contains notes (and is a chord) + CreateChord(eventNode); + } else { LogWarning("Unsupported event '%s'", name.c_str()); } @@ -423,6 +428,27 @@ void CmmeInput::CreateBarline(pugi::xml_node barlineNode) m_currentContainer->AddChild(barLine); } +void CmmeInput::CreateChord(pugi::xml_node chordNode) +{ + assert(m_currentContainer); + + Chord *chord = new Chord(); + m_currentContainer->AddChild(chord); + m_currentContainer = chord; + pugi::xpath_node_set events = chordNode.select_nodes("./*"); + for (pugi::xpath_node event : events) { + pugi::xml_node eventNode = event.node(); + std::string name = eventNode.name(); + if (name == "Note") { + CreateNote(eventNode); + } + else { + LogWarning("Unsupported chord component: '%s'", name.c_str()); + } + } + m_currentContainer = m_currentContainer->GetParent(); +} + void CmmeInput::CreateClef(pugi::xml_node clefNode) { static const std::map<std::string, data_CLEFSHAPE> shapeMap{ From f851aefc0526dec67293aa04bcd821ae012edf66 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 10:46:55 +0200 Subject: [PATCH 041/105] Add num and numbase in mensur --- src/iocmme.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 584f244f501..c6f7d28cb34 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -594,7 +594,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->SetModusmaior(modusmaior); /// Mensuration: visual domain - /// Sign/MainSymbol to @sign + /// Mensuration/Sign/MainSymbol to @sign pugi::xml_node signNode = mensurationNode.child("Sign"); std::string signValue = this->ChildAsString(signNode, "MainSymbol"); if (signValue == "O") { @@ -606,7 +606,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else if (signValue != "") { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } - /// Sign/Dot to @dot + /// Mensuration/Sign/Dot to @dot pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); mensur->SetDot(((dotNode) ? BOOLEAN_true : BOOLEAN_false)); /// Sign/Strokes to @slash @@ -614,7 +614,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) if (strokes != VRV_UNSET) { mensur->SetSlash(strokes); } - /// Sign/Orientation to @orient + /// Mensuration/Sign/Orientation to @orient std::string orientation = this->ChildAsString(signNode, "Orientation"); if (orientation == "Reversed") { mensur->SetOrient(ORIENTATION_reversed); @@ -628,6 +628,18 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else if (orientation != "") { LogWarning("Unsupported mesuration orientation in CMME (not 'Reversed' or '90CW' or '90CCW')"); } + /// Mensuration/Number/Num to @num and Number/Den to @numbase + pugi::xml_node numberNode = mensurationNode.child("Number"); + if (numberNode != NULL) { + int numValue = this->ChildAsInt(numberNode, "Num"); + int denValue = this->ChildAsInt(numberNode, "Den"); + if (numValue != VRV_UNSET and numValue != 0) { + mensur->SetNum(numValue); + } + if (denValue != VRV_UNSET and denValue != 0) { + mensur->SetNumbase(denValue); + } + } this->ReadEditorialCommentary(mensurationNode, mensur); From 76c0a2118a66a7cbbe9300ed35bdb39cf0d375b6 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 10:59:47 +0200 Subject: [PATCH 042/105] Add support for StaffLoc in mensur --- src/iocmme.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index c6f7d28cb34..e6a85fb7bb9 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -640,6 +640,11 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->SetNumbase(denValue); } } + /// Menusration/StaffLoc to @loc + int staffLoc = this->ChildAsInt(mensurationNode, "StaffLoc"); + if (staffLoc != VRV_UNSET) { + mensur->SetLoc(staffLoc); + } this->ReadEditorialCommentary(mensurationNode, mensur); From f4884ca5a7dc3ecf67638534276be51659271e3f Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 11:25:49 +0200 Subject: [PATCH 043/105] Add lines for readibility --- src/iocmme.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index e6a85fb7bb9..756f54ff245 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -606,14 +606,17 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else if (signValue != "") { LogWarning("Unsupported mesuration sign in CMME (not 'O' or 'C')"); } + /// Mensuration/Sign/Dot to @dot pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); mensur->SetDot(((dotNode) ? BOOLEAN_true : BOOLEAN_false)); + /// Sign/Strokes to @slash int strokes = this->ChildAsInt(signNode, "Strokes"); if (strokes != VRV_UNSET) { mensur->SetSlash(strokes); } + /// Mensuration/Sign/Orientation to @orient std::string orientation = this->ChildAsString(signNode, "Orientation"); if (orientation == "Reversed") { @@ -628,6 +631,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) else if (orientation != "") { LogWarning("Unsupported mesuration orientation in CMME (not 'Reversed' or '90CW' or '90CCW')"); } + /// Mensuration/Number/Num to @num and Number/Den to @numbase pugi::xml_node numberNode = mensurationNode.child("Number"); if (numberNode != NULL) { @@ -640,6 +644,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->SetNumbase(denValue); } } + /// Menusration/StaffLoc to @loc int staffLoc = this->ChildAsInt(mensurationNode, "StaffLoc"); if (staffLoc != VRV_UNSET) { From 6105ae750b1b6e41f2e08c9fbf3fbe281ef8d6db Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 11:38:01 +0200 Subject: [PATCH 044/105] Make a map for orientation --- src/iocmme.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 756f54ff245..17829d2a5be 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -618,19 +618,14 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) } /// Mensuration/Sign/Orientation to @orient + static const std::map<std::string, data_ORIENTATION> orientationMap{ + { "Reversed", ORIENTATION_reversed }, // + { "90CW", ORIENTATION_90CW }, // + { "90CCW", ORIENTATION_90CCW } // + }; std::string orientation = this->ChildAsString(signNode, "Orientation"); - if (orientation == "Reversed") { - mensur->SetOrient(ORIENTATION_reversed); - } - else if (orientation == "90CW") { - mensur->SetOrient(ORIENTATION_90CW); - } - else if (orientation == "90CCW") { - mensur->SetOrient(ORIENTATION_90CCW); - } - else if (orientation != "") { - LogWarning("Unsupported mesuration orientation in CMME (not 'Reversed' or '90CW' or '90CCW')"); - } + data_ORIENTATION orient = orientationMap.contains(orientation) ? orientationMap.at(orientation) : ORIENTATION_NONE; + mensur->SetOrient(orient); /// Mensuration/Number/Num to @num and Number/Den to @numbase pugi::xml_node numberNode = mensurationNode.child("Number"); From 3931d221ab770eef490d2d1a93ded2b1eec01066 Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Thu, 19 Sep 2024 12:20:48 +0200 Subject: [PATCH 045/105] Add dur info to chords on CMME import --- include/vrv/iocmme.h | 3 +++ src/iocmme.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 14292361100..17b439fd740 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -9,6 +9,7 @@ #define __VRV_IOCMME_H__ #include <string> +#include <utility> #include <vector> //---------------------------------------------------------------------------- @@ -106,6 +107,8 @@ class CmmeInput : public Input { std::vector<cmme::mensInfo> m_mensInfos; /** The mensural info for the current voice */ cmme::mensInfo *m_mensInfo; + /** Latest note and its absolute duration (in minims) */ + std::pair<Note *, double> m_lastNoteDuration; /** The number of voices as given in the general data */ int m_numVoices; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 17829d2a5be..d038eb77320 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -65,6 +65,7 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_currentNote = NULL; m_isInSyllable = false; m_mensInfo = NULL; + m_lastNoteDuration = std::make_pair(nullptr, 0.0); } CmmeInput::~CmmeInput() {} @@ -436,11 +437,21 @@ void CmmeInput::CreateChord(pugi::xml_node chordNode) m_currentContainer->AddChild(chord); m_currentContainer = chord; pugi::xpath_node_set events = chordNode.select_nodes("./*"); + double longestDuration = 0; for (pugi::xpath_node event : events) { pugi::xml_node eventNode = event.node(); std::string name = eventNode.name(); if (name == "Note") { CreateNote(eventNode); + // If this is the longest note, we will need it to add duration + // info to chord + if ((m_lastNoteDuration.second > longestDuration)) { + longestDuration = m_lastNoteDuration.second; + Note *note = m_lastNoteDuration.first; + chord->SetDur(note->GetDur()); + chord->SetNum(note->GetNum()); + chord->SetNumbase(note->GetNumbase()); + } } else { LogWarning("Unsupported chord component: '%s'", name.c_str()); @@ -697,6 +708,7 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) if (num != VRV_UNSET && numbase != VRV_UNSET) { note->SetNumbase(num); note->SetNum(numbase); + m_lastNoteDuration = std::make_pair(note, num / numbase); } int oct = this->ChildAsInt(noteNode, "OctaveNum"); From 983132c22da25278c061e2ff545582f9576972dc Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 12:25:28 +0200 Subject: [PATCH 046/105] Add comment about how to get Num and Den into cmme --- src/iocmme.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 17829d2a5be..e83e5db8e00 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -628,6 +628,9 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->SetOrient(orient); /// Mensuration/Number/Num to @num and Number/Den to @numbase + /// However, Number/Den cannot be entered in the CMME Editor. + /// It can only be added in the XML manually and imported into the CMME Editor, + /// where it won't render, but one can see it in the "Event Inspector." pugi::xml_node numberNode = mensurationNode.child("Number"); if (numberNode != NULL) { int numValue = this->ChildAsInt(numberNode, "Num"); From 898e30c6e78d8d9f58a4beb10296fdb2489d82e2 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 14:15:15 +0200 Subject: [PATCH 047/105] Add CMME mention in `projectDesc` --- src/iocmme.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 2b6f9316c1d..9e7974faaf0 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -77,6 +77,15 @@ bool CmmeInput::Import(const std::string &cmme) try { m_doc->Reset(); m_doc->SetType(Raw); + + // Genereate the header and add a comment to the project description + m_doc->GenerateMEIHeader(false); + pugi::xml_node projectDesc = m_doc->m_header.first_child().select_node("//projectDesc").node(); + if (projectDesc) { + pugi::xml_node p1 = projectDesc.append_child("p"); + p1.text().set("Converted from CMME XML"); + } + pugi::xml_document doc; doc.load_string(cmme.c_str(), (pugi::parse_comments | pugi::parse_default) & ~pugi::parse_eol); pugi::xml_node root = doc.first_child(); From 6ef0c962724a9fc60525a13229bc336b02dd2e09 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 14:19:11 +0200 Subject: [PATCH 048/105] Revert adding duration to chords --- include/vrv/iocmme.h | 2 -- src/iocmme.cpp | 24 +++++++++--------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 17b439fd740..296d0179153 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -107,8 +107,6 @@ class CmmeInput : public Input { std::vector<cmme::mensInfo> m_mensInfos; /** The mensural info for the current voice */ cmme::mensInfo *m_mensInfo; - /** Latest note and its absolute duration (in minims) */ - std::pair<Note *, double> m_lastNoteDuration; /** The number of voices as given in the general data */ int m_numVoices; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 9e7974faaf0..32b00a71b66 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -65,7 +65,6 @@ CmmeInput::CmmeInput(Doc *doc) : Input(doc) m_currentNote = NULL; m_isInSyllable = false; m_mensInfo = NULL; - m_lastNoteDuration = std::make_pair(nullptr, 0.0); } CmmeInput::~CmmeInput() {} @@ -452,15 +451,6 @@ void CmmeInput::CreateChord(pugi::xml_node chordNode) std::string name = eventNode.name(); if (name == "Note") { CreateNote(eventNode); - // If this is the longest note, we will need it to add duration - // info to chord - if ((m_lastNoteDuration.second > longestDuration)) { - longestDuration = m_lastNoteDuration.second; - Note *note = m_lastNoteDuration.first; - chord->SetDur(note->GetDur()); - chord->SetNum(note->GetNum()); - chord->SetNumbase(note->GetNumbase()); - } } else { LogWarning("Unsupported chord component: '%s'", name.c_str()); @@ -720,7 +710,6 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) if (num != VRV_UNSET && numbase != VRV_UNSET) { note->SetNumbase(num); note->SetNum(numbase); - m_lastNoteDuration = std::make_pair(note, num / numbase); } int oct = this->ChildAsInt(noteNode, "OctaveNum"); @@ -782,10 +771,15 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) data_LIGATUREFORM form = (lig == "Obliqua") ? LIGATUREFORM_obliqua : LIGATUREFORM_recta; // First note of the ligature, create the ligature element if (!m_currentContainer->Is(LIGATURE)) { - Ligature *ligature = new Ligature(); - ligature->SetForm(form); - m_currentContainer->AddChild(ligature); - m_currentContainer = ligature; + if (m_currentContainer->Is(CHORD)) { + LogWarning("Ligature within chord is not supported"); + } + else { + Ligature *ligature = new Ligature(); + ligature->SetForm(form); + m_currentContainer->AddChild(ligature); + m_currentContainer = ligature; + } } // Otherwise simply add the `@lig` to the note else { From 0720247422370d71792a8229132b516a5443879b Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 14:45:18 +0200 Subject: [PATCH 049/105] Align mensural chords looking at the duration of the notes --- src/layerelement.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 78cae4a13e8..92d8abc1dd3 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -677,6 +677,18 @@ double LayerElement::GetAlignmentDuration( return 0.0; } + // Mensural chords are aligned looking at the duration of the notes + if (this->Is(CHORD) && IsMensuralType(notationType)) { + double duration = 0.0; + ListOfConstObjects notes = this->FindAllDescendantsByType(NOTE); + for (const Object *object : notes) { + const Note *note = vrv_cast<const Note *>(object); + double noteDuration = note->GetAlignmentDuration(mensur, meterSig, notGraceOnly, notationType); + duration = std::max(duration, noteDuration); + } + return duration; + } + // Only resolve simple sameas links to avoid infinite recursion const LayerElement *sameas = dynamic_cast<const LayerElement *>(this->GetSameasLink()); if (sameas && !sameas->HasSameasLink()) { From 7f1eef2b37e3e339ba98d72a5d66c712b8d5b35e Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 15:37:12 +0200 Subject: [PATCH 050/105] Add support for proportions Missing getNum and getNumbase methods for proport object in Verovio --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 17b439fd740..f9fdc6d674c 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -69,6 +69,7 @@ class CmmeInput : public Input { void CreateKeySig(pugi::xml_node keyNode); void CreateMensuration(pugi::xml_node mensurationNode); void CreateOriginalText(pugi::xml_node originalTextNode); + void CreateProport(pugi::xml_node proportNode); void CreateNote(pugi::xml_node noteNode); void CreateRest(pugi::xml_node restNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 2b6f9316c1d..704b23116c2 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -36,6 +36,7 @@ #include "measure.h" #include "mensur.h" #include "note.h" +#include "proport.h" #include "rdg.h" #include "rest.h" #include "score.h" @@ -316,6 +317,9 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (name == "OriginalText") { CreateOriginalText(eventNode); } + else if (name == "Proportion") { + CreateProport(eventNode); + } else if (name == "Rest") { CreateRest(eventNode); } @@ -622,7 +626,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); mensur->SetDot(((dotNode) ? BOOLEAN_true : BOOLEAN_false)); - /// Sign/Strokes to @slash + /// Mensuration/Sign/Strokes to @slash int strokes = this->ChildAsInt(signNode, "Strokes"); if (strokes != VRV_UNSET) { mensur->SetSlash(strokes); @@ -654,7 +658,7 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) } } - /// Menusration/StaffLoc to @loc + /// Mensuration/StaffLoc to @loc int staffLoc = this->ChildAsInt(mensurationNode, "StaffLoc"); if (staffLoc != VRV_UNSET) { mensur->SetLoc(staffLoc); @@ -664,6 +668,24 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) m_currentContainer->AddChild(mensur); + /// Proportion part coming from CMME <TempoChange> in <MensInfo> in <Mensuration>. In this case, create an MEI + /// <proport> element that follows the MEI <mensuration> element and that contains the proport/@num and + /// proport/@numbase values of 'num' and 'den' + pugi::xml_node tempoChangeNode = mensInfo.child("TempoChange"); + if (tempoChangeNode != NULL) { + Proport *proport = new Proport(); + int numVal = this->ChildAsInt(tempoChangeNode, "Num"); + int denVal = this->ChildAsInt(tempoChangeNode, "Den"); + if (numVal != VRV_UNSET) { + proport->SetNum(numVal); + } + if (denVal != VRV_UNSET) { + proport->SetNumbase(denVal); + } + proport->SetType("cmme_tempo_change"); + m_currentContainer->AddChild(proport); + } + return; } @@ -801,6 +823,26 @@ void CmmeInput::CreateOriginalText(pugi::xml_node originalTextNode) return; } +void CmmeInput::CreateProport(pugi::xml_node proportNode) +{ + assert(m_currentContainer); + + /// Proportion part coming from CMME <Proportion>. In this case, create an MEI <proport> element is created alone + /// (not following an MEI <mensuration> element) + Proport *proport = new Proport(); + int numVal = this->ChildAsInt(proportNode, "Num"); + int denVal = this->ChildAsInt(proportNode, "Den"); + if (numVal != VRV_UNSET) { + proport->SetNum(numVal); + } + if (denVal != VRV_UNSET) { + proport->SetNumbase(denVal); + } + proport->SetType("cmme_proportion"); + m_currentContainer->AddChild(proport); + return; +} + void CmmeInput::CreateRest(pugi::xml_node restNode) { assert(m_currentContainer); From 85a1ba485aceaaf884f8f027395dd3080278f1d7 Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Thu, 19 Sep 2024 15:51:58 +0200 Subject: [PATCH 051/105] Line and page ends from CMME --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 296d0179153..5390697f1e5 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -62,6 +62,7 @@ class CmmeInput : public Input { void CreateAccid(pugi::xml_node accidNode); void CreateBarline(pugi::xml_node barlineNode); + void CreateBreak(pugi::xml_node breakNode); void CreateChord(pugi::xml_node chordNode); void CreateClef(pugi::xml_node clefNode); void CreateCustos(pugi::xml_node custosNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 32b00a71b66..17df6749bfa 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -26,6 +26,7 @@ #include "custos.h" #include "doc.h" #include "dot.h" +#include "genericlayerelement.h" #include "keyaccid.h" #include "keysig.h" #include "label.h" @@ -290,6 +291,9 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (name == "Dot") { CreateDot(eventNode); } + else if (name == "LineEnd") { + CreateBreak(eventNode); + } else if (name == "Mensuration") { CreateMensuration(eventNode); } @@ -437,6 +441,21 @@ void CmmeInput::CreateBarline(pugi::xml_node barlineNode) m_currentContainer->AddChild(barLine); } +void CmmeInput::CreateBreak(pugi::xml_node breakNode) +{ + assert(m_currentContainer); + + // This is either a system or page break (usually only + // in one part, so not easy to visualise in score) + if (breakNode.select_node("./PageEnd")){ + GenericLayerElement *pb = new GenericLayerElement("pb"); + m_currentContainer->AddChild(pb); + } else { + GenericLayerElement *sb = new GenericLayerElement("sb"); + m_currentContainer->AddChild(sb); + } +} + void CmmeInput::CreateChord(pugi::xml_node chordNode) { assert(m_currentContainer); From 87ff9719f404dbf4b4fa1452fff43f54a0c4e846 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 16:00:43 +0200 Subject: [PATCH 052/105] Add support for 'Small' CMME element Co-authored-by: annplaksin <anna.plaksin@uni-paderborn.de> --- src/iocmme.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index b1a80a57757..fc511a61ceb 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -641,6 +641,14 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) data_ORIENTATION orient = orientationMap.contains(orientation) ? orientationMap.at(orientation) : ORIENTATION_NONE; mensur->SetOrient(orient); + /// Mensuration/Small to @fontsize=small (not yet rendered in Verovio). + /// In the long run, we should add @size to att.mensur.vis because we have @mensur.size for <staffDef>, see class + /// att.mensural.vis + pugi::xml_node smallNode = mensurationNode.child("Small"); + if (smallNode != NULL) { + mensur->m_unsupported.push_back(std::make_pair("fontsize", "small")); + } + /// Mensuration/Number/Num to @num and Number/Den to @numbase /// However, Number/Den cannot be entered in the CMME Editor. /// It can only be added in the XML manually and imported into the CMME Editor, From ae226ac5c435091023654026966ed28e4a26d7b5 Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Thu, 19 Sep 2024 16:06:09 +0200 Subject: [PATCH 053/105] Minor cleanup of CreateChord for CMME import --- src/iocmme.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 17df6749bfa..c945645fd4f 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -464,7 +464,6 @@ void CmmeInput::CreateChord(pugi::xml_node chordNode) m_currentContainer->AddChild(chord); m_currentContainer = chord; pugi::xpath_node_set events = chordNode.select_nodes("./*"); - double longestDuration = 0; for (pugi::xpath_node event : events) { pugi::xml_node eventNode = event.node(); std::string name = eventNode.name(); From c81e251f7b835ed18ac30f72a73d6f4bd89325fa Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 16:19:55 +0200 Subject: [PATCH 054/105] Enable content for generic layer elements --- include/vrv/genericlayerelement.h | 8 ++++++++ src/iomei.cpp | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/vrv/genericlayerelement.h b/include/vrv/genericlayerelement.h index 2a422527511..6b93f50a142 100644 --- a/include/vrv/genericlayerelement.h +++ b/include/vrv/genericlayerelement.h @@ -39,6 +39,12 @@ class GenericLayerElement : public LayerElement { */ std::string GetMEIName() const { return m_meiName; } + /** + * Return the MEI element original name + */ + std::string GetContent() { return m_content; } + void SetContent(std::string content) { m_content = content; } + //----------// // Functors // //----------// @@ -58,6 +64,8 @@ class GenericLayerElement : public LayerElement { std::string m_className; /** The MEI element name */ std::string m_meiName; + /** The MEI element content */ + std::string m_content; public: // diff --git a/src/iomei.cpp b/src/iomei.cpp index 2fb82d8e41f..3ea22a2dc3f 100644 --- a/src/iomei.cpp +++ b/src/iomei.cpp @@ -2522,6 +2522,13 @@ void MEIOutput::WriteGenericLayerElement(pugi::xml_node currentNode, GenericLaye currentNode.set_name(element->GetMEIName().c_str()); + // Reparse the original content stored as a string document + pugi::xml_document content; + content.load_string(element->GetContent().c_str()); + for (pugi::xml_node child : content.first_child().children()) { + currentNode.append_copy(child); + } + this->WriteLayerElement(currentNode, element); } @@ -6656,6 +6663,13 @@ bool MEIInput::ReadGenericLayerElement(Object *parent, pugi::xml_node element) GenericLayerElement *vrvElement = new GenericLayerElement(element.name()); this->ReadLayerElement(element, vrvElement); + // Store the content as a string document + pugi::xml_document content; + content.append_copy(element); + std::ostringstream oss; + content.save(oss); + vrvElement->SetContent(oss.str()); + parent->AddChild(vrvElement); this->ReadUnsupportedAttr(element, vrvElement); return true; From 38d4d5da9ae674b3bb3246630434effb93c35aef Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 16:32:37 +0200 Subject: [PATCH 055/105] Fix formatting --- src/iocmme.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index ccadfafb1d6..aafc23787b3 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -292,9 +292,9 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (name == "Dot") { CreateDot(eventNode); } - else if (name == "LineEnd") { - CreateBreak(eventNode); - } + else if (name == "LineEnd") { + CreateBreak(eventNode); + } else if (name == "Mensuration") { CreateMensuration(eventNode); } @@ -449,12 +449,13 @@ void CmmeInput::CreateBreak(pugi::xml_node breakNode) { assert(m_currentContainer); - // This is either a system or page break (usually only + // This is either a system or page break (usually only // in one part, so not easy to visualise in score) - if (breakNode.select_node("./PageEnd")){ + if (breakNode.select_node("./PageEnd")) { GenericLayerElement *pb = new GenericLayerElement("pb"); m_currentContainer->AddChild(pb); - } else { + } + else { GenericLayerElement *sb = new GenericLayerElement("sb"); m_currentContainer->AddChild(sb); } From 10e9a1fb4d3008be87995bd3c8a08db3553b61b5 Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 16:35:00 +0200 Subject: [PATCH 056/105] Fix formatting --- src/iocmme.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index ccadfafb1d6..aafc23787b3 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -292,9 +292,9 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (name == "Dot") { CreateDot(eventNode); } - else if (name == "LineEnd") { - CreateBreak(eventNode); - } + else if (name == "LineEnd") { + CreateBreak(eventNode); + } else if (name == "Mensuration") { CreateMensuration(eventNode); } @@ -449,12 +449,13 @@ void CmmeInput::CreateBreak(pugi::xml_node breakNode) { assert(m_currentContainer); - // This is either a system or page break (usually only + // This is either a system or page break (usually only // in one part, so not easy to visualise in score) - if (breakNode.select_node("./PageEnd")){ + if (breakNode.select_node("./PageEnd")) { GenericLayerElement *pb = new GenericLayerElement("pb"); m_currentContainer->AddChild(pb); - } else { + } + else { GenericLayerElement *sb = new GenericLayerElement("sb"); m_currentContainer->AddChild(sb); } From 8536d5ff5dbd92b65240eb3ab4795f90cedfdf1b Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 16:36:23 +0200 Subject: [PATCH 057/105] Add missing call to write durationratio in proport --- src/iomei.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/iomei.cpp b/src/iomei.cpp index 3ea22a2dc3f..5eb935cdce0 100644 --- a/src/iomei.cpp +++ b/src/iomei.cpp @@ -2803,6 +2803,8 @@ void MEIOutput::WriteProport(pugi::xml_node currentNode, Proport *proport) assert(proport); this->WriteLayerElement(currentNode, proport); + + proport->WriteDurationRatio(currentNode); } void MEIOutput::WriteQuilisma(pugi::xml_node currentNode, Quilisma *quilisma) From 979e97528a6f441a4b022659d998b8a936b1e89e Mon Sep 17 00:00:00 2001 From: martha-thomae <thomaemartha@gmail.com> Date: Thu, 19 Sep 2024 16:41:05 +0200 Subject: [PATCH 058/105] Add support for CMME NoScoreEffect --- src/iocmme.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index aafc23787b3..f3e3fed6d7d 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -668,6 +668,12 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) mensur->m_unsupported.push_back(std::make_pair("fontsize", "small")); } + /// Mesuration/NoScoreEffect to @type = cmme_no_score_effect + pugi::xml_node noScoreEffect = mensurationNode.child("NoScoreEffect"); + if (noScoreEffect != NULL) { + mensur->SetType("cmme_no_score_effect"); + } + /// Mensuration/Number/Num to @num and Number/Den to @numbase /// However, Number/Den cannot be entered in the CMME Editor. /// It can only be added in the XML manually and imported into the CMME Editor, From 589dbe343fd105534166a83c956c81dc968288c4 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 19 Sep 2024 17:13:46 +0200 Subject: [PATCH 059/105] Remove drawing proportions --- src/view_mensural.cpp | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/view_mensural.cpp b/src/view_mensural.cpp index 3bce2133234..f0db3da4a74 100644 --- a/src/view_mensural.cpp +++ b/src/view_mensural.cpp @@ -546,39 +546,12 @@ void View::DrawProportFigures(DeviceContext *dc, int x, int y, int num, int numB void View::DrawProport(DeviceContext *dc, LayerElement *element, Layer *layer, Staff *staff, Measure *measure) { + assert(element); assert(layer); assert(staff); - assert(dynamic_cast<Proport *>(element)); // Element must be a Proport" - - int x1, x2, y1, y2; - - Proport *proport = dynamic_cast<Proport *>(element); dc->StartGraphic(element, "", element->GetID()); - int y = staff->GetDrawingY() - (m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 4); - int x = element->GetDrawingX(); - - x1 = x + 120; - x2 = x1 + 150; // ??TEST: JUST DRAW AN ARBITRARY RECTANGLE - y1 = y; - y2 = y + 50 + (50 * proport->GetNum()); - // DrawFilledRectangle(dc,x1,y1,x2,y2); - this->DrawPartFilledRectangle(dc, x1, y1, x2, y2, 0); - - if (proport->HasNum()) { - x = element->GetDrawingX(); - // if (proport->GetSign() || proport->HasTempus()) // ??WHAT SHOULD THIS BE? - { - x += m_doc->GetDrawingUnit(staff->m_drawingStaffSize) - * 5; // step forward because we have a sign or a meter symbol - } - int numbase = proport->HasNumbase() ? proport->GetNumbase() : 0; - this->DrawProportFigures(dc, x, - staff->GetDrawingY() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * (staff->m_drawingLines - 1), - proport->GetNum(), numbase, staff); - } - dc->EndGraphic(element, this); } From 759958046401f6c4f1179060cba5ed2a61acd78a Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Thu, 19 Sep 2024 17:24:33 +0200 Subject: [PATCH 060/105] Add CMME Ellipsis as <gap> --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 30 ++++++++++++++++++++++++------ src/iomei.cpp | 3 +++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index ed8d809f8db..395843a5455 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -67,6 +67,7 @@ class CmmeInput : public Input { void CreateClef(pugi::xml_node clefNode); void CreateCustos(pugi::xml_node custosNode); void CreateDot(pugi::xml_node dotNode); + void CreateEllipsis(); void CreateKeySig(pugi::xml_node keyNode); void CreateMensuration(pugi::xml_node mensurationNode); void CreateOriginalText(pugi::xml_node originalTextNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index ccadfafb1d6..542d4576474 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -292,9 +292,9 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (name == "Dot") { CreateDot(eventNode); } - else if (name == "LineEnd") { - CreateBreak(eventNode); - } + else if (name == "LineEnd") { + CreateBreak(eventNode); + } else if (name == "Mensuration") { CreateMensuration(eventNode); } @@ -304,6 +304,13 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) pugi::xml_node barlineNode = eventNode.select_node("./Barline").node(); CreateBarline(barlineNode); } + else if (eventNode.select_node("./Ellipsis")) { + CreateEllipsis(); + } + else + { + LogWarning("Unsupported MiscItem content"); + } } else if (name == "MultiEvent") { /// Assuming that a multievent contains a key signature, all events are key signatures @@ -449,12 +456,13 @@ void CmmeInput::CreateBreak(pugi::xml_node breakNode) { assert(m_currentContainer); - // This is either a system or page break (usually only + // This is either a system or page break (usually only // in one part, so not easy to visualise in score) - if (breakNode.select_node("./PageEnd")){ + if (breakNode.select_node("./PageEnd")) { GenericLayerElement *pb = new GenericLayerElement("pb"); m_currentContainer->AddChild(pb); - } else { + } + else { GenericLayerElement *sb = new GenericLayerElement("sb"); m_currentContainer->AddChild(sb); } @@ -553,6 +561,16 @@ void CmmeInput::CreateDot(pugi::xml_node dotNode) return; } +void CmmeInput::CreateEllipsis() +{ + assert(m_currentContainer); + + GenericLayerElement *gap = new GenericLayerElement("gap"); + gap->SetType("cmme_ellipsis"); + gap->m_unsupported.push_back(std::make_pair("reason", "incipit")); + m_currentContainer->AddChild(gap); +} + void CmmeInput::CreateKeySig(pugi::xml_node keyNode) { static const std::map<std::string, data_ACCIDENTAL_WRITTEN> shapeMap{ diff --git a/src/iomei.cpp b/src/iomei.cpp index 3ea22a2dc3f..743031e326f 100644 --- a/src/iomei.cpp +++ b/src/iomei.cpp @@ -6270,6 +6270,9 @@ bool MEIInput::ReadLayerChildren(Object *parent, pugi::xml_node parentNode, Obje else if (elementName == "fTrem") { success = this->ReadFTrem(parent, xmlElement); } + else if (elementName == "gap") { + success = this->ReadGenericLayerElement(parent, xmlElement); + } else if (elementName == "graceGrp") { success = this->ReadGraceGrp(parent, xmlElement); } From d5ffe5463b8765795043e7207af13aa7e2529a5c Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Fri, 20 Sep 2024 09:27:09 +0200 Subject: [PATCH 061/105] Add support for CMME Lacuna (currently doesn't compile because the Supplied class lacks addChild --- include/vrv/iocmme.h | 1 + src/iocmme.cpp | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index 395843a5455..7df84ef55ee 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -69,6 +69,7 @@ class CmmeInput : public Input { void CreateDot(pugi::xml_node dotNode); void CreateEllipsis(); void CreateKeySig(pugi::xml_node keyNode); + void CreateLacuna(pugi::xml_node lacunaNode); void CreateMensuration(pugi::xml_node mensurationNode); void CreateOriginalText(pugi::xml_node originalTextNode); void CreateProport(pugi::xml_node proportNode); diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 542d4576474..1b9c2d5be63 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -42,9 +42,11 @@ #include "rest.h" #include "score.h" #include "section.h" +#include "space.h" #include "staff.h" #include "staffdef.h" #include "staffgrp.h" +#include "supplied.h" #include "syl.h" #include "text.h" #include "verse.h" @@ -307,8 +309,11 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (eventNode.select_node("./Ellipsis")) { CreateEllipsis(); } - else - { + else if (eventNode.select_node("./Lacuna")) { + pugi::xml_node lacunaNode = eventNode.select_node("./Lacuna").node(); + CreateLacuna(lacunaNode); + } + else { LogWarning("Unsupported MiscItem content"); } } @@ -619,6 +624,25 @@ void CmmeInput::CreateKeySig(pugi::xml_node keyNode) m_currentSignature->AddChild(keyAccid); } +void CmmeInput::CreateLacuna(pugi::xml_node lacunaNode) +{ + // A lacuna is used in CMME to pad a part where + // the scribe's version is temporally incomplete. + // We use mei:space, but since this is not explicit + // in the source, we wrap it in mei:supplied + assert(m_currentContainer); + Space *space = new Space(); + Supplied *supplied = new Supplied(); + supplied->addChild(space); + int num; + int numbase; + data_DURATION duration = this->ReadDuration(lacunaNode, num, numbase); + space->SetDur(duration); + space->SetType("cmme_lacuna"); + supplied->SetType("cmme_lacuna"); + m_currentContainer->AddChild(supplied); +} + void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) { assert(m_currentContainer); From a74f479dd8ee1ea6e58905c4056325adf8c3233c Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Fri, 20 Sep 2024 09:34:45 +0200 Subject: [PATCH 062/105] Fix typo for CMME Lacuna --- src/iocmme.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 7c6ab47ed30..7ea9ae55f2b 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -633,7 +633,7 @@ void CmmeInput::CreateLacuna(pugi::xml_node lacunaNode) assert(m_currentContainer); Space *space = new Space(); Supplied *supplied = new Supplied(); - supplied->addChild(space); + supplied->AddChild(space); int num; int numbase; data_DURATION duration = this->ReadDuration(lacunaNode, num, numbase); From b688ee61edc2f3a1e56ddd5d1f8cc579f9b16276 Mon Sep 17 00:00:00 2001 From: David Lewis <d.lewis@gold.ac.uk> Date: Fri, 20 Sep 2024 10:03:55 +0200 Subject: [PATCH 063/105] CMME Signum congruentiae (realised as @type) --- src/iocmme.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 7ea9ae55f2b..21b376c5315 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -842,6 +842,12 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) note->AddChild(accid); } + if (noteNode.child("Signum")) { + // MEI currently lacks signum congruentiae, so we warn and set not type + LogWarning("Signum Congruentiae in CMME mapped to @type"); + note->SetType("cmme_signum_congruentiae"); + } + if (noteNode.child("Stem")) { std::string dir = this->ChildAsString(noteNode.child("Stem"), "Dir"); if (dir == "Barline") { @@ -936,6 +942,12 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) this->ReadEditorialCommentary(restNode, rest); + if (restNode.child("Signum")) { + // MEI currently lacks signum congruentiae, so we warn and set not type + LogWarning("Signum Congruentiae in CMME mapped to @type"); + rest->SetType("cmme_signum_congruentiae"); + } + m_currentContainer->AddChild(rest); return; From 1bb94ef75468311d6fc45d0fa5740d1c71908ce1 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 12:20:25 +0200 Subject: [PATCH 064/105] Fix post merge change --- src/layerelement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 075b549ed35..c2b77daac8c 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -684,7 +684,7 @@ double LayerElement::GetAlignmentDuration( ListOfConstObjects notes = this->FindAllDescendantsByType(NOTE); for (const Object *object : notes) { const Note *note = vrv_cast<const Note *>(object); - double noteDuration = note->GetAlignmentDuration(mensur, meterSig, notGraceOnly, notationType); + double noteDuration = note->GetAlignmentDuration(params, notGraceOnly, notationType); duration = std::max(duration, noteDuration); } return duration; From b6e82eb800b26506e353b3c27e999326e493439e Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 12:20:50 +0200 Subject: [PATCH 065/105] Reset mensuration to binary with cmme mensInfo is missing --- src/iocmme.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index f3e3fed6d7d..6631eef1f9a 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -614,6 +614,13 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) m_mensInfo->modusminor = this->ChildAsInt(mensInfo, "ModusMinor"); m_mensInfo->modusmaior = this->ChildAsInt(mensInfo, "ModusMaior"); } + // If there is no <MensInfo> then resets everything to binary + else { + m_mensInfo->prolatio = 2; + m_mensInfo->tempus = 2; + m_mensInfo->modusminor = 2; + m_mensInfo->modusmaior = 2; + } /// Mensuration: logical domain Mensur *mensur = new Mensur(); From f988cd204d8845c74709fd91842089f5af20be7c Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 14:21:47 +0200 Subject: [PATCH 066/105] Add proport to AlignMeterParams --- include/vrv/alignfunctor.h | 6 ++++-- src/alignfunctor.cpp | 2 -- src/layerelement.cpp | 4 ---- src/midifunctor.cpp | 2 -- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/include/vrv/alignfunctor.h b/include/vrv/alignfunctor.h index cd4dabf1757..e2257f49897 100644 --- a/include/vrv/alignfunctor.h +++ b/include/vrv/alignfunctor.h @@ -14,6 +14,7 @@ namespace vrv { class Mensur; class MeterSig; +class Proport; //---------------------------------------------------------------------------- // AlignmentParams @@ -22,8 +23,9 @@ class MeterSig; * Regroup pointers to meterSig, mensur and proport objects */ struct AlignMeterParams { - const MeterSig *meterSig; - const Mensur *mensur; + const MeterSig *meterSig = NULL; + const Mensur *mensur = NULL; + const Proport *proport = NULL; }; //---------------------------------------------------------------------------- diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index 655fcd2034f..2e6f0ae0887 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -41,8 +41,6 @@ AlignHorizontallyFunctor::AlignHorizontallyFunctor(Doc *doc) : DocFunctor(doc) { m_measureAligner = NULL; m_time = 0.0; - m_currentParams.mensur = NULL; - m_currentParams.meterSig = NULL; m_notationType = NOTATIONTYPE_cmn; m_scoreDefRole = SCOREDEF_NONE; m_isFirstMeasure = false; diff --git a/src/layerelement.cpp b/src/layerelement.cpp index c2b77daac8c..b69b2b48a51 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -782,8 +782,6 @@ double LayerElement::GetAlignmentDuration( double LayerElement::GetAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE notationType) const { AlignMeterParams params; - params.meterSig = NULL; - params.mensur = NULL; return this->GetAlignmentDuration(params, notGraceOnly, notationType); } @@ -825,8 +823,6 @@ double LayerElement::GetContentAlignmentDuration( double LayerElement::GetContentAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE notationType) const { AlignMeterParams params; - params.meterSig = NULL; - params.mensur = NULL; return this->GetContentAlignmentDuration(params, notGraceOnly, notationType); } diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 05f91a550da..7639723d726 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -44,8 +44,6 @@ InitOnsetOffsetFunctor::InitOnsetOffsetFunctor() : Functor() { m_currentScoreTime = 0.0; m_currentRealTimeSeconds = 0.0; - m_meterParams.mensur = NULL; - m_meterParams.meterSig = NULL; m_notationType = NOTATIONTYPE_cmn; m_currentTempo = MIDI_TEMPO; } From ea1e9e9e51aef105af9be7df71ed7696d4c653cf Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 17:15:25 +0200 Subject: [PATCH 067/105] Add utility to reduce a fraction --- include/vrv/vrv.h | 5 +++++ src/vrv.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/include/vrv/vrv.h b/include/vrv/vrv.h index daec31198e2..e6104524c0b 100644 --- a/include/vrv/vrv.h +++ b/include/vrv/vrv.h @@ -71,6 +71,11 @@ bool IsValidDouble(const std::string &value); */ bool IsDigits(const std::string &value); +/** + * Utility to reduce are faction of two integers + */ +void Reduce(int &numerator, int &denominator); + /** * Extract the ID from any URI */ diff --git a/src/vrv.cpp b/src/vrv.cpp index 764e29370bf..c4f686dc492 100644 --- a/src/vrv.cpp +++ b/src/vrv.cpp @@ -253,6 +253,42 @@ bool IsDigits(const std::string &value) return std::regex_match(value, re); } +// Function to compute the Greatest Common Divisor (GCD) +int GCD(int a, int b) +{ + if (b == 0) { + return std::abs(a); + } + return GCD(b, a % b); +} + +// Function to reduce the fraction +void Reduce(int &numerator, int &denominator) +{ + // Handle cases with zero denominator or numerator + if ((denominator == 0) || (denominator == VRV_UNSET)) { + return; + } + + if ((numerator == 0) || (denominator == VRV_UNSET)) { + denominator = 1; // A fraction with 0 numerator is 0/1 + return; + } + + // Get the greatest common divisor + int divisor = GCD(numerator, denominator); + + // Divide numerator and denominator by GCD + numerator /= divisor; + denominator /= divisor; + + // Ensure denominator is always positive + if (denominator < 0) { + numerator = -numerator; + denominator = -denominator; + } +} + std::string ExtractIDFragment(std::string refID) { size_t pos = refID.find_last_of("#"); From de74afbb7530e9eecbab865ad692e3633696e892 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 17:18:05 +0200 Subject: [PATCH 068/105] Store cumulated values in proportion --- include/vrv/proport.h | 8 ++++++++ src/proport.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/vrv/proport.h b/include/vrv/proport.h index ad3db4c2f2b..8aa0c240ca4 100644 --- a/include/vrv/proport.h +++ b/include/vrv/proport.h @@ -34,6 +34,11 @@ class Proport : public LayerElement, public AttDurationRatio { std::string GetClassName() const override { return "Proport"; } ///@} + int GetCumulatedNum() const; + int GetCumulatedNumbase() const; + + void Cumulate(const Proport *proport); + /** Override the method since alignment is required */ bool HasToBeAligned() const override { return true; } @@ -52,6 +57,9 @@ class Proport : public LayerElement, public AttDurationRatio { public: // private: + /** the cumulated num and numbase */ + int m_cumulatedNum; + int m_cumulatedNumbase; }; } // namespace vrv diff --git a/src/proport.cpp b/src/proport.cpp index 0ee5336561e..614d2e08b37 100644 --- a/src/proport.cpp +++ b/src/proport.cpp @@ -32,6 +32,30 @@ void Proport::Reset() { LayerElement::Reset(); this->ResetDurationRatio(); + + m_cumulatedNum = VRV_UNSET; + m_cumulatedNumbase = VRV_UNSET; +} + +int Proport::GetCumulatedNum() const +{ + return (m_cumulatedNum != VRV_UNSET) ? m_cumulatedNum : this->GetNum(); +} + +int Proport::GetCumulatedNumbase() const +{ + return (m_cumulatedNumbase != VRV_UNSET) ? m_cumulatedNumbase : this->GetNumbase(); +} + +void Proport::Cumulate(const Proport *proport) +{ + // Unset values are not cumulated + if (proport->HasNum() && this->HasNum()) { + m_cumulatedNum = this->GetNum() * proport->GetCumulatedNum(); + } + if (proport->HasNumbase() && this->HasNumbase()) { + m_cumulatedNumbase = this->GetNumbase() * proport->GetCumulatedNumbase(); + } } FunctorCode Proport::Accept(Functor &functor) From 710fe00fff619a5cf4e6dfdae06ff368c6ad44f5 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 17:19:24 +0200 Subject: [PATCH 069/105] Add proportion to drawing staffdef propagated values --- include/vrv/drawinginterface.h | 6 ++++++ include/vrv/layer.h | 2 ++ include/vrv/setscoredeffunctor.h | 1 + src/drawinginterface.cpp | 8 ++++++++ src/layer.cpp | 12 ++++++++++++ src/setscoredeffunctor.cpp | 9 +++++++++ 6 files changed, 38 insertions(+) diff --git a/include/vrv/drawinginterface.h b/include/vrv/drawinginterface.h index 32d2e88e253..79efbaa2fd7 100644 --- a/include/vrv/drawinginterface.h +++ b/include/vrv/drawinginterface.h @@ -14,6 +14,7 @@ #include "mensur.h" #include "metersig.h" #include "metersiggrp.h" +#include "proport.h" #include "vrvdef.h" namespace vrv { @@ -260,6 +261,7 @@ class StaffDefDrawingInterface { void SetCurrentMeterSig(const MeterSig *meterSig); void SetCurrentMeterSigGrp(const MeterSigGrp *meterSigGrp); void AlternateCurrentMeterSig(const Measure *measure); + void SetCurrentProport(const Proport *proport); ///@} /** @@ -277,6 +279,8 @@ class StaffDefDrawingInterface { const MeterSig *GetCurrentMeterSig() const { return &m_currentMeterSig; } MeterSigGrp *GetCurrentMeterSigGrp() { return &m_currentMeterSigGrp; } const MeterSigGrp *GetCurrentMeterSigGrp() const { return &m_currentMeterSigGrp; } + Proport *GetCurrentProport() { return &m_currentProport; } + const Proport *GetCurrentProport() const { return &m_currentProport; } ///@} private: @@ -290,6 +294,8 @@ class StaffDefDrawingInterface { MeterSig m_currentMeterSig; /** The meter signature group */ MeterSigGrp m_currentMeterSigGrp; + /** The proport */ + Proport m_currentProport; /** * @name Flags for indicating whether the clef, keysig and mensur needs to be drawn or not diff --git a/include/vrv/layer.h b/include/vrv/layer.h index 45fefba99a1..16aed1c9595 100644 --- a/include/vrv/layer.h +++ b/include/vrv/layer.h @@ -167,6 +167,8 @@ class Layer : public Object, const Mensur *GetCurrentMensur() const; MeterSig *GetCurrentMeterSig(); const MeterSig *GetCurrentMeterSig() const; + Proport *GetCurrentProport(); + const Proport *GetCurrentProport() const; ///@} void ResetStaffDefObjects(); diff --git a/include/vrv/setscoredeffunctor.h b/include/vrv/setscoredeffunctor.h index 60e3d9af41d..6c4eaa18a1b 100644 --- a/include/vrv/setscoredeffunctor.h +++ b/include/vrv/setscoredeffunctor.h @@ -136,6 +136,7 @@ class ScoreDefSetCurrentFunctor : public DocFunctor { FunctorCode VisitMeasure(Measure *measure) override; FunctorCode VisitMensur(Mensur *mensur) override; FunctorCode VisitPage(Page *page) override; + FunctorCode VisitProport(Proport *proport) override; FunctorCode VisitScore(Score *score) override; FunctorCode VisitScoreDef(ScoreDef *scoreDef) override; FunctorCode VisitStaff(Staff *staff) override; diff --git a/src/drawinginterface.cpp b/src/drawinginterface.cpp index c843d0431fb..c9825ea1475 100644 --- a/src/drawinginterface.cpp +++ b/src/drawinginterface.cpp @@ -650,6 +650,14 @@ void StaffDefDrawingInterface::AlternateCurrentMeterSig(const Measure *measure) } } +void StaffDefDrawingInterface::SetCurrentProport(const Proport *proport) +{ + if (proport) { + m_currentProport = *proport; + m_currentProport.CloneReset(); + } +} + //---------------------------------------------------------------------------- // StemmedDrawingInterface //---------------------------------------------------------------------------- diff --git a/src/layer.cpp b/src/layer.cpp index 560e5642bb2..6e1ea6b1681 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -541,6 +541,18 @@ const MeterSig *Layer::GetCurrentMeterSig() const return staff->m_drawingStaffDef->GetCurrentMeterSig(); } +Proport *Layer::GetCurrentProport() +{ + return const_cast<Proport *>(std::as_const(*this).GetCurrentProport()); +} + +const Proport *Layer::GetCurrentProport() const +{ + const Staff *staff = vrv_cast<const Staff *>(this->GetFirstAncestor(STAFF)); + assert(staff && staff->m_drawingStaffDef); + return staff->m_drawingStaffDef->GetCurrentProport(); +} + void Layer::SetDrawingStaffDefValues(StaffDef *currentStaffDef) { if (!currentStaffDef) { diff --git a/src/setscoredeffunctor.cpp b/src/setscoredeffunctor.cpp index 29f6548c8ce..6bbab04cd80 100644 --- a/src/setscoredeffunctor.cpp +++ b/src/setscoredeffunctor.cpp @@ -230,6 +230,15 @@ FunctorCode ScoreDefSetCurrentFunctor::VisitPage(Page *page) return FUNCTOR_CONTINUE; } +FunctorCode ScoreDefSetCurrentFunctor::VisitProport(Proport *proport) +{ + assert(m_currentStaffDef); + StaffDef *upcomingStaffDef = m_upcomingScoreDef.GetStaffDef(m_currentStaffDef->GetN()); + assert(upcomingStaffDef); + upcomingStaffDef->SetCurrentProport(proport); + return FUNCTOR_CONTINUE; +} + FunctorCode ScoreDefSetCurrentFunctor::VisitScore(Score *score) { m_currentScore = score; From 22cbf404ac083acbdf0cdf989481b2d8a6061954 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 17:20:06 +0200 Subject: [PATCH 070/105] Take proportion into account when aligning data --- include/vrv/alignfunctor.h | 7 ++----- include/vrv/horizontalaligner.h | 1 + include/vrv/layerelement.h | 2 +- src/alignfunctor.cpp | 12 ++++++++++++ src/layerelement.cpp | 7 +++++++ 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/vrv/alignfunctor.h b/include/vrv/alignfunctor.h index e2257f49897..746fbcafe38 100644 --- a/include/vrv/alignfunctor.h +++ b/include/vrv/alignfunctor.h @@ -12,10 +12,6 @@ namespace vrv { -class Mensur; -class MeterSig; -class Proport; - //---------------------------------------------------------------------------- // AlignmentParams //---------------------------------------------------------------------------- @@ -25,7 +21,8 @@ class Proport; struct AlignMeterParams { const MeterSig *meterSig = NULL; const Mensur *mensur = NULL; - const Proport *proport = NULL; + // Not const since we are cumulating proportion + Proport *proport = NULL; }; //---------------------------------------------------------------------------- diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index 0ace9f9cbfe..7351c1f9ed5 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -42,6 +42,7 @@ enum AlignmentType { ALIGNMENT_KEYSIG, ALIGNMENT_MENSUR, ALIGNMENT_METERSIG, + ALIGNMENT_PROPORT, ALIGNMENT_DOT, ALIGNMENT_CUSTOS, ALIGNMENT_ACCID, diff --git a/include/vrv/layerelement.h b/include/vrv/layerelement.h index 80d8b26c541..881b5922e9b 100644 --- a/include/vrv/layerelement.h +++ b/include/vrv/layerelement.h @@ -20,7 +20,7 @@ namespace vrv { class Alignment; -class AlignMeterParams; +struct AlignMeterParams; class Beam; class BeamElementCoord; class FTrem; diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index 2e6f0ae0887..6c146eacd8f 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -18,6 +18,7 @@ #include "nc.h" #include "neume.h" #include "page.h" +#include "proport.h" #include "rend.h" #include "rest.h" #include "runningelement.h" @@ -51,6 +52,7 @@ FunctorCode AlignHorizontallyFunctor::VisitLayer(Layer *layer) { m_currentParams.mensur = layer->GetCurrentMensur(); m_currentParams.meterSig = layer->GetCurrentMeterSig(); + m_currentParams.proport = layer->GetCurrentProport(); // We are starting a new layer, reset the time; // We set it to -1.0 for the scoreDef attributes since they have to be aligned before any timestamp event (-1.0) @@ -232,6 +234,16 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme type = ALIGNMENT_SCOREDEF_METERSIG; } } + else if (layerElement->Is(PROPORT)) { + // replace the current proport + const Proport *previous = (m_currentParams.proport) ? (m_currentParams.proport) : NULL; + m_currentParams.proport = vrv_cast<Proport *>(layerElement); + assert(m_currentParams.proport); + if (previous) { + m_currentParams.proport->Cumulate(previous); + } + type = ALIGNMENT_PROPORT; + } else if (layerElement->Is({ MULTIREST, MREST, MRPT })) { type = ALIGNMENT_FULLMEASURE; } diff --git a/src/layerelement.cpp b/src/layerelement.cpp index b69b2b48a51..9d12ffcab45 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -50,6 +50,7 @@ #include "neume.h" #include "note.h" #include "page.h" +#include "proport.h" #include "rest.h" #include "slur.h" #include "smufl.h" @@ -699,6 +700,12 @@ double LayerElement::GetAlignmentDuration( if (this->HasInterface(INTERFACE_DURATION)) { int num = 1; int numbase = 1; + + if (params.proport) { + if (params.proport->HasNum()) num *= params.proport->GetCumulatedNum(); + if (params.proport->HasNumbase()) numbase *= params.proport->GetCumulatedNumbase(); + } + const Tuplet *tuplet = vrv_cast<const Tuplet *>(this->GetFirstAncestor(TUPLET, MAX_TUPLET_DEPTH)); if (tuplet) { ListOfConstObjects objects; From 7406a0944e29773c6a71f710b8b5c1fce2ae1369 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 17:48:30 +0200 Subject: [PATCH 071/105] Move cmme mensur@num/numbase to type * It does seem for Mensuration/Number/Num to be only visual --- src/iocmme.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 6631eef1f9a..a887e52293f 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -689,12 +689,16 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) if (numberNode != NULL) { int numValue = this->ChildAsInt(numberNode, "Num"); int denValue = this->ChildAsInt(numberNode, "Den"); + std::string mensurType; if (numValue != VRV_UNSET and numValue != 0) { - mensur->SetNum(numValue); + // mensur->SetNum(numValue); + mensurType += StringFormat("cmme_mensur_num_%d", numValue); } if (denValue != VRV_UNSET and denValue != 0) { - mensur->SetNumbase(denValue); + // mensur->SetNumbase(denValue); + mensurType += StringFormat(" cmme_mensur_den_%d", denValue); } + mensur->SetType(mensurType); } /// Mensuration/StaffLoc to @loc From f28f0ab225038e2af1f204272b4cb52fdf7ef179 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 20 Sep 2024 17:49:04 +0200 Subject: [PATCH 072/105] Cumulate proportion in duration calculation in cmme --- include/vrv/iocmme.h | 2 ++ src/iocmme.cpp | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/vrv/iocmme.h b/include/vrv/iocmme.h index ed8d809f8db..29b67aadff3 100644 --- a/include/vrv/iocmme.h +++ b/include/vrv/iocmme.h @@ -35,6 +35,8 @@ namespace cmme { int tempus = 2; int modusminor = 2; int modusmaior = 2; + int proportNum = 1; + int proportDen = 1; }; } // namespace cmme diff --git a/src/iocmme.cpp b/src/iocmme.cpp index a887e52293f..6c4b48dec65 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -873,6 +873,7 @@ void CmmeInput::CreateOriginalText(pugi::xml_node originalTextNode) void CmmeInput::CreateProport(pugi::xml_node proportNode) { assert(m_currentContainer); + assert(m_mensInfo); /// Proportion part coming from CMME <Proportion>. In this case, create an MEI <proport> element is created alone /// (not following an MEI <mensuration> element) @@ -881,10 +882,15 @@ void CmmeInput::CreateProport(pugi::xml_node proportNode) int denVal = this->ChildAsInt(proportNode, "Den"); if (numVal != VRV_UNSET) { proport->SetNum(numVal); + // Cumulated it + m_mensInfo->proportNum *= numVal; } if (denVal != VRV_UNSET) { proport->SetNumbase(denVal); + // Cumulated it + m_mensInfo->proportDen *= denVal; } + vrv::Reduce(m_mensInfo->proportNum, m_mensInfo->proportDen); proport->SetType("cmme_proportion"); m_currentContainer->AddChild(proport); return; @@ -968,6 +974,10 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int num = this->ChildAsInt(durationNode.child("Length"), "Num"); numbase = this->ChildAsInt(durationNode.child("Length"), "Den"); + // Apply the proportion + num *= m_mensInfo->proportNum; + numbase *= m_mensInfo->proportDen; + std::pair<int, int> ratio = { 1, 1 }; if (type == "Maxima") { @@ -992,11 +1002,11 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int ratio.second = 8; } - if (ratio.first != num || ratio.second != numbase) { - num *= ratio.second; - numbase *= ratio.first; - } - else { + num *= ratio.second; + numbase *= ratio.first; + vrv::Reduce(numbase, num); + + if (num == numbase) { num = VRV_UNSET; numbase = VRV_UNSET; } From ae9d6ff86bb4c91e55ec2d0a451bc259991c52b1 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Sat, 21 Sep 2024 10:53:18 +0200 Subject: [PATCH 073/105] Adjust the way proportions are applied --- src/durationinterface.cpp | 14 +++++++------- src/iocmme.cpp | 10 +++++----- src/layerelement.cpp | 5 +++-- src/proport.cpp | 3 +++ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 27c4ec698e0..d8ffcbae7bc 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -111,8 +111,8 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num || ((this->GetDur() == DURATION_semibrevis) && (currentMensur->GetProlatio() == PROLATIO_2)) || (this->GetDur() == DURATION_minima) || (this->GetDur() == DURATION_semiminima) || (this->GetDur() == DURATION_fusa) || (this->GetDur() == DURATION_semifusa)) { - num *= 2; - numBase *= 3; + num *= 3; + numBase *= 2; } } // imperfecta in perfect mensuration (three imperfectas in the place of the two original perfectas) @@ -120,16 +120,16 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num if (((this->GetDur() == DURATION_longa) && (currentMensur->GetModusminor() != MODUSMINOR_2)) || ((this->GetDur() == DURATION_brevis) && (currentMensur->GetTempus() != TEMPUS_2)) || ((this->GetDur() == DURATION_semibrevis) && (currentMensur->GetProlatio() != PROLATIO_2))) { - num *= 3; - numBase *= 2; + num *= 2; + numBase *= 3; } } // altera, maior, or duplex else if (this->HasDurQuality() && (this->GetDurQuality() == DURQUALITY_mensural_altera || this->GetDurQuality() == DURQUALITY_mensural_maior || this->GetDurQuality() == DURQUALITY_mensural_duplex)) { - num *= 1; - numBase *= 2; + num *= 2; + numBase *= 1; } // Any other case (minor, perfecta in tempus perfectum, and imperfecta in tempus imperfectum) follows the // mensuration and has no @num and @numbase attributes @@ -150,7 +150,7 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num duration /= (double)abs(currentMensur->GetTempus()) * (double)abs(currentMensur->GetProlatio()) * ratio; break; } - duration *= (double)numBase / (double)num; + duration *= (double)num / (double)numBase; // LogDebug("Duration %d; %d/%d; Alignment %f; Ratio %f", noteDur, num, numbase, duration, ratio); duration = durRound(duration); return duration; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 6c4b48dec65..78962f238d0 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -774,8 +774,8 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) data_DURATION duration = this->ReadDuration(noteNode, num, numbase); note->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { - note->SetNumbase(num); - note->SetNum(numbase); + note->SetNum(num); + note->SetNumbase(numbase); } int oct = this->ChildAsInt(noteNode, "OctaveNum"); @@ -906,8 +906,8 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) data_DURATION duration = this->ReadDuration(restNode, num, numbase); rest->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { - rest->SetNumbase(num); - rest->SetNum(numbase); + rest->SetNum(num); + rest->SetNumbase(numbase); } this->ReadEditorialCommentary(restNode, rest); @@ -1004,7 +1004,7 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int num *= ratio.second; numbase *= ratio.first; - vrv::Reduce(numbase, num); + vrv::Reduce(num, numbase); if (num == numbase) { num = VRV_UNSET; diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 9d12ffcab45..df50215c52b 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -702,8 +702,9 @@ double LayerElement::GetAlignmentDuration( int numbase = 1; if (params.proport) { - if (params.proport->HasNum()) num *= params.proport->GetCumulatedNum(); - if (params.proport->HasNumbase()) numbase *= params.proport->GetCumulatedNumbase(); + // Proportion are applied reversly - higher ratio means shorter values + if (params.proport->HasNum()) numbase *= params.proport->GetCumulatedNum(); + if (params.proport->HasNumbase()) num *= params.proport->GetCumulatedNumbase(); } const Tuplet *tuplet = vrv_cast<const Tuplet *>(this->GetFirstAncestor(TUPLET, MAX_TUPLET_DEPTH)); diff --git a/src/proport.cpp b/src/proport.cpp index 614d2e08b37..80ee2ad2f54 100644 --- a/src/proport.cpp +++ b/src/proport.cpp @@ -56,6 +56,9 @@ void Proport::Cumulate(const Proport *proport) if (proport->HasNumbase() && this->HasNumbase()) { m_cumulatedNumbase = this->GetNumbase() * proport->GetCumulatedNumbase(); } + if ((m_cumulatedNum != VRV_UNSET) && (m_cumulatedNumbase != VRV_UNSET)) { + vrv::Reduce(m_cumulatedNum, m_cumulatedNumbase); + } } FunctorCode Proport::Accept(Functor &functor) From ea48ada2572227b857da18ed118aa1bc9aaaf409 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 08:39:29 +0200 Subject: [PATCH 074/105] Revert changes in num / numbase proportion handling --- src/durationinterface.cpp | 14 +++++++------- src/iocmme.cpp | 10 +++++----- src/layerelement.cpp | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index d8ffcbae7bc..27c4ec698e0 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -111,8 +111,8 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num || ((this->GetDur() == DURATION_semibrevis) && (currentMensur->GetProlatio() == PROLATIO_2)) || (this->GetDur() == DURATION_minima) || (this->GetDur() == DURATION_semiminima) || (this->GetDur() == DURATION_fusa) || (this->GetDur() == DURATION_semifusa)) { - num *= 3; - numBase *= 2; + num *= 2; + numBase *= 3; } } // imperfecta in perfect mensuration (three imperfectas in the place of the two original perfectas) @@ -120,16 +120,16 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num if (((this->GetDur() == DURATION_longa) && (currentMensur->GetModusminor() != MODUSMINOR_2)) || ((this->GetDur() == DURATION_brevis) && (currentMensur->GetTempus() != TEMPUS_2)) || ((this->GetDur() == DURATION_semibrevis) && (currentMensur->GetProlatio() != PROLATIO_2))) { - num *= 2; - numBase *= 3; + num *= 3; + numBase *= 2; } } // altera, maior, or duplex else if (this->HasDurQuality() && (this->GetDurQuality() == DURQUALITY_mensural_altera || this->GetDurQuality() == DURQUALITY_mensural_maior || this->GetDurQuality() == DURQUALITY_mensural_duplex)) { - num *= 2; - numBase *= 1; + num *= 1; + numBase *= 2; } // Any other case (minor, perfecta in tempus perfectum, and imperfecta in tempus imperfectum) follows the // mensuration and has no @num and @numbase attributes @@ -150,7 +150,7 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num duration /= (double)abs(currentMensur->GetTempus()) * (double)abs(currentMensur->GetProlatio()) * ratio; break; } - duration *= (double)num / (double)numBase; + duration *= (double)numBase / (double)num; // LogDebug("Duration %d; %d/%d; Alignment %f; Ratio %f", noteDur, num, numbase, duration, ratio); duration = durRound(duration); return duration; diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 78962f238d0..6c4b48dec65 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -774,8 +774,8 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) data_DURATION duration = this->ReadDuration(noteNode, num, numbase); note->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { - note->SetNum(num); - note->SetNumbase(numbase); + note->SetNumbase(num); + note->SetNum(numbase); } int oct = this->ChildAsInt(noteNode, "OctaveNum"); @@ -906,8 +906,8 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) data_DURATION duration = this->ReadDuration(restNode, num, numbase); rest->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { - rest->SetNum(num); - rest->SetNumbase(numbase); + rest->SetNumbase(num); + rest->SetNum(numbase); } this->ReadEditorialCommentary(restNode, rest); @@ -1004,7 +1004,7 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int num *= ratio.second; numbase *= ratio.first; - vrv::Reduce(num, numbase); + vrv::Reduce(numbase, num); if (num == numbase) { num = VRV_UNSET; diff --git a/src/layerelement.cpp b/src/layerelement.cpp index df50215c52b..32c060264b0 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -703,8 +703,8 @@ double LayerElement::GetAlignmentDuration( if (params.proport) { // Proportion are applied reversly - higher ratio means shorter values - if (params.proport->HasNum()) numbase *= params.proport->GetCumulatedNum(); - if (params.proport->HasNumbase()) num *= params.proport->GetCumulatedNumbase(); + if (params.proport->HasNum()) num *= params.proport->GetCumulatedNum(); + if (params.proport->HasNumbase()) numbase *= params.proport->GetCumulatedNumbase(); } const Tuplet *tuplet = vrv_cast<const Tuplet *>(this->GetFirstAncestor(TUPLET, MAX_TUPLET_DEPTH)); From 469a61b2bf09596e89a7e989f4e7f1f5af3c1111 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 10:43:01 +0200 Subject: [PATCH 075/105] Add `@dot` only when true --- src/iocmme.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 6c4b48dec65..b2db55aaea9 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -648,8 +648,9 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) } /// Mensuration/Sign/Dot to @dot - pugi::xml_node dotNode = (signNode) ? signNode.child("Dot") : pugi::xml_node(NULL); - mensur->SetDot(((dotNode) ? BOOLEAN_true : BOOLEAN_false)); + if (signNode.child("Dot")) { + mensur->SetDot(BOOLEAN_true); + } /// Mensuration/Sign/Strokes to @slash int strokes = this->ChildAsInt(signNode, "Strokes"); @@ -689,16 +690,12 @@ void CmmeInput::CreateMensuration(pugi::xml_node mensurationNode) if (numberNode != NULL) { int numValue = this->ChildAsInt(numberNode, "Num"); int denValue = this->ChildAsInt(numberNode, "Den"); - std::string mensurType; if (numValue != VRV_UNSET and numValue != 0) { - // mensur->SetNum(numValue); - mensurType += StringFormat("cmme_mensur_num_%d", numValue); + mensur->SetNum(numValue); } if (denValue != VRV_UNSET and denValue != 0) { - // mensur->SetNumbase(denValue); - mensurType += StringFormat(" cmme_mensur_den_%d", denValue); + mensur->SetNumbase(denValue); } - mensur->SetType(mensurType); } /// Mensuration/StaffLoc to @loc From ded5957c7657621e735a269cb4ff7d0acf920d40 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 10:43:26 +0200 Subject: [PATCH 076/105] Treat mensur@num as visual only --- include/vrv/drawinginterface.h | 2 +- src/durationinterface.cpp | 3 --- src/view_mensural.cpp | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/vrv/drawinginterface.h b/include/vrv/drawinginterface.h index 79efbaa2fd7..384c415c432 100644 --- a/include/vrv/drawinginterface.h +++ b/include/vrv/drawinginterface.h @@ -240,7 +240,7 @@ class StaffDefDrawingInterface { void SetDrawClef(bool drawClef) { m_drawClef = drawClef; } bool DrawKeySig() const { return (m_drawKeySig); } void SetDrawKeySig(bool drawKeySig) { m_drawKeySig = drawKeySig; } - bool DrawMensur() const { return (m_drawMensur && m_currentMensur.HasSign()); } + bool DrawMensur() const { return (m_drawMensur && (m_currentMensur.HasSign() || m_currentMensur.HasNum())); } void SetDrawMensur(bool drawMensur) { m_drawMensur = drawMensur; } bool DrawMeterSig() const { diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 27c4ec698e0..fdde51deecd 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -133,9 +133,6 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num } // Any other case (minor, perfecta in tempus perfectum, and imperfecta in tempus imperfectum) follows the // mensuration and has no @num and @numbase attributes - if (currentMensur->HasNum()) num *= currentMensur->GetNum(); - if (currentMensur->HasNumbase()) numBase *= currentMensur->GetNumbase(); - double ratio = 0.0; double duration = (double)DUR_MENSURAL_REF; switch (noteDur) { diff --git a/src/view_mensural.cpp b/src/view_mensural.cpp index f0db3da4a74..231caba9f0f 100644 --- a/src/view_mensural.cpp +++ b/src/view_mensural.cpp @@ -85,7 +85,7 @@ void View::DrawMensur(DeviceContext *dc, LayerElement *element, Layer *layer, St Mensur *mensur = vrv_cast<Mensur *>(element); assert(mensur); - if (!mensur->HasSign()) { + if (!mensur->HasSign() && !mensur->HasNum()) { // only react to visual attributes return; } From 45ea4275a888f39fe6160843cd9cd6a935d7436f Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 11:03:21 +0200 Subject: [PATCH 077/105] Update src/iocmme.cpp --- src/iocmme.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 21b376c5315..b7e7dd74ef0 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -306,7 +306,7 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) pugi::xml_node barlineNode = eventNode.select_node("./Barline").node(); CreateBarline(barlineNode); } - else if (eventNode.select_node("./Ellipsis")) { + else if (eventNode.child("Ellipsis")) { CreateEllipsis(); } else if (eventNode.select_node("./Lacuna")) { From 7f25b38f371be2cd47fefdf6c59060c94423a59a Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 11:03:55 +0200 Subject: [PATCH 078/105] Update src/iocmme.cpp --- src/iocmme.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index b7e7dd74ef0..3dd95928601 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -309,7 +309,7 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) else if (eventNode.child("Ellipsis")) { CreateEllipsis(); } - else if (eventNode.select_node("./Lacuna")) { + else if (eventNode.child("Lacuna")) { pugi::xml_node lacunaNode = eventNode.select_node("./Lacuna").node(); CreateLacuna(lacunaNode); } From f6b4461060d3bf1c27ad2924576aea6a9319a444 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 11:04:42 +0200 Subject: [PATCH 079/105] Update src/iocmme.cpp --- src/iocmme.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 3dd95928601..91be35af73d 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -310,7 +310,6 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) CreateEllipsis(); } else if (eventNode.child("Lacuna")) { - pugi::xml_node lacunaNode = eventNode.select_node("./Lacuna").node(); CreateLacuna(lacunaNode); } else { From dc67c93f6f01eedfe132d8fc4b03d869582915a6 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 11:05:35 +0200 Subject: [PATCH 080/105] Read all cmme variant versions --- src/iocmme.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index b2db55aaea9..bce74192d82 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -245,7 +245,18 @@ void CmmeInput::CreateLemOrRdg(pugi::xml_node lemOrRdgNode, bool isFirst) } lemOrRdg->m_visibility = (isFirst) ? Visible : Hidden; - if (lemOrRdg->Is(RDG)) lemOrRdg->SetLabel(versionId); + if (lemOrRdg->Is(RDG)) { + std::string label; + // Loop through the event lists + pugi::xpath_node_set variants = lemOrRdgNode.select_nodes("./VariantVersionID"); + bool isFirst = true; + for (pugi::xpath_node variant : variants) { + if (!isFirst) label += "; "; + label += this->AsString(variant.node()); + isFirst = false; + } + lemOrRdg->SetLabel(label); + } if (lemOrRdgNode.child("Error")) { lemOrRdg->SetType("Error"); From 556263bf2fb2065e0a65cd997d570edbd2ac018a Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 11:21:23 +0200 Subject: [PATCH 081/105] Post-merge fix in cmme import --- src/iocmme.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 5b888513e36..d751c144a6c 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -321,7 +321,7 @@ void CmmeInput::ReadEvents(pugi::xml_node eventsNode) CreateEllipsis(); } else if (eventNode.child("Lacuna")) { - CreateLacuna(lacunaNode); + CreateLacuna(eventNode.child("Lacuna")); } else { LogWarning("Unsupported MiscItem content"); From d799c73f70566cf4d00e7c6d49f1e475e34dbc8a Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Mon, 23 Sep 2024 11:41:43 +0200 Subject: [PATCH 082/105] Use local variables for clarifying cmme duration processing --- src/iocmme.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/iocmme.cpp b/src/iocmme.cpp index d751c144a6c..92cea2b092c 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -822,8 +822,8 @@ void CmmeInput::CreateNote(pugi::xml_node noteNode) data_DURATION duration = this->ReadDuration(noteNode, num, numbase); note->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { - note->SetNumbase(num); - note->SetNum(numbase); + note->SetNum(num); + note->SetNumbase(numbase); } int oct = this->ChildAsInt(noteNode, "OctaveNum"); @@ -960,8 +960,8 @@ void CmmeInput::CreateRest(pugi::xml_node restNode) data_DURATION duration = this->ReadDuration(restNode, num, numbase); rest->SetDur(duration); if (num != VRV_UNSET && numbase != VRV_UNSET) { - rest->SetNumbase(num); - rest->SetNum(numbase); + rest->SetNum(num); + rest->SetNumbase(numbase); } this->ReadEditorialCommentary(restNode, rest); @@ -1031,12 +1031,16 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int numbase = VRV_UNSET; if (durationNode.child("Length")) { - num = this->ChildAsInt(durationNode.child("Length"), "Num"); - numbase = this->ChildAsInt(durationNode.child("Length"), "Den"); + int cmmeNum = this->ChildAsInt(durationNode.child("Length"), "Num"); + int cmmeDen = this->ChildAsInt(durationNode.child("Length"), "Den"); + + if ((cmmeNum == VRV_UNSET) || (cmmeDen == VRV_UNSET)) { + return duration; + } // Apply the proportion - num *= m_mensInfo->proportNum; - numbase *= m_mensInfo->proportDen; + cmmeNum *= m_mensInfo->proportNum; + cmmeDen *= m_mensInfo->proportDen; std::pair<int, int> ratio = { 1, 1 }; @@ -1062,9 +1066,14 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int ratio.second = 8; } - num *= ratio.second; - numbase *= ratio.first; - vrv::Reduce(numbase, num); + cmmeNum *= ratio.second; + cmmeDen *= ratio.first; + + // MEI num and numabase are cmme den and num respectively + num = cmmeDen; + numbase = cmmeNum; + + vrv::Reduce(num, numbase); if (num == numbase) { num = VRV_UNSET; From 3ee90f8d5a400bc4ee8797c95ee2c5bf258a3dbf Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 2 Oct 2024 19:01:14 +0200 Subject: [PATCH 083/105] Initial refactoring for using fraction in alignment calculation --- include/vrv/alignfunctor.h | 2 +- include/vrv/calcalignmentxposfunctor.h | 2 +- include/vrv/findlayerelementsfunctor.h | 12 +-- include/vrv/horizontalaligner.h | 76 ++++++++++++--- include/vrv/layer.h | 10 +- include/vrv/layerelement.h | 12 +-- src/alignfunctor.cpp | 14 +-- src/calcalignmentxposfunctor.cpp | 12 +-- src/findlayerelementsfunctor.cpp | 18 ++-- src/horizontalaligner.cpp | 128 +++++++++++++++++++++---- src/iopae.cpp | 2 +- src/layer.cpp | 22 +++-- src/layerelement.cpp | 26 ++--- src/measure.cpp | 4 +- src/midifunctor.cpp | 25 ++--- src/view_element.cpp | 6 +- 16 files changed, 260 insertions(+), 111 deletions(-) diff --git a/include/vrv/alignfunctor.h b/include/vrv/alignfunctor.h index a4fadfef313..2b9aa627331 100644 --- a/include/vrv/alignfunctor.h +++ b/include/vrv/alignfunctor.h @@ -75,7 +75,7 @@ class AlignHorizontallyFunctor : public DocFunctor { // The measureAligner MeasureAligner *m_measureAligner; // The time - double m_time; + Fraction m_time; // The current MeterSig, Mensur and Proport AlignMeterParams m_currentParams; // The current notation type diff --git a/include/vrv/calcalignmentxposfunctor.h b/include/vrv/calcalignmentxposfunctor.h index cce4a6e6ac4..5eda96449a8 100644 --- a/include/vrv/calcalignmentxposfunctor.h +++ b/include/vrv/calcalignmentxposfunctor.h @@ -61,7 +61,7 @@ class CalcAlignmentXPosFunctor : public DocFunctor { // private: // The previous time position - double m_previousTime; + Fraction m_previousTime; // The previous x rel position int m_previousXRel; // Duration of the longest note diff --git a/include/vrv/findlayerelementsfunctor.h b/include/vrv/findlayerelementsfunctor.h index 8d1ec87b1a1..7bdf1eeb657 100644 --- a/include/vrv/findlayerelementsfunctor.h +++ b/include/vrv/findlayerelementsfunctor.h @@ -41,7 +41,7 @@ class LayersInTimeSpanFunctor : public ConstFunctor { /* * Set the time and duration of the event */ - void SetEvent(double time, double duration); + void SetEvent(const Fraction &time, const Fraction &duration); /* * Retrieve the search result @@ -65,9 +65,9 @@ class LayersInTimeSpanFunctor : public ConstFunctor { // private: // The time of the event - double m_time; + Fraction m_time; // The duration of the event - double m_duration; + Fraction m_duration; // The layers (layerN) found std::set<int> m_layers; // The current time alignment parameters @@ -99,7 +99,7 @@ class LayerElementsInTimeSpanFunctor : public ConstFunctor { /* * Set the time and duration of the event */ - void SetEvent(double time, double duration); + void SetEvent(const Fraction &time, const Fraction &duration); /* * Consider all layers except the current one @@ -126,9 +126,9 @@ class LayerElementsInTimeSpanFunctor : public ConstFunctor { // private: // The time of the event - double m_time; + Fraction m_time; // The duration of the event - double m_duration; + Fraction m_duration; // The list of layer elements found ListOfConstObjects m_elements; // The current time alignment parameters diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index 73f8e09c03d..ff6a97da218 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -12,6 +12,8 @@ #include "object.h" #include "vrv.h" +#include <numeric> + namespace vrv { class Accid; @@ -60,6 +62,53 @@ enum AlignmentType { #define BARLINE_REFERENCES -1 #define TSTAMP_REFERENCES -2 +//---------------------------------------------------------------------------- +// Fraction +//---------------------------------------------------------------------------- + +class Fraction { + +public: + // Constructors + Fraction(int num = 0, int denom = 1); + + /** Addition operator */ + Fraction operator+(const Fraction &other) const; + /** Subtraction operator */ + Fraction operator-(const Fraction &other) const; + /** Multiplication operator */ + Fraction operator*(const Fraction &other) const; + /** Division operator */ + Fraction operator/(const Fraction &other) const; + + /** Equality operator */ + bool operator==(const Fraction &other) const; + /** Less than operator */ + bool operator<(const Fraction &other) const; + /** Less than or equal operator */ + bool operator<=(const Fraction &other) const; + /** Greater than operator */ + bool operator>(const Fraction &other) const; + /** Greater than or equal operator */ + bool operator>=(const Fraction &other) const; + + /** Convert fraction to a double */ + double ToDouble() const; + + /** Convert fraction to a string */ + std::string ToString() const; + +private: + /** Reduce the fraction */ + void Reduce(); + +public: + // +private: + int m_numerator; + int m_denominator; +}; + //---------------------------------------------------------------------------- // Alignment //---------------------------------------------------------------------------- @@ -75,7 +124,7 @@ class Alignment : public Object { */ ///@{ Alignment(); - Alignment(double time, AlignmentType type = ALIGNMENT_DEFAULT); + Alignment(const Fraction &time, AlignmentType type = ALIGNMENT_DEFAULT); virtual ~Alignment(); void Reset() override; ///@} @@ -102,8 +151,8 @@ class Alignment : public Object { * @name Set and get the time value of the alignment */ ///@{ - void SetTime(double time) { m_time = time; } - double GetTime() const { return m_time; } + void SetTime(const Fraction &time) { m_time = time; } + Fraction GetTime() const { return m_time; } ///@} /** @@ -188,7 +237,10 @@ class Alignment : public Object { /** * Debug message */ - std::string LogDebugTreeMsg() override { return StringFormat("%d %f", this->GetXRel(), this->GetTime()); } + std::string LogDebugTreeMsg() override + { + return StringFormat("%d %s", this->GetXRel(), this->GetTime().ToString().c_str()); + } //----------------// // Static methods // @@ -210,7 +262,7 @@ class Alignment : public Object { * formula with parameters can come close and has other advantages. */ static int HorizontalSpaceForDuration( - double intervalTime, int maxActualDur, double spacingLinear, double spacingNonLinear); + const Fraction &intervalTime, int maxActualDur, double spacingLinear, double spacingNonLinear); //----------// // Functors // @@ -247,7 +299,7 @@ class Alignment : public Object { * Stores the time at which the alignment occur. * It is set by the AlignHorizontallyFunctor. */ - double m_time; + Fraction m_time; /** * Defines the type of alignment (see the AlignmentType enum). * We have different types because we want some events occuring at the same @@ -384,8 +436,8 @@ class HorizontalAligner : public Object { * If not, return in idx the position where it needs to be inserted (-1 if it is the end) */ ///@{ - Alignment *SearchAlignmentAtTime(double time, AlignmentType type, int &idx); - const Alignment *SearchAlignmentAtTime(double time, AlignmentType type, int &idx) const; + Alignment *SearchAlignmentAtTime(const Fraction &time, AlignmentType type, int &idx); + const Alignment *SearchAlignmentAtTime(const Fraction &time, AlignmentType type, int &idx) const; ///@} /** @@ -430,19 +482,19 @@ class MeasureAligner : public HorizontalAligner { * The alignment object is added if not found. * The maximum time position is also adjusted accordingly for end barline positioning */ - Alignment *GetAlignmentAtTime(double time, AlignmentType type); + Alignment *GetAlignmentAtTime(const Fraction &time, AlignmentType type); /** * Keep the maximum time of the measure. * This corresponds to the whole duration of the measure and * should be the same for all staves/layers. */ - void SetMaxTime(double time); + void SetMaxTime(const Fraction &time); /** * Return the max time of the measure (i.e., the right measure alignment time) */ - double GetMaxTime() const; + Fraction GetMaxTime() const; /** * @name Set and Get the non-justifiable margin (right and left scoreDefs) @@ -569,7 +621,7 @@ class GraceAligner : public HorizontalAligner { * Retrieve the alignmnet of the type at that time. * The alignment object is added if not found. */ - Alignment *GetAlignmentAtTime(double time, AlignmentType type); + Alignment *GetAlignmentAtTime(const Fraction &time, AlignmentType type); /** * Because the grace notes appear from left to right but need to be aligned diff --git a/include/vrv/layer.h b/include/vrv/layer.h index 45fefba99a1..c450619d864 100644 --- a/include/vrv/layer.h +++ b/include/vrv/layer.h @@ -130,8 +130,10 @@ class Layer : public Object, * Takes into account cross-staff situations: cross staff layers have negative N. */ ///@{ - std::set<int> GetLayersNInTimeSpan(double time, double duration, const Measure *measure, int staff) const; - int GetLayerCountInTimeSpan(double time, double duration, const Measure *measure, int staff) const; + std::set<int> GetLayersNInTimeSpan( + const Fraction &time, const Fraction &duration, const Measure *measure, int staff) const; + int GetLayerCountInTimeSpan( + const Fraction &time, const Fraction &duration, const Measure *measure, int staff) const; ///@} /** @@ -150,9 +152,9 @@ class Layer : public Object, */ ///@{ ListOfObjects GetLayerElementsInTimeSpan( - double time, double duration, const Measure *measure, int staff, bool excludeCurrent); + const Fraction &time, const Fraction &duration, const Measure *measure, int staff, bool excludeCurrent); ListOfConstObjects GetLayerElementsInTimeSpan( - double time, double duration, const Measure *measure, int staff, bool excludeCurrent) const; + const Fraction &time, const Fraction &duration, const Measure *measure, int staff, bool excludeCurrent) const; ///@} /** diff --git a/include/vrv/layerelement.h b/include/vrv/layerelement.h index da9cdc01a0e..30f8e1323c1 100644 --- a/include/vrv/layerelement.h +++ b/include/vrv/layerelement.h @@ -14,12 +14,12 @@ #include "atts_shared.h" #include "facsimileinterface.h" +#include "horizontalaligner.h" #include "linkinginterface.h" #include "object.h" namespace vrv { -class Alignment; class Beam; class BeamElementCoord; class FTrem; @@ -262,26 +262,26 @@ class LayerElement : public Object, /** * Return the duration if the element has a DurationInterface. */ - double GetAlignmentDuration(const AlignMeterParams ¶ms, bool notGraceOnly = true, + Fraction GetAlignmentDuration(const AlignMeterParams ¶ms, bool notGraceOnly = true, data_NOTATIONTYPE notationType = NOTATIONTYPE_cmn) const; /** * Return the duration if the element has a DurationInterface. * Shortcut assigning default values for AlignParameter. */ - double GetAlignmentDuration(bool notGraceOnly = true, data_NOTATIONTYPE notationType = NOTATIONTYPE_cmn) const; + Fraction GetAlignmentDuration(bool notGraceOnly = true, data_NOTATIONTYPE notationType = NOTATIONTYPE_cmn) const; /** * Return the duration if the content of the layer element with a @sameas attribute. * Used only on beam, tuplet or ftrem have. */ - double GetSameAsContentAlignmentDuration(const AlignMeterParams ¶ms, bool notGraceOnly = true, + Fraction GetSameAsContentAlignmentDuration(const AlignMeterParams ¶ms, bool notGraceOnly = true, data_NOTATIONTYPE notationType = NOTATIONTYPE_cmn) const; - double GetContentAlignmentDuration(const AlignMeterParams ¶ms, bool notGraceOnly = true, + Fraction GetContentAlignmentDuration(const AlignMeterParams ¶ms, bool notGraceOnly = true, data_NOTATIONTYPE notationType = NOTATIONTYPE_cmn) const; - double GetContentAlignmentDuration( + Fraction GetContentAlignmentDuration( bool notGraceOnly = true, data_NOTATIONTYPE notationType = NOTATIONTYPE_cmn) const; /** diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index 779518f07de..329b8b2b104 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -169,15 +169,15 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme Alignment *alignment = firstNote->GetAlignment(); layerElement->SetAlignment(alignment); alignment->AddLayerElementRef(layerElement); - double duration = layerElement->GetAlignmentDuration(m_currentParams, true, m_notationType); - m_time += duration; + Fraction duration = layerElement->GetAlignmentDuration(m_currentParams, true, m_notationType); + m_time = m_time + duration; return FUNCTOR_CONTINUE; } } // We do not align these (container). Any other? else if (layerElement->Is({ BEAM, LIGATURE, FTREM, TUPLET })) { - double duration = layerElement->GetSameAsContentAlignmentDuration(m_currentParams, true, m_notationType); - m_time += duration; + Fraction duration = layerElement->GetSameAsContentAlignmentDuration(m_currentParams, true, m_notationType); + m_time = m_time + duration; return FUNCTOR_CONTINUE; } else if (layerElement->Is(BARLINE)) { @@ -304,12 +304,14 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme type = ALIGNMENT_GRACENOTE; } - double duration = 0.0; + Fraction duration; // We have already an alignment with grace note children - skip this if (!layerElement->GetAlignment()) { // get the duration of the event duration = layerElement->GetAlignmentDuration(m_currentParams, true, m_notationType); + //LogDebug("duration %s %f", duration.ToString().c_str(), duration.ToDouble()); + // For timestamp, what we get from GetAlignmentDuration is actually the position of the timestamp // So use it as current time - we can do this because the timestamp loop is redirected from the measure // The time will be reset to 0.0 when starting a new layer anyway @@ -350,7 +352,7 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme if (!layerElement->Is(TIMESTAMP_ATTR)) { // increase the time position, but only when not a timestamp (it would actually do nothing) - m_time += duration; + m_time = m_time + duration; } return FUNCTOR_CONTINUE; diff --git a/src/calcalignmentxposfunctor.cpp b/src/calcalignmentxposfunctor.cpp index 780c076f5b9..cad0ee57f3d 100644 --- a/src/calcalignmentxposfunctor.cpp +++ b/src/calcalignmentxposfunctor.cpp @@ -36,7 +36,7 @@ FunctorCode CalcAlignmentXPosFunctor::VisitAlignment(Alignment *alignment) if (alignment->GetType() <= ALIGNMENT_MEASURE_LEFT_BARLINE) return FUNCTOR_CONTINUE; int intervalXRel = 0; - double intervalTime = alignment->GetTime() - m_previousTime; + Fraction intervalTime = alignment->GetTime() - m_previousTime; if (alignment->GetType() > ALIGNMENT_MEASURE_RIGHT_BARLINE) { intervalTime = 0.0; @@ -68,22 +68,22 @@ FunctorCode CalcAlignmentXPosFunctor::VisitAlignment(Alignment *alignment) // alignments, then we now need to move them appropriately if (!m_timestamps.empty() && m_lastNonTimestamp) { int startXRel = m_lastNonTimestamp->GetXRel(); - double startTime = m_lastNonTimestamp->GetTime(); - double endTime = alignment->GetTime(); + Fraction startTime = m_lastNonTimestamp->GetTime(); + Fraction endTime = alignment->GetTime(); // We have timestamp alignments between the left barline and the first beat. We need // to use the MeasureAligner::m_initialTstampDur to calculate the time (percentage) position if (m_lastNonTimestamp->GetType() == ALIGNMENT_MEASURE_LEFT_BARLINE) { startTime = m_measureAligner->GetInitialTstampDur(); } // The duration since the last alignment and the current one - double duration = endTime - startTime; + Fraction duration = endTime - startTime; int space = alignment->GetXRel() - m_lastNonTimestamp->GetXRel(); // For each timestamp alignment, move them proportionally to the space we currently have for (auto &tsAlignment : m_timestamps) { // Avoid division by zero (nothing to move with the alignment anyway if (duration == 0.0) break; - double percent = (tsAlignment->GetTime() - startTime) / duration; - tsAlignment->SetXRel(startXRel + space * percent); + Fraction percent = (tsAlignment->GetTime() - startTime) / duration; + tsAlignment->SetXRel(startXRel + space * percent.ToDouble()); } m_timestamps.clear(); } diff --git a/src/findlayerelementsfunctor.cpp b/src/findlayerelementsfunctor.cpp index 8c5b53fe942..0ebba8830fa 100644 --- a/src/findlayerelementsfunctor.cpp +++ b/src/findlayerelementsfunctor.cpp @@ -22,13 +22,11 @@ namespace vrv { LayersInTimeSpanFunctor::LayersInTimeSpanFunctor(const MeterSig *meterSig, const Mensur *mensur) : ConstFunctor() { - m_time = 0.0; - m_duration = 0.0; m_meterParams.meterSig = meterSig; m_meterParams.mensur = mensur; } -void LayersInTimeSpanFunctor::SetEvent(double time, double duration) +void LayersInTimeSpanFunctor::SetEvent(const Fraction &time, const Fraction &duration) { m_time = time; m_duration = duration; @@ -51,15 +49,15 @@ FunctorCode LayersInTimeSpanFunctor::VisitLayerElement(const LayerElement *layer return FUNCTOR_CONTINUE; if (layerElement->Is(NOTE) && layerElement->GetParent()->Is(CHORD)) return FUNCTOR_CONTINUE; - double duration = layerElement->GetAlignmentDuration(m_meterParams); - double time = layerElement->GetAlignment()->GetTime(); + Fraction duration = layerElement->GetAlignmentDuration(m_meterParams); + Fraction time = layerElement->GetAlignment()->GetTime(); // The event is starting after the end of the element - if (time + duration <= m_time) { + if ((time + duration) <= m_time) { return FUNCTOR_CONTINUE; } // The element is starting after the event end - we can stop here - else if (time >= m_time + m_duration) { + else if (time >= (m_time + m_duration)) { return FUNCTOR_STOP; } @@ -100,7 +98,7 @@ LayerElementsInTimeSpanFunctor::LayerElementsInTimeSpanFunctor( m_allLayersButCurrent = false; } -void LayerElementsInTimeSpanFunctor::SetEvent(double time, double duration) +void LayerElementsInTimeSpanFunctor::SetEvent(const Fraction &time, const Fraction &duration) { m_time = time; m_duration = duration; @@ -124,11 +122,11 @@ FunctorCode LayerElementsInTimeSpanFunctor::VisitLayerElement(const LayerElement if (!layerElement->GetDurationInterface() || layerElement->Is({ MSPACE, SPACE })) return FUNCTOR_CONTINUE; - const double duration = !layerElement->GetFirstAncestor(CHORD) + Fraction duration = !layerElement->GetFirstAncestor(CHORD) ? layerElement->GetAlignmentDuration(m_meterParams) : vrv_cast<const Chord *>(layerElement->GetFirstAncestor(CHORD))->GetAlignmentDuration(m_meterParams); - const double time = layerElement->GetAlignment()->GetTime(); + Fraction time = layerElement->GetAlignment()->GetTime(); // The event is starting after the end of the element if ((time + duration) <= m_time) return FUNCTOR_CONTINUE; diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index f0b86cb2497..b6b2df1fd80 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -33,6 +33,97 @@ namespace vrv { +//---------------------------------------------------------------------------- +// Fraction +//---------------------------------------------------------------------------- + +Fraction::Fraction(int num, int denom) : m_numerator(num), m_denominator(denom) +{ + if (denom == 0) { + LogDebug("Denominator cannot be zero."); + denom = 1; + } + Reduce(); +} + +Fraction Fraction::operator+(const Fraction &other) const +{ + int num = m_numerator * other.m_denominator + other.m_numerator * m_denominator; + int denom = m_denominator * other.m_denominator; + return Fraction(num, denom); +} + +Fraction Fraction::operator-(const Fraction &other) const +{ + int num = m_numerator * other.m_denominator - other.m_numerator * m_denominator; + int denom = m_denominator * other.m_denominator; + return Fraction(num, denom); +} + +Fraction Fraction::operator*(const Fraction &other) const +{ + int num = m_numerator * other.m_numerator; + int denom = m_denominator * other.m_denominator; + return Fraction(num, denom); +} + +Fraction Fraction::operator/(const Fraction &other) const +{ + if (other.m_numerator == 0) { + LogDebug("Cannot divide by zero."); + return *this; + } + int num = m_numerator * other.m_denominator; + int denom = m_denominator * other.m_numerator; + return Fraction(num, denom); +} + +bool Fraction::operator==(const Fraction &other) const +{ + return (m_numerator == other.m_numerator) && (m_denominator == other.m_denominator); +} + +bool Fraction::operator<(const Fraction &other) const +{ + return m_numerator * other.m_denominator < other.m_numerator * m_denominator; +} + +bool Fraction::operator<=(const Fraction &other) const +{ + return m_numerator * other.m_denominator <= other.m_numerator * m_denominator; +} + +bool Fraction::operator>(const Fraction &other) const +{ + return m_numerator * other.m_denominator > other.m_numerator * m_denominator; +} + +bool Fraction::operator>=(const Fraction &other) const +{ + return m_numerator * other.m_denominator >= other.m_numerator * m_denominator; +} + +double Fraction::ToDouble() const +{ + return static_cast<double>(m_numerator) / m_denominator; +} + +std::string Fraction::ToString() const +{ + return StringFormat("%d/%d", m_numerator, m_denominator); +} + +void Fraction::Reduce() +{ + if (m_denominator < 0) { // Keep the denominator positive + m_numerator = -m_numerator; + m_denominator = -m_denominator; + } + int gcdVal = std::gcd(abs(m_numerator), abs(m_denominator)); + m_numerator /= gcdVal; + m_denominator /= gcdVal; +} + //---------------------------------------------------------------------------- // HorizontalAligner //---------------------------------------------------------------------------- @@ -49,12 +140,12 @@ void HorizontalAligner::Reset() Object::Reset(); } -Alignment *HorizontalAligner::SearchAlignmentAtTime(double time, AlignmentType type, int &idx) +Alignment *HorizontalAligner::SearchAlignmentAtTime(const Fraction &time, AlignmentType type, int &idx) { return const_cast<Alignment *>(std::as_const(*this).SearchAlignmentAtTime(time, type, idx)); } -const Alignment *HorizontalAligner::SearchAlignmentAtTime(double time, AlignmentType type, int &idx) const +const Alignment *HorizontalAligner::SearchAlignmentAtTime(const Fraction &time, AlignmentType type, int &idx) const { idx = -1; // the index if we reach the end. const Alignment *alignment = NULL; @@ -63,8 +154,8 @@ const Alignment *HorizontalAligner::SearchAlignmentAtTime(double time, Alignment alignment = vrv_cast<const Alignment *>(this->GetChild(i)); assert(alignment); - double alignment_time = alignment->GetTime(); - if (AreEqual(alignment_time, time)) { + Fraction alignment_time = alignment->GetTime(); + if (alignment_time == time) { if (alignment->GetType() == type) { return alignment; } @@ -150,10 +241,10 @@ bool MeasureAligner::IsSupportedChild(Object *child) return true; } -Alignment *MeasureAligner::GetAlignmentAtTime(double time, AlignmentType type) +Alignment *MeasureAligner::GetAlignmentAtTime(const Fraction &time, AlignmentType type) { int idx; // the index if we reach the end. - time = durRound(time); + // time = durRound(time); Alignment *alignment = this->SearchAlignmentAtTime(time, type, idx); // we already have a alignment of the type at that time if (alignment != NULL) return alignment; @@ -175,7 +266,7 @@ Alignment *MeasureAligner::GetAlignmentAtTime(double time, AlignmentType type) return newAlignment; } -void MeasureAligner::SetMaxTime(double time) +void MeasureAligner::SetMaxTime(const Fraction &time) { // we have to have a m_rightBarLineAlignment assert(m_rightBarLineAlignment); @@ -194,7 +285,7 @@ void MeasureAligner::SetMaxTime(double time) } } -double MeasureAligner::GetMaxTime() const +Fraction MeasureAligner::GetMaxTime() const { // we have to have a m_rightBarLineAlignment assert(m_rightBarLineAlignment); @@ -360,10 +451,10 @@ void GraceAligner::Reset() m_totalWidth = 0; } -Alignment *GraceAligner::GetAlignmentAtTime(double time, AlignmentType type) +Alignment *GraceAligner::GetAlignmentAtTime(const Fraction &time, AlignmentType type) { int idx; // the index if we reach the end. - time = round(time); + // time = round(time); Alignment *alignment = this->SearchAlignmentAtTime(time, type, idx); // we already have a alignment of the type at that time if (alignment != NULL) return alignment; @@ -392,14 +483,14 @@ void GraceAligner::StackGraceElement(LayerElement *element) void GraceAligner::AlignStack() { - double time = 0.0; + Fraction time; for (int i = (int)m_graceStack.size(); i > 0; --i) { LayerElement *element = vrv_cast<LayerElement *>(m_graceStack.at(i - 1)); assert(element); // get the duration of the event - double duration = element->GetAlignmentDuration(false); + Fraction duration = element->GetAlignmentDuration(false); // Time goes backward with grace notes - time -= duration; + time = time - duration; Alignment *alignment = this->GetAlignmentAtTime(time, ALIGNMENT_DEFAULT); element->SetGraceAlignment(alignment); @@ -506,7 +597,7 @@ Alignment::Alignment() : Object(ALIGNMENT) this->Reset(); } -Alignment::Alignment(double time, AlignmentType type) : Object(ALIGNMENT) +Alignment::Alignment(const Fraction &time, AlignmentType type) : Object(ALIGNMENT) { this->Reset(); m_time = time; @@ -518,7 +609,7 @@ void Alignment::Reset() Object::Reset(); m_xRel = 0; - m_time = 0.0; + m_time = Fraction(0, 1); m_type = ALIGNMENT_DEFAULT; ClearGraceAligners(); @@ -736,13 +827,14 @@ std::pair<int, int> Alignment::GetAlignmentTopBottom() const } int Alignment::HorizontalSpaceForDuration( - double intervalTime, int maxActualDur, double spacingLinear, double spacingNonLinear) + const Fraction &intervalTime, int maxActualDur, double spacingLinear, double spacingNonLinear) { + double doubleIntervalTime = intervalTime.ToDouble(); /* If the longest duration interval in the score is longer than semibreve, adjust spacing so that interval gets the space a semibreve would ordinarily get. */ - if (maxActualDur < DUR_1) intervalTime /= pow(2.0, DUR_1 - maxActualDur); + if (maxActualDur < DUR_1) doubleIntervalTime /= pow(2.0, DUR_1 - maxActualDur); - return pow(intervalTime, spacingNonLinear) * spacingLinear * 10.0; // numbers are experimental constants + return pow(doubleIntervalTime, spacingNonLinear) * spacingLinear * 10.0; // numbers are experimental constants } FunctorCode Alignment::Accept(Functor &functor) diff --git a/src/iopae.cpp b/src/iopae.cpp index 7f7cf315322..5aa0bbd3fc8 100644 --- a/src/iopae.cpp +++ b/src/iopae.cpp @@ -521,7 +521,7 @@ void PAEOutput::WriteTuplet(Tuplet *tuplet) Staff *staff = tuplet->GetAncestorStaff(); - double content = tuplet->GetContentAlignmentDuration(true, staff->m_drawingNotationType); + double content = tuplet->GetContentAlignmentDuration(true, staff->m_drawingNotationType).ToDouble(); // content = DUR_MAX / 2^(dur - 2) int tupletDur = (content != 0.0) ? log2(DUR_MAX / content) + 2 : 4; // We should be looking for dotted values diff --git a/src/layer.cpp b/src/layer.cpp index 560e5642bb2..e76afa8c94d 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -351,8 +351,8 @@ data_STEMDIRECTION Layer::GetDrawingStemDir(const ArrayOfBeamElementCoords *coor // We are ignoring cross-staff situation here because this should not be called if we have one const Staff *staff = first->GetAncestorStaff(); - double time = alignmentFirst->GetTime(); - double duration = 0.0; + Fraction time = alignmentFirst->GetTime(); + Fraction duration; // For the sake of counting number of layers consider only current measure. If first and last elements' layers are // different, take only time within current measure to run GetLayerCountInTimeSpan. const Measure *lastMeasure = vrv_cast<const Measure *>(last->GetFirstAncestor(MEASURE)); @@ -362,7 +362,7 @@ data_STEMDIRECTION Layer::GetDrawingStemDir(const ArrayOfBeamElementCoords *coor else { duration = measure->m_measureAligner.GetRightAlignment()->GetTime() - time; } - duration = durRound(duration); + // duration = durRound(duration); if (this->GetLayerCountInTimeSpan(time, duration, measure, staff->GetN()) < 2) { return STEMDIRECTION_NONE; @@ -392,7 +392,8 @@ int Layer::GetLayerCountForTimeSpanOf(const LayerElement *element) const return static_cast<int>(this->GetLayersNForTimeSpanOf(element).size()); } -std::set<int> Layer::GetLayersNInTimeSpan(double time, double duration, const Measure *measure, int staff) const +std::set<int> Layer::GetLayersNInTimeSpan( + const Fraction &time, const Fraction &duration, const Measure *measure, int staff) const { assert(measure); @@ -409,7 +410,8 @@ std::set<int> Layer::GetLayersNInTimeSpan(double time, double duration, const Me return layersInTimeSpan.GetLayers(); } -int Layer::GetLayerCountInTimeSpan(double time, double duration, const Measure *measure, int staff) const +int Layer::GetLayerCountInTimeSpan( + const Fraction &time, const Fraction &duration, const Measure *measure, int staff) const { return static_cast<int>(this->GetLayersNInTimeSpan(time, duration, measure, staff).size()); } @@ -430,8 +432,8 @@ ListOfConstObjects Layer::GetLayerElementsForTimeSpanOf(const LayerElement *elem const Measure *measure = vrv_cast<const Measure *>(this->GetFirstAncestor(MEASURE)); assert(measure); - double time = 0.0; - double duration = 0.0; + Fraction time; + Fraction duration; const Alignment *alignment = element->GetAlignment(); // Get duration and time if element has alignment if (alignment) { @@ -449,7 +451,7 @@ ListOfConstObjects Layer::GetLayerElementsForTimeSpanOf(const LayerElement *elem if (!first || !last) return {}; time = first->GetAlignment()->GetTime(); - double lastTime = last->GetAlignment()->GetTime(); + Fraction lastTime = last->GetAlignment()->GetTime(); duration = lastTime - time + last->GetAlignmentDuration(); } else { @@ -462,7 +464,7 @@ ListOfConstObjects Layer::GetLayerElementsForTimeSpanOf(const LayerElement *elem } ListOfObjects Layer::GetLayerElementsInTimeSpan( - double time, double duration, const Measure *measure, int staff, bool excludeCurrent) + const Fraction &time, const Fraction &duration, const Measure *measure, int staff, bool excludeCurrent) { ListOfConstObjects elements = std::as_const(*this).GetLayerElementsInTimeSpan(time, duration, measure, staff, excludeCurrent); @@ -473,7 +475,7 @@ ListOfObjects Layer::GetLayerElementsInTimeSpan( } ListOfConstObjects Layer::GetLayerElementsInTimeSpan( - double time, double duration, const Measure *measure, int staff, bool excludeCurrent) const + const Fraction &time, const Fraction &duration, const Measure *measure, int staff, bool excludeCurrent) const { assert(measure); diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 454c91fd311..d7bd8b4cd16 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -671,11 +671,11 @@ int LayerElement::GetDrawingRadius(const Doc *doc, bool isInLigature) const return doc->GetGlyphWidth(code, staff->m_drawingStaffSize, this->GetDrawingCueSize()) / 2; } -double LayerElement::GetAlignmentDuration( +Fraction LayerElement::GetAlignmentDuration( const AlignMeterParams ¶ms, bool notGraceOnly, data_NOTATIONTYPE notationType) const { if (this->IsGraceNote() && notGraceOnly) { - return 0.0; + return Fraction(0, 1); } // Only resolve simple sameas links to avoid infinite recursion @@ -719,11 +719,11 @@ double LayerElement::GetAlignmentDuration( return NEUME_SMALL_SPACE; } } - double durationValue = duration->GetInterfaceAlignmentDuration(num, numbase); + Fraction durationValue = duration->GetInterfaceAlignmentDuration(num, numbase); // With fTrem we need to divide the duration by two const FTrem *fTrem = vrv_cast<const FTrem *>(this->GetFirstAncestor(FTREM, MAX_FTREM_DEPTH)); if (fTrem) { - durationValue /= 2.0; + durationValue = durationValue * Fraction(1, 2); } return durationValue; } @@ -763,11 +763,11 @@ double LayerElement::GetAlignmentDuration( return (syllable->GetLast() == this) ? NEUME_MEDIUM_SPACE : NEUME_SMALL_SPACE; } else { - return 0.0; + return Fraction(0, 1); } } -double LayerElement::GetAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE notationType) const +Fraction LayerElement::GetAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE notationType) const { AlignMeterParams params; params.meterSig = NULL; @@ -775,11 +775,11 @@ double LayerElement::GetAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE n return this->GetAlignmentDuration(params, notGraceOnly, notationType); } -double LayerElement::GetSameAsContentAlignmentDuration( +Fraction LayerElement::GetSameAsContentAlignmentDuration( const AlignMeterParams ¶ms, bool notGraceOnly, data_NOTATIONTYPE notationType) const { if (!this->HasSameasLink() || !this->GetSameasLink()->Is({ BEAM, FTREM, TUPLET })) { - return 0.0; + return Fraction(0, 1); } const LayerElement *sameas = vrv_cast<const LayerElement *>(this->GetSameasLink()); @@ -788,14 +788,14 @@ double LayerElement::GetSameAsContentAlignmentDuration( return sameas->GetContentAlignmentDuration(params, notGraceOnly, notationType); } -double LayerElement::GetContentAlignmentDuration( +Fraction LayerElement::GetContentAlignmentDuration( const AlignMeterParams ¶ms, bool notGraceOnly, data_NOTATIONTYPE notationType) const { if (!this->Is({ BEAM, FTREM, TUPLET })) { - return 0.0; + return Fraction(0, 1); } - double duration = 0.0; + Fraction duration; for (const Object *child : this->GetChildren()) { // Skip everything that does not have a duration interface and notes in chords @@ -804,13 +804,13 @@ double LayerElement::GetContentAlignmentDuration( } const LayerElement *element = vrv_cast<const LayerElement *>(child); assert(element); - duration += element->GetAlignmentDuration(params, notGraceOnly, notationType); + duration = duration + element->GetAlignmentDuration(params, notGraceOnly, notationType); } return duration; } -double LayerElement::GetContentAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE notationType) const +Fraction LayerElement::GetContentAlignmentDuration(bool notGraceOnly, data_NOTATIONTYPE notationType) const { AlignMeterParams params; params.meterSig = NULL; diff --git a/src/measure.cpp b/src/measure.cpp index 13347082ca6..48bd70e42af 100644 --- a/src/measure.cpp +++ b/src/measure.cpp @@ -475,8 +475,8 @@ const Staff *Measure::GetBottomVisibleStaff() const int Measure::EnclosesTime(int time) const { int repeat = 1; - double timeDuration = m_measureAligner.GetRightAlignment()->GetTime() * static_cast<int>(DURATION_4) / DUR_MAX - * 60.0 / m_currentTempo * 1000.0 + double timeDuration = m_measureAligner.GetRightAlignment()->GetTime().ToDouble() * static_cast<int>(DURATION_4) + / DUR_MAX * 60.0 / m_currentTempo * 1000.0 + 0.5; std::vector<double>::const_iterator iter; for (iter = m_realTimeOffsetMilliseconds.begin(); iter != m_realTimeOffsetMilliseconds.end(); ++iter) { diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 05f91a550da..45ea551835c 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -54,7 +54,7 @@ FunctorCode InitOnsetOffsetFunctor::VisitChordEnd(Chord *chord) { LayerElement *element = chord->ThisOrSameasLink(); - double incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType); + double incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; @@ -84,7 +84,7 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement double incrementScoreTime; if (element->Is(REST) || element->Is(SPACE)) { - incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType); + incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); // For rests to be possibly added to the timemap if (element->Is(REST)) { @@ -111,13 +111,13 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement // If the note has a @dur or a @dur.ges, take it into account // This means that overwriting only @dots or @dots.ges will not be taken into account if (chord && !note->HasDur() && !note->HasDurGes()) { - incrementScoreTime = chord->GetAlignmentDuration(m_meterParams, true, m_notationType); + incrementScoreTime = chord->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); } else if (tabGrp && !note->HasDur() && !note->HasDurGes()) { - incrementScoreTime = tabGrp->GetAlignmentDuration(m_meterParams, true, m_notationType); + incrementScoreTime = tabGrp->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); } else { - incrementScoreTime = note->GetAlignmentDuration(m_meterParams, true, m_notationType); + incrementScoreTime = note->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); } incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; @@ -145,14 +145,15 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement BeatRpt *rpt = vrv_cast<BeatRpt *>(element); assert(rpt); - incrementScoreTime = rpt->GetAlignmentDuration(m_meterParams, true, m_notationType); + incrementScoreTime = rpt->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); rpt->SetScoreTimeOnset(m_currentScoreTime); m_currentScoreTime += incrementScoreTime; m_currentRealTimeSeconds += incrementScoreTime * 60.0 / m_currentTempo; } else if (layerElement->Is({ BEAM, LIGATURE, FTREM, TUPLET }) && layerElement->HasSameasLink()) { - incrementScoreTime = layerElement->GetSameAsContentAlignmentDuration(m_meterParams, true, m_notationType); + incrementScoreTime + = layerElement->GetSameAsContentAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); m_currentScoreTime += incrementScoreTime; m_currentRealTimeSeconds += incrementScoreTime * 60.0 / m_currentTempo; @@ -188,7 +189,7 @@ FunctorCode InitOnsetOffsetFunctor::VisitTabGrpEnd(TabGrp *tabGrp) { LayerElement *element = tabGrp->ThisOrSameasLink(); - double incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType); + double incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; @@ -238,8 +239,8 @@ FunctorCode InitMaxMeasureDurationFunctor::VisitMeasureEnd(Measure *measure) const double tempo = this->GetAdjustedTempo(); measure->SetCurrentTempo(tempo); - const double scoreTimeIncrement = measure->m_measureAligner.GetRightAlignment()->GetTime() * m_multiRestFactor - * static_cast<int>(DURATION_4) / DUR_MAX; + const double scoreTimeIncrement = measure->m_measureAligner.GetRightAlignment()->GetTime().ToDouble() + * m_multiRestFactor * static_cast<int>(DURATION_4) / DUR_MAX; m_currentScoreTime += scoreTimeIncrement; m_currentRealTimeSeconds += scoreTimeIncrement * 60.0 / tempo; m_multiRestFactor = 1; @@ -362,7 +363,7 @@ FunctorCode GenerateMIDIFunctor::VisitBeatRpt(const BeatRpt *beatRpt) { // Sameas not taken into account for now AlignMeterParams params; - double beatLength = beatRpt->GetAlignmentDuration(params) / (DUR_MAX / DURATION_4); + double beatLength = beatRpt->GetAlignmentDuration(params).ToDouble() / (DUR_MAX / DURATION_4); double startTime = m_totalTime + beatRpt->GetScoreTimeOnset(); int tpq = m_midiFile->getTPQ(); @@ -702,7 +703,7 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) { if (!pedal->HasDir()) return FUNCTOR_CONTINUE; - double pedalTime = pedal->GetStart()->GetAlignment()->GetTime() * static_cast<int>(DURATION_4) / DUR_MAX; + double pedalTime = pedal->GetStart()->GetAlignment()->GetTime().ToDouble() * static_cast<int>(DURATION_4) / DUR_MAX; double startTime = m_totalTime + pedalTime; int tpq = m_midiFile->getTPQ(); diff --git a/src/view_element.cpp b/src/view_element.cpp index 325723616c7..ee980ff0d13 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -1165,11 +1165,11 @@ void View::DrawMRest(DeviceContext *dc, LayerElement *element, Layer *layer, Sta const bool drawingCueSize = mRest->GetDrawingCueSize(); int x = mRest->GetDrawingX(); - int y = (measure->m_measureAligner.GetMaxTime() >= (DUR_MAX * 2)) + int y = (measure->m_measureAligner.GetMaxTime().ToDouble() >= (DUR_MAX * 2)) ? element->GetDrawingY() - m_doc->GetDrawingDoubleUnit(staffSize) : element->GetDrawingY(); - char32_t rest - = (measure->m_measureAligner.GetMaxTime() >= (DUR_MAX * 2)) ? SMUFL_E4E2_restDoubleWhole : SMUFL_E4E3_restWhole; + char32_t rest = (measure->m_measureAligner.GetMaxTime().ToDouble() >= (DUR_MAX * 2)) ? SMUFL_E4E2_restDoubleWhole + : SMUFL_E4E3_restWhole; x -= m_doc->GetGlyphWidth(rest, staffSize, drawingCueSize) / 2; From 3605499a6e38ad330db334b11e0a03a127035160 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Wed, 2 Oct 2024 19:33:51 +0200 Subject: [PATCH 084/105] Formatting --- src/alignfunctor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index 329b8b2b104..fad1c8874f4 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -310,7 +310,7 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme // get the duration of the event duration = layerElement->GetAlignmentDuration(m_currentParams, true, m_notationType); - //LogDebug("duration %s %f", duration.ToString().c_str(), duration.ToDouble()); + // LogDebug("duration %s %f", duration.ToString().c_str(), duration.ToDouble()); // For timestamp, what we get from GetAlignmentDuration is actually the position of the timestamp // So use it as current time - we can do this because the timestamp loop is redirected from the measure From 75cc51b3541a7b28660bb9d31f709c637552a15c Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 12:44:36 +0200 Subject: [PATCH 085/105] Change additional time variable to Fraction --- include/vrv/durationinterface.h | 7 ++++--- include/vrv/horizontalaligner.h | 2 -- src/durationinterface.cpp | 6 +++--- src/horizontalaligner.cpp | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index 17d0ec0cc22..bf6b9f3b4b2 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -12,6 +12,7 @@ #include "atts_gestural.h" #include "atts_mensural.h" #include "atts_shared.h" +#include "horizontalaligner.h" #include "interface.h" namespace vrv { @@ -57,12 +58,12 @@ class DurationInterface : public Interface, ///@} /** - * Returns the duration (in double) for the element. - * It returns 0.0 for grace notes. + * Returns the duration (in Fraction) for the element. + * It returns 0/1 for grace notes. * Careful: this method is not overriding LayerElement::GetAlignmentDuration since * LayerElement and DurationInterface have no inheritance link. */ - double GetInterfaceAlignmentDuration(int num, int numBase) const; + Fraction GetInterfaceAlignmentDuration(int num, int numBase) const; /** * Returns the duration (in double) for the element for mensural notation diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index ff6a97da218..efa5a210895 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -12,8 +12,6 @@ #include "object.h" #include "vrv.h" -#include <numeric> - namespace vrv { class Accid; diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 27c4ec698e0..c0b526a5e22 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -72,7 +72,7 @@ void DurationInterface::Reset() m_scoreTimeTiedDuration = 0.0; } -double DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) const +Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) const { int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); if (noteDur == DUR_NONE) noteDur = DUR_4; @@ -80,11 +80,11 @@ double DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) co if (this->HasNum()) num *= this->GetNum(); if (this->HasNumbase()) numBase *= this->GetNumbase(); - double duration = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; + Fraction duration = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; int noteDots = (this->HasDotsGes()) ? this->GetDotsGes() : this->GetDots(); if (noteDots != VRV_UNSET) { - duration = 2 * duration - (duration / pow(2, noteDots)); + duration = duration * 2 - (duration / pow(2, noteDots)); } // LogDebug("Duration %d; Dot %d; Alignment %f", noteDur, this->GetDots(), duration); return duration; diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index b6b2df1fd80..5d7371f9044 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -11,6 +11,7 @@ #include <cassert> #include <math.h> +#include <numeric> //---------------------------------------------------------------------------- From cfcf7f379b45d5478d1bcc314566b8d11fd39418 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 14:03:31 +0200 Subject: [PATCH 086/105] Remove unnecessary duration defined values --- include/vrv/durationinterface.h | 2 +- libmei/addons/attdef.h | 19 +-- src/adjustbeamsfunctor.cpp | 7 +- src/adjustxposfunctor.cpp | 4 +- src/beam.cpp | 51 ++++---- src/btrem.cpp | 4 +- src/calcalignmentpitchposfunctor.cpp | 6 +- src/calcdotsfunctor.cpp | 18 +-- src/calcligatureorneumeposfunctor.cpp | 22 ++-- src/calcstemfunctor.cpp | 18 +-- src/drawinginterface.cpp | 4 +- src/durationinterface.cpp | 16 +-- src/horizontalaligner.cpp | 2 +- src/iopae.cpp | 20 +-- src/layerelement.cpp | 32 ++--- src/note.cpp | 26 ++-- src/page.cpp | 2 +- src/preparedatafunctor.cpp | 14 +-- src/rest.cpp | 172 ++++++++++++++------------ src/view_beam.cpp | 14 +-- src/view_element.cpp | 25 ++-- src/view_mensural.cpp | 14 +-- src/view_tab.cpp | 22 ++-- 23 files changed, 263 insertions(+), 251 deletions(-) diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index bf6b9f3b4b2..b52e34d8953 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -85,7 +85,7 @@ class DurationInterface : public Interface, /** * @name Return the actual (gestural) duration of the note, for both CMN and mensural durations * See data_DURATION - * For CMN, it is the same (DURATION_1 == DUR_1) + * For CMN, it is the same (DURATION_1 == DURATION_1) * For mensural, we need to apply the DUR_MENSURAL_MASK */ ///@{ diff --git a/libmei/addons/attdef.h b/libmei/addons/attdef.h index fd991b11345..d04af822ac6 100644 --- a/libmei/addons/attdef.h +++ b/libmei/addons/attdef.h @@ -39,19 +39,6 @@ typedef double data_VU; */ #define DUR_NONE -32 #define DUR_MX -1 // maxima -#define DUR_LG 0 // longa -#define DUR_BR 1 // brevis -#define DUR_1 2 // whole note (semibrevis) -#define DUR_2 3 // half note (minima) -#define DUR_4 4 // ... -#define DUR_8 5 -#define DUR_16 6 -#define DUR_32 7 -#define DUR_64 8 -#define DUR_128 9 -#define DUR_256 10 -#define DUR_512 11 -#define DUR_1024 12 // this is it for now // used for alignement #define DUR_MAX 1024 // mensural duration @@ -102,7 +89,8 @@ typedef std::vector<std::pair<double, double>> data_BULGE; */ enum data_DURATION { DURATION_NONE = DUR_NONE, - DURATION_long = DUR_LG, + DURATION_maxima = DUR_MX, + DURATION_long, DURATION_breve, DURATION_1, DURATION_2, @@ -116,8 +104,7 @@ enum data_DURATION { DURATION_512, DURATION_1024, DURATION_2048, - DURATION_maxima = DUR_MX, - DURATION_longa = DUR_MENSURAL_OFFSET + DUR_LG, + DURATION_longa = DUR_MENSURAL_OFFSET + DURATION_long, DURATION_brevis, DURATION_semibrevis, DURATION_minima, diff --git a/src/adjustbeamsfunctor.cpp b/src/adjustbeamsfunctor.cpp index c887831d837..86c2f41b524 100644 --- a/src/adjustbeamsfunctor.cpp +++ b/src/adjustbeamsfunctor.cpp @@ -69,7 +69,8 @@ FunctorCode AdjustBeamsFunctor::VisitBeam(Beam *beam) } int leftMargin = 0, rightMargin = 0; - const int beamCount = m_outerBeam->GetBeamPartDuration((*beamSegment.m_beamElementCoordRefs.begin())->m_x) - DUR_8; + const int beamCount + = m_outerBeam->GetBeamPartDuration((*beamSegment.m_beamElementCoordRefs.begin())->m_x) - DURATION_8; const int currentBeamYLeft = m_y1 + m_beamSlope * ((*beamSegment.m_beamElementCoordRefs.begin())->m_x - m_x1); const int currentBeamYRight = m_y1 + m_beamSlope * (beamSegment.m_beamElementCoordRefs.back()->m_x - m_x1); leftMargin = (*beamSegment.m_beamElementCoordRefs.begin())->m_yBeam - currentBeamYLeft @@ -130,7 +131,7 @@ FunctorCode AdjustBeamsFunctor::VisitClef(Clef *clef) Staff *staff = clef->GetAncestorStaff(); // find number of beams at current position - const int beams = m_outerBeam->GetBeamPartDuration(clef) - DUR_4; + const int beams = m_outerBeam->GetBeamPartDuration(clef) - DURATION_4; const int beamWidth = m_outerBeam->m_beamWidth; // find beam Y positions that are relevant to current clef const int currentBeamYLeft = m_y1 + m_beamSlope * (clef->GetContentLeft() - m_x1); @@ -298,7 +299,7 @@ FunctorCode AdjustBeamsFunctor::VisitRest(Rest *rest) if (!m_outerBeam) return FUNCTOR_SIBLINGS; // Calculate possible overlap for the rest with beams - const int beams = m_outerBeam->GetBeamPartDuration(rest, false) - DUR_4; + const int beams = m_outerBeam->GetBeamPartDuration(rest, false) - DURATION_4; const int beamWidth = m_outerBeam->m_beamWidth; const int overlapMargin = rest->Intersects(m_outerBeam, SELF, beams * beamWidth, true) * m_directionBias; diff --git a/src/adjustxposfunctor.cpp b/src/adjustxposfunctor.cpp index 1aa27238bf7..eb923f0a974 100644 --- a/src/adjustxposfunctor.cpp +++ b/src/adjustxposfunctor.cpp @@ -406,8 +406,8 @@ std::pair<int, int> AdjustXPosFunctor::CalculateXPosOffset(LayerElement *layerEl if (layerElement->Is({ NOTE, CHORD }) && !layerElement->GetFirstAncestor(TUPLET) && bboxElement->Is(REST) && bboxElement->GetFirstAncestor(TUPLET)) { Rest *rest = vrv_cast<Rest *>(bboxElement); - if (rest->GetDur() > DUR_8) { - overlap = 1.5 * (rest->GetDur() - DUR_8) * drawingUnit; + if (rest->GetDur() > DURATION_8) { + overlap = 1.5 * (rest->GetDur() - DURATION_8) * drawingUnit; } } } diff --git a/src/beam.cpp b/src/beam.cpp index 062426112f6..297674fe23a 100644 --- a/src/beam.cpp +++ b/src/beam.cpp @@ -204,7 +204,7 @@ void BeamSegment::CalcSetStemValues(const Staff *staff, const Doc *doc, const Be int stemOffset = 0; const int unit = doc->GetDrawingUnit(staff->m_drawingStaffSize); if (coord->m_partialFlagPlace == coord->m_beamRelativePlace) { - stemOffset = (coord->m_dur - DUR_8) * beamInterface->m_beamWidth; + stemOffset = (coord->m_dur - DURATION_8) * beamInterface->m_beamWidth; } else if (el->GetIsInBeamSpan() && (coord->m_partialFlagPlace != BEAMPLACE_above) && (coord->m_stem->GetDrawingStemDir() == STEMDIRECTION_up)) { @@ -547,7 +547,7 @@ void BeamSegment::AdjustBeamToTremolos(const Doc *doc, const Staff *staff, const if (!stemmedInterface) continue; Stem *stem = stemmedInterface->GetDrawingStem(); - const int offset = (coord->m_dur - DUR_8) * beamInterface->m_beamWidth + beamInterface->m_beamWidthBlack; + const int offset = (coord->m_dur - DURATION_8) * beamInterface->m_beamWidth + beamInterface->m_beamWidthBlack; const int currentAdjustment = stem->CalculateStemModAdjustment(doc, staff, offset); if (std::abs(currentAdjustment) > std::abs(maxAdjustment)) maxAdjustment = currentAdjustment; } @@ -590,7 +590,7 @@ void BeamSegment::CalcBeamInit( beamInterface->m_beamWidthBlack = doc->GetDrawingBeamWidth(staff->m_drawingStaffSize, beamInterface->m_cueSize); beamInterface->m_beamWidthWhite = doc->GetDrawingBeamWhiteWidth(staff->m_drawingStaffSize, beamInterface->m_cueSize); - if (beamInterface->m_shortestDur == DUR_64) { + if (beamInterface->m_shortestDur == DURATION_64) { beamInterface->m_beamWidthWhite *= 4; beamInterface->m_beamWidthWhite /= 3; } @@ -886,7 +886,7 @@ int BeamSegment::CalcBeamSlopeStep( // duration const int dur = beamInterface->m_shortestDur; // Prevent short step with values not shorter than a 16th - if (shortStep && (dur >= DUR_32)) { + if (shortStep && (dur >= DURATION_32)) { step = unit * 2; shortStep = false; } @@ -1002,7 +1002,7 @@ void BeamSegment::CalcAdjustSlope(const Staff *staff, const Doc *doc, BeamDrawin break; } // Here we should look at duration too because longer values in the middle could actually be OK as they are - else if (((coord != m_lastNoteOrChord) || (coord != m_firstNoteOrChord)) && (coord->m_dur > DUR_8)) { + else if (((coord != m_lastNoteOrChord) || (coord != m_firstNoteOrChord)) && (coord->m_dur > DURATION_8)) { const int durLen = len - 0.9 * unit; if (durLen < refLen) { lengthen = true; @@ -1268,9 +1268,9 @@ int BeamSegment::CalcMixedBeamCenterY(int step, int unit) const std::tuple<int, int, int> BeamSegment::CalcStemDefiningNote(const Staff *staff, data_BEAMPLACE place) const { - int shortestDuration = DUR_4; + int shortestDuration = DURATION_4; int shortestLoc = VRV_UNSET; - int relevantDuration = DUR_4; + int relevantDuration = DURATION_4; int relevantLoc = VRV_UNSET; const data_STEMDIRECTION globalStemDir = (place == BEAMPLACE_below) ? STEMDIRECTION_down : STEMDIRECTION_up; for (BeamElementCoord *coord : m_beamElementCoordRefs) { @@ -1410,9 +1410,10 @@ void BeamSegment::CalcMixedBeamPlace(const Staff *staff) void BeamSegment::CalcPartialFlagPlace() { - // Start from note that is shorter than DUR_8 - we do not care otherwise, since those do not have additional beams + // Start from note that is shorter than DURATION_8 - we do not care otherwise, since those do not have additional + // beams auto start = std::find_if(m_beamElementCoordRefs.begin(), m_beamElementCoordRefs.end(), - [](BeamElementCoord *coord) { return coord->m_dur >= DUR_16; }); + [](BeamElementCoord *coord) { return coord->m_dur >= DURATION_16; }); if (m_beamElementCoordRefs.end() == start) return; while (start != m_beamElementCoordRefs.end()) { auto subdivision = start; @@ -1426,14 +1427,14 @@ void BeamSegment::CalcPartialFlagPlace() // Find first note longer than 8th or first note that is cross-staff auto found = std::find_if(subdivision, m_beamElementCoordRefs.end(), [&](BeamElementCoord *coord) { if (coord->m_element->Is(REST)) return false; - return ((coord->m_beamRelativePlace != place) || (coord->m_dur <= DUR_8) || (coord->m_breaksec)); + return ((coord->m_beamRelativePlace != place) || (coord->m_dur <= DURATION_8) || (coord->m_breaksec)); }); subdivision = found; // Handle different cases, where we either don't want to proceed (e.g. end of the beam reached) or we want // to process them separately (e.g. on direction change from shorter to longer notes, or vice versa, we do // not want last note of the subdivision to have additional beam, so that it's clearly distinguishable). - if ((m_beamElementCoordRefs.end() == found) || ((*found)->m_dur <= DUR_8)) break; + if ((m_beamElementCoordRefs.end() == found) || ((*found)->m_dur <= DURATION_8)) break; if (((*found)->m_breaksec)) breakSec = true; if ((m_beamElementCoordRefs.end() - 1) == found) { subdivision = m_beamElementCoordRefs.end(); @@ -1467,14 +1468,14 @@ void BeamSegment::CalcSetValues() int BeamSegment::GetAdjacentElementsDuration(int elementX) const { if ((elementX < m_beamElementCoordRefs.front()->m_x) || (elementX > m_beamElementCoordRefs.back()->m_x)) { - return DUR_8; + return DURATION_8; } for (int i = 0; i < int(m_beamElementCoordRefs.size()) - 1; ++i) { if ((m_beamElementCoordRefs.at(i)->m_x < elementX) && (m_beamElementCoordRefs.at(i + 1)->m_x > elementX)) { return std::min(m_beamElementCoordRefs.at(i)->m_dur, m_beamElementCoordRefs.at(i + 1)->m_dur); } } - return DUR_8; + return DURATION_8; } int BeamSegment::GetStartingX() const @@ -1960,7 +1961,7 @@ int BeamElementCoord::CalculateStemLength( const int directionBias = (stemDir == STEMDIRECTION_up) ? 1 : -1; int stemLen = directionBias; // For 8th notes, use the shortened stem (if shortened) - if (preferredDur == DUR_8) { + if (preferredDur == DURATION_8) { if (stemLenInHalfUnits != standardStemLen) { stemLen *= stemLenInHalfUnits; } @@ -1971,13 +1972,13 @@ int BeamElementCoord::CalculateStemLength( else { const bool isOddLength = (extend || !isHorizontal); switch (m_dur) { - case (DUR_16): stemLen *= isOddLength ? 14 : 13; break; - case (DUR_32): stemLen *= isOddLength ? 18 : 16; break; - case (DUR_64): stemLen *= isOddLength ? 22 : 20; break; - case (DUR_128): stemLen *= isOddLength ? 26 : 24; break; - case (DUR_256): stemLen *= isOddLength ? 30 : 28; break; - case (DUR_512): stemLen *= isOddLength ? 34 : 32; break; - case (DUR_1024): stemLen *= isOddLength ? 38 : 36; break; + case (DURATION_16): stemLen *= isOddLength ? 14 : 13; break; + case (DURATION_32): stemLen *= isOddLength ? 18 : 16; break; + case (DURATION_64): stemLen *= isOddLength ? 22 : 20; break; + case (DURATION_128): stemLen *= isOddLength ? 26 : 24; break; + case (DURATION_256): stemLen *= isOddLength ? 30 : 28; break; + case (DURATION_512): stemLen *= isOddLength ? 34 : 32; break; + case (DURATION_1024): stemLen *= isOddLength ? 38 : 36; break; default: stemLen *= 14; } } @@ -2080,8 +2081,8 @@ void BeamElementCoord::UpdateStemLength( std::pair<int, int> Beam::GetAdditionalBeamCount() const { - int topShortestDur = DUR_8; - int bottomShortestDur = DUR_8; + int topShortestDur = DURATION_8; + int bottomShortestDur = DURATION_8; std::for_each(m_beamElementCoords.begin(), m_beamElementCoords.end(), [&](BeamElementCoord *coord) { if (coord->m_partialFlagPlace == BEAMPLACE_above) { topShortestDur = std::max(topShortestDur, coord->m_dur); @@ -2091,7 +2092,7 @@ std::pair<int, int> Beam::GetAdditionalBeamCount() const } }); - return { topShortestDur - DUR_8, bottomShortestDur - DUR_8 }; + return { topShortestDur - DURATION_8, bottomShortestDur - DURATION_8 }; } void Beam::SetElementShortening(int shortening) @@ -2109,7 +2110,7 @@ int Beam::GetBeamPartDuration(int x, bool includeRests) const }); // handle cases when coordinate is outside of the beam if (it == m_beamSegment.m_beamElementCoordRefs.end()) { - return DUR_8; + return DURATION_8; } else if (it == m_beamSegment.m_beamElementCoordRefs.begin()) { return (*it)->m_dur; diff --git a/src/btrem.cpp b/src/btrem.cpp index f26464cc33c..97496ef0dcf 100644 --- a/src/btrem.cpp +++ b/src/btrem.cpp @@ -144,11 +144,11 @@ data_STEMMODIFIER BTrem::GetDrawingStemMod() const const int drawingDur = duration->GetActualDur(); if (!this->HasUnitdur()) { - if (drawingDur < DUR_2) return STEMMODIFIER_3slash; + if (drawingDur < DURATION_2) return STEMMODIFIER_3slash; return STEMMODIFIER_NONE; } int slashDur = this->GetUnitdur() - drawingDur; - if (drawingDur < DUR_4) slashDur = this->GetUnitdur() - DUR_4; + if (drawingDur < DURATION_4) slashDur = this->GetUnitdur() - DURATION_4; switch (slashDur) { case 0: return STEMMODIFIER_NONE; case 1: return STEMMODIFIER_1slash; diff --git a/src/calcalignmentpitchposfunctor.cpp b/src/calcalignmentpitchposfunctor.cpp index 188095fc068..b7a95489439 100644 --- a/src/calcalignmentpitchposfunctor.cpp +++ b/src/calcalignmentpitchposfunctor.cpp @@ -169,10 +169,10 @@ FunctorCode CalcAlignmentPitchPosFunctor::VisitLayerElement(LayerElement *layerE // set default location to the middle of the staff Staff *staff = layerElement->GetAncestorStaff(); loc = staff->m_drawingLines - 1; - if ((durInterface->GetDur() < DUR_4) && (loc % 2 != 0)) --loc; + if ((durInterface->GetDur() < DURATION_4) && (loc % 2 != 0)) --loc; // Adjust special cases - if ((durInterface->GetDur() == DUR_1) && (staff->m_drawingLines > 1)) loc += 2; - if ((durInterface->GetDur() == DUR_BR) && (staff->m_drawingLines < 2)) loc -= 2; + if ((durInterface->GetDur() == DURATION_1) && (staff->m_drawingLines > 1)) loc += 2; + if ((durInterface->GetDur() == DURATION_breve) && (staff->m_drawingLines < 2)) loc -= 2; // If within a beam, calculate the rest's height based on it's relationship to the notes that surround it Beam *beam = vrv_cast<Beam *>(layerElement->GetFirstAncestor(BEAM, 1)); diff --git a/src/calcdotsfunctor.cpp b/src/calcdotsfunctor.cpp index 2be321aa7a9..f2bc3cddba8 100644 --- a/src/calcdotsfunctor.cpp +++ b/src/calcdotsfunctor.cpp @@ -80,7 +80,7 @@ FunctorCode CalcDotsFunctor::VisitNote(Note *note) assert(dots); // Stem up, shorter than 4th and not in beam - if ((note->GetDots() > 0) && (m_chordStemDir == STEMDIRECTION_up) && (note->GetDrawingDur() > DUR_4) + if ((note->GetDots() > 0) && (m_chordStemDir == STEMDIRECTION_up) && (note->GetDrawingDur() > DURATION_4) && !note->IsInBeam()) { // Shift according to the flag width if the top note is not flipped if ((note == chord->GetTopNote()) && !note->GetFlippedNotehead()) { @@ -129,7 +129,7 @@ FunctorCode CalcDotsFunctor::VisitRest(Rest *rest) } // Nothing to do - if ((rest->GetDur() <= DUR_BR) || (rest->GetDots() < 1)) { + if ((rest->GetDur() <= DURATION_breve) || (rest->GetDots() < 1)) { return FUNCTOR_SIBLINGS; } @@ -150,12 +150,12 @@ FunctorCode CalcDotsFunctor::VisitRest(Rest *rest) } switch (rest->GetActualDur()) { - case DUR_32: - case DUR_64: loc += 2; break; - case DUR_128: - case DUR_256: loc += 4; break; - case DUR_512: loc += 6; break; - case DUR_1024: loc += 8; break; + case DURATION_32: + case DURATION_64: loc += 2; break; + case DURATION_128: + case DURATION_256: loc += 4; break; + case DURATION_512: loc += 6; break; + case DURATION_1024: loc += 8; break; default: break; } @@ -164,7 +164,7 @@ FunctorCode CalcDotsFunctor::VisitRest(Rest *rest) // HARDCODED int xRel = m_doc->GetDrawingUnit(staffSize) * 2.5; if (drawingCueSize) xRel = m_doc->GetCueSize(xRel); - if (rest->GetDur() > DUR_2) { + if (rest->GetDur() > DURATION_2) { xRel = m_doc->GetGlyphWidth(rest->GetRestGlyph(), staff->m_drawingStaffSize, drawingCueSize); } dots->SetDrawingXRel(std::max(dots->GetDrawingXRel(), xRel)); diff --git a/src/calcligatureorneumeposfunctor.cpp b/src/calcligatureorneumeposfunctor.cpp index efefc3dc3f5..5fb5576ff4f 100644 --- a/src/calcligatureorneumeposfunctor.cpp +++ b/src/calcligatureorneumeposfunctor.cpp @@ -67,18 +67,18 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) // Same treatment for Mx and LG except for positioning, which is done above // We still need to avoid oblique, so keep a flag. bool isMaxima = false; - if (dur1 == DUR_MX) { - dur1 = DUR_LG; + if (dur1 == DURATION_maxima) { + dur1 = DURATION_long; isMaxima = true; } - if (dur2 == DUR_MX) dur2 = DUR_LG; + if (dur2 == DURATION_maxima) dur2 = DURATION_long; int diatonicStep = note->GetDiatonicPitch() - previousNote->GetDiatonicPitch(); bool up = (diatonicStep > 0); bool isLastNote = (note == lastNote); // L - L - if ((dur1 == DUR_LG) && (dur2 == DUR_LG)) { + if ((dur1 == DURATION_long) && (dur2 == DURATION_long)) { if (up) { ligature->m_drawingShapes.at(n1) = LIGATURE_STEM_RIGHT_DOWN; ligature->m_drawingShapes.at(n2) = LIGATURE_STEM_RIGHT_DOWN; @@ -88,7 +88,7 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) } } // L - B - else if ((dur1 == DUR_LG) && (dur2 == DUR_BR)) { + else if ((dur1 == DURATION_long) && (dur2 == DURATION_breve)) { if (up) { ligature->m_drawingShapes.at(n1) = LIGATURE_STEM_RIGHT_DOWN; } @@ -102,7 +102,7 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) } } // B - B - else if ((dur1 == DUR_BR) && (dur2 == DUR_BR)) { + else if ((dur1 == DURATION_breve) && (dur2 == DURATION_breve)) { if (up) { // nothing to change } @@ -119,7 +119,7 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) } } // B - L - else if ((dur1 == DUR_BR) && (dur2 == DUR_LG)) { + else if ((dur1 == DURATION_breve) && (dur2 == DURATION_long)) { if (up) { ligature->m_drawingShapes.at(n2) = LIGATURE_STEM_RIGHT_DOWN; } @@ -133,11 +133,11 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) } } // SB - SB - else if ((dur1 == DUR_1) && (dur2 == DUR_1)) { + else if ((dur1 == DURATION_1) && (dur2 == DURATION_1)) { ligature->m_drawingShapes.at(n1) = LIGATURE_STEM_LEFT_UP; } // SB - L (this should not happen on the first two notes, but this is an encoding problem) - else if ((dur1 == DUR_1) && (dur2 == DUR_LG)) { + else if ((dur1 == DURATION_1) && (dur2 == DURATION_long)) { if (up) { ligature->m_drawingShapes.at(n2) = LIGATURE_STEM_RIGHT_DOWN; } @@ -146,7 +146,7 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) } } // SB - B (this should not happen on the first two notes, but this is an encoding problem) - else if ((dur1 == DUR_1) && (dur2 == DUR_BR)) { + else if ((dur1 == DURATION_1) && (dur2 == DURATION_breve)) { if (up) { // nothing to change } @@ -168,7 +168,7 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) } // With mensural black notation, stack longa going up - if (isLastNote && isMensuralBlack && (dur2 == DUR_LG) && up) { + if (isLastNote && isMensuralBlack && (dur2 == DURATION_long) && up) { // Stack only if at least a third int stackThreshold = 1; // If the previous was going down, adjust the threshold diff --git a/src/calcstemfunctor.cpp b/src/calcstemfunctor.cpp index 36210118578..c5f483ddb31 100644 --- a/src/calcstemfunctor.cpp +++ b/src/calcstemfunctor.cpp @@ -32,7 +32,7 @@ CalcStemFunctor::CalcStemFunctor(Doc *doc) : DocFunctor(doc) { m_chordStemLength = 0; m_verticalCenter = 0; - m_dur = DUR_1; + m_dur = DURATION_1; m_isGraceNote = false; m_isStemSameasSecondary = false; m_tabGrpWithNoNote = false; @@ -348,7 +348,7 @@ FunctorCode CalcStemFunctor::VisitStem(Stem *stem) const bool drawingCueSize = stem->GetDrawingCueSize(); // For notes longer than half notes the stem is always 0 - if (m_dur < DUR_2) { + if (m_dur < DURATION_2) { stem->SetDrawingXRel(0); stem->SetDrawingYRel(0); stem->SetDrawingStemLen(0); @@ -409,7 +409,7 @@ FunctorCode CalcStemFunctor::VisitStem(Stem *stem) int flagOffset = 0; Flag *flag = NULL; // There is never a flag with a duration longer than 8th notes - if (m_dur > DUR_4) { + if (m_dur > DURATION_4) { flag = vrv_cast<Flag *>(stem->GetFirst(FLAG)); assert(flag); // There is never a flag with stem sameas notes @@ -417,7 +417,7 @@ FunctorCode CalcStemFunctor::VisitStem(Stem *stem) flag->m_drawingNbFlags = 0; } else { - flag->m_drawingNbFlags = m_dur - DUR_4; + flag->m_drawingNbFlags = m_dur - DURATION_4; flagOffset = unit * (flag->m_drawingNbFlags + 1); } } @@ -441,7 +441,7 @@ FunctorCode CalcStemFunctor::VisitStem(Stem *stem) int flagHeight = 0; // SMUFL flags cover some additional stem length from the 32th only - if (m_dur > DUR_16) { + if (m_dur > DURATION_16) { assert(flag); Point stemEnd; if (stem->GetDrawingStemDir() == STEMDIRECTION_up) { @@ -450,7 +450,7 @@ FunctorCode CalcStemFunctor::VisitStem(Stem *stem) else { stemEnd = flag->GetStemDownNW(m_doc, staffSize, drawingCueSize); } - // Trick for shortening the stem with DUR_8 + // Trick for shortening the stem with DURATION_8 flagHeight = stemEnd.y; } @@ -496,7 +496,7 @@ FunctorCode CalcStemFunctor::VisitTabDurSym(TabDurSym *tabDurSym) assert(stem); // Do not draw virtual (e.g., whole note) stems - if (m_dur < DUR_2 || m_tabGrpWithNoNote) { + if (m_dur < DURATION_2 || m_tabGrpWithNoNote) { stem->IsVirtual(true); return FUNCTOR_SIBLINGS; } @@ -554,7 +554,7 @@ FunctorCode CalcStemFunctor::VisitTabDurSym(TabDurSym *tabDurSym) int stemSize = tabDurSym->CalcStemLenInThirdUnits(m_staff, stemDir) * m_doc->GetDrawingUnit(staffSize); stemSize /= (3 * stemDirFactor); - if (m_dur == DUR_2) { + if (m_dur == DURATION_2) { // Stems for half notes twice shorter stemSize /= 2; } @@ -565,7 +565,7 @@ FunctorCode CalcStemFunctor::VisitTabDurSym(TabDurSym *tabDurSym) if (m_staff->IsTabGuitar()) { Flag *flag = vrv_cast<Flag *>(stem->GetFirst(FLAG)); if (flag) { - flag->m_drawingNbFlags = m_dur - DUR_4; + flag->m_drawingNbFlags = m_dur - DURATION_4; flag->SetDrawingYRel(-stemSize); } } diff --git a/src/drawinginterface.cpp b/src/drawinginterface.cpp index ebd382c517f..d4be4bf9d35 100644 --- a/src/drawinginterface.cpp +++ b/src/drawinginterface.cpp @@ -108,7 +108,7 @@ void BeamDrawingInterface::Reset() int BeamDrawingInterface::GetTotalBeamWidth() const { - return m_beamWidthBlack + (m_shortestDur - DUR_8) * m_beamWidth; + return m_beamWidthBlack + (m_shortestDur - DURATION_8) * m_beamWidth; } void BeamDrawingInterface::ClearCoords() @@ -459,7 +459,7 @@ bool BeamDrawingInterface::IsRepeatedPattern() const bool BeamDrawingInterface::HasOneStepHeight() const { - if (m_shortestDur < DUR_32) return false; + if (m_shortestDur < DURATION_32) return false; int top = -128; int bottom = 128; diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index c0b526a5e22..e39fad14f98 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -75,7 +75,7 @@ void DurationInterface::Reset() Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) const { int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); - if (noteDur == DUR_NONE) noteDur = DUR_4; + if (noteDur == DUR_NONE) noteDur = DURATION_4; if (this->HasNum()) num *= this->GetNum(); if (this->HasNumbase()) numBase *= this->GetNumbase(); @@ -93,7 +93,7 @@ Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int numBase, const Mensur *currentMensur) const { int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); - if (noteDur == DUR_NONE) noteDur = DUR_4; + if (noteDur == DUR_NONE) noteDur = DURATION_4; if (!currentMensur) { LogWarning("No current mensur for calculating duration"); @@ -139,14 +139,14 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num double ratio = 0.0; double duration = (double)DUR_MENSURAL_REF; switch (noteDur) { - case DUR_MX: + case DURATION_maxima: duration *= (double)abs(currentMensur->GetModusminor()) * (double)abs(currentMensur->GetModusmaior()); break; - case DUR_LG: duration *= (double)abs(currentMensur->GetModusminor()); break; - case DUR_BR: break; - case DUR_1: duration /= (double)abs(currentMensur->GetTempus()); break; + case DURATION_long: duration *= (double)abs(currentMensur->GetModusminor()); break; + case DURATION_breve: break; + case DURATION_1: duration /= (double)abs(currentMensur->GetTempus()); break; default: - ratio = pow(2.0, (double)(noteDur - DUR_2)); + ratio = pow(2.0, (double)(noteDur - DURATION_2)); duration /= (double)abs(currentMensur->GetTempus()) * (double)abs(currentMensur->GetProlatio()) * ratio; break; } @@ -190,7 +190,7 @@ int DurationInterface::CalcActualDur(data_DURATION dur) const { if (dur == DURATION_NONE) return DUR_NONE; // maxima (-1) is a mensural only value - if (dur == DURATION_maxima) return DUR_MX; + if (dur == DURATION_maxima) return DURATION_maxima; return (dur & DUR_MENSURAL_MASK); } diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 5d7371f9044..8315fabfaee 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -833,7 +833,7 @@ int Alignment::HorizontalSpaceForDuration( double doubleIntervalTime = intervalTime.ToDouble(); /* If the longest duration interval in the score is longer than semibreve, adjust spacing so that interval gets the space a semibreve would ordinarily get. */ - if (maxActualDur < DUR_1) doubleIntervalTime /= pow(2.0, DUR_1 - maxActualDur); + if (maxActualDur < DURATION_1) doubleIntervalTime /= pow(2.0, DURATION_1 - maxActualDur); return pow(doubleIntervalTime, spacingNonLinear) * spacingLinear * 10.0; // numbers are experimental constants } diff --git a/src/iopae.cpp b/src/iopae.cpp index 5aa0bbd3fc8..5c654356e48 100644 --- a/src/iopae.cpp +++ b/src/iopae.cpp @@ -528,16 +528,16 @@ void PAEOutput::WriteTuplet(Tuplet *tuplet) std::string dur; switch (tupletDur) { - case (DUR_LG): dur = "0"; break; - case (DUR_BR): dur = "9"; break; - case (DUR_1): dur = "1"; break; - case (DUR_2): dur = "2"; break; - case (DUR_4): dur = "4"; break; - case (DUR_8): dur = "8"; break; - case (DUR_16): dur = "6"; break; - case (DUR_32): dur = "3"; break; - case (DUR_64): dur = "5"; break; - case (DUR_128): dur = "7"; break; + case (DURATION_long): dur = "0"; break; + case (DURATION_breve): dur = "9"; break; + case (DURATION_1): dur = "1"; break; + case (DURATION_2): dur = "2"; break; + case (DURATION_4): dur = "4"; break; + case (DURATION_8): dur = "8"; break; + case (DURATION_16): dur = "6"; break; + case (DURATION_32): dur = "3"; break; + case (DURATION_64): dur = "5"; break; + case (DURATION_128): dur = "7"; break; default: LogWarning("Unsupported tuplet duration"); dur = "4"; } diff --git a/src/layerelement.cpp b/src/layerelement.cpp index d7bd8b4cd16..3a0f99bb6e2 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -73,7 +73,7 @@ namespace vrv { // Large spacing between syllables is a quarter note space -// MAX_DURATION / pow(2.0, (DUR_4 - 2.0)) +// MAX_DURATION / pow(2.0, (DURATION_4 - 2.0)) #define NEUME_LARGE_SPACE 256 // Medium spacing between neume is a 8th note space // MAX_DURATION / pow(2.0, (DUR_5 - 2.0)) @@ -554,7 +554,7 @@ int LayerElement::GetDrawingTop(const Doc *doc, int staffSize, bool withArtic, A if (note) { const DurationInterface *durationInterface = this->GetDurationInterface(); assert(durationInterface); - if (durationInterface->GetNoteOrChordDur(this) < DUR_2) { + if (durationInterface->GetNoteOrChordDur(this) < DURATION_2) { return note->GetDrawingY() + doc->GetDrawingUnit(staffSize); } // We should also take into account the stem shift to the right @@ -592,7 +592,7 @@ int LayerElement::GetDrawingBottom(const Doc *doc, int staffSize, bool withArtic if (note) { const DurationInterface *durationInterface = this->GetDurationInterface(); assert(durationInterface); - if (durationInterface->GetNoteOrChordDur(this) < DUR_2) { + if (durationInterface->GetNoteOrChordDur(this) < DURATION_2) { return note->GetDrawingY() - doc->GetDrawingUnit(staffSize); } // We should also take into account the stem shift to the right @@ -616,7 +616,7 @@ int LayerElement::GetDrawingRadius(const Doc *doc, bool isInLigature) const if (!this->Is({ CHORD, NC, NOTE, REST })) return 0; char32_t code = 0; - int dur = DUR_4; + int dur = DURATION_4; const Staff *staff = this->GetAncestorStaff(); bool isMensuralDur = false; if (this->Is(NOTE)) { @@ -636,13 +636,13 @@ int LayerElement::GetDrawingRadius(const Doc *doc, bool isInLigature) const assert(chord); dur = chord->GetActualDur(); isMensuralDur = chord->IsMensuralDur(); - if (dur == DUR_BR) { + if (dur == DURATION_breve) { code = SMUFL_E0A1_noteheadDoubleWholeSquare; } - else if (dur == DUR_1) { + else if (dur == DURATION_1) { code = SMUFL_E0A2_noteheadWhole; } - else if (dur == DUR_2) { + else if (dur == DURATION_2) { code = SMUFL_E0A3_noteheadHalf; } else { @@ -653,9 +653,9 @@ int LayerElement::GetDrawingRadius(const Doc *doc, bool isInLigature) const code = SMUFL_E0A4_noteheadBlack; } - // Mensural note shorter than DUR_BR - if ((isMensuralDur && (dur <= DUR_BR)) || ((dur == DUR_1) && isInLigature)) { - int widthFactor = (dur == DUR_MX) ? 2 : 1; + // Mensural note shorter than DURATION_breve + if ((isMensuralDur && (dur <= DURATION_breve)) || ((dur == DURATION_1) && isInLigature)) { + int widthFactor = (dur == DURATION_maxima) ? 2 : 1; if (staff->m_drawingNotationType == NOTATIONTYPE_mensural_black) { return widthFactor * doc->GetDrawingBrevisWidth(staff->m_drawingStaffSize) * 0.7; } @@ -1212,11 +1212,11 @@ std::pair<int, bool> LayerElement::CalcElementHorizontalOverlap(const Doc *doc, || ((STEMDIRECTION_up == stemDir) && (parentChord->GetTopNote() == previousNote)); } // Reduce the margin to 0 for whole notes unisson - else if ((currentNote->GetDrawingDur() == DUR_1) && (previousDuration == DUR_1)) { + else if ((currentNote->GetDrawingDur() == DURATION_1) && (previousDuration == DURATION_1)) { horizontalMargin = 0; } if (!isPreviousChord || isEdgeElement || isChordElement) { - if ((currentNote->GetDrawingDur() == DUR_2) && (previousDuration == DUR_2)) { + if ((currentNote->GetDrawingDur() == DURATION_2) && (previousDuration == DURATION_2)) { isInUnison = true; } else if ((!currentNote->IsGraceNote() && !currentNote->GetDrawingCueSize()) @@ -1232,7 +1232,7 @@ std::pair<int, bool> LayerElement::CalcElementHorizontalOverlap(const Doc *doc, isInUnison = true; continue; } - else if ((currentNote->GetDrawingDur() > DUR_2) && (previousDuration > DUR_2)) { + else if ((currentNote->GetDrawingDur() > DURATION_2) && (previousDuration > DURATION_2)) { isInUnison = true; } if (isInUnison && (currentNote->GetDots() == previousNote->GetDots())) { @@ -1240,7 +1240,8 @@ std::pair<int, bool> LayerElement::CalcElementHorizontalOverlap(const Doc *doc, } else { isInUnison = false; - if ((currentNote->GetDrawingDur() <= DUR_1) || (previousNote->GetDrawingDur() <= DUR_1)) { + if ((currentNote->GetDrawingDur() <= DURATION_1) + || (previousNote->GetDrawingDur() <= DURATION_1)) { horizontalMargin *= -1; } else { @@ -1263,7 +1264,8 @@ std::pair<int, bool> LayerElement::CalcElementHorizontalOverlap(const Doc *doc, if (previousNote->GetDrawingLoc() - currentNote->GetDrawingLoc() == -1) { horizontalMargin *= -1; } - else if ((currentNote->GetDrawingDur() <= DUR_1) && (previousNote->GetDrawingDur() <= DUR_1)) { + else if ((currentNote->GetDrawingDur() <= DURATION_1) + && (previousNote->GetDrawingDur() <= DURATION_1)) { continue; } else if (previousNote->m_crossStaff || m_crossStaff) diff --git a/src/note.cpp b/src/note.cpp index 08b8ad11ca2..1037dd17315 100644 --- a/src/note.cpp +++ b/src/note.cpp @@ -473,7 +473,7 @@ int Note::CalcStemLenInThirdUnits(const Staff *staff, data_STEMDIRECTION stemDir // Limit shortening with duration shorter than quarter not when not in a beam - if ((this->GetDrawingDur() > DUR_4) && !this->IsInBeam()) { + if ((this->GetDrawingDur() > DURATION_4) && !this->IsInBeam()) { if (this->GetDrawingStemDir() == STEMDIRECTION_up) { shortening = std::min(4, shortening); } @@ -494,7 +494,7 @@ char32_t Note::GetMensuralNoteheadGlyph() const int drawingDur = this->GetDrawingDur(); // No SMuFL code used for these values - if (drawingDur < DUR_1) { + if (drawingDur < DURATION_1) { return 0; } @@ -507,7 +507,7 @@ char32_t Note::GetMensuralNoteheadGlyph() const } else { if (this->GetColored() == BOOLEAN_true) { - if (drawingDur > DUR_2) { + if (drawingDur > DURATION_2) { code = SMUFL_E93C_mensuralNoteheadMinimaWhite; } else { @@ -515,7 +515,7 @@ char32_t Note::GetMensuralNoteheadGlyph() const } } else { - if (drawingDur > DUR_2) { + if (drawingDur > DURATION_2) { code = SMUFL_E93D_mensuralNoteheadSemiminimaWhite; } else { @@ -549,7 +549,7 @@ char32_t Note::GetNoteheadGlyph(const int duration) const // case HEADSHAPE_circle: return SMUFL_E0B3_noteheadCircleX; case HEADSHAPE_plus: return SMUFL_E0AF_noteheadPlusBlack; case HEADSHAPE_diamond: { - if (duration < DUR_4) { + if (duration < DURATION_4) { return (this->GetHeadFill() == FILL_solid) ? SMUFL_E0DB_noteheadDiamondBlack : SMUFL_E0D9_noteheadDiamondHalf; } @@ -562,7 +562,7 @@ char32_t Note::GetNoteheadGlyph(const int duration) const // case HEADSHAPE_oval: return SMUFL_noteheadOval; // case HEADSHAPE_piewedge: return SMUFL_noteheadPieWedge; case HEADSHAPE_rectangle: - if (duration < DUR_4) { + if (duration < DURATION_4) { return (this->GetHeadFill() == FILL_solid) ? SMUFL_E0B9_noteheadSquareBlack : SMUFL_E0B8_noteheadSquareWhite; } @@ -573,14 +573,14 @@ char32_t Note::GetNoteheadGlyph(const int duration) const // case HEADSHAPE_rtriangle: return SMUFL_noteheadRTriangle; // case HEADSHAPE_semicircle: return SMUFL_noteheadSemicircle; case HEADSHAPE_slash: { - if (DUR_1 >= duration) return SMUFL_E102_noteheadSlashWhiteWhole; - if (DUR_2 == duration) return SMUFL_E103_noteheadSlashWhiteHalf; + if (DURATION_1 >= duration) return SMUFL_E102_noteheadSlashWhiteWhole; + if (DURATION_2 == duration) return SMUFL_E103_noteheadSlashWhiteHalf; return SMUFL_E101_noteheadSlashHorizontalEnds; } // case HEADSHAPE_square: return SMUFL_noteheadSquare; case HEADSHAPE_x: { - if (DUR_1 == duration) return SMUFL_E0B5_noteheadWholeWithX; - if (DUR_2 == duration) return SMUFL_E0B6_noteheadHalfWithX; + if (DURATION_1 == duration) return SMUFL_E0B5_noteheadWholeWithX; + if (DURATION_2 == duration) return SMUFL_E0B6_noteheadHalfWithX; return SMUFL_E0A9_noteheadXBlack; } default: break; @@ -591,10 +591,10 @@ char32_t Note::GetNoteheadGlyph(const int duration) const default: break; } - if (DUR_BR == duration) return SMUFL_E0A1_noteheadDoubleWholeSquare; - if (DUR_1 == duration) return SMUFL_E0A2_noteheadWhole; + if (DURATION_breve == duration) return SMUFL_E0A1_noteheadDoubleWholeSquare; + if (DURATION_1 == duration) return SMUFL_E0A2_noteheadWhole; // We support solid on half notes or void on quarter and shorter notes - if (DUR_2 == duration) { + if (DURATION_2 == duration) { return (this->GetHeadFill() == FILL_solid) ? SMUFL_E0A4_noteheadBlack : SMUFL_E0A3_noteheadHalf; } else { diff --git a/src/page.cpp b/src/page.cpp index 17388407eb8..cab9e92fea6 100644 --- a/src/page.cpp +++ b/src/page.cpp @@ -318,7 +318,7 @@ void Page::ResetAligners() // Unless duration-based spacing is disabled, set the X position of each Alignment. // Does non-linear spacing based on the duration space between two Alignment objects. if (!doc->GetOptions()->m_evenNoteSpacing.GetValue()) { - int longestActualDur = DUR_4; + int longestActualDur = DURATION_4; // Detect the longest duration in order to adjust the spacing (false by default) if (doc->GetOptions()->m_spacingDurDetection.GetValue()) { diff --git a/src/preparedatafunctor.cpp b/src/preparedatafunctor.cpp index 1bb1389a6a6..091b6be6d54 100644 --- a/src/preparedatafunctor.cpp +++ b/src/preparedatafunctor.cpp @@ -1102,11 +1102,11 @@ FunctorCode PrepareLayerElementPartsFunctor::VisitChord(Chord *chord) currentStem->FillAttributes(*chord); int duration = chord->GetNoteOrChordDur(chord); - if ((duration < DUR_2) || (chord->GetStemVisible() == BOOLEAN_false)) { + if ((duration < DURATION_2) || (chord->GetStemVisible() == BOOLEAN_false)) { currentStem->IsVirtual(true); } - const bool shouldHaveFlag = ((duration > DUR_4) && !chord->IsInBeam() && !chord->GetAncestorFTrem()); + const bool shouldHaveFlag = ((duration > DURATION_4) && !chord->IsInBeam() && !chord->GetAncestorFTrem()); currentFlag = this->ProcessFlag(currentFlag, currentStem, shouldHaveFlag); chord->SetDrawingStem(currentStem); @@ -1150,7 +1150,7 @@ FunctorCode PrepareLayerElementPartsFunctor::VisitNote(Note *note) currentStem->AttGraced::operator=(*note); currentStem->FillAttributes(*note); - if (note->GetActualDur() < DUR_2 || (note->GetStemVisible() == BOOLEAN_false)) { + if (note->GetActualDur() < DURATION_2 || (note->GetStemVisible() == BOOLEAN_false)) { currentStem->IsVirtual(true); } } @@ -1177,8 +1177,8 @@ FunctorCode PrepareLayerElementPartsFunctor::VisitNote(Note *note) if (note->IsMensuralDur()) return FUNCTOR_CONTINUE; if (currentStem) { - const bool shouldHaveFlag = ((note->GetActualDur() > DUR_4) && !note->IsInBeam() && !note->GetAncestorFTrem() - && !note->IsChordTone() && !note->IsTabGrpNote()); + const bool shouldHaveFlag = ((note->GetActualDur() > DURATION_4) && !note->IsInBeam() + && !note->GetAncestorFTrem() && !note->IsChordTone() && !note->IsTabGrpNote()); currentFlag = this->ProcessFlag(currentFlag, currentStem, shouldHaveFlag); if (!chord) note->SetDrawingStem(currentStem); @@ -1196,7 +1196,7 @@ FunctorCode PrepareLayerElementPartsFunctor::VisitRest(Rest *rest) { Dots *currentDots = vrv_cast<Dots *>(rest->FindDescendantByType(DOTS, 1)); - const bool shouldHaveDots = (rest->GetDur() > DUR_BR) && (rest->GetDots() > 0); + const bool shouldHaveDots = (rest->GetDur() > DURATION_breve) && (rest->GetDots() > 0); currentDots = this->ProcessDots(currentDots, rest, shouldHaveDots); /************ Prepare the drawing cue size ************/ @@ -1222,7 +1222,7 @@ FunctorCode PrepareLayerElementPartsFunctor::VisitTabDurSym(TabDurSym *tabDurSym assert(tabGrp); // No flag within beam for durations longer than 8th notes - const bool shouldHaveFlag = (!tabDurSym->IsInBeam() && (tabGrp->GetActualDur() > DUR_4)); + const bool shouldHaveFlag = (!tabDurSym->IsInBeam() && (tabGrp->GetActualDur() > DURATION_4)); currentFlag = this->ProcessFlag(currentFlag, currentStem, shouldHaveFlag); return FUNCTOR_SIBLINGS; diff --git a/src/rest.cpp b/src/rest.cpp index 5f0779dd004..444159f8e63 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -37,100 +37,118 @@ RestOffsets g_defaultRests{ { { RA_none, { { RLP_restOnTopLayer, { { RNP_noteInSpace, - { { DUR_1, 3 }, { DUR_2, 3 }, { DUR_4, 5 }, { DUR_8, 5 }, { DUR_16, 7 }, { DUR_32, 7 }, - { DUR_64, 9 }, { DUR_128, 9 }, { DUR_LG, 5 }, { DUR_BR, 5 } } }, + { { DURATION_1, 3 }, { DURATION_2, 3 }, { DURATION_4, 5 }, { DURATION_8, 5 }, + { DURATION_16, 7 }, { DURATION_32, 7 }, { DURATION_64, 9 }, { DURATION_128, 9 }, + { DURATION_long, 5 }, { DURATION_breve, 5 } } }, { RNP_noteOnLine, - { { DUR_1, 2 }, { DUR_2, 4 }, { DUR_4, 6 }, { DUR_8, 4 }, { DUR_16, 6 }, { DUR_32, 6 }, - { DUR_64, 8 }, { DUR_128, 8 }, { DUR_LG, 6 }, { DUR_BR, 4 } } } } }, + { { DURATION_1, 2 }, { DURATION_2, 4 }, { DURATION_4, 6 }, { DURATION_8, 4 }, + { DURATION_16, 6 }, { DURATION_32, 6 }, { DURATION_64, 8 }, { DURATION_128, 8 }, + { DURATION_long, 6 }, { DURATION_breve, 4 } } } } }, { RLP_restOnBottomLayer, { { RNP_noteInSpace, - { { DUR_1, -5 }, { DUR_2, -5 }, { DUR_4, -5 }, { DUR_8, -5 }, { DUR_16, -5 }, - { DUR_32, -7 }, { DUR_64, -7 }, { DUR_128, -9 }, { DUR_LG, -5 }, { DUR_BR, -5 } } }, + { { DURATION_1, -5 }, { DURATION_2, -5 }, { DURATION_4, -5 }, { DURATION_8, -5 }, + { DURATION_16, -5 }, { DURATION_32, -7 }, { DURATION_64, -7 }, { DURATION_128, -9 }, + { DURATION_long, -5 }, { DURATION_breve, -5 } } }, { RNP_noteOnLine, - { { DUR_1, -6 }, { DUR_2, -6 }, { DUR_4, -6 }, { DUR_8, -4 }, { DUR_16, -4 }, - { DUR_32, -6 }, { DUR_64, -6 }, { DUR_128, -8 }, { DUR_LG, -6 }, - { DUR_BR, -6 } } } } } } }, + { { DURATION_1, -6 }, { DURATION_2, -6 }, { DURATION_4, -6 }, { DURATION_8, -4 }, + { DURATION_16, -4 }, { DURATION_32, -6 }, { DURATION_64, -6 }, { DURATION_128, -8 }, + { DURATION_long, -6 }, { DURATION_breve, -6 } } } } } } }, { RA_s, { { RLP_restOnTopLayer, { { RNP_noteInSpace, - { { DUR_1, 3 }, { DUR_2, 5 }, { DUR_4, 7 }, { DUR_8, 5 }, { DUR_16, 7 }, { DUR_32, 7 }, - { DUR_64, 9 }, { DUR_128, 9 }, { DUR_LG, 5 }, { DUR_BR, 5 } } }, + { { DURATION_1, 3 }, { DURATION_2, 5 }, { DURATION_4, 7 }, { DURATION_8, 5 }, + { DURATION_16, 7 }, { DURATION_32, 7 }, { DURATION_64, 9 }, { DURATION_128, 9 }, + { DURATION_long, 5 }, { DURATION_breve, 5 } } }, { RNP_noteOnLine, - { { DUR_1, 2 }, { DUR_2, 4 }, { DUR_4, 6 }, { DUR_8, 6 }, { DUR_16, 8 }, { DUR_32, 8 }, - { DUR_64, 10 }, { DUR_128, 10 }, { DUR_LG, 6 }, { DUR_BR, 4 } } } } }, + { { DURATION_1, 2 }, { DURATION_2, 4 }, { DURATION_4, 6 }, { DURATION_8, 6 }, + { DURATION_16, 8 }, { DURATION_32, 8 }, { DURATION_64, 10 }, { DURATION_128, 10 }, + { DURATION_long, 6 }, { DURATION_breve, 4 } } } } }, { RLP_restOnBottomLayer, { { RNP_noteInSpace, - { { DUR_1, -5 }, { DUR_2, -5 }, { DUR_4, -5 }, { DUR_8, -5 }, { DUR_16, -5 }, - { DUR_32, -7 }, { DUR_64, -7 }, { DUR_128, -9 }, { DUR_LG, -5 }, { DUR_BR, -5 } } }, + { { DURATION_1, -5 }, { DURATION_2, -5 }, { DURATION_4, -5 }, { DURATION_8, -5 }, + { DURATION_16, -5 }, { DURATION_32, -7 }, { DURATION_64, -7 }, { DURATION_128, -9 }, + { DURATION_long, -5 }, { DURATION_breve, -5 } } }, { RNP_noteOnLine, - { { DUR_1, -6 }, { DUR_2, -6 }, { DUR_4, -6 }, { DUR_8, -6 }, { DUR_16, -6 }, - { DUR_32, -6 }, { DUR_64, -6 }, { DUR_128, -8 }, { DUR_LG, -6 }, - { DUR_BR, -6 } } } } } } }, + { { DURATION_1, -6 }, { DURATION_2, -6 }, { DURATION_4, -6 }, { DURATION_8, -6 }, + { DURATION_16, -6 }, { DURATION_32, -6 }, { DURATION_64, -6 }, { DURATION_128, -8 }, + { DURATION_long, -6 }, { DURATION_breve, -6 } } } } } } }, { RA_f, { { RLP_restOnTopLayer, { { RNP_noteInSpace, - { { DUR_1, 3 }, { DUR_2, 5 }, { DUR_4, 5 }, { DUR_8, 5 }, { DUR_16, 7 }, { DUR_32, 7 }, - { DUR_64, 9 }, { DUR_128, 9 }, { DUR_LG, 5 }, { DUR_BR, 5 } } }, + { { DURATION_1, 3 }, { DURATION_2, 5 }, { DURATION_4, 5 }, { DURATION_8, 5 }, + { DURATION_16, 7 }, { DURATION_32, 7 }, { DURATION_64, 9 }, { DURATION_128, 9 }, + { DURATION_long, 5 }, { DURATION_breve, 5 } } }, { RNP_noteOnLine, - { { DUR_1, 4 }, { DUR_2, 4 }, { DUR_4, 6 }, { DUR_8, 6 }, { DUR_16, 8 }, { DUR_32, 8 }, - { DUR_64, 10 }, { DUR_128, 10 }, { DUR_LG, 6 }, { DUR_BR, 4 } } } } }, + { { DURATION_1, 4 }, { DURATION_2, 4 }, { DURATION_4, 6 }, { DURATION_8, 6 }, + { DURATION_16, 8 }, { DURATION_32, 8 }, { DURATION_64, 10 }, { DURATION_128, 10 }, + { DURATION_long, 6 }, { DURATION_breve, 4 } } } } }, { RLP_restOnBottomLayer, { { RNP_noteInSpace, - { { DUR_1, -5 }, { DUR_2, -5 }, { DUR_4, -5 }, { DUR_8, -5 }, { DUR_16, -5 }, - { DUR_32, -7 }, { DUR_64, -7 }, { DUR_128, -9 }, { DUR_LG, -5 }, { DUR_BR, -5 } } }, + { { DURATION_1, -5 }, { DURATION_2, -5 }, { DURATION_4, -5 }, { DURATION_8, -5 }, + { DURATION_16, -5 }, { DURATION_32, -7 }, { DURATION_64, -7 }, { DURATION_128, -9 }, + { DURATION_long, -5 }, { DURATION_breve, -5 } } }, { RNP_noteOnLine, - { { DUR_1, -6 }, { DUR_2, -6 }, { DUR_4, -6 }, { DUR_8, -4 }, { DUR_16, -4 }, - { DUR_32, -6 }, { DUR_64, -6 }, { DUR_128, -8 }, { DUR_LG, -6 }, - { DUR_BR, -6 } } } } } } }, + { { DURATION_1, -6 }, { DURATION_2, -6 }, { DURATION_4, -6 }, { DURATION_8, -4 }, + { DURATION_16, -4 }, { DURATION_32, -6 }, { DURATION_64, -6 }, { DURATION_128, -8 }, + { DURATION_long, -6 }, { DURATION_breve, -6 } } } } } } }, { RA_x, { { RLP_restOnTopLayer, { { RNP_noteInSpace, - { { DUR_1, 3 }, { DUR_2, 3 }, { DUR_4, 5 }, { DUR_8, 5 }, { DUR_16, 7 }, { DUR_32, 7 }, - { DUR_64, 9 }, { DUR_128, 9 }, { DUR_LG, 5 }, { DUR_BR, 5 } } }, + { { DURATION_1, 3 }, { DURATION_2, 3 }, { DURATION_4, 5 }, { DURATION_8, 5 }, + { DURATION_16, 7 }, { DURATION_32, 7 }, { DURATION_64, 9 }, { DURATION_128, 9 }, + { DURATION_long, 5 }, { DURATION_breve, 5 } } }, { RNP_noteOnLine, - { { DUR_1, 2 }, { DUR_2, 4 }, { DUR_4, 6 }, { DUR_8, 6 }, { DUR_16, 8 }, { DUR_32, 8 }, - { DUR_64, 10 }, { DUR_128, 10 }, { DUR_LG, 6 }, { DUR_BR, 4 } } } } }, + { { DURATION_1, 2 }, { DURATION_2, 4 }, { DURATION_4, 6 }, { DURATION_8, 6 }, + { DURATION_16, 8 }, { DURATION_32, 8 }, { DURATION_64, 10 }, { DURATION_128, 10 }, + { DURATION_long, 6 }, { DURATION_breve, 4 } } } } }, { RLP_restOnBottomLayer, { { RNP_noteInSpace, - { { DUR_1, -5 }, { DUR_2, -5 }, { DUR_4, -5 }, { DUR_8, -5 }, { DUR_16, -5 }, - { DUR_32, -7 }, { DUR_64, -7 }, { DUR_128, -9 }, { DUR_LG, -5 }, { DUR_BR, -5 } } }, + { { DURATION_1, -5 }, { DURATION_2, -5 }, { DURATION_4, -5 }, { DURATION_8, -5 }, + { DURATION_16, -5 }, { DURATION_32, -7 }, { DURATION_64, -7 }, { DURATION_128, -9 }, + { DURATION_long, -5 }, { DURATION_breve, -5 } } }, { RNP_noteOnLine, - { { DUR_1, -6 }, { DUR_2, -4 }, { DUR_4, -6 }, { DUR_8, -4 }, { DUR_16, -4 }, - { DUR_32, -6 }, { DUR_64, -6 }, { DUR_128, -8 }, { DUR_LG, -6 }, - { DUR_BR, -6 } } } } } } }, + { { DURATION_1, -6 }, { DURATION_2, -4 }, { DURATION_4, -6 }, { DURATION_8, -4 }, + { DURATION_16, -4 }, { DURATION_32, -6 }, { DURATION_64, -6 }, { DURATION_128, -8 }, + { DURATION_long, -6 }, { DURATION_breve, -6 } } } } } } }, { RA_n, { { RLP_restOnTopLayer, { { RNP_noteInSpace, - { { DUR_1, 3 }, { DUR_2, 3 }, { DUR_4, 5 }, { DUR_8, 5 }, { DUR_16, 7 }, { DUR_32, 7 }, - { DUR_64, 9 }, { DUR_128, 9 }, { DUR_LG, 5 }, { DUR_BR, 5 } } }, + { { DURATION_1, 3 }, { DURATION_2, 3 }, { DURATION_4, 5 }, { DURATION_8, 5 }, + { DURATION_16, 7 }, { DURATION_32, 7 }, { DURATION_64, 9 }, { DURATION_128, 9 }, + { DURATION_long, 5 }, { DURATION_breve, 5 } } }, { RNP_noteOnLine, - { { DUR_1, 2 }, { DUR_2, 6 }, { DUR_4, 6 }, { DUR_8, 6 }, { DUR_16, 8 }, { DUR_32, 8 }, - { DUR_64, 10 }, { DUR_128, 10 }, { DUR_LG, 6 }, { DUR_BR, 4 } } } } }, + { { DURATION_1, 2 }, { DURATION_2, 6 }, { DURATION_4, 6 }, { DURATION_8, 6 }, + { DURATION_16, 8 }, { DURATION_32, 8 }, { DURATION_64, 10 }, { DURATION_128, 10 }, + { DURATION_long, 6 }, { DURATION_breve, 4 } } } } }, { RLP_restOnBottomLayer, { { RNP_noteInSpace, - { { DUR_1, -7 }, { DUR_2, -5 }, { DUR_4, -7 }, { DUR_8, -5 }, { DUR_16, -5 }, - { DUR_32, -7 }, { DUR_64, -7 }, { DUR_128, -9 }, { DUR_LG, -5 }, { DUR_BR, -5 } } }, + { { DURATION_1, -7 }, { DURATION_2, -5 }, { DURATION_4, -7 }, { DURATION_8, -5 }, + { DURATION_16, -5 }, { DURATION_32, -7 }, { DURATION_64, -7 }, { DURATION_128, -9 }, + { DURATION_long, -5 }, { DURATION_breve, -5 } } }, { RNP_noteOnLine, - { { DUR_1, -6 }, { DUR_2, -6 }, { DUR_4, -6 }, { DUR_8, -6 }, { DUR_16, -6 }, - { DUR_32, -6 }, { DUR_64, -6 }, { DUR_128, -8 }, { DUR_LG, -6 }, - { DUR_BR, -6 } } } } } } } } }, + { { DURATION_1, -6 }, { DURATION_2, -6 }, { DURATION_4, -6 }, { DURATION_8, -6 }, + { DURATION_16, -6 }, { DURATION_32, -6 }, { DURATION_64, -6 }, { DURATION_128, -8 }, + { DURATION_long, -6 }, { DURATION_breve, -6 } } } } } } } } }, { RL_sameLayer, { { RA_none, { { RLP_restOnTopLayer, { { RNP_noteInSpace, - { { DUR_1, -1 }, { DUR_2, 1 }, { DUR_4, 1 }, { DUR_8, 1 }, { DUR_16, 3 }, { DUR_32, 3 }, - { DUR_64, 5 }, { DUR_128, 5 }, { DUR_LG, 3 }, { DUR_BR, 1 } } }, + { { DURATION_1, -1 }, { DURATION_2, 1 }, { DURATION_4, 1 }, { DURATION_8, 1 }, + { DURATION_16, 3 }, { DURATION_32, 3 }, { DURATION_64, 5 }, { DURATION_128, 5 }, + { DURATION_long, 3 }, { DURATION_breve, 1 } } }, { RNP_noteOnLine, - { { DUR_1, 0 }, { DUR_2, 0 }, { DUR_4, 2 }, { DUR_8, 2 }, { DUR_16, 2 }, { DUR_32, 2 }, - { DUR_64, 4 }, { DUR_128, 4 }, { DUR_LG, 2 }, { DUR_BR, 2 } } } } }, + { { DURATION_1, 0 }, { DURATION_2, 0 }, { DURATION_4, 2 }, { DURATION_8, 2 }, + { DURATION_16, 2 }, { DURATION_32, 2 }, { DURATION_64, 4 }, { DURATION_128, 4 }, + { DURATION_long, 2 }, { DURATION_breve, 2 } } } } }, { RLP_restOnBottomLayer, { { RNP_noteInSpace, - { { DUR_1, -3 }, { DUR_2, -1 }, { DUR_4, -1 }, { DUR_8, -1 }, { DUR_16, -1 }, { DUR_32, -3 }, - { DUR_64, -3 }, { DUR_128, -5 }, { DUR_LG, -3 }, { DUR_BR, -3 } } }, + { { DURATION_1, -3 }, { DURATION_2, -1 }, { DURATION_4, -1 }, { DURATION_8, -1 }, + { DURATION_16, -1 }, { DURATION_32, -3 }, { DURATION_64, -3 }, { DURATION_128, -5 }, + { DURATION_long, -3 }, { DURATION_breve, -3 } } }, { RNP_noteOnLine, - { { DUR_1, -2 }, { DUR_2, -2 }, { DUR_4, -2 }, { DUR_8, -2 }, { DUR_16, -2 }, - { DUR_32, -4 }, { DUR_64, -4 }, { DUR_128, -6 }, { DUR_LG, -2 }, - { DUR_BR, -2 } } } } } } } } } + { { DURATION_1, -2 }, { DURATION_2, -2 }, { DURATION_4, -2 }, { DURATION_8, -2 }, + { DURATION_16, -2 }, { DURATION_32, -4 }, { DURATION_64, -4 }, { DURATION_128, -6 }, + { DURATION_long, -2 }, { DURATION_breve, -2 } } } } } } } } } }; // helper function for conversion @@ -244,31 +262,31 @@ char32_t Rest::GetRestGlyph(const int duration) const if (this->IsMensuralDur()) { switch (duration) { - case DUR_MX: return SMUFL_E9F0_mensuralRestMaxima; break; - case DUR_LG: return SMUFL_E9F2_mensuralRestLongaImperfecta; break; - case DUR_BR: return SMUFL_E9F3_mensuralRestBrevis; break; - case DUR_1: return SMUFL_E9F4_mensuralRestSemibrevis; break; - case DUR_2: return SMUFL_E9F5_mensuralRestMinima; break; - case DUR_4: return SMUFL_E9F6_mensuralRestSemiminima; break; - case DUR_8: return SMUFL_E9F7_mensuralRestFusa; break; - case DUR_16: return SMUFL_E9F8_mensuralRestSemifusa; break; + case DURATION_maxima: return SMUFL_E9F0_mensuralRestMaxima; break; + case DURATION_long: return SMUFL_E9F2_mensuralRestLongaImperfecta; break; + case DURATION_breve: return SMUFL_E9F3_mensuralRestBrevis; break; + case DURATION_1: return SMUFL_E9F4_mensuralRestSemibrevis; break; + case DURATION_2: return SMUFL_E9F5_mensuralRestMinima; break; + case DURATION_4: return SMUFL_E9F6_mensuralRestSemiminima; break; + case DURATION_8: return SMUFL_E9F7_mensuralRestFusa; break; + case DURATION_16: return SMUFL_E9F8_mensuralRestSemifusa; break; } } else { switch (duration) { - case DUR_LG: return SMUFL_E4E1_restLonga; break; - case DUR_BR: return SMUFL_E4E2_restDoubleWhole; break; - case DUR_1: return SMUFL_E4E3_restWhole; break; - case DUR_2: return SMUFL_E4E4_restHalf; break; - case DUR_4: return SMUFL_E4E5_restQuarter; break; - case DUR_8: return SMUFL_E4E6_rest8th; break; - case DUR_16: return SMUFL_E4E7_rest16th; break; - case DUR_32: return SMUFL_E4E8_rest32nd; break; - case DUR_64: return SMUFL_E4E9_rest64th; break; - case DUR_128: return SMUFL_E4EA_rest128th; break; - case DUR_256: return SMUFL_E4EB_rest256th; break; - case DUR_512: return SMUFL_E4EC_rest512th; break; - case DUR_1024: return SMUFL_E4ED_rest1024th; break; + case DURATION_long: return SMUFL_E4E1_restLonga; break; + case DURATION_breve: return SMUFL_E4E2_restDoubleWhole; break; + case DURATION_1: return SMUFL_E4E3_restWhole; break; + case DURATION_2: return SMUFL_E4E4_restHalf; break; + case DURATION_4: return SMUFL_E4E5_restQuarter; break; + case DURATION_8: return SMUFL_E4E6_rest8th; break; + case DURATION_16: return SMUFL_E4E7_rest16th; break; + case DURATION_32: return SMUFL_E4E8_rest32nd; break; + case DURATION_64: return SMUFL_E4E9_rest64th; break; + case DURATION_128: return SMUFL_E4EA_rest128th; break; + case DURATION_256: return SMUFL_E4EB_rest256th; break; + case DURATION_512: return SMUFL_E4EC_rest512th; break; + case DURATION_1024: return SMUFL_E4ED_rest1024th; break; } } @@ -543,8 +561,8 @@ int Rest::GetRestOffsetFromOptions( { int duration = this->GetActualDur(); // Make sure we are in the boundaries of g_defaultRests - if (duration > DUR_128) duration = DUR_128; - if (duration < DUR_LG) duration = DUR_LG; + if (duration > DURATION_128) duration = DURATION_128; + if (duration < DURATION_long) duration = DURATION_long; return g_defaultRests.at(layer) .at(RL_sameLayer == layer ? location.second : RA_none) .at(isTopLayer ? RLP_restOnTopLayer : RLP_restOnBottomLayer) diff --git a/src/view_beam.cpp b/src/view_beam.cpp index 34d04de9f06..566234d1cc3 100644 --- a/src/view_beam.cpp +++ b/src/view_beam.cpp @@ -152,7 +152,7 @@ void View::DrawFTremSegment(DeviceContext *dc, Staff *staff, FTrem *fTrem) if (!durationElement) return; const int dur = durationElement->GetDur(); - if (dur > DUR_1) { + if (dur > DURATION_1) { // Adjust the x position of the first and last element for taking into account the stem width firstElement->m_x -= (m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize)) / 2; secondElement->m_x += (m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize)) / 2; @@ -177,7 +177,7 @@ void View::DrawFTremSegment(DeviceContext *dc, Staff *staff, FTrem *fTrem) int space = m_doc->GetDrawingBeamWidth(staff->m_drawingStaffSize, fTrem->m_cueSize); // for non-stem notes the bar should be shortened - if (dur < DUR_2) { + if (dur < DURATION_2) { if (fTrem->m_drawingPlace == BEAMPLACE_below) x1 += 2 * space; y1 += 2 * space * fTrem->m_beamSegment.m_beamSlope; if (fTrem->m_drawingPlace == BEAMPLACE_above) x2 -= 2 * space; @@ -186,7 +186,7 @@ void View::DrawFTremSegment(DeviceContext *dc, Staff *staff, FTrem *fTrem) fullBars = allBars; floatingBars = 0; } - else if ((dur > DUR_2) && !floatingBars) { + else if ((dur > DURATION_2) && !floatingBars) { fullBars = dur - 4; floatingBars = allBars - fullBars; } @@ -289,12 +289,12 @@ void View::DrawBeamSegment( } int noteCount = (int)noteIndexes.size(); - int durRef = DUR_8; - int durRef2 = DUR_16; + int durRef = DURATION_8; + int durRef2 = DURATION_16; if (staff->IsTabLuteFrench() || staff->IsTabLuteItalian()) { - durRef = DUR_4; - durRef2 = DUR_8; + durRef = DURATION_4; + durRef2 = DURATION_8; } int barY = 0; diff --git a/src/view_element.cpp b/src/view_element.cpp index ee980ff0d13..0f15863eab9 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -285,7 +285,7 @@ void View::DrawAccid(DeviceContext *dc, LayerElement *element, Layer *layer, Sta if (accid->GetFunc() != accidLog_FUNC_edit) onStaff = (accid->GetOnstaff() != BOOLEAN_false); const int verticalCenter = staffTop - (staff->m_drawingLines - 1) * unit; const data_STEMDIRECTION stemDir = this->GetMensuralStemDir(layer, note, verticalCenter); - if ((drawingDur > DUR_1) || (drawingDur < DUR_BR)) { + if ((drawingDur > DURATION_1) || (drawingDur < DURATION_breve)) { if (stemDir == STEMDIRECTION_up) { noteTop = note->GetDrawingY() + unit * STANDARD_STEMLENGTH; noteBottom -= unit; @@ -600,7 +600,7 @@ void View::DrawChordCluster(DeviceContext *dc, Chord *chord, Layer *layer, Staff dc->StartCustomGraphic("notehead"); - if (chord->GetActualDur() < DUR_4) { + if (chord->GetActualDur() < DURATION_4) { const int line = unit / 2; this->DrawNotFilledRectangle(dc, x + line / 2, y1 - line / 2, x + width - line / 2, y2 + line / 2, line, 0); } @@ -1459,19 +1459,19 @@ void View::DrawNote(DeviceContext *dc, LayerElement *element, Layer *layer, Staf if (note->IsInBeam() && !dc->Is(BBOX_DEVICE_CONTEXT)) { LogWarning("Missing duration for note '%s' in beam", note->GetID().c_str()); } - drawingDur = DUR_4; + drawingDur = DURATION_4; } - if (drawingDur < DUR_BR) { + if (drawingDur < DURATION_breve) { this->DrawMaximaToBrevis(dc, noteY, element, layer, staff); } else { // Whole notes char32_t fontNo; if (note->GetColored() == BOOLEAN_true) { - if (DUR_1 == drawingDur) { + if (DURATION_1 == drawingDur) { fontNo = SMUFL_E0FA_noteheadWholeFilled; } - else if (DUR_2 == drawingDur) { + else if (DURATION_2 == drawingDur) { fontNo = SMUFL_E0FB_noteheadHalfFilled; } else { @@ -1544,7 +1544,7 @@ void View::DrawRest(DeviceContext *dc, LayerElement *element, Layer *layer, Staf if (!dc->Is(BBOX_DEVICE_CONTEXT)) { LogWarning("Missing duration for rest '%s'", rest->GetID().c_str()); } - drawingDur = DUR_4; + drawingDur = DURATION_4; } const char32_t drawingGlyph = rest->GetRestGlyph(drawingDur); @@ -1553,7 +1553,7 @@ void View::DrawRest(DeviceContext *dc, LayerElement *element, Layer *layer, Staf this->DrawSmuflCode(dc, x, y, drawingGlyph, staffSize, drawingCueSize); - if ((drawingDur == DUR_1 || drawingDur == DUR_2 || drawingDur == DUR_BR)) { + if ((drawingDur == DURATION_1 || drawingDur == DURATION_2 || drawingDur == DURATION_breve)) { const int width = m_doc->GetGlyphWidth(drawingGlyph, staffSize, drawingCueSize); int ledgerLineThickness = m_doc->GetOptions()->m_ledgerLineThickness.GetValue() * m_doc->GetDrawingUnit(staffSize); @@ -1569,14 +1569,14 @@ void View::DrawRest(DeviceContext *dc, LayerElement *element, Layer *layer, Staf dc->StartCustomGraphic("ledgerLines"); // single legder line for half and whole rests - if ((drawingDur == DUR_1 || drawingDur == DUR_2) && (y > topMargin || y < bottomMargin)) { + if ((drawingDur == DURATION_1 || drawingDur == DURATION_2) && (y > topMargin || y < bottomMargin)) { dc->DeactivateGraphicX(); this->DrawHorizontalLine( dc, x - ledgerLineExtension, x + width + ledgerLineExtension, y, ledgerLineThickness); dc->ReactivateGraphic(); } // double ledger line for breve rests - else if (drawingDur == DUR_BR && (y >= topMargin || y <= bottomMargin)) { + else if (drawingDur == DURATION_breve && (y >= topMargin || y <= bottomMargin)) { const int height = m_doc->GetGlyphHeight(drawingGlyph, staffSize, drawingCueSize); dc->DeactivateGraphicX(); if (y != topMargin) { @@ -1623,7 +1623,7 @@ void View::DrawStem(DeviceContext *dc, LayerElement *element, Layer *layer, Staf // We check if this belongs to a mensural note Note *parent = vrv_cast<Note *>(stem->GetFirstAncestor(NOTE)); if (parent && parent->IsMensuralDur()) { - if (parent->GetDrawingDur() > DUR_1) { + if (parent->GetDrawingDur() > DURATION_1) { /************** Stem/notehead direction: **************/ const int staffCenter = staff->GetDrawingY() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * (staff->m_drawingLines - 1); @@ -1717,7 +1717,8 @@ void View::DrawStemMod(DeviceContext *dc, LayerElement *element, Staff *staff) // calculate position for the stem mod const int y = note->GetDrawingY() + stemRelY; - const int x = (drawingDur <= DUR_1) ? childElement->GetDrawingX() + childElement->GetDrawingRadius(m_doc) : stemX; + const int x + = (drawingDur <= DURATION_1) ? childElement->GetDrawingX() + childElement->GetDrawingRadius(m_doc) : stemX; if ((code != SMUFL_E645_vocalSprechgesang) || !element->Is(BTREM)) { int adjust = 0; diff --git a/src/view_mensural.cpp b/src/view_mensural.cpp index 2423f321eaf..a02bc5f9cad 100644 --- a/src/view_mensural.cpp +++ b/src/view_mensural.cpp @@ -58,7 +58,7 @@ void View::DrawMensuralNote(DeviceContext *dc, LayerElement *element, Layer *lay if (note->IsInLigature() && !m_options->m_ligatureAsBracket.GetValue()) { this->DrawLigatureNote(dc, element, layer, staff); } - else if (drawingDur < DUR_1) { + else if (drawingDur < DURATION_1) { this->DrawMaximaToBrevis(dc, yNote, element, layer, staff); } // Semibrevis and shorter @@ -169,7 +169,7 @@ void View::DrawMensuralStem(DeviceContext *dc, Note *note, Staff *staff, data_ST /* In black notation, the semiminima gets one flag; in white notation, it gets none. In both cases, as in CWMN, each shorter duration gets one additional flag. */ - const int nbFlags = (mensural_black ? drawingDur - DUR_2 : drawingDur - DUR_4); + const int nbFlags = (mensural_black ? drawingDur - DURATION_2 : drawingDur - DURATION_4); // SMuFL's mensural stems are not centered const int halfStemWidth @@ -218,7 +218,7 @@ void View::DrawMaximaToBrevis(DeviceContext *dc, int y, LayerElement *element, L const int staffSize = staff->m_drawingStaffSize; int shape = LIGATURE_DEFAULT; - if (note->GetActualDur() != DUR_BR) { + if (note->GetActualDur() != DURATION_breve) { bool up = false; // Mensural notes have no Stem child - rely on the MEI @stem.dir if (note->GetStemDir() != STEMDIRECTION_NONE) { @@ -263,7 +263,7 @@ void View::DrawMaximaToBrevis(DeviceContext *dc, int y, LayerElement *element, L // serifs and / or stem this->DrawFilledRectangle(dc, topLeft.x, sides[0], topLeft.x + stemWidth, sides[1]); - if (note->GetActualDur() != DUR_BR) { + if (note->GetActualDur() != DURATION_breve) { // Right side is a stem - end the notehead first dc->EndCustomGraphic(); dc->StartCustomGraphic("stem"); @@ -449,7 +449,7 @@ void View::DrawDotInLigature(DeviceContext *dc, LayerElement *element, Layer *la isVerticalDot = !isLast && (shape & LIGATURE_OBLIQUE); } else { - if (note->GetActualDur() == DUR_1) shiftMultiplier = 3.5; + if (note->GetActualDur() == DURATION_1) shiftMultiplier = 3.5; } int y = note->GetDrawingY(); @@ -484,7 +484,7 @@ void View::DrawPlica(DeviceContext *dc, LayerElement *element, Layer *layer, Sta const bool isMensuralBlack = (staff->m_drawingNotationType == NOTATIONTYPE_mensural_black); const int stemWidth = m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize); - const bool isLonga = (note->GetActualDur() == DUR_LG); + const bool isLonga = (note->GetActualDur() == DURATION_long); const bool up = (plica->GetDir() == STEMDIRECTION_basic_up); int shape = LIGATURE_DEFAULT; @@ -722,7 +722,7 @@ data_STEMDIRECTION View::GetMensuralStemDir(Layer *layer, Note *note, int vertic stemDir = layerStemDir; } else { - if (drawingDur < DUR_1) { + if (drawingDur < DURATION_1) { stemDir = STEMDIRECTION_down; } else { diff --git a/src/view_tab.cpp b/src/view_tab.cpp index dd28a98fe09..6fa926578e3 100644 --- a/src/view_tab.cpp +++ b/src/view_tab.cpp @@ -177,13 +177,13 @@ void View::DrawTabDurSym(DeviceContext *dc, LayerElement *element, Layer *layer, if (!tabGrp->IsInBeam() && !staff->IsTabGuitar()) { int symc = 0; switch (drawingDur) { - case DUR_1: symc = SMUFL_EBA6_luteDurationDoubleWhole; break; // 1 back flag */ - case DUR_2: symc = SMUFL_EBA7_luteDurationWhole; break; // 0 flags - case DUR_4: symc = SMUFL_EBA8_luteDurationHalf; break; // 1 flag - case DUR_8: symc = SMUFL_EBA9_luteDurationQuarter; break; // 2 flags - case DUR_16: symc = SMUFL_EBAA_luteDuration8th; break; // 3 flags - case DUR_32: symc = SMUFL_EBAB_luteDuration16th; break; // 4 flags - case DUR_64: symc = SMUFL_EBAC_luteDuration32nd; break; // 5 flags + case DURATION_1: symc = SMUFL_EBA6_luteDurationDoubleWhole; break; // 1 back flag */ + case DURATION_2: symc = SMUFL_EBA7_luteDurationWhole; break; // 0 flags + case DURATION_4: symc = SMUFL_EBA8_luteDurationHalf; break; // 1 flag + case DURATION_8: symc = SMUFL_EBA9_luteDurationQuarter; break; // 2 flags + case DURATION_16: symc = SMUFL_EBAA_luteDuration8th; break; // 3 flags + case DURATION_32: symc = SMUFL_EBAB_luteDuration16th; break; // 4 flags + case DURATION_64: symc = SMUFL_EBAC_luteDuration32nd; break; // 5 flags default: symc = SMUFL_EBA9_luteDurationQuarter; // 2 flags } @@ -205,9 +205,11 @@ void View::DrawTabDurSym(DeviceContext *dc, LayerElement *element, Layer *layer, } else { // Vertical: the more flags the lower the dots - const int durfactor = DUR_64 - std::min(std::max(drawingDur, DUR_2), DUR_64) + 1; - static_assert(DUR_64 - DUR_2 + 1 == 6); - static_assert(DUR_64 - DUR_64 + 1 == 1); + int durOffset = (drawingDur > DURATION_2) ? drawingDur : DURATION_2; + durOffset = (durOffset < DURATION_64) ? durOffset : DURATION_64; + const int durfactor = DURATION_64 - durOffset + 1; + static_assert(DURATION_64 - DURATION_2 + 1 == 6); + static_assert(DURATION_64 - DURATION_64 + 1 == 1); y += m_doc->GetDrawingUnit(glyphSize) * stemDirFactor * durfactor * 2 / 5; From 66a275b4cb069f237cb21c9e5d2ad1266d26aba7 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 14:27:41 +0200 Subject: [PATCH 087/105] Additional change to data_DURATION type --- include/vrv/durationinterface.h | 8 ++++---- src/durationinterface.cpp | 25 +++++++++++++------------ src/view_element.cpp | 4 ++-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index b52e34d8953..4265aedcfd7 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -89,15 +89,15 @@ class DurationInterface : public Interface, * For mensural, we need to apply the DUR_MENSURAL_MASK */ ///@{ - int GetActualDur() const; - int GetActualDurGes() const; + data_DURATION GetActualDur() const; + data_DURATION GetActualDurGes() const; ///@} /** * If the element is part of a chord, return the chord actual duration, otherwise the note actual duration. * Since we need to check what the element is, we need to pass it as parameter. */ - int GetNoteOrChordDur(const LayerElement *element) const; + data_DURATION GetNoteOrChordDur(const LayerElement *element) const; /** * Return true if the value is a mensural (DURATION_longa, brevis, etc.) @@ -141,7 +141,7 @@ class DurationInterface : public Interface, /** * Calculate the actual duration => translate mensural values */ - int CalcActualDur(data_DURATION dur) const; + data_DURATION CalcActualDur(data_DURATION dur) const; public: // diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index e39fad14f98..07aafa0f0c8 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -74,8 +74,8 @@ void DurationInterface::Reset() Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) const { - int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); - if (noteDur == DUR_NONE) noteDur = DURATION_4; + data_DURATION noteDur = (this->GetDurGes() != DURATION_NONE) ? this->GetActualDurGes() : this->GetActualDur(); + if (noteDur == DURATION_NONE) noteDur = DURATION_4; if (this->HasNum()) num *= this->GetNum(); if (this->HasNumbase()) numBase *= this->GetNumbase(); @@ -93,7 +93,7 @@ Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int numBase, const Mensur *currentMensur) const { int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); - if (noteDur == DUR_NONE) noteDur = DURATION_4; + if (noteDur == DURATION_NONE) noteDur = DURATION_4; if (!currentMensur) { LogWarning("No current mensur for calculating duration"); @@ -174,36 +174,37 @@ bool DurationInterface::IsLastInBeam(const LayerElement *noteOrRest) const return (noteOrRest == beam->GetListBack()); } -int DurationInterface::GetActualDur() const +data_DURATION DurationInterface::GetActualDur() const { const data_DURATION dur = this->HasDur() ? this->GetDur() : this->GetDurDefault(); return this->CalcActualDur(dur); } -int DurationInterface::GetActualDurGes() const +data_DURATION DurationInterface::GetActualDurGes() const { const data_DURATION dur = this->HasDurGes() ? this->GetDurGes() : DURATION_NONE; return this->CalcActualDur(dur); } -int DurationInterface::CalcActualDur(data_DURATION dur) const +data_DURATION DurationInterface::CalcActualDur(data_DURATION dur) const { - if (dur == DURATION_NONE) return DUR_NONE; + if (dur == DURATION_NONE) return DURATION_NONE; // maxima (-1) is a mensural only value if (dur == DURATION_maxima) return DURATION_maxima; - return (dur & DUR_MENSURAL_MASK); + // return (dur & DUR_MENSURAL_MASK); + return DURATION_breve; } -int DurationInterface::GetNoteOrChordDur(const LayerElement *element) const +data_DURATION DurationInterface::GetNoteOrChordDur(const LayerElement *element) const { if (element->Is(CHORD)) { - int duration = this->GetActualDur(); - if (duration != DUR_NONE) return duration; + data_DURATION duration = this->GetActualDur(); + if (duration != DURATION_NONE) return duration; const Chord *chord = vrv_cast<const Chord *>(element); for (const Note *note : { chord->GetTopNote(), chord->GetBottomNote() }) { duration = note->GetActualDur(); - if (duration != DUR_NONE) { + if (duration != DURATION_NONE) { return duration; } } diff --git a/src/view_element.cpp b/src/view_element.cpp index 0f15863eab9..fe041d76cc4 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -1455,7 +1455,7 @@ void View::DrawNote(DeviceContext *dc, LayerElement *element, Layer *layer, Staf if (!(note->GetHeadVisible() == BOOLEAN_false)) { /************** Noteheads: **************/ int drawingDur = note->GetDrawingDur(); - if (drawingDur == DUR_NONE) { + if (drawingDur == DURATION_NONE) { if (note->IsInBeam() && !dc->Is(BBOX_DEVICE_CONTEXT)) { LogWarning("Missing duration for note '%s' in beam", note->GetID().c_str()); } @@ -1540,7 +1540,7 @@ void View::DrawRest(DeviceContext *dc, LayerElement *element, Layer *layer, Staf const bool drawingCueSize = rest->GetDrawingCueSize(); const int staffSize = staff->GetDrawingStaffNotationSize(); int drawingDur = rest->GetActualDur(); - if (drawingDur == DUR_NONE) { + if (drawingDur == DURATION_NONE) { if (!dc->Is(BBOX_DEVICE_CONTEXT)) { LogWarning("Missing duration for rest '%s'", rest->GetID().c_str()); } From 0113f25c4f4215f90b02f3efcd1ba55e6d858b08 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 16:08:21 +0200 Subject: [PATCH 088/105] Change durations from int to data_DURATION for better typing * 2 static_cast left in BeamSegment::AdjustBeamToFrenchStyle * 1 static_cast left in BeamSegment::CalcStemDefiningNote --- include/vrv/beam.h | 4 ++-- include/vrv/calcalignmentxposfunctor.h | 4 ++-- include/vrv/calcstemfunctor.h | 4 ++-- include/vrv/drawinginterface.h | 2 +- include/vrv/note.h | 4 ++-- include/vrv/rest.h | 2 +- include/vrv/vrv.h | 7 ++++++ src/beam.cpp | 33 ++++++++++++++------------ src/calcalignmentxposfunctor.cpp | 2 +- src/calcligatureorneumeposfunctor.cpp | 4 ++-- src/calcstemfunctor.cpp | 2 +- src/drawinginterface.cpp | 6 ++--- src/durationinterface.cpp | 16 +++++++++---- src/layerelement.cpp | 4 ++-- src/note.cpp | 6 ++--- src/page.cpp | 2 +- src/preparedatafunctor.cpp | 2 +- src/rest.cpp | 4 ++-- src/view_beam.cpp | 6 ++--- src/view_element.cpp | 6 ++--- src/view_mensural.cpp | 6 ++--- src/vrv.cpp | 10 ++++++++ 22 files changed, 82 insertions(+), 54 deletions(-) diff --git a/include/vrv/beam.h b/include/vrv/beam.h index 5ae37892360..855d556417d 100644 --- a/include/vrv/beam.h +++ b/include/vrv/beam.h @@ -156,7 +156,7 @@ class BeamSegment { int CalcMixedBeamCenterY(int step, int unit) const; // Helper to calculate location and duration of the note that would be setting highest/lowest point for the beam - std::tuple<int, int, int> CalcStemDefiningNote(const Staff *staff, data_BEAMPLACE place) const; + std::tuple<int, int, data_DURATION> CalcStemDefiningNote(const Staff *staff, data_BEAMPLACE place) const; // Calculate positioning for the horizontal beams void CalcHorizontalBeam(const Doc *doc, const Staff *staff, const BeamDrawingInterface *beamInterface); @@ -454,7 +454,7 @@ class BeamElementCoord { int m_x; int m_yBeam; // y value of stem top position - int m_dur; // drawing duration + data_DURATION m_dur; // drawing duration int m_breaksec; int m_overlapMargin; int m_maxShortening; // maximum allowed shortening in half units diff --git a/include/vrv/calcalignmentxposfunctor.h b/include/vrv/calcalignmentxposfunctor.h index 5eda96449a8..2680dc611e5 100644 --- a/include/vrv/calcalignmentxposfunctor.h +++ b/include/vrv/calcalignmentxposfunctor.h @@ -40,7 +40,7 @@ class CalcAlignmentXPosFunctor : public DocFunctor { */ ///@{ int GetLongestActualDur() const { return m_longestActualDur; } - void SetLongestActualDur(int dur) { m_longestActualDur = dur; } + void SetLongestActualDur(data_DURATION dur) { m_longestActualDur = dur; } ///@} /* @@ -65,7 +65,7 @@ class CalcAlignmentXPosFunctor : public DocFunctor { // The previous x rel position int m_previousXRel; // Duration of the longest note - int m_longestActualDur; + data_DURATION m_longestActualDur; // The estimated justification ratio of the system double m_estimatedJustificationRatio; // The last alignment that was not timestamp-only diff --git a/include/vrv/calcstemfunctor.h b/include/vrv/calcstemfunctor.h index ee414083668..c90f8db60a8 100644 --- a/include/vrv/calcstemfunctor.h +++ b/include/vrv/calcstemfunctor.h @@ -62,7 +62,7 @@ class CalcStemFunctor : public DocFunctor { * Adjusts the flag placement and stem length if they are crossing notehead or ledger lines */ void AdjustFlagPlacement( - const Doc *doc, Stem *stem, Flag *flag, int staffSize, int verticalCenter, int duration) const; + const Doc *doc, Stem *stem, Flag *flag, int staffSize, int verticalCenter, data_DURATION duration) const; public: // @@ -72,7 +72,7 @@ class CalcStemFunctor : public DocFunctor { // The vertical center of the staff int m_verticalCenter; // The actual duration of the chord / note - int m_dur; + data_DURATION m_dur; // The flag for grace notes (stem is not extended) bool m_isGraceNote; // The flag for stem.sameas notes diff --git a/include/vrv/drawinginterface.h b/include/vrv/drawinginterface.h index 32d2e88e253..49b85b6c421 100644 --- a/include/vrv/drawinginterface.h +++ b/include/vrv/drawinginterface.h @@ -186,7 +186,7 @@ class BeamDrawingInterface : public ObjectListInterface { Staff *m_crossStaffContent; data_STAFFREL_basic m_crossStaffRel; bool m_isSpanningElement; - int m_shortestDur; + data_DURATION m_shortestDur; data_STEMDIRECTION m_notesStemDir; data_BEAMPLACE m_drawingPlace; Staff *m_beamStaff; diff --git a/include/vrv/note.h b/include/vrv/note.h index b6b8261ac6f..2ab4cc48bcf 100644 --- a/include/vrv/note.h +++ b/include/vrv/note.h @@ -146,7 +146,7 @@ class Note : public LayerElement, ///@{ Chord *IsChordTone(); const Chord *IsChordTone() const; - int GetDrawingDur() const; + data_DURATION GetDrawingDur() const; bool IsNoteGroupExtreme() const; // used to find if it is the highest or lowest note in a note group ///@} @@ -211,7 +211,7 @@ class Note : public LayerElement, /** * Return a SMuFL code for the notehead */ - char32_t GetNoteheadGlyph(const int duration) const; + char32_t GetNoteheadGlyph(const data_DURATION duration) const; /** * Check whether current note is enharmonic with another diff --git a/include/vrv/rest.h b/include/vrv/rest.h index b737eebc0d7..506df84a891 100644 --- a/include/vrv/rest.h +++ b/include/vrv/rest.h @@ -84,7 +84,7 @@ class Rest : public LayerElement, */ ///@{ char32_t GetRestGlyph() const; - char32_t GetRestGlyph(const int duration) const; + char32_t GetRestGlyph(const data_DURATION duration) const; ///@} /** diff --git a/include/vrv/vrv.h b/include/vrv/vrv.h index d103807cd37..9a8a80937cf 100644 --- a/include/vrv/vrv.h +++ b/include/vrv/vrv.h @@ -22,6 +22,7 @@ #include <time.h> #endif +#include "attdef.h" #include "atttypes.h" #include "toolkitdef.h" @@ -131,6 +132,12 @@ std::string FromCamelCase(const std::string &s); */ std::string ToCamelCase(const std::string &s); +/* + * Min / Max for data_DURATION (std::min/max not possible) + */ +data_DURATION DurationMin(data_DURATION dur1, data_DURATION dur2); +data_DURATION DurationMax(data_DURATION dur1, data_DURATION dur2); + /** * */ diff --git a/src/beam.cpp b/src/beam.cpp index 297674fe23a..8eddeb4968a 100644 --- a/src/beam.cpp +++ b/src/beam.cpp @@ -457,7 +457,7 @@ void BeamSegment::AdjustBeamToFrenchStyle(const BeamDrawingInterface *beamInterf assert(beamInterface); // set to store durations of relevant notes (it's ordered, so min duration is going to be first) - std::set<int> noteDurations; + std::set<data_DURATION> noteDurations; // lambda check whether coord has element set and whether that element is CHORD or NOTE const auto isNoteOrChord = [](BeamElementCoord *coord) { return (coord->m_element && coord->m_element->Is({ CHORD, NOTE })); }; @@ -470,7 +470,9 @@ void BeamSegment::AdjustBeamToFrenchStyle(const BeamDrawingInterface *beamInterf if (!isNoteOrChord(*it)) continue; // get current element duration - const int val = (*it)->m_breaksec ? std::min((*it)->m_breaksec + DURATION_4, (*it)->m_dur) : (*it)->m_dur; + const data_DURATION val = (*it)->m_breaksec + ? vrv::DurationMin(static_cast<data_DURATION>((*it)->m_breaksec + DURATION_4), (*it)->m_dur) + : (*it)->m_dur; noteDurations.insert(val); // get next element duration CoordIt nextElement = std::find_if(it + 1, m_beamElementCoordRefs.end(), isNoteOrChord); @@ -481,8 +483,9 @@ void BeamSegment::AdjustBeamToFrenchStyle(const BeamDrawingInterface *beamInterf CoordReverseIt reverse = std::make_reverse_iterator(it); CoordReverseIt prevElement = std::find_if(reverse, m_beamElementCoordRefs.rend(), isNoteOrChord); if (prevElement != m_beamElementCoordRefs.rend()) { - const int prevVal = (*prevElement)->m_breaksec - ? std::min((*prevElement)->m_breaksec + DURATION_4, (*prevElement)->m_dur) + const data_DURATION prevVal = (*prevElement)->m_breaksec + ? vrv::DurationMin( + static_cast<data_DURATION>((*prevElement)->m_breaksec + DURATION_4), (*prevElement)->m_dur) : (*prevElement)->m_dur; noteDurations.insert(prevVal); } @@ -884,7 +887,7 @@ int BeamSegment::CalcBeamSlopeStep( } // duration - const int dur = beamInterface->m_shortestDur; + const data_DURATION dur = beamInterface->m_shortestDur; // Prevent short step with values not shorter than a 16th if (shortStep && (dur >= DURATION_32)) { step = unit * 2; @@ -1212,7 +1215,7 @@ void BeamSegment::CalcBeamStemLength(const Staff *staff, data_BEAMPLACE place, b // skip current element if it's longer that minDuration and is not a part of fTrem if ((coord->m_dur < noteDur) && !(coord->m_element && coord->m_element->GetFirstAncestor(FTREM))) continue; // adjust stem length if location matches - const int dur = (preferredDur != 0) ? preferredDur : coord->m_dur; + const data_DURATION dur = (preferredDur != 0) ? preferredDur : coord->m_dur; const int coordStemLength = coord->CalculateStemLength(staff, stemDir, isHorizontal, dur); if (coord->m_closestNote->GetDrawingLoc() == noteLoc) { m_uniformStemLength = coordStemLength; @@ -1266,11 +1269,11 @@ int BeamSegment::CalcMixedBeamCenterY(int step, int unit) const return centerY; } -std::tuple<int, int, int> BeamSegment::CalcStemDefiningNote(const Staff *staff, data_BEAMPLACE place) const +std::tuple<int, int, data_DURATION> BeamSegment::CalcStemDefiningNote(const Staff *staff, data_BEAMPLACE place) const { - int shortestDuration = DURATION_4; + data_DURATION shortestDuration = DURATION_4; int shortestLoc = VRV_UNSET; - int relevantDuration = DURATION_4; + data_DURATION relevantDuration = DURATION_4; int relevantLoc = VRV_UNSET; const data_STEMDIRECTION globalStemDir = (place == BEAMPLACE_below) ? STEMDIRECTION_down : STEMDIRECTION_up; for (BeamElementCoord *coord : m_beamElementCoordRefs) { @@ -1313,7 +1316,7 @@ std::tuple<int, int, int> BeamSegment::CalcStemDefiningNote(const Staff *staff, } } - int adjusted_duration = 0; + data_DURATION adjusted_duration = DURATION_NONE; // if shortest note location does not offset its duration (shorter notes need more space for additional beams) then // give preference to the its location if ((shortestDuration - relevantDuration) > (std::abs(relevantLoc - shortestLoc) + 1)) { @@ -1328,7 +1331,7 @@ std::tuple<int, int, int> BeamSegment::CalcStemDefiningNote(const Staff *staff, } } else if ((shortestDuration - relevantDuration) == std::abs(relevantLoc - shortestLoc)) { - adjusted_duration = (relevantDuration + shortestDuration) / 2; + adjusted_duration = static_cast<data_DURATION>((relevantDuration + shortestDuration) / 2); } return { relevantLoc, relevantDuration, adjusted_duration }; @@ -2081,14 +2084,14 @@ void BeamElementCoord::UpdateStemLength( std::pair<int, int> Beam::GetAdditionalBeamCount() const { - int topShortestDur = DURATION_8; - int bottomShortestDur = DURATION_8; + data_DURATION topShortestDur = DURATION_8; + data_DURATION bottomShortestDur = DURATION_8; std::for_each(m_beamElementCoords.begin(), m_beamElementCoords.end(), [&](BeamElementCoord *coord) { if (coord->m_partialFlagPlace == BEAMPLACE_above) { - topShortestDur = std::max(topShortestDur, coord->m_dur); + topShortestDur = vrv::DurationMax(topShortestDur, coord->m_dur); } else if (coord->m_partialFlagPlace == BEAMPLACE_below) { - bottomShortestDur = std::max(bottomShortestDur, coord->m_dur); + bottomShortestDur = vrv::DurationMax(bottomShortestDur, coord->m_dur); } }); diff --git a/src/calcalignmentxposfunctor.cpp b/src/calcalignmentxposfunctor.cpp index cad0ee57f3d..1aaf14eeddc 100644 --- a/src/calcalignmentxposfunctor.cpp +++ b/src/calcalignmentxposfunctor.cpp @@ -24,7 +24,7 @@ CalcAlignmentXPosFunctor::CalcAlignmentXPosFunctor(Doc *doc) : DocFunctor(doc) { m_previousTime = 0.0; m_previousXRel = 0; - m_longestActualDur = 0; + m_longestActualDur = DURATION_NONE; m_estimatedJustificationRatio = 1.0; m_lastNonTimestamp = NULL; m_measureAligner = NULL; diff --git a/src/calcligatureorneumeposfunctor.cpp b/src/calcligatureorneumeposfunctor.cpp index 5fb5576ff4f..4ed08423439 100644 --- a/src/calcligatureorneumeposfunctor.cpp +++ b/src/calcligatureorneumeposfunctor.cpp @@ -62,8 +62,8 @@ FunctorCode CalcLigatureOrNeumePosFunctor::VisitLigature(Ligature *ligature) // Look at the @lig attribute on the previous note if (previousNote->GetLig() == LIGATUREFORM_obliqua) oblique = true; - int dur1 = previousNote->GetActualDur(); - int dur2 = note->GetActualDur(); + data_DURATION dur1 = previousNote->GetActualDur(); + data_DURATION dur2 = note->GetActualDur(); // Same treatment for Mx and LG except for positioning, which is done above // We still need to avoid oblique, so keep a flag. bool isMaxima = false; diff --git a/src/calcstemfunctor.cpp b/src/calcstemfunctor.cpp index c5f483ddb31..17a65040e5a 100644 --- a/src/calcstemfunctor.cpp +++ b/src/calcstemfunctor.cpp @@ -621,7 +621,7 @@ data_STEMDIRECTION CalcStemFunctor::CalcStemDirection(const Chord *chord, int ve } void CalcStemFunctor::AdjustFlagPlacement( - const Doc *doc, Stem *stem, Flag *flag, int staffSize, int verticalCenter, int duration) const + const Doc *doc, Stem *stem, Flag *flag, int staffSize, int verticalCenter, data_DURATION duration) const { assert(stem->GetParent()); assert(stem->GetParent()->IsLayerElement()); diff --git a/src/drawinginterface.cpp b/src/drawinginterface.cpp index d4be4bf9d35..facd2c57737 100644 --- a/src/drawinginterface.cpp +++ b/src/drawinginterface.cpp @@ -94,7 +94,7 @@ void BeamDrawingInterface::Reset() m_crossStaffContent = NULL; m_crossStaffRel = STAFFREL_basic_NONE; m_isSpanningElement = false; - m_shortestDur = 0; + m_shortestDur = DURATION_NONE; m_notesStemDir = STEMDIRECTION_NONE; m_drawingPlace = BEAMPLACE_NONE; m_beamStaff = NULL; @@ -148,7 +148,7 @@ void BeamDrawingInterface::InitCoords(const ListOfObjects &childList, Staff *sta // Beam list should contain only DurationInterface objects assert(current->GetDurationInterface()); - int lastDur = (current->GetDurationInterface())->GetActualDur(); + data_DURATION lastDur = (current->GetDurationInterface())->GetActualDur(); /******************************************************************/ // Populate BeamElementCoord for each element in the beam @@ -164,7 +164,7 @@ void BeamDrawingInterface::InitCoords(const ListOfObjects &childList, Staff *sta do { // Beam list should contain only DurationInterface objects assert(current->GetDurationInterface()); - const int currentDur = (current->GetDurationInterface())->GetActualDur(); + const data_DURATION currentDur = (current->GetDurationInterface())->GetActualDur(); if (current->Is(CHORD)) { m_beamHasChord = true; diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 07aafa0f0c8..e6675538482 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -188,11 +188,19 @@ data_DURATION DurationInterface::GetActualDurGes() const data_DURATION DurationInterface::CalcActualDur(data_DURATION dur) const { - if (dur == DURATION_NONE) return DURATION_NONE; // maxima (-1) is a mensural only value - if (dur == DURATION_maxima) return DURATION_maxima; - // return (dur & DUR_MENSURAL_MASK); - return DURATION_breve; + if (dur < DUR_MAX) return dur; + // Mensural duration (except maxima) + switch (dur) { + case (DURATION_longa): return DURATION_long; + case (DURATION_brevis): return DURATION_breve; + case (DURATION_semibrevis): return DURATION_1; + case (DURATION_minima): return DURATION_2; + case (DURATION_semiminima): return DURATION_4; + case (DURATION_fusa): return DURATION_8; + case (DURATION_semifusa): return DURATION_16; + default: return DURATION_NONE; + } } data_DURATION DurationInterface::GetNoteOrChordDur(const LayerElement *element) const diff --git a/src/layerelement.cpp b/src/layerelement.cpp index 3a0f99bb6e2..cd6c0da8a44 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -616,7 +616,7 @@ int LayerElement::GetDrawingRadius(const Doc *doc, bool isInLigature) const if (!this->Is({ CHORD, NC, NOTE, REST })) return 0; char32_t code = 0; - int dur = DURATION_4; + data_DURATION dur = DURATION_4; const Staff *staff = this->GetAncestorStaff(); bool isMensuralDur = false; if (this->Is(NOTE)) { @@ -1200,7 +1200,7 @@ std::pair<int, bool> LayerElement::CalcElementHorizontalOverlap(const Doc *doc, isUnisonElement = currentNote->IsUnisonWith(previousNote, true); // Unisson, look at the duration for the note heads if (unison && currentNote->IsUnisonWith(previousNote, false)) { - int previousDuration = previousNote->GetDrawingDur(); + data_DURATION previousDuration = previousNote->GetDrawingDur(); assert(previousNote->GetParent()); const bool isPreviousChord = previousNote->GetParent()->Is(CHORD); bool isEdgeElement = false; diff --git a/src/note.cpp b/src/note.cpp index 1037dd17315..54af2ee5695 100644 --- a/src/note.cpp +++ b/src/note.cpp @@ -239,7 +239,7 @@ const Chord *Note::IsChordTone() const return vrv_cast<const Chord *>(this->GetFirstAncestor(CHORD, MAX_CHORD_DEPTH)); } -int Note::GetDrawingDur() const +data_DURATION Note::GetDrawingDur() const { const Chord *chordParent = vrv_cast<const Chord *>(this->GetFirstAncestor(CHORD, MAX_CHORD_DEPTH)); if (chordParent && !this->HasDur()) { @@ -491,7 +491,7 @@ char32_t Note::GetMensuralNoteheadGlyph() const { assert(this->IsMensuralDur()); - int drawingDur = this->GetDrawingDur(); + data_DURATION drawingDur = this->GetDrawingDur(); // No SMuFL code used for these values if (drawingDur < DURATION_1) { @@ -526,7 +526,7 @@ char32_t Note::GetMensuralNoteheadGlyph() const return code; } -char32_t Note::GetNoteheadGlyph(const int duration) const +char32_t Note::GetNoteheadGlyph(const data_DURATION duration) const { static std::map<std::string, char32_t> additionalNoteheadSymbols = { { "noteheadDiamondBlackWide", SMUFL_E0DC_noteheadDiamondBlackWide }, diff --git a/src/page.cpp b/src/page.cpp index cab9e92fea6..a5de8172a24 100644 --- a/src/page.cpp +++ b/src/page.cpp @@ -318,7 +318,7 @@ void Page::ResetAligners() // Unless duration-based spacing is disabled, set the X position of each Alignment. // Does non-linear spacing based on the duration space between two Alignment objects. if (!doc->GetOptions()->m_evenNoteSpacing.GetValue()) { - int longestActualDur = DURATION_4; + data_DURATION longestActualDur = DURATION_4; // Detect the longest duration in order to adjust the spacing (false by default) if (doc->GetOptions()->m_spacingDurDetection.GetValue()) { diff --git a/src/preparedatafunctor.cpp b/src/preparedatafunctor.cpp index 091b6be6d54..8666862c692 100644 --- a/src/preparedatafunctor.cpp +++ b/src/preparedatafunctor.cpp @@ -1101,7 +1101,7 @@ FunctorCode PrepareLayerElementPartsFunctor::VisitChord(Chord *chord) currentStem->AttGraced::operator=(*chord); currentStem->FillAttributes(*chord); - int duration = chord->GetNoteOrChordDur(chord); + data_DURATION duration = chord->GetNoteOrChordDur(chord); if ((duration < DURATION_2) || (chord->GetStemVisible() == BOOLEAN_false)) { currentStem->IsVirtual(true); } diff --git a/src/rest.cpp b/src/rest.cpp index 444159f8e63..323cb970a86 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -244,7 +244,7 @@ char32_t Rest::GetRestGlyph() const return this->GetRestGlyph(this->GetActualDur()); } -char32_t Rest::GetRestGlyph(const int duration) const +char32_t Rest::GetRestGlyph(const data_DURATION duration) const { const Resources *resources = this->GetDocResources(); if (!resources) return 0; @@ -559,7 +559,7 @@ int Rest::GetMarginLayerLocation(bool isTopLayer, bool restOverlap) const int Rest::GetRestOffsetFromOptions( RestLayer layer, const std::pair<int, RestAccidental> &location, bool isTopLayer) const { - int duration = this->GetActualDur(); + data_DURATION duration = this->GetActualDur(); // Make sure we are in the boundaries of g_defaultRests if (duration > DURATION_128) duration = DURATION_128; if (duration < DURATION_long) duration = DURATION_long; diff --git a/src/view_beam.cpp b/src/view_beam.cpp index 566234d1cc3..046e24e190e 100644 --- a/src/view_beam.cpp +++ b/src/view_beam.cpp @@ -150,7 +150,7 @@ void View::DrawFTremSegment(DeviceContext *dc, Staff *staff, FTrem *fTrem) // We look only at the first one for the duration since both are expected to be the same AttDurationLog *durationElement = dynamic_cast<AttDurationLog *>(firstElement->m_element); if (!durationElement) return; - const int dur = durationElement->GetDur(); + const data_DURATION dur = durationElement->GetDur(); if (dur > DURATION_1) { // Adjust the x position of the first and last element for taking into account the stem width @@ -289,8 +289,8 @@ void View::DrawBeamSegment( } int noteCount = (int)noteIndexes.size(); - int durRef = DURATION_8; - int durRef2 = DURATION_16; + data_DURATION durRef = DURATION_8; + data_DURATION durRef2 = DURATION_16; if (staff->IsTabLuteFrench() || staff->IsTabLuteItalian()) { durRef = DURATION_4; diff --git a/src/view_element.cpp b/src/view_element.cpp index fe041d76cc4..b6bf6101623 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -275,7 +275,7 @@ void View::DrawAccid(DeviceContext *dc, LayerElement *element, Layer *layer, Sta // look at the note position and adjust it if necessary Note *note = vrv_cast<Note *>(accid->GetFirstAncestor(NOTE, MAX_ACCID_DEPTH)); if (note) { - const int drawingDur = note->GetDrawingDur(); + const data_DURATION drawingDur = note->GetDrawingDur(); int noteTop = note->GetDrawingTop(m_doc, staff->m_drawingStaffSize); int noteBottom = note->GetDrawingBottom(m_doc, staff->m_drawingStaffSize); bool onStaff = (accid->GetOnstaff() == BOOLEAN_true); @@ -1454,7 +1454,7 @@ void View::DrawNote(DeviceContext *dc, LayerElement *element, Layer *layer, Staf if (!(note->GetHeadVisible() == BOOLEAN_false)) { /************** Noteheads: **************/ - int drawingDur = note->GetDrawingDur(); + data_DURATION drawingDur = note->GetDrawingDur(); if (drawingDur == DURATION_NONE) { if (note->IsInBeam() && !dc->Is(BBOX_DEVICE_CONTEXT)) { LogWarning("Missing duration for note '%s' in beam", note->GetID().c_str()); @@ -1539,7 +1539,7 @@ void View::DrawRest(DeviceContext *dc, LayerElement *element, Layer *layer, Staf const bool drawingCueSize = rest->GetDrawingCueSize(); const int staffSize = staff->GetDrawingStaffNotationSize(); - int drawingDur = rest->GetActualDur(); + data_DURATION drawingDur = rest->GetActualDur(); if (drawingDur == DURATION_NONE) { if (!dc->Is(BBOX_DEVICE_CONTEXT)) { LogWarning("Missing duration for rest '%s'", rest->GetID().c_str()); diff --git a/src/view_mensural.cpp b/src/view_mensural.cpp index a02bc5f9cad..5222b8d916d 100644 --- a/src/view_mensural.cpp +++ b/src/view_mensural.cpp @@ -50,7 +50,7 @@ void View::DrawMensuralNote(DeviceContext *dc, LayerElement *element, Layer *lay const int yNote = element->GetDrawingY(); const int xNote = element->GetDrawingX(); - const int drawingDur = note->GetDrawingDur(); + const data_DURATION drawingDur = note->GetDrawingDur(); /************** Noteheads: **************/ @@ -161,7 +161,7 @@ void View::DrawMensuralStem(DeviceContext *dc, Note *note, Staff *staff, data_ST assert(note); const int staffSize = staff->m_drawingStaffSize; - const int drawingDur = note->GetDrawingDur(); + const data_DURATION drawingDur = note->GetDrawingDur(); const int radius = note->GetDrawingRadius(m_doc); // Cue size is currently disabled const bool drawingCueSize = false; @@ -710,7 +710,7 @@ void View::CalcObliquePoints(Note *note1, Note *note2, Staff *staff, Point point data_STEMDIRECTION View::GetMensuralStemDir(Layer *layer, Note *note, int verticalCenter) { // constants - const int drawingDur = note->GetDrawingDur(); + const data_DURATION drawingDur = note->GetDrawingDur(); const int yNote = note->GetDrawingY(); data_STEMDIRECTION layerStemDir; diff --git a/src/vrv.cpp b/src/vrv.cpp index 06340f6ecff..2378a542dd8 100644 --- a/src/vrv.cpp +++ b/src/vrv.cpp @@ -459,6 +459,16 @@ std::string ToCamelCase(const std::string &s) return result; } +data_DURATION DurationMin(data_DURATION dur1, data_DURATION dur2) +{ + return (dur1 < dur2) ? dur1 : dur2; +} + +data_DURATION DurationMax(data_DURATION dur1, data_DURATION dur2) +{ + return (dur1 > dur2) ? dur1 : dur2; +} + //---------------------------------------------------------------------------- // Notation type checks //---------------------------------------------------------------------------- From 25e2d10f460b2bf53e43972f68056e69e68e2a0b Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 16:13:14 +0200 Subject: [PATCH 089/105] Fix missing switch default and remove () --- src/durationinterface.cpp | 14 +++++++------- src/rest.cpp | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index e6675538482..24297314f3a 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -192,13 +192,13 @@ data_DURATION DurationInterface::CalcActualDur(data_DURATION dur) const if (dur < DUR_MAX) return dur; // Mensural duration (except maxima) switch (dur) { - case (DURATION_longa): return DURATION_long; - case (DURATION_brevis): return DURATION_breve; - case (DURATION_semibrevis): return DURATION_1; - case (DURATION_minima): return DURATION_2; - case (DURATION_semiminima): return DURATION_4; - case (DURATION_fusa): return DURATION_8; - case (DURATION_semifusa): return DURATION_16; + case DURATION_longa: return DURATION_long; + case DURATION_brevis: return DURATION_breve; + case DURATION_semibrevis: return DURATION_1; + case DURATION_minima: return DURATION_2; + case DURATION_semiminima: return DURATION_4; + case DURATION_fusa: return DURATION_8; + case DURATION_semifusa: return DURATION_16; default: return DURATION_NONE; } } diff --git a/src/rest.cpp b/src/rest.cpp index 323cb970a86..7e622d604d1 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -270,6 +270,7 @@ char32_t Rest::GetRestGlyph(const data_DURATION duration) const case DURATION_4: return SMUFL_E9F6_mensuralRestSemiminima; break; case DURATION_8: return SMUFL_E9F7_mensuralRestFusa; break; case DURATION_16: return SMUFL_E9F8_mensuralRestSemifusa; break; + default: return 0; } } else { @@ -287,6 +288,7 @@ char32_t Rest::GetRestGlyph(const data_DURATION duration) const case DURATION_256: return SMUFL_E4EB_rest256th; break; case DURATION_512: return SMUFL_E4EC_rest512th; break; case DURATION_1024: return SMUFL_E4ED_rest1024th; break; + default: return 0; } } From ae4ab4abd11e6896d0f426ca5990d89f2d3f7120 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 16:14:29 +0200 Subject: [PATCH 090/105] Add Fraction constructor from data_DURATION --- include/vrv/horizontalaligner.h | 1 + src/durationinterface.cpp | 2 ++ src/horizontalaligner.cpp | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index efa5a210895..824cfa6b7ba 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -69,6 +69,7 @@ class Fraction { public: // Constructors Fraction(int num = 0, int denom = 1); + Fraction(data_DURATION duration); /** Addition operator */ Fraction operator+(const Fraction &other) const; diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 24297314f3a..75a42299beb 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -80,6 +80,8 @@ Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) if (this->HasNum()) num *= this->GetNum(); if (this->HasNumbase()) numBase *= this->GetNumbase(); + // Fraction duration(noteDur); + // duration = duration * numBase / num; Fraction duration = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; int noteDots = (this->HasDotsGes()) ? this->GetDotsGes() : this->GetDots(); diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 8315fabfaee..955443e5ab9 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -47,6 +47,14 @@ Fraction::Fraction(int num, int denom) : m_numerator(num), m_denominator(denom) Reduce(); } +Fraction::Fraction(data_DURATION duration) +{ + int den = pow(2, (duration + 1)); + m_numerator = 8; + m_denominator = den; + Reduce(); +} + Fraction Fraction::operator+(const Fraction &other) const { int num = m_numerator * other.m_denominator + other.m_numerator * m_denominator; From 7479d5da2eccab68a19ca3a2a03f481d27f2f1f0 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 16:44:12 +0200 Subject: [PATCH 091/105] Fix regression on grace note stems --- include/vrv/beam.h | 3 ++- src/beam.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/vrv/beam.h b/include/vrv/beam.h index 855d556417d..2ab3afd24cc 100644 --- a/include/vrv/beam.h +++ b/include/vrv/beam.h @@ -429,7 +429,8 @@ class BeamElementCoord { void SetClosestNoteOrTabDurSym(data_STEMDIRECTION stemDir, bool outsideStaff); /** Helper for calculating the stem length for staff notation and tablature beams within the staff */ - int CalculateStemLength(const Staff *staff, data_STEMDIRECTION stemDir, bool isHorizontal, int preferredDur) const; + int CalculateStemLength( + const Staff *staff, data_STEMDIRECTION stemDir, bool isHorizontal, data_DURATION preferredDur) const; /** Helper for calculating the stem length for tablature beam placed outside the staff */ int CalculateStemLengthTab(const Staff *staff, data_STEMDIRECTION stemDir) const; diff --git a/src/beam.cpp b/src/beam.cpp index 8eddeb4968a..5cffc7fb905 100644 --- a/src/beam.cpp +++ b/src/beam.cpp @@ -1215,7 +1215,7 @@ void BeamSegment::CalcBeamStemLength(const Staff *staff, data_BEAMPLACE place, b // skip current element if it's longer that minDuration and is not a part of fTrem if ((coord->m_dur < noteDur) && !(coord->m_element && coord->m_element->GetFirstAncestor(FTREM))) continue; // adjust stem length if location matches - const data_DURATION dur = (preferredDur != 0) ? preferredDur : coord->m_dur; + const data_DURATION dur = (preferredDur != DURATION_NONE) ? preferredDur : coord->m_dur; const int coordStemLength = coord->CalculateStemLength(staff, stemDir, isHorizontal, dur); if (coord->m_closestNote->GetDrawingLoc() == noteLoc) { m_uniformStemLength = coordStemLength; @@ -1942,7 +1942,7 @@ void BeamElementCoord::SetDrawingStemDir(data_STEMDIRECTION stemDir, const Staff } int BeamElementCoord::CalculateStemLength( - const Staff *staff, data_STEMDIRECTION stemDir, bool isHorizontal, int preferredDur) const + const Staff *staff, data_STEMDIRECTION stemDir, bool isHorizontal, data_DURATION preferredDur) const { if (!m_closestNote) return 0; From 22629d166645d415cf00514070004419b8a34dff Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 19:37:55 +0200 Subject: [PATCH 092/105] Change alignment to Fraction with whole note == 1/1 --- include/vrv/beatrpt.h | 2 +- include/vrv/durationinterface.h | 2 +- include/vrv/horizontalaligner.h | 24 +++++++++++++++++------- include/vrv/metersig.h | 6 ++++++ include/vrv/timestamp.h | 2 +- src/alignfunctor.cpp | 10 ++++++---- src/beatrpt.cpp | 8 ++++---- src/calcalignmentxposfunctor.cpp | 10 +++++----- src/durationinterface.cpp | 17 ++++++++++------- src/findlayerelementsfunctor.cpp | 4 ++-- src/horizontalaligner.cpp | 23 ++++++++++++----------- src/layerelement.cpp | 27 ++++++++++----------------- src/metersig.cpp | 13 +++++++++++++ src/timestamp.cpp | 5 +++-- src/view_control.cpp | 4 ++-- 15 files changed, 93 insertions(+), 64 deletions(-) diff --git a/include/vrv/beatrpt.h b/include/vrv/beatrpt.h index d4d8a4d9b5d..8db95215c38 100644 --- a/include/vrv/beatrpt.h +++ b/include/vrv/beatrpt.h @@ -43,7 +43,7 @@ class BeatRpt : public LayerElement, public AttColor, public AttBeatRptLog, publ * Returns the duration (in double) for the BeatRpt. */ - double GetBeatRptAlignmentDuration(int meterUnit) const; + Fraction GetBeatRptAlignmentDuration(data_DURATION meterUnit) const; /** * MIDI timing information diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index 4265aedcfd7..b1cd3d3760c 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -70,7 +70,7 @@ class DurationInterface : public Interface, * Currently this assume brevis equality (through DUR_MENSURAL_REF) and would * need to be modified for shorter equality in later repertoire. */ - double GetInterfaceAlignmentMensuralDuration(int num, int numBase, const Mensur *currentMensur) const; + Fraction GetInterfaceAlignmentMensuralDuration(int num, int numBase, const Mensur *currentMensur) const; /** * Return true if the note or rest is the first of a beam. diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index 824cfa6b7ba..d28fa25c731 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -67,9 +67,15 @@ enum AlignmentType { class Fraction { public: - // Constructors - Fraction(int num = 0, int denom = 1); - Fraction(data_DURATION duration); + // Constructors - make them explicit to avoid type conversion + explicit Fraction(int num = 0, int denom = 1); + explicit Fraction(data_DURATION duration); + + // Enable implicit conversion constructor for `int` + template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>> + Fraction(T num) : m_numerator(num), m_denominator(1) + { + } /** Addition operator */ Fraction operator+(const Fraction &other) const; @@ -91,6 +97,10 @@ class Fraction { /** Greater than or equal operator */ bool operator>=(const Fraction &other) const; + /** Getters */ + int GetNumerator() const { return m_numerator; } + int GetDenominator() const { return m_denominator; } + /** Convert fraction to a double */ double ToDouble() const; @@ -261,7 +271,7 @@ class Alignment : public Object { * formula with parameters can come close and has other advantages. */ static int HorizontalSpaceForDuration( - const Fraction &intervalTime, int maxActualDur, double spacingLinear, double spacingNonLinear); + const Fraction &intervalTime, data_DURATION maxActualDur, double spacingLinear, double spacingNonLinear); //----------// // Functors // @@ -507,8 +517,8 @@ class MeasureAligner : public HorizontalAligner { * Setter takes a meter unit parameter. */ ///@{ - void SetInitialTstamp(int meterUnit); - double GetInitialTstampDur() const { return m_initialTstampDur; } + void SetInitialTstamp(data_DURATION meterUnit); + Fraction GetInitialTstampDur() const { return m_initialTstampDur; } ///@} /** @@ -593,7 +603,7 @@ class MeasureAligner : public HorizontalAligner { * The time duration of the timestamp between 0.0 and 1.0. * This depends on the meter signature in the preceeding scoreDef */ - double m_initialTstampDur; + Fraction m_initialTstampDur; }; //---------------------------------------------------------------------------- diff --git a/include/vrv/metersig.h b/include/vrv/metersig.h index 585c259b9c4..4e3363e4863 100644 --- a/include/vrv/metersig.h +++ b/include/vrv/metersig.h @@ -54,6 +54,12 @@ class MeterSig : public LayerElement, /** Evaluate additive meter counts */ int GetTotalCount() const; + /** + * Return the unit (int) as data_DURATION (up to 32). + * Return DURATION_4 if no match. + */ + data_DURATION GetUnitAsDur() const; + /** Retrieves the symbol glyph */ char32_t GetSymbolGlyph() const; diff --git a/include/vrv/timestamp.h b/include/vrv/timestamp.h index c715b569ec0..fe537184dad 100644 --- a/include/vrv/timestamp.h +++ b/include/vrv/timestamp.h @@ -41,7 +41,7 @@ class TimestampAttr : public LayerElement { /** * Returns the duration (in double) for the Timestamp. */ - double GetTimestampAttrAlignmentDuration(int meterUnit) const; + Fraction GetTimestampAttrAlignmentDuration(data_DURATION meterUnit) const; //----------// // Functors // diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index fad1c8874f4..4dd8fe4a3ca 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -40,7 +40,7 @@ namespace vrv { AlignHorizontallyFunctor::AlignHorizontallyFunctor(Doc *doc) : DocFunctor(doc) { m_measureAligner = NULL; - m_time = 0.0; + m_time = 0; m_currentParams.mensur = NULL; m_currentParams.meterSig = NULL; m_notationType = NOTATIONTYPE_cmn; @@ -56,7 +56,7 @@ FunctorCode AlignHorizontallyFunctor::VisitLayer(Layer *layer) // We are starting a new layer, reset the time; // We set it to -1.0 for the scoreDef attributes since they have to be aligned before any timestamp event (-1.0) - m_time = DUR_MAX * -1.0; + m_time = -1; m_scoreDefRole = m_isFirstMeasure ? SCOREDEF_SYSTEM : SCOREDEF_INTERMEDIATE; @@ -87,7 +87,7 @@ FunctorCode AlignHorizontallyFunctor::VisitLayer(Layer *layer) m_scoreDefRole = SCOREDEF_NONE; // Now we have to set it to 0.0 since we will start aligning musical content - m_time = 0.0; + m_time = 0; return FUNCTOR_CONTINUE; } @@ -378,7 +378,9 @@ FunctorCode AlignHorizontallyFunctor::VisitMeasure(Measure *measure) FunctorCode AlignHorizontallyFunctor::VisitMeasureEnd(Measure *measure) { - int meterUnit = m_currentParams.meterSig ? m_currentParams.meterSig->GetUnit() : 4; + data_DURATION meterUnit = (m_currentParams.meterSig && m_currentParams.meterSig->HasUnit()) + ? m_currentParams.meterSig->GetUnitAsDur() + : DURATION_4; measure->m_measureAligner.SetInitialTstamp(meterUnit); // We also need to align the timestamps - we do it at the end since we need the *meterSig to be initialized by a diff --git a/src/beatrpt.cpp b/src/beatrpt.cpp index 3b72624333c..26dc321bc07 100644 --- a/src/beatrpt.cpp +++ b/src/beatrpt.cpp @@ -54,11 +54,11 @@ void BeatRpt::Reset() m_scoreTimeOnset = 0.0; } -double BeatRpt::GetBeatRptAlignmentDuration(int meterUnit) const +Fraction BeatRpt::GetBeatRptAlignmentDuration(data_DURATION meterUnit) const { - double dur = DUR_MAX / meterUnit; - if (this->HasBeatdef()) dur *= this->GetBeatdef(); - return dur; + Fraction duration(meterUnit); + if (this->HasBeatdef()) duration = duration * Fraction(this->GetBeatdef() * DUR_MAX, DUR_MAX); + return duration; } void BeatRpt::SetScoreTimeOnset(double scoreTime) diff --git a/src/calcalignmentxposfunctor.cpp b/src/calcalignmentxposfunctor.cpp index 1aaf14eeddc..6f8c291dc8e 100644 --- a/src/calcalignmentxposfunctor.cpp +++ b/src/calcalignmentxposfunctor.cpp @@ -22,7 +22,7 @@ namespace vrv { CalcAlignmentXPosFunctor::CalcAlignmentXPosFunctor(Doc *doc) : DocFunctor(doc) { - m_previousTime = 0.0; + m_previousTime = 0; m_previousXRel = 0; m_longestActualDur = DURATION_NONE; m_estimatedJustificationRatio = 1.0; @@ -39,7 +39,7 @@ FunctorCode CalcAlignmentXPosFunctor::VisitAlignment(Alignment *alignment) Fraction intervalTime = alignment->GetTime() - m_previousTime; if (alignment->GetType() > ALIGNMENT_MEASURE_RIGHT_BARLINE) { - intervalTime = 0.0; + intervalTime = 0; } // Do not move aligners that are only time-stamps at this stage but add it to the pending list @@ -48,7 +48,7 @@ FunctorCode CalcAlignmentXPosFunctor::VisitAlignment(Alignment *alignment) return FUNCTOR_CONTINUE; } - if (intervalTime > 0.0) { + if (intervalTime > 0) { intervalXRel = Alignment::HorizontalSpaceForDuration(intervalTime, m_longestActualDur, m_doc->GetOptions()->m_spacingLinear.GetValue(), m_doc->GetOptions()->m_spacingNonLinear.GetValue()); // LogDebug("CalcAlignmentXPos: intervalTime=%.2f intervalXRel=%d", intervalTime, intervalXRel); @@ -81,7 +81,7 @@ FunctorCode CalcAlignmentXPosFunctor::VisitAlignment(Alignment *alignment) // For each timestamp alignment, move them proportionally to the space we currently have for (auto &tsAlignment : m_timestamps) { // Avoid division by zero (nothing to move with the alignment anyway - if (duration == 0.0) break; + if (duration == 0) break; Fraction percent = (tsAlignment->GetTime() - startTime) / duration; tsAlignment->SetXRel(startXRel + space * percent.ToDouble()); } @@ -98,7 +98,7 @@ FunctorCode CalcAlignmentXPosFunctor::VisitMeasure(Measure *measure) { // We start a new Measure // Reset the previous time position and x_rel to 0; - m_previousTime = 0.0; + m_previousTime = 0; // We un-measured music we never have a left barline, so do not add a default space m_previousXRel = (measure->IsMeasuredMusic()) ? m_doc->GetDrawingUnit(100) : 0; diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 75a42299beb..68c05cea91e 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -80,26 +80,29 @@ Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) if (this->HasNum()) num *= this->GetNum(); if (this->HasNumbase()) numBase *= this->GetNumbase(); - // Fraction duration(noteDur); - // duration = duration * numBase / num; - Fraction duration = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; + Fraction duration(noteDur); + duration = duration * numBase / num; + // double old = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; + // duration = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; int noteDots = (this->HasDotsGes()) ? this->GetDotsGes() : this->GetDots(); if (noteDots != VRV_UNSET) { - duration = duration * 2 - (duration / pow(2, noteDots)); + Fraction durationReduction(duration.GetNumerator(), duration.GetDenominator() * pow(2, noteDots)); + duration = duration * 2 - durationReduction; } // LogDebug("Duration %d; Dot %d; Alignment %f", noteDur, this->GetDots(), duration); return duration; } -double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int numBase, const Mensur *currentMensur) const +Fraction DurationInterface::GetInterfaceAlignmentMensuralDuration( + int num, int numBase, const Mensur *currentMensur) const { int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); if (noteDur == DURATION_NONE) noteDur = DURATION_4; if (!currentMensur) { LogWarning("No current mensur for calculating duration"); - return DUR_MENSURAL_REF; + return Fraction(1, 1); } if (this->HasNum() || this->HasNumbase()) { @@ -155,7 +158,7 @@ double DurationInterface::GetInterfaceAlignmentMensuralDuration(int num, int num duration *= (double)numBase / (double)num; // LogDebug("Duration %d; %d/%d; Alignment %f; Ratio %f", noteDur, num, numbase, duration, ratio); duration = durRound(duration); - return duration; + return Fraction(DUR_MAX * duration, DUR_MAX * DUR_MAX); } bool DurationInterface::IsFirstInBeam(const LayerElement *noteOrRest) const diff --git a/src/findlayerelementsfunctor.cpp b/src/findlayerelementsfunctor.cpp index 0ebba8830fa..35129d8b0af 100644 --- a/src/findlayerelementsfunctor.cpp +++ b/src/findlayerelementsfunctor.cpp @@ -90,8 +90,8 @@ LayerElementsInTimeSpanFunctor::LayerElementsInTimeSpanFunctor( const MeterSig *meterSig, const Mensur *mensur, const Layer *layer) : ConstFunctor() { - m_time = 0.0; - m_duration = 0.0; + m_time = 0; + m_duration = 0; m_meterParams.meterSig = meterSig; m_meterParams.mensur = mensur; m_layer = layer; diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 955443e5ab9..8cbf97a20ab 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -49,6 +49,8 @@ Fraction::Fraction(int num, int denom) : m_numerator(num), m_denominator(denom) Fraction::Fraction(data_DURATION duration) { + duration = vrv::DurationMin(duration, DURATION_1024); + duration = vrv::DurationMax(duration, DURATION_NONE); int den = pow(2, (duration + 1)); m_numerator = 8; m_denominator = den; @@ -232,16 +234,16 @@ void MeasureAligner::Reset() { HorizontalAligner::Reset(); m_nonJustifiableLeftMargin = 0; - m_leftAlignment = new Alignment(-1.0 * DUR_MAX, ALIGNMENT_MEASURE_START); + m_leftAlignment = new Alignment(-1, ALIGNMENT_MEASURE_START); AddAlignment(m_leftAlignment); - m_leftBarLineAlignment = new Alignment(-1.0 * DUR_MAX, ALIGNMENT_MEASURE_LEFT_BARLINE); + m_leftBarLineAlignment = new Alignment(-1, ALIGNMENT_MEASURE_LEFT_BARLINE); AddAlignment(m_leftBarLineAlignment); - m_rightBarLineAlignment = new Alignment(0.0 * DUR_MAX, ALIGNMENT_MEASURE_RIGHT_BARLINE); + m_rightBarLineAlignment = new Alignment(0, ALIGNMENT_MEASURE_RIGHT_BARLINE); AddAlignment(m_rightBarLineAlignment); - m_rightAlignment = new Alignment(0.0 * DUR_MAX, ALIGNMENT_MEASURE_END); + m_rightAlignment = new Alignment(0, ALIGNMENT_MEASURE_END); AddAlignment(m_rightAlignment); - m_initialTstampDur = -DUR_MAX; + m_initialTstampDur = -1; } bool MeasureAligner::IsSupportedChild(Object *child) @@ -302,11 +304,9 @@ Fraction MeasureAligner::GetMaxTime() const return m_rightAlignment->GetTime(); } -void MeasureAligner::SetInitialTstamp(int meterUnit) +void MeasureAligner::SetInitialTstamp(data_DURATION meterUnit) { - if (meterUnit != 0) { - m_initialTstampDur = DUR_MAX / meterUnit * -1; - } + m_initialTstampDur = Fraction(meterUnit) * -1; } void MeasureAligner::AdjustProportionally(const ArrayOfAdjustmentTuples &adjustments) @@ -836,14 +836,15 @@ std::pair<int, int> Alignment::GetAlignmentTopBottom() const } int Alignment::HorizontalSpaceForDuration( - const Fraction &intervalTime, int maxActualDur, double spacingLinear, double spacingNonLinear) + const Fraction &intervalTime, data_DURATION maxActualDur, double spacingLinear, double spacingNonLinear) { double doubleIntervalTime = intervalTime.ToDouble(); /* If the longest duration interval in the score is longer than semibreve, adjust spacing so that interval gets the space a semibreve would ordinarily get. */ if (maxActualDur < DURATION_1) doubleIntervalTime /= pow(2.0, DURATION_1 - maxActualDur); - return pow(doubleIntervalTime, spacingNonLinear) * spacingLinear * 10.0; // numbers are experimental constants + return pow(doubleIntervalTime * 1024, spacingNonLinear) * spacingLinear + * 10.0; // numbers are experimental constants } FunctorCode Alignment::Accept(Functor &functor) diff --git a/src/layerelement.cpp b/src/layerelement.cpp index cd6c0da8a44..20f59628df1 100644 --- a/src/layerelement.cpp +++ b/src/layerelement.cpp @@ -76,11 +76,9 @@ namespace vrv { // MAX_DURATION / pow(2.0, (DURATION_4 - 2.0)) #define NEUME_LARGE_SPACE 256 // Medium spacing between neume is a 8th note space -// MAX_DURATION / pow(2.0, (DUR_5 - 2.0)) -#define NEUME_MEDIUM_SPACE 128 +#define NEUME_MEDIUM_SPACE Fraction(1, 8) // Small spacing between neume components is a 16th note space -// MAX_DURATION / pow(2.0, (DUR_6 - 2.0)) -#define NEUME_SMALL_SPACE 64 +#define NEUME_SMALL_SPACE Fraction(1, 16) //---------------------------------------------------------------------------- // LayerElement @@ -730,30 +728,25 @@ Fraction LayerElement::GetAlignmentDuration( else if (this->Is(BEATRPT)) { const BeatRpt *beatRpt = vrv_cast<const BeatRpt *>(this); assert(beatRpt); - int meterUnit = 4; - if (params.meterSig && params.meterSig->HasUnit()) meterUnit = params.meterSig->GetUnit(); + data_DURATION meterUnit = DURATION_4; + if (params.meterSig && params.meterSig->HasUnit()) meterUnit = params.meterSig->GetUnitAsDur(); return beatRpt->GetBeatRptAlignmentDuration(meterUnit); } else if (this->Is(TIMESTAMP_ATTR)) { const TimestampAttr *timestampAttr = vrv_cast<const TimestampAttr *>(this); assert(timestampAttr); - int meterUnit = 4; - if (params.meterSig && params.meterSig->HasUnit()) meterUnit = params.meterSig->GetUnit(); + data_DURATION meterUnit = DURATION_4; + if (params.meterSig && params.meterSig->HasUnit()) meterUnit = params.meterSig->GetUnitAsDur(); return timestampAttr->GetTimestampAttrAlignmentDuration(meterUnit); } // We align all full measure element to the current time signature, even the ones that last longer than one measure else if (this->Is({ HALFMRPT, MREST, MULTIREST, MRPT, MRPT2, MULTIRPT })) { - int meterUnit = 4; + data_DURATION meterUnit = DURATION_4; int meterCount = 4; - if (params.meterSig && params.meterSig->HasUnit()) meterUnit = params.meterSig->GetUnit(); + if (params.meterSig && params.meterSig->HasUnit()) meterUnit = params.meterSig->GetUnitAsDur(); if (params.meterSig && params.meterSig->HasCount()) meterCount = params.meterSig->GetTotalCount(); - - if (this->Is(HALFMRPT)) { - return (DUR_MAX / meterUnit * meterCount) / 2; - } - else { - return DUR_MAX / meterUnit * meterCount; - } + Fraction duration = Fraction(meterUnit) * meterCount; + return (this->Is(HALFMRPT)) ? (duration / 2) : duration; } // This is not called with --neume-as-note since otherwise each nc has an aligner else if (this->Is(NEUME)) { diff --git a/src/metersig.cpp b/src/metersig.cpp index f3df8054d23..8ff16ecf702 100644 --- a/src/metersig.cpp +++ b/src/metersig.cpp @@ -108,6 +108,19 @@ int MeterSig::GetTotalCount() const return counts.front(); } +data_DURATION MeterSig::GetUnitAsDur() const +{ + switch (this->GetUnit()) { + case 1: return DURATION_1; + case 2: return DURATION_2; + case 4: return DURATION_4; + case 8: return DURATION_8; + case 16: return DURATION_16; + case 32: return DURATION_32; + default: return DURATION_4; + } +} + char32_t MeterSig::GetSymbolGlyph() const { char32_t glyph = 0; diff --git a/src/timestamp.cpp b/src/timestamp.cpp index da4a52e682d..c7bd31c6269 100644 --- a/src/timestamp.cpp +++ b/src/timestamp.cpp @@ -35,9 +35,10 @@ void TimestampAttr::Reset() m_actualDurPos = 0.0; } -double TimestampAttr::GetTimestampAttrAlignmentDuration(int meterUnit) const +Fraction TimestampAttr::GetTimestampAttrAlignmentDuration(data_DURATION meterUnit) const { - return DUR_MAX / meterUnit * m_actualDurPos; + Fraction duration(meterUnit); + return (duration * Fraction(m_actualDurPos * DUR_MAX, DUR_MAX)); } FunctorCode TimestampAttr::Accept(Functor &functor) diff --git a/src/view_control.cpp b/src/view_control.cpp index 9a0065f0ce9..6c908fb21ff 100644 --- a/src/view_control.cpp +++ b/src/view_control.cpp @@ -1269,8 +1269,8 @@ void View::DrawSylConnector( } // We are in the system of the last note - draw the connector from the beginning of the system else if (spanningType == SPANNING_END) { - // If we do not want to show hyphens at the start of a system and the end is at time 0.0 - if (m_options->m_lyricNoStartHyphen.GetValue() && (syl->GetEnd()->GetAlignment()->GetTime() == 0.0)) { + // If we do not want to show hyphens at the start of a system and the end is at time 0 + if (m_options->m_lyricNoStartHyphen.GetValue() && (syl->GetEnd()->GetAlignment()->GetTime() == 0)) { // Return but only if the end is in the first measure of the system... Measure *measure = vrv_cast<Measure *>(syl->GetEnd()->GetFirstAncestor(MEASURE)); assert(measure); From 0ce9f54a4b429637af3cb6e1775b2bff30837ef3 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 20:04:09 +0200 Subject: [PATCH 093/105] Fix comments --- include/vrv/beatrpt.h | 2 +- include/vrv/durationinterface.h | 2 +- include/vrv/timestamp.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/vrv/beatrpt.h b/include/vrv/beatrpt.h index 8db95215c38..bf892e589c0 100644 --- a/include/vrv/beatrpt.h +++ b/include/vrv/beatrpt.h @@ -40,7 +40,7 @@ class BeatRpt : public LayerElement, public AttColor, public AttBeatRptLog, publ bool HasToBeAligned() const override { return true; } /** - * Returns the duration (in double) for the BeatRpt. + * Returns the duration (in Fraction) for the BeatRpt. */ Fraction GetBeatRptAlignmentDuration(data_DURATION meterUnit) const; diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index b1cd3d3760c..215ba4fce57 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -66,7 +66,7 @@ class DurationInterface : public Interface, Fraction GetInterfaceAlignmentDuration(int num, int numBase) const; /** - * Returns the duration (in double) for the element for mensural notation + * Returns the duration (in Fraction) for the element for mensural notation * Currently this assume brevis equality (through DUR_MENSURAL_REF) and would * need to be modified for shorter equality in later repertoire. */ diff --git a/include/vrv/timestamp.h b/include/vrv/timestamp.h index fe537184dad..71e208592c9 100644 --- a/include/vrv/timestamp.h +++ b/include/vrv/timestamp.h @@ -39,7 +39,7 @@ class TimestampAttr : public LayerElement { ///@} /** - * Returns the duration (in double) for the Timestamp. + * Returns the duration (in Fraction) for the Timestamp. */ Fraction GetTimestampAttrAlignmentDuration(data_DURATION meterUnit) const; From 449fc72e459e932d10a5114dbfbfa2b961e875a8 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 20:58:34 +0200 Subject: [PATCH 094/105] Remove call to Fraction::ToDouble --- src/alignfunctor.cpp | 2 -- src/view_element.cpp | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/alignfunctor.cpp b/src/alignfunctor.cpp index 4dd8fe4a3ca..f28c7badeda 100644 --- a/src/alignfunctor.cpp +++ b/src/alignfunctor.cpp @@ -310,8 +310,6 @@ FunctorCode AlignHorizontallyFunctor::VisitLayerElement(LayerElement *layerEleme // get the duration of the event duration = layerElement->GetAlignmentDuration(m_currentParams, true, m_notationType); - // LogDebug("duration %s %f", duration.ToString().c_str(), duration.ToDouble()); - // For timestamp, what we get from GetAlignmentDuration is actually the position of the timestamp // So use it as current time - we can do this because the timestamp loop is redirected from the measure // The time will be reset to 0.0 when starting a new layer anyway diff --git a/src/view_element.cpp b/src/view_element.cpp index b6bf6101623..9766eac5833 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -1165,11 +1165,9 @@ void View::DrawMRest(DeviceContext *dc, LayerElement *element, Layer *layer, Sta const bool drawingCueSize = mRest->GetDrawingCueSize(); int x = mRest->GetDrawingX(); - int y = (measure->m_measureAligner.GetMaxTime().ToDouble() >= (DUR_MAX * 2)) - ? element->GetDrawingY() - m_doc->GetDrawingDoubleUnit(staffSize) - : element->GetDrawingY(); - char32_t rest = (measure->m_measureAligner.GetMaxTime().ToDouble() >= (DUR_MAX * 2)) ? SMUFL_E4E2_restDoubleWhole - : SMUFL_E4E3_restWhole; + const bool isDouble = (measure->m_measureAligner.GetMaxTime() >= Fraction(2, 1)); + int y = isDouble ? element->GetDrawingY() - m_doc->GetDrawingDoubleUnit(staffSize) : element->GetDrawingY(); + char32_t rest = isDouble ? SMUFL_E4E2_restDoubleWhole : SMUFL_E4E3_restWhole; x -= m_doc->GetGlyphWidth(rest, staffSize, drawingCueSize) / 2; From 501de5f8908093980e9237c8b66c486578411ace Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 21:12:11 +0200 Subject: [PATCH 095/105] Change beam pattern detection items --- src/drawinginterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drawinginterface.cpp b/src/drawinginterface.cpp index facd2c57737..c4a102a9432 100644 --- a/src/drawinginterface.cpp +++ b/src/drawinginterface.cpp @@ -421,7 +421,7 @@ bool BeamDrawingInterface::IsRepeatedPattern() const if (!coord->m_stem || !coord->m_closestNote) continue; // Could this be an overflow with 32 bits? - items.push_back(coord->m_closestNote->GetDrawingY() * DUR_MAX + coord->m_dur); + items.push_back(coord->m_closestNote->GetDrawingY() + DUR_MAX * coord->m_dur); } int itemCount = (int)items.size(); From f569cd06ac5ca68d9e2bf52a768b1bac33b190ca Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 21:12:45 +0200 Subject: [PATCH 096/105] Remove unnecessary defines --- libmei/addons/attdef.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/libmei/addons/attdef.h b/libmei/addons/attdef.h index d04af822ac6..6bb21ecd9b7 100644 --- a/libmei/addons/attdef.h +++ b/libmei/addons/attdef.h @@ -33,12 +33,6 @@ typedef double data_VU; // Durations //---------------------------------------------------------------------------- -/** - * These duration values are used for internal calculation and differ from the - * MEI data.DURATION types (see below) - */ -#define DUR_NONE -32 -#define DUR_MX -1 // maxima // used for alignement #define DUR_MAX 1024 // mensural duration @@ -88,13 +82,13 @@ typedef std::vector<std::pair<double, double>> data_BULGE; * MEI data.DURATION */ enum data_DURATION { - DURATION_NONE = DUR_NONE, - DURATION_maxima = DUR_MX, - DURATION_long, + DURATION_NONE = -2, + DURATION_maxima, // -1 + DURATION_long, // 0 DURATION_breve, DURATION_1, DURATION_2, - DURATION_4, + DURATION_4, // 4 DURATION_8, DURATION_16, DURATION_32, From 4b3c462a169fa73cee143144910e023247ced4ca Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Thu, 3 Oct 2024 21:14:27 +0200 Subject: [PATCH 097/105] Rename variable --- src/horizontalaligner.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 8cbf97a20ab..7b440275c51 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -838,13 +838,12 @@ std::pair<int, int> Alignment::GetAlignmentTopBottom() const int Alignment::HorizontalSpaceForDuration( const Fraction &intervalTime, data_DURATION maxActualDur, double spacingLinear, double spacingNonLinear) { - double doubleIntervalTime = intervalTime.ToDouble(); + double intervalTimeDbl = intervalTime.ToDouble(); /* If the longest duration interval in the score is longer than semibreve, adjust spacing so that interval gets the space a semibreve would ordinarily get. */ - if (maxActualDur < DURATION_1) doubleIntervalTime /= pow(2.0, DURATION_1 - maxActualDur); + if (maxActualDur < DURATION_1) intervalTimeDbl /= pow(2.0, DURATION_1 - maxActualDur); - return pow(doubleIntervalTime * 1024, spacingNonLinear) * spacingLinear - * 10.0; // numbers are experimental constants + return pow(intervalTimeDbl * 1024, spacingNonLinear) * spacingLinear * 10.0; // numbers are experimental constants } FunctorCode Alignment::Accept(Functor &functor) From d9e5f1f625032aaa8cbf0de4e478130a57d82bd4 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 4 Oct 2024 10:53:16 +0200 Subject: [PATCH 098/105] Add method to convert Fraction to data_DURATION * Used in PAE output --- include/vrv/horizontalaligner.h | 3 +++ libmei/addons/attdef.h | 2 +- src/horizontalaligner.cpp | 15 +++++++++++++++ src/iopae.cpp | 7 ++++--- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index d28fa25c731..25ca888dbb3 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -107,6 +107,9 @@ class Fraction { /** Convert fraction to a string */ std::string ToString() const; + /** Convert to data_DURATION and the remaining Fraction */ + std::pair<data_DURATION, Fraction> ToDur() const; + private: /** Reduce the fraction */ void Reduce(); diff --git a/libmei/addons/attdef.h b/libmei/addons/attdef.h index 6bb21ecd9b7..1bbd8de2975 100644 --- a/libmei/addons/attdef.h +++ b/libmei/addons/attdef.h @@ -96,7 +96,7 @@ enum data_DURATION { DURATION_128, DURATION_256, DURATION_512, - DURATION_1024, + DURATION_1024, // 12 DURATION_2048, DURATION_longa = DUR_MENSURAL_OFFSET + DURATION_long, DURATION_brevis, diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 7b440275c51..f1a68746279 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -135,6 +135,21 @@ void Fraction::Reduce() m_denominator /= gcdVal; } +std::pair<data_DURATION, Fraction> Fraction::ToDur() const +{ + if (m_numerator == 0) return { DURATION_NONE, 0 }; + + int value = ceil(log2((double)m_denominator / (double)m_numerator * 8)) - 1; + data_DURATION dur = static_cast<data_DURATION>(value); + dur = vrv::DurationMax(DURATION_maxima, dur); + dur = vrv::DurationMin(DURATION_2048, dur); + + Fraction remainder = *this - Fraction(dur); + // Making sure we would not be trigger an inifite loop when looping over the remainder + if ((remainder >= *this) || (remainder < 0)) remainder = 0; + return { dur, remainder }; +} + //---------------------------------------------------------------------------- // HorizontalAligner //---------------------------------------------------------------------------- diff --git a/src/iopae.cpp b/src/iopae.cpp index 5c654356e48..2106985c027 100644 --- a/src/iopae.cpp +++ b/src/iopae.cpp @@ -521,10 +521,11 @@ void PAEOutput::WriteTuplet(Tuplet *tuplet) Staff *staff = tuplet->GetAncestorStaff(); - double content = tuplet->GetContentAlignmentDuration(true, staff->m_drawingNotationType).ToDouble(); - // content = DUR_MAX / 2^(dur - 2) - int tupletDur = (content != 0.0) ? log2(DUR_MAX / content) + 2 : 4; + auto [tupletDur, remainder] = tuplet->GetContentAlignmentDuration(true, staff->m_drawingNotationType).ToDur(); // We should be looking for dotted values + if (remainder != 0) { + LogWarning("The tuplet content is not a single non-dotted duration"); + } std::string dur; switch (tupletDur) { From 72d18e484732ea13b07a098bf8430bd03bc1b6cf Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 4 Oct 2024 13:44:40 +0200 Subject: [PATCH 099/105] Adjust variable --- src/calcalignmentxposfunctor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calcalignmentxposfunctor.cpp b/src/calcalignmentxposfunctor.cpp index 6f8c291dc8e..38e992e3741 100644 --- a/src/calcalignmentxposfunctor.cpp +++ b/src/calcalignmentxposfunctor.cpp @@ -82,8 +82,8 @@ FunctorCode CalcAlignmentXPosFunctor::VisitAlignment(Alignment *alignment) for (auto &tsAlignment : m_timestamps) { // Avoid division by zero (nothing to move with the alignment anyway if (duration == 0) break; - Fraction percent = (tsAlignment->GetTime() - startTime) / duration; - tsAlignment->SetXRel(startXRel + space * percent.ToDouble()); + double percent = ((tsAlignment->GetTime() - startTime) / duration).ToDouble(); + tsAlignment->SetXRel(startXRel + space * percent); } m_timestamps.clear(); } From 755402537bd453dba26fa30062b49c5ab7331480 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 4 Oct 2024 15:17:02 +0200 Subject: [PATCH 100/105] Use Fraction for score time information --- include/vrv/beatrpt.h | 6 +- include/vrv/durationinterface.h | 20 +++--- include/vrv/measure.h | 6 +- include/vrv/midifunctor.h | 6 +- include/vrv/vrvdef.h | 10 +++ src/beatrpt.cpp | 6 +- src/durationinterface.cpp | 20 +++--- src/featureextractor.cpp | 2 +- src/iomusxml.cpp | 8 +-- src/measure.cpp | 4 +- src/midifunctor.cpp | 117 ++++++++++++++++---------------- 11 files changed, 106 insertions(+), 99 deletions(-) diff --git a/include/vrv/beatrpt.h b/include/vrv/beatrpt.h index bf892e589c0..5108e3bc67c 100644 --- a/include/vrv/beatrpt.h +++ b/include/vrv/beatrpt.h @@ -49,8 +49,8 @@ class BeatRpt : public LayerElement, public AttColor, public AttBeatRptLog, publ * MIDI timing information */ ///@{ - void SetScoreTimeOnset(double scoreTime); - double GetScoreTimeOnset() const; + void SetScoreTimeOnset(Fraction scoreTime); + Fraction GetScoreTimeOnset() const; //----------// // Functors // @@ -75,7 +75,7 @@ class BeatRpt : public LayerElement, public AttColor, public AttBeatRptLog, publ * The score-time onset of the note in the measure (duration from the start of measure in * quarter notes). */ - double m_scoreTimeOnset; + Fraction m_scoreTimeOnset; }; } // namespace vrv diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index 215ba4fce57..6a9c21292f9 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -114,17 +114,17 @@ class DurationInterface : public Interface, * MIDI timing information */ ///@{ - void SetScoreTimeOnset(double scoreTime); + void SetScoreTimeOnset(Fraction scoreTime); void SetRealTimeOnsetSeconds(double timeInSeconds); - void SetScoreTimeOffset(double scoreTime); + void SetScoreTimeOffset(Fraction scoreTime); void SetRealTimeOffsetSeconds(double timeInSeconds); - void SetScoreTimeTiedDuration(double timeInSeconds); - double GetScoreTimeOnset() const; + void SetScoreTimeTiedDuration(Fraction timeInSeconds); + Fraction GetScoreTimeOnset() const; double GetRealTimeOnsetMilliseconds() const; - double GetScoreTimeOffset() const; - double GetScoreTimeTiedDuration() const; + Fraction GetScoreTimeOffset() const; + Fraction GetScoreTimeTiedDuration() const; double GetRealTimeOffsetMilliseconds() const; - double GetScoreTimeDuration() const; + Fraction GetScoreTimeDuration() const; ///@} //-----------------// @@ -150,7 +150,7 @@ class DurationInterface : public Interface, * The score-time onset of the note in the measure (duration from the start of measure in * quarter notes). */ - double m_scoreTimeOnset; + Fraction m_scoreTimeOnset; /** * The score-time off-time of the note in the measure (duration from the start of the measure @@ -160,7 +160,7 @@ class DurationInterface : public Interface, * of the printed note, and the m_scoreTimeTiedDuration is -1.0 to indicate that it should not * be exported when creating a MIDI file. */ - double m_scoreTimeOffset; + Fraction m_scoreTimeOffset; /** * The time in milliseconds since the start of the measure element that contains the note. @@ -180,7 +180,7 @@ class DurationInterface : public Interface, * If the note is a secondary note in a tied group, then this variable is set to -1.0 to * indicate that it should not be written to MIDI output. */ - double m_scoreTimeTiedDuration; + Fraction m_scoreTimeTiedDuration; /** * The default duration: extracted from scoreDef/staffDef and used when no duration attribute is given diff --git a/include/vrv/measure.h b/include/vrv/measure.h index dcf96d15243..8069f161ae0 100644 --- a/include/vrv/measure.h +++ b/include/vrv/measure.h @@ -316,7 +316,7 @@ class Measure : public Object, /** * Read only access to m_scoreTimeOffset */ - double GetLastTimeOffset() const { return m_scoreTimeOffset.back(); } + Fraction GetLastTimeOffset() const { return m_scoreTimeOffset.back(); } /** * Return the real time offset in milliseconds @@ -331,7 +331,7 @@ class Measure : public Object, */ ///@{ void ClearScoreTimeOffset() { m_scoreTimeOffset.clear(); } - void AddScoreTimeOffset(double offset) { m_scoreTimeOffset.push_back(offset); } + void AddScoreTimeOffset(Fraction offset) { m_scoreTimeOffset.push_back(offset); } void ClearRealTimeOffset() { m_realTimeOffsetMilliseconds.clear(); } void AddRealTimeOffset(double milliseconds) { m_realTimeOffsetMilliseconds.push_back(milliseconds); } ///@} @@ -448,7 +448,7 @@ class Measure : public Object, /** * Start time state variables. */ - std::vector<double> m_scoreTimeOffset; + std::vector<Fraction> m_scoreTimeOffset; std::vector<double> m_realTimeOffsetMilliseconds; double m_currentTempo; diff --git a/include/vrv/midifunctor.h b/include/vrv/midifunctor.h index 8d7600bdf10..47e4b47d3bf 100644 --- a/include/vrv/midifunctor.h +++ b/include/vrv/midifunctor.h @@ -65,7 +65,7 @@ class InitOnsetOffsetFunctor : public Functor { // private: // The current score time in the measure (incremented by each element) - double m_currentScoreTime; + Fraction m_currentScoreTime; // The current real time in seconds in the measure (incremented by each element) double m_currentRealTimeSeconds; // The current time alignment parameters @@ -127,7 +127,7 @@ class InitMaxMeasureDurationFunctor : public Functor { // private: // The current score time - double m_currentScoreTime; + Fraction m_currentScoreTime; // The current time in seconds double m_currentRealTimeSeconds; // The current tempo @@ -423,7 +423,7 @@ class GenerateTimemapFunctor : public ConstFunctor { // private: // The score time from the start of the piece to the previous barline in quarter notes - double m_scoreTimeOffset; + Fraction m_scoreTimeOffset; // Real time from the start of the piece to the previous barline in ms double m_realTimeOffsetMilliseconds; // The current tempo diff --git a/include/vrv/vrvdef.h b/include/vrv/vrvdef.h index 66c40feceb4..5e02c4d153d 100644 --- a/include/vrv/vrvdef.h +++ b/include/vrv/vrvdef.h @@ -670,6 +670,16 @@ enum GraphicID { PRIMARY = 0, SPANNING, SYMBOLREF }; enum MeasureType { MEASURED = 0, UNMEASURED, NEUMELINE }; +//---------------------------------------------------------------------------- +// The score time unit (quarter note) +//---------------------------------------------------------------------------- + +#define SCORE_TIME_UNIT 4 + +//---------------------------------------------------------------------------- +// Section representing a line in neon +//---------------------------------------------------------------------------- + #define NEUME_LINE_TYPE "neon-neume-line" //---------------------------------------------------------------------------- diff --git a/src/beatrpt.cpp b/src/beatrpt.cpp index 26dc321bc07..d3221f02c46 100644 --- a/src/beatrpt.cpp +++ b/src/beatrpt.cpp @@ -51,7 +51,7 @@ void BeatRpt::Reset() this->ResetBeatRptVis(); this->ResetColor(); - m_scoreTimeOnset = 0.0; + m_scoreTimeOnset = 0; } Fraction BeatRpt::GetBeatRptAlignmentDuration(data_DURATION meterUnit) const @@ -61,12 +61,12 @@ Fraction BeatRpt::GetBeatRptAlignmentDuration(data_DURATION meterUnit) const return duration; } -void BeatRpt::SetScoreTimeOnset(double scoreTime) +void BeatRpt::SetScoreTimeOnset(Fraction scoreTime) { m_scoreTimeOnset = scoreTime; } -double BeatRpt::GetScoreTimeOnset() const +Fraction BeatRpt::GetScoreTimeOnset() const { return m_scoreTimeOnset; } diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 68c05cea91e..71d7a8de98d 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -65,11 +65,11 @@ void DurationInterface::Reset() m_durDefault = DURATION_NONE; - m_scoreTimeOnset = 0.0; - m_scoreTimeOffset = 0.0; + m_scoreTimeOnset = 0; + m_scoreTimeOffset = 0; m_realTimeOnsetMilliseconds = 0; m_realTimeOffsetMilliseconds = 0; - m_scoreTimeTiedDuration = 0.0; + m_scoreTimeTiedDuration = 0; } Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) const @@ -251,7 +251,7 @@ bool DurationInterface::HasIdenticalDurationInterface(const DurationInterface *o */ } -void DurationInterface::SetScoreTimeOnset(double scoreTime) +void DurationInterface::SetScoreTimeOnset(Fraction scoreTime) { m_scoreTimeOnset = scoreTime; } @@ -262,7 +262,7 @@ void DurationInterface::SetRealTimeOnsetSeconds(double timeInSeconds) m_realTimeOnsetMilliseconds = timeInSeconds * 1000.0; } -void DurationInterface::SetScoreTimeOffset(double scoreTime) +void DurationInterface::SetScoreTimeOffset(Fraction scoreTime) { m_scoreTimeOffset = scoreTime; } @@ -273,12 +273,12 @@ void DurationInterface::SetRealTimeOffsetSeconds(double timeInSeconds) m_realTimeOffsetMilliseconds = timeInSeconds * 1000.0; } -void DurationInterface::SetScoreTimeTiedDuration(double scoreTime) +void DurationInterface::SetScoreTimeTiedDuration(Fraction scoreTime) { m_scoreTimeTiedDuration = scoreTime; } -double DurationInterface::GetScoreTimeOnset() const +Fraction DurationInterface::GetScoreTimeOnset() const { return m_scoreTimeOnset; } @@ -288,7 +288,7 @@ double DurationInterface::GetRealTimeOnsetMilliseconds() const return m_realTimeOnsetMilliseconds; } -double DurationInterface::GetScoreTimeOffset() const +Fraction DurationInterface::GetScoreTimeOffset() const { return m_scoreTimeOffset; } @@ -298,12 +298,12 @@ double DurationInterface::GetRealTimeOffsetMilliseconds() const return m_realTimeOffsetMilliseconds; } -double DurationInterface::GetScoreTimeTiedDuration() const +Fraction DurationInterface::GetScoreTimeTiedDuration() const { return m_scoreTimeTiedDuration; } -double DurationInterface::GetScoreTimeDuration() const +Fraction DurationInterface::GetScoreTimeDuration() const { return this->GetScoreTimeOffset() - this->GetScoreTimeOnset(); } diff --git a/src/featureextractor.cpp b/src/featureextractor.cpp index fad1e07b47b..a1c2a9e9a40 100644 --- a/src/featureextractor.cpp +++ b/src/featureextractor.cpp @@ -59,7 +59,7 @@ void FeatureExtractor::Extract(const Object *object) if (chord && (note != chord->GetTopNote())) return; // Check if the note is tied to a previous one and skip it if yes - if (note->GetScoreTimeTiedDuration() == -1.0) { + if (note->GetScoreTimeTiedDuration() == -1) { // Check if we need to add it to the previous interval ids const int intervalsIdsSize = (int)m_intervalsIds.size(); if (intervalsIdsSize > 0) m_intervalsIds.get<jsonxx::Array>(intervalsIdsSize - 1) << note->GetID(); diff --git a/src/iomusxml.cpp b/src/iomusxml.cpp index 0432bf0caf1..98a09782a54 100644 --- a/src/iomusxml.cpp +++ b/src/iomusxml.cpp @@ -1761,11 +1761,11 @@ void MusicXmlInput::MatchTies(bool matchLayers) // match tie stop with pitch/oct identity, with start note earlier than end note, // and with earliest end note. if ((iter->m_note->IsEnharmonicWith(jter->m_note)) - && (iter->m_note->GetScoreTimeOnset() < jter->m_note->GetScoreTimeOnset()) - && (jter->m_note->GetScoreTimeOnset() < lastScoreTimeOnset) + && (iter->m_note->GetRealTimeOnsetMilliseconds() < jter->m_note->GetRealTimeOnsetMilliseconds()) + && (jter->m_note->GetRealTimeOnsetMilliseconds() < lastScoreTimeOnset) && (!matchLayers || (iter->m_layerNum == jter->m_layerNum))) { iter->m_tie->SetEndid("#" + jter->m_note->GetID()); - lastScoreTimeOnset = jter->m_note->GetScoreTimeOnset(); + lastScoreTimeOnset = jter->m_note->GetRealTimeOnsetMilliseconds(); tieMatched = true; break; } @@ -2830,7 +2830,7 @@ void MusicXmlInput::ReadMusicXmlNote( if (!noteID.empty()) { note->SetID(noteID); } - note->SetScoreTimeOnset(onset); // remember the MIDI onset within that measure + note->SetRealTimeOnsetSeconds(onset); // remember the MIDI onset within that measure // set @staff attribute, if existing and different from parent staff number if (noteStaffNum > 0 && noteStaffNum + staffOffset != staff->GetN()) note->SetStaff( diff --git a/src/measure.cpp b/src/measure.cpp index 48bd70e42af..ea7b78ae3fd 100644 --- a/src/measure.cpp +++ b/src/measure.cpp @@ -475,8 +475,8 @@ const Staff *Measure::GetBottomVisibleStaff() const int Measure::EnclosesTime(int time) const { int repeat = 1; - double timeDuration = m_measureAligner.GetRightAlignment()->GetTime().ToDouble() * static_cast<int>(DURATION_4) - / DUR_MAX * 60.0 / m_currentTempo * 1000.0 + double timeDuration + = m_measureAligner.GetRightAlignment()->GetTime().ToDouble() * SCORE_TIME_UNIT * 60.0 / m_currentTempo * 1000.0 + 0.5; std::vector<double>::const_iterator iter; for (iter = m_realTimeOffsetMilliseconds.begin(); iter != m_realTimeOffsetMilliseconds.end(); ++iter) { diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 45ea551835c..c05965ae93a 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -42,7 +42,7 @@ namespace vrv { InitOnsetOffsetFunctor::InitOnsetOffsetFunctor() : Functor() { - m_currentScoreTime = 0.0; + m_currentScoreTime = 0; m_currentRealTimeSeconds = 0.0; m_meterParams.mensur = NULL; m_meterParams.meterSig = NULL; @@ -54,11 +54,10 @@ FunctorCode InitOnsetOffsetFunctor::VisitChordEnd(Chord *chord) { LayerElement *element = chord->ThisOrSameasLink(); - double incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); - incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); - double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; + Fraction incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; + double realTimeIncrementSeconds = incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; - m_currentScoreTime += incrementScoreTime; + m_currentScoreTime = m_currentScoreTime + incrementScoreTime; m_currentRealTimeSeconds += realTimeIncrementSeconds; return FUNCTOR_CONTINUE; @@ -66,7 +65,7 @@ FunctorCode InitOnsetOffsetFunctor::VisitChordEnd(Chord *chord) FunctorCode InitOnsetOffsetFunctor::VisitLayer(Layer *layer) { - m_currentScoreTime = 0.0; + m_currentScoreTime = 0; m_currentRealTimeSeconds = 0.0; m_meterParams.mensur = layer->GetCurrentMensur(); @@ -81,22 +80,21 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement LayerElement *element = layerElement->ThisOrSameasLink(); - double incrementScoreTime; + Fraction incrementScoreTime; if (element->Is(REST) || element->Is(SPACE)) { - incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); - incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); + incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; // For rests to be possibly added to the timemap if (element->Is(REST)) { Rest *rest = vrv_cast<Rest *>(element); - double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; + double realTimeIncrementSeconds = incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; rest->SetScoreTimeOnset(m_currentScoreTime); rest->SetRealTimeOnsetSeconds(m_currentRealTimeSeconds); rest->SetScoreTimeOffset(m_currentScoreTime + incrementScoreTime); rest->SetRealTimeOffsetSeconds(m_currentRealTimeSeconds + realTimeIncrementSeconds); } - m_currentScoreTime += incrementScoreTime; - m_currentRealTimeSeconds += incrementScoreTime * 60.0 / m_currentTempo; + m_currentScoreTime = m_currentScoreTime + incrementScoreTime; + m_currentRealTimeSeconds += incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; } else if (element->Is(NOTE)) { Note *note = vrv_cast<Note *>(element); @@ -111,16 +109,15 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement // If the note has a @dur or a @dur.ges, take it into account // This means that overwriting only @dots or @dots.ges will not be taken into account if (chord && !note->HasDur() && !note->HasDurGes()) { - incrementScoreTime = chord->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); + incrementScoreTime = chord->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; } else if (tabGrp && !note->HasDur() && !note->HasDurGes()) { - incrementScoreTime = tabGrp->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); + incrementScoreTime = tabGrp->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; } else { - incrementScoreTime = note->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); + incrementScoreTime = note->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; } - incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); - double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; + double realTimeIncrementSeconds = incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; // LogDebug("Note Alignment Duration %f - Dur %d - Diatonic Pitch %d - Track %d", GetAlignmentDuration(), // note->GetNoteOrChordDur(element), note->GetDiatonicPitch(), *midiTrack); @@ -137,7 +134,7 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement // increase the currentTime accordingly, but only if not in a chord or tabGrp if (!note->IsChordTone() && !note->IsTabGrpNote()) { - m_currentScoreTime += incrementScoreTime; + m_currentScoreTime = m_currentScoreTime + incrementScoreTime; m_currentRealTimeSeconds += realTimeIncrementSeconds; } } @@ -145,18 +142,16 @@ FunctorCode InitOnsetOffsetFunctor::VisitLayerElement(LayerElement *layerElement BeatRpt *rpt = vrv_cast<BeatRpt *>(element); assert(rpt); - incrementScoreTime = rpt->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); - incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); + incrementScoreTime = rpt->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; rpt->SetScoreTimeOnset(m_currentScoreTime); - m_currentScoreTime += incrementScoreTime; - m_currentRealTimeSeconds += incrementScoreTime * 60.0 / m_currentTempo; + m_currentScoreTime = m_currentScoreTime + incrementScoreTime; + m_currentRealTimeSeconds += incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; } else if (layerElement->Is({ BEAM, LIGATURE, FTREM, TUPLET }) && layerElement->HasSameasLink()) { incrementScoreTime - = layerElement->GetSameAsContentAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); - incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); - m_currentScoreTime += incrementScoreTime; - m_currentRealTimeSeconds += incrementScoreTime * 60.0 / m_currentTempo; + = layerElement->GetSameAsContentAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; + m_currentScoreTime = m_currentScoreTime + incrementScoreTime; + m_currentRealTimeSeconds += incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; } else if (layerElement->Is(MENSUR)) { this->m_meterParams.mensur = vrv_cast<Mensur *>(layerElement); @@ -189,11 +184,10 @@ FunctorCode InitOnsetOffsetFunctor::VisitTabGrpEnd(TabGrp *tabGrp) { LayerElement *element = tabGrp->ThisOrSameasLink(); - double incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType).ToDouble(); - incrementScoreTime = incrementScoreTime / (DUR_MAX / DURATION_4); - double realTimeIncrementSeconds = incrementScoreTime * 60.0 / m_currentTempo; + Fraction incrementScoreTime = element->GetAlignmentDuration(m_meterParams, true, m_notationType) * SCORE_TIME_UNIT; + double realTimeIncrementSeconds = incrementScoreTime.ToDouble() * 60.0 / m_currentTempo; - m_currentScoreTime += incrementScoreTime; + m_currentScoreTime = m_currentScoreTime + incrementScoreTime; m_currentRealTimeSeconds += realTimeIncrementSeconds; return FUNCTOR_CONTINUE; @@ -205,7 +199,7 @@ FunctorCode InitOnsetOffsetFunctor::VisitTabGrpEnd(TabGrp *tabGrp) InitMaxMeasureDurationFunctor::InitMaxMeasureDurationFunctor() : Functor() { - m_currentScoreTime = 0.0; + m_currentScoreTime = 0; m_currentRealTimeSeconds = 0.0; m_currentTempo = MIDI_TEMPO; m_tempoAdjustment = 1.0; @@ -239,10 +233,10 @@ FunctorCode InitMaxMeasureDurationFunctor::VisitMeasureEnd(Measure *measure) const double tempo = this->GetAdjustedTempo(); measure->SetCurrentTempo(tempo); - const double scoreTimeIncrement = measure->m_measureAligner.GetRightAlignment()->GetTime().ToDouble() - * m_multiRestFactor * static_cast<int>(DURATION_4) / DUR_MAX; - m_currentScoreTime += scoreTimeIncrement; - m_currentRealTimeSeconds += scoreTimeIncrement * 60.0 / tempo; + const Fraction scoreTimeIncrement + = measure->m_measureAligner.GetRightAlignment()->GetTime() * m_multiRestFactor * SCORE_TIME_UNIT; + m_currentScoreTime = m_currentScoreTime + scoreTimeIncrement; + m_currentRealTimeSeconds += scoreTimeIncrement.ToDouble() * 60.0 / tempo; m_multiRestFactor = 1; return FUNCTOR_CONTINUE; @@ -287,16 +281,16 @@ FunctorCode InitTimemapTiesFunctor::VisitTie(Tie *tie) return FUNCTOR_CONTINUE; } - double sttd2 = note2->GetScoreTimeTiedDuration(); - double std2 = note2->GetScoreTimeDuration(); + Fraction sttd2 = note2->GetScoreTimeTiedDuration(); + Fraction std2 = note2->GetScoreTimeDuration(); - if (sttd2 > 0.0) { + if (sttd2 > 0) { note1->SetScoreTimeTiedDuration(sttd2 + std2); } else { note1->SetScoreTimeTiedDuration(std2); } - note2->SetScoreTimeTiedDuration(-1.0); + note2->SetScoreTimeTiedDuration(-1); return FUNCTOR_SIBLINGS; } @@ -363,8 +357,8 @@ FunctorCode GenerateMIDIFunctor::VisitBeatRpt(const BeatRpt *beatRpt) { // Sameas not taken into account for now AlignMeterParams params; - double beatLength = beatRpt->GetAlignmentDuration(params).ToDouble() / (DUR_MAX / DURATION_4); - double startTime = m_totalTime + beatRpt->GetScoreTimeOnset(); + double beatLength = beatRpt->GetAlignmentDuration(params).ToDouble() * SCORE_TIME_UNIT; + double startTime = m_totalTime + beatRpt->GetScoreTimeOnset().ToDouble(); int tpq = m_midiFile->getTPQ(); // filter last beat and copy all notes @@ -418,7 +412,8 @@ FunctorCode GenerateMIDIFunctor::VisitBTrem(const BTrem *bTrem) const Note *note = vrv_cast<const Note *>(obj); assert(note); const int pitch = note->GetMIDIPitch(m_transSemi); - const double totalInQuarterDur = note->GetScoreTimeDuration() + note->GetScoreTimeTiedDuration(); + const double totalInQuarterDur + = note->GetScoreTimeDuration().ToDouble() + note->GetScoreTimeTiedDuration().ToDouble(); int multiplicity = totalInQuarterDur / noteInQuarterDur; double noteDuration = noteInQuarterDur; // if NUM has been set for the bTrem, override calculated values @@ -490,7 +485,7 @@ FunctorCode GenerateMIDIFunctor::VisitGraceGrpEnd(const GraceGrp *graceGrp) // Handling of Nachschlag if (!m_graceNotes.empty() && (graceGrp->GetAttach() == graceGrpLog_ATTACH_pre) && !m_accentedGraceNote && m_lastNote) { - double startTime = m_totalTime + m_lastNote->GetScoreTimeOffset(); + double startTime = m_totalTime + m_lastNote->GetScoreTimeOffset().ToDouble(); const double graceNoteDur = UNACC_GRACENOTE_DUR * m_currentTempo / 60000.0; const double totalDur = graceNoteDur * m_graceNotes.size(); startTime -= totalDur; @@ -559,7 +554,7 @@ FunctorCode GenerateMIDIFunctor::VisitLayerElement(const LayerElement *layerElem FunctorCode GenerateMIDIFunctor::VisitMeasure(const Measure *measure) { // Here we need to update the m_totalTime from the starting time of the measure. - m_totalTime = measure->GetLastTimeOffset(); + m_totalTime = measure->GetLastTimeOffset().ToDouble(); if (measure->GetCurrentTempo() != m_currentTempo) { m_currentTempo = measure->GetCurrentTempo(); @@ -593,7 +588,7 @@ FunctorCode GenerateMIDIFunctor::VisitNote(const Note *note) } // If the note is a secondary tied note, then ignore it - if (note->GetScoreTimeTiedDuration() < 0.0) { + if (note->GetScoreTimeTiedDuration() < 0) { return FUNCTOR_SIBLINGS; } @@ -621,7 +616,7 @@ FunctorCode GenerateMIDIFunctor::VisitNote(const Note *note) int velocity = MIDI_VELOCITY; if (note->HasVel()) velocity = note->GetVel(); - double startTime = m_totalTime + note->GetScoreTimeOnset(); + double startTime = m_totalTime + note->GetScoreTimeOnset().ToDouble(); const int tpq = m_midiFile->getTPQ(); // Check if some grace notes must be performed @@ -680,13 +675,15 @@ FunctorCode GenerateMIDIFunctor::VisitNote(const Note *note) const double defaultHoldTime = 4; // quarter notes m_heldNotes[course - 1].m_pitch = pitch; m_heldNotes[course - 1].m_stopTime = m_totalTime - + std::max(defaultHoldTime, note->GetScoreTimeOffset() + note->GetScoreTimeTiedDuration()); + + std::max(defaultHoldTime, + note->GetScoreTimeOffset().ToDouble() + note->GetScoreTimeTiedDuration().ToDouble()); // start this note m_midiFile->addNoteOn(m_midiTrack, startTime * tpq, channel, pitch, velocity); } else { - const double stopTime = m_totalTime + note->GetScoreTimeOffset() + note->GetScoreTimeTiedDuration(); + const double stopTime + = m_totalTime + note->GetScoreTimeOffset().ToDouble() + note->GetScoreTimeTiedDuration().ToDouble(); m_midiFile->addNoteOn(m_midiTrack, startTime * tpq, channel, pitch, velocity); m_midiFile->addNoteOff(m_midiTrack, stopTime * tpq, channel, pitch); @@ -703,7 +700,7 @@ FunctorCode GenerateMIDIFunctor::VisitPedal(const Pedal *pedal) { if (!pedal->HasDir()) return FUNCTOR_CONTINUE; - double pedalTime = pedal->GetStart()->GetAlignment()->GetTime().ToDouble() * static_cast<int>(DURATION_4) / DUR_MAX; + double pedalTime = pedal->GetStart()->GetAlignment()->GetTime().ToDouble() * SCORE_TIME_UNIT; double startTime = m_totalTime + pedalTime; int tpq = m_midiFile->getTPQ(); @@ -730,7 +727,7 @@ FunctorCode GenerateMIDIFunctor::VisitScoreDef(const ScoreDef *scoreDef) const Object *next = parent->GetNext(scoreDef); if (next && next->Is(MEASURE)) { const Measure *nextMeasure = vrv_cast<const Measure *>(next); - totalTime = nextMeasure->GetLastTimeOffset(); + totalTime = nextMeasure->GetLastTimeOffset().ToDouble(); } } const double currentTick = totalTime * m_midiFile->getTPQ(); @@ -803,7 +800,7 @@ FunctorCode GenerateMIDIFunctor::VisitStaffDef(const StaffDef *staffDef) FunctorCode GenerateMIDIFunctor::VisitSyl(const Syl *syl) { - const double startTime = m_totalTime + m_lastNote->GetScoreTimeOnset(); + const double startTime = m_totalTime + m_lastNote->GetScoreTimeOnset().ToDouble(); const std::string sylText = UTF32to8(syl->GetText()); m_midiFile->addLyric(m_midiTrack, startTime * m_midiFile->getTPQ(), sylText); @@ -840,7 +837,7 @@ void GenerateMIDIFunctor::DeferMIDINote(const Note *refNote, double shift, bool } // Register the shift - if (shift < refNote->GetScoreTimeDuration() + refNote->GetScoreTimeTiedDuration()) { + if (shift < refNote->GetScoreTimeDuration().ToDouble() + refNote->GetScoreTimeTiedDuration().ToDouble()) { m_deferredNotes[refNote] = shift; } } @@ -850,7 +847,7 @@ void GenerateMIDIFunctor::GenerateGraceNoteMIDI( { double graceNoteDur = 0.0; if (m_accentedGraceNote && !m_graceNotes.empty()) { - const double totalDur = refNote->GetScoreTimeDuration() / 2.0; + const double totalDur = refNote->GetScoreTimeDuration().ToDouble() / 2.0; this->DeferMIDINote(refNote, totalDur, true); graceNoteDur = totalDur / m_graceNotes.size(); } @@ -881,7 +878,7 @@ void GenerateMIDIFunctor::GenerateGraceNoteMIDI( GenerateTimemapFunctor::GenerateTimemapFunctor(Timemap *timemap) : ConstFunctor() { - m_scoreTimeOffset = 0.0; + m_scoreTimeOffset = 0; m_realTimeOffsetMilliseconds = 0.0; m_currentTempo = MIDI_TEMPO; m_cueExclusion = false; @@ -945,10 +942,10 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) assert(interface); double realTimeStart = round(m_realTimeOffsetMilliseconds + interface->GetRealTimeOnsetMilliseconds()); - double scoreTimeStart = m_scoreTimeOffset + interface->GetScoreTimeOnset(); + Fraction scoreTimeStart = m_scoreTimeOffset + interface->GetScoreTimeOnset(); double realTimeEnd = round(m_realTimeOffsetMilliseconds + interface->GetRealTimeOffsetMilliseconds()); - double scoreTimeEnd = m_scoreTimeOffset + interface->GetScoreTimeOffset(); + Fraction scoreTimeEnd = m_scoreTimeOffset + interface->GetScoreTimeOffset(); bool isRest = (object->Is(REST)); @@ -958,7 +955,7 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) // Should check if value for realTimeStart already exists and if so, then // ensure that it is equal to scoreTimeStart: - startEntry.qstamp = scoreTimeStart; + startEntry.qstamp = scoreTimeStart.ToDouble(); // Store the element ID in list to turn on at given time - note or rest if (!isRest) startEntry.notesOn.push_back(object->GetID()); @@ -973,7 +970,7 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) // Should check if value for realTimeEnd already exists and if so, then // ensure that it is equal to scoreTimeEnd: - endEntry.qstamp = scoreTimeEnd; + endEntry.qstamp = scoreTimeEnd.ToDouble(); // Store the element ID in list to turn off at given time - notes or rest if (!isRest) endEntry.notesOff.push_back(object->GetID()); @@ -985,14 +982,14 @@ void GenerateTimemapFunctor::AddTimemapEntry(const Object *object) assert(measure); // Deal with repeated music later, for now get the last times. - double scoreTimeStart = m_scoreTimeOffset; + Fraction scoreTimeStart = m_scoreTimeOffset; double realTimeStart = round(m_realTimeOffsetMilliseconds); TimemapEntry &startEntry = m_timemap->GetEntry(realTimeStart); // Should check if value for realTimeStart already exists and if so, then // ensure that it is equal to scoreTimeStart: - startEntry.qstamp = scoreTimeStart; + startEntry.qstamp = scoreTimeStart.ToDouble(); // Add the measureOn startEntry.measureOn = measure->GetID(); From 416c8926ff6cb070c4fcc7ec052b672f7ecdb241 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Fri, 4 Oct 2024 15:43:49 +0200 Subject: [PATCH 101/105] Add test to avoid useless division in Fraction::Reduce --- src/horizontalaligner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index f1a68746279..6b6098f28eb 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -131,8 +131,10 @@ void Fraction::Reduce() m_denominator = -m_denominator; } int gcdVal = std::gcd(abs(m_numerator), abs(m_denominator)); - m_numerator /= gcdVal; - m_denominator /= gcdVal; + if (gcdVal != 1) { + m_numerator /= gcdVal; + m_denominator /= gcdVal; + } } std::pair<data_DURATION, Fraction> Fraction::ToDur() const From 16a3c5dba0409268a7be0d95eef196a82a10bd32 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Sat, 5 Oct 2024 14:35:05 +0200 Subject: [PATCH 102/105] Use Fraction in mensural alignment --- src/durationinterface.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/durationinterface.cpp b/src/durationinterface.cpp index 71d7a8de98d..075c3ab2dd5 100644 --- a/src/durationinterface.cpp +++ b/src/durationinterface.cpp @@ -82,8 +82,6 @@ Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) Fraction duration(noteDur); duration = duration * numBase / num; - // double old = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; - // duration = DUR_MAX / pow(2.0, (double)(noteDur - 2.0)) * numBase / num; int noteDots = (this->HasDotsGes()) ? this->GetDotsGes() : this->GetDots(); if (noteDots != VRV_UNSET) { @@ -97,7 +95,7 @@ Fraction DurationInterface::GetInterfaceAlignmentDuration(int num, int numBase) Fraction DurationInterface::GetInterfaceAlignmentMensuralDuration( int num, int numBase, const Mensur *currentMensur) const { - int noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); + data_DURATION noteDur = this->GetDurGes() != DURATION_NONE ? this->GetActualDurGes() : this->GetActualDur(); if (noteDur == DURATION_NONE) noteDur = DURATION_4; if (!currentMensur) { @@ -141,24 +139,24 @@ Fraction DurationInterface::GetInterfaceAlignmentMensuralDuration( if (currentMensur->HasNum()) num *= currentMensur->GetNum(); if (currentMensur->HasNumbase()) numBase *= currentMensur->GetNumbase(); - double ratio = 0.0; - double duration = (double)DUR_MENSURAL_REF; + int ratio = 0; + Fraction duration(DURATION_breve); switch (noteDur) { case DURATION_maxima: - duration *= (double)abs(currentMensur->GetModusminor()) * (double)abs(currentMensur->GetModusmaior()); + duration = duration * abs(currentMensur->GetModusminor()) * abs(currentMensur->GetModusmaior()); break; - case DURATION_long: duration *= (double)abs(currentMensur->GetModusminor()); break; + case DURATION_long: duration = duration * abs(currentMensur->GetModusminor()); break; case DURATION_breve: break; - case DURATION_1: duration /= (double)abs(currentMensur->GetTempus()); break; + case DURATION_1: duration = duration / abs(currentMensur->GetTempus()); break; default: ratio = pow(2.0, (double)(noteDur - DURATION_2)); - duration /= (double)abs(currentMensur->GetTempus()) * (double)abs(currentMensur->GetProlatio()) * ratio; + assert(ratio); + duration = duration / abs(currentMensur->GetTempus()) / abs(currentMensur->GetProlatio()) / ratio; break; } - duration *= (double)numBase / (double)num; - // LogDebug("Duration %d; %d/%d; Alignment %f; Ratio %f", noteDur, num, numbase, duration, ratio); - duration = durRound(duration); - return Fraction(DUR_MAX * duration, DUR_MAX * DUR_MAX); + duration = duration * numBase / num; + + return duration; } bool DurationInterface::IsFirstInBeam(const LayerElement *noteOrRest) const @@ -193,9 +191,9 @@ data_DURATION DurationInterface::GetActualDurGes() const data_DURATION DurationInterface::CalcActualDur(data_DURATION dur) const { - // maxima (-1) is a mensural only value - if (dur < DUR_MAX) return dur; - // Mensural duration (except maxima) + // No mapping needed for values below, including maxima and NONE + if (dur < DURATION_longa) return dur; + // Mensural durations (except maxima) switch (dur) { case DURATION_longa: return DURATION_long; case DURATION_brevis: return DURATION_breve; @@ -235,7 +233,7 @@ bool DurationInterface::IsMensuralDur() const { // maxima (-1) is a mensural only value if (this->GetDur() == DURATION_maxima) return true; - return (this->GetDur() > DUR_MENSURAL_MASK); + return (this->GetDur() >= DURATION_longa); } bool DurationInterface::HasIdenticalDurationInterface(const DurationInterface *otherDurationInterface) const From a170857b4c618bb1fbd3e42ab50dd3b0d65c74ef Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Sat, 5 Oct 2024 14:36:00 +0200 Subject: [PATCH 103/105] Additional cleanup * Remove some duration defines * Remove some uses of DUR_MAX * Adjust code comments --- include/vrv/durationinterface.h | 5 ++--- include/vrv/horizontalaligner.h | 2 +- include/vrv/vrvdef.h | 2 -- libmei/addons/attdef.h | 11 +++-------- src/drawinginterface.cpp | 2 +- src/horizontalaligner.cpp | 1 - src/layer.cpp | 1 - src/view_element.cpp | 2 +- 8 files changed, 8 insertions(+), 18 deletions(-) diff --git a/include/vrv/durationinterface.h b/include/vrv/durationinterface.h index 6a9c21292f9..2a101f46e8c 100644 --- a/include/vrv/durationinterface.h +++ b/include/vrv/durationinterface.h @@ -67,7 +67,7 @@ class DurationInterface : public Interface, /** * Returns the duration (in Fraction) for the element for mensural notation - * Currently this assume brevis equality (through DUR_MENSURAL_REF) and would + * Currently this assume brevis equality and would * need to be modified for shorter equality in later repertoire. */ Fraction GetInterfaceAlignmentMensuralDuration(int num, int numBase, const Mensur *currentMensur) const; @@ -85,8 +85,7 @@ class DurationInterface : public Interface, /** * @name Return the actual (gestural) duration of the note, for both CMN and mensural durations * See data_DURATION - * For CMN, it is the same (DURATION_1 == DURATION_1) - * For mensural, we need to apply the DUR_MENSURAL_MASK + * For Mensural, it is the same (DURATION_2 == DURATION_minima) */ ///@{ data_DURATION GetActualDur() const; diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index 25ca888dbb3..fa761c6e549 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -527,7 +527,7 @@ class MeasureAligner : public HorizontalAligner { /** * Get left Alignment for the measure and for the left BarLine. * For each MeasureAligner, we keep and Alignment for the left position. - * The Alignment time will be always -1.0 * DUR_MAX and will appear first in the list. + * The Alignment time will be always -1.0 and will appear first in the list. */ ///@{ Alignment *GetLeftAlignment() { return m_leftAlignment; } diff --git a/include/vrv/vrvdef.h b/include/vrv/vrvdef.h index 5e02c4d153d..b596eac7762 100644 --- a/include/vrv/vrvdef.h +++ b/include/vrv/vrvdef.h @@ -430,8 +430,6 @@ typedef std::map<int, LayerN_VerserN_t> StaffN_LayerN_VerseN_t; #define isIn(x, a, b) (((x) >= std::min((a), (b))) && ((x) <= std::max((a), (b)))) -#define durRound(dur) round(dur *pow(10, 8)) / pow(10, 8) - /** * Codes returned by Functors. * Default is FUNCTOR_CONTINUE. diff --git a/libmei/addons/attdef.h b/libmei/addons/attdef.h index 1bbd8de2975..04ee0b3c3ed 100644 --- a/libmei/addons/attdef.h +++ b/libmei/addons/attdef.h @@ -34,12 +34,7 @@ typedef double data_VU; //---------------------------------------------------------------------------- // used for alignement -#define DUR_MAX 1024 -// mensural duration -#define DUR_MENSURAL_OFFSET (2 * DUR_MAX) -#define DUR_MENSURAL_MASK (2 * DUR_MAX - 1) -// used for mensural alignment -#define DUR_MENSURAL_REF 1728 +#define DUR_MAX 2048 //---------------------------------------------------------------------------- // MEI data defines @@ -98,8 +93,8 @@ enum data_DURATION { DURATION_512, DURATION_1024, // 12 DURATION_2048, - DURATION_longa = DUR_MENSURAL_OFFSET + DURATION_long, - DURATION_brevis, + DURATION_longa = 100, + DURATION_brevis, // 101 DURATION_semibrevis, DURATION_minima, DURATION_semiminima, diff --git a/src/drawinginterface.cpp b/src/drawinginterface.cpp index c4a102a9432..09f209df455 100644 --- a/src/drawinginterface.cpp +++ b/src/drawinginterface.cpp @@ -420,7 +420,7 @@ bool BeamDrawingInterface::IsRepeatedPattern() const for (BeamElementCoord *coord : m_beamElementCoords) { if (!coord->m_stem || !coord->m_closestNote) continue; - // Could this be an overflow with 32 bits? + // Could this be an overflow with 32 bits? Not sure why DUR_MAX is used here items.push_back(coord->m_closestNote->GetDrawingY() + DUR_MAX * coord->m_dur); } int itemCount = (int)items.size(); diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 6b6098f28eb..5e1a30ae9b8 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -272,7 +272,6 @@ bool MeasureAligner::IsSupportedChild(Object *child) Alignment *MeasureAligner::GetAlignmentAtTime(const Fraction &time, AlignmentType type) { int idx; // the index if we reach the end. - // time = durRound(time); Alignment *alignment = this->SearchAlignmentAtTime(time, type, idx); // we already have a alignment of the type at that time if (alignment != NULL) return alignment; diff --git a/src/layer.cpp b/src/layer.cpp index e76afa8c94d..eaa30b8be3d 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -362,7 +362,6 @@ data_STEMDIRECTION Layer::GetDrawingStemDir(const ArrayOfBeamElementCoords *coor else { duration = measure->m_measureAligner.GetRightAlignment()->GetTime() - time; } - // duration = durRound(duration); if (this->GetLayerCountInTimeSpan(time, duration, measure, staff->GetN()) < 2) { return STEMDIRECTION_NONE; diff --git a/src/view_element.cpp b/src/view_element.cpp index 9766eac5833..efa5fd74b63 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -1174,7 +1174,7 @@ void View::DrawMRest(DeviceContext *dc, LayerElement *element, Layer *layer, Sta this->DrawSmuflCode(dc, x, y, rest, staffSize, drawingCueSize); // single legder line for whole rest glyphs - if ((measure->m_measureAligner.GetMaxTime() < (DUR_MAX * 2)) + if ((measure->m_measureAligner.GetMaxTime() < Fraction(DURATION_1)) && (y > staff->GetDrawingY() || y < staff->GetDrawingY() - (staff->m_drawingLines - 1) * m_doc->GetDrawingDoubleUnit(staffSize))) { const int width = m_doc->GetGlyphWidth(rest, staffSize, drawingCueSize); From dc62331aef34e7fd8110e258fa90dae16009c8e0 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Sat, 5 Oct 2024 14:59:29 +0200 Subject: [PATCH 104/105] Add static function to reduce are fraction --- include/vrv/horizontalaligner.h | 7 +++++++ src/horizontalaligner.cpp | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/include/vrv/horizontalaligner.h b/include/vrv/horizontalaligner.h index fa761c6e549..d6d428ec211 100644 --- a/include/vrv/horizontalaligner.h +++ b/include/vrv/horizontalaligner.h @@ -110,6 +110,13 @@ class Fraction { /** Convert to data_DURATION and the remaining Fraction */ std::pair<data_DURATION, Fraction> ToDur() const; + //----------------// + // Static methods // + //----------------// + + /** Reduce the faction represented by the two numbers */ + static void Reduce(int &numerator, int &denominator); + private: /** Reduce the fraction */ void Reduce(); diff --git a/src/horizontalaligner.cpp b/src/horizontalaligner.cpp index 5e1a30ae9b8..aa837ebd4d2 100644 --- a/src/horizontalaligner.cpp +++ b/src/horizontalaligner.cpp @@ -152,6 +152,13 @@ std::pair<data_DURATION, Fraction> Fraction::ToDur() const return { dur, remainder }; } +void Fraction::Reduce(int &numerator, int &denominator) +{ + Fraction fraction(numerator, denominator); + numerator = fraction.GetNumerator(); + denominator = fraction.GetDenominator(); +} + //---------------------------------------------------------------------------- // HorizontalAligner //---------------------------------------------------------------------------- From d58072ed27193530752f13cee84493fbc0c51dd7 Mon Sep 17 00:00:00 2001 From: Laurent Pugin <lxpugin@gmail.com> Date: Sat, 5 Oct 2024 15:01:37 +0200 Subject: [PATCH 105/105] Remove vrv::Reduce and use Fraction::Reduce --- include/vrv/vrv.h | 5 ----- src/iocmme.cpp | 4 ++-- src/proport.cpp | 2 +- src/vrv.cpp | 36 ------------------------------------ 4 files changed, 3 insertions(+), 44 deletions(-) diff --git a/include/vrv/vrv.h b/include/vrv/vrv.h index 9c4789a3386..9a8a80937cf 100644 --- a/include/vrv/vrv.h +++ b/include/vrv/vrv.h @@ -72,11 +72,6 @@ bool IsValidDouble(const std::string &value); */ bool IsDigits(const std::string &value); -/** - * Utility to reduce are faction of two integers - */ -void Reduce(int &numerator, int &denominator); - /** * Extract the ID from any URI */ diff --git a/src/iocmme.cpp b/src/iocmme.cpp index 92cea2b092c..87f530c3e64 100644 --- a/src/iocmme.cpp +++ b/src/iocmme.cpp @@ -944,7 +944,7 @@ void CmmeInput::CreateProport(pugi::xml_node proportNode) // Cumulated it m_mensInfo->proportDen *= denVal; } - vrv::Reduce(m_mensInfo->proportNum, m_mensInfo->proportDen); + Fraction::Reduce(m_mensInfo->proportNum, m_mensInfo->proportDen); proport->SetType("cmme_proportion"); m_currentContainer->AddChild(proport); return; @@ -1073,7 +1073,7 @@ data_DURATION CmmeInput::ReadDuration(pugi::xml_node durationNode, int &num, int num = cmmeDen; numbase = cmmeNum; - vrv::Reduce(num, numbase); + Fraction::Reduce(num, numbase); if (num == numbase) { num = VRV_UNSET; diff --git a/src/proport.cpp b/src/proport.cpp index 80ee2ad2f54..44466ca8a59 100644 --- a/src/proport.cpp +++ b/src/proport.cpp @@ -57,7 +57,7 @@ void Proport::Cumulate(const Proport *proport) m_cumulatedNumbase = this->GetNumbase() * proport->GetCumulatedNumbase(); } if ((m_cumulatedNum != VRV_UNSET) && (m_cumulatedNumbase != VRV_UNSET)) { - vrv::Reduce(m_cumulatedNum, m_cumulatedNumbase); + Fraction::Reduce(m_cumulatedNum, m_cumulatedNumbase); } } diff --git a/src/vrv.cpp b/src/vrv.cpp index bde1baab791..2378a542dd8 100644 --- a/src/vrv.cpp +++ b/src/vrv.cpp @@ -252,42 +252,6 @@ bool IsDigits(const std::string &value) return std::regex_match(value, re); } -// Function to compute the Greatest Common Divisor (GCD) -int GCD(int a, int b) -{ - if (b == 0) { - return std::abs(a); - } - return GCD(b, a % b); -} - -// Function to reduce the fraction -void Reduce(int &numerator, int &denominator) -{ - // Handle cases with zero denominator or numerator - if ((denominator == 0) || (denominator == VRV_UNSET)) { - return; - } - - if ((numerator == 0) || (denominator == VRV_UNSET)) { - denominator = 1; // A fraction with 0 numerator is 0/1 - return; - } - - // Get the greatest common divisor - int divisor = GCD(numerator, denominator); - - // Divide numerator and denominator by GCD - numerator /= divisor; - denominator /= divisor; - - // Ensure denominator is always positive - if (denominator < 0) { - numerator = -numerator; - denominator = -denominator; - } -} - std::string ExtractIDFragment(std::string refID) { size_t pos = refID.find_last_of("#");