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
package/index.js CHANGED
@@ -57,6 +57,7 @@ var supportsAudio = require('./src/synth/supports-audio');
57
57
  var playEvent = require('./src/synth/play-event');
58
58
  var SynthController = require('./src/synth/synth-controller');
59
59
  var getMidiFile = require('./src/synth/get-midi-file');
60
+ var midiRenderer = require('./src/synth/abc_midi_renderer');
60
61
 
61
62
  abcjs.synth = {
62
63
  CreateSynth: CreateSynth,
@@ -71,6 +72,7 @@ abcjs.synth = {
71
72
  playEvent: playEvent,
72
73
  getMidiFile: getMidiFile,
73
74
  sequence: sequence,
75
+ midiRenderer: midiRenderer,
74
76
  };
75
77
 
76
78
  abcjs['Editor'] = require('./src/edit/abc_editor');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abcjs",
3
- "version": "6.2.2",
3
+ "version": "6.3.0",
4
4
  "description": "Renderer for abc music notation",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
package/plugin.js CHANGED
@@ -248,7 +248,7 @@ if (autostart &&
248
248
  }
249
249
 
250
250
  var abcjs = {
251
- plugin: Plugin
251
+ plugin: plugin
252
252
  };
253
253
 
254
254
  module.exports = abcjs;
@@ -5,17 +5,17 @@
5
5
  * where plugin represents a plugin instance
6
6
  *
7
7
  */
8
- var ViolinTablature = require('../tablatures/instruments/violin/tab-violin');
9
- var GuitarTablature = require('../tablatures/instruments/guitar/tab-guitar');
8
+ var StringTablature = require('../tablatures/instruments/tab-string');
10
9
 
11
10
  /* extend the table below when adding a new instrument plugin */
12
11
 
13
12
  // Existing tab classes
14
13
  var pluginTab = {
15
- 'violin': 'ViolinTab',
16
- 'fiddle': 'ViolinTab',
17
- 'mandolin': 'ViolinTab',
18
- 'guitar': 'GuitarTab'
14
+ 'violin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0},
15
+ 'fiddle': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0},
16
+ 'mandolin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0},
17
+ 'guitar': { name: 'StringTab', defaultTuning: ['E,', 'A,', 'D', 'G' , 'B' , 'e'], isTabBig: true, tabSymbolOffset: 0},
18
+ 'fiveString': { name: 'StringTab', defaultTuning: ['C,', 'G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: -.95},
19
19
  };
20
20
 
21
21
  var abcTablatures = {
@@ -66,7 +66,7 @@ var abcTablatures = {
66
66
  var tabName = pluginTab[instrument];
67
67
  var plugin = null;
68
68
  if (tabName) {
69
- plugin = this.plugins[tabName];
69
+ plugin = this.plugins[tabName.name];
70
70
  }
71
71
  if (plugin) {
72
72
  if (params.visualTranspose != 0) {
@@ -79,11 +79,15 @@ var abcTablatures = {
79
79
  tuneNumber: tuneNumber,
80
80
  params: args,
81
81
  instance: null,
82
+ tabType: tabName,
82
83
  };
83
84
  // proceed with tab plugin init
84
85
  // plugin.init(tune, tuneNumber, args, ii);
85
86
  returned.push(pluginInstance);
86
87
  nbPlugins++;
88
+ } else if (instrument === '') {
89
+ // create a placeholder - there is no tab for this staff
90
+ returned.push(null)
87
91
  } else {
88
92
  // unknown tab plugin
89
93
  //this.emit_error('Undefined tablature plugin: ' + tabName)
@@ -100,16 +104,50 @@ var abcTablatures = {
100
104
  * @param {*} renderer
101
105
  * @param {*} abcTune
102
106
  */
103
- layoutTablatures: function (renderer, abcTune) {
107
+ layoutTablatures: function layoutTablatures(renderer, abcTune) {
104
108
  var tabs = abcTune.tablatures;
109
+
105
110
  // chack tabs request for each staffs
111
+ var staffLineCount = 0;
112
+
113
+ // Clear the suppression flag
114
+ if (tabs && (tabs.length > 0)){
115
+ var nTabs = tabs.length;
116
+ for (var kk=0;kk<nTabs;++kk){
117
+ if (tabs[kk] && tabs[kk].params.firstStaffOnly){
118
+ tabs[kk].params.suppress = false;
119
+ }
120
+ }
121
+ }
122
+
106
123
  for (var ii = 0; ii < abcTune.lines.length; ii++) {
107
124
  var line = abcTune.lines[ii];
125
+
126
+ if (line.staff){
127
+ staffLineCount++;
128
+ }
129
+
130
+ // MAE 27Nov2023
131
+ // If tab param "firstStaffOnly", remove the tab label after the first staff
132
+ if (staffLineCount > 1){
133
+ if (tabs && (tabs.length > 0)){
134
+ var nTabs = tabs.length;
135
+ for (var kk=0;kk<nTabs;++kk){
136
+ if (tabs[kk].params.firstStaffOnly){
137
+ // Set the staff draw suppression flag
138
+ tabs[kk].params.suppress = true;
139
+ }
140
+ }
141
+ }
142
+ }
143
+
108
144
  var curStaff = line.staff;
109
145
  if (curStaff) {
146
+ var maxStaves = curStaff.length
110
147
  for (var jj = 0; jj < curStaff.length; jj++) {
111
- if (tabs[jj]) {
112
- // tablature requested for staff
148
+
149
+ if (tabs[jj] && jj < maxStaves) {
150
+ // tablature requested for staff
113
151
  var tabPlugin = tabs[jj];
114
152
  if (tabPlugin.instance == null) {
115
153
  tabPlugin.instance = new tabPlugin.classz();
@@ -118,7 +156,8 @@ var abcTablatures = {
118
156
  tabPlugin.instance.init(abcTune,
119
157
  tabPlugin.tuneNumber,
120
158
  tabPlugin.params,
121
- jj
159
+ jj,
160
+ tabPlugin.tabType
122
161
  );
123
162
  }
124
163
  // render next
@@ -135,8 +174,7 @@ var abcTablatures = {
135
174
  init: function () {
136
175
  // just register plugin hosted by abcjs
137
176
  if (!this.inited) {
138
- this.register(new ViolinTablature());
139
- this.register(new GuitarTablature());
177
+ this.register(new StringTablature());
140
178
  this.inited = true;
141
179
  }
142
180
  }
@@ -117,12 +117,12 @@ var renderAbc = function(output, abc, parserParams, engraverParams, renderParams
117
117
  div.setAttribute("style", "visibility: hidden;");
118
118
  document.body.appendChild(div);
119
119
  }
120
- if (params.afterParsing)
121
- params.afterParsing(tune, tuneNumber, abcString);
122
120
  if (!removeDiv && params.wrap && params.staffwidth) {
123
- tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
121
+ tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
124
122
  return tune;
125
123
  }
124
+ if (params.afterParsing)
125
+ params.afterParsing(tune, tuneNumber, abcString);
126
126
  renderOne(div, tune, params, tuneNumber, 0);
127
127
  if (removeDiv)
128
128
  div.parentNode.removeChild(div);
@@ -145,6 +145,8 @@ function doLineWrapping(div, tune, tuneNumber, abcString, params) {
145
145
  if (warnings)
146
146
  tune.warnings = warnings;
147
147
  }
148
+ if (params.afterParsing)
149
+ params.afterParsing(tune, tuneNumber, abcString);
148
150
  renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
149
151
  tune.explanation = ret.explanation;
150
152
  return tune;
@@ -684,27 +684,27 @@ var parseDirective = {};
684
684
  };
685
685
 
686
686
  parseDirective.parseFontChangeLine = function(textstr) {
687
+ // We don't want to match two dollar signs, so change those temporarily
688
+ textstr = textstr.replace(/\$\$/g,"\x03")
687
689
  var textParts = textstr.split('$');
688
690
  if (textParts.length > 1 && multilineVars.setfont) {
689
- var textarr = [ { text: textParts[0] }];
691
+ var textarr = [ ];
692
+ if (textParts[0] !== '') // did the original string start with `$`?
693
+ textarr.push({ text: textParts[0] })
690
694
  for (var i = 1; i < textParts.length; i++) {
691
695
  if (textParts[i][0] === '0')
692
- textarr.push({ text: textParts[i].substring(1) });
693
- else if (textParts[i][0] === '1' && multilineVars.setfont[1])
694
- textarr.push({font: multilineVars.setfont[1], text: textParts[i].substring(1) });
695
- else if (textParts[i][0] === '2' && multilineVars.setfont[2])
696
- textarr.push({font: multilineVars.setfont[2], text: textParts[i].substring(1) });
697
- else if (textParts[i][0] === '3' && multilineVars.setfont[3])
698
- textarr.push({font: multilineVars.setfont[3], text: textParts[i].substring(1) });
699
- else if (textParts[i][0] === '4' && multilineVars.setfont[4])
700
- textarr.push({font: multilineVars.setfont[4], text: textParts[i].substring(1) });
701
- else
702
- textarr[textarr.length-1].text += '$' + textParts[i];
696
+ textarr.push({ text: textParts[i].substring(1).replace(/\x03/g,"$$") });
697
+ else {
698
+ var whichFont = parseInt(textParts[i][0],10)
699
+ if (multilineVars.setfont[whichFont])
700
+ textarr.push({font: multilineVars.setfont[whichFont], text: textParts[i].substring(1).replace(/\x03/g,"$$") });
701
+ else
702
+ textarr[textarr.length-1].text += '$' + textParts[i].replace(/\x03/g,"$$");
703
+ }
703
704
  }
704
- if (textarr.length > 1)
705
- return textarr;
705
+ return textarr;
706
706
  }
707
- return textstr;
707
+ return textstr.replace(/\x03/g,"$$");
708
708
  };
709
709
 
710
710
  var positionChoices = [ 'auto', 'above', 'below', 'hidden' ];
@@ -748,6 +748,7 @@ var parseDirective = {};
748
748
  case "bagpipes":tune.formatting.bagpipes = true;break;
749
749
  case "flatbeams":tune.formatting.flatbeams = true;break;
750
750
  case "jazzchords":tune.formatting.jazzchords = true;break;
751
+ case "accentAbove":tune.formatting.accentAbove = true;break;
751
752
  case "germanAlphabet":tune.formatting.germanAlphabet = true;break;
752
753
  case "landscape":multilineVars.landscape = true;break;
753
754
  case "papersize":multilineVars.papersize = restOfString;break;
@@ -939,7 +940,7 @@ var parseDirective = {};
939
940
  if (sfTokens.length >= 4) {
940
941
  if (sfTokens[0].token === '-' && sfTokens[1].type === 'number') {
941
942
  var sfNum = parseInt(sfTokens[1].token);
942
- if (sfNum >= 1 && sfNum <= 4) {
943
+ if (sfNum >= 1 && sfNum <= 9) {
943
944
  if (!multilineVars.setfont)
944
945
  multilineVars.setfont = [];
945
946
  sfTokens.shift();
@@ -11,15 +11,12 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
11
11
  };
12
12
  this.reset(tokenizer, warn, multilineVars, tune);
13
13
 
14
- this.setTitle = function(title) {
14
+ this.setTitle = function(title, origSize) {
15
15
  if (multilineVars.hasMainTitle)
16
- tuneBuilder.addSubtitle(tokenizer.translateString(tokenizer.stripComment(title)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2}); // display secondary title
16
+ tuneBuilder.addSubtitle(title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2}); // display secondary title
17
17
  else
18
18
  {
19
- var titleStr = tokenizer.translateString(tokenizer.theReverser(tokenizer.stripComment(title)));
20
- if (multilineVars.titlecaps)
21
- titleStr = titleStr.toUpperCase();
22
- tuneBuilder.addMetaText("title", titleStr, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2});
19
+ tuneBuilder.addMetaText("title", title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2});
23
20
  multilineVars.hasMainTitle = true;
24
21
  }
25
22
  };
@@ -371,10 +368,11 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
371
368
  tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
372
369
  return [ e-i+1+ws ];
373
370
  case "[P:":
371
+ var part = parseDirective.parseFontChangeLine(line.substring(i+3, e))
374
372
  if (startLine || tune.lines.length <= tune.lineNum)
375
- multilineVars.partForNextLine = { title: line.substring(i+3, e), startChar: startChar, endChar: endChar };
373
+ multilineVars.partForNextLine = { title: part, startChar: startChar, endChar: endChar };
376
374
  else
377
- tuneBuilder.appendElement('part', startChar, endChar, {title: line.substring(i+3, e)});
375
+ tuneBuilder.appendElement('part', startChar, endChar, {title: part});
378
376
  return [ e-i+1+ws ];
379
377
  case "[L:":
380
378
  this.setDefaultLength(line, i+3, e);
@@ -477,23 +475,26 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
477
475
 
478
476
  this.parseHeader = function(line) {
479
477
  var field = metaTextHeaders[line[0]];
480
- if (field !== undefined) {
481
- if (field === 'unalignedWords')
482
- tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line.substring(2)))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
483
- else
484
- tuneBuilder.addMetaText(field, tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
485
- return {};
478
+ var origSize = line.length-2
479
+ var restOfLine = tokenizer.translateString(tokenizer.stripComment(line.substring(2)))
480
+ if (field === 'unalignedWords' || field === 'notes') {
481
+ // These fields can be multi-line
482
+ tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
483
+ } else if (field !== undefined) {
484
+ // these fields are single line
485
+ tuneBuilder.addMetaText(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
486
486
  } else {
487
487
  var startChar = multilineVars.iChar;
488
488
  var endChar = startChar + line.length;
489
489
  switch(line[0])
490
490
  {
491
491
  case 'H':
492
- tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
492
+ // History is a little different because once it starts it continues until another header field is encountered
493
+ tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
493
494
  line = tokenizer.peekLine()
494
495
  while (line && line[1] !== ':') {
495
496
  tokenizer.nextLine()
496
- tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
497
+ tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
497
498
  line = tokenizer.peekLine()
498
499
  }
499
500
  break;
@@ -518,9 +519,9 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
518
519
  case 'P':
519
520
  // TODO-PER: There is more to do with parts, but the writer doesn't care.
520
521
  if (multilineVars.is_in_header)
521
- tuneBuilder.addMetaText("partOrder", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
522
+ tuneBuilder.addMetaText("partOrder", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
522
523
  else
523
- multilineVars.partForNextLine = { title: tokenizer.translateString(tokenizer.stripComment(line.substring(2))), startChar: startChar, endChar: endChar};
524
+ multilineVars.partForNextLine = { title: restOfLine, startChar: startChar, endChar: endChar};
524
525
  break;
525
526
  case 'Q':
526
527
  var tempo = this.setTempo(line, 2, line.length, multilineVars.iChar);
@@ -533,7 +534,9 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
533
534
  }
534
535
  break;
535
536
  case 'T':
536
- this.setTitle(line.substring(2));
537
+ if (multilineVars.titlecaps)
538
+ restOfLine = restOfLine.toUpperCase();
539
+ this.setTitle(parseDirective.parseFontChangeLine(tokenizer.theReverser(restOfLine)), origSize);
537
540
  break;
538
541
  case 'U':
539
542
  this.addUserDefinition(line, 2, line.length);
@@ -9,6 +9,20 @@ var tune;
9
9
  var tuneBuilder;
10
10
  var header;
11
11
 
12
+ var {
13
+ legalAccents,
14
+ volumeDecorations,
15
+ dynamicDecorations,
16
+ accentPseudonyms,
17
+ accentDynamicPseudonyms,
18
+ nonDecorations,
19
+ durations,
20
+ pitches,
21
+ rests,
22
+ accMap,
23
+ tripletQ
24
+ } = require('./abc_parse_settings')
25
+
12
26
  var MusicParser = function(_tokenizer, _warn, _multilineVars, _tune, _tuneBuilder, _header) {
13
27
  tokenizer = _tokenizer;
14
28
  warn = _warn;
@@ -76,7 +90,6 @@ var MusicParser = function(_tokenizer, _warn, _multilineVars, _tune, _tuneBuilde
76
90
  // double-quote: chord symbol
77
91
  // less-than, greater-than, slash: duration
78
92
  // back-tick, space, tab: space
79
- var nonDecorations = "ABCDEFGabcdefgxyzZ[]|^_{"; // use this to prescreen so we don't have to look for a decoration at every note.
80
93
 
81
94
  var isInTie = function(multilineVars, overlayLevel, el) {
82
95
  if (multilineVars.inTie[overlayLevel] === undefined)
@@ -540,15 +553,8 @@ MusicParser.prototype.parseMusic = function(line) {
540
553
  // Create a warning if this is not a displayable duration.
541
554
  // The first item on a line is a regular note value, each item after that represents a dot placed after the previous note.
542
555
  // Only durations less than a whole note are tested because whole note durations have some tricky rules.
543
- var durations = [
544
- 0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375,
545
- 0.25, 0.375, 0.4375, 0.46875, 0.484375, 0.4921875,
546
- 0.125, 0.1875, 0.21875, 0.234375, 0.2421875, 0.24609375,
547
- 0.0625, 0.09375, 0.109375, 0.1171875, 0.12109375, 0.123046875,
548
- 0.03125, 0.046875, 0.0546875, 0.05859375, 0.060546875, 0.0615234375,
549
- 0.015625, 0.0234375, 0.02734375, 0.029296875, 0.0302734375, 0.03076171875,
550
- ];
551
- if (el.duration < 1 && durations.indexOf(el.duration) === -1 && el.duration !== 0) {
556
+
557
+ if (el.duration < 1 && durations.indexOf(el.duration) === -1 && el.duration !== 0) {
552
558
  if (!el.rest || el.rest.type !== 'spacer')
553
559
  warn("Duration not representable: " + line.substring(startI, i), line, i);
554
560
  }
@@ -717,35 +723,8 @@ function durationOfMeasure(multilineVars) {
717
723
  return parseInt(meter.value[0].num, 10) / parseInt(meter.value[0].den, 10);
718
724
  }
719
725
 
720
- var legalAccents = [
721
- "trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent",
722
- "fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge",
723
- "open", "thumb", "snap", "turn", "roll", "breath", "shortphrase", "mediumphrase", "longphrase",
724
- "segno", "coda", "D.S.", "D.C.", "fine", "beambr1", "beambr2",
725
- "slide", "marcato",
726
- "upbow", "downbow", "/", "//", "///", "////", "trem1", "trem2", "trem3", "trem4",
727
- "turnx", "invertedturn", "invertedturnx", "trill(", "trill)", "arpeggio", "xstem", "mark", "umarcato",
728
- "style=normal", "style=harmonic", "style=rhythm", "style=x", "style=triangle", "D.C.alcoda", "D.C.alfine", "D.S.alcoda", "D.S.alfine", "editorial", "courtesy"
729
- ];
730
-
731
- var volumeDecorations = [
732
- "p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz"
733
- ];
734
-
735
- var dynamicDecorations = [
736
- "crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)"
737
- ];
738
-
739
- var accentPseudonyms = [
740
- ["<", "accent"], [">", "accent"], ["tr", "trill"],
741
- ["plus", "+"], [ "emphasis", "accent"],
742
- [ "^", "umarcato" ], [ "marcato", "umarcato" ]
743
- ];
744
-
745
- var accentDynamicPseudonyms = [
746
- ["<(", "crescendo("], ["<)", "crescendo)"],
747
- [">(", "diminuendo("], [">)", "diminuendo)"]
748
- ];
726
+
727
+
749
728
 
750
729
  var letter_to_accent = function(line, i) {
751
730
  var macro = multilineVars.macros[line[i]];
@@ -877,17 +856,6 @@ var letter_to_bar = function(line, curr_pos) {
877
856
  return [ret.len+retRep.len, ret.token, retRep.token];
878
857
  };
879
858
 
880
- var tripletQ = {
881
- 2: 3,
882
- 3: 2,
883
- 4: 3,
884
- 5: 2, // TODO-PER: not handling 6/8 rhythm yet
885
- 6: 2,
886
- 7: 2, // TODO-PER: not handling 6/8 rhythm yet
887
- 8: 3,
888
- 9: 2 // TODO-PER: not handling 6/8 rhythm yet
889
- };
890
-
891
859
  var letter_to_open_slurs_and_triplets = function(line, i) {
892
860
  // consume spaces, and look for all the open parens. If there is a number after the open paren,
893
861
  // that is a triplet. Otherwise that is a slur. Collect all the slurs and the first triplet.
@@ -1050,9 +1018,6 @@ var addEndBeam = function(el) {
1050
1018
  return el;
1051
1019
  };
1052
1020
 
1053
- var pitches = {A: 5, B: 6, C: 0, D: 1, E: 2, F: 3, G: 4, a: 12, b: 13, c: 7, d: 8, e: 9, f: 10, g: 11};
1054
- var rests = {x: 'invisible', X: 'invisible-multimeasure', y: 'spacer', z: 'rest', Z: 'multimeasure' };
1055
- var accMap = { 'dblflat': '__', 'flat': '_', 'natural': '=', 'sharp': '^', 'dblsharp': '^^', 'quarterflat': '_/', 'quartersharp': '^/'};
1056
1021
  var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
1057
1022
  //var el = { startChar: index };
1058
1023
  var isComplete = function(state) {
@@ -0,0 +1,165 @@
1
+ module.exports.legalAccents = [
2
+ 'trill',
3
+ 'lowermordent',
4
+ 'uppermordent',
5
+ 'mordent',
6
+ 'pralltriller',
7
+ 'accent',
8
+ 'fermata',
9
+ 'invertedfermata',
10
+ 'tenuto',
11
+ '0',
12
+ '1',
13
+ '2',
14
+ '3',
15
+ '4',
16
+ '5',
17
+ '+',
18
+ 'wedge',
19
+ 'open',
20
+ 'thumb',
21
+ 'snap',
22
+ 'turn',
23
+ 'roll',
24
+ 'breath',
25
+ 'shortphrase',
26
+ 'mediumphrase',
27
+ 'longphrase',
28
+ 'segno',
29
+ 'coda',
30
+ 'D.S.',
31
+ 'D.C.',
32
+ 'fine',
33
+ 'beambr1',
34
+ 'beambr2',
35
+ 'slide',
36
+ 'marcato',
37
+ 'upbow',
38
+ 'downbow',
39
+ '/',
40
+ '//',
41
+ '///',
42
+ '////',
43
+ 'trem1',
44
+ 'trem2',
45
+ 'trem3',
46
+ 'trem4',
47
+ 'turnx',
48
+ 'invertedturn',
49
+ 'invertedturnx',
50
+ 'trill(',
51
+ 'trill)',
52
+ 'arpeggio',
53
+ 'xstem',
54
+ 'mark',
55
+ 'umarcato',
56
+ 'style=normal',
57
+ 'style=harmonic',
58
+ 'style=rhythm',
59
+ 'style=x',
60
+ 'style=triangle',
61
+ 'D.C.alcoda',
62
+ 'D.C.alfine',
63
+ 'D.S.alcoda',
64
+ 'D.S.alfine',
65
+ 'editorial',
66
+ 'courtesy'
67
+ ];
68
+
69
+ module.exports.volumeDecorations = [
70
+ 'p',
71
+ 'pp',
72
+ 'f',
73
+ 'ff',
74
+ 'mf',
75
+ 'mp',
76
+ 'ppp',
77
+ 'pppp',
78
+ 'fff',
79
+ 'ffff',
80
+ 'sfz'
81
+ ];
82
+
83
+ module.exports.dynamicDecorations = [
84
+ 'crescendo(',
85
+ 'crescendo)',
86
+ 'diminuendo(',
87
+ 'diminuendo)',
88
+ 'glissando(',
89
+ 'glissando)',
90
+ '~(',
91
+ '~)'
92
+ ];
93
+
94
+ module.exports.accentPseudonyms = [
95
+ ['<', 'accent'],
96
+ ['>', 'accent'],
97
+ ['tr', 'trill'],
98
+ ['plus', '+'],
99
+ ['emphasis', 'accent'],
100
+ ['^', 'umarcato'],
101
+ ['marcato', 'umarcato']
102
+ ];
103
+
104
+ module.exports.accentDynamicPseudonyms = [
105
+ ['<(', 'crescendo('],
106
+ ['<)', 'crescendo)'],
107
+ ['>(', 'diminuendo('],
108
+ ['>)', 'diminuendo)']
109
+ ];
110
+
111
+ module.exports.nonDecorations = 'ABCDEFGabcdefgxyzZ[]|^_{'; // use this to prescreen so we don't have to look for a decoration at every note.
112
+
113
+ module.exports.durations = [
114
+ 0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375, 0.25, 0.375, 0.4375, 0.46875,
115
+ 0.484375, 0.4921875, 0.125, 0.1875, 0.21875, 0.234375, 0.2421875, 0.24609375,
116
+ 0.0625, 0.09375, 0.109375, 0.1171875, 0.12109375, 0.123046875, 0.03125,
117
+ 0.046875, 0.0546875, 0.05859375, 0.060546875, 0.0615234375, 0.015625,
118
+ 0.0234375, 0.02734375, 0.029296875, 0.0302734375, 0.03076171875
119
+ ];
120
+
121
+ module.exports.pitches = {
122
+ A: 5,
123
+ B: 6,
124
+ C: 0,
125
+ D: 1,
126
+ E: 2,
127
+ F: 3,
128
+ G: 4,
129
+ a: 12,
130
+ b: 13,
131
+ c: 7,
132
+ d: 8,
133
+ e: 9,
134
+ f: 10,
135
+ g: 11
136
+ };
137
+
138
+ module.exports.rests = {
139
+ x: 'invisible',
140
+ X: 'invisible-multimeasure',
141
+ y: 'spacer',
142
+ z: 'rest',
143
+ Z: 'multimeasure'
144
+ };
145
+
146
+ module.exports.accMap = {
147
+ dblflat: '__',
148
+ flat: '_',
149
+ natural: '=',
150
+ sharp: '^',
151
+ dblsharp: '^^',
152
+ quarterflat: '_/',
153
+ quartersharp: '^/'
154
+ };
155
+
156
+ module.exports.tripletQ = {
157
+ 2: 3,
158
+ 3: 2,
159
+ 4: 3,
160
+ 5: 2, // TODO-PER: not handling 6/8 rhythm yet
161
+ 6: 2,
162
+ 7: 2, // TODO-PER: not handling 6/8 rhythm yet
163
+ 8: 3,
164
+ 9: 2 // TODO-PER: not handling 6/8 rhythm yet
165
+ };