Even though OSMD version 1.0.0. got released recently, something fresh came up from our assembly lines. We’ve added a new sponsor-only feature that boosts the rendering speed of sheet music 2-3 times, depending on the browser and piece. We’ve achieved this by making some changes in the calculate phase, using SVG over the canvas (details below). This is made available as an OSMD option that can be enabled or disabled (disabled by default).
During the processing of the sheet music, we utilize 2d heightmap representations called “Sky” and “Bottom” lines. These are essentially coordinate lists that map the bounds of the music staff lines so we can avoid collisions when calculating and ‘placing’ objects. We can actually render these with an OSMD setting to see how they look, e.g.:
As the sheet music is processed, the sky and bottom lines are updated in several ways. Some items, like slurs, do all the necessary bezier curve calculations in code to get the right values (Or labels just use a simple bounding box calculation). For beams and some other shapes (key signatures, noteheads) we use a different “catch-all” method.
The Canvas Method
This way of calculating the sky and bottom lines involves looping through each measure, and ‘rendering’ it on a hidden canvas. Then we grab the pixel data from the canvas, loop through it, and determine the bounds of the measure by the pixels’ alpha channel (only actual objects will have an alpha channel over 0).
This was the most time-consuming portion of the calculation process.
The New Method
With the performance mode option, we do things differently to speed up the process. We still render a hidden version of the measure, but use SVG instead of canvas. This enables us to access all the individual glyph elements of a measure. During rendering, we now also group the SVG elements by type, e.g.: ties, notes, beams, and so on. This enables us to process categories of objects specifically (and thus more efficiently).
We first establish a ‘baseline’ of where the sky and bottom lines rest on the stave lines themselves. If the overall rendered measure (including all other objects) is outside of these bounds, we process it. We look at all the child objects recursively and process only those branches that are outside of the baseline bounds.
For most objects, we simply use the built-in SVG method ‘getBBox’ which returns a rectangle bounding box of the object (slurs and labels still use their own methods, so we don’t need to worry about those). It seems this is sufficient and it is not necessary to calculate all the bezier curves or paths of the more complex glyphs. E.g.:
We can see here that though the bounding boxes aren’t as precise as the previous image, it doesn’t really affect the rendering end result (or affects it very little).
We do perform slope calculations on the beams based on their SVG path data. Since this calculation is not resource-intensive, it makes sense to do so and get their bounding lines more accurate.
And that’s it, in short. This gives a performance boost that is worth the small trade-off of having slightly less precise sky/bottom lines.
As mentioned, the speed of increase is browser-dependent. It’s all up to how optimized the getBBox implementation is for the given browser. The major browsers: Firefox, Chrome, and Edge, see the 2-3x speed increase. Our tests with Brave were not as impressive, though still an improvement (a 3-second increase on large pieces).
This is just phase 1 of our attempts to improve rendering times. We have some more ideas on the horizon that we hope to implement for greater factors of improvement.
The performance mode is an exclusive feature available only to our GitHub Sponsorsors. Other than early releases, our sponsors get awesome perks and goodies.
There’s also the Discord channel for all topics related to digital sheet music and Music XML. Accept the invite and hang out with other sheet music developers. As for anything related to OSMD follow our blog for frequent updates.