Design & implementation

Updated 7 años ago

There are only a few documents regarding MuseScore internals, except of course the code and its comments.

Element classes hierarchy


Click on the image to download as PDF

Elements and score objects model


Click on the image to download as PDF.

A score is represented by a Score object in memory. A Score object can have a parent Score if the score is an Excerpt. An Excerpt object is used to represent a part in part extraction. A Score also maintain a list of Excerpts if it has parts.

In a Score, notes are stored in a list of Measure objects. Measure inherits from MeasureBase together with the frames. A Measure represents a measure across all the staves of a system, it's a "vertical column" of music. The Score also stores the tempo change list (TempoMap) and the time signature change list TimeSigMap. A Score object is complex, and has several states variables for layout, audio rendering. It also stores score metadata, style etc...

Layers in a Score object are a way to hide or show some Element according to the selected layer. A Score stores a list of Layers.

Layout

Element positions

The screen position of a visible element is computed from three values:

AP Anchor position of element. This is usually the position of the parent element.
LO Layout Offset, computed in the layout engine. MuseScore calculates it as the normal position of the element
UO User Offset, created by dragging an element by the user

The display position is computed as:
Display Position = AP + LO + UO

The saved position in a MuseScore file is computed as:
Saved Position = LO + UO

On read the saved position is written to the UserOffset (UO). The LayoutOffset (LO) is set to zero. On the first call of layout() the values for UO and LO are reconstructed. The condition LO==0 is used to determine the first call to layout().
After first Layout the values are computed as (RP = read position from file)

void Element::adjustReadPos()
            {
            if (RP != 0) {
		      UO = RP – newLO;
	            RP = 0;
		      }
            }

As a consequence, if you are writing an import filter and want to override the automatic placement of elements on import, set Element->_readPos. After layout MuseScore will compute a proper userOffset out of it.

Older MuseScore versions (<= 0.9.6) do only save the UO value. If loaded with a different MuseScore version than created, the position of certain elements may differ, as the layout algorithm (and the LO value) may have changed. This is avoided with the above scheme.

Caveats: adjustReadPos() has to be applied after the first complete layout of an element. This also means that a second layout() call should not change any element position. The layout has to be done in one pass.

Playback and synthesizers

msynth is a wrapper for Fluid and Zerberus.
Fluid is a SF2/SF3 soundfont synthesizer. The SF3 format is not a standard and use by MuseScore only. It's exactly like SF2 except the samples are encoded in OGG instead of WAV.
Zerberus is a SFZ synthesizer. It's mainly tested with the salamander piano SFZ. Any work to add support for more opcode is welcome.