Apply collision avoidance rules for marcato to sforzato accent as well

• Sep 6, 2015 - 15:12
Reported version
S5 - Suggestion

I'm working on a concert band score that includes many, many examples of this articulation:


The issue here is that, unlike the staccato on the second note, the sforzato on the first note is not offset by the presence of the slur. I can't even calculate the amount of time it would take me to adjust every single incidence of this. What's interesting is that, if I replace the sforzato with a marcato, I see that the marcato clearly is offset to avoid colliding with the slur.

So, my feature request is very simple: simply apply the same layout rules for marcato/slur interaction to sforzato/slur interactions.

Attachment Size
accent-slur.png 2.64 KB


Is this reasonable? Is it feasible? I suspect that it would be incredibly easy—just copy and paste a few lines of code from one place to another, perhaps with a "find-and-replace" operation to rename a word or two. The problem is that I don't have the knowledge to make that pull request, so I'm asking someone else to.

It's reaosnable, and probably feasible, but doubtful that easy. The code for articulation placement is full of special cases that each need to be handled differently, and the marcato placement code is rather different from the sforzando placement code. So the collision avoidance code would probably need to differ as well.

Well, I'll keep waiting. This is the first score I might be likely to publish, but not while this issue exists (by the way, should I reclassify this as a bug report? Or a task?). When possible, I'd very much like to see this worked out.

I looked at the code again. Sforzato and marcato are handled quite differently internally - they obey different rules, so unfortunately it is *not* just a matter of copying the marcato code. Not saying it isn't possible, just not *that* simple. Meanwhile, just leave this as a feature request, because that's exactly what it is.

Considering that thousands upon thousands of scores have been published either before notation software even existed, or with notation software with less sophisticated automatic layout that required more manual adjustment, and that literally millions of manual adjustments have been made over the years to produce the final results, I wouldn't let the fact that these markings will need manual adjustment stop you. Yes, it's work, but no more work than virtually everyone who has ever published a score has done many times over as well. It's just how it is.

It might be possible to completely automate collision avoidance using a points-based system or a cost-based system. In such a system you define rules about how many "points" a particular positioning of symbols is worth, and you choose the layout that is worth the least points (points are bad!). To use sforzato as an example:

Points rules for sforzato:

  1. Default placement = 0 points
  2. Add 1 point for every spatium ("stave space" unit) above the default position.
  3. Add 2 points for every spatium below the default. (i.e. prefer above default)
  4. Add 5 points for every spatium left/right of default. (i.e. horizontal movement is bad!)
  5. Add 10 points for a collision.

So the sforzato symbol would always be at the default position, unless there was a collision in which case it would almost always be moved above the colliding element.

Such a system would probably take quite a bit of work to set up initially but it would be trivial to add new rules later and even refine existing ones.

It could even be extended to controlling things like page layout automatically. Ideally music exactly fills a page. Any remaining space is a waste, so...

Rules for trying to force the music to exactly fill a page:

  1. Music exactly fills a page without adjustment = 0 points
  2. Add 1 point for every decrease of "stretch".
  3. Add 2 points for every increase of "stretch". (i.e. prefer fewer pages)
  4. Add 1 point for every decrease of "spatium" unit.
  5. Add 2 points for every increase of "spatium" unit.
  6. 20 point penalty if music doesn't exactly fill a page after adjustment.

Now MuseScore automatically adjusts the "stretch" and "spatium" units to make the music exactly fill a page to a maximum of 20 points. If 20 points of adjustment can't do it then the music is left half-filling a page.

This type of system can be good, but computationally extremely expensive. That's the balancing act we are trying to do here - get the best placement we can in essentially just a single pass, so response time isn't LilyPond-slow. Keep in mind, we layo out the entire score on every edit. If some day we are able to optimize that to only layout what is necessary, this would definitely open up doors for things like what is described here.

A points based method would indeed be computationally expensive. Some ways to reduce the load:

  1. Don't do it automatically. Use the current defaults and have an "Optimize score" button which calculates the new offsets, etc. (Or even via a plugin, but this could be slow and I don't know if a plugin could detect a collision.)
  2. Start optimization in the first bar and work through them in order. When the user makes a change to a bar somewhere in the middle of the score...
    • For most changes (e.g. vertical offsets), only that bar needs re-optimization.
    • For pretty much all other changes (e.g. horizontal offsets), only that bar and later bars need it.
    • Only for major layout changes (e.g. changes of stretch or spatium) must all bars be re-optimized.

Re. "Are you offering to do this?"
I'm just starting a Master's degree in Human Computer Interaction so I don't have much free time at the moment, but I have lots of ideas to contribute! After my degree I will be able to help more, and be qualified to do so! Anyone is welcome to have a go at implementing my ideas in the meantime, and I might have a go myself if I find a spare moment in which to do so...

Why don't you have a go at coding, Zack? You're pretty active on these forums, but if you spent a little bit of that time learning to code I think you'd get into it quite quickly. I can help you get started if you want. This is too big a task to start with, but there are plenty of smaller bugs and minor annoyances that you could have a go at tackling. Or you could try writing a plugin?

I was about to say (actually, I thought I had said, but it appears I never clicked "Save"—luckily the tab was still open):

Somewhere around here somebody once suggested that something like this (yes, that's very vague, but that's all I can remember) should be available among the Tools, but should not be included in the "re-layout on every edit" system. It might take several seconds during which the program might be unresponsive, but that's reasonable if you've just given the command to reprocess the entire score and adjust things based on a certain layout algorithm.

As to contributing to the code, I've often considered it but a) I'm pretty busy myself (among other things, preparing to apply to music school); and b) it's not just that I'm not familiar with MuseScore's code—I really know absolutely nothing about any type of computer code or language at all. Helping me get started would probably be more difficult than writing the collision avoidance algorithm. ;-)

I am not opposed to the semi-automatic thing, but I don't think that is terribly popular. As for the ways of reducing the laod, well, yes, it's those sort of things we want to do across the board to make layout faster - only redoing what is needed. Right now, the code just isn't structured in a way that makes this very feasible.

What to do once a collision has been detected (like the "point based" algorithm hinted at above) is just one part of the task; the other part, possibly the more complex, is the collision detection itself!

Element bounding boxes cannot be used: look at the example at the top of the thread, the staccato dot is inside the bounding box of the slur and a bounding box-based detection would (mis-)place the dot and/or the slur who knows where!

If I am not mistaken, Marc implemented an algorithm for accidental spacing which uses a box-minus-variable-corners model, tuned for accidentals; other kind of score elements would need specific models; in particular slurs, varying a lot in size and shape, may require rather sophisticated models in order to determine their 'repulsion areas'; also there are elements which may be embedded within the area occupied by a slur and other which cannot. A general algorithm for collision detection with slurs is going to be very complex.

Let's just remember that the specific issue at hand is for sforzato positioning relative to slurs. The rest of it is really a whole other conversation.

@Zack true, but a general solution is always preferable

@Miwarre it might be possible to use the font's raw vector data to determine a collision, though admittedly this would probably be pretty difficult to code and quite processor intensive.

Edit: The accepted answer to this Stack Overflow question gives an example of something similar using Javascript, so perhaps it wouldn't be too difficult or processor intensive after all! (You can try it here, click on the letters and the turn red. Admittedly a mouse-click is only a single point whereas detecting overlapping symbols requires many points to be evaluated, but JavaScript isn't as fast as C++).

For the record, yes, I did use a bounding-box-with-cutouts model for accidental placement. The SMuFL folks added that information to the standard and to the Bravura glyphs specifically at my request. Slurs would be trickier, though, since they aren't glyphs.

The way we do slur avoidance right now is not sophisticated at all - if there is a slur, we raise the articulation some fixed amount, only for articulations that happen to be handled in one particular part of the code. Sforzato is handled in a separate part of the code because, among other things, we also go to pains to avoid the staff lines.

Not a bad idea, but I'm not sure that's always desirable or always enough. Consider for example:


Not saying this sort of thing isn't worth trying, but my fear is, we come up with some sort of hack like this that works sometimes, doens't work other times, and people make their manual adjustments based on that, then later someone complains again and we try to change the hack, and suddenly the manual adjustments applied previously aren't good. To some extent there are ways around that, but it gets complicated really fast.

That's why I often point out it is in some cases better to have consistent / predictable defaults thatn to implement a half-solution that ends up causing problems down the road. Not saying this is definitely in that category, but it's definitely a valid concern.

Status (old) active fixed
Status active fixed
Reported version 2.1

The case is correctly processed in current master. It is better to create new request with the related case in current master.