abcjs 6.2.2 → 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 (66) hide show
  1. package/README.md +4 -0
  2. package/RELEASE.md +78 -0
  3. package/abc2xml_239/abc2xml.html +769 -0
  4. package/abc2xml_239/abc2xml.py +2248 -0
  5. package/abc2xml_239/abc2xml_changelog.html +124 -0
  6. package/abc2xml_239/lazy-river.abc +26 -0
  7. package/abc2xml_239/lazy-river.xml +3698 -0
  8. package/abc2xml_239/mean-to-me.abc +22 -0
  9. package/abc2xml_239/mean-to-me.xml +2954 -0
  10. package/abc2xml_239/pyparsing.py +3672 -0
  11. package/abc2xml_239/pyparsing.pyc +0 -0
  12. package/dist/abcjs-basic-min.js +2 -2
  13. package/dist/abcjs-basic.js +909 -485
  14. package/dist/abcjs-basic.js.map +1 -1
  15. package/dist/abcjs-plugin-min.js +2 -2
  16. package/index.js +2 -0
  17. package/package.json +1 -1
  18. package/plugin.js +1 -1
  19. package/src/api/abc_tablatures.js +51 -13
  20. package/src/api/abc_tunebook_svg.js +5 -3
  21. package/src/parse/abc_parse_directive.js +17 -16
  22. package/src/parse/abc_parse_header.js +22 -19
  23. package/src/parse/abc_parse_music.js +18 -53
  24. package/src/parse/abc_parse_settings.js +165 -0
  25. package/src/parse/abc_tokenizer.js +72 -7
  26. package/src/parse/tune-builder.js +60 -1
  27. package/src/synth/create-synth.js +4 -0
  28. package/src/synth/place-note.js +6 -0
  29. package/src/synth/play-event.js +7 -5
  30. package/src/synth/synth-controller.js +6 -2
  31. package/src/tablatures/instruments/string-patterns.js +11 -0
  32. package/src/tablatures/instruments/{guitar/guitar-patterns.js → tab-string-patterns.js} +6 -6
  33. package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
  34. package/src/tablatures/tab-absolute-elements.js +19 -9
  35. package/src/tablatures/tab-renderer.js +24 -10
  36. package/src/test/abc_parser_lint.js +1 -0
  37. package/src/write/creation/abstract-engraver.js +9 -2
  38. package/src/write/creation/add-chord.js +102 -82
  39. package/src/write/creation/add-text-if.js +2 -2
  40. package/src/write/creation/decoration.js +16 -8
  41. package/src/write/creation/elements/bottom-text.js +62 -47
  42. package/src/write/creation/elements/rich-text.js +51 -0
  43. package/src/write/creation/elements/top-text.js +37 -11
  44. package/src/write/creation/glyphs.js +2 -2
  45. package/src/write/draw/absolute.js +4 -1
  46. package/src/write/draw/draw.js +13 -4
  47. package/src/write/draw/glissando.js +1 -0
  48. package/src/write/draw/non-music.js +3 -1
  49. package/src/write/draw/relative.js +1 -1
  50. package/src/write/draw/set-paper-size.js +1 -1
  51. package/src/write/draw/tempo.js +1 -1
  52. package/src/write/draw/text.js +10 -0
  53. package/src/write/draw/tie.js +9 -1
  54. package/src/write/engraver-controller.js +58 -11
  55. package/src/write/helpers/classes.js +1 -1
  56. package/src/write/helpers/get-font-and-attr.js +8 -1
  57. package/src/write/helpers/get-text-size.js +8 -1
  58. package/src/write/interactive/selection.js +6 -0
  59. package/src/write/layout/layout.js +33 -3
  60. package/src/write/svg.js +30 -0
  61. package/temp.txt +50 -0
  62. package/types/index.d.ts +74 -26
  63. package/version.js +1 -1
  64. package/.github/workflows/tests.yml +0 -29
  65. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
  66. package/src/tablatures/instruments/violin/violin-patterns.js +0 -23
@@ -639,13 +639,78 @@ var Tokenizer = function(lines, multilineVars) {
639
639
  return {value: num/den, index: index};
640
640
  };
641
641
 
642
- this.theReverser = function(str) {
643
- if (parseCommon.endsWith(str, ", The"))
644
- return "The " + str.substring(0, str.length-5);
645
- if (parseCommon.endsWith(str, ", A"))
646
- return "A " + str.substring(0, str.length-3);
647
- return str;
648
- };
642
+ //
643
+ // MAE 10 Jan 2023 - For better handling of tunes that have tune numbers in front of them.
644
+ //
645
+ // Previous version would take:
646
+ // 21. Woman of the House, The
647
+ // and return:
648
+ // The 21. Woman of the House
649
+ //
650
+ // This fix results in:
651
+ // 21. The Woman of the House
652
+ //
653
+ // Also added additional checks and handlers for lower case ", the" and ", a" since I found several tune collections with those tune name constructs
654
+ //
655
+ // Find an optional title number at the start of a tune title
656
+ function getTitleNumber(str){
657
+
658
+ const regex = /^(\d+)\./;
659
+
660
+ // Use the exec method to search for the pattern in the string
661
+ const match = regex.exec(str);
662
+
663
+ // Check if a match is found
664
+ if (match) {
665
+
666
+ // The matched number is captured in the first group (index 1)
667
+ const foundNumber = match[1];
668
+ return foundNumber;
669
+
670
+ } else {
671
+
672
+ // Return null if no match is found
673
+ return null;
674
+
675
+ }
676
+
677
+ }
678
+
679
+ var thePatterns = [
680
+ { match: /,\s*[Tt]he$/, replace: "The " },
681
+ { match: /,\s*[Aa]$/, replace: "A " },
682
+ { match: /,\s*[Aa]n$/, replace: "An " },
683
+ ]
684
+
685
+ this.theReverser = function (str) {
686
+
687
+ for (var i = 0; i < thePatterns.length; i++) {
688
+ var thisPattern = thePatterns[i]
689
+ var match = str.match(thisPattern.match)
690
+ if (match) {
691
+ var theTitleNumber = getTitleNumber(str);
692
+ if (theTitleNumber){
693
+
694
+ //console.log("theReverser The titlenumber:"+theTitleNumber);
695
+
696
+ str = str.replace(theTitleNumber+".","");
697
+ str = str.trim();
698
+ }
699
+ var len = match[0].length
700
+ var result = thisPattern.replace + str.substring(0, str.length - len);
701
+
702
+ if (theTitleNumber){
703
+ result = theTitleNumber+". "+result;
704
+ }
705
+
706
+ return result;
707
+
708
+ }
709
+ }
710
+
711
+ return str;
712
+
713
+ };
649
714
 
650
715
  this.stripComment = function(str) {
651
716
  var i = str.indexOf('%');
@@ -1,5 +1,6 @@
1
1
  var parseKeyVoice = require('../parse/abc_parse_key_voice');
2
2
  var parseCommon = require('../parse/abc_common');
3
+ var parseDirective = require('./abc_parse_directive');
3
4
 
4
5
  var TuneBuilder = function(tune) {
5
6
  var self = this;
@@ -147,6 +148,9 @@ var TuneBuilder = function(tune) {
147
148
  this.closeLine(); // Close the last line.
148
149
  delete tune.runningFonts;
149
150
 
151
+ simplifyMetaText(tune)
152
+ //addRichTextToAnnotationsAndLyrics(tune)
153
+
150
154
  // 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.
151
155
  if (tune.metaText.tempo && tune.metaText.tempo.bpm && !tune.metaText.tempo.duration)
152
156
  tune.metaText.tempo.duration = [ tune.getBeatLength() ];
@@ -878,7 +882,15 @@ var TuneBuilder = function(tune) {
878
882
  tune.metaText[key] = value;
879
883
  tune.metaTextInfo[key] = info;
880
884
  } else {
881
- tune.metaText[key] += "\n" + value;
885
+ if (typeof tune.metaText[key] === 'string' && typeof value === 'string')
886
+ tune.metaText[key] += "\n" + value;
887
+ else {
888
+ if (tune.metaText[key] === 'string')
889
+ tune.metaText[key] = [{text: tune.metaText[key]}]
890
+ if (typeof value === 'string')
891
+ value = [{text: value}]
892
+ tune.metaText[key] =tune.metaText[key].concat(value)
893
+ }
882
894
  tune.metaTextInfo[key].endChar = info.endChar;
883
895
  }
884
896
  };
@@ -898,4 +910,51 @@ var TuneBuilder = function(tune) {
898
910
  };
899
911
  };
900
912
 
913
+ function isArrayOfStrings(arr) {
914
+ if (!arr) return false
915
+ if (typeof arr === "string") return false
916
+ var str = ''
917
+ for (var i = 0; i < arr.length; i++) {
918
+ if (typeof arr[i] !== 'string')
919
+ return false
920
+ }
921
+ return true
922
+ }
923
+
924
+ function simplifyMetaText(tune) {
925
+ if (isArrayOfStrings(tune.metaText.notes))
926
+ tune.metaText.notes = tune.metaText.notes.join("\n")
927
+ if (isArrayOfStrings(tune.metaText.history))
928
+ tune.metaText.history = tune.metaText.history.join("\n")
929
+ }
930
+
931
+ function addRichTextToAnnotationsAndLyrics(tune) {
932
+ var lines = tune.lines
933
+ for (var i = 0; i < lines.length; i++) {
934
+ if (lines[i].staff !== undefined) {
935
+ for (var s = 0; s < lines[i].staff.length; s++) {
936
+ for (var v = 0; v < lines[i].staff[s].voices.length; v++) {
937
+ var voice = lines[i].staff[s].voices[v];
938
+ for (var n = 0; n < voice.length; n++) {
939
+ var element = voice[n]
940
+ if (element.chord) {
941
+ for (var c = 0; c < element.chord.length; c++) {
942
+ element.chord[c].name = parseDirective.parseFontChangeLine(element.chord[c].name)
943
+ console.log(element.chord[c].name)
944
+ }
945
+ }
946
+ if (element.lyric) {
947
+ for (var l = 0; l < element.lyric.length; l++) {
948
+ element.lyric[l].syllable = parseDirective.parseFontChangeLine(element.lyric[l].syllable)
949
+ console.log(element.lyric[l].syllable)
950
+ }
951
+ }
952
+ }
953
+ }
954
+ }
955
+ }
956
+ }
957
+
958
+ }
959
+
901
960
  module.exports = TuneBuilder;
@@ -511,6 +511,10 @@ function CreateSynth() {
511
511
  return self.audioBuffers[0];
512
512
  };
513
513
 
514
+ self.getIsRunning = function() {
515
+ return self.isRunning;
516
+ }
517
+
514
518
  /////////////// Private functions //////////////
515
519
 
516
520
  self._deviceCapable = function() {
@@ -17,6 +17,12 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
17
17
  len = 0.005; // Have some small audible length no matter how short the note is.
18
18
  var offlineCtx = new OfflineAC(2,Math.floor((len+fadeTimeSec)*sampleRate),sampleRate);
19
19
  var noteName = pitchToNoteName[sound.pitch];
20
+ if (!soundsCache[sound.instrument]) {
21
+ // It shouldn't happen that the entire instrument cache wasn't created, but this has been seen in practice, so guard against it.
22
+ if (debugCallback)
23
+ debugCallback('placeNote skipped (instrument empty): '+sound.instrument+':'+noteName)
24
+ return Promise.resolve();
25
+ }
20
26
  var noteBufferPromise = soundsCache[sound.instrument][noteName];
21
27
 
22
28
  if (!noteBufferPromise) {
@@ -2,7 +2,7 @@ var SynthSequence = require('./synth-sequence');
2
2
  var CreateSynth = require('./create-synth');
3
3
  var activeAudioContext = require("./active-audio-context");
4
4
 
5
- function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure) {
5
+ function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure, soundFontUrl, debugCallback) {
6
6
  var sequence = new SynthSequence();
7
7
 
8
8
  for (var i = 0; i < midiPitches.length; i++) {
@@ -21,18 +21,20 @@ function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure) {
21
21
  var ac = activeAudioContext();
22
22
  if (ac.state === "suspended") {
23
23
  return ac.resume().then(function () {
24
- return doPlay(sequence, millisecondsPerMeasure);
24
+ return doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback);
25
25
  });
26
26
  } else {
27
- return doPlay(sequence, millisecondsPerMeasure);
27
+ return doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback);
28
28
  }
29
29
  }
30
30
 
31
- function doPlay(sequence, millisecondsPerMeasure) {
31
+ function doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback) {
32
32
  var buffer = new CreateSynth();
33
33
  return buffer.init({
34
34
  sequence: sequence,
35
- millisecondsPerMeasure: millisecondsPerMeasure
35
+ millisecondsPerMeasure: millisecondsPerMeasure,
36
+ options: { soundFontUrl: soundFontUrl },
37
+ debugCallback: debugCallback,
36
38
  }).then(function () {
37
39
  return buffer.prime();
38
40
  }).then(function () {
@@ -21,6 +21,10 @@ function SynthController() {
21
21
  self.load = function (selector, cursorControl, visualOptions) {
22
22
  if (!visualOptions)
23
23
  visualOptions = {};
24
+ if (visualOptions.displayPlay === undefined)
25
+ visualOptions.displayPlay = true
26
+ if (visualOptions.displayProgress === undefined)
27
+ visualOptions.displayProgress = true
24
28
  self.control = new CreateSynthControl(selector, {
25
29
  loopHandler: visualOptions.displayLoop ? self.toggleLoop : undefined,
26
30
  restartHandler: visualOptions.displayRestart ? self.restart : undefined,
@@ -41,7 +45,7 @@ function SynthController() {
41
45
  self.setTune = function(visualObj, userAction, audioParams) {
42
46
  self.visualObj = visualObj;
43
47
  self.disable(false);
44
- self.options = audioParams;
48
+ self.options = audioParams ? audioParams : {};
45
49
 
46
50
  if (self.control) {
47
51
  self.pause();
@@ -195,7 +199,7 @@ function SynthController() {
195
199
 
196
200
  self._randomAccess = function (ev) {
197
201
  var background = (ev.target.classList.contains('abcjs-midi-progress-indicator')) ? ev.target.parentNode : ev.target;
198
- var percent = (ev.x - background.offsetLeft) / background.offsetWidth;
202
+ var percent = (ev.x - background.getBoundingClientRect().left) / background.offsetWidth;
199
203
  if (percent < 0)
200
204
  percent = 0;
201
205
  if (percent > 1)
@@ -265,6 +265,17 @@ StringPatterns.prototype.tabInfos = function (plugin) {
265
265
  return '';
266
266
  };
267
267
 
268
+ // MAE 27 Nov 2023
269
+ StringPatterns.prototype.suppress = function (plugin) {
270
+ var _super = plugin._super;
271
+ var suppress = _super.params.suppress;
272
+ if (suppress){
273
+ return true;
274
+ }
275
+ return false;
276
+ };
277
+ // MAE 27 Nov 2023 End
278
+
268
279
  /**
269
280
  * Common patterns for all string instruments
270
281
  * @param {} plugin
@@ -1,23 +1,23 @@
1
- var StringPatterns = require('../string-patterns');
1
+ var StringPatterns = require('./string-patterns');
2
2
 
3
- function GuitarPatterns(plugin) {
3
+ function TabStringPatterns(plugin, defaultTuning) {
4
4
  this.tuning = plugin._super.params.tuning;
5
5
  if (!this.tuning) {
6
- this.tuning = ['E,', 'A,', 'D', 'G' , 'B' , 'e'];
6
+ this.tuning = defaultTuning;
7
7
  }
8
8
  plugin.tuning = this.tuning;
9
9
  this.strings = new StringPatterns(plugin);
10
10
  }
11
11
 
12
- GuitarPatterns.prototype.notesToNumber = function (notes, graces) {
12
+ TabStringPatterns.prototype.notesToNumber = function (notes, graces) {
13
13
  var converter = this.strings;
14
14
  return converter.notesToNumber(notes, graces);
15
15
  };
16
16
 
17
- GuitarPatterns.prototype.stringToPitch = function (stringNumber) {
17
+ TabStringPatterns.prototype.stringToPitch = function (stringNumber) {
18
18
  var converter = this.strings;
19
19
  return converter.stringToPitch(stringNumber);
20
20
  };
21
21
 
22
22
 
23
- module.exports = GuitarPatterns;
23
+ module.exports = TabStringPatterns;
@@ -1,8 +1,8 @@
1
1
 
2
- var StringTablature = require('../string-tablature');
3
- var TabCommon = require('../../tab-common');
4
- var TabRenderer = require('../../tab-renderer');
5
- var ViolinPatterns = require('./violin-patterns');
2
+ var StringTablature = require('./string-tablature');
3
+ var TabCommon = require('../tab-common');
4
+ var TabRenderer = require('../tab-renderer');
5
+ var TabStringPatterns = require('./tab-string-patterns');
6
6
 
7
7
 
8
8
  /**
@@ -11,18 +11,20 @@ var ViolinPatterns = require('./violin-patterns');
11
11
  * @param {*} tuneNumber the parsed tune AST tree
12
12
  * @param {*} params complementary args provided to Tablature Plugin
13
13
  */
14
- Plugin.prototype.init = function (abcTune, tuneNumber, params) {
14
+ Plugin.prototype.init = function (abcTune, tuneNumber, params, staffNumber, tabSettings) {
15
15
  var _super = new TabCommon(abcTune, tuneNumber, params);
16
16
  this.abcTune = abcTune;
17
17
  this._super = _super;
18
18
  this.linePitch = 3;
19
- this.nbLines = 4;
20
- this.isTabBig = false;
19
+ this.nbLines = tabSettings.defaultTuning.length;
20
+ this.isTabBig = tabSettings.isTabBig;
21
+ this.tabSymbolOffset = tabSettings.tabSymbolOffset;
21
22
  this.capo = params.capo;
22
23
  this.transpose = params.visualTranspose;
24
+ this.hideTabSymbol = params.hideTabSymbol;
23
25
  this.tablature = new StringTablature(this.nbLines,
24
26
  this.linePitch);
25
- var semantics = new ViolinPatterns(this);
27
+ var semantics = new TabStringPatterns(this, tabSettings.defaultTuning);
26
28
  this.semantics = semantics;
27
29
  };
28
30
 
@@ -38,8 +40,8 @@ function Plugin() {}
38
40
  //
39
41
  // Tablature plugin definition
40
42
  //
41
- var AbcViolinTab = function () {
42
- return { name: 'ViolinTab', tablature: Plugin };
43
+ var AbcStringTab = function () {
44
+ return { name: 'StringTab', tablature: Plugin };
43
45
  };
44
46
 
45
- module.exports = AbcViolinTab;
47
+ module.exports = AbcStringTab;
@@ -60,13 +60,22 @@ function buildTabAbsolute(plugin, absX, relX) {
60
60
  icon: tabIcon,
61
61
  Ypos: tabYPos
62
62
  };
63
- var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0);
64
- tabAbsolute.x = absX;
65
- var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab");
66
- tabRelative.x = relX;
67
- tabAbsolute.children.push(tabRelative);
68
- if (tabAbsolute.abcelem.el_type == 'tab') {
69
- tabRelative.pitch = tabYPos;
63
+
64
+ // Offset the TAB symbol position if specified in the tab description
65
+ tabYPos += plugin.tabSymbolOffset;
66
+
67
+ // For tablature like whistle tab where you want the TAB symbol hidden
68
+ if (!plugin.hideTabSymbol){
69
+
70
+ var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0);
71
+ tabAbsolute.x = absX;
72
+ var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab");
73
+ tabRelative.x = relX;
74
+ tabAbsolute.children.push(tabRelative);
75
+ if (tabAbsolute.abcelem.el_type == 'tab') {
76
+ tabRelative.pitch = tabYPos;
77
+ }
78
+
70
79
  }
71
80
  return tabAbsolute;
72
81
  }
@@ -177,10 +186,11 @@ TabAbsoluteElements.prototype.build = function (plugin,
177
186
  tabVoice,
178
187
  voiceIndex,
179
188
  staffIndex,
180
- keySig ) {
189
+ keySig,
190
+ tabVoiceIndex ) {
181
191
  var staffSize = getInitialStaffSize(staffAbsolute);
182
192
  var source = staffAbsolute[staffIndex+voiceIndex];
183
- var dest = staffAbsolute[staffSize+staffIndex+voiceIndex];
193
+ var dest = staffAbsolute[tabVoiceIndex];
184
194
  var tabPos = null;
185
195
  var defNote = null;
186
196
  if (source.children[0].abcelem.el_type != 'clef') {
@@ -37,12 +37,24 @@ function buildTabName(self, dest) {
37
37
  var controller = self.renderer.controller;
38
38
  var textSize = controller.getTextSize;
39
39
  var tabName = stringSemantics.tabInfos(self.plugin);
40
- var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
41
- dest.tabNameInfos = {
42
- textSize: size,
43
- name: tabName
44
- };
45
- return size.height;
40
+ var suppress = stringSemantics.suppress(self.plugin);
41
+ var doDraw = true;
42
+
43
+ if (suppress){
44
+ doDraw = false
45
+ }
46
+
47
+
48
+ if (doDraw){
49
+ var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
50
+ dest.tabNameInfos = {
51
+ textSize: {height:size.height,width:size.width},
52
+ name: tabName
53
+ };
54
+ return size.height;
55
+ }
56
+ return 0
57
+
46
58
  }
47
59
 
48
60
  /**
@@ -230,16 +242,18 @@ TabRenderer.prototype.doLayout = function () {
230
242
  if (ii > 0) tabVoice.duplicate = true;
231
243
  var nameHeight = buildTabName(this, tabVoice) / spacing.STEP;
232
244
  nameHeight = Math.max(nameHeight, 1) // If there is no label for the tab line, then there needs to be a little padding
233
- staffGroup.staffs[this.staffIndex].top += nameHeight;
234
- staffGroup.height += nameHeight * spacing.STEP;
245
+ // This was pushing down the top staff by the tab label height
246
+ //staffGroup.staffs[this.staffIndex].top += nameHeight;
247
+ staffGroup.staffs[this.staffIndex].top += 1;
248
+ staffGroup.height += nameHeight;
235
249
  tabVoice.staff = staffGroupInfos;
250
+ var tabVoiceIndex = voices.length
236
251
  voices.splice(voices.length, 0, tabVoice);
237
252
  var keySig = checkVoiceKeySig(voices, ii + this.staffIndex);
238
253
  this.tabStaff.voices[ii] = [];
239
- this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii , this.staffIndex ,keySig);
254
+ this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii , this.staffIndex ,keySig, tabVoiceIndex);
240
255
  }
241
256
  linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
242
257
  };
243
258
 
244
-
245
259
  module.exports = TabRenderer;
@@ -427,6 +427,7 @@ var ParserLint = function() {
427
427
  var formattingProperties = {
428
428
  type:"object",
429
429
  properties: {
430
+ accentAbove: { type: "boolean", optional: true },
430
431
  alignbars: { type: "number", optional: true },
431
432
  aligncomposer: { type: "string", Enum: [ 'left', 'center','right' ], optional: true },
432
433
  annotationfont: fontType,
@@ -53,6 +53,7 @@ var AbstractEngraver = function (getTextSize, tuneNumber, options) {
53
53
  this.percmap = options.percmap;
54
54
  this.initialClef = options.initialClef
55
55
  this.jazzchords = !!options.jazzchords
56
+ this.accentAbove = !!options.accentAbove
56
57
  this.germanAlphabet = !!options.germanAlphabet
57
58
  this.reset();
58
59
  };
@@ -747,6 +748,12 @@ AbstractEngraver.prototype.addNoteToAbcElement = function (abselem, elem, dot, s
747
748
  else
748
749
  p1 += 1;
749
750
  }
751
+ if (noteHead && noteHead.c === 'noteheads.triangle.quarter') {
752
+ if (dir === 'down')
753
+ p2 -= 0.7;
754
+ else
755
+ p1 -= 1.2;
756
+ }
750
757
  abselem.addRight(new RelativeElement(null, dx, 0, p1, { "type": "stem", "pitch2": p2, linewidth: width, bottom: p1 - 1 }));
751
758
  //var RelativeElement = function RelativeElement(c, dx, w, pitch, opt) {
752
759
  min = Math.min(p1, p2);
@@ -824,7 +831,7 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
824
831
  }
825
832
 
826
833
  if (elem.decoration) {
827
- this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals);
834
+ this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals, this.accentAbove);
828
835
  }
829
836
 
830
837
  if (elem.barNumber) {
@@ -983,7 +990,7 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
983
990
  }
984
991
 
985
992
  if (elem.decoration) {
986
- this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals);
993
+ this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals, this.accentAbove);
987
994
  }
988
995
 
989
996
  if (thick) {