Comparing version 6.2.3 to 6.3.0
@@ -60,2 +60,3 @@ /**! | ||
var getMidiFile = require('./src/synth/get-midi-file'); | ||
var midiRenderer = require('./src/synth/abc_midi_renderer'); | ||
@@ -75,2 +76,3 @@ abcjs.synth = { | ||
sequence: sequence, | ||
midiRenderer: midiRenderer, | ||
}; | ||
@@ -77,0 +79,0 @@ |
{ | ||
"name": "abcjs", | ||
"version": "6.2.3", | ||
"version": "6.3.0", | ||
"description": "Renderer for abc music notation", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -251,5 +251,5 @@ /**! | ||
var abcjs = { | ||
plugin: Plugin | ||
plugin: plugin | ||
}; | ||
module.exports = abcjs; |
@@ -13,2 +13,6 @@ ![abcjs](https://paulrosen.github.io/abcjs/img/abcjs_comp_extended_08.svg) | ||
## Announcement: version 6.3.0 | ||
Most users won't see any difference, but there was some changes to the underlying SVG structure for the top (the title, etc.) and bottom (the notes, etc.) text, so if your code depends on particular classes then this might be a breaking change. Hopefully the new structure will be clearer and will allow css to target particular parts easier. | ||
## Announcement: version 6.2.2 | ||
@@ -15,0 +19,0 @@ |
@@ -8,4 +8,3 @@ /* | ||
*/ | ||
var ViolinTablature = require('../tablatures/instruments/violin/tab-violin'); | ||
var GuitarTablature = require('../tablatures/instruments/guitar/tab-guitar'); | ||
var StringTablature = require('../tablatures/instruments/tab-string'); | ||
@@ -16,6 +15,7 @@ /* extend the table below when adding a new instrument plugin */ | ||
var pluginTab = { | ||
'violin': 'ViolinTab', | ||
'fiddle': 'ViolinTab', | ||
'mandolin': 'ViolinTab', | ||
'guitar': 'GuitarTab' | ||
'violin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0}, | ||
'fiddle': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0}, | ||
'mandolin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0}, | ||
'guitar': { name: 'StringTab', defaultTuning: ['E,', 'A,', 'D', 'G' , 'B' , 'e'], isTabBig: true, tabSymbolOffset: 0}, | ||
'fiveString': { name: 'StringTab', defaultTuning: ['C,', 'G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: -.95}, | ||
}; | ||
@@ -71,3 +71,3 @@ | ||
if (tabName) { | ||
plugin = this.plugins[tabName]; | ||
plugin = this.plugins[tabName.name]; | ||
} | ||
@@ -85,2 +85,3 @@ if (plugin) { | ||
instance: null, | ||
tabType: tabName, | ||
}; | ||
@@ -110,12 +111,46 @@ // proceed with tab plugin init | ||
*/ | ||
layoutTablatures: function (renderer, abcTune) { | ||
layoutTablatures: function layoutTablatures(renderer, abcTune) { | ||
var tabs = abcTune.tablatures; | ||
// chack tabs request for each staffs | ||
var staffLineCount = 0; | ||
// Clear the suppression flag | ||
if (tabs && (tabs.length > 0)){ | ||
var nTabs = tabs.length; | ||
for (var kk=0;kk<nTabs;++kk){ | ||
if (tabs[kk] && tabs[kk].params.firstStaffOnly){ | ||
tabs[kk].params.suppress = false; | ||
} | ||
} | ||
} | ||
for (var ii = 0; ii < abcTune.lines.length; ii++) { | ||
var line = abcTune.lines[ii]; | ||
if (line.staff){ | ||
staffLineCount++; | ||
} | ||
// MAE 27Nov2023 | ||
// If tab param "firstStaffOnly", remove the tab label after the first staff | ||
if (staffLineCount > 1){ | ||
if (tabs && (tabs.length > 0)){ | ||
var nTabs = tabs.length; | ||
for (var kk=0;kk<nTabs;++kk){ | ||
if (tabs[kk].params.firstStaffOnly){ | ||
// Set the staff draw suppression flag | ||
tabs[kk].params.suppress = true; | ||
} | ||
} | ||
} | ||
} | ||
var curStaff = line.staff; | ||
if (curStaff) { | ||
var maxStaves = curStaff.length | ||
for (var jj = 0; jj < curStaff.length; jj++) { | ||
if (tabs[jj]) { | ||
// tablature requested for staff | ||
if (tabs[jj] && jj < maxStaves) { | ||
// tablature requested for staff | ||
var tabPlugin = tabs[jj]; | ||
@@ -129,3 +164,4 @@ if (tabPlugin.instance == null) { | ||
tabPlugin.params, | ||
jj | ||
jj, | ||
tabPlugin.tabType | ||
); | ||
@@ -147,4 +183,3 @@ } | ||
if (!this.inited) { | ||
this.register(new ViolinTablature()); | ||
this.register(new GuitarTablature()); | ||
this.register(new StringTablature()); | ||
this.inited = true; | ||
@@ -151,0 +186,0 @@ } |
@@ -687,23 +687,23 @@ var parseCommon = require('./abc_common'); | ||
parseDirective.parseFontChangeLine = function(textstr) { | ||
// We don't want to match two dollar signs, so change those temporarily | ||
textstr = textstr.replace(/\$\$/g,"\x03") | ||
var textParts = textstr.split('$'); | ||
if (textParts.length > 1 && multilineVars.setfont) { | ||
var textarr = [ { text: textParts[0] }]; | ||
var textarr = [ ]; | ||
if (textParts[0] !== '') // did the original string start with `$`? | ||
textarr.push({ text: textParts[0] }) | ||
for (var i = 1; i < textParts.length; i++) { | ||
if (textParts[i][0] === '0') | ||
textarr.push({ text: textParts[i].substring(1) }); | ||
else if (textParts[i][0] === '1' && multilineVars.setfont[1]) | ||
textarr.push({font: multilineVars.setfont[1], text: textParts[i].substring(1) }); | ||
else if (textParts[i][0] === '2' && multilineVars.setfont[2]) | ||
textarr.push({font: multilineVars.setfont[2], text: textParts[i].substring(1) }); | ||
else if (textParts[i][0] === '3' && multilineVars.setfont[3]) | ||
textarr.push({font: multilineVars.setfont[3], text: textParts[i].substring(1) }); | ||
else if (textParts[i][0] === '4' && multilineVars.setfont[4]) | ||
textarr.push({font: multilineVars.setfont[4], text: textParts[i].substring(1) }); | ||
else | ||
textarr[textarr.length-1].text += '$' + textParts[i]; | ||
textarr.push({ text: textParts[i].substring(1).replace(/\x03/g,"$$") }); | ||
else { | ||
var whichFont = parseInt(textParts[i][0],10) | ||
if (multilineVars.setfont[whichFont]) | ||
textarr.push({font: multilineVars.setfont[whichFont], text: textParts[i].substring(1).replace(/\x03/g,"$$") }); | ||
else | ||
textarr[textarr.length-1].text += '$' + textParts[i].replace(/\x03/g,"$$"); | ||
} | ||
} | ||
if (textarr.length > 1) | ||
return textarr; | ||
return textarr; | ||
} | ||
return textstr; | ||
return textstr.replace(/\x03/g,"$$"); | ||
}; | ||
@@ -752,2 +752,3 @@ | ||
case "jazzchords":tune.formatting.jazzchords = true;break; | ||
case "accentAbove":tune.formatting.accentAbove = true;break; | ||
case "germanAlphabet":tune.formatting.germanAlphabet = true;break; | ||
@@ -944,3 +945,3 @@ case "landscape":multilineVars.landscape = true;break; | ||
var sfNum = parseInt(sfTokens[1].token); | ||
if (sfNum >= 1 && sfNum <= 4) { | ||
if (sfNum >= 1 && sfNum <= 9) { | ||
if (!multilineVars.setfont) | ||
@@ -947,0 +948,0 @@ multilineVars.setfont = []; |
@@ -14,11 +14,8 @@ // abc_parse_header.js: parses a the header fields from a string representing ABC Music Notation into a usable internal structure. | ||
this.setTitle = function(title) { | ||
this.setTitle = function(title, origSize) { | ||
if (multilineVars.hasMainTitle) | ||
tuneBuilder.addSubtitle(tokenizer.translateString(tokenizer.stripComment(title)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2}); // display secondary title | ||
tuneBuilder.addSubtitle(title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2}); // display secondary title | ||
else | ||
{ | ||
var titleStr = tokenizer.translateString(tokenizer.theReverser(tokenizer.stripComment(title))); | ||
if (multilineVars.titlecaps) | ||
titleStr = titleStr.toUpperCase(); | ||
tuneBuilder.addMetaText("title", titleStr, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2}); | ||
tuneBuilder.addMetaText("title", title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2}); | ||
multilineVars.hasMainTitle = true; | ||
@@ -375,6 +372,7 @@ } | ||
case "[P:": | ||
var part = parseDirective.parseFontChangeLine(line.substring(i+3, e)) | ||
if (startLine || tune.lines.length <= tune.lineNum) | ||
multilineVars.partForNextLine = { title: line.substring(i+3, e), startChar: startChar, endChar: endChar }; | ||
multilineVars.partForNextLine = { title: part, startChar: startChar, endChar: endChar }; | ||
else | ||
tuneBuilder.appendElement('part', startChar, endChar, {title: line.substring(i+3, e)}); | ||
tuneBuilder.appendElement('part', startChar, endChar, {title: part}); | ||
return [ e-i+1+ws ]; | ||
@@ -482,8 +480,10 @@ case "[L:": | ||
var field = metaTextHeaders[line[0]]; | ||
if (field !== undefined) { | ||
if (field === 'unalignedWords') | ||
tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line.substring(2)))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
else | ||
tuneBuilder.addMetaText(field, tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
return {}; | ||
var origSize = line.length-2 | ||
var restOfLine = tokenizer.translateString(tokenizer.stripComment(line.substring(2))) | ||
if (field === 'unalignedWords' || field === 'notes') { | ||
// These fields can be multi-line | ||
tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
} else if (field !== undefined) { | ||
// these fields are single line | ||
tuneBuilder.addMetaText(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
} else { | ||
@@ -495,7 +495,8 @@ var startChar = multilineVars.iChar; | ||
case 'H': | ||
tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
// History is a little different because once it starts it continues until another header field is encountered | ||
tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
line = tokenizer.peekLine() | ||
while (line && line[1] !== ':') { | ||
tokenizer.nextLine() | ||
tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
line = tokenizer.peekLine() | ||
@@ -525,5 +526,5 @@ } | ||
if (multilineVars.is_in_header) | ||
tuneBuilder.addMetaText("partOrder", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
tuneBuilder.addMetaText("partOrder", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length}); | ||
else | ||
multilineVars.partForNextLine = { title: tokenizer.translateString(tokenizer.stripComment(line.substring(2))), startChar: startChar, endChar: endChar}; | ||
multilineVars.partForNextLine = { title: restOfLine, startChar: startChar, endChar: endChar}; | ||
break; | ||
@@ -541,3 +542,5 @@ case 'Q': | ||
case 'T': | ||
this.setTitle(line.substring(2)); | ||
if (multilineVars.titlecaps) | ||
restOfLine = restOfLine.toUpperCase(); | ||
this.setTitle(parseDirective.parseFontChangeLine(tokenizer.theReverser(restOfLine)), origSize); | ||
break; | ||
@@ -544,0 +547,0 @@ case 'U': |
@@ -642,10 +642,75 @@ // abc_tokenizer.js: tokenizes an ABC Music Notation string to support abc_parse. | ||
this.theReverser = function(str) { | ||
if (parseCommon.endsWith(str, ", The")) | ||
return "The " + str.substring(0, str.length-5); | ||
if (parseCommon.endsWith(str, ", A")) | ||
return "A " + str.substring(0, str.length-3); | ||
return str; | ||
}; | ||
// | ||
// MAE 10 Jan 2023 - For better handling of tunes that have tune numbers in front of them. | ||
// | ||
// Previous version would take: | ||
// 21. Woman of the House, The | ||
// and return: | ||
// The 21. Woman of the House | ||
// | ||
// This fix results in: | ||
// 21. The Woman of the House | ||
// | ||
// Also added additional checks and handlers for lower case ", the" and ", a" since I found several tune collections with those tune name constructs | ||
// | ||
// Find an optional title number at the start of a tune title | ||
function getTitleNumber(str){ | ||
const regex = /^(\d+)\./; | ||
// Use the exec method to search for the pattern in the string | ||
const match = regex.exec(str); | ||
// Check if a match is found | ||
if (match) { | ||
// The matched number is captured in the first group (index 1) | ||
const foundNumber = match[1]; | ||
return foundNumber; | ||
} else { | ||
// Return null if no match is found | ||
return null; | ||
} | ||
} | ||
var thePatterns = [ | ||
{ match: /,\s*[Tt]he$/, replace: "The " }, | ||
{ match: /,\s*[Aa]$/, replace: "A " }, | ||
{ match: /,\s*[Aa]n$/, replace: "An " }, | ||
] | ||
this.theReverser = function (str) { | ||
for (var i = 0; i < thePatterns.length; i++) { | ||
var thisPattern = thePatterns[i] | ||
var match = str.match(thisPattern.match) | ||
if (match) { | ||
var theTitleNumber = getTitleNumber(str); | ||
if (theTitleNumber){ | ||
//console.log("theReverser The titlenumber:"+theTitleNumber); | ||
str = str.replace(theTitleNumber+".",""); | ||
str = str.trim(); | ||
} | ||
var len = match[0].length | ||
var result = thisPattern.replace + str.substring(0, str.length - len); | ||
if (theTitleNumber){ | ||
result = theTitleNumber+". "+result; | ||
} | ||
return result; | ||
} | ||
} | ||
return str; | ||
}; | ||
this.stripComment = function(str) { | ||
@@ -652,0 +717,0 @@ var i = str.indexOf('%'); |
var parseKeyVoice = require('../parse/abc_parse_key_voice'); | ||
var parseCommon = require('../parse/abc_common'); | ||
var parseDirective = require('./abc_parse_directive'); | ||
@@ -150,2 +151,5 @@ var TuneBuilder = function(tune) { | ||
simplifyMetaText(tune) | ||
//addRichTextToAnnotationsAndLyrics(tune) | ||
// If the tempo was created with a string like "Allegro", then the duration of a beat needs to be set at the last moment, when it is most likely known. | ||
@@ -882,3 +886,11 @@ if (tune.metaText.tempo && tune.metaText.tempo.bpm && !tune.metaText.tempo.duration) | ||
} else { | ||
tune.metaText[key] += "\n" + value; | ||
if (typeof tune.metaText[key] === 'string' && typeof value === 'string') | ||
tune.metaText[key] += "\n" + value; | ||
else { | ||
if (tune.metaText[key] === 'string') | ||
tune.metaText[key] = [{text: tune.metaText[key]}] | ||
if (typeof value === 'string') | ||
value = [{text: value}] | ||
tune.metaText[key] =tune.metaText[key].concat(value) | ||
} | ||
tune.metaTextInfo[key].endChar = info.endChar; | ||
@@ -903,2 +915,49 @@ } | ||
function isArrayOfStrings(arr) { | ||
if (!arr) return false | ||
if (typeof arr === "string") return false | ||
var str = '' | ||
for (var i = 0; i < arr.length; i++) { | ||
if (typeof arr[i] !== 'string') | ||
return false | ||
} | ||
return true | ||
} | ||
function simplifyMetaText(tune) { | ||
if (isArrayOfStrings(tune.metaText.notes)) | ||
tune.metaText.notes = tune.metaText.notes.join("\n") | ||
if (isArrayOfStrings(tune.metaText.history)) | ||
tune.metaText.history = tune.metaText.history.join("\n") | ||
} | ||
function addRichTextToAnnotationsAndLyrics(tune) { | ||
var lines = tune.lines | ||
for (var i = 0; i < lines.length; i++) { | ||
if (lines[i].staff !== undefined) { | ||
for (var s = 0; s < lines[i].staff.length; s++) { | ||
for (var v = 0; v < lines[i].staff[s].voices.length; v++) { | ||
var voice = lines[i].staff[s].voices[v]; | ||
for (var n = 0; n < voice.length; n++) { | ||
var element = voice[n] | ||
if (element.chord) { | ||
for (var c = 0; c < element.chord.length; c++) { | ||
element.chord[c].name = parseDirective.parseFontChangeLine(element.chord[c].name) | ||
console.log(element.chord[c].name) | ||
} | ||
} | ||
if (element.lyric) { | ||
for (var l = 0; l < element.lyric.length; l++) { | ||
element.lyric[l].syllable = parseDirective.parseFontChangeLine(element.lyric[l].syllable) | ||
console.log(element.lyric[l].syllable) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
module.exports = TuneBuilder; |
@@ -24,2 +24,6 @@ var CreateSynthControl = require('./create-synth-control'); | ||
visualOptions = {}; | ||
if (visualOptions.displayPlay === undefined) | ||
visualOptions.displayPlay = true | ||
if (visualOptions.displayProgress === undefined) | ||
visualOptions.displayProgress = true | ||
self.control = new CreateSynthControl(selector, { | ||
@@ -45,3 +49,3 @@ loopHandler: visualOptions.displayLoop ? self.toggleLoop : undefined, | ||
self.disable(false); | ||
self.options = audioParams; | ||
self.options = audioParams ? audioParams : {}; | ||
@@ -200,3 +204,3 @@ if (self.control) { | ||
var background = (ev.target.classList.contains('abcjs-midi-progress-indicator')) ? ev.target.parentNode : ev.target; | ||
var percent = (ev.x - background.offsetLeft) / background.offsetWidth; | ||
var percent = (ev.x - background.getBoundingClientRect().left) / background.offsetWidth; | ||
if (percent < 0) | ||
@@ -203,0 +207,0 @@ percent = 0; |
@@ -268,2 +268,13 @@ const {noteToMidi} = require('../../synth/note-to-midi'); | ||
// MAE 27 Nov 2023 | ||
StringPatterns.prototype.suppress = function (plugin) { | ||
var _super = plugin._super; | ||
var suppress = _super.params.suppress; | ||
if (suppress){ | ||
return true; | ||
} | ||
return false; | ||
}; | ||
// MAE 27 Nov 2023 End | ||
/** | ||
@@ -270,0 +281,0 @@ * Common patterns for all string instruments |
@@ -63,9 +63,18 @@ /** | ||
}; | ||
var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0); | ||
tabAbsolute.x = absX; | ||
var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab"); | ||
tabRelative.x = relX; | ||
tabAbsolute.children.push(tabRelative); | ||
if (tabAbsolute.abcelem.el_type == 'tab') { | ||
tabRelative.pitch = tabYPos; | ||
// Offset the TAB symbol position if specified in the tab description | ||
tabYPos += plugin.tabSymbolOffset; | ||
// For tablature like whistle tab where you want the TAB symbol hidden | ||
if (!plugin.hideTabSymbol){ | ||
var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0); | ||
tabAbsolute.x = absX; | ||
var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab"); | ||
tabRelative.x = relX; | ||
tabAbsolute.children.push(tabRelative); | ||
if (tabAbsolute.abcelem.el_type == 'tab') { | ||
tabRelative.pitch = tabYPos; | ||
} | ||
} | ||
@@ -72,0 +81,0 @@ return tabAbsolute; |
@@ -40,8 +40,20 @@ /* eslint-disable no-debugger */ | ||
var tabName = stringSemantics.tabInfos(self.plugin); | ||
var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname'); | ||
dest.tabNameInfos = { | ||
textSize: size, | ||
name: tabName | ||
}; | ||
return size.height; | ||
var suppress = stringSemantics.suppress(self.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 | ||
} | ||
@@ -234,4 +246,6 @@ | ||
nameHeight = Math.max(nameHeight, 1) // If there is no label for the tab line, then there needs to be a little padding | ||
staffGroup.staffs[this.staffIndex].top += nameHeight; | ||
staffGroup.height += nameHeight * spacing.STEP; | ||
// This was pushing down the top staff by the tab label height | ||
//staffGroup.staffs[this.staffIndex].top += nameHeight; | ||
staffGroup.staffs[this.staffIndex].top += 1; | ||
staffGroup.height += nameHeight; | ||
tabVoice.staff = staffGroupInfos; | ||
@@ -247,3 +261,2 @@ var tabVoiceIndex = voices.length | ||
module.exports = TabRenderer; |
@@ -54,15 +54,15 @@ // abc_parser_lint.js: Analyzes the output of abc_parse. | ||
var { legalAccents } = require('../parse/abc_parse_settings'); | ||
var ParserLint = function() { | ||
"use strict"; | ||
var decorationList = { type: 'array', optional: true, items: { type: 'string', Enum: [ | ||
"trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent", | ||
"fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge", | ||
"open", "thumb", "snap", "turn", "roll", "irishroll", "breath", "shortphrase", "mediumphrase", "longphrase", | ||
"segno", "coda", "D.S.", "D.C.", "fine", "crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)", | ||
"p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz", "repeatbar", "repeatbar2", "slide", | ||
"upbow", "downbow", "staccato", "trem1", "trem2", "trem3", "trem4", | ||
"/", "//", "///", "////", "turnx", "invertedturn", "invertedturnx", "arpeggio", "trill(", "trill)", "xstem", | ||
"mark", "marcato", "umarcato", "D.C.alcoda", "D.C.alfine", "D.S.alcoda", "D.S.alfine", "editorial", "courtesy" | ||
] } }; | ||
var ParserLint = function () { | ||
'use strict'; | ||
var decorationList = { | ||
type: 'array', | ||
optional: true, | ||
items: { | ||
type: 'string', | ||
Enum: legalAccents | ||
} | ||
}; | ||
var tempoProperties = { | ||
@@ -431,2 +431,3 @@ duration: { type: "array", optional: true, output: "join", requires: [ 'bpm'], items: { type: "number"} }, | ||
properties: { | ||
accentAbove: { type: "boolean", optional: true }, | ||
alignbars: { type: "number", optional: true }, | ||
@@ -433,0 +434,0 @@ aligncomposer: { type: "string", Enum: [ 'left', 'center','right' ], optional: true }, |
@@ -56,2 +56,3 @@ // abc_abstract_engraver.js: Creates a data structure suitable for printing a line of abc | ||
this.jazzchords = !!options.jazzchords | ||
this.accentAbove = !!options.accentAbove | ||
this.germanAlphabet = !!options.germanAlphabet | ||
@@ -834,3 +835,3 @@ this.reset(); | ||
if (elem.decoration) { | ||
this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals); | ||
this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals, this.accentAbove); | ||
} | ||
@@ -994,3 +995,3 @@ | ||
if (elem.decoration) { | ||
this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals); | ||
this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals, this.accentAbove); | ||
} | ||
@@ -997,0 +998,0 @@ |
@@ -9,95 +9,115 @@ var RelativeElement = require('./elements/relative-element'); | ||
var rel_position = elem.chord[i].rel_position; | ||
var chords = elem.chord[i].name.split("\n"); | ||
for (var j = chords.length - 1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top. | ||
var chord = chords[j]; | ||
var x = 0; | ||
var y; | ||
var font; | ||
var klass; | ||
if (pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position) { | ||
font = 'annotationfont'; | ||
klass = "annotation"; | ||
} else { | ||
font = 'gchordfont'; | ||
klass = "chord"; | ||
chord = translateChord(chord, jazzchords, germanAlphabet); | ||
var isAnnotation = pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position | ||
var font; | ||
var klass; | ||
if (isAnnotation) { | ||
font = 'annotationfont'; | ||
klass = "abcjs-annotation"; | ||
} else { | ||
font = 'gchordfont'; | ||
klass = "abcjs-chord"; | ||
} | ||
var attr = getTextSize.attr(font, klass); | ||
var name = elem.chord[i].name | ||
var ret; | ||
//console.log("chord",name) | ||
if (typeof name === "string") { | ||
ret = chordString(name, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet) | ||
roomTaken = ret.roomTaken | ||
roomTakenRight = ret.roomTakenRight | ||
} else { | ||
for (var j = 0; j < name.length; j++) { | ||
ret = chordString(name[j].text, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet) | ||
roomTaken = ret.roomTaken | ||
roomTakenRight = ret.roomTakenRight | ||
} | ||
var attr = getTextSize.attr(font, klass); | ||
var dim = getTextSize.calc(chord, font, klass); | ||
var chordWidth = dim.width; | ||
var chordHeight = dim.height / spacing.STEP; | ||
switch (pos) { | ||
case "left": | ||
roomTaken += chordWidth + 7; | ||
x = -roomTaken; // TODO-PER: This is just a guess from trial and error | ||
y = elem.averagepitch; | ||
abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, { | ||
} | ||
} | ||
return { roomTaken: roomTaken, roomTakenRight: roomTakenRight }; | ||
}; | ||
function chordString(chordString, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet) { | ||
var chords = chordString.split("\n"); | ||
for (var j = chords.length - 1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top. | ||
var chord = chords[j]; | ||
var x = 0; | ||
var y; | ||
if (!isAnnotation) | ||
chord = translateChord(chord, jazzchords, germanAlphabet); | ||
var dim = getTextSize.calc(chord, font, klass); | ||
var chordWidth = dim.width; | ||
var chordHeight = dim.height / spacing.STEP; | ||
switch (pos) { | ||
case "left": | ||
roomTaken += chordWidth + 7; | ||
x = -roomTaken; // TODO-PER: This is just a guess from trial and error | ||
y = elem.averagepitch; | ||
abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, { | ||
type: "text", | ||
height: chordHeight, | ||
dim: attr, | ||
position: "left" | ||
})); | ||
break; | ||
case "right": | ||
roomTakenRight += 4; | ||
x = roomTakenRight;// TODO-PER: This is just a guess from trial and error | ||
y = elem.averagepitch; | ||
abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, { | ||
type: "text", | ||
height: chordHeight, | ||
dim: attr, | ||
position: "right" | ||
})); | ||
break; | ||
case "below": | ||
// setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is. | ||
abselem.addRight(new RelativeElement(chord, 0, 0, undefined, { | ||
type: "text", | ||
position: "below", | ||
height: chordHeight, | ||
dim: attr, | ||
realWidth: chordWidth | ||
})); | ||
break; | ||
case "above": | ||
// setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is. | ||
abselem.addRight(new RelativeElement(chord, 0, 0, undefined, { | ||
type: "text", | ||
position: "above", | ||
height: chordHeight, | ||
dim: attr, | ||
realWidth: chordWidth | ||
})); | ||
break; | ||
default: | ||
if (rel_position) { | ||
var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps | ||
abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, { | ||
position: "relative", | ||
type: "text", | ||
height: chordHeight, | ||
dim: attr, | ||
position: "left" | ||
dim: attr | ||
})); | ||
break; | ||
case "right": | ||
roomTakenRight += 4; | ||
x = roomTakenRight;// TODO-PER: This is just a guess from trial and error | ||
y = elem.averagepitch; | ||
abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, { | ||
type: "text", | ||
height: chordHeight, | ||
dim: attr, | ||
position: "right" | ||
})); | ||
break; | ||
case "below": | ||
} else { | ||
// setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is. | ||
abselem.addRight(new RelativeElement(chord, 0, 0, undefined, { | ||
type: "text", | ||
position: "below", | ||
height: chordHeight, | ||
dim: attr, | ||
realWidth: chordWidth | ||
})); | ||
break; | ||
case "above": | ||
// setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is. | ||
abselem.addRight(new RelativeElement(chord, 0, 0, undefined, { | ||
type: "text", | ||
position: "above", | ||
height: chordHeight, | ||
dim: attr, | ||
realWidth: chordWidth | ||
})); | ||
break; | ||
default: | ||
if (rel_position) { | ||
var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps | ||
abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, { | ||
position: "relative", | ||
type: "text", | ||
var pos2 = 'above'; | ||
if (elem.positioning && elem.positioning.chordPosition) | ||
pos2 = elem.positioning.chordPosition; | ||
if (pos2 !== 'hidden') { | ||
abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, { | ||
type: "chord", | ||
position: pos2, | ||
height: chordHeight, | ||
dim: attr | ||
dim: attr, | ||
realWidth: chordWidth | ||
})); | ||
} else { | ||
// setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is. | ||
var pos2 = 'above'; | ||
if (elem.positioning && elem.positioning.chordPosition) | ||
pos2 = elem.positioning.chordPosition; | ||
if (pos2 !== 'hidden') { | ||
abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, { | ||
type: "chord", | ||
position: pos2, | ||
height: chordHeight, | ||
dim: attr, | ||
realWidth: chordWidth | ||
})); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return { roomTaken: roomTaken, roomTakenRight: roomTakenRight }; | ||
}; | ||
} | ||
module.exports = addChord; |
@@ -11,6 +11,6 @@ function addTextIf(rows, params, getTextSize) { | ||
rows.push({ move: params.marginTop }); | ||
var attr = { left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar }; | ||
var attr = { left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar, 'dominant-baseline': params['dominant-baseline'] }; | ||
if (params.absElemType) | ||
attr.absElemType = params.absElemType; | ||
if (!params.inGroup) | ||
if (!params.inGroup && params.klass) | ||
attr.klass = params.klass; | ||
@@ -17,0 +17,0 @@ if (params.name) |
@@ -17,6 +17,6 @@ // abc_decoration.js: Creates a data structure suitable for printing a line of abc | ||
var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch) { | ||
var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove) { | ||
var yPos; | ||
for (var i = 0; i < decoration.length; i++) { | ||
if (decoration[i] === "staccato" || decoration[i] === "tenuto" || decoration[i] === "accent") { | ||
if (decoration[i] === "staccato" || decoration[i] === "tenuto" || (decoration[i] === "accent" && !accentAbove)) { | ||
var symbol = "scripts." + decoration[i]; | ||
@@ -127,3 +127,3 @@ if (decoration[i] === "accent") symbol = "scripts.sforzato"; | ||
var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom) { | ||
var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom, accentAbove) { | ||
function incrementPlacement(placement, height) { | ||
@@ -268,2 +268,8 @@ if (placement === 'above') | ||
break; | ||
case "accent": | ||
if (accentAbove) { | ||
symbolDecoration("scripts.sforzato", positioning); | ||
hasOne = true; | ||
} | ||
break; | ||
} | ||
@@ -342,3 +348,3 @@ } | ||
Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) { | ||
Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals, accentAbove) { | ||
if (!positioning) | ||
@@ -352,10 +358,10 @@ positioning = { ornamentPosition: 'above', volumePosition: hasVocals ? 'above' : 'below', dynamicPosition: hasVocals ? 'above' : 'below' }; | ||
// treat staccato, accent, and tenuto first (may need to shift other markers) | ||
var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch); | ||
var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove); | ||
// yPos is an object containing 'above' and 'below'. That is the placement of the next symbol on either side. | ||
yPos.above = Math.max(yPos.above, this.minTop); | ||
var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom); | ||
if (hasOne) { | ||
var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom, accentAbove); | ||
//if (hasOne) { | ||
// abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor. | ||
} | ||
//} | ||
leftDecoration(decoration, abselem, roomtaken); | ||
@@ -362,0 +368,0 @@ }; |
const addTextIf = require("../add-text-if"); | ||
const richText = require("./rich-text"); | ||
function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize) { | ||
function BottomText(metaText, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) { | ||
this.rows = []; | ||
if (metaText.unalignedWords && metaText.unalignedWords.length > 0) | ||
this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, getTextSize); | ||
this.extraText(metaText, paddingLeft, spacing, getTextSize); | ||
this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, shouldAddClasses, getTextSize); | ||
this.extraText(metaText, paddingLeft, spacing, shouldAddClasses, getTextSize); | ||
if (metaText.footer && isPrint) | ||
@@ -12,56 +13,70 @@ this.footer(metaText.footer, width, paddingLeft, getTextSize); | ||
BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spacing, getTextSize) { | ||
var klass = 'meta-bottom unaligned-words'; | ||
BottomText.prototype.unalignedWords = function (unalignedWords, marginLeft, spacing, shouldAddClasses, getTextSize) { | ||
var klass = shouldAddClasses ? 'abcjs-unaligned-words' : '' | ||
var defFont = 'wordsfont'; | ||
this.rows.push({ startGroup: "unalignedWords", klass: 'abcjs-meta-bottom abcjs-unaligned-words', name: "words" }); | ||
var space = getTextSize.calc("i", defFont, klass); | ||
this.rows.push({ move: spacing.words }); | ||
addMultiLine(this.rows, '', unalignedWords, marginLeft, defFont, "unalignedWords", "unalignedWords", klass, "unalignedWords", spacing, shouldAddClasses, getTextSize) | ||
this.rows.push({ move: space.height }); | ||
} | ||
for (var j = 0; j < unalignedWords.length; j++) { | ||
if (unalignedWords[j] === '') | ||
this.rows.push({ move: space.height }); | ||
else if (typeof unalignedWords[j] === 'string') { | ||
addTextIf(this.rows, { marginLeft: paddingLeft, text: unalignedWords[j], font: defFont, klass: klass, inGroup: true, name: "words" }, getTextSize); | ||
function addSingleLine(rows, preface, text, marginLeft, klass, shouldAddClasses, getTextSize) { | ||
if (text) { | ||
if (preface) { | ||
if (typeof text === 'string') | ||
text = preface + text | ||
else | ||
text = [{text: preface}].concat(text) | ||
} | ||
klass = shouldAddClasses ? 'abcjs-extra-text '+klass : '' | ||
richText(rows, text, 'historyfont', klass, "description", marginLeft, {absElemType: "extraText", anchor: 'start'}, getTextSize) | ||
} | ||
} | ||
function addMultiLine(rows, preface, content, marginLeft, defFont, absElemType, groupName, klass, name, spacing, shouldAddClasses, getTextSize) { | ||
if (content) { | ||
klass = shouldAddClasses ? 'abcjs-extra-text '+klass : '' | ||
var size = getTextSize.calc("A", defFont, klass); | ||
if (typeof content === 'string') { | ||
if (preface) | ||
content = preface + "\n" + content | ||
addTextIf(rows, { marginLeft: marginLeft, text: content, font: defFont, absElemType: "extraText", name: name, 'dominant-baseline': 'middle', klass: klass }, getTextSize); | ||
//rows.push({move: size.height*3/4}) | ||
} else { | ||
var largestY = 0; | ||
var offsetX = 0; | ||
for (var k = 0; k < unalignedWords[j].length; k++) { | ||
var thisWord = unalignedWords[j][k]; | ||
var font = (thisWord.font) ? thisWord.font : defFont; | ||
this.rows.push({ | ||
left: paddingLeft + offsetX, | ||
text: thisWord.text, | ||
font: font, | ||
anchor: 'start' | ||
}); | ||
var size = getTextSize.calc(thisWord.text, defFont, klass); | ||
largestY = Math.max(largestY, size.height); | ||
offsetX += size.width; | ||
// If the phrase ends in a space, then that is not counted in the width, so we need to add that in ourselves. | ||
if (thisWord.text[thisWord.text.length - 1] === ' ') { | ||
offsetX += space.width; | ||
} | ||
rows.push({ startGroup: groupName, klass: klass, name: name }); | ||
rows.push({move: spacing.info}) | ||
if (preface) { | ||
addTextIf(rows, { marginLeft: marginLeft, text: preface, font: defFont, absElemType: "extraText", name: name, 'dominant-baseline': 'middle' }, getTextSize); | ||
rows.push({move: size.height*3/4}) | ||
} | ||
this.rows.push({ move: largestY }); | ||
for (var j = 0; j < content.length; j++) { | ||
richText(rows, content[j], defFont, '', name, marginLeft, {anchor: 'start'}, getTextSize) | ||
// TODO-PER: Hack! the string and rich lines should have used up the same amount of space without this. | ||
if (j < content.length-1 && typeof content[j] === 'string' && typeof content[j+1] !== 'string') | ||
rows.push({move: size.height*3/4}) | ||
} | ||
rows.push({ endGroup: groupName, absElemType: absElemType, startChar: -1, endChar: -1, name: name }); | ||
rows.push({move: size.height}) | ||
} | ||
} | ||
this.rows.push({ move: space.height * 2 }); | ||
this.rows.push({ endGroup: "unalignedWords", absElemType: "unalignedWords", startChar: -1, endChar: -1, name: "unalignedWords" }); | ||
} | ||
BottomText.prototype.extraText = function (metaText, marginLeft, spacing, shouldAddClasses, getTextSize) { | ||
addSingleLine(this.rows, "Book: ", metaText.book, marginLeft, 'abcjs-book', shouldAddClasses, getTextSize) | ||
addSingleLine(this.rows, "Source: ", metaText.source, marginLeft, 'abcjs-source', shouldAddClasses, getTextSize) | ||
addSingleLine(this.rows, "Discography: ", metaText.discography, marginLeft, 'abcjs-discography', shouldAddClasses, getTextSize) | ||
BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTextSize) { | ||
var extraText = ""; | ||
if (metaText.book) extraText += "Book: " + metaText.book + "\n"; | ||
if (metaText.source) extraText += "Source: " + metaText.source + "\n"; | ||
if (metaText.discography) extraText += "Discography: " + metaText.discography + "\n"; | ||
if (metaText.notes) extraText += "Notes: " + metaText.notes + "\n"; | ||
if (metaText.transcription) extraText += "Transcription: " + metaText.transcription + "\n"; | ||
if (metaText.history) extraText += "History: " + metaText.history + "\n"; | ||
if (metaText['abc-copyright']) extraText += "Copyright: " + metaText['abc-copyright'] + "\n"; | ||
if (metaText['abc-creator']) extraText += "Creator: " + metaText['abc-creator'] + "\n"; | ||
if (metaText['abc-edited-by']) extraText += "Edited By: " + metaText['abc-edited-by'] + "\n"; | ||
if (extraText.length > 0) { | ||
addTextIf(this.rows, { marginLeft: marginLeft, text: extraText, font: 'historyfont', klass: 'meta-bottom extra-text', marginTop: spacing.info, absElemType: "extraText", name: "description" }, getTextSize); | ||
} | ||
addMultiLine(this.rows, 'Notes:', metaText.notes, marginLeft, 'historyfont', "extraText", "notes", 'abcjs-notes', "description", spacing, shouldAddClasses, getTextSize) | ||
addSingleLine(this.rows, "Transcription: ", metaText.transcription, marginLeft, 'abcjs-transcription', shouldAddClasses, getTextSize) | ||
addMultiLine(this.rows, "History:", metaText.history, marginLeft, 'historyfont', "extraText", "history", 'abcjs-history', "description", spacing, shouldAddClasses, getTextSize) | ||
addSingleLine(this.rows, "Copyright: ", metaText['abc-copyright'], marginLeft, 'abcjs-copyright', shouldAddClasses, getTextSize) | ||
addSingleLine(this.rows, "Creator: ", metaText['abc-creator'], marginLeft, 'abcjs-creator', shouldAddClasses, getTextSize) | ||
addSingleLine(this.rows, "Edited By: ", metaText['abc-edited-by'], marginLeft, 'abcjs-edited-by', shouldAddClasses, getTextSize) | ||
} | ||
@@ -68,0 +83,0 @@ |
const addTextIf = require("../add-text-if"); | ||
const richText = require("./rich-text"); | ||
function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, getTextSize) { | ||
function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) { | ||
this.rows = []; | ||
@@ -21,3 +22,4 @@ | ||
if (metaText.title) { | ||
addTextIf(this.rows, { marginLeft: tLeft, text: metaText.title, font: 'titlefont', klass: 'title meta-top', marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title, name: "title" }, getTextSize); | ||
var klass = shouldAddClasses ? 'abcjs-title' : '' | ||
richText(this.rows, metaText.title, "titlefont", klass, 'title', tLeft, {marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title}, getTextSize) | ||
} | ||
@@ -27,3 +29,4 @@ if (lines.length) { | ||
while (index < lines.length && lines[index].subtitle) { | ||
addTextIf(this.rows, { marginLeft: tLeft, text: lines[index].subtitle.text, font: 'subtitlefont', klass: 'text meta-top subtitle', marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle, name: "subtitle" }, getTextSize); | ||
var klass = shouldAddClasses ? 'abcjs-text abcjs-subtitle' : '' | ||
richText(this.rows, lines[index].subtitle.text, "subtitlefont", klass, 'subtitle', tLeft, {marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle}, getTextSize) | ||
index++; | ||
@@ -37,18 +40,41 @@ } | ||
var noMove = !!(metaText.composer || metaText.origin); | ||
addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: 'meta-top rhythm', absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize); | ||
var klass = shouldAddClasses ? 'abcjs-rhythm' : '' | ||
addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: klass, absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize); | ||
} | ||
var composerLine = ""; | ||
if (metaText.composer) composerLine += metaText.composer; | ||
if (metaText.origin) composerLine += ' (' + metaText.origin + ')'; | ||
if (composerLine.length > 0) { | ||
addTextIf(this.rows, { marginLeft: paddingLeft + width, text: composerLine, font: 'composerfont', klass: 'meta-top composer', anchor: "end", absElemType: "composer", info: metaTextInfo.composer, name: "composer" }, getTextSize); | ||
var hasSimpleComposerLine = true | ||
if (metaText.composer && typeof metaText.composer !== 'string') | ||
hasSimpleComposerLine = false | ||
if (metaText.origin && typeof metaText.origin !== 'string') | ||
hasSimpleComposerLine = false | ||
var composerLine = metaText.composer ? metaText.composer : ''; | ||
if (metaText.origin) { | ||
if (typeof composerLine === 'string' && typeof metaText.origin === 'string') | ||
composerLine += ' (' + metaText.origin + ')'; | ||
else if (typeof composerLine === 'string' && typeof metaText.origin !== 'string') { | ||
composerLine = [{text:composerLine}] | ||
composerLine.push({text:" ("}) | ||
composerLine = composerLine.concat(metaText.origin) | ||
composerLine.push({text:")"}) | ||
} else { | ||
composerLine.push({text:" ("}) | ||
composerLine = composerLine.concat(metaText.origin) | ||
composerLine.push({text:")"}) | ||
} | ||
} | ||
if (composerLine) { | ||
var klass = shouldAddClasses ? 'abcjs-composer' : '' | ||
richText(this.rows, composerLine, 'composerfont', klass, "composer", paddingLeft+width, {anchor: "end", absElemType: "composer", info: metaTextInfo.composer, ingroup: true}, getTextSize) | ||
} | ||
} | ||
if (metaText.author && metaText.author.length > 0) { | ||
addTextIf(this.rows, { marginLeft: paddingLeft + width, text: metaText.author, font: 'composerfont', klass: 'meta-top author', anchor: "end", absElemType: "author", info: metaTextInfo.author, name: "author" }, getTextSize); | ||
var klass = shouldAddClasses ? 'abcjs-author' : '' | ||
richText(this.rows, metaText.author, 'composerfont', klass, "author", paddingLeft+width, {anchor: "end", absElemType: "author", info: metaTextInfo.author}, getTextSize) | ||
} | ||
if (metaText.partOrder && metaText.partOrder.length > 0) { | ||
addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.partOrder, font: 'partsfont', klass: 'meta-top part-order', absElemType: "partOrder", info: metaTextInfo.partOrder, name: "part-order" }, getTextSize); | ||
var klass = shouldAddClasses ? 'abcjs-part-order' : '' | ||
richText(this.rows, metaText.partOrder, 'partsfont', klass, "part-order", paddingLeft, {absElemType: "partOrder", info: metaTextInfo.partOrder, anchor: 'start'}, getTextSize) | ||
} | ||
@@ -55,0 +81,0 @@ } |
@@ -19,3 +19,6 @@ var drawTempo = require('./tempo'); | ||
default: | ||
drawRelativeElement(renderer, child, bartop); | ||
var el = drawRelativeElement(renderer, child, bartop); | ||
if (child.type === "symbol" && child.c && child.c.indexOf('notehead') >= 0) { | ||
el.setAttribute('class', 'abcjs-notehead') | ||
} | ||
} | ||
@@ -22,0 +25,0 @@ } |
@@ -9,3 +9,6 @@ var drawStaffGroup = require('./staff-group'); | ||
var selectables = new Selectables(renderer.paper, selectTypes, tuneNumber); | ||
renderer.paper.openGroup() | ||
var groupClasses = {} | ||
if (classes.shouldAddClasses) | ||
groupClasses.klass = "abcjs-meta-top" | ||
renderer.paper.openGroup(groupClasses) | ||
renderer.moveY(renderer.padding.top); | ||
@@ -20,3 +23,5 @@ nonMusic(renderer, abcTune.topText, selectables); | ||
if (abcLine.staff) { | ||
renderer.paper.openGroup() | ||
if (classes.shouldAddClasses) | ||
groupClasses.klass = "abcjs-staff l" + classes.lineNumber | ||
renderer.paper.openGroup(groupClasses) | ||
if (abcLine.vskip) { | ||
@@ -32,3 +37,5 @@ renderer.moveY(abcLine.vskip); | ||
} else if (abcLine.nonMusic) { | ||
renderer.paper.openGroup() | ||
if (classes.shouldAddClasses) | ||
groupClasses.klass = "abcjs-non-music" | ||
renderer.paper.openGroup(groupClasses) | ||
nonMusic(renderer, abcLine.nonMusic, selectables); | ||
@@ -41,3 +48,5 @@ renderer.paper.closeGroup() | ||
if (abcTune.bottomText && abcTune.bottomText.rows && abcTune.bottomText.rows.length > 0) { | ||
renderer.paper.openGroup() | ||
if (classes.shouldAddClasses) | ||
groupClasses.klass = "abcjs-meta-bottom" | ||
renderer.paper.openGroup(groupClasses) | ||
renderer.moveY(24); // TODO-PER: Empirically discovered. What variable should this be? | ||
@@ -44,0 +53,0 @@ nonMusic(renderer, abcTune.bottomText, selectables); |
@@ -11,3 +11,3 @@ var drawSeparator = require('./separator'); | ||
renderer.moveY(row.move); | ||
} else if (row.text) { | ||
} else if (row.text || row.phrases) { | ||
var x = row.left ? row.left : 0; | ||
@@ -18,2 +18,4 @@ var el = renderText(renderer, { | ||
text: row.text, | ||
phrases: row.phrases, | ||
'dominant-baseline': row['dominant-baseline'], | ||
type: row.font, | ||
@@ -20,0 +22,0 @@ klass: row.klass, |
@@ -30,3 +30,3 @@ var renderText = require('./text'); | ||
var tabFont = "tabnumberfont"; | ||
var tabClass = 'tab-number'; | ||
var tabClass = 'abcjs-tab-number'; | ||
if (params.isGrace) { | ||
@@ -33,0 +33,0 @@ tabFont = "tabgracefont"; |
@@ -19,3 +19,3 @@ var drawRelativeElement = require('./relative'); | ||
if (params.tempo.preString) { | ||
text = renderText(renderer, { x: x, y: y, text: params.tempo.preString, type: 'tempofont', klass: 'abcjs-tempo', anchor: "start", noClass: true, "dominant-baseline": "ideographic", name: "pre" }, true); | ||
text = renderText(renderer, { x: x, y: y, text: params.tempo.preString, type: 'tempofont', klass: 'abcjs-tempo', anchor: "start", noClass: true, name: "pre" }, true); | ||
size = renderer.controller.getTextSize.calc(params.tempo.preString, 'tempofont', 'tempo', text); | ||
@@ -22,0 +22,0 @@ var preWidth = size.width; |
@@ -5,2 +5,10 @@ var roundNumber = require("./round-number"); | ||
var y = params.y; | ||
// TODO-PER: Probably need to merge the regular text and rich text better. At the least, rich text loses the font box. | ||
if (params.phrases) { | ||
//richTextLine = function (phrases, x, y, klass, anchor, target) | ||
var elem = renderer.paper.richTextLine(params.phrases, params.x, params.y, params.klass, params.anchor); | ||
return elem; | ||
} | ||
if (params.lane) { | ||
@@ -19,2 +27,4 @@ var laneMargin = params.dim.font.size * 0.25; | ||
hash.attr["text-anchor"] = params.anchor; | ||
if (params['dominant-baseline']) | ||
hash.attr["dominant-baseline"] = params['dominant-baseline']; | ||
hash.attr.x = params.x; | ||
@@ -21,0 +31,0 @@ hash.attr.y = y; |
@@ -68,2 +68,4 @@ // abc_engraver_controller.js: Controls the engraving process of an ABCJS abstract syntax tree as produced by ABCJS/parse | ||
this.jazzchords = params.jazzchords; | ||
if (params.accentAbove) | ||
this.accentAbove = params.accentAbove; | ||
if (params.germanAlphabet) | ||
@@ -127,2 +129,3 @@ this.germanAlphabet = params.germanAlphabet; | ||
this.getTextSize = new GetTextSize(this.getFontAndAttr, this.renderer.paper); | ||
var origJazzChords = this.jazzchords | ||
@@ -175,2 +178,3 @@ this.setupTune(abcTune, 0); | ||
} | ||
this.jazzchords = origJazzChords | ||
return ret; | ||
@@ -184,2 +188,4 @@ }; | ||
this.jazzchords = abcTune.formatting.jazzchords; | ||
if (abcTune.formatting.accentAbove !== undefined) | ||
this.accentAbove = abcTune.formatting.accentAbove; | ||
@@ -194,2 +200,3 @@ this.renderer.newTune(abcTune); | ||
jazzchords: this.jazzchords, | ||
accentAbove: this.accentAbove, | ||
germanAlphabet: this.germanAlphabet | ||
@@ -214,3 +221,3 @@ }); | ||
EngraverController.prototype.constructTuneElements = function (abcTune) { | ||
abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize); | ||
abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize); | ||
@@ -242,17 +249,50 @@ // Generate the raw staff line data | ||
} | ||
abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize); | ||
abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize); | ||
}; | ||
EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOffset) { | ||
var origJazzChords = this.jazzchords | ||
var scale = this.setupTune(abcTune, tuneNumber); | ||
// Create all of the element objects that will appear on the page. | ||
this.constructTuneElements(abcTune); | ||
//Set the top text now that we know the width | ||
// Do all the positioning, both horizontally and vertically | ||
var maxWidth = layout(this.renderer, abcTune, this.width, this.space, this.expandToWidest); | ||
//Set the top text now that we know the width | ||
if (this.expandToWidest && maxWidth > this.width + 1) { | ||
abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, maxWidth, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize); | ||
if ((abcTune.lines)&&(abcTune.lines.length > 0)){ | ||
var nlines = abcTune.lines.length; | ||
//Set the top text now that we know the width | ||
if (this.expandToWidest && maxWidth > this.width+1) { | ||
abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, maxWidth, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize); | ||
for (var i=0;i<nlines;++i){ | ||
var entry = abcTune.lines[i]; | ||
if (entry.nonMusic){ | ||
if ((entry.nonMusic.rows) && (entry.nonMusic.rows.length > 0)){ | ||
var nRows = entry.nonMusic.rows.length; | ||
for (var j=0;j<nRows;++j){ | ||
var thisRow = entry.nonMusic.rows[j]; | ||
// Recenter the element if it's a subtitle or centered text | ||
if (thisRow.left){ | ||
if (entry.subtitle){ | ||
thisRow.left = (maxWidth/2) + this.renderer.padding.left; | ||
} else { | ||
if ((entry.text)&&(entry.text.length>0)){ | ||
if (entry.text[0].center){ | ||
thisRow.left = (maxWidth/2) + this.renderer.padding.left; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -262,5 +302,5 @@ | ||
if (abcTune.tablatures) { | ||
tablatures.layoutTablatures(this.renderer, abcTune); | ||
tablatures.layoutTablatures(this.renderer, abcTune); | ||
} | ||
// Do all the writing to the SVG | ||
@@ -270,10 +310,11 @@ var ret = draw(this.renderer, this.classes, abcTune, this.width, maxWidth, this.responsive, scale, this.selectTypes, tuneNumber, lineOffset); | ||
this.selectables = ret.selectables; | ||
if (this.oneSvgPerLine) { | ||
var div = this.renderer.paper.svg.parentNode | ||
this.svgs = splitSvgIntoLines(this.renderer, div, abcTune.metaText.title, this.responsive) | ||
var div = this.renderer.paper.svg.parentNode; | ||
this.svgs = splitSvgIntoLines(this.renderer, div, abcTune.metaText.title, this.responsive); | ||
} else { | ||
this.svgs = [this.renderer.paper.svg]; | ||
this.svgs = [this.renderer.paper.svg]; | ||
} | ||
setupSelection(this, this.svgs); | ||
this.jazzchords = origJazzChords | ||
}; | ||
@@ -280,0 +321,0 @@ |
@@ -82,3 +82,3 @@ var Classes = function Classes(options) { | ||
if (c && c.length > 0) ret.push(c); | ||
if (c === "tab-number") // TODO-PER-HACK! straighten out the tablature | ||
if (c === "abcjs-tab-number") // TODO-PER-HACK! straighten out the tablature | ||
return ret.join(' ') | ||
@@ -85,0 +85,0 @@ if (c === "text instrument-name") |
@@ -17,2 +17,9 @@ var GetFontAndAttr = function GetFontAndAttr(formatting, classes) { | ||
GetFontAndAttr.prototype.getFamily = function (type) { | ||
if (type[0] === '"' && type[type.length-1] === '"') { | ||
return type.substring(1, type.length-1) | ||
} | ||
return type | ||
}; | ||
GetFontAndAttr.prototype.calc = function (type, klass) { | ||
@@ -34,3 +41,3 @@ var font; | ||
"font-size": font.size, 'font-style': font.style, | ||
"font-family": font.face, 'font-weight': font.weight, 'text-decoration': font.decoration, | ||
"font-family": this.getFamily(font.face), 'font-weight': font.weight, 'text-decoration': font.decoration, | ||
'class': this.classes.generate(klass) | ||
@@ -37,0 +44,0 @@ }; |
@@ -14,2 +14,9 @@ var GetTextSize = function GetTextSize(getFontAndAttr, svg) { | ||
GetTextSize.prototype.getFamily = function (type) { | ||
if (type[0] === '"' && type[type.length-1] === '"') { | ||
return type.substring(1, type.length-1) | ||
} | ||
return type | ||
}; | ||
GetTextSize.prototype.calc = function (text, type, klass, el) { | ||
@@ -32,3 +39,3 @@ var hash; | ||
"font-style": type.style, | ||
"font-family": type.face, | ||
"font-family": this.getFamily(type.face), | ||
"font-weight": type.weight, | ||
@@ -35,0 +42,0 @@ "text-decoration": type.decoration, |
@@ -214,2 +214,32 @@ // abc_voice_element.js: Definition of the VoiceElement class. | ||
Svg.prototype.richTextLine = function (phrases, x, y, klass, anchor, target) { | ||
var el = document.createElementNS(svgNS, 'text'); | ||
el.setAttribute("stroke", "none"); | ||
el.setAttribute("class", klass); | ||
el.setAttribute("x", x); | ||
el.setAttribute("y", y); | ||
el.setAttribute("text-anchor", anchor); | ||
el.setAttribute("dominant-baseline", "middle"); | ||
for (var i = 0; i < phrases.length; i++) { | ||
var phrase = phrases[i] | ||
var tspan = document.createElementNS(svgNS, 'tspan'); | ||
var attrs = Object.keys(phrase.attrs) | ||
for (var j = 0; j < attrs.length; j++) { | ||
var value = phrase.attrs[attrs[j]] | ||
if (value !== '') | ||
tspan.setAttribute(attrs[j], value) | ||
} | ||
tspan.textContent = phrase.content; | ||
el.appendChild(tspan); | ||
} | ||
if (target) | ||
target.appendChild(el); | ||
else | ||
this.append(el); | ||
return el; | ||
} | ||
Svg.prototype.guessWidth = function (text, attr) { | ||
@@ -216,0 +246,0 @@ var svg = this.createDummySvg(); |
@@ -265,2 +265,3 @@ declare module 'abcjs' { | ||
export interface AbcVisualParams { | ||
accentAbove?: boolean; | ||
add_classes?: boolean; | ||
@@ -321,4 +322,4 @@ afterParsing?: AfterParsing; | ||
el: Selector; | ||
cursorControl: CursorControl; | ||
options: SynthOptions; | ||
cursorControl?: CursorControl; | ||
options?: SynthOptions; | ||
} | ||
@@ -341,3 +342,3 @@ | ||
pitch: number; | ||
instrument: number; | ||
instrument: string; | ||
start: number; | ||
@@ -852,2 +853,3 @@ end: number; | ||
setTiming: (bpm?: number, measuresOfDelay? : number) => void; | ||
setupEvents: (startingDelay: number, timeDivider:number, startingBpm: number, warp?: number) => Array<NoteTimingEvent>; | ||
setUpAudio: (options: SynthOptions) => AudioTracks; | ||
@@ -1033,7 +1035,27 @@ makeVoicesArray: () => Array<Selectable[]> | ||
export interface AudioTrack { | ||
cmd: AudioTrackCommand; | ||
[param: string]: any; // TODO - make this a union | ||
export interface AudioTrackProgramItem { | ||
cmd: 'program'; | ||
channel: number; | ||
instrument: number; | ||
} | ||
export interface AudioTrackNoteItem { | ||
cmd: 'note'; | ||
duration: number; | ||
endChar: number; | ||
endType?: "staccato"|"tenuto"; | ||
gap: number; | ||
instrument: number; | ||
pitch: number; | ||
start: number; | ||
startChar: number; | ||
volume: number; | ||
} | ||
export interface AudioTrackTextItem { | ||
cmd: 'text'; | ||
type: 'name'; | ||
text: string; | ||
} | ||
export type AudioTrack = Array<AudioTrackProgramItem|AudioTrackNoteItem|AudioTrackTextItem> | ||
export interface AudioTracks { | ||
@@ -1165,2 +1187,3 @@ tempo: number; | ||
getIsRunning(): boolean | ||
getAudioBuffer(): AudioBuffer | undefined | ||
} | ||
@@ -1197,2 +1220,18 @@ | ||
export interface MidiRenderer { | ||
setTempo(bpm: number): void | ||
setGlobalInfo(bpm: number, name: string, key:KeySignature, time:MeterFraction): void | ||
startTrack(): void | ||
endTrack(): void | ||
setText(type: string, text: string):void | ||
setInstrument(instrument: number):void | ||
setChannel(channel:number, pan?: number):void | ||
startNote(pitch:number, loudness:number, cents?:number):void | ||
endNote(pitch:number):void | ||
addRest(length:number):void | ||
getData():string | ||
embed(parent:Element, noplayer:boolean):void | ||
} | ||
export namespace synth { | ||
@@ -1212,2 +1251,3 @@ let instrumentIndexToName: [string] | ||
export function sequence(visualObj: TuneObject, options: AbcVisualParams): AudioSequence | ||
export function midiRenderer(): MidiRenderer | ||
} | ||
@@ -1214,0 +1254,0 @@ |
@@ -1,3 +0,3 @@ | ||
var version = '6.2.3'; | ||
var version = '6.3.0'; | ||
module.exports = version; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6488487
51773
124
185