|
|
var layoutBeam = require('./beam'); |
|
|
var getBarYAt = require('./get-bar-y-at'); |
|
|
var layoutTriplet = require('./triplet'); |
|
|
|
|
|
var layoutVoice = function (voice) { |
|
|
for (var i = 0; i < voice.beams.length; i++) { |
|
|
if (voice.beams[i].type === 'BeamElem') { |
|
|
layoutBeam(voice.beams[i]); |
|
|
moveDecorations(voice.beams[i]); |
|
|
|
|
|
for (var j = 0; j < voice.beams[i].elems.length; j++) { |
|
|
voice.adjustRange(voice.beams[i].elems[j]); |
|
|
} |
|
|
} |
|
|
} |
|
|
voice.staff.specialY.chordLines = setLaneForChord(voice.children); |
|
|
|
|
|
|
|
|
for (i = 0; i < voice.otherchildren.length; i++) { |
|
|
var child = voice.otherchildren[i]; |
|
|
if (child.type === 'TripletElem') { |
|
|
layoutTriplet(child); |
|
|
voice.adjustRange(child); |
|
|
} |
|
|
} |
|
|
voice.staff.top = Math.max(voice.staff.top, voice.top); |
|
|
voice.staff.bottom = Math.min(voice.staff.bottom, voice.bottom); |
|
|
}; |
|
|
|
|
|
function moveDecorations(beam) { |
|
|
var padding = 1.5; |
|
|
for (var ch = 0; ch < beam.elems.length; ch++) { |
|
|
var child = beam.elems[ch]; |
|
|
if (child.top) { |
|
|
|
|
|
var top = yAtNote(child, beam); |
|
|
for (var i = 0; i < child.children.length; i++) { |
|
|
var el = child.children[i]; |
|
|
if (el.klass === 'ornament' && el.position !== 'below') { |
|
|
if (el.bottom - padding < top) { |
|
|
var distance = top - el.bottom + padding; |
|
|
el.bottom += distance; |
|
|
el.top += distance; |
|
|
el.pitch += distance; |
|
|
top = child.top = el.top; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
function placeInLane(rightMost, relElem) { |
|
|
|
|
|
|
|
|
var xCoords = relElem.getChordDim(); |
|
|
if (xCoords) { |
|
|
for (var i = 0; i < rightMost.length; i++) { |
|
|
var fits = rightMost[i] < xCoords.left; |
|
|
if (fits) { |
|
|
if (i > 0) |
|
|
relElem.putChordInLane(i); |
|
|
rightMost[i] = xCoords.right; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
rightMost.push(xCoords.right); |
|
|
relElem.putChordInLane(rightMost.length - 1); |
|
|
} |
|
|
} |
|
|
|
|
|
function setLaneForChord(absElems) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var rightMostAbove = [0]; |
|
|
var rightMostBelow = [0]; |
|
|
var i; |
|
|
var j; |
|
|
var relElem; |
|
|
for (i = 0; i < absElems.length; i++) { |
|
|
for (j = 0; j < absElems[i].children.length; j++) { |
|
|
relElem = absElems[i].children[j]; |
|
|
if (relElem.chordHeightAbove) { |
|
|
placeInLane(rightMostAbove, relElem); |
|
|
} |
|
|
} |
|
|
for (j = absElems[i].children.length - 1; j >= 0; j--) { |
|
|
relElem = absElems[i].children[j]; |
|
|
if (relElem.chordHeightBelow) { |
|
|
placeInLane(rightMostBelow, relElem); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (rightMostAbove.length > 1 || rightMostBelow.length > 1) |
|
|
setLane(absElems, rightMostAbove.length, rightMostBelow.length); |
|
|
return { above: rightMostAbove.length, below: rightMostBelow.length }; |
|
|
} |
|
|
|
|
|
function numAnnotationsBelow(absElem) { |
|
|
var count = 0; |
|
|
for (var j = 0; j < absElem.children.length; j++) { |
|
|
var relElem = absElem.children[j]; |
|
|
if (relElem.chordHeightBelow) |
|
|
count++; |
|
|
} |
|
|
return count; |
|
|
} |
|
|
|
|
|
function setLane(absElems, numLanesAbove, numLanesBelow) { |
|
|
for (var i = 0; i < absElems.length; i++) { |
|
|
var below = numAnnotationsBelow(absElems[i]); |
|
|
for (var j = 0; j < absElems[i].children.length; j++) { |
|
|
var relElem = absElems[i].children[j]; |
|
|
if (relElem.chordHeightAbove) { |
|
|
relElem.invertLane(numLanesAbove); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
function yAtNote(element, beam) { |
|
|
beam = beam.beams[0]; |
|
|
return getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, element.x); |
|
|
} |
|
|
|
|
|
|
|
|
module.exports = layoutVoice; |
|
|
|