Skip to content

Instantly share code, notes, and snippets.

@joeberkovitz
Last active March 12, 2018 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joeberkovitz/41a1970047c32b74a77948608da50c1c to your computer and use it in GitHub Desktop.
Save joeberkovitz/41a1970047c32b74a77948608da50c1c to your computer and use it in GitHub Desktop.
Approaches to standardizing CWMN horizontal layout

Introduction

This document examines possible approaches to standardizing CWMN horizontal layout in MNX.

An attempt is made to analyze horizontal layout into a sequence of well-defined phases, expressed in terms of an underlying layout model. For each phase, a set of controlling style properties are proposed.

Producer Impact

For producers, these properties allow an implementation to express the results of its own layout decisions in a portable fashion by encoding them as style properties.

Consumer Impact

For consumers, these properties allow an implementation to reproduce the layout decisions of the original producer, while providing a standardized layout if no layout decisions are encoded.

It is unclear to what extent producer-consumer applications like notation editors will maintain imported style settings across editing sessions, however.

Definitions

The visual renderings of events, directions and barlines are called layout objects (or, for brevity, simply "objects"). The function of the layout algorithm is to determine the horizontal positions of these objects that is optimal for musical legibility and clarity.

The terminology used here is partly borrowed from John Gourlay's paper "Spacing a Line of Music", but adapted for MNX's vocabulary.

Unless otherwise stated, all dimensional units are relative, and may be expressed in terms of staff line spaces.

Layout Phases

Sim Determination

A set of simultaneities or sims are determined for each measure, across all parts and sequences. Every object belongs to exactly one sim, and is visually aligned to that sim at a horizontal position called the beatline. There is a single sim for all simultaneous objects placed at the same metrical position.

Within any given sequence, a sim at metrical position P therefore corresponds to either an event at P, or a notional boundary between the sim preceding P and the sim following P. In the latter case, sims subdivide events into event fractions.

Style properties do not control this layout phase, which is deterministic and solely based on the musical content.

Ideal Width

An ideal width is allocated to each sim. This is the width that the sim would occupy in staff line units if all objects occupied zero horizontal space, and there was no stretching or system justification.

Each sim's ideal width is calculated indirectly from events' ideal widths, so let's start there. The style property ideal-width, if specified by an event, explicitly gives the ideal width of the overall event in staff lines.

If ideal-width is not specified, a default ideal width of the event is calculated. As one approach to doing so, one might use a style property ideal-width-table, which provides a list of entries. Each entry consists of a pair of values: a note value which is the base 2 logarithm of duration (i.e. whole = 0, half = -1, etc.), and an ideal width in staff line units. Entries are sorted by note value in ascending order. The first entry, for the smallest note value, acts as a minimum ideal width.

To calculate the ideal width of a sim:

  • Set the sim's ideal width to zero.
  • For each event e intersected by the sim:
    • Determine the event width of e as specified above.
    • Let contributed width be sim duration * event width / event duration. This weights the event width to reflect the time fraction of the event occupied by the sim.
    • Set the sim's ideal width to the maximum of its current value and contributed width.

The above approach generally causes sims' width to be based on the shortest events that they intersect, since the ratio event width / event duration will be larger for shorter events.

Question: do we want to inflate all ideal widths, in the presence of short note values in some neighborhood? Opinions differ.

Note that object size is not taken into account in this step: ideal widths assume that events and directions are "point-like" and do not take up any space. One may think of this phase as determining a layout for the music which would work well if all notes and directions were infinitely small and could not collide.

Density

A sim's ideal width may be tweaked by any desired proportional factor at this point, as an overall control on the density of the layout. The style property density (default 1) controls this tweaking.

Stretch Limits

As the space allocation may be altered in later steps, each sim also is assigned an upper and lower limit on its horizontal space allocation, proportional to its ideal width. These are defined as scale factors applied to the sim's ideal width, supplied by the style properties stretch-max (default 2, i.e. it can expand by up to a factor of 2) and stretch-min (default 0.5, it can shrink by up to a factor of 2).

Boxing

For each object, determine its various components and arrange them into one or more atomic layout units called boxes. Each box is considered to be internally rigid, and the arrangement of boxes belonging to any given object is likewise rigid and nondeformable. (For example, a chord has a stem, noteheads, accidentals, dots and so forth, but these do not shift relative to each other based on layout).

Each box possesses:

  • a beatline, the the X coordinate relative to the box's render origin which is to be horizontally aligned with the position of the object's sim. This may be specified by the beatline property in staff line units relative to the origin of the box's graphical content; if absent, it is calculated based on the SMuFL metrics for what's inside the box.

  • the coordinates left, right, expressed relative to the beatline in staff line units. Style properties box-left and box-right override these.

  • the coordinates top and bottom, expressed relative to the topmost staff line in staff line units. Style properties box-top and box-bottom override these.

The box dimensions are defaulted to the visual bounds of the contained graphics, plus padding controlled by other style props TBD.

The style properties above can be specified at the level of <event>, <note>, <lyric> or any direction element.

QUESTION: How granular are boxes? Would an accidental have its own box, or be part of a larger box for the event as a whole? Do producer impls get to decide this question?

Note that the bounds of boxes and the arrangement of their contents will be partly controlled by specialized padding properties, e.g. a required spacing between accidentals and notes.

(TBD: how to deal with directions that are not simultaneous with events -- do these create additional sims?)

Blocking Widths

For each sim, a minimum blocking width is determined. This is the smallest width it can be assigned without causing any of its boxes to collide.

The algorithm is as follows:

  • Set the blocking width of each sim to its ideal width.

  • For each object obj in the layout,

    • Let left sim be the sim to which obj belongs.
    • For each box left box associated with obj,
      • Let total ideal be the ideal width of left sim.
      • Let right sim be the sim following left sim.
      • Let blocked sims be a list with left sim as its only element.
      • Let collidable be an empty list.
      • While right sim is within some maximum search limit,
        • For each object right obj simultaneous with right sim,
          • For each box right box associated with right obj,
            • If right box's vertical extent intersects any boxes in collidable
              • We ignore this box, as there are other objects that would collide first.
            • Else, if right box's vertical extent intersects that of left box,
              • Let collision width be the sum of left box's right, and right box's left.
              • For each element blocked of blocked sims,
                • Set blocking width to the maximum of blocking width and collision width * ideal width / total ideal. This apportions blocking width in a weighted fashion across all sims starting from left box up to right box.
            • Append right box to collidable.
        • If the union of all vertical extents in collidable covers the vertical extent of left box,
          • Exit this loop, because no additional collisions are possible.
        • Add the ideal width of right sim to total ideal.
        • Append right sim to blocked sims.
        • Advance right sim to the following sim.

Layout

This phase can be performed repeatedly, with any desired value of stretch, a variable that adds a further proportional adjustment to sim spacing.

Each sim is allocated a layout width equal to its ideal width, multiplied by its density and stretch factors, using its blocking width as a floor value. Sims are arranged in sequence, with each sim occupying its layout width. All objects aligned with a sim are positioned with their beatlines at the horizontal position of the sim.

System and Page Flow

Determine page and system breaks and chop up into systems, if needed. This will typically be an iterative process involving multiple layout passes with different values of stretch, observing the stretch/shrink limits for sims specified by stretch-max and stretch-min.

Justification

A final layout pass for each system determines the value of stretch yielding the exact system width needed, and places the layout objects in their final positions.

Layouts

A new element <layout> at the document level, specifies a set of identified layouts for the document. Each layout describes a way that the document can be formatted, and has:

  • A description of the geometry of the rendering surface (dimensions, or dimension ranges a la CSS media queries)
  • A set of <layout-part> elements that are included in the layout, in some specified order and grouping. Each of these includes the contents of <part> elements by reference.
  • A user-visible name.
  • A set of document-scoped style properties that only apply when this layout is in effect.
  • A set of <style-selector> and <style-class> property/class definitions that only apply when this layout is in effect.

Layouts are optional, and if absent, then a default layout applies to the entire score.

Breaks and Flow Control

System breaks, page breaks, and flow control instructions (like keeping measures together) are style properties that belong to <measure> elements. Within a <global>, they describe breaks for the full score. Within a <part>, they describe breaks for that part when displayed standalone.

Breaks come in two flavors: hints (i.e. "this is a preferred place to break") and declarations ("a break always occurs here").

To allow breaks to be specific to a layout, the may define a style class whose content is a break property. Elements bearing this class will then act as a break only when that layout is in effect.

@joeberkovitz
Copy link
Author

From 3/9/2018 chair call:

  • Should we bring back layouts as optional elements? breaks need to be relative to some specific geometry.
  • Break hints would be difficult for producers to distinguish from break declarations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment