|
|
|
|
|
|
|
|
var AbsoluteElement = require('./elements/absolute-element'); |
|
|
var BeamElem = require('./elements/beam-element'); |
|
|
var BraceElem = require('./elements/brace-element'); |
|
|
var createClef = require('./create-clef'); |
|
|
var createKeySignature = require('./create-key-signature'); |
|
|
var createNoteHead = require('./create-note-head'); |
|
|
var createTimeSignature = require('./create-time-signature'); |
|
|
var Decoration = require('./decoration'); |
|
|
var EndingElem = require('./elements/ending-element'); |
|
|
var glyphs = require('./glyphs'); |
|
|
var RelativeElement = require('./elements/relative-element'); |
|
|
var spacing = require('../helpers/spacing'); |
|
|
var StaffGroupElement = require('./elements/staff-group-element'); |
|
|
var TempoElement = require('./elements/tempo-element'); |
|
|
var TieElem = require('./elements/tie-element'); |
|
|
var TripletElem = require('./elements/triplet-element'); |
|
|
var VoiceElement = require('./elements/voice-element'); |
|
|
var addChord = require('./add-chord'); |
|
|
var pitchesToPerc = require('../../synth/pitches-to-perc') |
|
|
|
|
|
var parseCommon = require('../../parse/abc_common'); |
|
|
|
|
|
var getDuration = function (elem) { |
|
|
var d = 0; |
|
|
if (elem.duration) { |
|
|
d = elem.duration; |
|
|
} |
|
|
return d; |
|
|
}; |
|
|
|
|
|
var hint = false; |
|
|
|
|
|
var chartable = { |
|
|
rest: { 0: "rests.whole", 1: "rests.half", 2: "rests.quarter", 3: "rests.8th", 4: "rests.16th", 5: "rests.32nd", 6: "rests.64th", 7: "rests.128th", "multi": "rests.multimeasure" }, |
|
|
note: { "-1": "noteheads.dbl", 0: "noteheads.whole", 1: "noteheads.half", 2: "noteheads.quarter", 3: "noteheads.quarter", 4: "noteheads.quarter", 5: "noteheads.quarter", 6: "noteheads.quarter", 7: "noteheads.quarter", 'nostem': "noteheads.quarter" }, |
|
|
rhythm: { "-1": "noteheads.slash.whole", 0: "noteheads.slash.whole", 1: "noteheads.slash.whole", 2: "noteheads.slash.quarter", 3: "noteheads.slash.quarter", 4: "noteheads.slash.quarter", 5: "noteheads.slash.quarter", 6: "noteheads.slash.quarter", 7: "noteheads.slash.quarter", nostem: "noteheads.slash.nostem" }, |
|
|
x: { "-1": "noteheads.indeterminate", 0: "noteheads.indeterminate", 1: "noteheads.indeterminate", 2: "noteheads.indeterminate", 3: "noteheads.indeterminate", 4: "noteheads.indeterminate", 5: "noteheads.indeterminate", 6: "noteheads.indeterminate", 7: "noteheads.indeterminate", nostem: "noteheads.indeterminate" }, |
|
|
harmonic: { "-1": "noteheads.harmonic.quarter", 0: "noteheads.harmonic.quarter", 1: "noteheads.harmonic.quarter", 2: "noteheads.harmonic.quarter", 3: "noteheads.harmonic.quarter", 4: "noteheads.harmonic.quarter", 5: "noteheads.harmonic.quarter", 6: "noteheads.harmonic.quarter", 7: "noteheads.harmonic.quarter", nostem: "noteheads.harmonic.quarter" }, |
|
|
triangle: { "-1": "noteheads.triangle.quarter", 0: "noteheads.triangle.quarter", 1: "noteheads.triangle.quarter", 2: "noteheads.triangle.quarter", 3: "noteheads.triangle.quarter", 4: "noteheads.triangle.quarter", 5: "noteheads.triangle.quarter", 6: "noteheads.triangle.quarter", 7: "noteheads.triangle.quarter", nostem: "noteheads.triangle.quarter" }, |
|
|
uflags: { 3: "flags.u8th", 4: "flags.u16th", 5: "flags.u32nd", 6: "flags.u64th" }, |
|
|
dflags: { 3: "flags.d8th", 4: "flags.d16th", 5: "flags.d32nd", 6: "flags.d64th" } |
|
|
}; |
|
|
|
|
|
var AbstractEngraver = function (getTextSize, tuneNumber, options) { |
|
|
this.decoration = new Decoration(); |
|
|
this.getTextSize = getTextSize; |
|
|
this.tuneNumber = tuneNumber; |
|
|
this.isBagpipes = options.bagpipes; |
|
|
this.flatBeams = options.flatbeams; |
|
|
this.graceSlurs = options.graceSlurs; |
|
|
this.percmap = options.percmap; |
|
|
this.initialClef = options.initialClef |
|
|
this.jazzchords = !!options.jazzchords |
|
|
this.accentAbove = !!options.accentAbove |
|
|
this.germanAlphabet = !!options.germanAlphabet |
|
|
this.reset(); |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.reset = function () { |
|
|
this.slurs = {}; |
|
|
this.ties = []; |
|
|
this.voiceScale = 1; |
|
|
this.voiceColor = undefined; |
|
|
this.slursbyvoice = {}; |
|
|
this.tiesbyvoice = {}; |
|
|
this.endingsbyvoice = {}; |
|
|
this.scaleByVoice = {}; |
|
|
this.colorByVoice = {}; |
|
|
this.tripletmultiplier = 1; |
|
|
|
|
|
this.abcline = undefined; |
|
|
this.accidentalSlot = undefined; |
|
|
this.accidentalshiftx = undefined; |
|
|
this.dotshiftx = undefined; |
|
|
this.hasVocals = false; |
|
|
this.minY = undefined; |
|
|
this.partstartelem = undefined; |
|
|
this.startlimitelem = undefined; |
|
|
this.stemdir = undefined; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.setStemHeight = function (heightInPixels) { |
|
|
this.stemHeight = Math.round(heightInPixels * 10 / spacing.STEP) / 10; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.getCurrentVoiceId = function (s, v) { |
|
|
return "s" + s + "v" + v; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.pushCrossLineElems = function (s, v) { |
|
|
this.slursbyvoice[this.getCurrentVoiceId(s, v)] = this.slurs; |
|
|
this.tiesbyvoice[this.getCurrentVoiceId(s, v)] = this.ties; |
|
|
this.endingsbyvoice[this.getCurrentVoiceId(s, v)] = this.partstartelem; |
|
|
this.scaleByVoice[this.getCurrentVoiceId(s, v)] = this.voiceScale; |
|
|
if (this.voiceColor) |
|
|
this.colorByVoice[this.getCurrentVoiceId(s, v)] = this.voiceColor; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.popCrossLineElems = function (s, v) { |
|
|
this.slurs = this.slursbyvoice[this.getCurrentVoiceId(s, v)] || {}; |
|
|
this.ties = this.tiesbyvoice[this.getCurrentVoiceId(s, v)] || []; |
|
|
this.partstartelem = this.endingsbyvoice[this.getCurrentVoiceId(s, v)]; |
|
|
this.voiceScale = this.scaleByVoice[this.getCurrentVoiceId(s, v)]; |
|
|
if (this.voiceScale === undefined) this.voiceScale = 1; |
|
|
this.voiceColor = this.colorByVoice[this.getCurrentVoiceId(s, v)]; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.containsLyrics = function (staves) { |
|
|
for (var i = 0; i < staves.length; i++) { |
|
|
for (var j = 0; j < staves[i].voices.length; j++) { |
|
|
for (var k = 0; k < staves[i].voices[j].length; k++) { |
|
|
var el = staves[i].voices[j][k]; |
|
|
if (el.lyric) { |
|
|
|
|
|
if (!el.positioning || el.positioning.vocalPosition === 'below') |
|
|
this.hasVocals = true; |
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.createABCLine = function (staffs, tempo, l) { |
|
|
this.minY = 2; |
|
|
|
|
|
this.containsLyrics(staffs); |
|
|
var staffgroup = new StaffGroupElement(this.getTextSize); |
|
|
this.tempoSet = false; |
|
|
for (var s = 0; s < staffs.length; s++) { |
|
|
if (hint) |
|
|
this.restoreState(); |
|
|
hint = false; |
|
|
this.createABCStaff(staffgroup, staffs[s], tempo, s, l); |
|
|
} |
|
|
return staffgroup; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.createABCStaff = function (staffgroup, abcstaff, tempo, s, l) { |
|
|
|
|
|
staffgroup.getTextSize.updateFonts(abcstaff); |
|
|
for (var v = 0; v < abcstaff.voices.length; v++) { |
|
|
var voice = new VoiceElement(v, abcstaff.voices.length); |
|
|
if (v === 0) { |
|
|
voice.barfrom = (abcstaff.connectBarLines === "start" || abcstaff.connectBarLines === "continue"); |
|
|
voice.barto = (abcstaff.connectBarLines === "continue" || abcstaff.connectBarLines === "end"); |
|
|
} else { |
|
|
voice.duplicate = true; |
|
|
} |
|
|
if (abcstaff.title && abcstaff.title[v]) { |
|
|
voice.header = abcstaff.title[v].replace(/\\n/g, "\n"); |
|
|
voice.headerPosition = 6 + staffgroup.getTextSize.baselineToCenter(voice.header, "voicefont", 'staff-extra voice-name', v, abcstaff.voices.length) / spacing.STEP; |
|
|
} |
|
|
if (abcstaff.clef && abcstaff.clef.type === "perc") |
|
|
voice.isPercussion = true; |
|
|
var clef = (!this.initialClef || l === 0) && createClef(abcstaff.clef, this.tuneNumber); |
|
|
if (clef) { |
|
|
if (v === 0 && abcstaff.barNumber) { |
|
|
this.addMeasureNumber(abcstaff.barNumber, clef); |
|
|
} |
|
|
voice.addChild(clef); |
|
|
this.startlimitelem = clef; |
|
|
} |
|
|
var keySig = createKeySignature(abcstaff.key, this.tuneNumber); |
|
|
if (keySig) { |
|
|
voice.addChild(keySig); |
|
|
this.startlimitelem = keySig; |
|
|
} |
|
|
if (abcstaff.meter) { |
|
|
if (abcstaff.meter.type === 'specified') { |
|
|
this.measureLength = abcstaff.meter.value[0].num / abcstaff.meter.value[0].den; |
|
|
} else |
|
|
this.measureLength = 1; |
|
|
var ts = createTimeSignature(abcstaff.meter, this.tuneNumber); |
|
|
voice.addChild(ts); |
|
|
this.startlimitelem = ts; |
|
|
} |
|
|
if (voice.duplicate) |
|
|
voice.children = []; |
|
|
var staffLines = abcstaff.clef.stafflines || abcstaff.clef.stafflines === 0 ? abcstaff.clef.stafflines : 5; |
|
|
staffgroup.addVoice(voice, s, staffLines); |
|
|
var isSingleLineStaff = staffLines === 1; |
|
|
this.createABCVoice(abcstaff.voices[v], tempo, s, v, isSingleLineStaff, voice); |
|
|
staffgroup.setStaffLimits(voice); |
|
|
if (v === 0) { |
|
|
|
|
|
if (abcstaff.brace === "start" || (!staffgroup.brace && abcstaff.brace)) { |
|
|
if (!staffgroup.brace) |
|
|
staffgroup.brace = []; |
|
|
staffgroup.brace.push(new BraceElem(voice, "brace")); |
|
|
} else if (abcstaff.brace === "end" && staffgroup.brace) { |
|
|
staffgroup.brace[staffgroup.brace.length - 1].setBottomStaff(voice); |
|
|
} else if (abcstaff.brace === "continue" && staffgroup.brace) { |
|
|
staffgroup.brace[staffgroup.brace.length - 1].continuing(voice); |
|
|
} |
|
|
if (abcstaff.bracket === "start" || (!staffgroup.bracket && abcstaff.bracket)) { |
|
|
if (!staffgroup.bracket) |
|
|
staffgroup.bracket = []; |
|
|
staffgroup.bracket.push(new BraceElem(voice, "bracket")); |
|
|
} else if (abcstaff.bracket === "end" && staffgroup.bracket) { |
|
|
staffgroup.bracket[staffgroup.bracket.length - 1].setBottomStaff(voice); |
|
|
} else if (abcstaff.bracket === "continue" && staffgroup.bracket) { |
|
|
staffgroup.bracket[staffgroup.bracket.length - 1].continuing(voice); |
|
|
} |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
function getBeamGroup(abcline, pos) { |
|
|
|
|
|
var elem = abcline[pos]; |
|
|
if (elem.el_type !== 'note' || !elem.startBeam || elem.endBeam) |
|
|
return { count: 1, elem: elem }; |
|
|
|
|
|
var group = []; |
|
|
while (pos < abcline.length && abcline[pos].el_type === 'note') { |
|
|
group.push(abcline[pos]); |
|
|
if (abcline[pos].endBeam) |
|
|
break; |
|
|
pos++; |
|
|
} |
|
|
return { count: group.length, elem: group }; |
|
|
} |
|
|
|
|
|
AbstractEngraver.prototype.createABCVoice = function (abcline, tempo, s, v, isSingleLineStaff, voice) { |
|
|
this.popCrossLineElems(s, v); |
|
|
this.stemdir = (this.isBagpipes) ? "down" : null; |
|
|
this.abcline = abcline; |
|
|
if (this.partstartelem) { |
|
|
this.partstartelem = new EndingElem("", null, null); |
|
|
voice.addOther(this.partstartelem); |
|
|
} |
|
|
var voiceNumber = voice.voicetotal < 2 ? -1 : voice.voicenumber; |
|
|
for (var slur in this.slurs) { |
|
|
if (this.slurs.hasOwnProperty(slur)) { |
|
|
|
|
|
this.slurs[slur] = new TieElem({ force: this.slurs[slur].force, voiceNumber: voiceNumber, stemDir: this.slurs[slur].stemDir, style: this.slurs[slur].dotted }); |
|
|
if (hint) this.slurs[slur].setHint(); |
|
|
voice.addOther(this.slurs[slur]); |
|
|
} |
|
|
} |
|
|
for (var i = 0; i < this.ties.length; i++) { |
|
|
|
|
|
this.ties[i] = new TieElem({ force: this.ties[i].force, stemDir: this.ties[i].stemDir, voiceNumber: voiceNumber, style: this.ties[i].dotted }); |
|
|
if (hint) this.ties[i].setHint(); |
|
|
voice.addOther(this.ties[i]); |
|
|
} |
|
|
|
|
|
for (var j = 0; j < this.abcline.length; j++) { |
|
|
setAveragePitch(this.abcline[j]); |
|
|
this.minY = Math.min(this.abcline[j].minpitch, this.minY); |
|
|
} |
|
|
|
|
|
var isFirstStaff = (s === 0); |
|
|
var pos = 0; |
|
|
while (pos < this.abcline.length) { |
|
|
var ret = getBeamGroup(this.abcline, pos); |
|
|
var abselems = this.createABCElement(isFirstStaff, isSingleLineStaff, voice, ret.elem); |
|
|
if (abselems) { |
|
|
for (i = 0; i < abselems.length; i++) { |
|
|
if (!this.tempoSet && tempo && !tempo.suppress) { |
|
|
this.tempoSet = true; |
|
|
var tempoElement = new AbsoluteElement(tempo, 0, 0, "tempo", this.tuneNumber, {}); |
|
|
tempoElement.addFixedX(new TempoElement(tempo, this.tuneNumber, createNoteHead)); |
|
|
voice.addChild(tempoElement); |
|
|
} |
|
|
voice.addChild(abselems[i]); |
|
|
} |
|
|
} |
|
|
pos += ret.count; |
|
|
} |
|
|
this.pushCrossLineElems(s, v); |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.saveState = function () { |
|
|
this.tiesSave = parseCommon.cloneArray(this.ties); |
|
|
this.slursSave = parseCommon.cloneHashOfHash(this.slurs); |
|
|
this.slursbyvoiceSave = parseCommon.cloneHashOfHash(this.slursbyvoice); |
|
|
this.tiesbyvoiceSave = parseCommon.cloneHashOfArrayOfHash(this.tiesbyvoice); |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.restoreState = function () { |
|
|
this.ties = parseCommon.cloneArray(this.tiesSave); |
|
|
this.slurs = parseCommon.cloneHashOfHash(this.slursSave); |
|
|
this.slursbyvoice = parseCommon.cloneHashOfHash(this.slursbyvoiceSave); |
|
|
this.tiesbyvoice = parseCommon.cloneHashOfArrayOfHash(this.tiesbyvoiceSave); |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AbstractEngraver.prototype.createABCElement = function (isFirstStaff, isSingleLineStaff, voice, elem) { |
|
|
var elemset = []; |
|
|
switch (elem.el_type) { |
|
|
case undefined: |
|
|
|
|
|
elemset = this.createBeam(isSingleLineStaff, voice, elem); |
|
|
break; |
|
|
case "note": |
|
|
elemset[0] = this.createNote(elem, false, isSingleLineStaff, voice); |
|
|
if (this.triplet && this.triplet.isClosed()) { |
|
|
voice.addOther(this.triplet); |
|
|
this.triplet = null; |
|
|
this.tripletmultiplier = 1; |
|
|
} |
|
|
break; |
|
|
case "bar": |
|
|
elemset[0] = this.createBarLine(voice, elem, isFirstStaff); |
|
|
if (voice.duplicate && elemset.length > 0) elemset[0].invisible = true; |
|
|
|
|
|
break; |
|
|
case "meter": |
|
|
elemset[0] = createTimeSignature(elem, this.tuneNumber); |
|
|
this.startlimitelem = elemset[0]; |
|
|
if (voice.duplicate && elemset.length > 0) elemset[0].invisible = true; |
|
|
break; |
|
|
case "clef": |
|
|
elemset[0] = createClef(elem, this.tuneNumber); |
|
|
if (!elemset[0]) return null; |
|
|
if (voice.duplicate && elemset.length > 0) elemset[0].invisible = true; |
|
|
break; |
|
|
case "key": |
|
|
var absKey = createKeySignature(elem, this.tuneNumber); |
|
|
if (absKey) { |
|
|
elemset[0] = absKey; |
|
|
this.startlimitelem = elemset[0]; |
|
|
} |
|
|
if (voice.duplicate && elemset.length > 0) elemset[0].invisible = true; |
|
|
break; |
|
|
case "stem": |
|
|
this.stemdir = elem.direction === "auto" ? undefined : elem.direction; |
|
|
break; |
|
|
case "part": |
|
|
var abselem = new AbsoluteElement(elem, 0, 0, 'part', this.tuneNumber); |
|
|
var dim = this.getTextSize.calc(elem.title, 'partsfont', "part"); |
|
|
abselem.addFixedX(new RelativeElement(elem.title, 0, 0, undefined, { type: "part", height: dim.height / spacing.STEP })); |
|
|
elemset[0] = abselem; |
|
|
break; |
|
|
case "tempo": |
|
|
var abselem3 = new AbsoluteElement(elem, 0, 0, 'tempo', this.tuneNumber); |
|
|
abselem3.addFixedX(new TempoElement(elem, this.tuneNumber, createNoteHead)); |
|
|
elemset[0] = abselem3; |
|
|
break; |
|
|
case "style": |
|
|
if (elem.head === "normal") |
|
|
delete this.style; |
|
|
else |
|
|
this.style = elem.head; |
|
|
break; |
|
|
case "hint": |
|
|
hint = true; |
|
|
this.saveState(); |
|
|
break; |
|
|
case "midi": |
|
|
|
|
|
break; |
|
|
case "scale": |
|
|
this.voiceScale = elem.size; |
|
|
break; |
|
|
case "color": |
|
|
this.voiceColor = elem.color; |
|
|
voice.color = this.voiceColor; |
|
|
break; |
|
|
|
|
|
default: |
|
|
var abselem2 = new AbsoluteElement(elem, 0, 0, 'unsupported', this.tuneNumber); |
|
|
abselem2.addFixed(new RelativeElement("element type " + elem.el_type, 0, 0, undefined, { type: "debug" })); |
|
|
elemset[0] = abselem2; |
|
|
} |
|
|
|
|
|
return elemset; |
|
|
}; |
|
|
|
|
|
function setAveragePitch(elem) { |
|
|
if (elem.pitches) { |
|
|
sortPitch(elem); |
|
|
var sum = 0; |
|
|
for (var p = 0; p < elem.pitches.length; p++) { |
|
|
sum += elem.pitches[p].verticalPos; |
|
|
} |
|
|
elem.averagepitch = sum / elem.pitches.length; |
|
|
elem.minpitch = elem.pitches[0].verticalPos; |
|
|
elem.maxpitch = elem.pitches[elem.pitches.length - 1].verticalPos; |
|
|
} |
|
|
} |
|
|
|
|
|
AbstractEngraver.prototype.createBeam = function (isSingleLineStaff, voice, elems) { |
|
|
var abselemset = []; |
|
|
|
|
|
var beamelem = new BeamElem(this.stemHeight * this.voiceScale, this.stemdir, this.flatBeams, elems[0]); |
|
|
if (hint) beamelem.setHint(); |
|
|
for (var i = 0; i < elems.length; i++) { |
|
|
|
|
|
beamelem.runningDirection(elems[i]) |
|
|
} |
|
|
beamelem.setStemDirection() |
|
|
var tempStemDir = this.stemdir |
|
|
this.stemdir = beamelem.stemsUp ? 'up' : 'down' |
|
|
for (i = 0; i < elems.length; i++) { |
|
|
var elem = elems[i]; |
|
|
var abselem = this.createNote(elem, true, isSingleLineStaff, voice); |
|
|
abselemset.push(abselem); |
|
|
beamelem.add(abselem); |
|
|
if (this.triplet && this.triplet.isClosed()) { |
|
|
voice.addOther(this.triplet); |
|
|
this.triplet = null; |
|
|
this.tripletmultiplier = 1; |
|
|
} |
|
|
} |
|
|
beamelem.calcDir(); |
|
|
voice.addBeam(beamelem); |
|
|
this.stemdir = tempStemDir |
|
|
return abselemset; |
|
|
}; |
|
|
|
|
|
var sortPitch = function (elem) { |
|
|
var sorted; |
|
|
do { |
|
|
sorted = true; |
|
|
for (var p = 0; p < elem.pitches.length - 1; p++) { |
|
|
if (elem.pitches[p].pitch > elem.pitches[p + 1].pitch) { |
|
|
sorted = false; |
|
|
var tmp = elem.pitches[p]; |
|
|
elem.pitches[p] = elem.pitches[p + 1]; |
|
|
elem.pitches[p + 1] = tmp; |
|
|
} |
|
|
} |
|
|
} while (!sorted); |
|
|
}; |
|
|
|
|
|
var ledgerLines = function (abselem, minPitch, maxPitch, isRest, symbolWidth, additionalLedgers, dir, dx, scale) { |
|
|
for (var i = maxPitch; i > 11; i--) { |
|
|
if (i % 2 === 0 && !isRest) { |
|
|
abselem.addFixed(new RelativeElement(null, dx, (symbolWidth + 4) * scale, i, { type: "ledger" })); |
|
|
} |
|
|
} |
|
|
|
|
|
for (i = minPitch; i < 1; i++) { |
|
|
if (i % 2 === 0 && !isRest) { |
|
|
abselem.addFixed(new RelativeElement(null, dx, (symbolWidth + 4) * scale, i, { type: "ledger" })); |
|
|
} |
|
|
} |
|
|
|
|
|
for (i = 0; i < additionalLedgers.length; i++) { |
|
|
var ofs = symbolWidth; |
|
|
if (dir === 'down') ofs = -ofs; |
|
|
abselem.addFixed(new RelativeElement(null, ofs + dx, (symbolWidth + 4) * scale, additionalLedgers[i], { type: "ledger" })); |
|
|
} |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.addGraceNotes = function (elem, voice, abselem, notehead, stemHeight, isBagpipes, roomtaken) { |
|
|
var gracescale = 3 / 5; |
|
|
var graceScaleStem = 3.5 / 5; |
|
|
stemHeight = Math.round(stemHeight * graceScaleStem); |
|
|
var gracebeam = null; |
|
|
var flag; |
|
|
|
|
|
if (elem.gracenotes.length > 1) { |
|
|
gracebeam = new BeamElem(stemHeight, "grace", isBagpipes); |
|
|
if (hint) gracebeam.setHint(); |
|
|
gracebeam.mainNote = abselem; |
|
|
} |
|
|
|
|
|
var i; |
|
|
var graceoffsets = []; |
|
|
for (i = elem.gracenotes.length - 1; i >= 0; i--) { |
|
|
roomtaken += 10; |
|
|
graceoffsets[i] = roomtaken; |
|
|
if (elem.gracenotes[i].accidental) { |
|
|
roomtaken += 7; |
|
|
} |
|
|
} |
|
|
|
|
|
for (i = 0; i < elem.gracenotes.length; i++) { |
|
|
var gracepitch = elem.gracenotes[i].verticalPos; |
|
|
|
|
|
flag = (gracebeam) ? null : chartable.uflags[(isBagpipes) ? 5 : 3]; |
|
|
var accidentalSlot = []; |
|
|
var ret = createNoteHead(abselem, "noteheads.quarter", elem.gracenotes[i], |
|
|
{ dir: "up", headx: -graceoffsets[i], extrax: -graceoffsets[i], flag: flag, scale: gracescale * this.voiceScale, accidentalSlot: accidentalSlot }); |
|
|
ret.notehead.highestVert = ret.notehead.pitch + stemHeight; |
|
|
var grace = ret.notehead; |
|
|
this.addSlursAndTies(abselem, elem.gracenotes[i], grace, voice, "up", true); |
|
|
|
|
|
abselem.addExtra(grace); |
|
|
|
|
|
if (elem.gracenotes[i].acciaccatura) { |
|
|
var pos = elem.gracenotes[i].verticalPos + 7 * gracescale; |
|
|
var dAcciaccatura = gracebeam ? 5 : 6; |
|
|
abselem.addRight(new RelativeElement("flags.ugrace", -graceoffsets[i] + dAcciaccatura, 0, pos, { scalex: gracescale, scaley: gracescale })); |
|
|
} |
|
|
if (gracebeam) { |
|
|
var graceDuration = elem.gracenotes[i].duration / 2; |
|
|
if (isBagpipes) graceDuration /= 2; |
|
|
var pseudoabselem = { |
|
|
heads: [grace], |
|
|
abcelem: { averagepitch: gracepitch, minpitch: gracepitch, maxpitch: gracepitch, duration: graceDuration } |
|
|
}; |
|
|
gracebeam.add(pseudoabselem); |
|
|
} else { |
|
|
var p1 = gracepitch + 1 / 3 * gracescale; |
|
|
var p2 = gracepitch + 7 * gracescale; |
|
|
var dx = grace.dx + grace.w; |
|
|
var width = -0.6; |
|
|
abselem.addExtra(new RelativeElement(null, dx, 0, p1, { "type": "stem", "pitch2": p2, linewidth: width })); |
|
|
} |
|
|
ledgerLines(abselem, gracepitch, gracepitch, false, glyphs.getSymbolWidth("noteheads.quarter"), [], true, grace.dx - 1, 0.6); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var isInvisibleRest = elem.rest && (elem.rest.type === "spacer" || elem.rest.type === "invisible"); |
|
|
if (i === 0 && !isBagpipes && this.graceSlurs && !isInvisibleRest) { |
|
|
|
|
|
voice.addOther(new TieElem({ anchor1: grace, anchor2: notehead, isGrace: true })); |
|
|
} |
|
|
} |
|
|
|
|
|
if (gracebeam) { |
|
|
gracebeam.calcDir(); |
|
|
voice.addBeam(gracebeam); |
|
|
} |
|
|
return roomtaken; |
|
|
}; |
|
|
|
|
|
function addRestToAbsElement(abselem, elem, duration, dot, isMultiVoice, stemdir, isSingleLineStaff, durlog, voiceScale) { |
|
|
var c; |
|
|
var restpitch = 7; |
|
|
var noteHead; |
|
|
var roomTaken; |
|
|
var roomTakenRight; |
|
|
|
|
|
if (isMultiVoice) { |
|
|
if (stemdir === "down") restpitch = 3; |
|
|
if (stemdir === "up") restpitch = 11; |
|
|
} |
|
|
|
|
|
if (isSingleLineStaff) { |
|
|
|
|
|
if (duration < 0.5) |
|
|
restpitch = 7; |
|
|
else if (duration < 1) |
|
|
restpitch = 7; |
|
|
else |
|
|
restpitch = 5; |
|
|
} |
|
|
switch (elem.rest.type) { |
|
|
case "whole": |
|
|
c = chartable.rest[0]; |
|
|
elem.averagepitch = restpitch; |
|
|
elem.minpitch = restpitch; |
|
|
elem.maxpitch = restpitch; |
|
|
dot = 0; |
|
|
break; |
|
|
case "rest": |
|
|
if (elem.style === "rhythm") |
|
|
c = chartable.rhythm[-durlog]; |
|
|
else |
|
|
c = chartable.rest[-durlog]; |
|
|
elem.averagepitch = restpitch; |
|
|
elem.minpitch = restpitch; |
|
|
elem.maxpitch = restpitch; |
|
|
break; |
|
|
case "invisible": |
|
|
case "invisible-multimeasure": |
|
|
case "spacer": |
|
|
c = ""; |
|
|
elem.averagepitch = restpitch; |
|
|
elem.minpitch = restpitch; |
|
|
elem.maxpitch = restpitch; |
|
|
break; |
|
|
case "multimeasure": |
|
|
c = chartable.rest['multi']; |
|
|
elem.averagepitch = restpitch; |
|
|
elem.minpitch = restpitch; |
|
|
elem.maxpitch = restpitch; |
|
|
dot = 0; |
|
|
var mmWidth = glyphs.getSymbolWidth(c); |
|
|
abselem.addHead(new RelativeElement(c, mmWidth, mmWidth * 2, 7)); |
|
|
var numMeasures = new RelativeElement("" + elem.rest.text, mmWidth, mmWidth, 16, { type: "multimeasure-text" }); |
|
|
abselem.addExtra(numMeasures); |
|
|
} |
|
|
if (elem.rest.type.indexOf("multimeasure") < 0 && elem.rest.type !== "invisible") { |
|
|
var ret = createNoteHead(abselem, c, { verticalPos: restpitch }, |
|
|
{ dot: dot, scale: voiceScale }); |
|
|
noteHead = ret.notehead; |
|
|
if (noteHead) { |
|
|
abselem.addHead(noteHead); |
|
|
roomTaken = ret.accidentalshiftx; |
|
|
roomTakenRight = ret.dotshiftx; |
|
|
} |
|
|
} |
|
|
return { noteHead: noteHead, roomTaken: roomTaken, roomTakenRight: roomTakenRight }; |
|
|
} |
|
|
|
|
|
function addIfNotExist(arr, item) { |
|
|
for (var i = 0; i < arr.length; i++) { |
|
|
if (JSON.stringify(arr[i]) === JSON.stringify(item)) |
|
|
return; |
|
|
} |
|
|
arr.push(item); |
|
|
} |
|
|
|
|
|
AbstractEngraver.prototype.addNoteToAbcElement = function (abselem, elem, dot, stemdir, style, zeroDuration, durlog, nostem, voice) { |
|
|
var dotshiftx = 0; |
|
|
var noteHead; |
|
|
var roomTaken = 0; |
|
|
var roomTakenRight = 0; |
|
|
var min; |
|
|
var i; |
|
|
var additionalLedgers = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var accidentalSlot = []; |
|
|
var symbolWidth = 0; |
|
|
|
|
|
var dir = (elem.averagepitch >= 6) ? "down" : "up"; |
|
|
if (stemdir) dir = stemdir; |
|
|
|
|
|
style = elem.style ? elem.style : style; |
|
|
if (!style || style === "normal") style = "note"; |
|
|
var noteSymbol; |
|
|
if (zeroDuration) |
|
|
noteSymbol = chartable[style].nostem; |
|
|
else |
|
|
noteSymbol = chartable[style][-durlog]; |
|
|
if (!noteSymbol) |
|
|
console.log("noteSymbol:", style, durlog, zeroDuration); |
|
|
|
|
|
|
|
|
var p; |
|
|
for (p = (dir === "down") ? elem.pitches.length - 2 : 1; (dir === "down") ? p >= 0 : p < elem.pitches.length; p = (dir === "down") ? p - 1 : p + 1) { |
|
|
var prev = elem.pitches[(dir === "down") ? p + 1 : p - 1]; |
|
|
var curr = elem.pitches[p]; |
|
|
var delta = (dir === "down") ? prev.pitch - curr.pitch : curr.pitch - prev.pitch; |
|
|
if (delta <= 1 && !prev.printer_shift) { |
|
|
curr.printer_shift = (delta) ? "different" : "same"; |
|
|
if (curr.verticalPos > 11 || curr.verticalPos < 1) { |
|
|
additionalLedgers.push(curr.verticalPos - (curr.verticalPos % 2)); |
|
|
} |
|
|
if (dir === "down") { |
|
|
roomTaken = glyphs.getSymbolWidth(noteSymbol) + 2; |
|
|
} else { |
|
|
dotshiftx = glyphs.getSymbolWidth(noteSymbol) + 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
var pp = elem.pitches.length; |
|
|
for (p = 0; p < elem.pitches.length; p++) { |
|
|
|
|
|
if (!nostem) { |
|
|
var flag; |
|
|
if ((dir === "down" && p !== 0) || (dir === "up" && p !== pp - 1)) { |
|
|
flag = null; |
|
|
} else { |
|
|
flag = chartable[(dir === "down") ? "dflags" : "uflags"][-durlog]; |
|
|
} |
|
|
} |
|
|
var c; |
|
|
if (elem.pitches[p].style) { |
|
|
c = chartable[elem.pitches[p].style][-durlog]; |
|
|
} else if (voice.isPercussion && this.percmap) { |
|
|
c = noteSymbol; |
|
|
var percHead = this.percmap[pitchesToPerc(elem.pitches[p])]; |
|
|
if (percHead && percHead.noteHead) { |
|
|
if (chartable[percHead.noteHead]) |
|
|
c = chartable[percHead.noteHead][-durlog]; |
|
|
} |
|
|
} else |
|
|
c = noteSymbol; |
|
|
|
|
|
|
|
|
elem.pitches[p].highestVert = elem.pitches[p].verticalPos; |
|
|
var isTopWhenStemIsDown = (stemdir === "up" || dir === "up") && p === 0; |
|
|
var isBottomWhenStemIsUp = (stemdir === "down" || dir === "down") && p === pp - 1; |
|
|
if (isTopWhenStemIsDown || isBottomWhenStemIsUp) { |
|
|
|
|
|
if (elem.startSlur || pp === 1) { |
|
|
elem.pitches[p].highestVert = elem.pitches[pp - 1].verticalPos; |
|
|
if (getDuration(elem) < 1 && (stemdir === "up" || dir === "up")) |
|
|
elem.pitches[p].highestVert += 6; |
|
|
} |
|
|
if (elem.startSlur) { |
|
|
if (!elem.pitches[p].startSlur) elem.pitches[p].startSlur = []; |
|
|
for (i = 0; i < elem.startSlur.length; i++) { |
|
|
addIfNotExist(elem.pitches[p].startSlur, elem.startSlur[i]); |
|
|
} |
|
|
} |
|
|
|
|
|
if (elem.endSlur) { |
|
|
elem.pitches[p].highestVert = elem.pitches[pp - 1].verticalPos; |
|
|
if (getDuration(elem) < 1 && (stemdir === "up" || dir === "up")) |
|
|
elem.pitches[p].highestVert += 6; |
|
|
if (!elem.pitches[p].endSlur) elem.pitches[p].endSlur = []; |
|
|
for (i = 0; i < elem.endSlur.length; i++) { |
|
|
addIfNotExist(elem.pitches[p].endSlur, elem.endSlur[i]); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
var hasStem = !nostem && durlog <= -1; |
|
|
var ret = createNoteHead(abselem, c, elem.pitches[p], |
|
|
{ dir: dir, extrax: -roomTaken, flag: flag, dot: dot, dotshiftx: dotshiftx, scale: this.voiceScale, accidentalSlot: accidentalSlot, shouldExtendStem: !stemdir, printAccidentals: !voice.isPercussion }); |
|
|
symbolWidth = Math.max(glyphs.getSymbolWidth(c), symbolWidth); |
|
|
abselem.extraw -= ret.extraLeft; |
|
|
noteHead = ret.notehead; |
|
|
if (noteHead) { |
|
|
this.addSlursAndTies(abselem, elem.pitches[p], noteHead, voice, hasStem ? dir : null, false); |
|
|
|
|
|
if (elem.gracenotes && elem.gracenotes.length > 0) |
|
|
noteHead.bottom = noteHead.bottom - 1; |
|
|
abselem.addHead(noteHead); |
|
|
} |
|
|
roomTaken += ret.accidentalshiftx; |
|
|
roomTakenRight = Math.max(roomTakenRight, ret.dotshiftx); |
|
|
} |
|
|
|
|
|
|
|
|
if (hasStem) { |
|
|
var stemHeight = Math.round(70 * this.voiceScale) / 10; |
|
|
var p1 = (dir === "down") ? elem.minpitch - stemHeight : elem.minpitch + 1 / 3; |
|
|
|
|
|
if (p1 > 6 && !stemdir) p1 = 6; |
|
|
var p2 = (dir === "down") ? elem.maxpitch - 1 / 3 : elem.maxpitch + stemHeight; |
|
|
|
|
|
if (p2 < 6 && !stemdir) p2 = 6; |
|
|
var dx = (dir === "down" || abselem.heads.length === 0) ? 0 : abselem.heads[0].w; |
|
|
var width = (dir === "down") ? 1 : -1; |
|
|
|
|
|
if (noteHead && noteHead.c === 'noteheads.slash.quarter') { |
|
|
if (dir === 'down') |
|
|
p2 -= 1; |
|
|
else |
|
|
p1 += 1; |
|
|
} |
|
|
if (noteHead && noteHead.c === 'noteheads.triangle.quarter') { |
|
|
if (dir === 'down') |
|
|
p2 -= 0.7; |
|
|
else |
|
|
p1 -= 1.2; |
|
|
} |
|
|
abselem.addRight(new RelativeElement(null, dx, 0, p1, { "type": "stem", "pitch2": p2, linewidth: width, bottom: p1 - 1 })); |
|
|
|
|
|
min = Math.min(p1, p2); |
|
|
} |
|
|
return { noteHead: noteHead, roomTaken: roomTaken, roomTakenRight: roomTakenRight, min: min, additionalLedgers: additionalLedgers, dir: dir, symbolWidth: symbolWidth }; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.addLyric = function (abselem, elem) { |
|
|
var lyricStr = ""; |
|
|
elem.lyric.forEach(function (ly) { |
|
|
var div = ly.divider === ' ' ? "" : ly.divider; |
|
|
lyricStr += ly.syllable + div + "\n"; |
|
|
}); |
|
|
var lyricDim = this.getTextSize.calc(lyricStr, 'vocalfont', "lyric"); |
|
|
var position = elem.positioning ? elem.positioning.vocalPosition : 'below'; |
|
|
abselem.addCentered(new RelativeElement(lyricStr, 0, lyricDim.width, undefined, { type: "lyric", position: position, height: lyricDim.height / spacing.STEP, dim: this.getTextSize.attr('vocalfont', "lyric") })); |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaff, voice) { |
|
|
var notehead = null; |
|
|
var roomtaken = 0; |
|
|
var roomtakenright = 0; |
|
|
var symbolWidth = 0; |
|
|
var additionalLedgers = []; |
|
|
|
|
|
var dir; |
|
|
|
|
|
var duration = getDuration(elem); |
|
|
var zeroDuration = false; |
|
|
if (duration === 0) { zeroDuration = true; duration = 0.25; nostem = true; } |
|
|
var durlog = Math.floor(Math.log(duration) / Math.log(2)); |
|
|
var dot = 0; |
|
|
|
|
|
for (var tot = Math.pow(2, durlog), inc = tot / 2; tot < duration; dot++, tot += inc, inc /= 2); |
|
|
|
|
|
|
|
|
if (elem.startTriplet) { |
|
|
this.tripletmultiplier = elem.tripletMultiplier; |
|
|
} |
|
|
|
|
|
var durationForSpacing = duration * this.tripletmultiplier; |
|
|
if (elem.rest && elem.rest.type === 'multimeasure') |
|
|
durationForSpacing = 1; |
|
|
if (elem.rest && elem.rest.type === 'invisible-multimeasure') |
|
|
durationForSpacing = this.measureLength * elem.rest.text; |
|
|
var absType = elem.rest ? "rest" : "note"; |
|
|
var abselem = new AbsoluteElement(elem, durationForSpacing, 1, absType, this.tuneNumber, { durationClassOveride: elem.duration * this.tripletmultiplier }); |
|
|
if (hint) abselem.setHint(); |
|
|
|
|
|
if (elem.rest) { |
|
|
if (this.measureLength === duration && elem.rest.type !== 'invisible' && elem.rest.type !== 'spacer' && elem.rest.type.indexOf('multimeasure') < 0) |
|
|
elem.rest.type = 'whole'; |
|
|
var ret1 = addRestToAbsElement(abselem, elem, duration, dot, voice.voicetotal > 1, this.stemdir, isSingleLineStaff, durlog, this.voiceScale); |
|
|
notehead = ret1.noteHead; |
|
|
roomtaken = ret1.roomTaken; |
|
|
roomtakenright = ret1.roomTakenRight; |
|
|
} else { |
|
|
var ret2 = this.addNoteToAbcElement(abselem, elem, dot, this.stemdir, this.style, zeroDuration, durlog, nostem, voice); |
|
|
if (ret2.min !== undefined) |
|
|
this.minY = Math.min(ret2.min, this.minY); |
|
|
notehead = ret2.noteHead; |
|
|
roomtaken = ret2.roomTaken; |
|
|
roomtakenright = ret2.roomTakenRight; |
|
|
additionalLedgers = ret2.additionalLedgers; |
|
|
dir = ret2.dir; |
|
|
symbolWidth = ret2.symbolWidth; |
|
|
} |
|
|
|
|
|
if (elem.lyric !== undefined) { |
|
|
this.addLyric(abselem, elem); |
|
|
} |
|
|
|
|
|
if (elem.gracenotes !== undefined) { |
|
|
roomtaken += this.addGraceNotes(elem, voice, abselem, notehead, this.stemHeight * this.voiceScale, this.isBagpipes, roomtaken); |
|
|
} |
|
|
|
|
|
if (elem.decoration) { |
|
|
|
|
|
|
|
|
var bottom = nostem && dir !== 'up' ? Math.min(-3, abselem.bottom - 6) : abselem.bottom |
|
|
this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, bottom, elem.positioning, this.hasVocals, this.accentAbove); |
|
|
} |
|
|
|
|
|
if (elem.barNumber) { |
|
|
abselem.addFixed(new RelativeElement(elem.barNumber, -10, 0, 0, { type: "barNumber" })); |
|
|
} |
|
|
|
|
|
|
|
|
ledgerLines(abselem, elem.minpitch, elem.maxpitch, elem.rest, symbolWidth, additionalLedgers, dir, -2, 1); |
|
|
|
|
|
if (elem.chord !== undefined) { |
|
|
var ret3 = addChord(this.getTextSize, abselem, elem, roomtaken, roomtakenright, symbolWidth, this.jazzchords, this.germanAlphabet); |
|
|
roomtaken = ret3.roomTaken; |
|
|
roomtakenright = ret3.roomTakenRight; |
|
|
} |
|
|
|
|
|
if (elem.startTriplet) { |
|
|
this.triplet = new TripletElem(elem.startTriplet, notehead, { flatBeams: this.flatBeams }); |
|
|
} |
|
|
|
|
|
if (elem.endTriplet && this.triplet) { |
|
|
this.triplet.setCloseAnchor(notehead); |
|
|
} |
|
|
|
|
|
if (this.triplet && !elem.startTriplet && !elem.endTriplet && !(elem.rest && elem.rest.type === "spacer")) { |
|
|
this.triplet.middleNote(notehead); |
|
|
} |
|
|
|
|
|
return abselem; |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.addSlursAndTies = function (abselem, pitchelem, notehead, voice, dir, isGrace) { |
|
|
if (pitchelem.endTie) { |
|
|
if (this.ties.length > 0) { |
|
|
|
|
|
var found = false; |
|
|
for (var j = 0; j < this.ties.length; j++) { |
|
|
if (this.ties[j].anchor1 && this.ties[j].anchor1.pitch === notehead.pitch) { |
|
|
this.ties[j].setEndAnchor(notehead); |
|
|
voice.setRange(this.ties[j]) |
|
|
this.ties.splice(j, 1); |
|
|
found = true; |
|
|
break; |
|
|
} |
|
|
} |
|
|
if (!found) { |
|
|
this.ties[0].setEndAnchor(notehead); |
|
|
voice.setRange(this.ties[0]) |
|
|
this.ties.splice(0, 1); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
var voiceNumber = voice.voicetotal < 2 ? -1 : voice.voicenumber; |
|
|
if (pitchelem.startTie) { |
|
|
var tie = new TieElem({ anchor1: notehead, force: (this.stemdir === "down" || this.stemdir === "up"), stemDir: this.stemdir, isGrace: isGrace, voiceNumber: voiceNumber, style: pitchelem.startTie.style }); |
|
|
if (hint) tie.setHint(); |
|
|
|
|
|
this.ties[this.ties.length] = tie; |
|
|
voice.addOther(tie); |
|
|
|
|
|
|
|
|
|
|
|
abselem.startTie = true; |
|
|
} |
|
|
|
|
|
var slur; |
|
|
var slurid; |
|
|
if (pitchelem.endSlur) { |
|
|
for (var i = 0; i < pitchelem.endSlur.length; i++) { |
|
|
slurid = pitchelem.endSlur[i]; |
|
|
if (this.slurs[slurid]) { |
|
|
slur = this.slurs[slurid]; |
|
|
slur.setEndAnchor(notehead); |
|
|
voice.setRange(slur) |
|
|
delete this.slurs[slurid]; |
|
|
} else { |
|
|
slur = new TieElem({ anchor2: notehead, stemDir: this.stemdir, voiceNumber: voiceNumber }); |
|
|
if (hint) slur.setHint(); |
|
|
voice.addOther(slur); |
|
|
} |
|
|
if (this.startlimitelem) { |
|
|
slur.setStartX(this.startlimitelem); |
|
|
} |
|
|
} |
|
|
} else if (!isGrace) { |
|
|
for (var s in this.slurs) { |
|
|
if (this.slurs.hasOwnProperty(s)) { |
|
|
this.slurs[s].addInternalNote(notehead); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (pitchelem.startSlur) { |
|
|
for (i = 0; i < pitchelem.startSlur.length; i++) { |
|
|
slurid = pitchelem.startSlur[i].label; |
|
|
slur = new TieElem({ anchor1: notehead, stemDir: this.stemdir, voiceNumber: voiceNumber, style: pitchelem.startSlur[i].style }); |
|
|
if (hint) slur.setHint(); |
|
|
this.slurs[slurid] = slur; |
|
|
voice.addOther(slur); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.addMeasureNumber = function (number, abselem) { |
|
|
var measureNumDim = this.getTextSize.calc(number, "measurefont", 'bar-number'); |
|
|
var dx = 0; |
|
|
if (abselem.isClef) |
|
|
dx += measureNumDim.width / 2 |
|
|
var vert = measureNumDim.width > 10 && abselem.abcelem.type === "treble" ? 13 : 11 |
|
|
abselem.addFixed(new RelativeElement(number, dx, measureNumDim.width, vert + measureNumDim.height / spacing.STEP, { type: "barNumber", dim: this.getTextSize.attr("measurefont", 'bar-number') })); |
|
|
}; |
|
|
|
|
|
AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff) { |
|
|
|
|
|
|
|
|
var abselem = new AbsoluteElement(elem, 0, 10, 'bar', this.tuneNumber); |
|
|
var anchor = null; |
|
|
var dx = 0; |
|
|
|
|
|
if (elem.barNumber) { |
|
|
this.addMeasureNumber(elem.barNumber, abselem); |
|
|
} |
|
|
|
|
|
|
|
|
var firstdots = (elem.type === "bar_right_repeat" || elem.type === "bar_dbl_repeat"); |
|
|
var firstthin = (elem.type !== "bar_left_repeat" && elem.type !== "bar_thick_thin" && elem.type !== "bar_invisible"); |
|
|
var thick = (elem.type === "bar_right_repeat" || elem.type === "bar_dbl_repeat" || elem.type === "bar_left_repeat" || |
|
|
elem.type === "bar_thin_thick" || elem.type === "bar_thick_thin"); |
|
|
var secondthin = (elem.type === "bar_left_repeat" || elem.type === "bar_thick_thin" || elem.type === "bar_thin_thin" || elem.type === "bar_dbl_repeat"); |
|
|
var seconddots = (elem.type === "bar_left_repeat" || elem.type === "bar_dbl_repeat"); |
|
|
|
|
|
|
|
|
if (firstdots || seconddots) { |
|
|
for (var slur in this.slurs) { |
|
|
if (this.slurs.hasOwnProperty(slur)) { |
|
|
this.slurs[slur].setEndX(abselem); |
|
|
} |
|
|
} |
|
|
this.startlimitelem = abselem; |
|
|
} |
|
|
|
|
|
if (firstdots) { |
|
|
abselem.addRight(new RelativeElement("dots.dot", dx, 1, 7)); |
|
|
abselem.addRight(new RelativeElement("dots.dot", dx, 1, 5)); |
|
|
dx += 6; |
|
|
} |
|
|
|
|
|
if (firstthin) { |
|
|
anchor = new RelativeElement(null, dx, 1, 2, { "type": "bar", "pitch2": 10, linewidth: 0.6 }); |
|
|
abselem.addRight(anchor); |
|
|
} |
|
|
|
|
|
if (elem.type === "bar_invisible") { |
|
|
anchor = new RelativeElement(null, dx, 1, 2, { "type": "none", "pitch2": 10, linewidth: 0.6 }); |
|
|
abselem.addRight(anchor); |
|
|
} |
|
|
|
|
|
if (elem.decoration) { |
|
|
this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals, this.accentAbove); |
|
|
} |
|
|
|
|
|
if (thick) { |
|
|
dx += 4; |
|
|
anchor = new RelativeElement(null, dx, 4, 2, { "type": "bar", "pitch2": 10, linewidth: 4 }); |
|
|
abselem.addRight(anchor); |
|
|
dx += 5; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.partstartelem && elem.endEnding) { |
|
|
this.partstartelem.anchor2 = anchor; |
|
|
this.partstartelem = null; |
|
|
} |
|
|
|
|
|
if (secondthin) { |
|
|
dx += 3; |
|
|
anchor = new RelativeElement(null, dx, 1, 2, { "type": "bar", "pitch2": 10, linewidth: 0.6 }); |
|
|
abselem.addRight(anchor); |
|
|
} |
|
|
|
|
|
if (seconddots) { |
|
|
dx += 3; |
|
|
abselem.addRight(new RelativeElement("dots.dot", dx, 1, 7)); |
|
|
abselem.addRight(new RelativeElement("dots.dot", dx, 1, 5)); |
|
|
} |
|
|
|
|
|
if (elem.startEnding && isFirstStaff) { |
|
|
var textWidth = this.getTextSize.calc(elem.startEnding, "repeatfont", '').width; |
|
|
abselem.minspacing += textWidth + 10; |
|
|
this.partstartelem = new EndingElem(elem.startEnding, anchor, null); |
|
|
voice.addOther(this.partstartelem); |
|
|
} |
|
|
|
|
|
|
|
|
abselem.extraw -= 5; |
|
|
|
|
|
if (elem.chord !== undefined) { |
|
|
var ret3 = addChord(this.getTextSize, abselem, elem, 0, 0, 0, false, this.germanAlphabet); |
|
|
} |
|
|
|
|
|
return abselem; |
|
|
|
|
|
}; |
|
|
|
|
|
module.exports = AbstractEngraver; |
|
|
|