abcjs 6.2.3 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +4 -0
  2. package/RELEASE.md +40 -1
  3. package/dist/abcjs-basic-min.js +2 -2
  4. package/dist/abcjs-basic.js +751 -416
  5. package/dist/abcjs-basic.js.map +1 -1
  6. package/dist/abcjs-plugin-min.js +2 -2
  7. package/index.js +2 -0
  8. package/package.json +1 -1
  9. package/plugin.js +1 -1
  10. package/src/api/abc_tablatures.js +48 -13
  11. package/src/parse/abc_parse_directive.js +17 -16
  12. package/src/parse/abc_parse_header.js +22 -19
  13. package/src/parse/abc_tokenizer.js +72 -7
  14. package/src/parse/tune-builder.js +60 -1
  15. package/src/synth/synth-controller.js +6 -2
  16. package/src/tablatures/instruments/string-patterns.js +11 -0
  17. package/src/tablatures/instruments/{guitar/guitar-patterns.js → tab-string-patterns.js} +6 -6
  18. package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
  19. package/src/tablatures/tab-absolute-elements.js +16 -7
  20. package/src/tablatures/tab-renderer.js +22 -9
  21. package/src/test/abc_parser_lint.js +13 -12
  22. package/src/write/creation/abstract-engraver.js +3 -2
  23. package/src/write/creation/add-chord.js +102 -82
  24. package/src/write/creation/add-text-if.js +2 -2
  25. package/src/write/creation/decoration.js +14 -8
  26. package/src/write/creation/elements/bottom-text.js +62 -47
  27. package/src/write/creation/elements/rich-text.js +51 -0
  28. package/src/write/creation/elements/top-text.js +37 -11
  29. package/src/write/creation/glyphs.js +1 -1
  30. package/src/write/draw/absolute.js +4 -1
  31. package/src/write/draw/draw.js +13 -4
  32. package/src/write/draw/non-music.js +3 -1
  33. package/src/write/draw/relative.js +1 -1
  34. package/src/write/draw/tempo.js +1 -1
  35. package/src/write/draw/text.js +10 -0
  36. package/src/write/engraver-controller.js +54 -13
  37. package/src/write/helpers/classes.js +1 -1
  38. package/src/write/helpers/get-font-and-attr.js +8 -1
  39. package/src/write/helpers/get-text-size.js +8 -1
  40. package/src/write/svg.js +30 -0
  41. package/temp.txt +50 -0
  42. package/types/index.d.ts +46 -6
  43. package/version.js +1 -1
  44. package/.github/workflows/tests.yml +0 -29
  45. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
  46. package/src/tablatures/instruments/violin/violin-patterns.js +0 -23
@@ -1,6 +1,7 @@
1
1
  const addTextIf = require("../add-text-if");
2
+ const richText = require("./rich-text");
2
3
 
3
- function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, getTextSize) {
4
+ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
4
5
  this.rows = [];
5
6
 
6
7
  if (metaText.header && isPrint) {
@@ -18,12 +19,14 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
18
19
  var tAnchor = formatting.titleleft ? 'start' : 'middle';
19
20
  var tLeft = formatting.titleleft ? paddingLeft : paddingLeft + width / 2;
20
21
  if (metaText.title) {
21
- 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);
22
+ var klass = shouldAddClasses ? 'abcjs-title' : ''
23
+ richText(this.rows, metaText.title, "titlefont", klass, 'title', tLeft, {marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title}, getTextSize)
22
24
  }
23
25
  if (lines.length) {
24
26
  var index = 0;
25
27
  while (index < lines.length && lines[index].subtitle) {
26
- 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);
28
+ var klass = shouldAddClasses ? 'abcjs-text abcjs-subtitle' : ''
29
+ richText(this.rows, lines[index].subtitle.text, "subtitlefont", klass, 'subtitle', tLeft, {marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle}, getTextSize)
27
30
  index++;
28
31
  }
29
32
  }
@@ -32,22 +35,45 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
32
35
  this.rows.push({ move: spacing.composer });
33
36
  if (metaText.rhythm && metaText.rhythm.length > 0) {
34
37
  var noMove = !!(metaText.composer || metaText.origin);
35
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: 'meta-top rhythm', absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize);
38
+ var klass = shouldAddClasses ? 'abcjs-rhythm' : ''
39
+ addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: klass, absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize);
36
40
  }
37
- var composerLine = "";
38
- if (metaText.composer) composerLine += metaText.composer;
39
- if (metaText.origin) composerLine += ' (' + metaText.origin + ')';
40
- if (composerLine.length > 0) {
41
- addTextIf(this.rows, { marginLeft: paddingLeft + width, text: composerLine, font: 'composerfont', klass: 'meta-top composer', anchor: "end", absElemType: "composer", info: metaTextInfo.composer, name: "composer" }, getTextSize);
41
+ var hasSimpleComposerLine = true
42
+ if (metaText.composer && typeof metaText.composer !== 'string')
43
+ hasSimpleComposerLine = false
44
+ if (metaText.origin && typeof metaText.origin !== 'string')
45
+ hasSimpleComposerLine = false
46
+
47
+ var composerLine = metaText.composer ? metaText.composer : '';
48
+ if (metaText.origin) {
49
+ if (typeof composerLine === 'string' && typeof metaText.origin === 'string')
50
+ composerLine += ' (' + metaText.origin + ')';
51
+ else if (typeof composerLine === 'string' && typeof metaText.origin !== 'string') {
52
+ composerLine = [{text:composerLine}]
53
+ composerLine.push({text:" ("})
54
+ composerLine = composerLine.concat(metaText.origin)
55
+ composerLine.push({text:")"})
56
+ } else {
57
+ composerLine.push({text:" ("})
58
+ composerLine = composerLine.concat(metaText.origin)
59
+ composerLine.push({text:")"})
60
+ }
61
+ }
62
+ if (composerLine) {
63
+ var klass = shouldAddClasses ? 'abcjs-composer' : ''
64
+ richText(this.rows, composerLine, 'composerfont', klass, "composer", paddingLeft+width, {anchor: "end", absElemType: "composer", info: metaTextInfo.composer, ingroup: true}, getTextSize)
42
65
  }
43
66
  }
44
67
 
45
68
  if (metaText.author && metaText.author.length > 0) {
46
- 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);
69
+ var klass = shouldAddClasses ? 'abcjs-author' : ''
70
+ richText(this.rows, metaText.author, 'composerfont', klass, "author", paddingLeft+width, {anchor: "end", absElemType: "author", info: metaTextInfo.author}, getTextSize)
47
71
  }
48
72
 
49
73
  if (metaText.partOrder && metaText.partOrder.length > 0) {
50
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.partOrder, font: 'partsfont', klass: 'meta-top part-order', absElemType: "partOrder", info: metaTextInfo.partOrder, name: "part-order" }, getTextSize);
74
+ var klass = shouldAddClasses ? 'abcjs-part-order' : ''
75
+ richText(this.rows, metaText.partOrder, 'partsfont', klass, "part-order", paddingLeft, {absElemType: "partOrder", info: metaTextInfo.partOrder, anchor: 'start'}, getTextSize)
76
+
51
77
  }
52
78
  }
53
79
 
@@ -86,7 +86,7 @@ var glyphs =
86
86
  's': { d: [['M', 4.47, -8.73], ['c', 0.09, 0.00, 0.36, -0.03, 0.57, -0.03], ['c', 0.75, 0.03, 1.29, 0.24, 1.71, 0.63], ['c', 0.51, 0.54, 0.66, 1.26, 0.36, 1.83], ['c', -0.24, 0.42, -0.63, 0.57, -1.11, 0.42], ['c', -0.33, -0.09, -0.60, -0.36, -0.60, -0.57], ['c', 0.00, -0.03, 0.06, -0.21, 0.15, -0.39], ['c', 0.12, -0.21, 0.15, -0.33, 0.18, -0.48], ['c', 0.00, -0.24, -0.06, -0.48, -0.15, -0.60], ['c', -0.15, -0.21, -0.42, -0.24, -0.75, -0.15], ['c', -0.27, 0.06, -0.48, 0.18, -0.69, 0.36], ['c', -0.39, 0.39, -0.51, 0.96, -0.33, 1.38], ['c', 0.09, 0.21, 0.42, 0.51, 0.78, 0.72], ['c', 1.11, 0.69, 1.59, 1.11, 1.89, 1.68], ['c', 0.21, 0.39, 0.24, 0.78, 0.15, 1.29], ['c', -0.18, 1.20, -1.17, 2.16, -2.52, 2.52], ['c', -1.02, 0.24, -1.95, 0.12, -2.70, -0.42], ['c', -0.72, -0.51, -0.99, -1.47, -0.60, -2.19], ['c', 0.24, -0.48, 0.72, -0.63, 1.17, -0.42], ['c', 0.33, 0.18, 0.54, 0.45, 0.57, 0.81], ['c', 0.00, 0.21, -0.03, 0.30, -0.33, 0.51], ['c', -0.33, 0.24, -0.39, 0.42, -0.27, 0.69], ['c', 0.06, 0.15, 0.21, 0.27, 0.45, 0.33], ['c', 0.30, 0.09, 0.87, 0.09, 1.20, 0.00], ['c', 0.75, -0.21, 1.23, -0.72, 1.29, -1.35], ['c', 0.03, -0.42, -0.15, -0.81, -0.54, -1.20], ['c', -0.24, -0.24, -0.48, -0.42, -1.41, -1.02], ['c', -0.69, -0.42, -1.05, -0.93, -1.05, -1.47], ['c', 0.00, -0.39, 0.12, -0.87, 0.30, -1.23], ['c', 0.27, -0.57, 0.78, -1.05, 1.38, -1.35], ['c', 0.24, -0.12, 0.63, -0.27, 0.90, -0.30], ['z']], w: 6.632, h: 8.758 },
87
87
  'z': { d: [['M', 2.64, -7.95], ['c', 0.36, -0.09, 0.81, -0.03, 1.71, 0.27], ['c', 0.78, 0.21, 0.96, 0.27, 1.74, 0.30], ['c', 0.87, 0.06, 1.02, 0.03, 1.38, -0.21], ['c', 0.21, -0.15, 0.33, -0.15, 0.48, -0.06], ['c', 0.15, 0.09, 0.21, 0.30, 0.15, 0.45], ['c', -0.03, 0.06, -1.26, 1.26, -2.76, 2.67], ['l', -2.73, 2.55], ['l', 0.54, 0.03], ['c', 0.54, 0.03, 0.72, 0.03, 2.01, 0.15], ['c', 0.36, 0.03, 0.90, 0.06, 1.20, 0.09], ['c', 0.66, 0.00, 0.81, -0.03, 1.02, -0.24], ['c', 0.30, -0.30, 0.39, -0.72, 0.27, -1.23], ['c', -0.06, -0.27, -0.06, -0.27, -0.03, -0.39], ['c', 0.15, -0.30, 0.54, -0.27, 0.69, 0.03], ['c', 0.15, 0.33, 0.27, 1.02, 0.27, 1.50], ['c', 0.00, 1.47, -1.11, 2.70, -2.52, 2.79], ['c', -0.57, 0.03, -1.02, -0.09, -2.01, -0.51], ['c', -1.02, -0.42, -1.23, -0.48, -2.13, -0.54], ['c', -0.81, -0.06, -0.96, -0.03, -1.26, 0.18], ['c', -0.12, 0.06, -0.24, 0.12, -0.27, 0.12], ['c', -0.27, 0.00, -0.45, -0.30, -0.36, -0.51], ['c', 0.03, -0.06, 1.32, -1.32, 2.91, -2.79], ['l', 2.88, -2.73], ['c', -0.03, 0.00, -0.21, 0.03, -0.42, 0.06], ['c', -0.21, 0.03, -0.78, 0.09, -1.23, 0.12], ['c', -1.11, 0.12, -1.23, 0.15, -1.95, 0.27], ['c', -0.72, 0.15, -1.17, 0.18, -1.29, 0.09], ['c', -0.27, -0.18, -0.21, -0.75, 0.12, -1.26], ['c', 0.39, -0.60, 0.93, -1.02, 1.59, -1.20], ['z']], w: 8.573, h: 8.743 },
88
88
  '+': { d: [['M', 3.48, -9.3], ['c', 0.18, -0.09, 0.36, -0.09, 0.54, 0.00], ['c', 0.18, 0.09, 0.24, 0.15, 0.33, 0.30], ['l', 0.06, 0.15], ['l', 0.00, 1.29], ['l', 0.00, 1.29], ['l', 1.29, 0.00], ['c', 1.23, 0.00, 1.29, 0.00, 1.41, 0.06], ['c', 0.06, 0.03, 0.15, 0.09, 0.18, 0.12], ['c', 0.12, 0.09, 0.21, 0.33, 0.21, 0.48], ['c', 0.00, 0.15, -0.09, 0.39, -0.21, 0.48], ['c', -0.03, 0.03, -0.12, 0.09, -0.18, 0.12], ['c', -0.12, 0.06, -0.18, 0.06, -1.41, 0.06], ['l', -1.29, 0.00], ['l', 0.00, 1.29], ['c', 0.00, 1.23, 0.00, 1.29, -0.06, 1.41], ['c', -0.09, 0.18, -0.15, 0.24, -0.30, 0.33], ['c', -0.21, 0.09, -0.39, 0.09, -0.57, 0.00], ['c', -0.18, -0.09, -0.24, -0.15, -0.33, -0.33], ['c', -0.06, -0.12, -0.06, -0.18, -0.06, -1.41], ['l', 0.00, -1.29], ['l', -1.29, 0.00], ['c', -1.23, 0.00, -1.29, 0.00, -1.41, -0.06], ['c', -0.18, -0.09, -0.24, -0.15, -0.33, -0.33], ['c', -0.09, -0.18, -0.09, -0.36, 0.00, -0.54], ['c', 0.09, -0.18, 0.15, -0.24, 0.33, -0.33], ['l', 0.15, -0.06], ['l', 1.26, 0.00], ['l', 1.29, 0.00], ['l', 0.00, -1.29], ['c', 0.00, -1.23, 0.00, -1.29, 0.06, -1.41], ['c', 0.09, -0.18, 0.15, -0.24, 0.33, -0.33], ['z']], w: 7.507, h: 7.515 },
89
- ',': { d: [['M', 1.32, -3.36], ['c', 0.57, -0.15, 1.17, 0.03, 1.59, 0.45], ['c', 0.45, 0.45, 0.60, 0.96, 0.51, 1.89], ['c', -0.09, 1.23, -0.42, 2.46, -0.99, 3.93], ['c', -0.30, 0.72, -0.72, 1.62, -0.78, 1.68], ['c', -0.18, 0.21, -0.51, 0.18, -0.66, -0.06], ['c', -0.03, -0.06, -0.06, -0.15, -0.06, -0.18], ['c', 0.00, -0.06, 0.12, -0.33, 0.24, -0.63], ['c', 0.84, -1.80, 1.02, -2.61, 0.69, -3.24], ['c', -0.12, -0.24, -0.27, -0.36, -0.75, -0.60], ['c', -0.36, -0.15, -0.42, -0.21, -0.60, -0.39], ['c', -0.69, -0.69, -0.69, -1.71, 0.00, -2.40], ['c', 0.21, -0.21, 0.51, -0.39, 0.81, -0.45], ['z']], w: 3.452, h: 8.143 },
89
+ ',': { d: [['M', 1.85, -3.36], ['c', 0.57, -0.15, 1.17, 0.03, 1.59, 0.45], ['c', 0.45, 0.45, 0.60, 0.96, 0.51, 1.89], ['c', -0.09, 1.23, -0.42, 2.46, -0.99, 3.93], ['c', -0.30, 0.72, -0.72, 1.62, -0.78, 1.68], ['c', -0.18, 0.21, -0.51, 0.18, -0.66, -0.06], ['c', -0.03, -0.06, -0.06, -0.15, -0.06, -0.18], ['c', 0.00, -0.06, 0.12, -0.33, 0.24, -0.63], ['c', 0.84, -1.80, 1.02, -2.61, 0.69, -3.24], ['c', -0.12, -0.24, -0.27, -0.36, -0.75, -0.60], ['c', -0.36, -0.15, -0.42, -0.21, -0.60, -0.39], ['c', -0.69, -0.69, -0.69, -1.71, 0.00, -2.40], ['c', 0.21, -0.21, 0.51, -0.39, 0.81, -0.45], ['z']], w: 3.452, h: 8.143 },
90
90
  '-': { d: [['M', 0.18, -5.34], ['c', 0.09, -0.06, 0.15, -0.06, 2.31, -0.06], ['c', 2.46, 0.00, 2.37, 0.00, 2.46, 0.21], ['c', 0.12, 0.21, 0.03, 0.42, -0.15, 0.54], ['c', -0.09, 0.06, -0.15, 0.06, -2.28, 0.06], ['c', -2.16, 0.00, -2.22, 0.00, -2.31, -0.06], ['c', -0.27, -0.15, -0.27, -0.54, -0.03, -0.69], ['z']], w: 5.001, h: 0.81 },
91
91
  '.': { d: [['M', 1.32, -3.36], ['c', 1.05, -0.27, 2.10, 0.57, 2.10, 1.65], ['c', 0.00, 1.08, -1.05, 1.92, -2.10, 1.65], ['c', -0.90, -0.21, -1.50, -1.14, -1.26, -2.04], ['c', 0.12, -0.63, 0.63, -1.11, 1.26, -1.26], ['z']], w: 3.413, h: 3.402 },
92
92
  'scripts.wedge': { d: [['M', -3.66, -7.44], ['c', 0.06, -0.09, 0.00, -0.09, 0.81, 0.03], ['c', 1.86, 0.30, 3.84, 0.30, 5.73, 0.00], ['c', 0.78, -0.12, 0.72, -0.12, 0.78, -0.03], ['c', 0.15, 0.15, 0.12, 0.24, -0.24, 0.60], ['c', -0.93, 0.93, -1.98, 2.76, -2.67, 4.62], ['c', -0.30, 0.78, -0.51, 1.71, -0.51, 2.13], ['c', 0.00, 0.15, 0.00, 0.18, -0.06, 0.27], ['c', -0.12, 0.09, -0.24, 0.09, -0.36, 0.00], ['c', -0.06, -0.09, -0.06, -0.12, -0.06, -0.27], ['c', 0.00, -0.42, -0.21, -1.35, -0.51, -2.13], ['c', -0.69, -1.86, -1.74, -3.69, -2.67, -4.62], ['c', -0.36, -0.36, -0.39, -0.45, -0.24, -0.60], ['z']], w: 7.49, h: 7.752 },
@@ -16,7 +16,10 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
16
16
  drawTempo(renderer, child);
17
17
  break;
18
18
  default:
19
- drawRelativeElement(renderer, child, bartop);
19
+ var el = drawRelativeElement(renderer, child, bartop);
20
+ if (child.type === "symbol" && child.c && child.c.indexOf('notehead') >= 0) {
21
+ el.setAttribute('class', 'abcjs-notehead')
22
+ }
20
23
  }
21
24
  }
22
25
  var klass = params.type;
@@ -6,7 +6,10 @@ var Selectables = require('./selectables');
6
6
 
7
7
  function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, selectTypes, tuneNumber, lineOffset) {
8
8
  var selectables = new Selectables(renderer.paper, selectTypes, tuneNumber);
9
- renderer.paper.openGroup()
9
+ var groupClasses = {}
10
+ if (classes.shouldAddClasses)
11
+ groupClasses.klass = "abcjs-meta-top"
12
+ renderer.paper.openGroup(groupClasses)
10
13
  renderer.moveY(renderer.padding.top);
11
14
  nonMusic(renderer, abcTune.topText, selectables);
12
15
  renderer.paper.closeGroup()
@@ -16,7 +19,9 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
16
19
  classes.incrLine();
17
20
  var abcLine = abcTune.lines[line];
18
21
  if (abcLine.staff) {
19
- renderer.paper.openGroup()
22
+ if (classes.shouldAddClasses)
23
+ groupClasses.klass = "abcjs-staff l" + classes.lineNumber
24
+ renderer.paper.openGroup(groupClasses)
20
25
  if (abcLine.vskip) {
21
26
  renderer.moveY(abcLine.vskip);
22
27
  }
@@ -27,7 +32,9 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
27
32
  staffgroups.push(staffgroup);
28
33
  renderer.paper.closeGroup()
29
34
  } else if (abcLine.nonMusic) {
30
- renderer.paper.openGroup()
35
+ if (classes.shouldAddClasses)
36
+ groupClasses.klass = "abcjs-non-music"
37
+ renderer.paper.openGroup(groupClasses)
31
38
  nonMusic(renderer, abcLine.nonMusic, selectables);
32
39
  renderer.paper.closeGroup()
33
40
  }
@@ -35,7 +42,9 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
35
42
 
36
43
  classes.reset();
37
44
  if (abcTune.bottomText && abcTune.bottomText.rows && abcTune.bottomText.rows.length > 0) {
38
- renderer.paper.openGroup()
45
+ if (classes.shouldAddClasses)
46
+ groupClasses.klass = "abcjs-meta-bottom"
47
+ renderer.paper.openGroup(groupClasses)
39
48
  renderer.moveY(24); // TODO-PER: Empirically discovered. What variable should this be?
40
49
  nonMusic(renderer, abcTune.bottomText, selectables);
41
50
  renderer.paper.closeGroup()
@@ -8,12 +8,14 @@ function nonMusic(renderer, obj, selectables) {
8
8
  renderer.absolutemoveY(row.absmove);
9
9
  } else if (row.move) {
10
10
  renderer.moveY(row.move);
11
- } else if (row.text) {
11
+ } else if (row.text || row.phrases) {
12
12
  var x = row.left ? row.left : 0;
13
13
  var el = renderText(renderer, {
14
14
  x: x,
15
15
  y: renderer.y,
16
16
  text: row.text,
17
+ phrases: row.phrases,
18
+ 'dominant-baseline': row['dominant-baseline'],
17
19
  type: row.font,
18
20
  klass: row.klass,
19
21
  name: row.name,
@@ -27,7 +27,7 @@ function drawRelativeElement(renderer, params, bartop) {
27
27
  case "tabNumber":
28
28
  var hAnchor = "middle";
29
29
  var tabFont = "tabnumberfont";
30
- var tabClass = 'tab-number';
30
+ var tabClass = 'abcjs-tab-number';
31
31
  if (params.isGrace) {
32
32
  tabFont = "tabgracefont";
33
33
  y += 2.5;
@@ -16,7 +16,7 @@ function drawTempo(renderer, params) {
16
16
  var text;
17
17
  var size;
18
18
  if (params.tempo.preString) {
19
- 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);
19
+ text = renderText(renderer, { x: x, y: y, text: params.tempo.preString, type: 'tempofont', klass: 'abcjs-tempo', anchor: "start", noClass: true, name: "pre" }, true);
20
20
  size = renderer.controller.getTextSize.calc(params.tempo.preString, 'tempofont', 'tempo', text);
21
21
  var preWidth = size.width;
22
22
  var charWidth = preWidth / params.tempo.preString.length; // Just get some average number to increase the spacing.
@@ -2,6 +2,14 @@ var roundNumber = require("./round-number");
2
2
 
3
3
  function renderText(renderer, params, alreadyInGroup) {
4
4
  var y = params.y;
5
+
6
+ // TODO-PER: Probably need to merge the regular text and rich text better. At the least, rich text loses the font box.
7
+ if (params.phrases) {
8
+ //richTextLine = function (phrases, x, y, klass, anchor, target)
9
+ var elem = renderer.paper.richTextLine(params.phrases, params.x, params.y, params.klass, params.anchor);
10
+ return elem;
11
+ }
12
+
5
13
  if (params.lane) {
6
14
  var laneMargin = params.dim.font.size * 0.25;
7
15
  y += (params.dim.font.size + laneMargin) * params.lane;
@@ -15,6 +23,8 @@ function renderText(renderer, params, alreadyInGroup) {
15
23
  hash = renderer.controller.getFontAndAttr.calc(params.type, params.klass);
16
24
  if (params.anchor)
17
25
  hash.attr["text-anchor"] = params.anchor;
26
+ if (params['dominant-baseline'])
27
+ hash.attr["dominant-baseline"] = params['dominant-baseline'];
18
28
  hash.attr.x = params.x;
19
29
  hash.attr.y = y;
20
30
  if (!params.centerVertically)
@@ -65,6 +65,8 @@ var EngraverController = function (paper, params) {
65
65
  this.renderer.showDebug = params.showDebug;
66
66
  if (params.jazzchords)
67
67
  this.jazzchords = params.jazzchords;
68
+ if (params.accentAbove)
69
+ this.accentAbove = params.accentAbove;
68
70
  if (params.germanAlphabet)
69
71
  this.germanAlphabet = params.germanAlphabet;
70
72
  if (params.lineThickness)
@@ -123,6 +125,7 @@ EngraverController.prototype.getMeasureWidths = function (abcTune) {
123
125
  this.reset();
124
126
  this.getFontAndAttr = new GetFontAndAttr(abcTune.formatting, this.classes);
125
127
  this.getTextSize = new GetTextSize(this.getFontAndAttr, this.renderer.paper);
128
+ var origJazzChords = this.jazzchords
126
129
 
127
130
  this.setupTune(abcTune, 0);
128
131
  this.constructTuneElements(abcTune);
@@ -170,6 +173,7 @@ EngraverController.prototype.getMeasureWidths = function (abcTune) {
170
173
  } else
171
174
  needNewSection = true;
172
175
  }
176
+ this.jazzchords = origJazzChords
173
177
  return ret;
174
178
  };
175
179
 
@@ -178,6 +182,8 @@ EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
178
182
 
179
183
  if (abcTune.formatting.jazzchords !== undefined)
180
184
  this.jazzchords = abcTune.formatting.jazzchords;
185
+ if (abcTune.formatting.accentAbove !== undefined)
186
+ this.accentAbove = abcTune.formatting.accentAbove;
181
187
 
182
188
  this.renderer.newTune(abcTune);
183
189
  this.engraver = new AbstractEngraver(this.getTextSize, tuneNumber, {
@@ -187,6 +193,7 @@ EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
187
193
  percmap: abcTune.formatting.percmap,
188
194
  initialClef: this.initialClef,
189
195
  jazzchords: this.jazzchords,
196
+ accentAbove: this.accentAbove,
190
197
  germanAlphabet: this.germanAlphabet
191
198
  });
192
199
  this.engraver.setStemHeight(this.renderer.spacing.stemHeight);
@@ -206,7 +213,7 @@ EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
206
213
  };
207
214
 
208
215
  EngraverController.prototype.constructTuneElements = function (abcTune) {
209
- 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);
216
+ 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);
210
217
 
211
218
  // Generate the raw staff line data
212
219
  var i;
@@ -233,40 +240,74 @@ EngraverController.prototype.constructTuneElements = function (abcTune) {
233
240
  abcLine.nonMusic = new Separator(abcLine.separator.spaceAbove, abcLine.separator.lineLength, abcLine.separator.spaceBelow);
234
241
  }
235
242
  }
236
- abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
243
+ abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize);
237
244
  };
238
245
 
239
246
  EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOffset) {
240
- var scale = this.setupTune(abcTune, tuneNumber);
241
247
 
248
+ var origJazzChords = this.jazzchords
249
+ var scale = this.setupTune(abcTune, tuneNumber);
250
+
242
251
  // Create all of the element objects that will appear on the page.
243
252
  this.constructTuneElements(abcTune);
244
-
253
+
254
+ //Set the top text now that we know the width
255
+
245
256
  // Do all the positioning, both horizontally and vertically
246
257
  var maxWidth = layout(this.renderer, abcTune, this.width, this.space, this.expandToWidest);
247
-
258
+
248
259
  //Set the top text now that we know the width
249
- if (this.expandToWidest && maxWidth > this.width+1) {
250
- 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);
260
+ if (this.expandToWidest && maxWidth > this.width + 1) {
261
+
262
+ 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);
263
+
264
+ if ((abcTune.lines)&&(abcTune.lines.length > 0)){
265
+ var nlines = abcTune.lines.length;
266
+
267
+ for (var i=0;i<nlines;++i){
268
+ var entry = abcTune.lines[i];
269
+ if (entry.nonMusic){
270
+ if ((entry.nonMusic.rows) && (entry.nonMusic.rows.length > 0)){
271
+ var nRows = entry.nonMusic.rows.length;
272
+ for (var j=0;j<nRows;++j){
273
+ var thisRow = entry.nonMusic.rows[j];
274
+ // Recenter the element if it's a subtitle or centered text
275
+ if (thisRow.left){
276
+ if (entry.subtitle){
277
+ thisRow.left = (maxWidth/2) + this.renderer.padding.left;
278
+ } else {
279
+ if ((entry.text)&&(entry.text.length>0)){
280
+ if (entry.text[0].center){
281
+ thisRow.left = (maxWidth/2) + this.renderer.padding.left;
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ }
288
+ }
289
+ }
290
+ }
251
291
  }
252
292
 
253
293
  // Deal with tablature for staff
254
294
  if (abcTune.tablatures) {
255
- tablatures.layoutTablatures(this.renderer, abcTune);
295
+ tablatures.layoutTablatures(this.renderer, abcTune);
256
296
  }
257
-
297
+
258
298
  // Do all the writing to the SVG
259
299
  var ret = draw(this.renderer, this.classes, abcTune, this.width, maxWidth, this.responsive, scale, this.selectTypes, tuneNumber, lineOffset);
260
300
  this.staffgroups = ret.staffgroups;
261
301
  this.selectables = ret.selectables;
262
-
263
302
  if (this.oneSvgPerLine) {
264
- var div = this.renderer.paper.svg.parentNode
265
- this.svgs = splitSvgIntoLines(this.renderer, div, abcTune.metaText.title, this.responsive)
303
+ var div = this.renderer.paper.svg.parentNode;
304
+ this.svgs = splitSvgIntoLines(this.renderer, div, abcTune.metaText.title, this.responsive);
266
305
  } else {
267
- this.svgs = [this.renderer.paper.svg];
306
+ this.svgs = [this.renderer.paper.svg];
268
307
  }
269
308
  setupSelection(this, this.svgs);
309
+
310
+ this.jazzchords = origJazzChords
270
311
  };
271
312
 
272
313
  function splitSvgIntoLines(renderer, output, title, responsive) {
@@ -79,7 +79,7 @@ Classes.prototype.generate = function (c) {
79
79
  return "";
80
80
  var ret = [];
81
81
  if (c && c.length > 0) ret.push(c);
82
- if (c === "tab-number") // TODO-PER-HACK! straighten out the tablature
82
+ if (c === "abcjs-tab-number") // TODO-PER-HACK! straighten out the tablature
83
83
  return ret.join(' ')
84
84
  if (c === "text instrument-name")
85
85
  return "abcjs-text abcjs-instrument-name"
@@ -14,6 +14,13 @@ GetFontAndAttr.prototype.updateFonts = function (fontOverrides) {
14
14
  this.formatting.vocalfont = fontOverrides.vocalfont;
15
15
  };
16
16
 
17
+ GetFontAndAttr.prototype.getFamily = function (type) {
18
+ if (type[0] === '"' && type[type.length-1] === '"') {
19
+ return type.substring(1, type.length-1)
20
+ }
21
+ return type
22
+ };
23
+
17
24
  GetFontAndAttr.prototype.calc = function (type, klass) {
18
25
  var font;
19
26
  if (typeof type === 'string') {
@@ -30,7 +37,7 @@ GetFontAndAttr.prototype.calc = function (type, klass) {
30
37
 
31
38
  var attr = {
32
39
  "font-size": font.size, 'font-style': font.style,
33
- "font-family": font.face, 'font-weight': font.weight, 'text-decoration': font.decoration,
40
+ "font-family": this.getFamily(font.face), 'font-weight': font.weight, 'text-decoration': font.decoration,
34
41
  'class': this.classes.generate(klass)
35
42
  };
36
43
  return { font: font, attr: attr };
@@ -11,6 +11,13 @@ GetTextSize.prototype.attr = function (type, klass) {
11
11
  return this.getFontAndAttr.calc(type, klass);
12
12
  };
13
13
 
14
+ GetTextSize.prototype.getFamily = function (type) {
15
+ if (type[0] === '"' && type[type.length-1] === '"') {
16
+ return type.substring(1, type.length-1)
17
+ }
18
+ return type
19
+ };
20
+
14
21
  GetTextSize.prototype.calc = function (text, type, klass, el) {
15
22
  var hash;
16
23
  // This can be passed in either a string or a font. If it is a string it names one of the standard fonts.
@@ -28,7 +35,7 @@ GetTextSize.prototype.calc = function (text, type, klass, el) {
28
35
  attr: {
29
36
  "font-size": type.size,
30
37
  "font-style": type.style,
31
- "font-family": type.face,
38
+ "font-family": this.getFamily(type.face),
32
39
  "font-weight": type.weight,
33
40
  "text-decoration": type.decoration,
34
41
  "class": this.getFontAndAttr.classes.generate(klass)
package/src/write/svg.js CHANGED
@@ -211,6 +211,36 @@ Svg.prototype.text = function (text, attr, target) {
211
211
  return el;
212
212
  };
213
213
 
214
+ Svg.prototype.richTextLine = function (phrases, x, y, klass, anchor, target) {
215
+ var el = document.createElementNS(svgNS, 'text');
216
+ el.setAttribute("stroke", "none");
217
+ el.setAttribute("class", klass);
218
+ el.setAttribute("x", x);
219
+ el.setAttribute("y", y);
220
+ el.setAttribute("text-anchor", anchor);
221
+ el.setAttribute("dominant-baseline", "middle");
222
+
223
+ for (var i = 0; i < phrases.length; i++) {
224
+ var phrase = phrases[i]
225
+ var tspan = document.createElementNS(svgNS, 'tspan');
226
+ var attrs = Object.keys(phrase.attrs)
227
+ for (var j = 0; j < attrs.length; j++) {
228
+ var value = phrase.attrs[attrs[j]]
229
+ if (value !== '')
230
+ tspan.setAttribute(attrs[j], value)
231
+ }
232
+ tspan.textContent = phrase.content;
233
+
234
+ el.appendChild(tspan);
235
+ }
236
+
237
+ if (target)
238
+ target.appendChild(el);
239
+ else
240
+ this.append(el);
241
+ return el;
242
+ }
243
+
214
244
  Svg.prototype.guessWidth = function (text, attr) {
215
245
  var svg = this.createDummySvg();
216
246
  var el = this.text(text, attr, svg);
package/temp.txt ADDED
@@ -0,0 +1,50 @@
1
+ ## Features
2
+
3
+ ### Tablature
4
+ * Add tab feature `hideTabSymbol`
5
+ * Add 5-string tab named "fiveString"
6
+ * Make "mandolin" and "fiddle" synonyms for "violin" in tablature.
7
+
8
+ ### Synth
9
+ * change the default synth control options for "play" and "progress" to be true
10
+ * expose the MIDI creator function
11
+ * Add a `getIsRunning()` function to enable play/pause
12
+ * allow passing in soundfont and debug callback when playing an event directly.
13
+
14
+ ### Rich Text
15
+ * allow up to 9 custom fonts in `%%setfont`
16
+ * for rich text fields, escape two dollar signs
17
+ * allow rich text in all non-music fields
18
+ * give all non-music fields a unique class
19
+
20
+ ### Miscellaneous
21
+ * add abcjs-notehead class to note heads;
22
+ * add `accentAbove` parameter
23
+ * handle numbered tune names in the reverser
24
+ * support reversing tune names with ", a" and ", an", with a variable amount of whitespace and case-insensitive
25
+ * Add Glissando Synonyms
26
+ * Put start and end char on slurs so they can be selected.
27
+ * Add `expandToWidest` option
28
+
29
+ ## Bugs
30
+ * fix placement of tab staff when there is no label
31
+ * fix font placement bugs
32
+ * remove spurious quotes in font name in svg attribute
33
+ * Fix the name of the `abcjs-tab-number` class
34
+ * fix crash when skipping a staff when creating tablature
35
+ * Fix tab staff height when there is a label
36
+ * Fix for crash when rendering multiple tab staves
37
+ * Offset breath mark to the right
38
+ * Center text when using `expandToWidest` set true
39
+ * fix placement of triangle notehead
40
+ * `afterParsing` now works with line wrapping.
41
+ * Add paddingleft to the size of the SVG - it was cut off if the padding was larger than the default.
42
+ * Guard against crash when the synth note wasn't loaded.
43
+ * protect against spurious mouse click in selection
44
+ * Fix bug in Firefox that cuts off the last line of the SVG
45
+
46
+ ## Documentation
47
+ * add missing typescript types
48
+ * fix synth control types
49
+ * fixed some typescript types in the TimingCallbacks
50
+ * TimingEvent is now NoteTimingEvent
package/types/index.d.ts CHANGED
@@ -262,6 +262,7 @@ declare module 'abcjs' {
262
262
  }
263
263
 
264
264
  export interface AbcVisualParams {
265
+ accentAbove?: boolean;
265
266
  add_classes?: boolean;
266
267
  afterParsing?: AfterParsing;
267
268
  ariaLabel?: string;
@@ -317,8 +318,8 @@ declare module 'abcjs' {
317
318
  export interface EditorSynth {
318
319
  synthControl?: SynthObjectController;
319
320
  el: Selector;
320
- cursorControl: CursorControl;
321
- options: SynthOptions;
321
+ cursorControl?: CursorControl;
322
+ options?: SynthOptions;
322
323
  }
323
324
 
324
325
  export interface EditorOptions {
@@ -336,7 +337,7 @@ declare module 'abcjs' {
336
337
  // Audio
337
338
  export interface NoteMapTrackItem {
338
339
  pitch: number;
339
- instrument: number;
340
+ instrument: string;
340
341
  start: number;
341
342
  end: number;
342
343
  startChar: number;
@@ -846,6 +847,7 @@ declare module 'abcjs' {
846
847
  getElementFromChar: (charPos: number) => VoiceItem | null;
847
848
  millisecondsPerMeasure: (bpm?: number) => number;
848
849
  setTiming: (bpm?: number, measuresOfDelay? : number) => void;
850
+ setupEvents: (startingDelay: number, timeDivider:number, startingBpm: number, warp?: number) => Array<NoteTimingEvent>;
849
851
  setUpAudio: (options: SynthOptions) => AudioTracks;
850
852
  makeVoicesArray: () => Array<Selectable[]>
851
853
  deline: () => Array<TuneLine>;
@@ -1026,10 +1028,30 @@ declare module 'abcjs' {
1026
1028
  loaded: Array<string>;
1027
1029
  }
1028
1030
 
1029
- export interface AudioTrack {
1030
- cmd: AudioTrackCommand;
1031
- [param: string]: any; // TODO - make this a union
1031
+ export interface AudioTrackProgramItem {
1032
+ cmd: 'program';
1033
+ channel: number;
1034
+ instrument: number;
1035
+ }
1036
+
1037
+ export interface AudioTrackNoteItem {
1038
+ cmd: 'note';
1039
+ duration: number;
1040
+ endChar: number;
1041
+ endType?: "staccato"|"tenuto";
1042
+ gap: number;
1043
+ instrument: number;
1044
+ pitch: number;
1045
+ start: number;
1046
+ startChar: number;
1047
+ volume: number;
1048
+ }
1049
+ export interface AudioTrackTextItem {
1050
+ cmd: 'text';
1051
+ type: 'name';
1052
+ text: string;
1032
1053
  }
1054
+ export type AudioTrack = Array<AudioTrackProgramItem|AudioTrackNoteItem|AudioTrackTextItem>
1033
1055
 
1034
1056
  export interface AudioTracks {
1035
1057
  tempo: number;
@@ -1157,6 +1179,7 @@ declare module 'abcjs' {
1157
1179
  stop(): number
1158
1180
  download(): string // returns audio buffer in wav format as a reference to a blob
1159
1181
  getIsRunning(): boolean
1182
+ getAudioBuffer(): AudioBuffer | undefined
1160
1183
  }
1161
1184
 
1162
1185
  export interface SynthInitResponse {
@@ -1188,6 +1211,22 @@ declare module 'abcjs' {
1188
1211
  appendNote(trackNumber: number, pitch: number, durationInMeasures: number, volume: number, cents: number): void
1189
1212
  }
1190
1213
 
1214
+ export interface MidiRenderer {
1215
+ setTempo(bpm: number): void
1216
+ setGlobalInfo(bpm: number, name: string, key:KeySignature, time:MeterFraction): void
1217
+ startTrack(): void
1218
+ endTrack(): void
1219
+ setText(type: string, text: string):void
1220
+ setInstrument(instrument: number):void
1221
+ setChannel(channel:number, pan?: number):void
1222
+ startNote(pitch:number, loudness:number, cents?:number):void
1223
+ endNote(pitch:number):void
1224
+ addRest(length:number):void
1225
+
1226
+ getData():string
1227
+ embed(parent:Element, noplayer:boolean):void
1228
+ }
1229
+
1191
1230
  export namespace synth {
1192
1231
  let instrumentIndexToName: [string]
1193
1232
  let pitchToNoteName: [string]
@@ -1202,6 +1241,7 @@ declare module 'abcjs' {
1202
1241
  export function getMidiFile(source: string | TuneObject, options?: MidiFileOptions): MidiFile;
1203
1242
  export function playEvent(pitches: MidiPitches, graceNotes: MidiGracePitches | undefined, milliSecondsPerMeasure: number, soundFontUrl? : string, debugCallback?: (message: string) => void): Promise<void>;
1204
1243
  export function sequence(visualObj: TuneObject, options: AbcVisualParams): AudioSequence
1244
+ export function midiRenderer(): MidiRenderer
1205
1245
  }
1206
1246
 
1207
1247
  //
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
- var version = '6.2.3';
1
+ var version = '6.3.0';
2
2
 
3
3
  module.exports = version;
@@ -1,29 +0,0 @@
1
- name: Tests
2
-
3
- on: [push, pull_request]
4
-
5
- jobs:
6
- Jest:
7
- runs-on: ubuntu-latest
8
- steps:
9
- - uses: actions/checkout@v2
10
-
11
- - name: Cache node modules
12
- uses: actions/cache@v2
13
- env:
14
- cache-name: cache-node-modules
15
- with:
16
- path: ~/.npm
17
- key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
18
- restore-keys: |
19
- ${{ runner.os }}-build-${{ env.cache-name }}-
20
- ${{ runner.os }}-build-
21
- ${{ runner.os }}-
22
-
23
- - name: Install Dependencies
24
- run: npm install --color="always"
25
-
26
- - name: Install Dependencies
27
- run: npm test -- --colors
28
-
29
-