|
|
|
|
|
var VoiceElement = require('../../write/creation/elements/voice-element'); |
|
|
var TabAbsoluteElements = require('./tab-absolute-elements'); |
|
|
var spacing = require('../../write/helpers/spacing'); |
|
|
|
|
|
function initSpecialY() { |
|
|
return { |
|
|
tempoHeightAbove: 0, |
|
|
partHeightAbove: 0, |
|
|
volumeHeightAbove: 0, |
|
|
dynamicHeightAbove: 0, |
|
|
endingHeightAbove: 0, |
|
|
chordHeightAbove: 0, |
|
|
lyricHeightAbove: 0, |
|
|
lyricHeightBelow: 0, |
|
|
chordHeightBelow: 0, |
|
|
volumeHeightBelow: 0, |
|
|
dynamicHeightBelow: 0 |
|
|
}; |
|
|
} |
|
|
|
|
|
function getLyricHeight(voice) { |
|
|
var maxLyricHeight = 0; |
|
|
for (var ii = 0; ii < voice.children.length; ii++) { |
|
|
var curAbs = voice.children[ii]; |
|
|
if (curAbs.specialY) { |
|
|
if (curAbs.specialY.lyricHeightBelow > maxLyricHeight) { |
|
|
maxLyricHeight = curAbs.specialY.lyricHeightBelow; |
|
|
} |
|
|
} |
|
|
} |
|
|
return maxLyricHeight; |
|
|
} |
|
|
|
|
|
function buildTabName(plugin, renderer, dest) { |
|
|
var stringSemantics = plugin.semantics; |
|
|
var textSize = renderer.controller.getTextSize; |
|
|
var tabName = stringSemantics.tabInfos(plugin); |
|
|
var suppress = stringSemantics.suppress(plugin); |
|
|
var doDraw = true; |
|
|
|
|
|
if (suppress) { |
|
|
doDraw = false |
|
|
} |
|
|
|
|
|
|
|
|
if (doDraw) { |
|
|
var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname'); |
|
|
dest.tabNameInfos = { |
|
|
textSize: { height: size.height, width: size.width }, |
|
|
name: tabName |
|
|
}; |
|
|
return size.height; |
|
|
} |
|
|
return 0 |
|
|
|
|
|
} |
|
|
|
|
|
function islastTabInStaff(index, staffGroup) { |
|
|
if (staffGroup[index].isTabStaff) { |
|
|
if (index === staffGroup.length - 1) return true; |
|
|
if (staffGroup[index + 1].isTabStaff) { |
|
|
return false; |
|
|
} else { |
|
|
return true; |
|
|
} |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
function getStaffNumbers(staffs) { |
|
|
var nbStaffs = 0; |
|
|
for (var ii = 0; ii < staffs.length; ii++) { |
|
|
if (!staffs[ii].isTabStaff) { |
|
|
nbStaffs++; |
|
|
} |
|
|
} |
|
|
return nbStaffs; |
|
|
} |
|
|
|
|
|
function getParentStaffIndex(staffs, index) { |
|
|
for (var ii = index; ii >= 0; ii--) { |
|
|
if (!staffs[ii].isTabStaff) { |
|
|
return ii; |
|
|
} |
|
|
} |
|
|
return -1; |
|
|
} |
|
|
|
|
|
|
|
|
function linkStaffAndTabs(staffs) { |
|
|
for (var ii = 0; ii < staffs.length; ii++) { |
|
|
if (staffs[ii].isTabStaff) { |
|
|
|
|
|
var parentIndex = getParentStaffIndex(staffs, ii); |
|
|
staffs[ii].hasStaff = staffs[parentIndex]; |
|
|
if (!staffs[parentIndex].hasTab) staffs[parentIndex].hasTab = []; |
|
|
staffs[parentIndex].hasTab.push(staffs[ii]); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
function isMultiVoiceSingleStaff(staffs, parent) { |
|
|
if (getStaffNumbers(staffs) === 1) { |
|
|
if (parent.voices.length > 1) return true; |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
function getNextTabPos(tabIndex, staffGroup) { |
|
|
var startIndex = 0; |
|
|
var handledVoices = 0; |
|
|
var inProgress = true; |
|
|
var nbVoices = 0; |
|
|
while (inProgress) { |
|
|
|
|
|
if (!staffGroup[startIndex]) |
|
|
return -1; |
|
|
if (!staffGroup[startIndex].isTabStaff) { |
|
|
nbVoices = staffGroup[startIndex].voices.length; |
|
|
} |
|
|
if (staffGroup[startIndex].isTabStaff) { |
|
|
handledVoices++; |
|
|
if (islastTabInStaff(startIndex, staffGroup)) { |
|
|
if (handledVoices < nbVoices) return startIndex + 1; |
|
|
} |
|
|
} else { |
|
|
handledVoices = 0; |
|
|
if (startIndex >= tabIndex) { |
|
|
if (startIndex + 1 == staffGroup.length) return startIndex + 1; |
|
|
if (!staffGroup[startIndex + 1].isTabStaff) return startIndex + 1; |
|
|
} |
|
|
} |
|
|
startIndex++; |
|
|
|
|
|
if (startIndex > staffGroup.length) return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
function getLastStaff(staffs, lastTab) { |
|
|
for (var ii = lastTab; ii >= 0; ii--) { |
|
|
if (!staffs[ii].isTabStaff) { |
|
|
return staffs[ii]; |
|
|
} |
|
|
} |
|
|
return null; |
|
|
} |
|
|
|
|
|
function checkVoiceKeySig(voices, ii) { |
|
|
var curVoice = voices[ii]; |
|
|
|
|
|
|
|
|
var elem0 = curVoice.children[0].abcelem; |
|
|
if (elem0.el_type === 'clef') return null; |
|
|
if (ii == 0) { |
|
|
|
|
|
return 'none'; |
|
|
} |
|
|
return voices[ii - 1].children[0]; |
|
|
} |
|
|
|
|
|
function tabRenderer(plugin, renderer, line, staffIndex) { |
|
|
|
|
|
var absolutes = new TabAbsoluteElements(); |
|
|
var tabStaff = { |
|
|
clef: { |
|
|
type: 'TAB' |
|
|
} |
|
|
}; |
|
|
var tabSize = (plugin.linePitch * plugin.nbLines); |
|
|
var staffs = line.staff; |
|
|
if (staffs) { |
|
|
|
|
|
var firstStaff = staffs[0]; |
|
|
if (firstStaff) { |
|
|
if (firstStaff.clef) { |
|
|
if (firstStaff.clef.stafflines == 0) { |
|
|
plugin.setError("No tablatures when stafflines=0"); |
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
|
staffs.splice( |
|
|
staffs.length, 0, |
|
|
tabStaff |
|
|
); |
|
|
} |
|
|
var staffGroup = line.staffGroup; |
|
|
|
|
|
var voices = staffGroup.voices; |
|
|
var firstVoice = voices[0]; |
|
|
|
|
|
var lyricsHeight = getLyricHeight(firstVoice); |
|
|
var padd = 3; |
|
|
var prevIndex = staffIndex; |
|
|
var previousStaff = staffGroup.staffs[prevIndex]; |
|
|
var tabTop = tabSize + padd - previousStaff.bottom - lyricsHeight; |
|
|
if (previousStaff.isTabStaff) { |
|
|
tabTop = previousStaff.top; |
|
|
} |
|
|
var staffGroupInfos = { |
|
|
bottom: -1, |
|
|
isTabStaff: true, |
|
|
specialY: initSpecialY(), |
|
|
lines: plugin.nbLines, |
|
|
linePitch: plugin.linePitch, |
|
|
dy: 0.15, |
|
|
top: tabTop, |
|
|
}; |
|
|
var nextTabPos = getNextTabPos(staffIndex, staffGroup.staffs); |
|
|
if (nextTabPos === -1) |
|
|
return; |
|
|
staffGroupInfos.parentIndex = nextTabPos - 1; |
|
|
staffGroup.staffs.splice(nextTabPos, 0, staffGroupInfos); |
|
|
|
|
|
staffGroup.height += tabSize + padd; |
|
|
var parentStaff = getLastStaff(staffGroup.staffs, nextTabPos); |
|
|
var nbVoices = 1; |
|
|
if (isMultiVoiceSingleStaff(staffGroup.staffs, parentStaff)) { |
|
|
nbVoices = parentStaff.voices.length; |
|
|
} |
|
|
|
|
|
tabStaff.voices = []; |
|
|
for (var ii = 0; ii < nbVoices; ii++) { |
|
|
var tabVoice = new VoiceElement(0, 0); |
|
|
if (ii > 0) tabVoice.duplicate = true; |
|
|
var nameHeight = buildTabName(plugin, renderer, tabVoice) / spacing.STEP; |
|
|
nameHeight = Math.max(nameHeight, 1) |
|
|
|
|
|
|
|
|
staffGroup.staffs[staffIndex].top += 1; |
|
|
staffGroup.height += nameHeight; |
|
|
tabVoice.staff = staffGroupInfos; |
|
|
var tabVoiceIndex = voices.length |
|
|
voices.splice(voices.length, 0, tabVoice); |
|
|
var keySig = checkVoiceKeySig(voices, ii + staffIndex); |
|
|
tabStaff.voices[ii] = []; |
|
|
absolutes.build(plugin, voices, tabStaff.voices[ii], ii, staffIndex, keySig, tabVoiceIndex); |
|
|
} |
|
|
linkStaffAndTabs(staffGroup.staffs); |
|
|
} |
|
|
|
|
|
module.exports = tabRenderer; |
|
|
|