rism-digital / verovio

🎵 Music notation engraving library for MEI with MusicXML and Humdrum support and various toolkits (JavaScript, Python)
https://www.verovio.org
GNU Lesser General Public License v3.0
661 stars 181 forks source link

Space harm appropriately #358

Closed craigsapp closed 3 years ago

craigsapp commented 7 years ago

As <harm> text length is increased, the <harm> text line rises for some reason. This rise eventually pushes the systems further apart as well. The example output on the left has short <harm> text, while the one on the right has long <harm> text.

screen shot 2016-11-17 at 23 18 28

Short harm example data:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="3.0.0">
    <meiHead>
        <fileDesc>
            <titleStmt>
                <title />
            </titleStmt>
            <pubStmt>
                <date>2016-11-17 22:57:12</date>
            </pubStmt>
        </fileDesc>
        <encodingDesc>
            <projectDesc>
                <p>Transcoded from Humdrum with Verovio version 0.9.13-dev-76b1067</p>
            </projectDesc>
        </encodingDesc>
    </meiHead>
    <music>
        <body>
            <mdiv>
                <score>
                    <scoreDef xml:id="scoredef-0000000818709889">
                        <staffGrp xml:id="m-0000000992362694">
                            <staffDef xml:id="staffdef-0000001281795456" clef.shape="G" clef.line="2" key.sig="0" meter.count="3" meter.unit="4" n="1" lines="5" />
                        </staffGrp>
                    </scoreDef>
                    <section xml:id="section-0000001997153672">
                        <measure xml:id="measure-L1" n="0">
                            <staff xml:id="staff-0000001658788722" n="1">
                                <layer xml:id="layer-L1F2" n="1">
                                    <note xml:id="note-L7F2" dots="1" dur="4" oct="5" pname="c" accid.ges="n" stem.dir="down" />
                                    <note xml:id="note-L8F2" dur="4" accid="f" oct="4" pname="b" stem.dir="down" />
                                    <note xml:id="note-L9F2" dur="8" accid="f" oct="4" pname="a" stem.dir="up" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000001869175712" staff="1" tstamp="1.000000">F</harm>
                            <harm xml:id="harm-0000001733895302" staff="1" tstamp="2.500000">B♭</harm>
                        </measure>
                        <measure xml:id="measure-L10">
                            <staff xml:id="staff-L10F2" n="1">
                                <layer xml:id="layer-L10F2" n="1">
                                    <note xml:id="note-L11F2" dots="1" dur="4" oct="4" pname="f" accid.ges="n" stem.dir="up" />
                                    <note xml:id="note-L12F2" dur="4" accid="f" oct="4" pname="a" stem.dir="up" />
                                    <note xml:id="note-L13F2" dur="8" accid="f" oct="4" pname="b" stem.dir="down" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000000666816101" staff="1" tstamp="1.000000">E♭</harm>
                        </measure>
                        <measure xml:id="measure-L14">
                            <staff xml:id="staff-L14F2" n="1">
                                <layer xml:id="layer-L14F2" n="1">
                                    <note xml:id="note-L15F2" dots="1" dur="4" oct="5" pname="c" accid.ges="n" stem.dir="down" />
                                    <note xml:id="note-L16F2" dur="4" accid="f" oct="4" pname="b" stem.dir="down" />
                                    <note xml:id="note-L17F2" dur="8" accid="f" oct="4" pname="a" stem.dir="up" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000000038480265" staff="1" tstamp="1.000000">B♭</harm>
                            <harm xml:id="harm-0000002029936609" staff="1" tstamp="3.500000">E♭</harm>
                        </measure>
                        <measure xml:id="measure-L18">
                            <staff xml:id="staff-L18F2" n="1">
                                <layer xml:id="layer-L18F2" n="1">
                                    <note xml:id="note-L19F2" dur="2" oct="4" pname="e" accid.ges="n" stem.dir="up" />
                                    <rest xml:id="rest-L20F2" dur="4" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000001555251778" staff="1" tstamp="1.000000">A♭</harm>
                        </measure>
                        <measure xml:id="measure-L21">
                            <staff xml:id="staff-L21F2" n="1">
                                <layer xml:id="layer-L21F2" n="1">
                                    <note xml:id="note-L22F2" dots="1" dur="4" oct="5" pname="c" accid.ges="n" stem.dir="down" />
                                    <note xml:id="note-L23F2" dur="4" accid="f" oct="4" pname="b" stem.dir="down" />
                                    <note xml:id="note-L24F2" dur="8" accid="f" oct="4" pname="a" stem.dir="up" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000000388685678" staff="1" tstamp="1.000000">F</harm>
                            <harm xml:id="harm-0000000788227284" staff="1" tstamp="2.500000">B♭</harm>
                        </measure>
                        <measure xml:id="measure-L25">
                            <staff xml:id="staff-L25F2" n="1">
                                <layer xml:id="layer-L25F2" n="1">
                                    <note xml:id="note-L26F2" dots="1" dur="4" oct="4" pname="f" accid.ges="n" stem.dir="up" />
                                    <note xml:id="note-L27F2" dur="4" accid="f" oct="4" pname="a" stem.dir="up" />
                                    <note xml:id="note-L28F2" dur="8" accid="f" oct="4" pname="b" stem.dir="down" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000000472998928" staff="1" tstamp="1.000000">E♭</harm>
                        </measure>
                    </section>
                </score>
            </mdiv>
        </body>
    </music>
</mei>

Long harm MEI

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="3.0.0">
    <meiHead>
        <fileDesc>
            <titleStmt>
                <title />
            </titleStmt>
            <pubStmt>
                <date>2016-11-17 22:55:33</date>
            </pubStmt>
        </fileDesc>
        <encodingDesc>
            <projectDesc>
                <p>Transcoded from Humdrum with Verovio version 0.9.13-dev-76b1067</p>
            </projectDesc>
        </encodingDesc>
    </meiHead>
    <music>
        <body>
            <mdiv>
                <score>
                    <scoreDef xml:id="scoredef-0000002093535509">
                        <staffGrp xml:id="m-0000001728054073">
                            <staffDef xml:id="staffdef-0000000835962883" clef.shape="G" clef.line="2" key.sig="0" meter.count="3" meter.unit="4" n="1" lines="5" />
                        </staffGrp>
                    </scoreDef>
                    <section xml:id="section-0000000543394331">
                        <measure xml:id="measure-L1" n="0">
                            <staff xml:id="staff-0000000022147551" n="1">
                                <layer xml:id="layer-L1F2" n="1">
                                    <note xml:id="note-L7F2" dots="1" dur="4" oct="5" pname="c" accid.ges="n" stem.dir="down" />
                                    <note xml:id="note-L8F2" dur="4" accid="f" oct="4" pname="b" stem.dir="down" />
                                    <note xml:id="note-L9F2" dur="8" accid="f" oct="4" pname="a" stem.dir="up" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000001206274047" staff="1" tstamp="1.000000">F minor-seventh</harm>
                            <harm xml:id="harm-0000000079211563" staff="1" tstamp="2.500000">B♭ dominant</harm>
                        </measure>
                        <measure xml:id="measure-L10">
                            <staff xml:id="staff-L10F2" n="1">
                                <layer xml:id="layer-L10F2" n="1">
                                    <note xml:id="note-L11F2" dots="1" dur="4" oct="4" pname="f" accid.ges="n" stem.dir="up" />
                                    <note xml:id="note-L12F2" dur="4" accid="f" oct="4" pname="a" stem.dir="up" />
                                    <note xml:id="note-L13F2" dur="8" accid="f" oct="4" pname="b" stem.dir="down" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000001458768941" staff="1" tstamp="1.000000">E♭ maj</harm>
                        </measure>
                        <measure xml:id="measure-L14">
                            <staff xml:id="staff-L14F2" n="1">
                                <layer xml:id="layer-L14F2" n="1">
                                    <note xml:id="note-L15F2" dots="1" dur="4" oct="5" pname="c" accid.ges="n" stem.dir="down" />
                                    <note xml:id="note-L16F2" dur="4" accid="f" oct="4" pname="b" stem.dir="down" />
                                    <note xml:id="note-L17F2" dur="8" accid="f" oct="4" pname="a" stem.dir="up" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000000042159528" staff="1" tstamp="1.000000">B♭ minor-seventh</harm>
                            <harm xml:id="harm-0000000133745035" staff="1" tstamp="3.500000">E♭ dominant</harm>
                        </measure>
                        <measure xml:id="measure-L18">
                            <staff xml:id="staff-L18F2" n="1">
                                <layer xml:id="layer-L18F2" n="1">
                                    <note xml:id="note-L19F2" dur="2" oct="4" pname="e" accid.ges="n" stem.dir="up" />
                                    <rest xml:id="rest-L20F2" dur="4" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000001667422194" staff="1" tstamp="1.000000">A♭ minor-major</harm>
                        </measure>
                        <measure xml:id="measure-L21">
                            <staff xml:id="staff-L21F2" n="1">
                                <layer xml:id="layer-L21F2" n="1">
                                    <note xml:id="note-L22F2" dots="1" dur="4" oct="5" pname="c" accid.ges="n" stem.dir="down" />
                                    <note xml:id="note-L23F2" dur="4" accid="f" oct="4" pname="b" stem.dir="down" />
                                    <note xml:id="note-L24F2" dur="8" accid="f" oct="4" pname="a" stem.dir="up" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000001531304268" staff="1" tstamp="1.000000">F minor-seventh</harm>
                            <harm xml:id="harm-0000000830883460" staff="1" tstamp="2.500000">B♭ dominant</harm>
                        </measure>
                        <measure xml:id="measure-L25">
                            <staff xml:id="staff-L25F2" n="1">
                                <layer xml:id="layer-L25F2" n="1">
                                    <note xml:id="note-L26F2" dots="1" dur="4" oct="4" pname="f" accid.ges="n" stem.dir="up" />
                                    <note xml:id="note-L27F2" dur="4" accid="f" oct="4" pname="a" stem.dir="up" />
                                    <note xml:id="note-L28F2" dur="8" accid="f" oct="4" pname="b" stem.dir="down" />
                                </layer>
                            </staff>
                            <harm xml:id="harm-0000000868591516" staff="1" tstamp="1.000000">E♭ maj</harm>
                        </measure>
                    </section>
                </score>
            </mdiv>
        </body>
    </music>
</mei>
lpugin commented 7 years ago

Make them short ;-)

craigsapp commented 7 years ago

Here is another case:

http://verovio.humdrum.org/?file=chopin/mazurkas/mazurka17-4.krn&filter=metlev%20-caemxhm

screen shot 2016-12-18 at 09 34 17

Using the <verse> system, the overlap is resolved:

http://verovio.humdrum.org/?file=chopin/mazurkas/mazurka17-4.krn&filter=metlev%20-caetext

But the problem is that I cannot attach lyrics to rests or to time offsets from a note attack:

screen shot 2016-12-18 at 09 40 35

It would be nice if the <harm> and <verse> systems had similar capabilities: both collision avoidance (currently only in <verse> and attachable to rest or arbitrary @tstamp locations (currently on in <harm>.

craigsapp commented 7 years ago

As the overlap increases, the veritcal offset increases:

screen shot 2016-12-18 at 09 59 20

So I suspect that there is a bug: overlap avoidance is being done, but it is applied to vertical offset rather than horizontal offset.

lpugin commented 7 years ago

There is a flaw in the algorithm. What is happening is that all the harm indications are aligned vertically (which means here pilled up in order to avoid collisions). Then they are all aligned with the highest one, which produces this. They should obviously be spaced before all this happening.

sonovice commented 5 years ago

There is a flaw in the algorithm. What is happening is that all the harm indications are aligned vertically (which means here pilled up in order to avoid collisions). Then they are all aligned with the highest one, which produces this. They should obviously be spaced before all this happening.

Could you maybe tell me where this happens in the code, please? I have the same problem right now and would take a look at it, but can't seem to find the right position...

sonovice commented 5 years ago

Responsible for the gaps are these lines of code, especially line 363 in this case: https://github.com/rism-ch/verovio/blob/13c67749cd8ee9b452ad67c18a649f7b8b9cd811/src/floatingobject.cpp#L355-L364

The information in that part are used here, probably directly after line 1581: https://github.com/rism-ch/verovio/blob/13c67749cd8ee9b452ad67c18a649f7b8b9cd811/src/view_control.cpp#L1545-L1604

I am still not able to find a solution. Any help would be highly appreciated.

lpugin commented 5 years ago

What needs to be added is a pass in the layout algorithm that spaces the harm before doing the vertical adjustment. This is missing, so it it not quite a matter of fixing existing code. (The additional problem is that adding this with the current justification algorithm will not work properly, so improving the justification algorithm should be done first. This is a quite significant task.) I will try to scaffold something.

sonovice commented 5 years ago

What needs to be added is a pass in the layout algorithm that spaces the harm before doing the vertical adjustment. This is missing, so it it not quite a matter of fixing existing code. (The additional problem is that adding this with the current justification algorithm will not work properly, so improving the justification algorithm should be done first. This is a quite significant task.) I will try to scaffold something.

Thank you so much, Laurent! If I can help in any way, please let me know.

sonovice commented 5 years ago

I really don't want to rush and I know that you certainly have a lot else on your plate. But do you think it's possible to look at this problem by the end of the month? I have the release date for an app breathing down my neck, and until recently I wasn't aware that solving the bug would require such profound changes that I unfortunately don't know the framework well enough for.

It would be great if you could just realistically estimate if the necessary changes are feasible in the next 2 weeks and if I can help somehow? Sorry if I lean too far out of the window. As I said, I don't want to pass on my own time pressure, but at the moment I'm a bit lost... 😟

EDIT: I just realized that--at least when using MusicXML--all harm texts are left-justified, so maybe there is no need to touch the justification algorithm in this case? Also the staffs below the overlapping harms are pushed further down, leaving space for multiple lines of harm text. So a quick solution might be to simply put the overlapping harms in the second (or even third?) line?

lpugin commented 5 years ago

I am afraid it will not be feasible for me to free some time for this in the next two weeks.

Now following up on your last edit: you should be able to manage multiple lines of harm text using @n, and they should be handled properly. Have you tried this?

lpugin commented 5 years ago

Could you send a sample MEI file? I can have a look this afternoon if there is at all a not too complicated fix for this.

sonovice commented 5 years ago

Could you send a sample MEI file? I can have a look this afternoon if there is at all a not too complicated fix for this.

Here is a MusicXML file and the MEI conversion done by Verovio: example.zip

Thank you for taking the time.

lpugin commented 5 years ago

OK, I implemented something 73fa29830199337ecc1e13ee0282eed19e67d3e6 As I said, because of some limitations in the justification algorithm this can still fail in some cases. Have a try and keep me posted.

craigsapp commented 5 years ago

You can use the --spacing-non-linear and/or --spacing-linear parameters to stretch the music spacing so that the longest <chord> does not collide with the next <chord>:

Screen Shot 2019-03-19 at 9 13 00 AM

The command-line options to generate the above rendering:

verovio --no-header --spacing-non-linear 0.65 example.musicxml

In Javascript toolkit, the options are named spacingNonLinear and spacingLinear.

spacingLinear parameter range: default: 0.25; min: 0.00; max: 1.00.

spacingNonLinear parameter range: default: 0.60; min: 0.00; max: 1.00

lpugin commented 5 years ago

image

sonovice commented 5 years ago

@lpugin Thank you so much! It works like a charm in most cases.

@craigsapp I already increased the spacing between notes but I needed a generic solution for several hundred songs in an iPhone App. The limited screen space makes your solution not viable, unfortunately. But thank you very much anyways!

lpugin commented 5 years ago

Great! What is the App? Looking forward to testing it.

sonovice commented 5 years ago

Great! What is the App? Looking forward to testing it.

It's not released yet (2 more weeks 😉 ) but the name is "Cantico".

earboxer commented 4 years ago

What is the status of the following?

bbloomf commented 3 years ago

Yes, what is the status of this? Has there been a regression? This example on verovio's site appears to be the same music as @lpugin posted here on March 20, 2019, but the overlap is not being prevented, and the extra vertical space is present.

bbloomf commented 3 years ago

I did a bit of digging, and 3dd860ad5 appears to have broken this, apparently because this->HasContentBB() is always returning false.

lpugin commented 3 years ago

Thanks for looking at this. Unfortunately, I do not understand what regression you are talking about. Can you be more explicit about it?

(As explained in this thread, spacing of harm indications is not expected to work because it has never been properly implemented.)

bbloomf commented 3 years ago

@lpugin What I meant is that before 3dd860a, running verovio on harm-004.mei produces output like in your comment above, but that commit introduced a change that causes verovio to produce output like what is shown on the Test Suite page

lpugin commented 3 years ago

You are right, it used to work better

image

I'll have a look

lpugin commented 3 years ago

We are now back to previous behaviour

image