GSoC 2020: Tree Model - Week 8

Posted 3 months ago

Hi all, Welcome to this week's GSoC progress blog!

I have been trying to refactor the write() function based on the tree model. The basic idea is very simple:
We will have a generic ScoreElement::write() function which will be something like the following:

void ScoreElement::write(XMLWriter& xml)
{
    xml.beginElement(name());
    for (p : properties()) {
         p.write(w);
    }
    for (c : children()) {
        c.write(w);
    }
    xml.endElement();
}

So the function will basically write the begin tag, all the properties related to the current element, then all the children elements. The problem is mainly in figuring out how to write the data related to each element.

The first thing I did was to go through the already existing write and read functions to see how they work and what changes I'm going to make to them.

Here is a rough diagram I made of the classes/functions that Score::write() goes through (click for larger version):

m.png

I made a few observations:
1. There is already a system for storing properties of classes using the getProperty and setProperty which uses the properties in Pid. The Pid enum contains a list of a lot of properties and their types, and each class has implemented getProperty and setProperty virtual functions.
2. Most of the classes use these Pid based properties to write the data in XML format in the write function, e.g. here in the Note class:

for (Pid id : { Pid::PITCH, Pid::TPC1, Pid::TPC2, Pid::SMALL, Pid::MIRROR_HEAD, Pid::DOT_POSITION,
                Pid::HEAD_SCHEME, Pid::HEAD_GROUP, Pid::VELO_OFFSET, Pid::PLAY, Pid::TUNING, Pid::FRET, Pid::STRING,
                Pid::GHOST, Pid::HEAD_TYPE, Pid::VELO_TYPE, Pid::FIXED, Pid::FIXED_LINE }) {
    writeProperty(xml, id);
}

or here, in Accidental:

void Accidental::write(XmlWriter& xml) const
{
    xml.stag(this);
    writeProperty(xml, Pid::ACCIDENTAL_BRACKET);
    writeProperty(xml, Pid::ROLE);
    writeProperty(xml, Pid::SMALL);
    writeProperty(xml, Pid::ACCIDENTAL_TYPE);
    Element::writeProperties(xml);
    xml.etag();
}
  1. However there are many places where instead of using Pid, some data is written directly using the xml.tag function.
    E.g. in Ambitus::write
    xml.tag("topPitch",   _topPitch);
    xml.tag("topTpc",     _topTpc);
    xml.tag("bottomPitch",_bottomPitch);
    xml.tag("bottomTpc",  _bottomTpc);
  1. If I search for xml.tag(" within libmscore, it gives me around 300 results in 56 files. So I will probably have to move all of them either to the Pid properties or make a new system for the properties.
  2. The hierarchy of write() function even goes through classes that are not derived from Element or ScoreElement, so there's a bit of problem here, because I cannot traverse these classes from the score tree. I'll have to figure out some way to handle these.
  3. One way to write all the data is to iterate over the Pid enum and write down all the properties I can write. I have tried to do this right now, on my experimental branch, and here's a side by side diff of the original and new mscx files: https://gist.github.com/Kartikay26/b57359ac6f297b46f3feafe22d33aafe (new one is on the right, original on the left)

I also tried to create a property system of my own on my experimental branch, and I'm still trying to figure out what will be the best way to handle the properties.

By the way, this week we also got to know that our institute's director has got changed and the new director has told the teachers to conduct the remaining evaluations of last semester. So I had three vivas this week and there's a seminar this upcoming Wednesday, so I wasn't able to make as much progress as I hoped to. But I'll try to quickly get back to schedule once it is over.

Other links:

Link to experimental code: https://github.com/Kartikay26/MuseScore/compare/gsoc-2020-scanElements-…
Previous blog: https://musescore.org/en/user/1743616/blog/2020/07/20/gsoc-2020-tree-mo…
Next blog: https://musescore.org/en/user/1743616/blog/2020/08/04/gsoc-2020-tree-mo…